[D3D] Some texturing work...

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

See the changelog :-)

Changelog:
 - added mipmapping support
 - added locking for concurrent access to the D3D device
 - improved tracing
 - added support for most texture combine stages (inspired by the D3D8 code)
 - disable current lock / unlock code pending proper solution
 
-- 
		 Lionel Ulmer - http://www.bbrox.org/
Index: dlls/ddraw/d3d_private.h
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/d3d_private.h,v
retrieving revision 1.29
diff -u -r1.29 d3d_private.h
--- dlls/ddraw/d3d_private.h	12 Feb 2003 21:40:25 -0000	1.29
+++ dlls/ddraw/d3d_private.h	9 May 2003 18:58:06 -0000
@@ -246,6 +246,9 @@
 			 D3DMATRIX *world_mat, D3DMATRIX *view_mat, D3DMATRIX *proj_mat);
 
     STATEBLOCK state_block;
+
+    /* Used to prevent locks and rendering to overlap */
+    CRITICAL_SECTION crit;
 };
 
 /*****************************************************************************
Index: dlls/ddraw/d3dtexture.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/d3dtexture.c,v
retrieving revision 1.43
diff -u -r1.43 d3dtexture.c
--- dlls/ddraw/d3dtexture.c	8 May 2003 21:03:57 -0000	1.43
+++ dlls/ddraw/d3dtexture.c	9 May 2003 18:58:07 -0000
@@ -49,7 +49,7 @@
     char buf[128];
     FILE *f;
     
-    sprintf(buf, "tex_%05d.pnm", glThis->tex_name);
+    sprintf(buf, "tex_%05d_%02d.pnm", glThis->tex_name, This->mipmap_level);
     f = fopen(buf, "wb");
     DDRAW_dump_surface_to_disk(This, f);
 }
@@ -60,6 +60,25 @@
 
 #endif
 
+static IDirectDrawSurfaceImpl *
+get_sub_mimaplevel(IDirectDrawSurfaceImpl *tex_ptr)
+{
+    /* Now go down the mipmap chain to the next surface */
+    static const DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 };
+    LPDIRECTDRAWSURFACE7 next_level;
+    IDirectDrawSurfaceImpl *surf_ptr;
+    HRESULT hr;
+    
+    hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(tex_ptr, IDirectDrawSurface7),
+						(DDSCAPS2 *) &mipmap_caps, &next_level);
+    if (FAILED(hr)) return NULL;
+    
+    surf_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, next_level);
+    IDirectDrawSurface7_Release(next_level);
+    
+    return surf_ptr;
+}
+
 /*******************************************************************************
  *			   IDirectSurface callback methods
  */
@@ -69,416 +88,435 @@
 #if 0
     static BOOL color_table_queried = FALSE;
 #endif
-    void (*ptr_ColorTableEXT) (GLenum target, GLenum internalformat,
-			       GLsizei width, GLenum format, GLenum type, const GLvoid *table) = NULL;
-    BOOL upload_done = FALSE;
-    BOOL error = FALSE;
-    GLenum format = GL_RGBA, pixel_format = GL_UNSIGNED_BYTE; /* This is only to prevent warnings.. */
-    VOID *surface = NULL;
-
-    DDSURFACEDESC *src_d = (DDSURFACEDESC *)&(This->surface_desc);
-
-    glBindTexture(GL_TEXTURE_2D, glThis->tex_name);
-
-    if (glThis->dirty_flag == FALSE) {
-        TRACE(" activating OpenGL texture id %d.\n", glThis->tex_name);
-	return DD_OK;
-    } else {
-        TRACE(" activating and uploading texture id %d (initial done = %d).\n", glThis->tex_name, glThis->initial_upload_done);
-    }
-
-    /* Texture snooping for the curious :-) */
-    snoop_texture(This);
+    static void (*ptr_ColorTableEXT) (GLenum target, GLenum internalformat,
+				      GLsizei width, GLenum format, GLenum type, const GLvoid *table) = NULL;
+    IDirectDrawSurfaceImpl *surf_ptr;
+    GLuint tex_name = glThis->tex_name;
     
-    if (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
-	  /* ****************
-	     Paletted Texture
-	     **************** */
-        IDirectDrawPaletteImpl* pal = This->palette;
-	BYTE table[256][4];
-	int i;
+    TRACE(" activating OpenGL texture id %d.\n", tex_name);
+    glBindTexture(GL_TEXTURE_2D, tex_name);
 
-#if 0
-	if (color_table_queried == FALSE) {
-	    ptr_ColorTableEXT =
-	        ((Mesa_DeviceCapabilities *) ((x11_dd_private *) This->surface->s.ddraw->d->private)->device_capabilities)->ptr_ColorTableEXT;
-	}
-#endif
+    if (This->mipmap_level != 0) {
+        WARN(" application activating a sub-level of the mipmapping chain (level %d) !\n", This->mipmap_level);
+    }
+    
+    surf_ptr = This;
+    while (surf_ptr != NULL) {
+        GLenum format = GL_RGBA, pixel_format = GL_UNSIGNED_BYTE; /* This is only to prevent warnings.. */
+	VOID *surface = NULL;
+	DDSURFACEDESC *src_d = (DDSURFACEDESC *)&(surf_ptr->surface_desc);
+	IDirect3DTextureGLImpl *gl_surf_ptr = (IDirect3DTextureGLImpl *) surf_ptr->tex_private;
+	BOOL upload_done = FALSE;
+	BOOL error = FALSE;
 	
-	if (pal == NULL) {
-	    /* Upload a black texture. The real one will be uploaded on palette change */
-	    WARN("Palettized texture Loading with a NULL palette !\n");
-	    memset(table, 0, 256 * 4);
+	if (gl_surf_ptr->dirty_flag == FALSE) {
+	    TRACE("   - level %d already uploaded.\n", surf_ptr->mipmap_level);
 	} else {
-	    /* Get the surface's palette */
-	    for (i = 0; i < 256; i++) {
-	        table[i][0] = pal->palents[i].peRed;
-		table[i][1] = pal->palents[i].peGreen;
-		table[i][2] = pal->palents[i].peBlue;
-		if ((src_d->dwFlags & DDSD_CKSRCBLT) &&
-		    (i >= src_d->ddckCKSrcBlt.dwColorSpaceLowValue) &&
-		    (i <= src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-		    /* We should maybe here put a more 'neutral' color than the standard bright purple
-		       one often used by application to prevent the nice purple borders when bi-linear
-		       filtering is on */
-		    table[i][3] = 0x00;
-		else
-		    table[i][3] = 0xFF;
-	    }
-	}
+	    TRACE("   - uploading texture level %d (initial done = %d).\n",
+		  surf_ptr->mipmap_level, gl_surf_ptr->initial_upload_done);
 
-	if (ptr_ColorTableEXT != NULL) {
-	    /* use Paletted Texture Extension */
-	    ptr_ColorTableEXT(GL_TEXTURE_2D,    /* target */
-			      GL_RGBA,          /* internal format */
-			      256,              /* table size */
-			      GL_RGBA,          /* table format */
-			      GL_UNSIGNED_BYTE, /* table type */
-			      table);           /* the color table */
-	    
-	    glTexImage2D(GL_TEXTURE_2D,       /* target */
-			 This->mipmap_level,                   /* level */
-			 GL_COLOR_INDEX8_EXT, /* internal format */
-			 src_d->dwWidth, src_d->dwHeight, /* width, height */
-			 0,                   /* border */
-			 GL_COLOR_INDEX,      /* texture format */
-			 GL_UNSIGNED_BYTE,    /* texture type */
-			 src_d->lpSurface); /* the texture */
-
-	    upload_done = TRUE;
-	} else {
-	    DWORD i;
-	    BYTE *src = (BYTE *) src_d->lpSurface, *dst;
-
-	    surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
-	    dst = (BYTE *) surface;
-	    
-	    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-	        BYTE color = *src++;
-		*dst++ = table[color][0];
-		*dst++ = table[color][1];
-		*dst++ = table[color][2];
-		*dst++ = table[color][3];
-	    }
-	    
-	    format = GL_RGBA;
-	    pixel_format = GL_UNSIGNED_BYTE;
-	}
-    } else if (src_d->ddpfPixelFormat.dwFlags & DDPF_RGB) {
-	    /* ************
-	       RGB Textures
-	       ************ */
-        if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 8) {
-	    if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xE0) &&
-		(src_d->ddpfPixelFormat.u3.dwGBitMask == 0x1C) &&
-		(src_d->ddpfPixelFormat.u4.dwBBitMask == 0x03)) {
-	        /* **********************
-		   GL_UNSIGNED_BYTE_3_3_2
-		   ********************** */
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    /* This texture format will never be used.. So do not care about color keying
-		       up until the point in time it will be needed :-) */
-		    error = TRUE;
-		} else {
-		    format = GL_RGB;
-		    pixel_format = GL_UNSIGNED_BYTE_3_3_2;
-		}
-	    } else {
-	        error = TRUE;
-	    }
-	} else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 16) {
-	    if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
-		(src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x07E0) &&
-		(src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
-		(src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000)) {
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    /* Converting the 565 format in 5551 packed to emulate color-keying.
-
-		       Note : in all these conversion, it would be best to average the averaging
-		              pixels to get the color of the pixel that will be color-keyed to
-			      prevent 'color bleeding'. This will be done later on if ever it is
-			      too visible.
-
-		       Note2: when using color-keying + alpha, are the alpha bits part of the
-		              color-space or not ?
-		    */
-		    DWORD i;
-		    WORD *src = (WORD *) src_d->lpSurface, *dst;
-		    
-		    surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
-		    dst = (WORD *) surface;
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst = ((color & 0xFFC0) | ((color & 0x1F) << 1));
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= 0x0001;
-			dst++;
-		    }
+	    /* Texture snooping for the curious :-) */
+	    snoop_texture(surf_ptr);
+    
+	    if (src_d->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
+	        /* ****************
+		   Paletted Texture
+		   **************** */
+	        IDirectDrawPaletteImpl* pal = surf_ptr->palette;
+		BYTE table[256][4];
+		int i;
 		
-		    format = GL_RGBA;
-		    pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
-		} else {
-		    format = GL_RGB;
-		    pixel_format = GL_UNSIGNED_SHORT_5_6_5;
-		}
-	    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
-		       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x07C0) &&
-		       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x003E) &&
-		       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0001)) {
-		format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;	        
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
-		    DWORD i;
-		    WORD *src = (WORD *) src_d->lpSurface, *dst;
-		    
-		    surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
-		    dst = (WORD *) surface;
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst = color & 0xFFFE;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= color & 0x0001;
-			dst++;
-		    }
-		}
-	    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF000) &&
-		       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0F00) &&
-		       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x00F0) &&
-		       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000F)) {
-	        format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_SHORT_4_4_4_4;	      
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
-		    DWORD i;
-		    WORD *src = (WORD *) src_d->lpSurface, *dst;
-		    
-		    surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
-		    dst = (WORD *) surface;
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst = color & 0xFFF0;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= color & 0x000F;
-			dst++;
-		    }
+#if 0
+		if (color_table_queried == FALSE) {
+		    ptr_ColorTableEXT =
+		      ((Mesa_DeviceCapabilities *) ((x11_dd_private *) surf_ptr->surface->s.ddraw->d->private)->device_capabilities)->ptr_ColorTableEXT;
 		}
