[D3D] Better color keying.

Lionel Ulmer lionel.ulmer at free.fr
Mon Nov 10 12:45:05 CST 2003


With this, MotoRacer2 has proper color keying. It works fine in ARX Fatalis
too now. Could no regression test on some games which do not start anymore
(ah, gotta love regressions :-) ).

It should fix the Carmageddon problems too...

         Lionel

Changelog:
 - better color-keying support

-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
--- dlls/ddraw_CVS/d3ddevice/mesa.c	Sun Nov  9 00:08:23 2003
+++ dlls/ddraw/d3ddevice/mesa.c	Mon Nov 10 19:39:50 2003
@@ -163,10 +163,8 @@
     if (gl_d3d_dev->cull_face != FALSE) glDisable(GL_CULL_FACE);
     if (use_alpha) {
 	if (gl_d3d_dev->alpha_test == FALSE) glEnable(GL_ALPHA_TEST);
-	if (((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) != 0x00) ||
-	    ((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]) != D3DCMP_GREATER)) {
-	    glAlphaFunc(GL_GREATER, 0.0);
-	}
+	if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
+	    glAlphaFunc(GL_NOTEQUAL, 0.0);
     } else {
 	if (gl_d3d_dev->alpha_test != FALSE) glDisable(GL_ALPHA_TEST);
     }
@@ -190,11 +188,8 @@
     else if ((gl_d3d_dev->alpha_test == 0) && (use_alpha != 0))
 	glDisable(GL_ALPHA_TEST);
     if (use_alpha) {
-	if (((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) != 0x00) ||
-	    ((d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]) != D3DCMP_GREATER)) {
-	    glAlphaFunc(convert_D3D_compare_to_GL(d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAFUNC - 1]),
-			(d3d_dev->state_block.render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) / 255.0);
-	}
+	if ((gl_d3d_dev->current_alpha_test_func != GL_NOTEQUAL) || (gl_d3d_dev->current_alpha_test_ref != 0.0))
+	    glAlphaFunc(gl_d3d_dev->current_alpha_test_func, gl_d3d_dev->current_alpha_test_ref);
     }
     if (gl_d3d_dev->stencil_test != 0) glEnable(GL_STENCIL_TEST);
     if (gl_d3d_dev->cull_face != 0) glEnable(GL_CULL_FACE);
@@ -2152,6 +2147,7 @@
 {
     IDirect3DDeviceGLImpl *glThis = (IDirect3DDeviceGLImpl *) This;
     DWORD stage;
+    BOOLEAN enable_colorkey = FALSE;
     
     for (stage = 0; stage < MAX_TEXTURES; stage++) {
 	IDirectDrawSurfaceImpl *surf_ptr = This->current_texture[stage];
@@ -2208,8 +2204,57 @@
 	   This will also update the various texture parameters if needed.
 	*/
 	gltex_upload_texture(surf_ptr, This, stage);
+
+	/* And finally check for color-keying (only on first stage) */
+	if (This->current_texture[stage]->surface_desc.dwFlags & DDSD_CKSRCBLT) {
+	    if (stage == 0) {
+		enable_colorkey = TRUE;
+	    } else {
+		static BOOL warn = FALSE;
+		if (warn == FALSE) {
+		    warn = TRUE;
+		    WARN(" Surface has color keying on stage different from 0 (%ld) !", stage);
+		}
+	    }
+	} else {
+	    if (stage == 0) {
+		enable_colorkey = FALSE;
+	    }
+	}
     }
 
+    /* Apparently, whatever the state of BLEND, color keying is always activated for 'old' D3D versions */
+    if (((This->state_block.render_state[D3DRENDERSTATE_COLORKEYENABLE - 1]) ||
+	 (glThis->version == 1)) &&
+	(enable_colorkey)) {
+	TRACE(" colorkey activated.\n");
+	
+	if (glThis->alpha_test == FALSE) {
+	    glEnable(GL_ALPHA_TEST);
+	    glThis->alpha_test = TRUE;
+	}
+	if ((glThis->current_alpha_test_func != GL_NOTEQUAL) || (glThis->current_alpha_test_ref != 0.0)) {
+	    if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == TRUE) {
+		static BOOL warn = FALSE;
+		if (warn == FALSE) {
+		    warn = TRUE;
+		    WARN(" Overriding application-given alpha test values - some graphical glitches may appear !\n");
+		}
+	    }
+	    glThis->current_alpha_test_func = GL_NOTEQUAL;
+	    glThis->current_alpha_test_ref = 0.0;
+	    glAlphaFunc(GL_NOTEQUAL, 0.0);
+	}
+	/* Some sanity checks should be added here if a game mixes alphatest + color keying...
+	   Only one has been found for now, and the ALPHAFUNC is 'Always' so it works :-) */
+    } else {
+	if (This->state_block.render_state[D3DRENDERSTATE_ALPHATESTENABLE - 1] == FALSE) {
+	    glDisable(GL_ALPHA_TEST);
+	    glThis->alpha_test = FALSE;
+	}
+	/* Maybe we should restore here the application-given alpha test states ? */
+    }
+    
     return stage;
 }
 
