From 6810ebb4c17628f2f6f7dc754914b853fbf066d5 Mon Sep 17 00:00:00 2001 From: Alexander Dorofeyev Date: Sun, 20 Jan 2008 20:17:54 -0800 Subject: [PATCH] ddraw: Fix handling of alpha with D3DTBLEND_MODULATE. --- dlls/ddraw/device.c | 277 +++++++++++++++++++++++++++++++------ dlls/ddraw/executebuffer.c | 2 +- 2 files changed, 235 insertions(+), 44 deletions(-) diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index a22d6113900..b60b6f3cc51 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -28,7 +28,6 @@ #include "config.h" #include "wine/port.h" -#include "wine/debug.h" #include #include @@ -36,6 +35,7 @@ #include #define COBJMACROS +#define NONAMELESSUNION #include "windef.h" #include "winbase.h" @@ -47,6 +47,7 @@ #include "d3d.h" #include "ddraw_private.h" +#include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(d3d7); WINE_DECLARE_DEBUG_CHANNEL(ddraw_thunk); @@ -2369,15 +2370,93 @@ Thunk_IDirect3DDeviceImpl_3_GetRenderState(IDirect3DDevice3 *iface, } static HRESULT WINAPI -Thunk_IDirect3DDeviceImpl_2_GetRenderState(IDirect3DDevice2 *iface, +IDirect3DDeviceImpl_2_GetRenderState(IDirect3DDevice2 *iface, D3DRENDERSTATETYPE dwRenderStateType, DWORD *lpdwRenderState) { ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface); - TRACE_(ddraw_thunk)("(%p)->(%08x,%p) thunking to IDirect3DDevice7 interface.\n", This, dwRenderStateType, lpdwRenderState); - return IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), + TRACE("(%p)->(%08x,%p): Relay\n", This, dwRenderStateType, lpdwRenderState); + + /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse + the mapping to get the value; other states relayed to IDirect3DDevice7::GetRenderState */ + switch(dwRenderStateType) + { + case D3DRENDERSTATE_TEXTUREMAPBLEND: + { + DWORD colorop, colorarg1, colorarg2; + DWORD alphaop, alphaarg1, alphaarg2; + + EnterCriticalSection(&ddraw_cs); + + IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, &colorop); + IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, &colorarg1); + IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG2, &colorarg2); + IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, &alphaop); + IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, &alphaarg1); + IWineD3DDevice_GetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG2, &alphaarg2); + + if (colorop == WINED3DTOP_SELECTARG1 && colorarg1 == WINED3DTA_TEXTURE && + alphaop == WINED3DTOP_SELECTARG1 && alphaarg1 == WINED3DTA_TEXTURE) + { + *lpdwRenderState = D3DTBLEND_DECAL; + } + else if (colorop == WINED3DTOP_SELECTARG1 && colorarg1 == WINED3DTA_TEXTURE && + alphaop == WINED3DTOP_MODULATE && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT) + { + *lpdwRenderState = D3DTBLEND_DECALALPHA; + } + else if (colorop == WINED3DTOP_MODULATE && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT && + alphaop == WINED3DTOP_MODULATE && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT) + { + *lpdwRenderState = D3DTBLEND_MODULATEALPHA; + } + else + { + HRESULT hr; + BOOL tex_alpha = FALSE; + IWineD3DBaseTexture *tex = NULL; + WINED3DSURFACE_DESC desc; + WINED3DFORMAT fmt; + DDPIXELFORMAT ddfmt; + + hr = IWineD3DDevice_GetTexture(This->wineD3DDevice, + 0, + &tex); + + if(hr == WINED3D_OK && tex) + { + memset(&desc, 0, sizeof(desc)); + desc.Format = &fmt; + hr = IWineD3DTexture_GetLevelDesc((IWineD3DTexture*) tex, 0, &desc); + if (SUCCEEDED(hr)) + { + ddfmt.dwSize = sizeof(ddfmt); + PixelFormat_WineD3DtoDD(&ddfmt, fmt); + if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE; + } + + IWineD3DBaseTexture_Release(tex); + } + + if (!(colorop == WINED3DTOP_MODULATE && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT && + alphaop == WINED3DTOP_SELECTARG1 && alphaarg1 == (tex_alpha ? WINED3DTA_TEXTURE : WINED3DTA_CURRENT))) + { + ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous\n"); + } + + *lpdwRenderState = D3DTBLEND_MODULATE; + } + + LeaveCriticalSection(&ddraw_cs); + + return D3D_OK; + } + + default: + return IDirect3DDevice7_GetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), dwRenderStateType, lpdwRenderState); + } } /***************************************************************************** @@ -2525,20 +2604,101 @@ IDirect3DDeviceImpl_7_SetRenderState(IDirect3DDevice7 *iface, Value); break; + default: + + /* FIXME: Unhandled: D3DRENDERSTATE_STIPPLEPATTERN00 - 31 */ + + hr = IWineD3DDevice_SetRenderState(This->wineD3DDevice, + RenderStateType, + Value); + break; + } + LeaveCriticalSection(&ddraw_cs); + return hr; +} + +static HRESULT WINAPI +Thunk_IDirect3DDeviceImpl_3_SetRenderState(IDirect3DDevice3 *iface, + D3DRENDERSTATETYPE RenderStateType, + DWORD Value) +{ + ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface); + TRACE_(ddraw_thunk)("(%p)->(%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, RenderStateType, Value); + return IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), + RenderStateType, + Value); +} + +static HRESULT WINAPI +IDirect3DDeviceImpl_2_SetRenderState(IDirect3DDevice2 *iface, + D3DRENDERSTATETYPE RenderStateType, + DWORD Value) +{ + /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values + for this state can be directly mapped to texture stage colorop and alphaop, but + D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha + from diffuse otherwise. So changing the texture is monitored here to modify + alphaarg when needed. + + Other states are relayed to IDirect3DDevice7 + + Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation */ + + HRESULT hr; + ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface); + TRACE("(%p)->(%08x,%d): Relay\n", This, RenderStateType, Value); + + switch(RenderStateType) + { case D3DRENDERSTATE_TEXTUREMAPBLEND: { - /* Old texture combine setup style, superseded by texture stage states - * in D3D7. It is safe for us to wrap it to texture stage states. - */ + EnterCriticalSection(&ddraw_cs); + switch ( (D3DTEXTUREBLEND) Value) { case D3DTBLEND_MODULATE: + { + BOOL tex_alpha = FALSE; + IWineD3DBaseTexture *tex = NULL; + WINED3DSURFACE_DESC desc; + WINED3DFORMAT fmt; + DDPIXELFORMAT ddfmt; + + hr = IWineD3DDevice_GetTexture(This->wineD3DDevice, + 0, + &tex); + + if(hr == WINED3D_OK && tex) + { + memset(&desc, 0, sizeof(desc)); + desc.Format = &fmt; + hr = IWineD3DTexture_GetLevelDesc((IWineD3DTexture*) tex, 0, &desc); + if (SUCCEEDED(hr)) + { + ddfmt.dwSize = sizeof(ddfmt); + PixelFormat_WineD3DtoDD(&ddfmt, fmt); + if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE; + } + + IWineD3DBaseTexture_Release(tex); + } + + IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1); + if (tex_alpha) + { + IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE); + } + else + { + IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_CURRENT); + } + IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE); - IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE); IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG2, WINED3DTA_CURRENT); IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLOROP, WINED3DTOP_MODULATE); - IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAOP, WINED3DTOP_SELECTARG1); + break; + } case D3DTBLEND_MODULATEALPHA: IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_COLORARG1, WINED3DTA_TEXTURE); @@ -2566,48 +2726,79 @@ IDirect3DDeviceImpl_7_SetRenderState(IDirect3DDevice7 *iface, default: ERR("Unhandled texture environment %d !\n",Value); + } + + LeaveCriticalSection(&ddraw_cs); + + hr = D3D_OK; + break; + } + + case D3DRENDERSTATE_TEXTUREHANDLE: + { + DWORD texmapblend; + + IDirect3DDevice2_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend); + + hr = IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), + D3DRENDERSTATE_TEXTUREHANDLE, + Value); + + if (texmapblend == D3DTBLEND_MODULATE) + { + BOOL tex_alpha = FALSE; + IWineD3DBaseTexture *tex = NULL; + WINED3DSURFACE_DESC desc; + WINED3DFORMAT fmt; + DDPIXELFORMAT ddfmt; + + EnterCriticalSection(&ddraw_cs); + + hr = IWineD3DDevice_GetTexture(This->wineD3DDevice, + 0, + &tex); + + if(hr == WINED3D_OK && tex) + { + memset(&desc, 0, sizeof(desc)); + desc.Format = &fmt; + hr = IWineD3DTexture_GetLevelDesc((IWineD3DTexture*) tex, 0, &desc); + if (SUCCEEDED(hr)) + { + ddfmt.dwSize = sizeof(ddfmt); + PixelFormat_WineD3DtoDD(&ddfmt, fmt); + if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE; + } + + IWineD3DBaseTexture_Release(tex); } - hr = D3D_OK; + + /* alphaop is WINED3DTOP_SELECTARG1 if it's D3DTBLEND_MODULATE, so only modify alphaarg1 */ + if (tex_alpha) + { + IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_TEXTURE); + } + else + { + IWineD3DDevice_SetTextureStageState(This->wineD3DDevice, 0, WINED3DTSS_ALPHAARG1, WINED3DTA_CURRENT); + } + + LeaveCriticalSection(&ddraw_cs); + } + break; } default: - - /* FIXME: Unhandled: D3DRENDERSTATE_STIPPLEPATTERN00 - 31 */ - - hr = IWineD3DDevice_SetRenderState(This->wineD3DDevice, - RenderStateType, - Value); + hr = IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), + RenderStateType, + Value); break; } - LeaveCriticalSection(&ddraw_cs); + return hr; } -static HRESULT WINAPI -Thunk_IDirect3DDeviceImpl_3_SetRenderState(IDirect3DDevice3 *iface, - D3DRENDERSTATETYPE RenderStateType, - DWORD Value) -{ - ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface); - TRACE_(ddraw_thunk)("(%p)->(%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, RenderStateType, Value); - return IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), - RenderStateType, - Value); -} - -static HRESULT WINAPI -Thunk_IDirect3DDeviceImpl_2_SetRenderState(IDirect3DDevice2 *iface, - D3DRENDERSTATETYPE RenderStateType, - DWORD Value) -{ - ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface); - TRACE_(ddraw_thunk)("(%p)->(%08x,%08x) thunking to IDirect3DDevice7 interface.\n", This, RenderStateType, Value); - return IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(This, IDirect3DDevice7), - RenderStateType, - Value); -} - /***************************************************************************** * Direct3DDevice3::SetLightState * @@ -5441,8 +5632,8 @@ const IDirect3DDevice2Vtbl IDirect3DDevice2_Vtbl = Thunk_IDirect3DDeviceImpl_2_Vertex, Thunk_IDirect3DDeviceImpl_2_Index, Thunk_IDirect3DDeviceImpl_2_End, - Thunk_IDirect3DDeviceImpl_2_GetRenderState, - Thunk_IDirect3DDeviceImpl_2_SetRenderState, + IDirect3DDeviceImpl_2_GetRenderState, + IDirect3DDeviceImpl_2_SetRenderState, Thunk_IDirect3DDeviceImpl_2_GetLightState, Thunk_IDirect3DDeviceImpl_2_SetLightState, Thunk_IDirect3DDeviceImpl_2_SetTransform, diff --git a/dlls/ddraw/executebuffer.c b/dlls/ddraw/executebuffer.c index e74bdb164ca..49b6d6c12e4 100644 --- a/dlls/ddraw/executebuffer.c +++ b/dlls/ddraw/executebuffer.c @@ -317,7 +317,7 @@ IDirect3DExecuteBufferImpl_Execute(IDirect3DExecuteBufferImpl *This, for (i = 0; i < count; i++) { LPD3DSTATE ci = (LPD3DSTATE) instr; - IDirect3DDevice7_SetRenderState(ICOM_INTERFACE(lpDevice, IDirect3DDevice7), + IDirect3DDevice2_SetRenderState(ICOM_INTERFACE(lpDevice, IDirect3DDevice2), ci->u1.drstRenderStateType, ci->u2.dwArg[0]); instr += size;