-	    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x0F00) &&
-		       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x00F0) &&
-		       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000F) &&
-		       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0xF000)) {
-	        /* Move the four Alpha bits... */
-		DWORD i;
-		WORD *src = (WORD *) src_d->lpSurface, *dst;
-		
-		surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
-		dst = surface;
+#endif
 		
-		if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst = (color & 0x0FFF) << 4;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= (color & 0xF000) >> 12;
-			dst++;
-		    }
+		if (pal == NULL) {
+		    /* Upload a black texture. The real one will be uploaded on palette change */
+		    WARN("Palettized texture Loading with a NULL palette !\n");
+		    memset(table, 0, 256 * 4);
 		} else {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst++ = (((color & 0x0FFF) << 4) |
-				  ((color & 0xF000) >> 12));
+		    /* Get the surface's palette */
+		    for (i = 0; i < 256; i++) {
+		        table[i][0] = pal->palents[i].peRed;
+			table[i][1] = pal->palents[i].peGreen;
+			table[i][2] = pal->palents[i].peBlue;
+			if ((src_d->dwFlags & DDSD_CKSRCBLT) &&
+			    (i >= src_d->ddckCKSrcBlt.dwColorSpaceLowValue) &&
+			    (i <= src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+			    /* We should maybe here put a more 'neutral' color than the standard bright purple
+			       one often used by application to prevent the nice purple borders when bi-linear
+			       filtering is on */
+			    table[i][3] = 0x00;
+			else
+			    table[i][3] = 0xFF;
 		    }
 		}
 
-	        format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_SHORT_4_4_4_4; 		
-	    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x7C00) &&
-		       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x03E0) &&
-		       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
-		       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x8000)) {
-	        /* Converting the 1555 format in 5551 packed */
-		DWORD i;
-		WORD *src = (WORD *) src_d->lpSurface, *dst;
-		
-		surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
-		dst = (WORD *) surface;
-		
-		if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst = (color & 0x7FFF) << 1;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= (color & 0x8000) >> 15;
-			dst++;
-		    }
+		if (ptr_ColorTableEXT != NULL) {
+		    /* use Paletted Texture Extension */
+		    ptr_ColorTableEXT(GL_TEXTURE_2D,    /* target */
+				      GL_RGBA,          /* internal format */
+				      256,              /* table size */
+				      GL_RGBA,          /* table format */
+				      GL_UNSIGNED_BYTE, /* table type */
+				      table);           /* the color table */
+		    
+		    glTexImage2D(GL_TEXTURE_2D,       /* target */
+				 surf_ptr->mipmap_level, /* level */
+				 GL_COLOR_INDEX8_EXT, /* internal format */
+				 src_d->dwWidth, src_d->dwHeight, /* width, height */
+				 0,                   /* border */
+				 GL_COLOR_INDEX,      /* texture format */
+				 GL_UNSIGNED_BYTE,    /* texture type */
+				 src_d->lpSurface); /* the texture */
+		    
+		    upload_done = TRUE;
 		} else {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        WORD color = *src++;
-			*dst++ = (((color & 0x7FFF) << 1) |
-				  ((color & 0x8000) >> 15));
-		    }		  
-		}
-		
-	        format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
-	    } else {
-		error = TRUE;
-	    }
-	} else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 24) {
-	    if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
-		(src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
-		(src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
-		(src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    /* This is a pain :-) */
 		    DWORD i;
-		    BYTE *src = (BYTE *) src_d->lpSurface;
-		    DWORD *dst;
+		    BYTE *src = (BYTE *) src_d->lpSurface, *dst;
+		    
+		    surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
+		    dst = (BYTE *) surface;
 		    
-		    surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
-		    dst = (DWORD *) surface;
 		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        DWORD color = *((DWORD *) src) & 0x00FFFFFF;
-			src += 3;
-		        *dst = *src++ << 8;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= 0xFF;
-			dst++;
+		        BYTE color = *src++;
+			*dst++ = table[color][0];
+			*dst++ = table[color][1];
+			*dst++ = table[color][2];
+			*dst++ = table[color][3];
 		    }
+		    
 		    format = GL_RGBA;
-		    pixel_format = GL_UNSIGNED_INT_8_8_8_8;
+		    pixel_format = GL_UNSIGNED_BYTE;
+		}
+	    } else if (src_d->ddpfPixelFormat.dwFlags & DDPF_RGB) {
+	        /* ************
+		   RGB Textures
+		   ************ */
+	        if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 8) {
+		    if ((src_d->ddpfPixelFormat.u2.dwRBitMask == 0xE0) &&
+			(src_d->ddpfPixelFormat.u3.dwGBitMask == 0x1C) &&
+			(src_d->ddpfPixelFormat.u4.dwBBitMask == 0x03)) {
+		        /* **********************
+			   GL_UNSIGNED_BYTE_3_3_2
+			   ********************** */
+		        if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    /* This texture format will never be used.. So do not care about color keying
+			       up until the point in time it will be needed :-) */
+			    error = TRUE;
+			} else {
+			    format = GL_RGB;
+			    pixel_format = GL_UNSIGNED_BYTE_3_3_2;
+			}
+		    } else {
+		        error = TRUE;
+		    }
+		} else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 16) {
+		    if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
+			(src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x07E0) &&
+			(src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
+			(src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0000)) {
+		        if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    /* Converting the 565 format in 5551 packed to emulate color-keying.
+			       
+			       Note : in all these conversion, it would be best to average the averaging
+			              pixels to get the color of the pixel that will be color-keyed to
+				      prevent 'color bleeding'. This will be done later on if ever it is
+				      too visible.
+				      
+			       Note2: when using color-keying + alpha, are the alpha bits part of the
+			              color-space or not ?
+			    */
+			    DWORD i;
+			    WORD *src = (WORD *) src_d->lpSurface, *dst;
+			    
+			    surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+							 src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
+			    dst = (WORD *) surface;
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst = ((color & 0xFFC0) | ((color & 0x1F) << 1));
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= 0x0001;
+				dst++;
+			    }
+			    
+			    format = GL_RGBA;
+			    pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
+			} else {
+			    format = GL_RGB;
+			    pixel_format = GL_UNSIGNED_SHORT_5_6_5;
+			}
+		    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF800) &&
+			       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x07C0) &&
+			       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x003E) &&
+			       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x0001)) {
+		        format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;	        
+			if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
+			    DWORD i;
+			    WORD *src = (WORD *) src_d->lpSurface, *dst;
+			    
+			    surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+							 src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
+			    dst = (WORD *) surface;
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst = color & 0xFFFE;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= color & 0x0001;
+				dst++;
+			    }
+			}
+		    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xF000) &&
+			       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0F00) &&
+			       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x00F0) &&
+			       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000F)) {
+		        format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_SHORT_4_4_4_4;	      
+			if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    /* Change the alpha value of the color-keyed pixels to emulate color-keying. */
+			    DWORD i;
+			    WORD *src = (WORD *) src_d->lpSurface, *dst;
+		    
+			    surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+							 src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
+			    dst = (WORD *) surface;
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst = color & 0xFFF0;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= color & 0x000F;
+				dst++;
+			    }
+			}
+		    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x0F00) &&
+			       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x00F0) &&
+			       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000F) &&
+			       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0xF000)) {
+		        /* Move the four Alpha bits... */
+		        DWORD i;
+			WORD *src = (WORD *) src_d->lpSurface, *dst;
+			
+			surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+						     src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
+			dst = surface;
+			
+			if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst = (color & 0x0FFF) << 4;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= (color & 0xF000) >> 12;
+				dst++;
+			    }
+			} else {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst++ = (((color & 0x0FFF) << 4) |
+					  ((color & 0xF000) >> 12));
+			    }
+			}
+
+			format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_SHORT_4_4_4_4; 		
+		    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x7C00) &&
+			       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x03E0) &&
+			       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x001F) &&
+			       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x8000)) {
+		        /* Converting the 1555 format in 5551 packed */
+		        DWORD i;
+			WORD *src = (WORD *) src_d->lpSurface, *dst;
+			
+			surface = (WORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+						     src_d->dwWidth * src_d->dwHeight * sizeof(WORD));
+			dst = (WORD *) surface;
+			
+			if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst = (color & 0x7FFF) << 1;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= (color & 0x8000) >> 15;
+				dst++;
+			    }
+			} else {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        WORD color = *src++;
+				*dst++ = (((color & 0x7FFF) << 1) |
+					  ((color & 0x8000) >> 15));
+			    }		  
+			}
+			
+			format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_SHORT_5_5_5_1;
+		    } else {
+		        error = TRUE;
+		    }
+		} else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 24) {
+		    if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
+			(src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
+			(src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
+			(src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
+		        if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    /* This is a pain :-) */
+			    DWORD i;
+			    BYTE *src = (BYTE *) src_d->lpSurface;
+			    DWORD *dst;
+			    
+			    surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+							  src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
+			    dst = (DWORD *) surface;
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        DWORD color = *((DWORD *) src) & 0x00FFFFFF;
+				src += 3;
+				*dst = *src++ << 8;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= 0xFF;
+				dst++;
+			    }
+			    format = GL_RGBA;
+			    pixel_format = GL_UNSIGNED_INT_8_8_8_8;
+			} else {
+			    format = GL_BGR;
+			    pixel_format = GL_UNSIGNED_BYTE;
+			}
+		    } else {
+		        error = TRUE;
+		    }
+		} else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 32) {
+		    if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xFF000000) &&
+			(src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x00FF0000) &&
+			(src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x0000FF00) &&
+			(src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000000FF)) {
+		        if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    /* Just use the alpha component to handle color-keying... */
+			    DWORD i;
+			    DWORD *src = (DWORD *) src_d->lpSurface, *dst;
+			    
+			    surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+							  src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
+			    dst = (DWORD *) surface;
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        DWORD color = *src++;
+				*dst = color & 0xFFFFFF00;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= color & 0x000000FF;
+				dst++;
+			    }
+			}
+			format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_INT_8_8_8_8;
+		    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
+			       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
+			       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
+			       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0xFF000000)) {
+		        /* Convert from ARGB (Windows' format) to RGBA.
+			   Note: need to check for GL extensions handling ARGB instead of always converting */
+		        DWORD i;
+			DWORD *src = (DWORD *) src_d->lpSurface, *dst;
+			
+			surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
+			dst = (DWORD *) surface;
+			if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        DWORD color = *src++;
+				*dst = (color & 0x00FFFFFF) << 8;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= (color & 0xFF000000) >> 24;
+				dst++;
+			    }
+			} else {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        DWORD color = *src++; 
+				*dst  = (color & 0x00FFFFFF) << 8; 
+				*dst |= (color & 0xFF000000) >> 24;
+			    }
+			}
+			format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_INT_8_8_8_8;
+		    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
+			       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
+			       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
+			       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
+		        /* Just add an alpha component and handle color-keying... */
+		        DWORD i;
+			DWORD *src = (DWORD *) src_d->lpSurface, *dst;
+			
+			surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
+			dst = (DWORD *) surface;
+			
+			if (src_d->dwFlags & DDSD_CKSRCBLT) {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        DWORD color = *src++;
+				*dst = color << 8;
+				if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
+				    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
+				    *dst |= 0xFF;
+				dst++;
+			    }
+			} else {
+			    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
+			        *dst++ = (*src++ << 8) | 0xFF;
+			      }
+			  }
+			format = GL_RGBA;
+			pixel_format = GL_UNSIGNED_INT_8_8_8_8;
+		    } else {
+		        error = TRUE;
+		    }
 		} else {
-		  format = GL_BGR;
-		  pixel_format = GL_UNSIGNED_BYTE;
+		    error = TRUE;
 		}
 	    } else {
 	        error = TRUE;
-	    }
-	} else if (src_d->ddpfPixelFormat.u1.dwRGBBitCount == 32) {
-	    if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0xFF000000) &&
-		(src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x00FF0000) &&
-		(src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x0000FF00) &&
-		(src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x000000FF)) {
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    /* Just use the alpha component to handle color-keying... */
-		    DWORD i;
-		    DWORD *src = (DWORD *) src_d->lpSurface, *dst;
-		
-		    surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
-		    dst = (DWORD *) surface;
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        DWORD color = *src++;
-		        *dst = color & 0xFFFFFF00;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= color & 0x000000FF;
-			dst++;
-		    }
-		}
-	        format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_INT_8_8_8_8;
-	    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
-		       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
-		       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
-		       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0xFF000000)) {
-	        /* Convert from ARGB (Windows' format) to RGBA.
-		   Note: need to check for GL extensions handling ARGB instead of always converting */
-	        DWORD i;
-		DWORD *src = (DWORD *) src_d->lpSurface, *dst;
-		
-		surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
-		dst = (DWORD *) surface;
-		if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        DWORD color = *src++;
-			*dst = (color & 0x00FFFFFF) << 8;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= (color & 0xFF000000) >> 24;
-			dst++;
-		    }
+	    } 
+	    
+	    if ((upload_done == FALSE) && (error == FALSE)) {
+	        if (gl_surf_ptr->initial_upload_done == FALSE) {
+		    glTexImage2D(GL_TEXTURE_2D,
+				 surf_ptr->mipmap_level,
+				 format,
+				 src_d->dwWidth, src_d->dwHeight,
+				 0,
+				 format,
+				 pixel_format,
+				 surface == NULL ? src_d->lpSurface : surface);
+		    gl_surf_ptr->initial_upload_done = TRUE;
 		} else {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        DWORD color = *src++;
-			*dst = (color & 0x00FFFFFF) << 8;
-			*dst |= (color & 0xFF000000) >> 24;
-		    }
+		    glTexSubImage2D(GL_TEXTURE_2D,
+				    surf_ptr->mipmap_level,
+				    0, 0,
+				    src_d->dwWidth, src_d->dwHeight,
+				    format,
+				    pixel_format,
+				    surface == NULL ? src_d->lpSurface : surface);
 		}