@@ -3712,7 +3757,7 @@
 }     
 
 HRESULT
-d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface)
+d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, BOOLEAN from_surface)
 {
     IDirect3DDeviceImpl *object;
     IDirect3DDeviceGLImpl *gl_object;
@@ -3744,7 +3789,14 @@
     InitializeCriticalSection(&(object->crit));
 
     TRACE(" device critical section : %p\n", &(object->crit));
-    
+
+    /* This is just a hack for some badly done games :-/ */
+    if (from_surface) {
+	gl_object->version = 1;
+	TRACE(" using D3D1 special hacks.\n");
+    } else
+	gl_object->version = 7;
+
     device_context = GetDC(surface->ddraw_owner->window);
     gl_object->display = get_display(device_context);
     gl_object->drawable = get_drawable(device_context);
@@ -3868,6 +3920,9 @@
     if (GL_extensions.glActiveTexture != NULL) {
 	GL_extensions.glActiveTexture(GL_TEXTURE0_WINE);
     }
+    gl_object->current_alpha_test_ref = 0.0;
+    gl_object->current_alpha_test_func = GL_ALWAYS;
+    glAlphaFunc(GL_ALWAYS, 0.0);
     
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     glDrawBuffer(buffer);
--- dlls/ddraw_CVS/direct3d/mesa.c	Sat Sep  6 14:09:45 2003
+++ dlls/ddraw/direct3d/mesa.c	Mon Nov 10 17:44:51 2003
@@ -146,7 +146,7 @@
     IDirect3DDeviceImpl *lpd3ddev;
     HRESULT ret_value;
 
-    ret_value = d3ddevice_create(&lpd3ddev, This, lpDDS);
+    ret_value = d3ddevice_create(&lpd3ddev, This, lpDDS, FALSE);
     if (FAILED(ret_value)) return ret_value;
     
     if ((iid == NULL) ||
--- dlls/ddraw_CVS/dsurface/main.c	Thu Jul 17 19:30:22 2003
+++ dlls/ddraw/dsurface/main.c	Mon Nov 10 17:44:40 2003
@@ -189,7 +189,7 @@
         IDirect3DDeviceImpl *d3ddevimpl;
 	HRESULT ret_value;
 
-	ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This);
+	ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This, TRUE);
 	if (FAILED(ret_value)) return ret_value;
 
 	*ppObj = ICOM_INTERFACE(d3ddevimpl, IDirect3DDevice);
--- dlls/ddraw_CVS/mesa.c	Sat Sep  6 14:09:45 2003
+++ dlls/ddraw/mesa.c	Mon Nov 10 19:33:18 2003
@@ -332,10 +332,17 @@
 	        glDepthFunc(convert_D3D_compare_to_GL(dwRenderState));
 	        break;
 	      
-	    case D3DRENDERSTATE_ALPHAREF:   /* 24 */
-	    case D3DRENDERSTATE_ALPHAFUNC:  /* 25 */
-	        glAlphaFunc(convert_D3D_compare_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_ALPHAFUNC - 1]),
-			    (lpStateBlock->render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) / 255.0);
+	    case D3DRENDERSTATE_ALPHAREF:    /* 24 */
+	    case D3DRENDERSTATE_ALPHAFUNC: { /* 25 */
+		    GLenum func = convert_D3D_compare_to_GL(lpStateBlock->render_state[D3DRENDERSTATE_ALPHAFUNC - 1]);
+		    GLclampf ref = (lpStateBlock->render_state[D3DRENDERSTATE_ALPHAREF - 1] & 0x000000FF) / 255.0;
+
+		    if ((func != glThis->current_alpha_test_func) || (ref != glThis->current_alpha_test_ref)) {
+			glAlphaFunc(func, ref);
+			glThis->current_alpha_test_func = func;
+			glThis->current_alpha_test_ref = ref;
+		    }
+	        }
 	        break;
 
 	    case D3DRENDERSTATE_DITHERENABLE:     /* 26 */
