ddraw: Fix handling of alpha with D3DTBLEND_MODULATE.

This commit is contained in:
Alexander Dorofeyev 2008-01-20 20:17:54 -08:00 committed by Alexandre Julliard
parent 536f98000d
commit 6810ebb4c1
2 changed files with 235 additions and 44 deletions

View File

@ -28,7 +28,6 @@
#include "config.h"
#include "wine/port.h"
#include "wine/debug.h"
#include <assert.h>
#include <stdarg.h>
@ -36,6 +35,7 @@
#include <stdlib.h>
#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,

View File

@ -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;