-		format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_INT_8_8_8_8;
-	    } else if ((src_d->ddpfPixelFormat.u2.dwRBitMask ==        0x00FF0000) &&
-		       (src_d->ddpfPixelFormat.u3.dwGBitMask ==        0x0000FF00) &&
-		       (src_d->ddpfPixelFormat.u4.dwBBitMask ==        0x000000FF) &&
-		       (src_d->ddpfPixelFormat.u5.dwRGBAlphaBitMask == 0x00000000)) {
-	        /* Just add an alpha component and handle color-keying... */
-	        DWORD i;
-		DWORD *src = (DWORD *) src_d->lpSurface, *dst;
+		gl_surf_ptr->dirty_flag = FALSE;
 		
-		surface = (DWORD *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, src_d->dwWidth * src_d->dwHeight * sizeof(DWORD));
-		dst = (DWORD *) surface;
-		
-	        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        DWORD color = *src++;
-		        *dst = color << 8;
-			if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
-			    (color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
-			    *dst |= 0xFF;
-			dst++;
-		    }
-		} else {
-		    for (i = 0; i < src_d->dwHeight * src_d->dwWidth; i++) {
-		        *dst++ = (*src++ << 8) | 0xFF;
-		    }
+		if (surface) HeapFree(GetProcessHeap(), 0, surface);
+	    } else if (error == TRUE) {
+	        if (ERR_ON(ddraw)) {
+		    ERR("  unsupported pixel format for textures : \n");
+		    DDRAW_dump_pixelformat(&src_d->ddpfPixelFormat);
 		}
-	        format = GL_RGBA;
-		pixel_format = GL_UNSIGNED_INT_8_8_8_8;
-	    } else {
-		error = TRUE;
 	    }
-	} else {
-	    error = TRUE;
-	}
-    } else {
-	error = TRUE;
-    } 
-
-    if ((upload_done == FALSE) && (error == FALSE)) {
-        if (glThis->initial_upload_done == FALSE) {
-	    glTexImage2D(GL_TEXTURE_2D,
-			 This->mipmap_level,
-			 format,
-			 src_d->dwWidth, src_d->dwHeight,
-			 0,
-			 format,
-			 pixel_format,
-			 surface == NULL ? src_d->lpSurface : surface);
-	    glThis->initial_upload_done = TRUE;
-	} else {
-	    glTexSubImage2D(GL_TEXTURE_2D,
-			    This->mipmap_level,
-			    0, 0,
-			    src_d->dwWidth, src_d->dwHeight,
-			    format,
-			    pixel_format,
-			    surface == NULL ? src_d->lpSurface : surface);
 	}
-	
-	if (surface) HeapFree(GetProcessHeap(), 0, surface);
-    } else if (error == TRUE) {
-	if (ERR_ON(ddraw)) {
-	    ERR("Unsupported pixel format for textures : \n");
-	    DDRAW_dump_pixelformat(&src_d->ddpfPixelFormat);
-	}
-    }
 