@@ -352,6 +359,11 @@
 		    glDisable(GL_BLEND);
 		}
 	        glThis->blending = dwRenderState;
+
+	        /* Hack for some old games ... */
+	        if (glThis->version == 1) {
+		    lpStateBlock->render_state[D3DRENDERSTATE_COLORKEYENABLE - 1] = dwRenderState;
+		}
 	        break;
 	      
 	    case D3DRENDERSTATE_FOGENABLE: /* 28 */
@@ -395,13 +407,7 @@
 		break;
 
 	    case D3DRENDERSTATE_COLORKEYENABLE:     /* 41 */
-	        /* This needs to be fixed. */
-	        if ((dwRenderState != 0) && (glThis->blending == 0)) {
-		    glEnable(GL_BLEND);
-		} else if ((dwRenderState == 0) && (glThis->blending != 0)) {
-		    glDisable(GL_BLEND);
-		}
-	        glThis->blending = dwRenderState;
+	        /* Nothing done here, only storage matters. */
 	        break;
 
 	    case D3DRENDERSTATE_MIPMAPLODBIAS: /* 46 */
@@ -926,6 +932,8 @@
 
     /* Used when converting stuff */
     line_increase = src_d->u1.lPitch - (width * bpp);
+
+    TRACE(" uploading texture to memory using conversion %d.\n", convert_type);
     
     switch (convert_type) {
         case CONVERT_PALETTED: {
@@ -996,7 +1004,7 @@
 	    for (y = 0; y < height; y++) {
 		for (x = 0; x < width; x++) {
 		    WORD color = *src++;
-		    *dst = ((color & 0xFFD0) | ((color & 0x1F) << 1));
+		    *dst = ((color & 0xFFC0) | ((color & 0x1F) << 1));
 		    if ((color < src_d->ddckCKSrcBlt.dwColorSpaceLowValue) ||
 			(color > src_d->ddckCKSrcBlt.dwColorSpaceHighValue))
 			*dst |= 0x0001;
--- dlls/ddraw_CVS/mesa_private.h	Fri Aug 22 22:42:24 2003
+++ dlls/ddraw/mesa_private.h	Mon Nov 10 17:45:57 2003
@@ -117,6 +117,9 @@
     /* The last type of vertex drawn */
     GL_TRANSFORM_STATE transform_state;
 
+    /* Maybe a hack, but it works */
+    DWORD version;
+    
     /* Used to handle fogging faster... */
     BYTE fog_table[3 * 0x10000]; /* 3 is for R, G and B
 				    0x10000 is 0xFF for the vertex color and
@@ -142,6 +145,8 @@
     DWORD prev_clear_stencil;
     D3DVALUE prev_clear_Z;
     BOOLEAN depth_mask, depth_test, alpha_test, stencil_test, cull_face, lighting, blending, fogging;
+    GLenum current_alpha_test_func;
+    GLclampf current_alpha_test_ref;
     GLenum current_tex_env;
     GLenum current_active_tex_unit;
 } IDirect3DDeviceGLImpl;
@@ -180,7 +185,7 @@
 extern HRESULT d3dmaterial_create(IDirect3DMaterialImpl **obj, IDirectDrawImpl *d3d);
 extern HRESULT d3dviewport_create(IDirect3DViewportImpl **obj, IDirectDrawImpl *d3d);
 extern HRESULT d3dvertexbuffer_create(IDirect3DVertexBufferImpl **obj, IDirectDrawImpl *d3d, LPD3DVERTEXBUFFERDESC lpD3DVertBufDesc, DWORD dwFlags);
-extern HRESULT d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface);
+extern HRESULT d3ddevice_create(IDirect3DDeviceImpl **obj, IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *surface, BOOLEAN from_surface);
 
 /* Used for Direct3D to request the device to enumerate itself */
 extern HRESULT d3ddevice_enumerate(LPD3DENUMDEVICESCALLBACK cb, LPVOID context, DWORD version) ;


More information about the wine-patches mailing list