-    glThis->dirty_flag = FALSE;
+	surf_ptr = get_sub_mimaplevel(surf_ptr);
+      }
 
     return DD_OK;
 }
@@ -499,7 +537,8 @@
     IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
 
     glThis->dirty_flag = TRUE;
-
+    /* TODO: check color-keying on mipmapped surfaces... */
+    
     return DD_OK;
 }
 
@@ -560,6 +599,8 @@
     
     /* And set the dirty flag */
     glThis->dirty_flag = TRUE;
+
+    /* TODO: check palette on mipmapped surfaces... */
 }
 
 static void
@@ -618,82 +659,99 @@
 				  LPDIRECT3DTEXTURE2 lpD3DTexture2)
 {
     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirect3DTexture2, iface);
-    IDirect3DTextureGLImpl *glThis = (IDirect3DTextureGLImpl *) This->tex_private;
-    IDirectDrawSurfaceImpl *lpD3DTextureImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
-    DWORD mem_used;
-    DDSURFACEDESC *src_d, *dst_d;
+    IDirectDrawSurfaceImpl *src_ptr = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, lpD3DTexture2);
+    IDirectDrawSurfaceImpl *dst_ptr = This;
     HRESULT ret_value = D3D_OK;
-    
+   
     TRACE("(%p/%p)->(%p)\n", This, iface, lpD3DTexture2);
 
-    if (glThis != NULL) {
-        if (glThis->loaded == FALSE) {
-	    /* Only check memory for not already loaded texture... */
-	    mem_used = This->surface_desc.dwHeight *
-	               This->surface_desc.u1.lPitch;
-	    if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
-	        TRACE(" out of virtual memory... Warning application.\n");
-		return D3DERR_TEXTURE_LOAD_FAILED;
+    if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
+	(src_ptr->surface_desc.u2.dwMipMapCount != dst_ptr->surface_desc.u2.dwMipMapCount)) {
+        ERR("Trying to load surfaces with different mip-map counts !\n");
+    }
+
+    /* Now loop through all mipmap levels and load all of them... */
+    while (1) {
+        IDirect3DTextureGLImpl *gl_dst_ptr = (IDirect3DTextureGLImpl *) dst_ptr->tex_private;
+	DDSURFACEDESC *src_d, *dst_d;
+	
+	if (gl_dst_ptr != NULL) {
+	    if (gl_dst_ptr->loaded == FALSE) {
+	        /* Only check memory for not already loaded texture... */
+	        DWORD mem_used = dst_ptr->surface_desc.dwHeight * dst_ptr->surface_desc.u1.lPitch;
+		if (This->ddraw_owner->allocate_memory(This->ddraw_owner, mem_used) < 0) {
+		    TRACE(" out of virtual memory... Warning application.\n");
+		    return D3DERR_TEXTURE_LOAD_FAILED;
+		}
 	    }
+	    gl_dst_ptr->loaded = TRUE;
 	}
-	glThis->loaded = TRUE;
-    }
     
-    TRACE("Copied surface %p to surface %p\n", lpD3DTextureImpl, This);
+	TRACE(" copying surface %p to surface %p (mipmap level %d)\n", src_ptr, dst_ptr, src_ptr->mipmap_level);
 
-    if ( This->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
-        /* If the surface is not allocated and its location is not yet specified,
-	   force it to video memory */ 
-        if ( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
-	    This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
-
-    /* Suppress the ALLOCONLOAD flag */
-    This->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
-    
-    /* After seeing some logs, not sure at all about this... */
-    if (This->palette == NULL) {
-        This->palette = lpD3DTextureImpl->palette;
-	if (lpD3DTextureImpl->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(lpD3DTextureImpl->palette,
-											IDirectDrawPalette));
-    } else {
-        if (lpD3DTextureImpl->palette != NULL) {
-	    PALETTEENTRY palent[256];
-	    IDirectDrawPalette *pal_int = ICOM_INTERFACE(lpD3DTextureImpl->palette, IDirectDrawPalette);
-	    IDirectDrawPalette_GetEntries(pal_int, 0, 0, 256, palent);
-	    IDirectDrawPalette_SetEntries(ICOM_INTERFACE(This->palette, IDirectDrawPalette),
-					  0, 0, 256, palent);
+	if ( dst_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD )
+	    /* If the surface is not allocated and its location is not yet specified,
+	       force it to video memory */ 
+	    if ( !(dst_ptr->surface_desc.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY)) )
+	        dst_ptr->surface_desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+
+	/* Suppress the ALLOCONLOAD flag */
+	dst_ptr->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
+    
+	/* After seeing some logs, not sure at all about this... */
+	if (dst_ptr->palette == NULL) {
+	    dst_ptr->palette = src_ptr->palette;
+	    if (src_ptr->palette != NULL) IDirectDrawPalette_AddRef(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette));
+	} else {
+	    if (src_ptr->palette != NULL) {
+	        PALETTEENTRY palent[256];
+		IDirectDrawPalette_GetEntries(ICOM_INTERFACE(src_ptr->palette, IDirectDrawPalette),
+					      0, 0, 256, palent);
+		IDirectDrawPalette_SetEntries(ICOM_INTERFACE(dst_ptr->palette, IDirectDrawPalette),
+					      0, 0, 256, palent);
+	    }
 	}
-    }
-    
-    /* Copy one surface on the other */
-    dst_d = (DDSURFACEDESC *)&(This->surface_desc);
-    src_d = (DDSURFACEDESC *)&(lpD3DTextureImpl->surface_desc);
-
-    if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
-        /* Should also check for same pixel format, u1.lPitch, ... */
-        ERR("Error in surface sizes\n");
-	return D3DERR_TEXTURE_LOAD_FAILED;
-    } else {
-        /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
-        /* I should put a macro for the calculus of bpp */
-
-        /* Copy also the ColorKeying stuff */
-        if (src_d->dwFlags & DDSD_CKSRCBLT) {
-	    dst_d->dwFlags |= DDSD_CKSRCBLT;
-	    dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
-	    dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
+	
+	/* Copy one surface on the other */
+	dst_d = (DDSURFACEDESC *)&(dst_ptr->surface_desc);
+	src_d = (DDSURFACEDESC *)&(src_ptr->surface_desc);
+
+	if ((src_d->dwWidth != dst_d->dwWidth) || (src_d->dwHeight != dst_d->dwHeight)) {
+	    /* Should also check for same pixel format, u1.lPitch, ... */
+	    ERR("Error in surface sizes\n");
+	    return D3DERR_TEXTURE_LOAD_FAILED;
+	} else {
+	    /* LPDIRECT3DDEVICE2 d3dd = (LPDIRECT3DDEVICE2) This->D3Ddevice; */
+	    /* I should put a macro for the calculus of bpp */
+	  
+	    /* Copy also the ColorKeying stuff */
+	    if (src_d->dwFlags & DDSD_CKSRCBLT) {
+	        dst_d->dwFlags |= DDSD_CKSRCBLT;
+		dst_d->ddckCKSrcBlt.dwColorSpaceLowValue = src_d->ddckCKSrcBlt.dwColorSpaceLowValue;
+		dst_d->ddckCKSrcBlt.dwColorSpaceHighValue = src_d->ddckCKSrcBlt.dwColorSpaceHighValue;
+	    }
+
+	    /* Copy the main memory texture into the surface that corresponds to the OpenGL
+	       texture object. */
+	    memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
+
+	    if (gl_dst_ptr != NULL) {
+	        /* If the GetHandle was not done, it is an error... */
+	        if (gl_dst_ptr->tex_name == 0) ERR("Unbound GL texture !!!\n");
+
+		/* Set this texture as dirty */
+		gl_dst_ptr->dirty_flag = TRUE;
+	    }
 	}
 
-	/* Copy the main memory texture into the surface that corresponds to the OpenGL
-	   texture object. */
-	memcpy(dst_d->lpSurface, src_d->lpSurface, src_d->u1.lPitch * src_d->dwHeight);
-
-	if (glThis != NULL) {
-	    /* If the GetHandle was not done, it is an error... */
-	    if (glThis->tex_name == 0) ERR("Unbound GL texture !!!\n");
+	src_ptr = get_sub_mimaplevel(src_ptr);
+	dst_ptr = get_sub_mimaplevel(dst_ptr);
 
-	    /* Set this texture as dirty */
-	    glThis->dirty_flag = TRUE;
+	if ((src_ptr == NULL) || (dst_ptr == NULL)) {
+	    if (src_ptr != dst_ptr) {
+	        ERR(" Loading surface with different mipmap structure !!!\n");
+	    }
+	    break;
 	}
     }
 
Index: dlls/ddraw/d3ddevice/main.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/d3ddevice/main.c,v
retrieving revision 1.38
diff -u -r1.38 main.c
--- dlls/ddraw/d3ddevice/main.c	15 Mar 2003 01:11:15 -0000	1.38
+++ dlls/ddraw/d3ddevice/main.c	9 May 2003 18:58:08 -0000
@@ -132,10 +132,10 @@
 };
 
 DWORD InitTextureStageStateTab[] = {
-    D3DTSS_COLOROP,          D3DTOP_DISABLE,
+    D3DTSS_COLOROP,          D3DTOP_DISABLE, /* Note, it's manually set for stage 0 */
     D3DTSS_COLORARG1,        D3DTA_TEXTURE,
     D3DTSS_COLORARG2,        D3DTA_CURRENT,
-    D3DTSS_ALPHAOP,          D3DTOP_DISABLE,
+    D3DTSS_ALPHAOP,          D3DTOP_DISABLE, /* Note, it's manually set for stage 0 */
     D3DTSS_ALPHAARG1,        D3DTA_TEXTURE,
     D3DTSS_ALPHAARG2,        D3DTA_CURRENT,
     /* FIXME: D3DTSS_BUMPENVMAT00,01,10,11 */
@@ -143,13 +143,13 @@
     D3DTSS_ADDRESS,          D3DTADDRESS_WRAP,
     D3DTSS_ADDRESSU,         D3DTADDRESS_WRAP,
     D3DTSS_ADDRESSV,         D3DTADDRESS_WRAP,
-    /* FIXME: D3DTSS_BORDERCOLOR */
+    D3DTSS_BORDERCOLOR,      0x00000000,
     D3DTSS_MAGFILTER,        D3DTFG_POINT,
     D3DTSS_MINFILTER,        D3DTFN_POINT,
     D3DTSS_MIPFILTER,        D3DTFP_NONE,
     D3DTSS_MIPMAPLODBIAS,    0x00000000, /* 0.0f */
-    D3DTSS_MAXMIPLEVEL,      0
-    /* FIXME: D3DTSS_MAXANISOTROPY */
+    D3DTSS_MAXMIPLEVEL,      0,
+    D3DTSS_MAXANISOTROPY,    1,
     /* FIXME: D3DTSS_BUMPENVLSCALE */
     /* FIXME: D3DTSS_NUMPENVLOFFSET */
     /* FIXME: D3DTSS_TEXTURETRANSFORMFLAGS */
@@ -158,21 +158,21 @@
 	
 void InitDefaultStateBlock(STATEBLOCK* lpStateBlock, int version)
 {
-    int i,j;  
+    int i, j;  
     TRACE("(%p,%d)\n", lpStateBlock, version);    
     memset(lpStateBlock, 0, sizeof(STATEBLOCK));
     
     /* Initialize render states */
-    for(i = 0; i < sizeof(InitRenderStateTab) / sizeof(InitRenderStateTab[0]); i += 2)
+    for (i = 0; i < sizeof(InitRenderStateTab) / sizeof(InitRenderStateTab[0]); i += 2)
     {
         lpStateBlock->render_state[InitRenderStateTab[i] - 1] = InitRenderStateTab[i + 1];
 	lpStateBlock->set_flags.render_state[InitRenderStateTab[i] - 1] = TRUE;
     }
 
     /* Initialize texture stages states */
-    for(i = 0; i < MAX_TEXTURES; i++)
+    for (i = 0; i < MAX_TEXTURES; i++)
     {
-       for(j = 0; j < sizeof(InitTextureStageStateTab) / sizeof(InitTextureStageStateTab[0]); j += 2)
+       for (j = 0; j < sizeof(InitTextureStageStateTab) / sizeof(InitTextureStageStateTab[0]); j += 2)
        {
            lpStateBlock->texture_stage_state[i][InitTextureStageStateTab[j] - 1] = InitTextureStageStateTab[j + 1];
            lpStateBlock->set_flags.texture_stage_state[i][InitTextureStageStateTab[j] - 1] = TRUE;
@@ -185,6 +185,8 @@
     /* The first texture is particular, update it consequently */
     lpStateBlock->texture_stage_state[0][D3DTSS_COLOROP - 1] = D3DTOP_MODULATE;
     lpStateBlock->texture_stage_state[0][D3DTSS_ALPHAOP - 1] = D3DTOP_SELECTARG1;
+    lpStateBlock->texture_stage_state[0][D3DTSS_COLORARG2 - 1] = D3DTA_DIFFUSE;
+    lpStateBlock->texture_stage_state[0][D3DTSS_ALPHAARG2 - 1] = D3DTA_DIFFUSE;
     
     /* Updates for particular versions */
     if ((version == 1) || (version==2))
Index: dlls/ddraw/d3ddevice/mesa.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/d3ddevice/mesa.c,v
retrieving revision 1.93
diff -u -r1.93 mesa.c
--- dlls/ddraw/d3ddevice/mesa.c	8 May 2003 21:03:57 -0000	1.93
+++ dlls/ddraw/d3ddevice/mesa.c	9 May 2003 18:58:09 -0000
@@ -327,6 +327,8 @@
 	    if (This->current_texture[i] != NULL)
 	        IDirectDrawSurface7_Release(ICOM_INTERFACE(This->current_texture[i], IDirectDrawSurface7));
 
+	/* TODO: remove the 'callbacks' for Flip and Lock/Unlock */
+	
 	/* And warn the D3D object that this device is no longer active... */
 	This->d3d->removed_device(This->d3d, This);
 
@@ -334,6 +336,8 @@
 	HeapFree(GetProcessHeap(), 0, This->view_mat);
 	HeapFree(GetProcessHeap(), 0, This->proj_mat);
 
+	DeleteCriticalSection(&(This->crit));
+	
 	ENTER_GL();
 	glXDestroyContext(glThis->display, glThis->gl_context);
 	LEAVE_GL();
@@ -408,6 +412,18 @@
     if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
     if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
 
+#if 0 /* Enabling this breaks Tomb Raider 3, need to investigate... */
+    TRACE("Enumerating GL_RGB unpacked (32)\n");
+    pformat->dwFlags = DDPF_RGB;
+    pformat->u1.dwRGBBitCount = 32;
+    pformat->u2.dwRBitMask =        0x00FF0000;
+    pformat->u3.dwGBitMask =        0x0000FF00;
+    pformat->u4.dwBBitMask =        0x000000FF;
+    pformat->u5.dwRGBAlphaBitMask = 0x00000000;
+    if (cb_1) if (cb_1(&sdesc , context) == 0) return DD_OK;
+    if (cb_2) if (cb_2(pformat, context) == 0) return DD_OK;
+#endif
+    
     TRACE("Enumerating GL_RGB unpacked (24)\n");
     pformat->dwFlags = DDPF_RGB;
     pformat->u1.dwRGBBitCount = 24;
@@ -847,7 +835,7 @@
 	} break;
 
         default:
-	    FIXME("Unhandled vertex type\n");
+	    FIXME("Unhandled vertex type %08x\n", d3dvt);
 	    break;
     }
 }
@@ -1051,6 +1040,10 @@
     BOOLEAN vertex_lighted = FALSE;
     IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This;
 
+    /* This is to prevent 'thread contention' between a thread locking the device and another
+       doing 3D display on it... */
+    EnterCriticalSection(&(This->crit));   
+    
     if (TRACE_ON(ddraw)) {
         TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType);
     }
@@ -1232,6 +1225,8 @@
 
     LEAVE_GL();
     TRACE("End\n");    
+
+    LeaveCriticalSection(&(This->crit));
 }
 
 HRESULT WINAPI
@@ -1396,20 +1391,28 @@
 }
 
 static GLenum
-convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwState)
+convert_min_filter_to_GL(D3DTEXTUREMINFILTER dwMinState, D3DTEXTUREMIPFILTER dwMipState)
 {
     GLenum gl_state;
 
-    switch (dwState) {
-        case D3DTFN_POINT:
-	    gl_state = GL_NEAREST;
-	    break;
-        case D3DTFN_LINEAR:
-	    gl_state = GL_LINEAR;
-	    break;
-        default:
-	    gl_state = GL_LINEAR;
-	    break;
+    if (dwMipState == D3DTFP_NONE) {
+        switch (dwMinState) {
+            case D3DTFN_POINT:  gl_state = GL_NEAREST; break;
+	    case D3DTFN_LINEAR: gl_state = GL_LINEAR;  break;
+	    default:            gl_state = GL_LINEAR;  break;
+	}
+    } else if (dwMipState == D3DTFP_POINT) {
+        switch (dwMinState) {
+            case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_NEAREST; break;
+	    case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
+	    default:            gl_state = GL_LINEAR_MIPMAP_NEAREST;  break;
+	}
+    } else {
+        switch (dwMinState) {
+            case D3DTFN_POINT:  gl_state = GL_NEAREST_MIPMAP_LINEAR; break;
+	    case D3DTFN_LINEAR: gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
+	    default:            gl_state = GL_LINEAR_MIPMAP_LINEAR;  break;
+	}
     }
     return gl_state;
 }
@@ -1433,6 +1436,73 @@
     return gl_state;
 }
 
+/* We need a static function for that to handle the 'special' case of 'SELECT_ARG2' */
+static BOOLEAN
+handle_color_alpha_args(DWORD dwStage, D3DTEXTURESTAGESTATETYPE d3dTexStageStateType, DWORD dwState, D3DTEXTUREOP tex_op)
+{
+    BOOLEAN is_complement = FALSE;
+    BOOLEAN is_alpha_replicate = FALSE;
+    BOOLEAN handled = TRUE;
+    GLenum src;
+    BOOLEAN is_color = ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2));
+    int num;
+    
+    if (is_color) {
+        if (d3dTexStageStateType == D3DTSS_COLORARG1) num = 0;
+	else if (d3dTexStageStateType == D3DTSS_COLORARG2) num = 1;
+	else {
+	    handled = FALSE;
+	    num = 0;
+	}
+	if (tex_op == D3DTOP_SELECTARG2) {
+	    num = 1 - num;
+	}
+    } else {
+        if (d3dTexStageStateType == D3DTSS_ALPHAARG1) num = 0;
+	else if (d3dTexStageStateType == D3DTSS_ALPHAARG2) num = 1;
+	else {
+	    handled = FALSE;
+	    num = 0;
+	}
+	if (tex_op == D3DTOP_SELECTARG2) {
+	    num = 1 - num;
+	}
+    }
+    
+    if (dwState & D3DTA_COMPLEMENT) {
+        is_complement = TRUE;
+    }
+    if (dwState & D3DTA_ALPHAREPLICATE) {
+	is_alpha_replicate = TRUE;
+    }
+    dwState &= D3DTA_SELECTMASK;
+    if ((dwStage == 0) && (dwState == D3DTA_CURRENT)) {
+        dwState = D3DTA_DIFFUSE;
+    }
+
+    switch (dwState) {
+        case D3DTA_CURRENT: src = GL_PREVIOUS_EXT; break;
+	case D3DTA_DIFFUSE: src = GL_PRIMARY_COLOR_ARB; break;
+	case D3DTA_TEXTURE: src = GL_TEXTURE; break;
+	case D3DTA_TFACTOR: src = GL_CONSTANT_ARB; FIXME(" no handling yet of setting of constant value !\n"); break;
+	default: src = GL_TEXTURE; handled = FALSE; break;
+    }
+
+    if (is_color) {
+        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB + num, src);
+	if (is_alpha_replicate) {
+	    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
+	} else {
+	    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB + num, is_complement ? GL_ONE_MINUS_SRC_COLOR : GL_SRC_COLOR);
+	}
+    } else {
+        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB + num, src);
+	glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB + num, is_complement ? GL_ONE_MINUS_SRC_ALPHA : GL_SRC_ALPHA);
+    }
+
+    return handled;
+}
+
 HRESULT WINAPI
 GL_IDirect3DDeviceImpl_7_3T_SetTextureStageState(LPDIRECT3DDEVICE7 iface,
 						 DWORD dwStage,
@@ -1440,63 +1510,83 @@
 						 DWORD dwState)
 {
     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
+    const char *type;
+    DWORD prev_state;
     
     TRACE("(%p/%p)->(%08lx,%08x,%08lx)\n", This, iface, dwStage, d3dTexStageStateType, dwState);
 
     if (dwStage > 0) return DD_OK; /* We nothing in this case for now */
 
-    if (TRACE_ON(ddraw)) {
-        TRACE(" Stage type is : ");
-	switch (d3dTexStageStateType) {
-#define GEN_CASE(a) case a: TRACE(#a " "); break
-	    GEN_CASE(D3DTSS_COLOROP);
-	    GEN_CASE(D3DTSS_COLORARG1);
-	    GEN_CASE(D3DTSS_COLORARG2);
-	    GEN_CASE(D3DTSS_ALPHAOP);
-	    GEN_CASE(D3DTSS_ALPHAARG1);
-	    GEN_CASE(D3DTSS_ALPHAARG2);
-	    GEN_CASE(D3DTSS_BUMPENVMAT00);
-	    GEN_CASE(D3DTSS_BUMPENVMAT01);
-	    GEN_CASE(D3DTSS_BUMPENVMAT10);
-	    GEN_CASE(D3DTSS_BUMPENVMAT11);
-	    GEN_CASE(D3DTSS_TEXCOORDINDEX);
-	    GEN_CASE(D3DTSS_ADDRESS);
-	    GEN_CASE(D3DTSS_ADDRESSU);
-	    GEN_CASE(D3DTSS_ADDRESSV);
-	    GEN_CASE(D3DTSS_BORDERCOLOR);
-	    GEN_CASE(D3DTSS_MAGFILTER);
-	    GEN_CASE(D3DTSS_MINFILTER);
-	    GEN_CASE(D3DTSS_MIPFILTER);
-	    GEN_CASE(D3DTSS_MIPMAPLODBIAS);
-	    GEN_CASE(D3DTSS_MAXMIPLEVEL);
-	    GEN_CASE(D3DTSS_MAXANISOTROPY);
-	    GEN_CASE(D3DTSS_BUMPENVLSCALE);
-	    GEN_CASE(D3DTSS_BUMPENVLOFFSET);
-	    GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
+    switch (d3dTexStageStateType) {
+#define GEN_CASE(a) case a: type = #a; break
+        GEN_CASE(D3DTSS_COLOROP);
+	GEN_CASE(D3DTSS_COLORARG1);
+	GEN_CASE(D3DTSS_COLORARG2);
+	GEN_CASE(D3DTSS_ALPHAOP);
+	GEN_CASE(D3DTSS_ALPHAARG1);
+	GEN_CASE(D3DTSS_ALPHAARG2);
+	GEN_CASE(D3DTSS_BUMPENVMAT00);
+	GEN_CASE(D3DTSS_BUMPENVMAT01);
+	GEN_CASE(D3DTSS_BUMPENVMAT10);
+	GEN_CASE(D3DTSS_BUMPENVMAT11);
+	GEN_CASE(D3DTSS_TEXCOORDINDEX);
+	GEN_CASE(D3DTSS_ADDRESS);
+	GEN_CASE(D3DTSS_ADDRESSU);
+	GEN_CASE(D3DTSS_ADDRESSV);
+	GEN_CASE(D3DTSS_BORDERCOLOR);
+	GEN_CASE(D3DTSS_MAGFILTER);
+	GEN_CASE(D3DTSS_MINFILTER);
+	GEN_CASE(D3DTSS_MIPFILTER);
+	GEN_CASE(D3DTSS_MIPMAPLODBIAS);
+	GEN_CASE(D3DTSS_MAXMIPLEVEL);
+	GEN_CASE(D3DTSS_MAXANISOTROPY);
+	GEN_CASE(D3DTSS_BUMPENVLSCALE);
+	GEN_CASE(D3DTSS_BUMPENVLOFFSET);
+	GEN_CASE(D3DTSS_TEXTURETRANSFORMFLAGS);
 #undef GEN_CASE
-	    default: TRACE("UNKNOWN !!!");
-	}
-	TRACE(" => ");
+        default: type = "UNKNOWN";
     }
 
+    /* Store the values in the state array */
+    prev_state = This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1];
+    This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
+    /* Some special cases when one state modifies more than one... */
+    if (d3dTexStageStateType == D3DTSS_ADDRESS) {
+        This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
+	This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
+    }
+    
     switch (d3dTexStageStateType) {
         case D3DTSS_MINFILTER:
+        case D3DTSS_MIPFILTER:
 	    if (TRACE_ON(ddraw)) {
-	        switch ((D3DTEXTUREMINFILTER) dwState) {
-	            case D3DTFN_POINT:  TRACE("D3DTFN_POINT\n"); break;
-		    case D3DTFN_LINEAR: TRACE("D3DTFN_LINEAR\n"); break;
-		    default: TRACE(" state unhandled (%ld).\n", dwState); break;
+	        if (d3dTexStageStateType == D3DTSS_MINFILTER) {
+		    switch ((D3DTEXTUREMINFILTER) dwState) {
+	                case D3DTFN_POINT:  TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_POINT\n"); break;
+			case D3DTFN_LINEAR: TRACE(" Stage type is : D3DTSS_MINFILTER => D3DTFN_LINEAR\n"); break;
+			default: FIXME(" Unhandled stage type : D3DTSS_MINFILTER => %08lx\n", dwState); break;
+		    }
+		} else {
+		    switch ((D3DTEXTUREMIPFILTER) dwState) {
+	                case D3DTFP_NONE:   TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_NONE\n"); break;
+			case D3DTFP_POINT:  TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_POINT\n"); break;
+			case D3DTFP_LINEAR: TRACE(" Stage type is : D3DTSS_MIPFILTER => D3DTFP_LINEAR\n"); break;
+			default: FIXME(" Unhandled stage type : D3DTSS_MIPFILTER => %08lx\n", dwState); break;
+		    }
 		}
 	    }
-	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, convert_min_filter_to_GL(dwState));
-            break;
+
+	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+			    convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1],
+						     This->state_block.texture_stage_state[dwStage][D3DTSS_MIPFILTER - 1]));
+	    break;
 	    
         case D3DTSS_MAGFILTER:
 	    if (TRACE_ON(ddraw)) {
 	        switch ((D3DTEXTUREMAGFILTER) dwState) {
-	            case D3DTFG_POINT:  TRACE("D3DTFN_POINT\n"); break;
-		    case D3DTFG_LINEAR: TRACE("D3DTFN_LINEAR\n"); break;
-		    default: TRACE(" state unhandled (%ld).\n", dwState); break;
+	            case D3DTFG_POINT:  TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_POINT\n"); break;
+		    case D3DTFG_LINEAR: TRACE(" Stage type is : D3DTSS_MAGFILTER => D3DTFN_LINEAR\n"); break;
+		    default: FIXME(" Unhandled stage type : D3DTSS_MAGFILTER => %08lx\n", dwState); break;
 		}
 	    }
 	    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, convert_mag_filter_to_GL(dwState));
@@ -1507,10 +1597,15 @@
         case D3DTSS_ADDRESSV: {
 	    GLenum arg = GL_REPEAT; /* Default value */
 	    switch ((D3DTEXTUREADDRESS) dwState) {
-	        case D3DTADDRESS_WRAP:   if (TRACE_ON(ddraw)) TRACE("D3DTADDRESS_WRAP\n"); arg = GL_REPEAT; break;
-	        case D3DTADDRESS_CLAMP:  if (TRACE_ON(ddraw)) TRACE("D3DTADDRESS_CLAMP\n"); arg = GL_CLAMP; break;
-	        case D3DTADDRESS_BORDER: if (TRACE_ON(ddraw)) TRACE("D3DTADDRESS_BORDER\n"); arg = GL_CLAMP_TO_EDGE; break;
-	        default: TRACE(" state unhandled (%ld).\n", dwState);
+	        case D3DTADDRESS_WRAP:   TRACE(" Stage type is : %s => D3DTADDRESS_WRAP\n", type); arg = GL_REPEAT; break;
+	        case D3DTADDRESS_CLAMP:  TRACE(" Stage type is : %s => D3DTADDRESS_CLAMP\n", type); arg = GL_CLAMP; break;
+	        case D3DTADDRESS_BORDER: TRACE(" Stage type is : %s => D3DTADDRESS_BORDER\n", type); arg = GL_CLAMP_TO_EDGE; break;
+#if defined(GL_VERSION_1_4)
+		case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); arg = GL_MIRRORED_REPEAT; break;
+#elif defined(GL_ARB_texture_mirrored_repeat)
+		case D3DTADDRESS_MIRROR: TRACE(" Stage type is : %s => D3DTADDRESS_MIRROR\n", type); arg = GL_MIRRORED_REPEAT_ARB; break;
+#endif
+	        default: FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState); break;
 	    }
 	    if ((d3dTexStageStateType == D3DTSS_ADDRESS) ||
 		(d3dTexStageStateType == D3DTSS_ADDRESSU))
@@ -1519,18 +1614,174 @@
 		(d3dTexStageStateType == D3DTSS_ADDRESSV))
 	        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, arg);
         } break;
+
+	case D3DTSS_ALPHAOP:
+	case D3DTSS_COLOROP: {
+            int scale = 1;
+            GLenum parm = (d3dTexStageStateType == D3DTSS_ALPHAOP) ? GL_COMBINE_ALPHA_ARB : GL_COMBINE_RGB_ARB;
+	    const char *value;
+	    int handled = 1;
+	    
+	    switch (dwState) {
+#define GEN_CASE(a) case a: value = #a; break
+	        GEN_CASE(D3DTOP_DISABLE);
+		GEN_CASE(D3DTOP_SELECTARG1);
+		GEN_CASE(D3DTOP_SELECTARG2);
+		GEN_CASE(D3DTOP_MODULATE);
+		GEN_CASE(D3DTOP_MODULATE2X);
+		GEN_CASE(D3DTOP_MODULATE4X);
+		GEN_CASE(D3DTOP_ADD);
+		GEN_CASE(D3DTOP_ADDSIGNED);
+		GEN_CASE(D3DTOP_ADDSIGNED2X);
+		GEN_CASE(D3DTOP_SUBTRACT);
+		GEN_CASE(D3DTOP_ADDSMOOTH);
+		GEN_CASE(D3DTOP_BLENDDIFFUSEALPHA);
+		GEN_CASE(D3DTOP_BLENDTEXTUREALPHA);
+		GEN_CASE(D3DTOP_BLENDFACTORALPHA);
+		GEN_CASE(D3DTOP_BLENDTEXTUREALPHAPM);
+		GEN_CASE(D3DTOP_BLENDCURRENTALPHA);
+		GEN_CASE(D3DTOP_PREMODULATE);
+		GEN_CASE(D3DTOP_MODULATEALPHA_ADDCOLOR);
+		GEN_CASE(D3DTOP_MODULATECOLOR_ADDALPHA);
+		GEN_CASE(D3DTOP_MODULATEINVALPHA_ADDCOLOR);
+		GEN_CASE(D3DTOP_MODULATEINVCOLOR_ADDALPHA);
+		GEN_CASE(D3DTOP_BUMPENVMAP);
+		GEN_CASE(D3DTOP_BUMPENVMAPLUMINANCE);
+		GEN_CASE(D3DTOP_DOTPRODUCT3);
+		GEN_CASE(D3DTOP_FORCE_DWORD);
+#undef GEN_CASE
+	        default: value = "UNKNOWN";
+	    }
+
+            if ((d3dTexStageStateType == D3DTSS_COLOROP) && (dwState == D3DTOP_DISABLE) && (dwStage == 0)) {
+                glDisable(GL_TEXTURE_2D);
+		TRACE(" disabling 2D texturing.\n");
+            } else {
+	        /* Re-enable texturing */
+	        if ((dwStage == 0) && (This->current_texture[0] != NULL)) {
+		    glEnable(GL_TEXTURE_2D);
+		    TRACE(" enabling 2D texturing.\n");
+		}
+		
+                /* Re-Enable GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB */
+                if (dwState != D3DTOP_DISABLE) {
+                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+                }
+
+                /* Now set up the operand correctly */
+                switch (dwState) {
+                    case D3DTOP_DISABLE:
+		        /* Contrary to the docs, alpha can be disabled when colorop is enabled
+			   and it works, so ignore this op */
+		        TRACE(" Note : disable ALPHAOP but COLOROP enabled!\n");
+			break;
+
+		    case D3DTOP_SELECTARG1:
+		    case D3DTOP_SELECTARG2:
+			glTexEnvi(GL_TEXTURE_ENV, parm, GL_REPLACE);
+			break;
+			
+		    case D3DTOP_MODULATE4X:
+			scale = scale * 2;  /* Drop through */
+		    case D3DTOP_MODULATE2X:
+			scale = scale * 2;  /* Drop through */
+		    case D3DTOP_MODULATE:
+			glTexEnvi(GL_TEXTURE_ENV, parm, GL_MODULATE);
+			break;
+
+		    case D3DTOP_ADD:
+			glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD);
+			break;
+
+		    case D3DTOP_ADDSIGNED2X:
+			scale = scale * 2;  /* Drop through */
+		    case D3DTOP_ADDSIGNED:
+			glTexEnvi(GL_TEXTURE_ENV, parm, GL_ADD_SIGNED_ARB);
+			break;
+
+		    default:
+			handled = FALSE;
+			break;
+                }
+            }
+
+	    if (((prev_state == D3DTOP_SELECTARG2) && (dwState != D3DTOP_SELECTARG2)) ||
+		((dwState == D3DTOP_SELECTARG2) && (prev_state != D3DTOP_SELECTARG2))) {
+	        /* Switch the arguments if needed... */
+	        if (d3dTexStageStateType == D3DTSS_COLOROP) {
+		    handle_color_alpha_args(dwStage, D3DTSS_COLORARG1,
+					    This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG1 - 1],
+					    dwState);
+		    handle_color_alpha_args(dwStage, D3DTSS_COLORARG2,
+					    This->state_block.texture_stage_state[dwStage][D3DTSS_COLORARG2 - 1],
+					    dwState);
+		} else {
+		    handle_color_alpha_args(dwStage, D3DTSS_ALPHAARG1,
+					    This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG1 - 1],
+					    dwState);
+		    handle_color_alpha_args(dwStage, D3DTSS_ALPHAARG2,
+					    This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAARG2 - 1],
+					    dwState);
+		}
+	    }
+	    
+	    if (handled) {
+	        if (d3dTexStageStateType == D3DTSS_ALPHAOP) {
+		    glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale);
+		} else {
+		    glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, scale);
+		}			
+		TRACE(" Stage type is : %s => %s\n", type, value);
+	    } else {
+	        FIXME(" Unhandled stage type is : %s => %s\n", type, value);
+	    }
+        } break;
+
+	case D3DTSS_COLORARG1:
+	case D3DTSS_COLORARG2:
+	case D3DTSS_ALPHAARG1:
+	case D3DTSS_ALPHAARG2: {
+	    const char *value, *value_comp = "", *value_alpha = "";
+	    BOOLEAN handled;
+	    D3DTEXTUREOP tex_op;
+	    
+	    switch (dwState & D3DTA_SELECTMASK) {
+#define GEN_CASE(a) case a: value = #a; break
+	        GEN_CASE(D3DTA_DIFFUSE);
+		GEN_CASE(D3DTA_CURRENT);
+		GEN_CASE(D3DTA_TEXTURE);
+		GEN_CASE(D3DTA_TFACTOR);
+	        GEN_CASE(D3DTA_SPECULAR);
+#undef GEN_CASE
+	        default: value = "UNKNOWN";
+	    }
+	    if (dwState & D3DTA_COMPLEMENT) {
+	        value_comp = " | D3DTA_COMPLEMENT";
+	    }
+	    if (dwState & D3DTA_ALPHAREPLICATE) {
+	        value_alpha = " | D3DTA_ALPHAREPLICATE";
+	    }
+
+	    if ((d3dTexStageStateType == D3DTSS_COLORARG1) || (d3dTexStageStateType == D3DTSS_COLORARG2)) {
+	        tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1];
+	    } else {
+	        tex_op = This->state_block.texture_stage_state[dwStage][D3DTSS_ALPHAOP - 1];
+	    }
+	    
+	    handled = handle_color_alpha_args(dwStage, d3dTexStageStateType, dwState, tex_op);
+	    
+	    if (handled) {
+	        TRACE(" Stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
+	    } else {
+	        FIXME(" Unhandled stage type : %s => %s%s%s\n", type, value, value_comp, value_alpha);
+	    }
+	} break;
 	    
 	default:
-	    if (TRACE_ON(ddraw)) TRACE(" unhandled.\n");
+	    FIXME(" Unhandled stage type : %s => %08lx\n", type, dwState);
+	    break;
     }
    
-    This->state_block.texture_stage_state[dwStage][d3dTexStageStateType - 1] = dwState;
-    /* Some special cases when one state modifies more than one... */
-    if (d3dTexStageStateType == D3DTSS_ADDRESS) {
-        This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSU - 1] = dwState;
-	This->state_block.texture_stage_state[dwStage][D3DTSS_ADDRESSV - 1] = dwState;
-    }
-
     return DD_OK;
 }
 
@@ -1558,17 +1809,30 @@
         glDisable(GL_TEXTURE_2D);
     } else {
         IDirectDrawSurfaceImpl *tex_impl = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, lpTexture2);
+	GLint max_mip_level;
 	
 	This->current_texture[dwStage] = tex_impl;
 	IDirectDrawSurface7_AddRef(ICOM_INTERFACE(tex_impl, IDirectDrawSurface7)); /* Not sure about this either */
-	
-        glEnable(GL_TEXTURE_2D);
+
+	if (This->state_block.texture_stage_state[dwStage][D3DTSS_COLOROP - 1] != D3DTOP_DISABLE) {
+	    /* Do not re-enable texturing if it was disabled due to the COLOROP code */
+	    glEnable(GL_TEXTURE_2D);
+	    TRACE(" enabling 2D texturing.\n");
+	}
 	gltex_upload_texture(tex_impl);
 
+	if ((tex_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) == 0) {
+	    max_mip_level = 0;
+	} else {
+	    max_mip_level = tex_impl->surface_desc.u2.dwMipMapCount - 1;
+	}
+	
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
 			convert_mag_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MAGFILTER - 1]));
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
-			convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1]));
+			convert_min_filter_to_GL(This->state_block.texture_stage_state[dwStage][D3DTSS_MINFILTER - 1],
+						  This->state_block.texture_stage_state[dwStage][D3DTSS_MIPFILTER - 1]));
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_mip_level);
     }
     LEAVE_GL();
     
@@ -2137,18 +2401,22 @@
 */
 static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags)
 {
-    /* First, check if we need to do anything */
+    /* Try to acquire the device critical section */
+    EnterCriticalSection(&(This->d3ddevice->crit));
+
+    /* Then check if we need to do anything */
     if ((This->lastlocktype & DDLOCK_WRITEONLY) == 0) {
         GLenum buffer_type;
 	GLenum prev_read;
 	RECT loc_rect;
 
+        WARN(" application does a lock on a 3D surface - expect slow downs.\n");
+	
 	ENTER_GL();
 
 	glGetIntegerv(GL_READ_BUFFER, &prev_read);
 	glFlush();
 	
-        WARN(" application does a lock on a 3D surface - expect slow downs.\n");
 	if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
 	    /* Application wants to lock the front buffer */
 	    glReadBuffer(GL_FRONT);
@@ -2174,10 +2442,12 @@
 	} else {
 	    loc_rect = *pRect;
 	}
+#if 0
 	glReadPixels(loc_rect.left, loc_rect.top, loc_rect.right, loc_rect.bottom,
 		     GL_RGB, buffer_type, ((char *)This->surface_desc.lpSurface
 					   + loc_rect.top * This->surface_desc.u1.lPitch
 					   + loc_rect.left * GET_BPP(This->surface_desc)));
+#endif
 	glReadBuffer(prev_read);
 	LEAVE_GL();
     }
@@ -2190,11 +2460,12 @@
         GLenum buffer_type;
 	GLenum prev_draw;
 
+        WARN(" application does an unlock on a 3D surface - expect slow downs.\n");
+	
 	ENTER_GL();
 
 	glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
 
-        WARN(" application does an unlock on a 3D surface - expect slow downs.\n");
 	if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) {
 	    /* Application wants to lock the front buffer */
 	    glDrawBuffer(GL_FRONT);
@@ -2210,17 +2481,41 @@
 	} else {
 	    WARN(" unsupported pixel format.\n");
 	    LEAVE_GL();
+	    
+	    /* And 'frees' the device critical section */
+	    LeaveCriticalSection(&(This->d3ddevice->crit));
 	    return;
 	}
 	glRasterPos2f(0.0, 0.0);
+#if 0
 	glDrawPixels(This->surface_desc.dwWidth, This->surface_desc.dwHeight, 
 		     GL_RGB, buffer_type, This->surface_desc.lpSurface);
+#endif
 	glDrawBuffer(prev_draw);
 
 	LEAVE_GL();
    }
+
+    /* And 'frees' the device critical section */
+    LeaveCriticalSection(&(This->d3ddevice->crit));
 }
 
+static void
+apply_texture_state(IDirect3DDeviceImpl *This)
+{
+    int stage, state;
+    
+    /* Initialize texture stages states */
+    for (stage = 0; stage < MAX_TEXTURES; stage++) {
+       for (state = 0; state < HIGHEST_TEXTURE_STAGE_STATE; state += 1) {
+	   if (This->state_block.set_flags.texture_stage_state[stage][state] == TRUE) {
+	       IDirect3DDevice7_SetTextureStageState(ICOM_INTERFACE(This, IDirect3DDevice7),
+						     stage, state + 1, This->state_block.texture_stage_state[stage][state]);
+	   }
+       }
+    }
+}     
+
 HRESULT
 d3ddevice_create(IDirect3DDeviceImpl **obj, IDirect3DImpl *d3d, IDirectDrawSurfaceImpl *surface)
 {
@@ -2248,6 +2543,8 @@
     object->set_matrices = d3ddevice_set_matrices;
     object->matrices_updated = d3ddevice_matrices_updated;
 
+    InitializeCriticalSection(&(object->crit));
+    
     TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d);
 
     device_context = GetDC(surface->ddraw_owner->window);
@@ -2295,18 +2592,26 @@
         buffer = GL_FRONT;
     }
     
-    for (surf = surface; surf->prev_attached != NULL; surf = surf->prev_attached) ;
-    for (; surf != NULL; surf = surf->next_attached) {
-        if (((surf->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
-	    ((surf->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
-	    /* Override the Lock / Unlock function for all these surfaces */
-	    surf->lock_update = d3ddevice_lock_update;
-	    surf->unlock_update = d3ddevice_unlock_update;
-	    /* And install also the blt / bltfast overrides */
-	    surf->aux_blt = d3ddevice_blt;
-	    surf->aux_bltfast = d3ddevice_bltfast;
+    for (surf = surface; surf != NULL; surf = surf->surface_owner) {
+        IDirectDrawSurfaceImpl *surf2;
+	for (surf2 = surf; surf2->prev_attached != NULL; surf2 = surf2->prev_attached) ;
+	for (; surf2 != NULL; surf2 = surf2->next_attached) {
+	    TRACE(" checking surface %p :", surf2);
+	    if (((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) &&
+		((surf2->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) {
+	        /* Override the Lock / Unlock function for all these surfaces */
+	        surf2->lock_update = d3ddevice_lock_update;
+		surf2->unlock_update = d3ddevice_unlock_update;
+		/* And install also the blt / bltfast overrides */
+		surf2->aux_blt = d3ddevice_blt;
+		surf2->aux_bltfast = d3ddevice_bltfast;
+		
+		TRACE(" overiding direct surface access.\n");
+	    } else {
+	        TRACE(" no overide.\n");
+	    }
+	    surf2->d3ddevice = object;
 	}
-	surf->d3ddevice = object;
     }
 
     /* Set the various light parameters */
@@ -2369,9 +2672,9 @@
 
     /* FIXME: Should handle other versions than just 7 */
     InitDefaultStateBlock(&object->state_block, 7);
-    /* Apply default render state values */
+    /* Apply default render state and texture stage state values */
     apply_render_state(object, &object->state_block);
-    /* FIXME: do something similar for ligh_state and texture_stage_state */
+    apply_texture_state(object);
 
     /* And fill the fog table with the default fog value */
     build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]);

[Index of Archives]     [Gimp for Windows]     [Red Hat]     [Samba]     [Yosemite Camping]     [Graphics Cards]     [Wine Home]

  Powered by Linux