From 7d9fb66422e34db851877a31fa28db9654d70022 Mon Sep 17 00:00:00 2001 From: Magnus Olsen Date: Fri, 17 Aug 2007 18:29:23 +0000 Subject: [PATCH] This is a temporary solution to our DX problem it will take some times getting native DirectX working in user mode. Wine Have manger ported their DirectX to Windows, And after some help from wine (Roderick Colenbrander aka Thunderbird), That mean we got now DirectX8 support in ReactOS from wine DirectX (base on opengl). (rember disable the SSE in mesa before trying it, and it is untested in ReactOS) svn path=/trunk/; revision=28386 --- reactos/dll/directx/wine/d3d8/Makefile.in | 33 + reactos/dll/directx/wine/d3d8/basetexture.c | 164 + reactos/dll/directx/wine/d3d8/cubetexture.c | 291 + reactos/dll/directx/wine/d3d8/d3d8.rbuild | 42 + reactos/dll/directx/wine/d3d8/d3d8.spec | 5 + reactos/dll/directx/wine/d3d8/d3d8_main.c | 135 + reactos/dll/directx/wine/d3d8/d3d8_private.h | 670 ++ reactos/dll/directx/wine/d3d8/device.c | 2212 ++++++ reactos/dll/directx/wine/d3d8/directx.c | 507 ++ reactos/dll/directx/wine/d3d8/indexbuffer.c | 209 + reactos/dll/directx/wine/d3d8/pixelshader.c | 95 + reactos/dll/directx/wine/d3d8/resource.c | 133 + reactos/dll/directx/wine/d3d8/stateblock.c | 96 + reactos/dll/directx/wine/d3d8/surface.c | 228 + reactos/dll/directx/wine/d3d8/swapchain.c | 104 + reactos/dll/directx/wine/d3d8/texture.c | 288 + reactos/dll/directx/wine/d3d8/version.rc | 26 + reactos/dll/directx/wine/d3d8/vertexbuffer.c | 210 + .../dll/directx/wine/d3d8/vertexdeclaration.c | 340 + reactos/dll/directx/wine/d3d8/vertexshader.c | 100 + reactos/dll/directx/wine/d3d8/volume.c | 256 + reactos/dll/directx/wine/d3d8/volumetexture.c | 291 + reactos/dll/directx/wine/readme.txt | 21 + reactos/dll/directx/wine/wine.rbuild | 11 + reactos/dll/directx/wine/wined3d/Makefile.in | 42 + .../directx/wine/wined3d/arb_program_shader.c | 1104 +++ reactos/dll/directx/wine/wined3d/baseshader.c | 1018 +++ .../dll/directx/wine/wined3d/basetexture.c | 465 ++ reactos/dll/directx/wine/wined3d/clipper.c | 203 + reactos/dll/directx/wine/wined3d/context.c | 890 +++ .../dll/directx/wine/wined3d/cubetexture.c | 406 + reactos/dll/directx/wine/wined3d/device.c | 6943 +++++++++++++++++ reactos/dll/directx/wine/wined3d/directx.c | 2604 +++++++ reactos/dll/directx/wine/wined3d/drawprim.c | 1535 ++++ .../dll/directx/wine/wined3d/glsl_shader.c | 2369 ++++++ .../dll/directx/wine/wined3d/indexbuffer.c | 211 + reactos/dll/directx/wine/wined3d/palette.c | 187 + .../dll/directx/wine/wined3d/pixelshader.c | 585 ++ reactos/dll/directx/wine/wined3d/query.c | 433 + reactos/dll/directx/wine/wined3d/resource.c | 274 + reactos/dll/directx/wine/wined3d/state.c | 4528 +++++++++++ reactos/dll/directx/wine/wined3d/stateblock.c | 1276 +++ reactos/dll/directx/wine/wined3d/surface.c | 3745 +++++++++ .../dll/directx/wine/wined3d/surface_gdi.c | 1605 ++++ reactos/dll/directx/wine/wined3d/swapchain.c | 560 ++ reactos/dll/directx/wine/wined3d/texture.c | 376 + reactos/dll/directx/wine/wined3d/utils.c | 2971 +++++++ reactos/dll/directx/wine/wined3d/version.rc | 27 + .../dll/directx/wine/wined3d/vertexbuffer.c | 504 ++ .../directx/wine/wined3d/vertexdeclaration.c | 182 + .../dll/directx/wine/wined3d/vertexshader.c | 663 ++ reactos/dll/directx/wine/wined3d/volume.c | 333 + .../dll/directx/wine/wined3d/volumetexture.c | 324 + reactos/dll/directx/wine/wined3d/wined3d.def | 3 + .../dll/directx/wine/wined3d/wined3d.rbuild | 51 + reactos/dll/directx/wine/wined3d/wined3d.spec | 2 + .../dll/directx/wine/wined3d/wined3d_main.c | 291 + .../directx/wine/wined3d/wined3d_private.h | 2133 +++++ .../wine/wined3d/wined3d_private_types.h | 309 + 59 files changed, 45619 insertions(+) create mode 100644 reactos/dll/directx/wine/d3d8/Makefile.in create mode 100644 reactos/dll/directx/wine/d3d8/basetexture.c create mode 100644 reactos/dll/directx/wine/d3d8/cubetexture.c create mode 100644 reactos/dll/directx/wine/d3d8/d3d8.rbuild create mode 100644 reactos/dll/directx/wine/d3d8/d3d8.spec create mode 100644 reactos/dll/directx/wine/d3d8/d3d8_main.c create mode 100644 reactos/dll/directx/wine/d3d8/d3d8_private.h create mode 100644 reactos/dll/directx/wine/d3d8/device.c create mode 100644 reactos/dll/directx/wine/d3d8/directx.c create mode 100644 reactos/dll/directx/wine/d3d8/indexbuffer.c create mode 100644 reactos/dll/directx/wine/d3d8/pixelshader.c create mode 100644 reactos/dll/directx/wine/d3d8/resource.c create mode 100644 reactos/dll/directx/wine/d3d8/stateblock.c create mode 100644 reactos/dll/directx/wine/d3d8/surface.c create mode 100644 reactos/dll/directx/wine/d3d8/swapchain.c create mode 100644 reactos/dll/directx/wine/d3d8/texture.c create mode 100644 reactos/dll/directx/wine/d3d8/version.rc create mode 100644 reactos/dll/directx/wine/d3d8/vertexbuffer.c create mode 100644 reactos/dll/directx/wine/d3d8/vertexdeclaration.c create mode 100644 reactos/dll/directx/wine/d3d8/vertexshader.c create mode 100644 reactos/dll/directx/wine/d3d8/volume.c create mode 100644 reactos/dll/directx/wine/d3d8/volumetexture.c create mode 100644 reactos/dll/directx/wine/readme.txt create mode 100644 reactos/dll/directx/wine/wine.rbuild create mode 100644 reactos/dll/directx/wine/wined3d/Makefile.in create mode 100644 reactos/dll/directx/wine/wined3d/arb_program_shader.c create mode 100644 reactos/dll/directx/wine/wined3d/baseshader.c create mode 100644 reactos/dll/directx/wine/wined3d/basetexture.c create mode 100644 reactos/dll/directx/wine/wined3d/clipper.c create mode 100644 reactos/dll/directx/wine/wined3d/context.c create mode 100644 reactos/dll/directx/wine/wined3d/cubetexture.c create mode 100644 reactos/dll/directx/wine/wined3d/device.c create mode 100644 reactos/dll/directx/wine/wined3d/directx.c create mode 100644 reactos/dll/directx/wine/wined3d/drawprim.c create mode 100644 reactos/dll/directx/wine/wined3d/glsl_shader.c create mode 100644 reactos/dll/directx/wine/wined3d/indexbuffer.c create mode 100644 reactos/dll/directx/wine/wined3d/palette.c create mode 100644 reactos/dll/directx/wine/wined3d/pixelshader.c create mode 100644 reactos/dll/directx/wine/wined3d/query.c create mode 100644 reactos/dll/directx/wine/wined3d/resource.c create mode 100644 reactos/dll/directx/wine/wined3d/state.c create mode 100644 reactos/dll/directx/wine/wined3d/stateblock.c create mode 100644 reactos/dll/directx/wine/wined3d/surface.c create mode 100644 reactos/dll/directx/wine/wined3d/surface_gdi.c create mode 100644 reactos/dll/directx/wine/wined3d/swapchain.c create mode 100644 reactos/dll/directx/wine/wined3d/texture.c create mode 100644 reactos/dll/directx/wine/wined3d/utils.c create mode 100644 reactos/dll/directx/wine/wined3d/version.rc create mode 100644 reactos/dll/directx/wine/wined3d/vertexbuffer.c create mode 100644 reactos/dll/directx/wine/wined3d/vertexdeclaration.c create mode 100644 reactos/dll/directx/wine/wined3d/vertexshader.c create mode 100644 reactos/dll/directx/wine/wined3d/volume.c create mode 100644 reactos/dll/directx/wine/wined3d/volumetexture.c create mode 100644 reactos/dll/directx/wine/wined3d/wined3d.def create mode 100644 reactos/dll/directx/wine/wined3d/wined3d.rbuild create mode 100644 reactos/dll/directx/wine/wined3d/wined3d.spec create mode 100644 reactos/dll/directx/wine/wined3d/wined3d_main.c create mode 100644 reactos/dll/directx/wine/wined3d/wined3d_private.h create mode 100644 reactos/dll/directx/wine/wined3d/wined3d_private_types.h diff --git a/reactos/dll/directx/wine/d3d8/Makefile.in b/reactos/dll/directx/wine/d3d8/Makefile.in new file mode 100644 index 00000000000..15bc92aed3b --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/Makefile.in @@ -0,0 +1,33 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = d3d8.dll +IMPORTLIB = libd3d8.$(IMPLIBEXT) +IMPORTS = wined3d user32 gdi32 advapi32 kernel32 +EXTRALIBS = -ldxguid -luuid + +C_SRCS = \ + basetexture.c \ + cubetexture.c \ + d3d8_main.c \ + device.c \ + directx.c \ + indexbuffer.c \ + pixelshader.c \ + resource.c \ + stateblock.c \ + surface.c \ + swapchain.c \ + texture.c \ + vertexbuffer.c \ + vertexdeclaration.c \ + vertexshader.c \ + volume.c \ + volumetexture.c + +RC_SRCS = version.rc + +@MAKE_DLL_RULES@ + +@DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/reactos/dll/directx/wine/d3d8/basetexture.c b/reactos/dll/directx/wine/d3d8/basetexture.c new file mode 100644 index 00000000000..122c22d5585 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/basetexture.c @@ -0,0 +1,164 @@ +/* + * IDirect3DBaseTexture8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DBaseTexture8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DBaseTexture8Impl_QueryInterface(LPDIRECT3DBASETEXTURE8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DBaseTexture8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DBaseTexture8Impl_AddRef(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DBaseTexture8Impl_Release(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + IWineD3DBaseTexture_Release(This->wineD3DBaseTexture); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/* IDirect3DBaseTexture8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DBaseTexture8Impl_GetDevice(LPDIRECT3DBASETEXTURE8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); +} + +static HRESULT WINAPI IDirect3DBaseTexture8Impl_SetPrivateData(LPDIRECT3DBASETEXTURE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_SetPrivateData(This->wineD3DBaseTexture, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IDirect3DBaseTexture8Impl_GetPrivateData(LPDIRECT3DBASETEXTURE8 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_GetPrivateData(This->wineD3DBaseTexture, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IDirect3DBaseTexture8Impl_FreePrivateData(LPDIRECT3DBASETEXTURE8 iface, REFGUID refguid) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_FreePrivateData(This->wineD3DBaseTexture, refguid); +} + +static DWORD WINAPI IDirect3DBaseTexture8Impl_SetPriority(LPDIRECT3DBASETEXTURE8 iface, DWORD PriorityNew) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_SetPriority(This->wineD3DBaseTexture, PriorityNew); +} + +static DWORD WINAPI IDirect3DBaseTexture8Impl_GetPriority(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_GetPriority(This->wineD3DBaseTexture); +} + +static void WINAPI IDirect3DBaseTexture8Impl_PreLoad(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + IWineD3DBaseTexture_PreLoad(This->wineD3DBaseTexture); + return; +} + +static D3DRESOURCETYPE WINAPI IDirect3DBaseTexture8Impl_GetType(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_GetType(This->wineD3DBaseTexture); +} + +/* IDirect3DBaseTexture8 Interface follow: */ +static DWORD WINAPI IDirect3DBaseTexture8Impl_SetLOD(LPDIRECT3DBASETEXTURE8 iface, DWORD LODNew) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_SetLOD(This->wineD3DBaseTexture, LODNew); +} + +static DWORD WINAPI IDirect3DBaseTexture8Impl_GetLOD(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_GetLOD(This->wineD3DBaseTexture); +} + +static DWORD WINAPI IDirect3DBaseTexture8Impl_GetLevelCount(LPDIRECT3DBASETEXTURE8 iface) { + IDirect3DBaseTexture8Impl *This = (IDirect3DBaseTexture8Impl *)iface; + TRACE("(%p) Relay\n" , This); + + return IWineD3DBaseTexture_GetLevelCount(This->wineD3DBaseTexture); +} + +const IDirect3DBaseTexture8Vtbl Direct3DBaseTexture8_Vtbl = +{ + IDirect3DBaseTexture8Impl_QueryInterface, + IDirect3DBaseTexture8Impl_AddRef, + IDirect3DBaseTexture8Impl_Release, + IDirect3DBaseTexture8Impl_GetDevice, + IDirect3DBaseTexture8Impl_SetPrivateData, + IDirect3DBaseTexture8Impl_GetPrivateData, + IDirect3DBaseTexture8Impl_FreePrivateData, + IDirect3DBaseTexture8Impl_SetPriority, + IDirect3DBaseTexture8Impl_GetPriority, + IDirect3DBaseTexture8Impl_PreLoad, + IDirect3DBaseTexture8Impl_GetType, + + IDirect3DBaseTexture8Impl_SetLOD, + IDirect3DBaseTexture8Impl_GetLOD, + IDirect3DBaseTexture8Impl_GetLevelCount +}; diff --git a/reactos/dll/directx/wine/d3d8/cubetexture.c b/reactos/dll/directx/wine/d3d8/cubetexture.c new file mode 100644 index 00000000000..ae343bbb712 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/cubetexture.c @@ -0,0 +1,291 @@ +/* + * IDirect3DCubeTexture8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DCubeTexture8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DCubeTexture8Impl_QueryInterface(LPDIRECT3DCUBETEXTURE8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DBaseTexture8) + || IsEqualGUID(riid, &IID_IDirect3DCubeTexture8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DCubeTexture8Impl_AddRef(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DCubeTexture8Impl_Release(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + TRACE("Releasing child %p\n", This->wineD3DCubeTexture); + EnterCriticalSection(&d3d8_cs); + IWineD3DCubeTexture_Destroy(This->wineD3DCubeTexture, D3D8CB_DestroySurface); + LeaveCriticalSection(&d3d8_cs); + IUnknown_Release(This->parentDevice); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DCubeTexture8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DCubeTexture8Impl_GetDevice(LPDIRECT3DCUBETEXTURE8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_SetPrivateData(LPDIRECT3DCUBETEXTURE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_SetPrivateData(This->wineD3DCubeTexture,refguid,pData,SizeOfData,Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_GetPrivateData(LPDIRECT3DCUBETEXTURE8 iface, REFGUID refguid, void *pData, DWORD *pSizeOfData) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_GetPrivateData(This->wineD3DCubeTexture,refguid,pData,pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_FreePrivateData(LPDIRECT3DCUBETEXTURE8 iface, REFGUID refguid) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_FreePrivateData(This->wineD3DCubeTexture,refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static DWORD WINAPI IDirect3DCubeTexture8Impl_SetPriority(LPDIRECT3DCUBETEXTURE8 iface, DWORD PriorityNew) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DCubeTexture_SetPriority(This->wineD3DCubeTexture, PriorityNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DCubeTexture8Impl_GetPriority(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DCubeTexture_GetPriority(This->wineD3DCubeTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static void WINAPI IDirect3DCubeTexture8Impl_PreLoad(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DCubeTexture_PreLoad(This->wineD3DCubeTexture); + LeaveCriticalSection(&d3d8_cs); +} + +static D3DRESOURCETYPE WINAPI IDirect3DCubeTexture8Impl_GetType(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + D3DRESOURCETYPE type; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + type = IWineD3DCubeTexture_GetType(This->wineD3DCubeTexture); + LeaveCriticalSection(&d3d8_cs); + return type; +} + +/* IDirect3DCubeTexture8 IDirect3DBaseTexture8 Interface follow: */ +static DWORD WINAPI IDirect3DCubeTexture8Impl_SetLOD(LPDIRECT3DCUBETEXTURE8 iface, DWORD LODNew) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + DWORD lod; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + lod = IWineD3DCubeTexture_SetLOD(This->wineD3DCubeTexture, LODNew); + LeaveCriticalSection(&d3d8_cs); + return lod; +} + +static DWORD WINAPI IDirect3DCubeTexture8Impl_GetLOD(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + DWORD lod; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + lod = IWineD3DCubeTexture_GetLOD((LPDIRECT3DBASETEXTURE8) This); + LeaveCriticalSection(&d3d8_cs); + return lod; +} + +static DWORD WINAPI IDirect3DCubeTexture8Impl_GetLevelCount(LPDIRECT3DCUBETEXTURE8 iface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + DWORD cnt; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + cnt = IWineD3DCubeTexture_GetLevelCount(This->wineD3DCubeTexture); + LeaveCriticalSection(&d3d8_cs); + return cnt; +} + +/* IDirect3DCubeTexture8 Interface follow: */ +static HRESULT WINAPI IDirect3DCubeTexture8Impl_GetLevelDesc(LPDIRECT3DCUBETEXTURE8 iface, UINT Level, D3DSURFACE_DESC *pDesc) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + WINED3DSURFACE_DESC wined3ddesc; + + TRACE("(%p) Relay\n", This); + + /* As d3d8 and d3d9 structures differ, pass in ptrs to where data needs to go */ + wined3ddesc.Format = (WINED3DFORMAT *)&pDesc->Format; + wined3ddesc.Type = (WINED3DRESOURCETYPE *)&pDesc->Type; + wined3ddesc.Usage = &pDesc->Usage; + wined3ddesc.Pool = (WINED3DPOOL *) &pDesc->Pool; + wined3ddesc.Size = &pDesc->Size; + wined3ddesc.MultiSampleType = (WINED3DMULTISAMPLE_TYPE *) &pDesc->MultiSampleType; + wined3ddesc.MultiSampleQuality = NULL; /* DirectX9 only */ + wined3ddesc.Width = &pDesc->Width; + wined3ddesc.Height = &pDesc->Height; + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_GetLevelDesc(This->wineD3DCubeTexture, Level, &wined3ddesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_GetCubeMapSurface(LPDIRECT3DCUBETEXTURE8 iface, D3DCUBEMAP_FACES FaceType, UINT Level, IDirect3DSurface8 **ppCubeMapSurface) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hrc = D3D_OK; + IWineD3DSurface *mySurface = NULL; + + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DCubeTexture_GetCubeMapSurface(This->wineD3DCubeTexture, (WINED3DCUBEMAP_FACES) FaceType, Level, &mySurface); + if (hrc == D3D_OK && NULL != ppCubeMapSurface) { + IWineD3DCubeTexture_GetParent(mySurface, (IUnknown **)ppCubeMapSurface); + IWineD3DCubeTexture_Release(mySurface); + } + LeaveCriticalSection(&d3d8_cs); + return hrc; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_LockRect(LPDIRECT3DCUBETEXTURE8 iface, D3DCUBEMAP_FACES FaceType, UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT *pRect, DWORD Flags) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_LockRect(This->wineD3DCubeTexture, (WINED3DCUBEMAP_FACES) FaceType, Level, (WINED3DLOCKED_RECT *) pLockedRect, pRect, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_UnlockRect(LPDIRECT3DCUBETEXTURE8 iface, D3DCUBEMAP_FACES FaceType, UINT Level) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_UnlockRect(This->wineD3DCubeTexture, (WINED3DCUBEMAP_FACES) FaceType, Level); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DCubeTexture8Impl_AddDirtyRect(LPDIRECT3DCUBETEXTURE8 iface, D3DCUBEMAP_FACES FaceType, CONST RECT *pDirtyRect) { + IDirect3DCubeTexture8Impl *This = (IDirect3DCubeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DCubeTexture_AddDirtyRect(This->wineD3DCubeTexture, (WINED3DCUBEMAP_FACES) FaceType, pDirtyRect); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + + +const IDirect3DCubeTexture8Vtbl Direct3DCubeTexture8_Vtbl = +{ + /* IUnknown */ + IDirect3DCubeTexture8Impl_QueryInterface, + IDirect3DCubeTexture8Impl_AddRef, + IDirect3DCubeTexture8Impl_Release, + /* IDirect3DResource8 */ + IDirect3DCubeTexture8Impl_GetDevice, + IDirect3DCubeTexture8Impl_SetPrivateData, + IDirect3DCubeTexture8Impl_GetPrivateData, + IDirect3DCubeTexture8Impl_FreePrivateData, + IDirect3DCubeTexture8Impl_SetPriority, + IDirect3DCubeTexture8Impl_GetPriority, + IDirect3DCubeTexture8Impl_PreLoad, + IDirect3DCubeTexture8Impl_GetType, + /* IDirect3DBaseTexture8 */ + IDirect3DCubeTexture8Impl_SetLOD, + IDirect3DCubeTexture8Impl_GetLOD, + IDirect3DCubeTexture8Impl_GetLevelCount, + /* IDirect3DCubeTexture8 */ + IDirect3DCubeTexture8Impl_GetLevelDesc, + IDirect3DCubeTexture8Impl_GetCubeMapSurface, + IDirect3DCubeTexture8Impl_LockRect, + IDirect3DCubeTexture8Impl_UnlockRect, + IDirect3DCubeTexture8Impl_AddDirtyRect +}; diff --git a/reactos/dll/directx/wine/d3d8/d3d8.rbuild b/reactos/dll/directx/wine/d3d8/d3d8.rbuild new file mode 100644 index 00000000000..d2264ca79b1 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/d3d8.rbuild @@ -0,0 +1,42 @@ + + + . + include/reactos/wine + + + + + 0x600 + 0x501 + 0x501 + + + + uuid + user32 + opengl32 + gdi32 + advapi32 + kernel32 + wined3d + + basetexture.c + cubetexture.c + d3d8_main.c + device.c + directx.c + indexbuffer.c + pixelshader.c + resource.c + stateblock.c + surface.c + swapchain.c + texture.c + vertexbuffer.c + vertexdeclaration.c + vertexshader.c + volume.c + volumetexture.c + d3d8.spec + + diff --git a/reactos/dll/directx/wine/d3d8/d3d8.spec b/reactos/dll/directx/wine/d3d8/d3d8.spec new file mode 100644 index 00000000000..4bad85023af --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/d3d8.spec @@ -0,0 +1,5 @@ +@ stdcall D3D8GetSWInfo() +@ stdcall DebugSetMute() +@ stdcall Direct3DCreate8(long) +@ stdcall ValidatePixelShader(ptr long long ptr) +@ stdcall ValidateVertexShader(ptr ptr ptr long ptr) diff --git a/reactos/dll/directx/wine/d3d8/d3d8_main.c b/reactos/dll/directx/wine/d3d8/d3d8_main.c new file mode 100644 index 00000000000..63cb47204d5 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/d3d8_main.c @@ -0,0 +1,135 @@ +/* + * Direct3D 8 + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "config.h" +#include "initguid.h" +#include "d3d8_private.h" +#include "wine/debug.h" + +static CRITICAL_SECTION_DEBUG d3d8_cs_debug = +{ + 0, 0, &d3d8_cs, + { &d3d8_cs_debug.ProcessLocksList, + &d3d8_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": d3d8_cs") } +}; +CRITICAL_SECTION d3d8_cs = { &d3d8_cs_debug, -1, 0, 0, 0, 0 }; + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +HRESULT WINAPI D3D8GetSWInfo(void) { + FIXME("(void): stub\n"); + return 0; +} + +void WINAPI DebugSetMute(void) { + /* nothing to do */ +} + +IDirect3D8* WINAPI Direct3DCreate8(UINT SDKVersion) { + IDirect3D8Impl* object; + TRACE("SDKVersion = %x\n", SDKVersion); + + EnterCriticalSection(&d3d8_cs); + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3D8Impl)); + + object->lpVtbl = &Direct3D8_Vtbl; + object->ref = 1; + object->WineD3D = WineDirect3DCreate(SDKVersion, 8, (IUnknown *)object); + + TRACE("Created Direct3D object @ %p, WineObj @ %p\n", object, object->WineD3D); + LeaveCriticalSection(&d3d8_cs); + + return (IDirect3D8*) object; +} + +/* At process attach */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) +{ + TRACE("fdwReason=%d\n", fdwReason); + if (fdwReason == DLL_PROCESS_ATTACH) + DisableThreadLibraryCalls(hInstDLL); + + return TRUE; +} + +/*********************************************************************** + * ValidateVertexShader (D3D8.@) + * + * I've seen reserved1 and reserved2 always passed as 0's + * bool seems always passed as 0 or 1, but other values work as well.... + * toto result? + */ +HRESULT WINAPI ValidateVertexShader(DWORD* vertexshader, DWORD* reserved1, DWORD* reserved2, BOOL bool, DWORD* toto) +{ + HRESULT ret; + FIXME("(%p %p %p %d %p): stub\n", vertexshader, reserved1, reserved2, bool, toto); + + if (!vertexshader) + return E_FAIL; + + if (reserved1 || reserved2) + return E_FAIL; + + switch(*vertexshader) { + case 0xFFFE0101: + case 0xFFFE0100: + ret=S_OK; + break; + default: + ERR("vertexshader version mismatch\n"); + ret=E_FAIL; + } + + return ret; +} + +/*********************************************************************** + * ValidatePixelShader (D3D8.@) + * + * PARAMS + * toto result? + */ +HRESULT WINAPI ValidatePixelShader(DWORD* pixelshader, DWORD* reserved1, BOOL bool, DWORD* toto) +{ + HRESULT ret; + FIXME("(%p %p %d %p): stub\n", pixelshader, reserved1, bool, toto); + + if (!pixelshader) + return E_FAIL; + + if (reserved1) + return E_FAIL; + + switch(*pixelshader) { + case 0xFFFF0100: + case 0xFFFF0101: + case 0xFFFF0102: + case 0xFFFF0103: + case 0xFFFF0104: + ret=S_OK; + break; + default: + ERR("pixelshader version mismatch\n"); + ret=E_FAIL; + } + return ret; +} diff --git a/reactos/dll/directx/wine/d3d8/d3d8_private.h b/reactos/dll/directx/wine/d3d8/d3d8_private.h new file mode 100644 index 00000000000..229762b9957 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/d3d8_private.h @@ -0,0 +1,670 @@ +/* + * Direct3D 8 private include file + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_D3D8_PRIVATE_H +#define __WINE_D3D8_PRIVATE_H + +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "wine/debug.h" +#include "d3d8.h" +#include "wine/wined3d_interface.h" + +/* Device caps */ +#define INITIAL_SHADER_HANDLE_TABLE_SIZE 64 + +/* CreateVertexShader can return > 0xFFFF */ +#define VS_HIGHESTFIXEDFXF 0xF0000000 + +/* =========================================================================== + Macros + =========================================================================== */ +/* Not nice, but it lets wined3d support different versions of directx */ +#define D3D8CAPSTOWINECAPS(_pD3D8Caps, _pWineCaps) \ + _pWineCaps->DeviceType = (WINED3DDEVTYPE *) &_pD3D8Caps->DeviceType; \ + _pWineCaps->AdapterOrdinal = &_pD3D8Caps->AdapterOrdinal; \ + _pWineCaps->Caps = &_pD3D8Caps->Caps; \ + _pWineCaps->Caps2 = &_pD3D8Caps->Caps2; \ + _pWineCaps->Caps3 = &_pD3D8Caps->Caps3; \ + _pWineCaps->PresentationIntervals = &_pD3D8Caps->PresentationIntervals; \ + _pWineCaps->CursorCaps = &_pD3D8Caps->CursorCaps; \ + _pWineCaps->DevCaps = &_pD3D8Caps->DevCaps; \ + _pWineCaps->PrimitiveMiscCaps = &_pD3D8Caps->PrimitiveMiscCaps; \ + _pWineCaps->RasterCaps = &_pD3D8Caps->RasterCaps; \ + _pWineCaps->ZCmpCaps = &_pD3D8Caps->ZCmpCaps; \ + _pWineCaps->SrcBlendCaps = &_pD3D8Caps->SrcBlendCaps; \ + _pWineCaps->DestBlendCaps = &_pD3D8Caps->DestBlendCaps; \ + _pWineCaps->AlphaCmpCaps = &_pD3D8Caps->AlphaCmpCaps; \ + _pWineCaps->ShadeCaps = &_pD3D8Caps->ShadeCaps; \ + _pWineCaps->TextureCaps = &_pD3D8Caps->TextureCaps; \ + _pWineCaps->TextureFilterCaps = &_pD3D8Caps->TextureFilterCaps; \ + _pWineCaps->CubeTextureFilterCaps = &_pD3D8Caps->CubeTextureFilterCaps; \ + _pWineCaps->VolumeTextureFilterCaps = &_pD3D8Caps->VolumeTextureFilterCaps; \ + _pWineCaps->TextureAddressCaps = &_pD3D8Caps->TextureAddressCaps; \ + _pWineCaps->VolumeTextureAddressCaps = &_pD3D8Caps->VolumeTextureAddressCaps; \ + _pWineCaps->LineCaps = &_pD3D8Caps->LineCaps; \ + _pWineCaps->MaxTextureWidth = &_pD3D8Caps->MaxTextureWidth; \ + _pWineCaps->MaxTextureHeight = &_pD3D8Caps->MaxTextureHeight; \ + _pWineCaps->MaxVolumeExtent = &_pD3D8Caps->MaxVolumeExtent; \ + _pWineCaps->MaxTextureRepeat = &_pD3D8Caps->MaxTextureRepeat; \ + _pWineCaps->MaxTextureAspectRatio = &_pD3D8Caps->MaxTextureAspectRatio; \ + _pWineCaps->MaxAnisotropy = &_pD3D8Caps->MaxAnisotropy; \ + _pWineCaps->MaxVertexW = &_pD3D8Caps->MaxVertexW; \ + _pWineCaps->GuardBandLeft = &_pD3D8Caps->GuardBandLeft; \ + _pWineCaps->GuardBandTop = &_pD3D8Caps->GuardBandTop; \ + _pWineCaps->GuardBandRight = &_pD3D8Caps->GuardBandRight; \ + _pWineCaps->GuardBandBottom = &_pD3D8Caps->GuardBandBottom; \ + _pWineCaps->ExtentsAdjust = &_pD3D8Caps->ExtentsAdjust; \ + _pWineCaps->StencilCaps = &_pD3D8Caps->StencilCaps; \ + _pWineCaps->FVFCaps = &_pD3D8Caps->FVFCaps; \ + _pWineCaps->TextureOpCaps = &_pD3D8Caps->TextureOpCaps; \ + _pWineCaps->MaxTextureBlendStages = &_pD3D8Caps->MaxTextureBlendStages; \ + _pWineCaps->MaxSimultaneousTextures = &_pD3D8Caps->MaxSimultaneousTextures; \ + _pWineCaps->VertexProcessingCaps = &_pD3D8Caps->VertexProcessingCaps; \ + _pWineCaps->MaxActiveLights = &_pD3D8Caps->MaxActiveLights; \ + _pWineCaps->MaxUserClipPlanes = &_pD3D8Caps->MaxUserClipPlanes; \ + _pWineCaps->MaxVertexBlendMatrices = &_pD3D8Caps->MaxVertexBlendMatrices; \ + _pWineCaps->MaxVertexBlendMatrixIndex = &_pD3D8Caps->MaxVertexBlendMatrixIndex; \ + _pWineCaps->MaxPointSize = &_pD3D8Caps->MaxPointSize; \ + _pWineCaps->MaxPrimitiveCount = &_pD3D8Caps->MaxPrimitiveCount; \ + _pWineCaps->MaxVertexIndex = &_pD3D8Caps->MaxVertexIndex; \ + _pWineCaps->MaxStreams = &_pD3D8Caps->MaxStreams; \ + _pWineCaps->MaxStreamStride = &_pD3D8Caps->MaxStreamStride; \ + _pWineCaps->VertexShaderVersion = &_pD3D8Caps->VertexShaderVersion; \ + _pWineCaps->MaxVertexShaderConst = &_pD3D8Caps->MaxVertexShaderConst; \ + _pWineCaps->PixelShaderVersion = &_pD3D8Caps->PixelShaderVersion; \ + _pWineCaps->PixelShader1xMaxValue = &_pD3D8Caps->MaxPixelShaderValue; + +/* Direct3D8 Interfaces: */ +typedef struct IDirect3DBaseTexture8Impl IDirect3DBaseTexture8Impl; +typedef struct IDirect3DVolumeTexture8Impl IDirect3DVolumeTexture8Impl; +typedef struct IDirect3D8Impl IDirect3D8Impl; +typedef struct IDirect3DDevice8Impl IDirect3DDevice8Impl; +typedef struct IDirect3DTexture8Impl IDirect3DTexture8Impl; +typedef struct IDirect3DCubeTexture8Impl IDirect3DCubeTexture8Impl; +typedef struct IDirect3DIndexBuffer8Impl IDirect3DIndexBuffer8Impl; +typedef struct IDirect3DSurface8Impl IDirect3DSurface8Impl; +typedef struct IDirect3DSwapChain8Impl IDirect3DSwapChain8Impl; +typedef struct IDirect3DResource8Impl IDirect3DResource8Impl; +typedef struct IDirect3DVolume8Impl IDirect3DVolume8Impl; +typedef struct IDirect3DVertexBuffer8Impl IDirect3DVertexBuffer8Impl; + +/** Private Interfaces: */ +typedef struct IDirect3DStateBlockImpl IDirect3DStateBlockImpl; +typedef struct IDirect3DVertexShaderImpl IDirect3DVertexShaderImpl; +typedef struct IDirect3DPixelShaderImpl IDirect3DPixelShaderImpl; +typedef struct IDirect3DVertexShaderDeclarationImpl IDirect3DVertexShaderDeclarationImpl; + +/* Advance declaration of structures to satisfy compiler */ +typedef struct IDirect3DVertexShader8Impl IDirect3DVertexShader8Impl; + +/* Global critical section */ +extern CRITICAL_SECTION d3d8_cs; + +/* =========================================================================== + The interfactes themselves + =========================================================================== */ + +/* ---------- */ +/* IDirect3D8 */ +/* ---------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3D8Vtbl Direct3D8_Vtbl; + +/***************************************************************************** + * IDirect3D implementation structure + */ +struct IDirect3D8Impl +{ + /* IUnknown fields */ + const IDirect3D8Vtbl *lpVtbl; + LONG ref; + + /* The WineD3D device */ + IWineD3D *WineD3D; +}; + +/* ---------------- */ +/* IDirect3DDevice8 */ +/* ---------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DDevice8Vtbl Direct3DDevice8_Vtbl; + +/***************************************************************************** + * IDirect3DDevice8 implementation structure + */ + +typedef void * shader_handle; + +struct FvfToDecl +{ + DWORD fvf; + IWineD3DVertexDeclaration *decl; +}; + +struct IDirect3DDevice8Impl +{ + /* IUnknown fields */ + const IDirect3DDevice8Vtbl *lpVtbl; + LONG ref; +/* But what about baseVertexIndex in state blocks? hmm... it may be a better idea to pass this to wined3d */ + IWineD3DDevice *WineD3DDevice; + DWORD shader_handle_table_size; + DWORD allocated_shader_handles; + shader_handle *shader_handles; + shader_handle *free_shader_handles; + + /* FVF management */ + struct FvfToDecl *decls; + UINT numConvertedDecls, declArraySize; + + /* Avoids recursion with nested ReleaseRef to 0 */ + BOOL inDestruction; +}; + +/* ---------------- */ +/* IDirect3DVolume8 */ +/* ---------------- */ + +/***************************************************************************** + * IDirect3DVolume8 implementation structure + */ +struct IDirect3DVolume8Impl +{ + /* IUnknown fields */ + const IDirect3DVolume8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DVolume8 fields */ + IWineD3DVolume *wineD3DVolume; + + /* The volume container */ + IUnknown *container; + + /* If set forward refcounting to this object */ + IUnknown *forwardReference; +}; + +/* ------------------- */ +/* IDirect3DSwapChain8 */ +/* ------------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DSwapChain8Vtbl Direct3DSwapChain8_Vtbl; + +/***************************************************************************** + * IDirect3DSwapChain8 implementation structure + */ +struct IDirect3DSwapChain8Impl +{ + /* IUnknown fields */ + const IDirect3DSwapChain8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DSwapChain8 fields */ + IWineD3DSwapChain *wineD3DSwapChain; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; +}; + +/* ----------------- */ +/* IDirect3DSurface8 */ +/* ----------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DSurface8Vtbl Direct3DSurface8_Vtbl; + +/***************************************************************************** + * IDirect3DSurface8 implementation structure + */ +struct IDirect3DSurface8Impl +{ + /* IUnknown fields */ + const IDirect3DSurface8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DSurface8 fields */ + IWineD3DSurface *wineD3DSurface; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; + + /* The surface container */ + IUnknown *container; + + /* If set forward refcounting to this object */ + IUnknown *forwardReference; + + /* Flags an implicit surface */ + BOOL isImplicit; +}; + +/* ------------------ */ +/* IDirect3DResource8 */ +/* ------------------ */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DResource8Vtbl Direct3DResource8_Vtbl; + +/***************************************************************************** + * IDirect3DResource8 implementation structure + */ +struct IDirect3DResource8Impl +{ + /* IUnknown fields */ + const IDirect3DResource8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DResource *wineD3DResource; +}; +extern HRESULT WINAPI IDirect3DResource8Impl_GetDevice(LPDIRECT3DRESOURCE8 iface, IDirect3DDevice8** ppDevice); + +/* ---------------------- */ +/* IDirect3DVertexBuffer8 */ +/* ---------------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DVertexBuffer8Vtbl Direct3DVertexBuffer8_Vtbl; + +/***************************************************************************** + * IDirect3DVertexBuffer8 implementation structure + */ +struct IDirect3DVertexBuffer8Impl +{ + /* IUnknown fields */ + const IDirect3DVertexBuffer8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DVertexBuffer *wineD3DVertexBuffer; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; +}; + +/* --------------------- */ +/* IDirect3DIndexBuffer8 */ +/* --------------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DIndexBuffer8Vtbl Direct3DIndexBuffer8_Vtbl; + +/***************************************************************************** + * IDirect3DIndexBuffer8 implementation structure + */ +struct IDirect3DIndexBuffer8Impl +{ + /* IUnknown fields */ + const IDirect3DIndexBuffer8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DIndexBuffer *wineD3DIndexBuffer; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; +}; + +/* --------------------- */ +/* IDirect3DBaseTexture8 */ +/* --------------------- */ + +/***************************************************************************** + * IDirect3DBaseTexture8 implementation structure + */ +struct IDirect3DBaseTexture8Impl +{ + /* IUnknown fields */ + const IDirect3DBaseTexture8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DBaseTexture *wineD3DBaseTexture; +}; + +/* --------------------- */ +/* IDirect3DCubeTexture8 */ +/* --------------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DCubeTexture8Vtbl Direct3DCubeTexture8_Vtbl; + +/***************************************************************************** + * IDirect3DCubeTexture8 implementation structure + */ +struct IDirect3DCubeTexture8Impl +{ + /* IUnknown fields */ + const IDirect3DCubeTexture8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DCubeTexture *wineD3DCubeTexture; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; +}; + +/* ----------------- */ +/* IDirect3DTexture8 */ +/* ----------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DTexture8Vtbl Direct3DTexture8_Vtbl; + +/***************************************************************************** + * IDirect3DTexture8 implementation structure + */ +struct IDirect3DTexture8Impl +{ + /* IUnknown fields */ + const IDirect3DTexture8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResourc8 fields */ + IWineD3DTexture *wineD3DTexture; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; +}; + +/* ----------------------- */ +/* IDirect3DVolumeTexture8 */ +/* ----------------------- */ + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DVolumeTexture8Vtbl Direct3DVolumeTexture8_Vtbl; + +/***************************************************************************** + * IDirect3DVolumeTexture8 implementation structure + */ +struct IDirect3DVolumeTexture8Impl +{ + /* IUnknown fields */ + const IDirect3DVolumeTexture8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DVolumeTexture *wineD3DVolumeTexture; + + /* Parent reference */ + LPDIRECT3DDEVICE8 parentDevice; +}; + +/* ----------------------- */ +/* IDirect3DStateBlockImpl */ +/* ----------------------- */ + +/* TODO: Generate a valid GUIDs */ +/* {83B073CE-6F30-11d9-C687-00046142C14F} */ +DEFINE_GUID(IID_IDirect3DStateBlock8, +0x83b073ce, 0x6f30, 0x11d9, 0xc6, 0x87, 0x0, 0x4, 0x61, 0x42, 0xc1, 0x4f); + +DEFINE_GUID(IID_IDirect3DVertexDeclaration8, +0x5dd7478d, 0xcbf3, 0x41a6, 0x8c, 0xfd, 0xfd, 0x19, 0x2b, 0x11, 0xc7, 0x90); + +DEFINE_GUID(IID_IDirect3DVertexShader8, +0xefc5557e, 0x6265, 0x4613, 0x8a, 0x94, 0x43, 0x85, 0x78, 0x89, 0xeb, 0x36); + +DEFINE_GUID(IID_IDirect3DPixelShader8, +0x6d3bdbdc, 0x5b02, 0x4415, 0xb8, 0x52, 0xce, 0x5e, 0x8b, 0xcc, 0xb2, 0x89); + + +/***************************************************************************** + * IDirect3DStateBlock8 interface + */ +#define INTERFACE IDirect3DStateBlock8 +DECLARE_INTERFACE_(IDirect3DStateBlock8, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirect3DStateBlock9 methods ***/ + STDMETHOD(GetDevice)(THIS_ struct IDirect3DDevice8** ppDevice) PURE; + STDMETHOD(Capture)(THIS) PURE; + STDMETHOD(Apply)(THIS) PURE; +}; +#undef INTERFACE + +/*** IUnknown methods ***/ +#define IDirect3DStateBlock8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DStateBlock8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DStateBlock8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirect3DStateBlock9 methods ***/ +#define IDirect3DStateBlock8_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a) +#define IDirect3DStateBlock8_Capture(p) (p)->lpVtbl->Capture(p) +#define IDirect3DStateBlock8_Apply(p) (p)->lpVtbl->Apply(p) + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DStateBlock8Vtbl Direct3DStateBlock8_Vtbl; + +/***************************************************************************** + * IDirect3DStateBlock implementation structure + */ +typedef struct IDirect3DStateBlock8Impl { + /* IUnknown fields */ + const IDirect3DStateBlock8Vtbl *lpVtbl; + LONG ref; + + /* IDirect3DResource8 fields */ + IWineD3DStateBlock *wineD3DStateBlock; +} IDirect3DStateBlock8Impl; + +/***************************************************************************** + * IDirect3DVertexDeclaration8 interface + */ +#define INTERFACE IDirect3DVertexDeclaration8 +DECLARE_INTERFACE_(IDirect3DVertexDeclaration8, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** obj_ptr) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; +}; +#undef INTERFACE + +/*** IUnknown methods ***/ +#define IDirect3DVertexDeclaration8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DVertexDeclaration8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DVertexDeclaration8_Release(p) (p)->lpVtbl->Release(p) + +/*** Implementation ***/ +extern const IDirect3DVertexDeclaration8Vtbl Direct3DVertexDeclaration8_Vtbl; + +typedef struct { + const IDirect3DVertexDeclaration8Vtbl *lpVtbl; + LONG ref_count; + + DWORD *elements; + DWORD elements_size; /* Size of elements, in bytes */ + + IWineD3DVertexDeclaration *wined3d_vertex_declaration; +} IDirect3DVertexDeclaration8Impl; + + +/***************************************************************************** + * IDirect3DVertexShader9 interface + */ +#define INTERFACE IDirect3DVertexShader8 +DECLARE_INTERFACE_(IDirect3DVertexShader8, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirect3DVertexShader9 methods ***/ + STDMETHOD(GetDevice)(THIS_ struct IDirect3DDevice8** ppDevice) PURE; + STDMETHOD(GetFunction)(THIS_ void*, UINT* pSizeOfData) PURE; +}; +#undef INTERFACE + +/*** IUnknown methods ***/ +#define IDirect3DVertexShader8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DVertexShader8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DVertexShader8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirect3DVertexShader8 methods ***/ +#define IDirect3DVertexShader8_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a) +#define IDirect3DVertexShader8_GetFunction(p,a,b) (p)->lpVtbl->GetFunction(p,a,b) + +/* ------------------------- */ +/* IDirect3DVertexShader8Impl */ +/* ------------------------- */ + +/***************************************************************************** + * IDirect3DPixelShader9 interface + */ +#define INTERFACE IDirect3DPixelShader8 +DECLARE_INTERFACE_(IDirect3DPixelShader8,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IDirect3DPixelShader8 methods ***/ + STDMETHOD(GetDevice)(THIS_ struct IDirect3DDevice8** ppDevice) PURE; + STDMETHOD(GetFunction)(THIS_ void*, UINT* pSizeOfData) PURE; +}; +#undef INTERFACE + +/*** IUnknown methods ***/ +#define IDirect3DPixelShader8_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirect3DPixelShader8_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DPixelShader8_Release(p) (p)->lpVtbl->Release(p) +/*** IDirect3DPixelShader8 methods ***/ +#define IDirect3DPixelShader8_GetDevice(p,a) (p)->lpVtbl->GetDevice(p,a) +#define IDirect3DPixelShader8_GetFunction(p,a,b) (p)->lpVtbl->GetFunction(p,a,b) + + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DVertexShader8Vtbl Direct3DVertexShader8_Vtbl; + +/***************************************************************************** + * IDirect3DVertexShader implementation structure + */ + +struct IDirect3DVertexShader8Impl { + const IDirect3DVertexShader8Vtbl *lpVtbl; + LONG ref; + + shader_handle *handle; + IDirect3DVertexDeclaration8 *vertex_declaration; + IWineD3DVertexShader *wineD3DVertexShader; +}; + + +/* ------------------------ */ +/* IDirect3DPixelShaderImpl */ +/* ------------------------ */ + + +/***************************************************************************** + * Predeclare the interface implementation structures + */ +extern const IDirect3DPixelShader8Vtbl Direct3DPixelShader8_Vtbl; + +/***************************************************************************** + * IDirect3DPixelShader implementation structure + */ +typedef struct IDirect3DPixelShader8Impl { + const IDirect3DPixelShader8Vtbl *lpVtbl; + LONG ref; + + shader_handle *handle; + /* The device, to be replaced by an IDirect3DDeviceImpl */ + IWineD3DPixelShader *wineD3DPixelShader; +} IDirect3DPixelShader8Impl; + +/** + * Internals functions + * + * to see how not defined it here + */ +void load_local_constants(const DWORD *d3d8_elements, IWineD3DVertexShader *wined3d_vertex_shader); +size_t convert_to_wined3d_declaration(const DWORD *d3d8_elements, DWORD *d3d8_elements_size, WINED3DVERTEXELEMENT **wined3d_elements); + +/* Callbacks */ +extern HRESULT WINAPI D3D8CB_CreateSurface(IUnknown *device, IUnknown *pSuperior, UINT Width, UINT Height, + WINED3DFORMAT Format, DWORD Usage, WINED3DPOOL Pool, UINT Level, + WINED3DCUBEMAP_FACES Face, IWineD3DSurface** ppSurface, + HANDLE* pSharedHandle); + +extern HRESULT WINAPI D3D8CB_CreateVolume(IUnknown *pDevice, IUnknown *pSuperior, UINT Width, UINT Height, UINT Depth, + WINED3DFORMAT Format, WINED3DPOOL Pool, DWORD Usage, + IWineD3DVolume **ppVolume, + HANDLE * pSharedHandle); + +extern HRESULT WINAPI D3D8CB_CreateDepthStencilSurface(IUnknown *device, IUnknown *pSuperior, UINT Width, UINT Height, + WINED3DFORMAT Format, WINED3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, BOOL Discard, + IWineD3DSurface** ppSurface, HANDLE* pSharedHandle); + +extern HRESULT WINAPI D3D8CB_CreateRenderTarget(IUnknown *device, IUnknown *pSuperior, UINT Width, UINT Height, + WINED3DFORMAT Format, WINED3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, BOOL Lockable, + IWineD3DSurface** ppSurface, HANDLE* pSharedHandle); + +extern ULONG WINAPI D3D8CB_DestroySwapChain (IWineD3DSwapChain *pSwapChain); + +extern ULONG WINAPI D3D8CB_DestroyDepthStencilSurface (IWineD3DSurface *pSurface); + +extern ULONG WINAPI D3D8CB_DestroyRenderTarget (IWineD3DSurface *pSurface); + +extern ULONG WINAPI D3D8CB_DestroySurface(IWineD3DSurface *pSurface); + +extern ULONG WINAPI D3D8CB_DestroyVolume(IWineD3DVolume *pVolume); + +#endif /* __WINE_D3DX8_PRIVATE_H */ diff --git a/reactos/dll/directx/wine/d3d8/device.c b/reactos/dll/directx/wine/d3d8/device.c new file mode 100644 index 00000000000..74a0d13cd28 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/device.c @@ -0,0 +1,2212 @@ +/* + * IDirect3DDevice8 implementation + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wingdi.h" +#include "wine/debug.h" + +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* Shader handle functions */ +static shader_handle *alloc_shader_handle(IDirect3DDevice8Impl *This) { + if (This->free_shader_handles) { + /* Use a free handle */ + shader_handle *handle = This->free_shader_handles; + This->free_shader_handles = *handle; + return handle; + } + if (!(This->allocated_shader_handles < This->shader_handle_table_size)) { + /* Grow the table */ + DWORD new_size = This->shader_handle_table_size + (This->shader_handle_table_size >> 1); + shader_handle *new_handles = HeapReAlloc(GetProcessHeap(), 0, This->shader_handles, new_size * sizeof(shader_handle)); + if (!new_handles) return NULL; + This->shader_handles = new_handles; + This->shader_handle_table_size = new_size; + } + + return &This->shader_handles[This->allocated_shader_handles++]; +} + +static void free_shader_handle(IDirect3DDevice8Impl *This, shader_handle *handle) { + *handle = This->free_shader_handles; + This->free_shader_handles = handle; +} + +/* IDirect3D IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DDevice8Impl_QueryInterface(LPDIRECT3DDEVICE8 iface,REFIID riid,LPVOID *ppobj) +{ + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DDevice8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DDevice8Impl_AddRef(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DDevice8Impl_Release(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + ULONG ref; + + if (This->inDestruction) return 0; + ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + int i; + + TRACE("Releasing wined3d device %p\n", This->WineD3DDevice); + EnterCriticalSection(&d3d8_cs); + This->inDestruction = TRUE; + + for(i = 0; i < This->numConvertedDecls; i++) { + IWineD3DVertexDeclaration_Release(This->decls[i].decl); + } + + IWineD3DDevice_Uninit3D(This->WineD3DDevice, D3D8CB_DestroyDepthStencilSurface, D3D8CB_DestroySwapChain); + IWineD3DDevice_Release(This->WineD3DDevice); + HeapFree(GetProcessHeap(), 0, This->shader_handles); + HeapFree(GetProcessHeap(), 0, This); + LeaveCriticalSection(&d3d8_cs); + } + return ref; +} + +/* IDirect3DDevice Interface follow: */ +static HRESULT WINAPI IDirect3DDevice8Impl_TestCooperativeLevel(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + + TRACE("(%p) : Relay\n", This); + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_TestCooperativeLevel(This->WineD3DDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static UINT WINAPI IDirect3DDevice8Impl_GetAvailableTextureMem(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + + TRACE("(%p) Relay\n", This); + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetAvailableTextureMem(This->WineD3DDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_ResourceManagerDiscardBytes(LPDIRECT3DDEVICE8 iface, DWORD Bytes) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + + TRACE("(%p) : Relay bytes(%d)\n", This, Bytes); + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_EvictManagedResources(This->WineD3DDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetDirect3D(LPDIRECT3DDEVICE8 iface, IDirect3D8** ppD3D8) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr = D3D_OK; + IWineD3D* pWineD3D; + + TRACE("(%p) Relay\n", This); + + if (NULL == ppD3D8) { + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetDirect3D(This->WineD3DDevice, &pWineD3D); + if (hr == D3D_OK && pWineD3D != NULL) + { + IWineD3D_GetParent(pWineD3D,(IUnknown **)ppD3D8); + IWineD3D_Release(pWineD3D); + } else { + FIXME("Call to IWineD3DDevice_GetDirect3D failed\n"); + *ppD3D8 = NULL; + } + TRACE("(%p) returning %p\n",This , *ppD3D8); + LeaveCriticalSection(&d3d8_cs); + + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetDeviceCaps(LPDIRECT3DDEVICE8 iface, D3DCAPS8* pCaps) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + WINED3DCAPS *pWineCaps; + + TRACE("(%p) : Relay pCaps %p\n", This, pCaps); + if(NULL == pCaps){ + return D3DERR_INVALIDCALL; + } + pWineCaps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINED3DCAPS)); + if(pWineCaps == NULL){ + return D3DERR_INVALIDCALL; /* well this is what MSDN says to return */ + } + + D3D8CAPSTOWINECAPS(pCaps, pWineCaps) + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_GetDeviceCaps(This->WineD3DDevice, pWineCaps); + LeaveCriticalSection(&d3d8_cs); + HeapFree(GetProcessHeap(), 0, pWineCaps); + + /* D3D8 doesn't support SM 2.0 or higher, so clamp to 1.x */ + if(pCaps->PixelShaderVersion > D3DPS_VERSION(1,4)){ + pCaps->PixelShaderVersion = D3DPS_VERSION(1,4); + } + if(pCaps->VertexShaderVersion > D3DVS_VERSION(1,1)){ + pCaps->VertexShaderVersion = D3DVS_VERSION(1,1); + } + + TRACE("Returning %p %p\n", This, pCaps); + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetDisplayMode(LPDIRECT3DDEVICE8 iface, D3DDISPLAYMODE* pMode) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetDisplayMode(This->WineD3DDevice, 0, (WINED3DDISPLAYMODE *) pMode); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetCreationParameters(LPDIRECT3DDEVICE8 iface, D3DDEVICE_CREATION_PARAMETERS *pParameters) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetCreationParameters(This->WineD3DDevice, (WINED3DDEVICE_CREATION_PARAMETERS *) pParameters); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetCursorProperties(LPDIRECT3DDEVICE8 iface, UINT XHotSpot, UINT YHotSpot, IDirect3DSurface8* pCursorBitmap) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DSurface8Impl *pSurface = (IDirect3DSurface8Impl*)pCursorBitmap; + HRESULT hr; + TRACE("(%p) Relay\n", This); + if(!pCursorBitmap) { + WARN("No cursor bitmap, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetCursorProperties(This->WineD3DDevice,XHotSpot,YHotSpot,(IWineD3DSurface*)pSurface->wineD3DSurface); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static void WINAPI IDirect3DDevice8Impl_SetCursorPosition(LPDIRECT3DDEVICE8 iface, UINT XScreenSpace, UINT YScreenSpace, DWORD Flags) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DDevice_SetCursorPosition(This->WineD3DDevice, XScreenSpace, YScreenSpace, Flags); + LeaveCriticalSection(&d3d8_cs); +} + +static BOOL WINAPI IDirect3DDevice8Impl_ShowCursor(LPDIRECT3DDEVICE8 iface, BOOL bShow) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + BOOL ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DDevice_ShowCursor(This->WineD3DDevice, bShow); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateAdditionalSwapChain(LPDIRECT3DDEVICE8 iface, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain8** pSwapChain) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DSwapChain8Impl* object; + HRESULT hrc = D3D_OK; + WINED3DPRESENT_PARAMETERS localParameters; + + TRACE("(%p) Relay\n", This); + + /* Fix the back buffer count */ + if(pPresentationParameters->BackBufferCount == 0) { + pPresentationParameters->BackBufferCount = 1; + } + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *pSwapChain = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + object->ref = 1; + object->lpVtbl = &Direct3DSwapChain8_Vtbl; + + /* Allocate an associated WineD3DDevice object */ + localParameters.BackBufferWidth = pPresentationParameters->BackBufferWidth; + localParameters.BackBufferHeight = pPresentationParameters->BackBufferHeight; + localParameters.BackBufferFormat = pPresentationParameters->BackBufferFormat; + localParameters.BackBufferCount = pPresentationParameters->BackBufferCount; + localParameters.MultiSampleType = pPresentationParameters->MultiSampleType; + localParameters.MultiSampleQuality = 0; /* d3d9 only */ + localParameters.SwapEffect = pPresentationParameters->SwapEffect; + localParameters.hDeviceWindow = pPresentationParameters->hDeviceWindow; + localParameters.Windowed = pPresentationParameters->Windowed; + localParameters.EnableAutoDepthStencil = pPresentationParameters->EnableAutoDepthStencil; + localParameters.AutoDepthStencilFormat = pPresentationParameters->AutoDepthStencilFormat; + localParameters.Flags = pPresentationParameters->Flags; + localParameters.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz; + localParameters.PresentationInterval = pPresentationParameters->FullScreen_PresentationInterval; + + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_CreateAdditionalSwapChain(This->WineD3DDevice, &localParameters, &object->wineD3DSwapChain, (IUnknown*)object, D3D8CB_CreateRenderTarget, D3D8CB_CreateDepthStencilSurface); + LeaveCriticalSection(&d3d8_cs); + + pPresentationParameters->BackBufferWidth = localParameters.BackBufferWidth; + pPresentationParameters->BackBufferHeight = localParameters.BackBufferHeight; + pPresentationParameters->BackBufferFormat = localParameters.BackBufferFormat; + pPresentationParameters->BackBufferCount = localParameters.BackBufferCount; + pPresentationParameters->MultiSampleType = localParameters.MultiSampleType; + pPresentationParameters->SwapEffect = localParameters.SwapEffect; + pPresentationParameters->hDeviceWindow = localParameters.hDeviceWindow; + pPresentationParameters->Windowed = localParameters.Windowed; + pPresentationParameters->EnableAutoDepthStencil = localParameters.EnableAutoDepthStencil; + pPresentationParameters->AutoDepthStencilFormat = localParameters.AutoDepthStencilFormat; + pPresentationParameters->Flags = localParameters.Flags; + pPresentationParameters->FullScreen_RefreshRateInHz = localParameters.FullScreen_RefreshRateInHz; + pPresentationParameters->FullScreen_PresentationInterval = localParameters.PresentationInterval; + + if (hrc != D3D_OK) { + FIXME("(%p) call to IWineD3DDevice_CreateAdditionalSwapChain failed\n", This); + HeapFree(GetProcessHeap(), 0 , object); + *pSwapChain = NULL; + }else{ + IUnknown_AddRef(iface); + object->parentDevice = iface; + *pSwapChain = (IDirect3DSwapChain8 *)object; + } + TRACE("(%p) returning %p\n", This, *pSwapChain); + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_Reset(LPDIRECT3DDEVICE8 iface, D3DPRESENT_PARAMETERS* pPresentationParameters) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + WINED3DPRESENT_PARAMETERS localParameters; + HRESULT hr; + + TRACE("(%p) Relay pPresentationParameters(%p)\n", This, pPresentationParameters); + + localParameters.BackBufferWidth = pPresentationParameters->BackBufferWidth; + localParameters.BackBufferHeight = pPresentationParameters->BackBufferHeight; + localParameters.BackBufferFormat = pPresentationParameters->BackBufferFormat; + localParameters.BackBufferCount = pPresentationParameters->BackBufferCount; + localParameters.MultiSampleType = pPresentationParameters->MultiSampleType; + localParameters.MultiSampleQuality = 0; /* d3d9 only */ + localParameters.SwapEffect = pPresentationParameters->SwapEffect; + localParameters.hDeviceWindow = pPresentationParameters->hDeviceWindow; + localParameters.Windowed = pPresentationParameters->Windowed; + localParameters.EnableAutoDepthStencil = pPresentationParameters->EnableAutoDepthStencil; + localParameters.AutoDepthStencilFormat = pPresentationParameters->AutoDepthStencilFormat; + localParameters.Flags = pPresentationParameters->Flags; + localParameters.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz; + localParameters.PresentationInterval = pPresentationParameters->FullScreen_PresentationInterval; + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_Reset(This->WineD3DDevice, &localParameters); + LeaveCriticalSection(&d3d8_cs); + + pPresentationParameters->BackBufferWidth = localParameters.BackBufferWidth; + pPresentationParameters->BackBufferHeight = localParameters.BackBufferHeight; + pPresentationParameters->BackBufferFormat = localParameters.BackBufferFormat; + pPresentationParameters->BackBufferCount = localParameters.BackBufferCount; + pPresentationParameters->MultiSampleType = localParameters.MultiSampleType; + pPresentationParameters->SwapEffect = localParameters.SwapEffect; + pPresentationParameters->hDeviceWindow = localParameters.hDeviceWindow; + pPresentationParameters->Windowed = localParameters.Windowed; + pPresentationParameters->EnableAutoDepthStencil = localParameters.EnableAutoDepthStencil; + pPresentationParameters->AutoDepthStencilFormat = localParameters.AutoDepthStencilFormat; + pPresentationParameters->Flags = localParameters.Flags; + pPresentationParameters->FullScreen_RefreshRateInHz = localParameters.FullScreen_RefreshRateInHz; + pPresentationParameters->FullScreen_PresentationInterval = localParameters.PresentationInterval; + + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_Present(LPDIRECT3DDEVICE8 iface, CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_Present(This->WineD3DDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetBackBuffer(LPDIRECT3DDEVICE8 iface, UINT BackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface8** ppBackBuffer) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IWineD3DSurface *retSurface = NULL; + HRESULT rc = D3D_OK; + + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + rc = IWineD3DDevice_GetBackBuffer(This->WineD3DDevice, 0, BackBuffer, (WINED3DBACKBUFFER_TYPE) Type, (IWineD3DSurface **)&retSurface); + if (rc == D3D_OK && NULL != retSurface && NULL != ppBackBuffer) { + IWineD3DSurface_GetParent(retSurface, (IUnknown **)ppBackBuffer); + IWineD3DSurface_Release(retSurface); + } + LeaveCriticalSection(&d3d8_cs); + return rc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetRasterStatus(LPDIRECT3DDEVICE8 iface, D3DRASTER_STATUS* pRasterStatus) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetRasterStatus(This->WineD3DDevice, 0, (WINED3DRASTER_STATUS *) pRasterStatus); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static void WINAPI IDirect3DDevice8Impl_SetGammaRamp(LPDIRECT3DDEVICE8 iface, DWORD Flags, CONST D3DGAMMARAMP* pRamp) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + TRACE("(%p) Relay\n", This); + + /* Note: D3DGAMMARAMP is compatible with WINED3DGAMMARAMP */ + EnterCriticalSection(&d3d8_cs); + IWineD3DDevice_SetGammaRamp(This->WineD3DDevice, 0, Flags, (CONST WINED3DGAMMARAMP *) pRamp); + LeaveCriticalSection(&d3d8_cs); +} + +static void WINAPI IDirect3DDevice8Impl_GetGammaRamp(LPDIRECT3DDEVICE8 iface, D3DGAMMARAMP* pRamp) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + TRACE("(%p) Relay\n", This); + + /* Note: D3DGAMMARAMP is compatible with WINED3DGAMMARAMP */ + EnterCriticalSection(&d3d8_cs); + IWineD3DDevice_GetGammaRamp(This->WineD3DDevice, 0, (WINED3DGAMMARAMP *) pRamp); + LeaveCriticalSection(&d3d8_cs); +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateTexture(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, UINT Levels, DWORD Usage, + D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture8 **ppTexture) { + IDirect3DTexture8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + + TRACE("(%p) : W(%d) H(%d), Lvl(%d) d(%d), Fmt(%u), Pool(%d)\n", This, Width, Height, Levels, Usage, Format, Pool); + + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTexture8Impl)); + + if (NULL == object) { + FIXME("Allocation of memory failed\n"); +/* *ppTexture = NULL; */ + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DTexture8_Vtbl; + object->ref = 1; + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_CreateTexture(This->WineD3DDevice, Width, Height, Levels, Usage & WINED3DUSAGE_MASK, + (WINED3DFORMAT)Format, (WINED3DPOOL) Pool, &object->wineD3DTexture, NULL, (IUnknown *)object, D3D8CB_CreateSurface); + LeaveCriticalSection(&d3d8_cs); + + if (FAILED(hrc)) { + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateTexture failed\n", This); + HeapFree(GetProcessHeap(), 0, object); +/* *ppTexture = NULL; */ + } else { + IUnknown_AddRef(iface); + object->parentDevice = iface; + *ppTexture = (LPDIRECT3DTEXTURE8) object; + } + + TRACE("(%p) Created Texture %p, %p\n",This,object,object->wineD3DTexture); + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateVolumeTexture(LPDIRECT3DDEVICE8 iface, + UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, + D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture8** ppVolumeTexture) { + + IDirect3DVolumeTexture8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + + TRACE("(%p) Relay\n", This); + + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVolumeTexture8Impl)); + if (NULL == object) { + FIXME("(%p) allocation of memory failed\n", This); + *ppVolumeTexture = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DVolumeTexture8_Vtbl; + object->ref = 1; + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_CreateVolumeTexture(This->WineD3DDevice, Width, Height, Depth, Levels, Usage & WINED3DUSAGE_MASK, + (WINED3DFORMAT)Format, (WINED3DPOOL) Pool, &object->wineD3DVolumeTexture, NULL, + (IUnknown *)object, D3D8CB_CreateVolume); + LeaveCriticalSection(&d3d8_cs); + + if (hrc != D3D_OK) { + + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateVolumeTexture failed\n", This); + HeapFree(GetProcessHeap(), 0, object); + *ppVolumeTexture = NULL; + } else { + IUnknown_AddRef(iface); + object->parentDevice = iface; + *ppVolumeTexture = (LPDIRECT3DVOLUMETEXTURE8) object; + } + TRACE("(%p) returning %p\n", This , *ppVolumeTexture); + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateCubeTexture(LPDIRECT3DDEVICE8 iface, UINT EdgeLength, UINT Levels, DWORD Usage, + D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture8** ppCubeTexture) { + + IDirect3DCubeTexture8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr = D3D_OK; + + TRACE("(%p) : ELen(%d) Lvl(%d) Usage(%d) fmt(%u), Pool(%d)\n" , This, EdgeLength, Levels, Usage, Format, Pool); + + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + + if (NULL == object) { + FIXME("(%p) allocation of CubeTexture failed\n", This); + *ppCubeTexture = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DCubeTexture8_Vtbl; + object->ref = 1; + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_CreateCubeTexture(This->WineD3DDevice, EdgeLength, Levels, Usage & WINED3DUSAGE_MASK, + (WINED3DFORMAT)Format, (WINED3DPOOL) Pool, &object->wineD3DCubeTexture, NULL, (IUnknown*)object, + D3D8CB_CreateSurface); + LeaveCriticalSection(&d3d8_cs); + + if (hr != D3D_OK){ + + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateCubeTexture failed\n", This); + HeapFree(GetProcessHeap(), 0, object); + *ppCubeTexture = NULL; + } else { + IUnknown_AddRef(iface); + object->parentDevice = iface; + *ppCubeTexture = (LPDIRECT3DCUBETEXTURE8) object; + } + + TRACE("(%p) returning %p\n",This, *ppCubeTexture); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateVertexBuffer(LPDIRECT3DDEVICE8 iface, UINT Size, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer8** ppVertexBuffer) { + IDirect3DVertexBuffer8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + + TRACE("(%p) Relay\n", This); + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVertexBuffer8Impl)); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *ppVertexBuffer = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DVertexBuffer8_Vtbl; + object->ref = 1; + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_CreateVertexBuffer(This->WineD3DDevice, Size, Usage & WINED3DUSAGE_MASK, FVF, (WINED3DPOOL) Pool, &(object->wineD3DVertexBuffer), NULL, (IUnknown *)object); + LeaveCriticalSection(&d3d8_cs); + + if (D3D_OK != hrc) { + + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateVertexBuffer failed\n", This); + HeapFree(GetProcessHeap(), 0, object); + *ppVertexBuffer = NULL; + } else { + IUnknown_AddRef(iface); + object->parentDevice = iface; + *ppVertexBuffer = (LPDIRECT3DVERTEXBUFFER8) object; + } + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateIndexBuffer(LPDIRECT3DDEVICE8 iface, UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer8** ppIndexBuffer) { + IDirect3DIndexBuffer8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + + TRACE("(%p) Relay\n", This); + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *ppIndexBuffer = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DIndexBuffer8_Vtbl; + object->ref = 1; + TRACE("Calling wined3d create index buffer\n"); + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_CreateIndexBuffer(This->WineD3DDevice, Length, Usage & WINED3DUSAGE_MASK, Format, (WINED3DPOOL) Pool, &object->wineD3DIndexBuffer, NULL, (IUnknown *)object); + LeaveCriticalSection(&d3d8_cs); + + if (D3D_OK != hrc) { + + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateIndexBuffer failed\n", This); + HeapFree(GetProcessHeap(), 0, object); + *ppIndexBuffer = NULL; + } else { + IUnknown_AddRef(iface); + object->parentDevice = iface; + *ppIndexBuffer = (LPDIRECT3DINDEXBUFFER8)object; + } + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateSurface(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IDirect3DSurface8 **ppSurface,D3DRESOURCETYPE Type, UINT Usage,D3DPOOL Pool, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality) { + HRESULT hrc; + IDirect3DSurface8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + TRACE("(%p) Relay\n", This); + if(MultisampleQuality < 0) { + FIXME("MultisampleQuality out of range %d, substituting 0\n", MultisampleQuality); + /*FIXME: Find out what windows does with a MultisampleQuality < 0 */ + MultisampleQuality=0; + } + + if(MultisampleQuality > 0){ + FIXME("MultisampleQuality set to %d, substituting 0\n" , MultisampleQuality); + /* + MultisampleQuality + [in] Quality level. The valid range is between zero and one less than the level returned by pQualityLevels used by IDirect3D8::CheckDeviceMultiSampleType. Passing a larger value returns the error D3DERR_INVALIDCALL. The MultisampleQuality values of paired render targets, depth stencil surfaces, and the MultiSample type must all match. + */ + MultisampleQuality=0; + } + /*FIXME: Check MAX bounds of MultisampleQuality*/ + + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DSurface8Impl)); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *ppSurface = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DSurface8_Vtbl; + object->ref = 1; + + TRACE("(%p) : w(%d) h(%d) fmt(%d) surf@%p\n", This, Width, Height, Format, *ppSurface); + + /* Not called from the VTable, no locking needed */ + hrc = IWineD3DDevice_CreateSurface(This->WineD3DDevice, Width, Height, Format, Lockable, Discard, Level, &object->wineD3DSurface, Type, Usage & WINED3DUSAGE_MASK, (WINED3DPOOL) Pool,MultiSample,MultisampleQuality, NULL, SURFACE_OPENGL, (IUnknown *)object); + if (hrc != D3D_OK || NULL == object->wineD3DSurface) { + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateSurface failed\n", This); + HeapFree(GetProcessHeap(), 0, object); + *ppSurface = NULL; + } else { + IUnknown_AddRef(iface); + object->parentDevice = iface; + *ppSurface = (LPDIRECT3DSURFACE8) object; + } + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateRenderTarget(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, BOOL Lockable, IDirect3DSurface8** ppSurface) { + HRESULT hr; + TRACE("Relay\n"); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DDevice8Impl_CreateSurface(iface, Width, Height, Format, Lockable, FALSE /* Discard */, 0 /* Level */ , ppSurface, D3DRTYPE_SURFACE, D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, MultiSample, 0); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateDepthStencilSurface(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, IDirect3DSurface8** ppSurface) { + HRESULT hr; + TRACE("Relay\n"); + + /* TODO: Verify that Discard is false */ + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DDevice8Impl_CreateSurface(iface, Width, Height, Format, TRUE /* Lockable */, FALSE, 0 /* Level */ + ,ppSurface, D3DRTYPE_SURFACE, D3DUSAGE_DEPTHSTENCIL, + D3DPOOL_DEFAULT, MultiSample, 0); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateImageSurface(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, IDirect3DSurface8** ppSurface) { + HRESULT hr; + TRACE("Relay\n"); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DDevice8Impl_CreateSurface(iface, Width, Height, Format, TRUE /* Loackable */ , FALSE /*Discard*/ , 0 /* Level */ , ppSurface, D3DRTYPE_SURFACE, 0 /* Usage (undefined/none) */ , D3DPOOL_SCRATCH, D3DMULTISAMPLE_NONE, 0 /* MultisampleQuality */); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CopyRects(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8 *pSourceSurface, CONST RECT *pSourceRects, UINT cRects, IDirect3DSurface8 *pDestinationSurface, CONST POINT *pDestPoints) { + IDirect3DSurface8Impl *Source = (IDirect3DSurface8Impl *) pSourceSurface; + IDirect3DSurface8Impl *Dest = (IDirect3DSurface8Impl *) pDestinationSurface; + + HRESULT hr = WINED3D_OK; + WINED3DFORMAT srcFormat, destFormat; + UINT srcWidth, destWidth; + UINT srcHeight, destHeight; + UINT srcSize; + WINED3DSURFACE_DESC winedesc; + + TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", iface, + pSourceSurface, pSourceRects, cRects, pDestinationSurface, pDestPoints); + + + /* Check that the source texture is in WINED3DPOOL_SYSTEMMEM and the destination texture is in WINED3DPOOL_DEFAULT */ + memset(&winedesc, 0, sizeof(winedesc)); + + winedesc.Format = &srcFormat; + winedesc.Width = &srcWidth; + winedesc.Height = &srcHeight; + winedesc.Size = &srcSize; + IWineD3DSurface_GetDesc(Source->wineD3DSurface, &winedesc); + + winedesc.Format = &destFormat; + winedesc.Width = &destWidth; + winedesc.Height = &destHeight; + winedesc.Size = NULL; + EnterCriticalSection(&d3d8_cs); + IWineD3DSurface_GetDesc(Dest->wineD3DSurface, &winedesc); + + /* Check that the source and destination formats match */ + if (srcFormat != destFormat && WINED3DFMT_UNKNOWN != destFormat) { + WARN("(%p) source %p format must match the dest %p format, returning WINED3DERR_INVALIDCALL\n", iface, pSourceSurface, pDestinationSurface); + LeaveCriticalSection(&d3d8_cs); + return WINED3DERR_INVALIDCALL; + } else if (WINED3DFMT_UNKNOWN == destFormat) { + TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", iface); + IWineD3DSurface_SetFormat(Dest->wineD3DSurface, srcFormat); + destFormat = srcFormat; + } + + /* Quick if complete copy ... */ + if (cRects == 0 && pSourceRects == NULL && pDestPoints == NULL) { + IWineD3DSurface_BltFast(Dest->wineD3DSurface, 0, 0, Source->wineD3DSurface, NULL, WINEDDBLTFAST_NOCOLORKEY); + } else { + unsigned int i; + /* Copy rect by rect */ + if (NULL != pSourceRects && NULL != pDestPoints) { + for (i = 0; i < cRects; ++i) { + IWineD3DSurface_BltFast(Dest->wineD3DSurface, pDestPoints[i].x, pDestPoints[i].y, Source->wineD3DSurface, (RECT *) &pSourceRects[i], WINEDDBLTFAST_NOCOLORKEY); + } + } else { + for (i = 0; i < cRects; ++i) { + IWineD3DSurface_BltFast(Dest->wineD3DSurface, 0, 0, Source->wineD3DSurface, (RECT *) &pSourceRects[i], WINEDDBLTFAST_NOCOLORKEY); + } + } + } + LeaveCriticalSection(&d3d8_cs); + + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_UpdateTexture(LPDIRECT3DDEVICE8 iface, IDirect3DBaseTexture8* pSourceTexture, IDirect3DBaseTexture8* pDestinationTexture) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_UpdateTexture(This->WineD3DDevice, ((IDirect3DBaseTexture8Impl *)pSourceTexture)->wineD3DBaseTexture, ((IDirect3DBaseTexture8Impl *)pDestinationTexture)->wineD3DBaseTexture); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetFrontBuffer(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8* pDestSurface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DSurface8Impl *destSurface = (IDirect3DSurface8Impl *)pDestSurface; + HRESULT hr; + + TRACE("(%p) Relay\n" , This); + + if (pDestSurface == NULL) { + WARN("(%p) : Caller passed NULL as pDestSurface returning D3DERR_INVALIDCALL\n", This); + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetFrontBufferData(This->WineD3DDevice, 0, destSurface->wineD3DSurface); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetRenderTarget(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8* pRenderTarget, IDirect3DSurface8* pNewZStencil) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DSurface8Impl *pSurface = (IDirect3DSurface8Impl *)pRenderTarget; + IDirect3DSurface8Impl *pZSurface = (IDirect3DSurface8Impl *)pNewZStencil; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + IWineD3DDevice_SetDepthStencilSurface(This->WineD3DDevice, NULL == pZSurface ? NULL : (IWineD3DSurface *)pZSurface->wineD3DSurface); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetRenderTarget(This->WineD3DDevice, 0, pSurface ? (IWineD3DSurface *)pSurface->wineD3DSurface : NULL); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetRenderTarget(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8** ppRenderTarget) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr = D3D_OK; + IWineD3DSurface *pRenderTarget; + + TRACE("(%p) Relay\n" , This); + + if (ppRenderTarget == NULL) { + return D3DERR_INVALIDCALL; + } + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetRenderTarget(This->WineD3DDevice, 0, &pRenderTarget); + + if (hr == D3D_OK && pRenderTarget != NULL) { + IWineD3DSurface_GetParent(pRenderTarget,(IUnknown**)ppRenderTarget); + IWineD3DSurface_Release(pRenderTarget); + } else { + FIXME("Call to IWineD3DDevice_GetRenderTarget failed\n"); + *ppRenderTarget = NULL; + } + LeaveCriticalSection(&d3d8_cs); + + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetDepthStencilSurface(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8** ppZStencilSurface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr = D3D_OK; + IWineD3DSurface *pZStencilSurface; + + TRACE("(%p) Relay\n" , This); + if(ppZStencilSurface == NULL){ + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + hr=IWineD3DDevice_GetDepthStencilSurface(This->WineD3DDevice,&pZStencilSurface); + if(hr == D3D_OK && pZStencilSurface != NULL){ + IWineD3DSurface_GetParent(pZStencilSurface,(IUnknown**)ppZStencilSurface); + IWineD3DSurface_Release(pZStencilSurface); + }else{ + FIXME("Call to IWineD3DDevice_GetDepthStencilSurface failed\n"); + *ppZStencilSurface = NULL; + } + LeaveCriticalSection(&d3d8_cs); + + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_BeginScene(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_BeginScene(This->WineD3DDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_EndScene(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_EndScene(This->WineD3DDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_Clear(LPDIRECT3DDEVICE8 iface, DWORD Count, CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DRECT is compatible with WINED3DRECT */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_Clear(This->WineD3DDevice, Count, (CONST WINED3DRECT*) pRects, Flags, Color, Z, Stencil); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* lpMatrix) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DMATRIX is compatible with WINED3DMATRIX */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetTransform(This->WineD3DDevice, State, (CONST WINED3DMATRIX*) lpMatrix); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE State,D3DMATRIX* pMatrix) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DMATRIX is compatible with WINED3DMATRIX */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetTransform(This->WineD3DDevice, State, (WINED3DMATRIX*) pMatrix); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_MultiplyTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DMATRIX is compatible with WINED3DMATRIX */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_MultiplyTransform(This->WineD3DDevice, State, (CONST WINED3DMATRIX*) pMatrix); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetViewport(LPDIRECT3DDEVICE8 iface, CONST D3DVIEWPORT8* pViewport) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DVIEWPORT8 is compatible with WINED3DVIEWPORT */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetViewport(This->WineD3DDevice, (const WINED3DVIEWPORT *)pViewport); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetViewport(LPDIRECT3DDEVICE8 iface, D3DVIEWPORT8* pViewport) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DVIEWPORT8 is compatible with WINED3DVIEWPORT */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetViewport(This->WineD3DDevice, (WINED3DVIEWPORT *)pViewport); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetMaterial(LPDIRECT3DDEVICE8 iface, CONST D3DMATERIAL8* pMaterial) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DMATERIAL8 is compatible with WINED3DMATERIAL */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetMaterial(This->WineD3DDevice, (const WINED3DMATERIAL *)pMaterial); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetMaterial(LPDIRECT3DDEVICE8 iface, D3DMATERIAL8* pMaterial) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DMATERIAL8 is compatible with WINED3DMATERIAL */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetMaterial(This->WineD3DDevice, (WINED3DMATERIAL *)pMaterial); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD Index, CONST D3DLIGHT8* pLight) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DLIGHT8 is compatible with WINED3DLIGHT */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetLight(This->WineD3DDevice, Index, (const WINED3DLIGHT *)pLight); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,D3DLIGHT8* pLight) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + /* Note: D3DLIGHT8 is compatible with WINED3DLIGHT */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetLight(This->WineD3DDevice, Index, (WINED3DLIGHT *)pLight); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_LightEnable(LPDIRECT3DDEVICE8 iface, DWORD Index,BOOL Enable) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetLightEnable(This->WineD3DDevice, Index, Enable); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetLightEnable(LPDIRECT3DDEVICE8 iface, DWORD Index,BOOL* pEnable) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetLightEnable(This->WineD3DDevice, Index, pEnable); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetClipPlane(LPDIRECT3DDEVICE8 iface, DWORD Index,CONST float* pPlane) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetClipPlane(This->WineD3DDevice, Index, pPlane); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetClipPlane(LPDIRECT3DDEVICE8 iface, DWORD Index,float* pPlane) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetClipPlane(This->WineD3DDevice, Index, pPlane); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetRenderState(LPDIRECT3DDEVICE8 iface, D3DRENDERSTATETYPE State,DWORD Value) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetRenderState(This->WineD3DDevice, State, Value); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetRenderState(LPDIRECT3DDEVICE8 iface, D3DRENDERSTATETYPE State,DWORD* pValue) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetRenderState(This->WineD3DDevice, State, pValue); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_BeginStateBlock(LPDIRECT3DDEVICE8 iface) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p)\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_BeginStateBlock(This->WineD3DDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_EndStateBlock(LPDIRECT3DDEVICE8 iface, DWORD* pToken) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + IWineD3DStateBlock* wineD3DStateBlock; + IDirect3DStateBlock8Impl* object; + + TRACE("(%p) Relay\n", This); + + /* Tell wineD3D to endstatablock before anything else (in case we run out + * of memory later and cause locking problems) + */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_EndStateBlock(This->WineD3DDevice , &wineD3DStateBlock); + if (hr != D3D_OK) { + FIXME("IWineD3DDevice_EndStateBlock returned an error\n"); + LeaveCriticalSection(&d3d8_cs); + return hr; + } + + /* allocate a new IDirectD3DStateBlock */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY ,sizeof(IDirect3DStateBlock8Impl)); + object->ref = 1; + object->lpVtbl = &Direct3DStateBlock8_Vtbl; + + object->wineD3DStateBlock = wineD3DStateBlock; + + *pToken = (DWORD)object; + TRACE("(%p)Returning %p %p\n", This, object, wineD3DStateBlock); + + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_ApplyStateBlock(LPDIRECT3DDEVICE8 iface, DWORD Token) { + IDirect3DStateBlock8Impl *pSB = (IDirect3DStateBlock8Impl*) Token; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + + TRACE("(%p) %p Relay\n", This, pSB); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DStateBlock_Apply(pSB->wineD3DStateBlock); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CaptureStateBlock(LPDIRECT3DDEVICE8 iface, DWORD Token) { + IDirect3DStateBlock8Impl* pSB = (IDirect3DStateBlock8Impl *)Token; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + + TRACE("(%p) %p Relay\n", This, pSB); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DStateBlock_Capture(pSB->wineD3DStateBlock); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DeleteStateBlock(LPDIRECT3DDEVICE8 iface, DWORD Token) { + IDirect3DStateBlock8Impl* pSB = (IDirect3DStateBlock8Impl *)Token; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + while(IUnknown_Release((IUnknown *)pSB)); + LeaveCriticalSection(&d3d8_cs); + + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateStateBlock(LPDIRECT3DDEVICE8 iface, D3DSTATEBLOCKTYPE Type, DWORD* pToken) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DStateBlock8Impl *object; + HRESULT hrc = D3D_OK; + + TRACE("(%p) Relay\n", This); + + if(Type != D3DSBT_ALL && Type != D3DSBT_PIXELSTATE && + Type != D3DSBT_VERTEXSTATE ) { + WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL\n"); + return D3DERR_INVALIDCALL; + } + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DStateBlock8Impl)); + if (NULL == object) { + *pToken = 0; + return E_OUTOFMEMORY; + } + object->lpVtbl = &Direct3DStateBlock8_Vtbl; + object->ref = 1; + + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_CreateStateBlock(This->WineD3DDevice, (WINED3DSTATEBLOCKTYPE)Type, &object->wineD3DStateBlock, (IUnknown *)object); + LeaveCriticalSection(&d3d8_cs); + if(D3D_OK != hrc){ + FIXME("(%p) Call to IWineD3DDevice_CreateStateBlock failed.\n", This); + HeapFree(GetProcessHeap(), 0, object); + *pToken = 0; + } else { + *pToken = (DWORD)object; + } + TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object); + + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetClipStatus(LPDIRECT3DDEVICE8 iface, CONST D3DCLIPSTATUS8* pClipStatus) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); +/* FIXME: Verify that D3DCLIPSTATUS8 ~= WINED3DCLIPSTATUS */ + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetClipStatus(This->WineD3DDevice, (const WINED3DCLIPSTATUS *)pClipStatus); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetClipStatus(LPDIRECT3DDEVICE8 iface, D3DCLIPSTATUS8* pClipStatus) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetClipStatus(This->WineD3DDevice, (WINED3DCLIPSTATUS *)pClipStatus); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetTexture(LPDIRECT3DDEVICE8 iface, DWORD Stage,IDirect3DBaseTexture8** ppTexture) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IWineD3DBaseTexture *retTexture = NULL; + HRESULT rc = D3D_OK; + + TRACE("(%p) Relay\n" , This); + + if(ppTexture == NULL){ + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + rc = IWineD3DDevice_GetTexture(This->WineD3DDevice, Stage, (IWineD3DBaseTexture **)&retTexture); + if (rc == D3D_OK && NULL != retTexture) { + IWineD3DBaseTexture_GetParent(retTexture, (IUnknown **)ppTexture); + IWineD3DBaseTexture_Release(retTexture); + } else { + FIXME("Call to get texture (%d) failed (%p)\n", Stage, retTexture); + *ppTexture = NULL; + } + LeaveCriticalSection(&d3d8_cs); + + return rc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetTexture(LPDIRECT3DDEVICE8 iface, DWORD Stage, IDirect3DBaseTexture8* pTexture) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay %d %p\n" , This, Stage, pTexture); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetTexture(This->WineD3DDevice, Stage, + pTexture==NULL ? NULL : ((IDirect3DBaseTexture8Impl *)pTexture)->wineD3DBaseTexture); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetTextureStageState(LPDIRECT3DDEVICE8 iface, DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD* pValue) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + switch(Type) { + case D3DTSS_ADDRESSU: + Type = WINED3DSAMP_ADDRESSU; + break; + case D3DTSS_ADDRESSV: + Type = WINED3DSAMP_ADDRESSV; + break; + case D3DTSS_ADDRESSW: + Type = WINED3DSAMP_ADDRESSW; + break; + case D3DTSS_BORDERCOLOR: + Type = WINED3DSAMP_BORDERCOLOR; + break; + case D3DTSS_MAGFILTER: + Type = WINED3DSAMP_MAGFILTER; + break; + case D3DTSS_MAXANISOTROPY: + Type = WINED3DSAMP_MAXANISOTROPY; + break; + case D3DTSS_MAXMIPLEVEL: + Type = WINED3DSAMP_MAXMIPLEVEL; + break; + case D3DTSS_MINFILTER: + Type = WINED3DSAMP_MINFILTER; + break; + case D3DTSS_MIPFILTER: + Type = WINED3DSAMP_MIPFILTER; + break; + case D3DTSS_MIPMAPLODBIAS: + Type = WINED3DSAMP_MIPMAPLODBIAS; + break; + default: + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetTextureStageState(This->WineD3DDevice, Stage, Type, pValue); + LeaveCriticalSection(&d3d8_cs); + return hr; + } + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetSamplerState(This->WineD3DDevice, Stage, Type, pValue); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetTextureStageState(LPDIRECT3DDEVICE8 iface, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + switch(Type) { + case D3DTSS_ADDRESSU: + Type = WINED3DSAMP_ADDRESSU; + break; + case D3DTSS_ADDRESSV: + Type = WINED3DSAMP_ADDRESSV; + break; + case D3DTSS_ADDRESSW: + Type = WINED3DSAMP_ADDRESSW; + break; + case D3DTSS_BORDERCOLOR: + Type = WINED3DSAMP_BORDERCOLOR; + break; + case D3DTSS_MAGFILTER: + Type = WINED3DSAMP_MAGFILTER; + break; + case D3DTSS_MAXANISOTROPY: + Type = WINED3DSAMP_MAXANISOTROPY; + break; + case D3DTSS_MAXMIPLEVEL: + Type = WINED3DSAMP_MAXMIPLEVEL; + break; + case D3DTSS_MINFILTER: + Type = WINED3DSAMP_MINFILTER; + break; + case D3DTSS_MIPFILTER: + Type = WINED3DSAMP_MIPFILTER; + break; + case D3DTSS_MIPMAPLODBIAS: + Type = WINED3DSAMP_MIPMAPLODBIAS; + break; + default: + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetTextureStageState(This->WineD3DDevice, Stage, Type, Value); + LeaveCriticalSection(&d3d8_cs); + return hr; + } + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetSamplerState(This->WineD3DDevice, Stage, Type, Value); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_ValidateDevice(LPDIRECT3DDEVICE8 iface, DWORD* pNumPasses) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_ValidateDevice(This->WineD3DDevice, pNumPasses); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetInfo(LPDIRECT3DDEVICE8 iface, DWORD DevInfoID, void* pDevInfoStruct, DWORD DevInfoStructSize) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + FIXME("(%p) : stub\n", This); + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetPaletteEntries(LPDIRECT3DDEVICE8 iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetPaletteEntries(This->WineD3DDevice, PaletteNumber, pEntries); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetPaletteEntries(LPDIRECT3DDEVICE8 iface, UINT PaletteNumber, PALETTEENTRY* pEntries) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetPaletteEntries(This->WineD3DDevice, PaletteNumber, pEntries); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetCurrentTexturePalette(LPDIRECT3DDEVICE8 iface, UINT PaletteNumber) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetCurrentTexturePalette(This->WineD3DDevice, PaletteNumber); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetCurrentTexturePalette(LPDIRECT3DDEVICE8 iface, UINT *PaletteNumber) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetCurrentTexturePalette(This->WineD3DDevice, PaletteNumber); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DrawPrimitive(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DrawPrimitive(This->WineD3DDevice, PrimitiveType, StartVertex, PrimitiveCount); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DrawIndexedPrimitive(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType, + UINT MinVertexIndex,UINT NumVertices,UINT startIndex,UINT primCount) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DrawIndexedPrimitive(This->WineD3DDevice, PrimitiveType, MinVertexIndex, NumVertices, startIndex, primCount); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DrawPrimitiveUP(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DrawPrimitiveUP(This->WineD3DDevice, PrimitiveType, PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DrawIndexedPrimitiveUP(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex, + UINT NumVertexIndices,UINT PrimitiveCount,CONST void* pIndexData, + D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData, + UINT VertexStreamZeroStride) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DrawIndexedPrimitiveUP(This->WineD3DDevice, PrimitiveType, MinVertexIndex, NumVertexIndices, PrimitiveCount, + pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_ProcessVertices(LPDIRECT3DDEVICE8 iface, UINT SrcStartIndex,UINT DestIndex,UINT VertexCount,IDirect3DVertexBuffer8* pDestBuffer,DWORD Flags) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_ProcessVertices(This->WineD3DDevice,SrcStartIndex, DestIndex, VertexCount, ((IDirect3DVertexBuffer8Impl *)pDestBuffer)->wineD3DVertexBuffer, NULL, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateVertexDeclaration(IDirect3DDevice8 *iface, CONST DWORD *declaration, IDirect3DVertexDeclaration8 **decl_ptr) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DVertexDeclaration8Impl *object; + WINED3DVERTEXELEMENT *wined3d_elements; + size_t wined3d_element_count; + HRESULT hr = D3D_OK; + + TRACE("(%p) : declaration %p\n", This, declaration); + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if (!object) { + ERR("Memory allocation failed\n"); + *decl_ptr = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->ref_count = 1; + object->lpVtbl = &Direct3DVertexDeclaration8_Vtbl; + + wined3d_element_count = convert_to_wined3d_declaration(declaration, &object->elements_size, &wined3d_elements); + object->elements = HeapAlloc(GetProcessHeap(), 0, object->elements_size); + if (!object->elements) { + ERR("Memory allocation failed\n"); + HeapFree(GetProcessHeap(), 0, wined3d_elements); + HeapFree(GetProcessHeap(), 0, object); + *decl_ptr = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + CopyMemory(object->elements, declaration, object->elements_size); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_CreateVertexDeclaration(This->WineD3DDevice, &object->wined3d_vertex_declaration, + (IUnknown *)object, wined3d_elements, wined3d_element_count); + LeaveCriticalSection(&d3d8_cs); + HeapFree(GetProcessHeap(), 0, wined3d_elements); + + if (FAILED(hr)) { + ERR("(%p) : IWineD3DDevice_CreateVertexDeclaration call failed\n", This); + HeapFree(GetProcessHeap(), 0, object->elements); + HeapFree(GetProcessHeap(), 0, object); + } else { + *decl_ptr = (IDirect3DVertexDeclaration8 *)object; + TRACE("(%p) : Created vertex declaration %p\n", This, object); + } + + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_CreateVertexShader(LPDIRECT3DDEVICE8 iface, CONST DWORD* pDeclaration, CONST DWORD* pFunction, DWORD* ppShader, DWORD Usage) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + IDirect3DVertexShader8Impl *object; + IWineD3DVertexDeclaration *wined3d_vertex_declaration; + + /* Setup a stub object for now */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + TRACE("(%p) : pFunction(%p), ppShader(%p)\n", This, pFunction, ppShader); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *ppShader = 0; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->ref = 1; + object->lpVtbl = &Direct3DVertexShader8_Vtbl; + + EnterCriticalSection(&d3d8_cs); + hrc = IDirect3DDevice8Impl_CreateVertexDeclaration(iface, pDeclaration, &object->vertex_declaration); + if (FAILED(hrc)) { + ERR("(%p) : IDirect3DDeviceImpl_CreateVertexDeclaration call failed\n", This); + LeaveCriticalSection(&d3d8_cs); + HeapFree(GetProcessHeap(), 0, object); + *ppShader = 0; + return D3DERR_INVALIDCALL; + } + wined3d_vertex_declaration = ((IDirect3DVertexDeclaration8Impl *)object->vertex_declaration)->wined3d_vertex_declaration; + + /* Usage is missing ... Use SetRenderState to set the sw vp render state in SetVertexShader */ + hrc = IWineD3DDevice_CreateVertexShader(This->WineD3DDevice, wined3d_vertex_declaration, pFunction, &object->wineD3DVertexShader, (IUnknown *)object); + + if (FAILED(hrc)) { + /* free up object */ + FIXME("Call to IWineD3DDevice_CreateVertexShader failed\n"); + HeapFree(GetProcessHeap(), 0, object); + *ppShader = 0; + } else { + /* TODO: Store the VS declarations locally so that they can be derefferenced with a value higher than VS_HIGHESTFIXEDFXF */ + shader_handle *handle = alloc_shader_handle(This); + if (!handle) { + ERR("Failed to allocate shader handle\n"); + IDirect3DVertexShader8_Release((IUnknown *)object); + hrc = E_OUTOFMEMORY; + } else { + object->handle = handle; + *handle = object; + *ppShader = (handle - This->shader_handles) + VS_HIGHESTFIXEDFXF + 1; + + load_local_constants(pDeclaration, object->wineD3DVertexShader); + } + } + LeaveCriticalSection(&d3d8_cs); + TRACE("(%p) : returning %p (handle %#x)\n", This, object, *ppShader); + + return hrc; +} + +IWineD3DVertexDeclaration *IDirect3DDevice8Impl_FindDecl(IDirect3DDevice8Impl *This, DWORD fvf) +{ + HRESULT hr; + IWineD3DVertexDeclaration* pDecl = NULL; + int p, low, high; /* deliberately signed */ + struct FvfToDecl *convertedDecls = This->decls; + + TRACE("Searching for declaration for fvf %08x... ", fvf); + + low = 0; + high = This->numConvertedDecls - 1; + while(low <= high) { + p = (low + high) >> 1; + TRACE("%d ", p); + if(convertedDecls[p].fvf == fvf) { + TRACE("found %p\n", convertedDecls[p].decl); + return convertedDecls[p].decl; + } else if(convertedDecls[p].fvf < fvf) { + low = p + 1; + } else { + high = p - 1; + } + } + TRACE("not found. Creating and inserting at position %d.\n", low); + + hr = IWineD3DDevice_CreateVertexDeclarationFromFVF(This->WineD3DDevice, + &pDecl, + (IUnknown *) This, + fvf); + if (FAILED(hr)) return NULL; + + if(This->declArraySize == This->numConvertedDecls) { + int grow = This->declArraySize / 2; + convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls, + sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow)); + if(!convertedDecls) { + /* This will destroy it */ + IWineD3DVertexDeclaration_Release(pDecl); + return NULL; + } + This->decls = convertedDecls; + This->declArraySize += grow; + } + + memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low)); + convertedDecls[low].decl = pDecl; + convertedDecls[low].fvf = fvf; + This->numConvertedDecls++; + + TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls); + return pDecl; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetVertexShader(LPDIRECT3DDEVICE8 iface, DWORD pShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hrc = D3D_OK; + + TRACE("(%p) : Relay\n", This); + EnterCriticalSection(&d3d8_cs); + if (VS_HIGHESTFIXEDFXF >= pShader) { + TRACE("Setting FVF, %d %d\n", VS_HIGHESTFIXEDFXF, pShader); + IWineD3DDevice_SetFVF(This->WineD3DDevice, pShader); + IWineD3DDevice_SetVertexDeclaration(This->WineD3DDevice, IDirect3DDevice8Impl_FindDecl(This, pShader)); + IWineD3DDevice_SetVertexShader(This->WineD3DDevice, NULL); + } else { + TRACE("Setting shader\n"); + if (This->allocated_shader_handles <= pShader - (VS_HIGHESTFIXEDFXF + 1)) { + FIXME("(%p) : Number of shaders exceeds the maximum number of possible shaders\n", This); + hrc = D3DERR_INVALIDCALL; + } else { + IDirect3DVertexShader8Impl *shader = This->shader_handles[pShader - (VS_HIGHESTFIXEDFXF + 1)]; + IWineD3DDevice_SetVertexDeclaration(This->WineD3DDevice, + shader ? ((IDirect3DVertexDeclaration8Impl *)shader->vertex_declaration)->wined3d_vertex_declaration : NULL); + hrc = IWineD3DDevice_SetVertexShader(This->WineD3DDevice, 0 == shader ? NULL : shader->wineD3DVertexShader); + } + } + TRACE("(%p) : returning hr(%u)\n", This, hrc); + LeaveCriticalSection(&d3d8_cs); + + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShader(LPDIRECT3DDEVICE8 iface, DWORD* ppShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IWineD3DVertexShader *pShader; + HRESULT hrc = D3D_OK; + + TRACE("(%p) : Relay device@%p\n", This, This->WineD3DDevice); + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_GetVertexShader(This->WineD3DDevice, &pShader); + if (D3D_OK == hrc) { + if(0 != pShader) { + IDirect3DVertexShader8Impl *d3d8_shader; + hrc = IWineD3DVertexShader_GetParent(pShader, (IUnknown **)&d3d8_shader); + IWineD3DVertexShader_Release(pShader); + *ppShader = (d3d8_shader->handle - This->shader_handles) + (VS_HIGHESTFIXEDFXF + 1); + } else { + *ppShader = 0; + hrc = D3D_OK; + } + } else { + WARN("(%p) : Call to IWineD3DDevice_GetVertexShader failed %u (device %p)\n", This, hrc, This->WineD3DDevice); + } + TRACE("(%p) : returning %#x\n", This, *ppShader); + LeaveCriticalSection(&d3d8_cs); + + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DeleteVertexShader(LPDIRECT3DDEVICE8 iface, DWORD pShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + + TRACE("(%p) : pShader %#x\n", This, pShader); + + EnterCriticalSection(&d3d8_cs); + if (pShader <= VS_HIGHESTFIXEDFXF || This->allocated_shader_handles <= pShader - (VS_HIGHESTFIXEDFXF + 1)) { + ERR("(%p) : Trying to delete an invalid handle\n", This); + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } else { + IWineD3DVertexShader *cur = NULL; + shader_handle *handle = &This->shader_handles[pShader - (VS_HIGHESTFIXEDFXF + 1)]; + IDirect3DVertexShader8Impl *shader = *handle; + + IWineD3DDevice_GetVertexShader(This->WineD3DDevice, &cur); + if(cur) { + if(cur == shader->wineD3DVertexShader) IDirect3DDevice8_SetVertexShader(iface, 0); + IWineD3DVertexShader_Release(cur); + } + + while(IUnknown_Release((IUnknown *)shader)); + free_shader_handle(This, handle); + } + LeaveCriticalSection(&d3d8_cs); + + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetVertexShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, CONST void* pConstantData, DWORD ConstantCount) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) : Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetVertexShaderConstantF(This->WineD3DDevice, Register, (CONST float *)pConstantData, ConstantCount); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, void* pConstantData, DWORD ConstantCount) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) : Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetVertexShaderConstantF(This->WineD3DDevice, Register, (float *)pConstantData, ConstantCount); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShaderDeclaration(LPDIRECT3DDEVICE8 iface, DWORD pVertexShader, void* pData, DWORD* pSizeOfData) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DVertexDeclaration8Impl *declaration; + IDirect3DVertexShader8Impl *shader = NULL; + + TRACE("(%p) : pVertexShader 0x%08x, pData %p, *pSizeOfData %u\n", This, pVertexShader, pData, *pSizeOfData); + + EnterCriticalSection(&d3d8_cs); + if (pVertexShader <= VS_HIGHESTFIXEDFXF || This->allocated_shader_handles <= pVertexShader - (VS_HIGHESTFIXEDFXF + 1)) { + ERR("Passed an invalid shader handle.\n"); + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } + + shader = This->shader_handles[pVertexShader - (VS_HIGHESTFIXEDFXF + 1)]; + declaration = (IDirect3DVertexDeclaration8Impl *)shader->vertex_declaration; + + /* If pData is NULL, we just return the required size of the buffer. */ + if (!pData) { + *pSizeOfData = declaration->elements_size; + LeaveCriticalSection(&d3d8_cs); + return D3D_OK; + } + + /* MSDN claims that if *pSizeOfData is smaller than the required size + * we should write the required size and return D3DERR_MOREDATA. + * That's not actually true. */ + if (*pSizeOfData < declaration->elements_size) { + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } + + CopyMemory(pData, declaration->elements, declaration->elements_size); + LeaveCriticalSection(&d3d8_cs); + + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShaderFunction(LPDIRECT3DDEVICE8 iface, DWORD pVertexShader, void* pData, DWORD* pSizeOfData) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DVertexShader8Impl *shader = NULL; + HRESULT hr; + + TRACE("(%p) : pVertexShader %#x, pData %p, pSizeOfData %p\n", This, pVertexShader, pData, pSizeOfData); + + EnterCriticalSection(&d3d8_cs); + if (pVertexShader <= VS_HIGHESTFIXEDFXF || This->allocated_shader_handles <= pVertexShader - (VS_HIGHESTFIXEDFXF + 1)) { + ERR("Passed an invalid shader handle.\n"); + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } + + shader = This->shader_handles[pVertexShader - (VS_HIGHESTFIXEDFXF + 1)]; + hr = IWineD3DVertexShader_GetFunction(shader->wineD3DVertexShader, pData, (UINT *)pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetIndices(LPDIRECT3DDEVICE8 iface, IDirect3DIndexBuffer8* pIndexData, UINT baseVertexIndex) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DDevice_SetBaseVertexIndex(This->WineD3DDevice, baseVertexIndex); + hr = IWineD3DDevice_SetIndices(This->WineD3DDevice, + pIndexData ? ((IDirect3DIndexBuffer8Impl *)pIndexData)->wineD3DIndexBuffer : NULL); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetIndices(LPDIRECT3DDEVICE8 iface, IDirect3DIndexBuffer8** ppIndexData,UINT* pBaseVertexIndex) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IWineD3DIndexBuffer *retIndexData = NULL; + HRESULT rc = D3D_OK; + + TRACE("(%p) Relay\n", This); + + if(ppIndexData == NULL){ + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + IWineD3DDevice_GetBaseVertexIndex(This->WineD3DDevice, pBaseVertexIndex); + rc = IWineD3DDevice_GetIndices(This->WineD3DDevice, &retIndexData); + if (SUCCEEDED(rc) && retIndexData) { + IWineD3DIndexBuffer_GetParent(retIndexData, (IUnknown **)ppIndexData); + IWineD3DIndexBuffer_Release(retIndexData); + } else { + if (FAILED(rc)) FIXME("Call to GetIndices failed\n"); + *ppIndexData = NULL; + } + LeaveCriticalSection(&d3d8_cs); + + return rc; +} +static HRESULT WINAPI IDirect3DDevice8Impl_CreatePixelShader(LPDIRECT3DDEVICE8 iface, CONST DWORD* pFunction, DWORD* ppShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DPixelShader8Impl *object; + HRESULT hrc = D3D_OK; + + TRACE("(%p) : pFunction(%p), ppShader(%p)\n", This, pFunction, ppShader); + + if (NULL == ppShader) { + TRACE("(%p) Invalid call\n", This); + return D3DERR_INVALIDCALL; + } + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + + if (NULL == object) { + return E_OUTOFMEMORY; + } else { + EnterCriticalSection(&d3d8_cs); + + object->ref = 1; + object->lpVtbl = &Direct3DPixelShader8_Vtbl; + hrc = IWineD3DDevice_CreatePixelShader(This->WineD3DDevice, pFunction, &object->wineD3DPixelShader , (IUnknown *)object); + if (D3D_OK != hrc) { + FIXME("(%p) call to IWineD3DDevice_CreatePixelShader failed\n", This); + HeapFree(GetProcessHeap(), 0 , object); + *ppShader = 0; + } else { + shader_handle *handle = alloc_shader_handle(This); + if (!handle) { + ERR("Failed to allocate shader handle\n"); + IDirect3DVertexShader8_Release((IUnknown *)object); + hrc = E_OUTOFMEMORY; + } else { + object->handle = handle; + *handle = object; + *ppShader = (handle - This->shader_handles) + VS_HIGHESTFIXEDFXF + 1; + } + } + LeaveCriticalSection(&d3d8_cs); + } + + TRACE("(%p) : returning %p (handle %#x)\n", This, object, *ppShader); + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetPixelShader(LPDIRECT3DDEVICE8 iface, DWORD pShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DPixelShader8Impl *shader = NULL; + HRESULT hr; + + TRACE("(%p) : pShader %#x\n", This, pShader); + + EnterCriticalSection(&d3d8_cs); + if (pShader > VS_HIGHESTFIXEDFXF && This->allocated_shader_handles > pShader - (VS_HIGHESTFIXEDFXF + 1)) { + shader = This->shader_handles[pShader - (VS_HIGHESTFIXEDFXF + 1)]; + } else if (pShader) { + ERR("Trying to set an invalid handle.\n"); + } + + TRACE("(%p) : Setting shader %p\n", This, shader); + hr = IWineD3DDevice_SetPixelShader(This->WineD3DDevice, shader == NULL ? NULL :shader->wineD3DPixelShader); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShader(LPDIRECT3DDEVICE8 iface, DWORD* ppShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IWineD3DPixelShader *object; + + HRESULT hrc = D3D_OK; + TRACE("(%p) Relay\n", This); + if (NULL == ppShader) { + TRACE("(%p) Invalid call\n", This); + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DDevice_GetPixelShader(This->WineD3DDevice, &object); + if (D3D_OK == hrc && NULL != object) { + IDirect3DPixelShader8Impl *d3d8_shader; + hrc = IWineD3DPixelShader_GetParent(object, (IUnknown **)&d3d8_shader); + IWineD3DPixelShader_Release(object); + *ppShader = (d3d8_shader->handle - This->shader_handles) + (VS_HIGHESTFIXEDFXF + 1); + } else { + *ppShader = (DWORD)NULL; + } + + TRACE("(%p) : returning %#x\n", This, *ppShader); + LeaveCriticalSection(&d3d8_cs); + return hrc; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DeletePixelShader(LPDIRECT3DDEVICE8 iface, DWORD pShader) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + + TRACE("(%p) : pShader %#x\n", This, pShader); + + EnterCriticalSection(&d3d8_cs); + if (pShader <= VS_HIGHESTFIXEDFXF || This->allocated_shader_handles <= pShader - (VS_HIGHESTFIXEDFXF + 1)) { + ERR("(%p) : Trying to delete an invalid handle\n", This); + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } else { + IWineD3DPixelShader *cur = NULL; + shader_handle *handle = &This->shader_handles[pShader - (VS_HIGHESTFIXEDFXF + 1)]; + IDirect3DPixelShader8Impl *shader = *handle; + + IWineD3DDevice_GetPixelShader(This->WineD3DDevice, &cur); + if(cur) { + if(cur == shader->wineD3DPixelShader) IDirect3DDevice8_SetPixelShader(iface, 0); + IWineD3DPixelShader_Release(cur); + } + + while(IUnknown_Release((IUnknown *)shader)); + free_shader_handle(This, handle); + } + LeaveCriticalSection(&d3d8_cs); + + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetPixelShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, CONST void* pConstantData, DWORD ConstantCount) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetPixelShaderConstantF(This->WineD3DDevice, Register, (CONST float *)pConstantData, ConstantCount); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, void* pConstantData, DWORD ConstantCount) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_GetPixelShaderConstantF(This->WineD3DDevice, Register, (float *)pConstantData, ConstantCount); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShaderFunction(LPDIRECT3DDEVICE8 iface, DWORD pPixelShader, void* pData, DWORD* pSizeOfData) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IDirect3DPixelShader8Impl *shader = NULL; + HRESULT hr; + + TRACE("(%p) : pPixelShader %#x, pData %p, pSizeOfData %p\n", This, pPixelShader, pData, pSizeOfData); + + EnterCriticalSection(&d3d8_cs); + if (pPixelShader <= VS_HIGHESTFIXEDFXF || This->allocated_shader_handles <= pPixelShader - (VS_HIGHESTFIXEDFXF + 1)) { + ERR("Passed an invalid shader handle.\n"); + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } + + shader = This->shader_handles[pPixelShader - (VS_HIGHESTFIXEDFXF + 1)]; + hr = IWineD3DPixelShader_GetFunction(shader->wineD3DPixelShader, pData, (UINT *)pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DrawRectPatch(LPDIRECT3DDEVICE8 iface, UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DrawRectPatch(This->WineD3DDevice, Handle, pNumSegs, (CONST WINED3DRECTPATCH_INFO *)pRectPatchInfo); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DrawTriPatch(LPDIRECT3DDEVICE8 iface, UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DrawTriPatch(This->WineD3DDevice, Handle, pNumSegs, (CONST WINED3DTRIPATCH_INFO *)pTriPatchInfo); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_DeletePatch(LPDIRECT3DDEVICE8 iface, UINT Handle) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_DeletePatch(This->WineD3DDevice, Handle); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_SetStreamSource(LPDIRECT3DDEVICE8 iface, UINT StreamNumber,IDirect3DVertexBuffer8* pStreamData,UINT Stride) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n" , This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DDevice_SetStreamSource(This->WineD3DDevice, StreamNumber, + NULL == pStreamData ? NULL : ((IDirect3DVertexBuffer8Impl *)pStreamData)->wineD3DVertexBuffer, + 0/* Offset in bytes */, Stride); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DDevice8Impl_GetStreamSource(LPDIRECT3DDEVICE8 iface, UINT StreamNumber,IDirect3DVertexBuffer8** pStream,UINT* pStride) { + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; + IWineD3DVertexBuffer *retStream = NULL; + HRESULT rc = D3D_OK; + + TRACE("(%p) Relay\n" , This); + + if(pStream == NULL){ + return D3DERR_INVALIDCALL; + } + + EnterCriticalSection(&d3d8_cs); + rc = IWineD3DDevice_GetStreamSource(This->WineD3DDevice, StreamNumber, (IWineD3DVertexBuffer **)&retStream, 0 /* Offset in bytes */, pStride); + if (rc == D3D_OK && NULL != retStream) { + IWineD3DVertexBuffer_GetParent(retStream, (IUnknown **)pStream); + IWineD3DVertexBuffer_Release(retStream); + }else{ + if (rc != D3D_OK){ + FIXME("Call to GetStreamSource failed %p\n", pStride); + } + *pStream = NULL; + } + LeaveCriticalSection(&d3d8_cs); + + return rc; +} + + +const IDirect3DDevice8Vtbl Direct3DDevice8_Vtbl = +{ + IDirect3DDevice8Impl_QueryInterface, + IDirect3DDevice8Impl_AddRef, + IDirect3DDevice8Impl_Release, + IDirect3DDevice8Impl_TestCooperativeLevel, + IDirect3DDevice8Impl_GetAvailableTextureMem, + IDirect3DDevice8Impl_ResourceManagerDiscardBytes, + IDirect3DDevice8Impl_GetDirect3D, + IDirect3DDevice8Impl_GetDeviceCaps, + IDirect3DDevice8Impl_GetDisplayMode, + IDirect3DDevice8Impl_GetCreationParameters, + IDirect3DDevice8Impl_SetCursorProperties, + IDirect3DDevice8Impl_SetCursorPosition, + IDirect3DDevice8Impl_ShowCursor, + IDirect3DDevice8Impl_CreateAdditionalSwapChain, + IDirect3DDevice8Impl_Reset, + IDirect3DDevice8Impl_Present, + IDirect3DDevice8Impl_GetBackBuffer, + IDirect3DDevice8Impl_GetRasterStatus, + IDirect3DDevice8Impl_SetGammaRamp, + IDirect3DDevice8Impl_GetGammaRamp, + IDirect3DDevice8Impl_CreateTexture, + IDirect3DDevice8Impl_CreateVolumeTexture, + IDirect3DDevice8Impl_CreateCubeTexture, + IDirect3DDevice8Impl_CreateVertexBuffer, + IDirect3DDevice8Impl_CreateIndexBuffer, + IDirect3DDevice8Impl_CreateRenderTarget, + IDirect3DDevice8Impl_CreateDepthStencilSurface, + IDirect3DDevice8Impl_CreateImageSurface, + IDirect3DDevice8Impl_CopyRects, + IDirect3DDevice8Impl_UpdateTexture, + IDirect3DDevice8Impl_GetFrontBuffer, + IDirect3DDevice8Impl_SetRenderTarget, + IDirect3DDevice8Impl_GetRenderTarget, + IDirect3DDevice8Impl_GetDepthStencilSurface, + IDirect3DDevice8Impl_BeginScene, + IDirect3DDevice8Impl_EndScene, + IDirect3DDevice8Impl_Clear, + IDirect3DDevice8Impl_SetTransform, + IDirect3DDevice8Impl_GetTransform, + IDirect3DDevice8Impl_MultiplyTransform, + IDirect3DDevice8Impl_SetViewport, + IDirect3DDevice8Impl_GetViewport, + IDirect3DDevice8Impl_SetMaterial, + IDirect3DDevice8Impl_GetMaterial, + IDirect3DDevice8Impl_SetLight, + IDirect3DDevice8Impl_GetLight, + IDirect3DDevice8Impl_LightEnable, + IDirect3DDevice8Impl_GetLightEnable, + IDirect3DDevice8Impl_SetClipPlane, + IDirect3DDevice8Impl_GetClipPlane, + IDirect3DDevice8Impl_SetRenderState, + IDirect3DDevice8Impl_GetRenderState, + IDirect3DDevice8Impl_BeginStateBlock, + IDirect3DDevice8Impl_EndStateBlock, + IDirect3DDevice8Impl_ApplyStateBlock, + IDirect3DDevice8Impl_CaptureStateBlock, + IDirect3DDevice8Impl_DeleteStateBlock, + IDirect3DDevice8Impl_CreateStateBlock, + IDirect3DDevice8Impl_SetClipStatus, + IDirect3DDevice8Impl_GetClipStatus, + IDirect3DDevice8Impl_GetTexture, + IDirect3DDevice8Impl_SetTexture, + IDirect3DDevice8Impl_GetTextureStageState, + IDirect3DDevice8Impl_SetTextureStageState, + IDirect3DDevice8Impl_ValidateDevice, + IDirect3DDevice8Impl_GetInfo, + IDirect3DDevice8Impl_SetPaletteEntries, + IDirect3DDevice8Impl_GetPaletteEntries, + IDirect3DDevice8Impl_SetCurrentTexturePalette, + IDirect3DDevice8Impl_GetCurrentTexturePalette, + IDirect3DDevice8Impl_DrawPrimitive, + IDirect3DDevice8Impl_DrawIndexedPrimitive, + IDirect3DDevice8Impl_DrawPrimitiveUP, + IDirect3DDevice8Impl_DrawIndexedPrimitiveUP, + IDirect3DDevice8Impl_ProcessVertices, + IDirect3DDevice8Impl_CreateVertexShader, + IDirect3DDevice8Impl_SetVertexShader, + IDirect3DDevice8Impl_GetVertexShader, + IDirect3DDevice8Impl_DeleteVertexShader, + IDirect3DDevice8Impl_SetVertexShaderConstant, + IDirect3DDevice8Impl_GetVertexShaderConstant, + IDirect3DDevice8Impl_GetVertexShaderDeclaration, + IDirect3DDevice8Impl_GetVertexShaderFunction, + IDirect3DDevice8Impl_SetStreamSource, + IDirect3DDevice8Impl_GetStreamSource, + IDirect3DDevice8Impl_SetIndices, + IDirect3DDevice8Impl_GetIndices, + IDirect3DDevice8Impl_CreatePixelShader, + IDirect3DDevice8Impl_SetPixelShader, + IDirect3DDevice8Impl_GetPixelShader, + IDirect3DDevice8Impl_DeletePixelShader, + IDirect3DDevice8Impl_SetPixelShaderConstant, + IDirect3DDevice8Impl_GetPixelShaderConstant, + IDirect3DDevice8Impl_GetPixelShaderFunction, + IDirect3DDevice8Impl_DrawRectPatch, + IDirect3DDevice8Impl_DrawTriPatch, + IDirect3DDevice8Impl_DeletePatch +}; + +/* Internal function called back during the CreateDevice to create a render target */ +HRESULT WINAPI D3D8CB_CreateSurface(IUnknown *device, IUnknown *pSuperior, UINT Width, UINT Height, + WINED3DFORMAT Format, DWORD Usage, WINED3DPOOL Pool, UINT Level, + WINED3DCUBEMAP_FACES Face, IWineD3DSurface **ppSurface, + HANDLE *pSharedHandle) { + + HRESULT res = D3D_OK; + IDirect3DSurface8Impl *d3dSurface = NULL; + BOOL Lockable = TRUE; + + if((WINED3DPOOL_DEFAULT == Pool && WINED3DUSAGE_DYNAMIC != Usage)) + Lockable = FALSE; + + TRACE("relay\n"); + res = IDirect3DDevice8Impl_CreateSurface((IDirect3DDevice8 *)device, Width, Height, (D3DFORMAT)Format, Lockable, FALSE/*Discard*/, Level, (IDirect3DSurface8 **)&d3dSurface, D3DRTYPE_SURFACE, Usage, Pool, D3DMULTISAMPLE_NONE, 0 /* MultisampleQuality */); + + if (SUCCEEDED(res)) { + *ppSurface = d3dSurface->wineD3DSurface; + d3dSurface->container = pSuperior; + IUnknown_Release(d3dSurface->parentDevice); + d3dSurface->parentDevice = NULL; + d3dSurface->forwardReference = pSuperior; + } else { + FIXME("(%p) IDirect3DDevice8_CreateSurface failed\n", device); + } + return res; +} + +ULONG WINAPI D3D8CB_DestroySurface(IWineD3DSurface *pSurface) { + IDirect3DSurface8Impl* surfaceParent; + TRACE("(%p) call back\n", pSurface); + + IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent); + /* GetParent's AddRef was forwarded to an object in destruction. + * Releasing it here again would cause an endless recursion. */ + surfaceParent->forwardReference = NULL; + return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent); +} diff --git a/reactos/dll/directx/wine/d3d8/directx.c b/reactos/dll/directx/wine/d3d8/directx.c new file mode 100644 index 00000000000..54c87e68484 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/directx.c @@ -0,0 +1,507 @@ +/* + * IDirect3D8 implementation + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3D IUnknown parts follow: */ +static HRESULT WINAPI IDirect3D8Impl_QueryInterface(LPDIRECT3D8 iface, REFIID riid,LPVOID *ppobj) +{ + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3D8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid),ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3D8Impl_AddRef(LPDIRECT3D8 iface) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3D8Impl_Release(LPDIRECT3D8 iface) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + TRACE("Releasing wined3d %p\n", This->WineD3D); + IWineD3D_Release(This->WineD3D); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/* IDirect3D8 Interface follow: */ +static HRESULT WINAPI IDirect3D8Impl_RegisterSoftwareDevice (LPDIRECT3D8 iface, void* pInitializeFunction) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%p)\n", This, pInitializeFunction); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_RegisterSoftwareDevice(This->WineD3D, pInitializeFunction); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static UINT WINAPI IDirect3D8Impl_GetAdapterCount (LPDIRECT3D8 iface) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_GetAdapterCount(This->WineD3D); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_GetAdapterIdentifier (LPDIRECT3D8 iface, + UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER8* pIdentifier) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + WINED3DADAPTER_IDENTIFIER adapter_id; + HRESULT hr; + + TRACE("(%p)->(%d,%08x, %p\n", This, Adapter, Flags, pIdentifier); + EnterCriticalSection(&d3d8_cs); + /* dx8 and dx9 have different structures to be filled in, with incompatible + layouts so pass in pointers to the places to be filled via an internal + structure */ + adapter_id.Driver = pIdentifier->Driver; + adapter_id.Description = pIdentifier->Description; + adapter_id.DeviceName = NULL; /* d3d9 only */ + adapter_id.DriverVersion = &pIdentifier->DriverVersion; + adapter_id.VendorId = &pIdentifier->VendorId; + adapter_id.DeviceId = &pIdentifier->DeviceId; + adapter_id.SubSysId = &pIdentifier->SubSysId; + adapter_id.Revision = &pIdentifier->Revision; + adapter_id.DeviceIdentifier = &pIdentifier->DeviceIdentifier; + adapter_id.WHQLLevel = &pIdentifier->WHQLLevel; + + hr = IWineD3D_GetAdapterIdentifier(This->WineD3D, Adapter, Flags, &adapter_id); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static UINT WINAPI IDirect3D8Impl_GetAdapterModeCount (LPDIRECT3D8 iface,UINT Adapter) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%d)\n", This, Adapter); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_GetAdapterModeCount(This->WineD3D, Adapter, 0 /* format */); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_EnumAdapterModes (LPDIRECT3D8 iface, UINT Adapter, UINT Mode, D3DDISPLAYMODE* pMode) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%d, %d, %p)\n", This, Adapter, Mode, pMode); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_EnumAdapterModes(This->WineD3D, Adapter, WINED3DFMT_UNKNOWN, Mode, (WINED3DDISPLAYMODE *) pMode); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_GetAdapterDisplayMode (LPDIRECT3D8 iface, UINT Adapter, D3DDISPLAYMODE* pMode) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%d,%p)\n", This, Adapter, pMode); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_GetAdapterDisplayMode(This->WineD3D, Adapter, (WINED3DDISPLAYMODE *) pMode); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_CheckDeviceType (LPDIRECT3D8 iface, + UINT Adapter, D3DDEVTYPE CheckType, D3DFORMAT DisplayFormat, + D3DFORMAT BackBufferFormat, BOOL Windowed) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%d, %d, %d, %d, %s)\n", This, Adapter, CheckType, DisplayFormat, BackBufferFormat, Windowed ? "true" : "false"); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_CheckDeviceType(This->WineD3D, Adapter, CheckType, DisplayFormat, + BackBufferFormat, Windowed); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_CheckDeviceFormat (LPDIRECT3D8 iface, + UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, + DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%d, %d, %d, %08x, %d, %d)\n", This, Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_CheckDeviceFormat(This->WineD3D, Adapter, DeviceType, AdapterFormat, + Usage, RType, CheckFormat); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_CheckDeviceMultiSampleType(LPDIRECT3D8 iface, + UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, + BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)-<(%d, %d, %d, %s, %d)\n", This, Adapter, DeviceType, SurfaceFormat, Windowed ? "true" : "false", MultiSampleType); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_CheckDeviceMultiSampleType(This->WineD3D, Adapter, DeviceType, SurfaceFormat, + Windowed, (WINED3DMULTISAMPLE_TYPE) MultiSampleType, NULL); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_CheckDepthStencilMatch(LPDIRECT3D8 iface, + UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, + D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hr; + TRACE("(%p)-<(%d, %d, %d, %d, %d)\n", This, Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3D_CheckDepthStencilMatch(This->WineD3D, Adapter, DeviceType, AdapterFormat, + RenderTargetFormat, DepthStencilFormat); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3D8Impl_GetDeviceCaps(LPDIRECT3D8 iface, UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS8* pCaps) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HRESULT hrc = D3D_OK; + WINED3DCAPS *pWineCaps; + + TRACE("(%p) Relay %d %u %p\n", This, Adapter, DeviceType, pCaps); + + if(NULL == pCaps){ + return D3DERR_INVALIDCALL; + } + pWineCaps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINED3DCAPS)); + if(pWineCaps == NULL){ + return D3DERR_INVALIDCALL; /*well this is what MSDN says to return*/ + } + D3D8CAPSTOWINECAPS(pCaps, pWineCaps) + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3D_GetDeviceCaps(This->WineD3D, Adapter, DeviceType, pWineCaps); + LeaveCriticalSection(&d3d8_cs); + HeapFree(GetProcessHeap(), 0, pWineCaps); + + /* D3D8 doesn't support SM 2.0 or higher, so clamp to 1.x */ + if(pCaps->PixelShaderVersion > D3DPS_VERSION(1,4)){ + pCaps->PixelShaderVersion = D3DPS_VERSION(1,4); + } + if(pCaps->VertexShaderVersion > D3DVS_VERSION(1,1)){ + pCaps->VertexShaderVersion = D3DVS_VERSION(1,1); + } + + TRACE("(%p) returning %p\n", This, pCaps); + return hrc; +} + +static HMONITOR WINAPI IDirect3D8Impl_GetAdapterMonitor(LPDIRECT3D8 iface, UINT Adapter) { + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + HMONITOR ret; + TRACE("(%p)->(%d)\n", This, Adapter); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3D_GetAdapterMonitor(This->WineD3D, Adapter); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +/* Internal function called back during the CreateDevice to create a render target */ +HRESULT WINAPI D3D8CB_CreateRenderTarget(IUnknown *device, IUnknown *pSuperior, UINT Width, UINT Height, + WINED3DFORMAT Format, WINED3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, BOOL Lockable, + IWineD3DSurface** ppSurface, HANDLE* pSharedHandle) { + HRESULT res = D3D_OK; + IDirect3DSurface8Impl *d3dSurface = NULL; + + TRACE("(%p) call back\n", device); + res = IDirect3DDevice8_CreateRenderTarget((IDirect3DDevice8 *)device, Width, Height, + (D3DFORMAT)Format, MultiSample, Lockable, + (IDirect3DSurface8 **)&d3dSurface); + + if (SUCCEEDED(res)) { + *ppSurface = d3dSurface->wineD3DSurface; + d3dSurface->container = device; + d3dSurface->isImplicit = TRUE; + /* Implicit surfaces are created with an refcount of 0 */ + IUnknown_Release((IUnknown *)d3dSurface); + } else { + *ppSurface = NULL; + } + return res; +} + +ULONG WINAPI D3D8CB_DestroyRenderTarget(IWineD3DSurface *pSurface) { + IDirect3DSurface8Impl* surfaceParent; + TRACE("(%p) call back\n", pSurface); + + IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent); + surfaceParent->isImplicit = FALSE; + /* Surface had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */ + return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent); +} + +/* Callback for creating the inplicite swapchain when the device is created */ +static HRESULT WINAPI D3D8CB_CreateAdditionalSwapChain(IUnknown *device, + WINED3DPRESENT_PARAMETERS* pPresentationParameters, + IWineD3DSwapChain ** ppSwapChain){ + HRESULT res = D3D_OK; + IDirect3DSwapChain8Impl *d3dSwapChain = NULL; + D3DPRESENT_PARAMETERS localParameters; + TRACE("(%p) call back\n", device); + + /* Copy the presentation parameters */ + localParameters.BackBufferWidth = pPresentationParameters->BackBufferWidth; + localParameters.BackBufferHeight = pPresentationParameters->BackBufferHeight; + localParameters.BackBufferFormat = pPresentationParameters->BackBufferFormat; + localParameters.BackBufferCount = pPresentationParameters->BackBufferCount; + localParameters.MultiSampleType = pPresentationParameters->MultiSampleType; + localParameters.SwapEffect = pPresentationParameters->SwapEffect; + localParameters.hDeviceWindow = pPresentationParameters->hDeviceWindow; + localParameters.Windowed = pPresentationParameters->Windowed; + localParameters.EnableAutoDepthStencil = pPresentationParameters->EnableAutoDepthStencil; + localParameters.AutoDepthStencilFormat = pPresentationParameters->AutoDepthStencilFormat; + localParameters.Flags = pPresentationParameters->Flags; + localParameters.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz; + localParameters.FullScreen_PresentationInterval = pPresentationParameters->PresentationInterval; + + res = IDirect3DDevice8_CreateAdditionalSwapChain((IDirect3DDevice8 *)device, &localParameters, (IDirect3DSwapChain8 **)&d3dSwapChain); + + /* Copy back the presentation parameters */ + pPresentationParameters->BackBufferWidth = localParameters.BackBufferWidth; + pPresentationParameters->BackBufferHeight = localParameters.BackBufferHeight; + pPresentationParameters->BackBufferFormat = localParameters.BackBufferFormat; + pPresentationParameters->BackBufferCount = localParameters.BackBufferCount; + pPresentationParameters->MultiSampleType = localParameters.MultiSampleType; + pPresentationParameters->SwapEffect = localParameters.SwapEffect; + pPresentationParameters->hDeviceWindow = localParameters.hDeviceWindow; + pPresentationParameters->Windowed = localParameters.Windowed; + pPresentationParameters->EnableAutoDepthStencil = localParameters.EnableAutoDepthStencil; + pPresentationParameters->AutoDepthStencilFormat = localParameters.AutoDepthStencilFormat; + pPresentationParameters->Flags = localParameters.Flags; + pPresentationParameters->FullScreen_RefreshRateInHz = localParameters.FullScreen_RefreshRateInHz; + pPresentationParameters->PresentationInterval = localParameters.FullScreen_PresentationInterval; + + if (SUCCEEDED(res)) { + *ppSwapChain = d3dSwapChain->wineD3DSwapChain; + IUnknown_Release(d3dSwapChain->parentDevice); + d3dSwapChain->parentDevice = NULL; + } else { + *ppSwapChain = NULL; + } + + return res; +} + +ULONG WINAPI D3D8CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) { + IUnknown* swapChainParent; + TRACE("(%p) call back\n", pSwapChain); + + IWineD3DSwapChain_GetParent(pSwapChain, &swapChainParent); + IUnknown_Release(swapChainParent); + return IUnknown_Release(swapChainParent); +} + +/* Internal function called back during the CreateDevice to create a render target */ +HRESULT WINAPI D3D8CB_CreateDepthStencilSurface(IUnknown *device, IUnknown *pSuperior, UINT Width, UINT Height, + WINED3DFORMAT Format, WINED3DMULTISAMPLE_TYPE MultiSample, + DWORD MultisampleQuality, BOOL Discard, + IWineD3DSurface** ppSurface, HANDLE* pSharedHandle) { + HRESULT res = D3D_OK; + IDirect3DSurface8Impl *d3dSurface = NULL; + TRACE("(%p) call back\n", device); + + res = IDirect3DDevice8_CreateDepthStencilSurface((IDirect3DDevice8 *)device, Width, Height, + (D3DFORMAT)Format, MultiSample, (IDirect3DSurface8 **)&d3dSurface); + if (SUCCEEDED(res)) { + *ppSurface = d3dSurface->wineD3DSurface; + d3dSurface->container = device; + d3dSurface->isImplicit = TRUE; + /* Implicit surfaces are created with an refcount of 0 */ + IUnknown_Release((IUnknown *)d3dSurface); + } + return res; +} + +ULONG WINAPI D3D8CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) { + IDirect3DSurface8Impl* surfaceParent; + TRACE("(%p) call back\n", pSurface); + + IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent); + surfaceParent->isImplicit = FALSE; + /* Surface had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */ + return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent); +} + +static HRESULT WINAPI IDirect3D8Impl_CreateDevice(LPDIRECT3D8 iface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, + DWORD BehaviourFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, + IDirect3DDevice8** ppReturnedDeviceInterface) { + + IDirect3D8Impl *This = (IDirect3D8Impl *)iface; + IDirect3DDevice8Impl *object = NULL; + WINED3DPRESENT_PARAMETERS localParameters; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + /* Check the validity range of the adapter parameter */ + if (Adapter >= IDirect3D8Impl_GetAdapterCount(iface)) { + *ppReturnedDeviceInterface = NULL; + return D3DERR_INVALIDCALL; + } + + /* Allocate the storage for the device object */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDevice8Impl)); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *ppReturnedDeviceInterface = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DDevice8_Vtbl; + object->ref = 1; + object->shader_handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, INITIAL_SHADER_HANDLE_TABLE_SIZE * sizeof(shader_handle)); + object->shader_handle_table_size = INITIAL_SHADER_HANDLE_TABLE_SIZE; + *ppReturnedDeviceInterface = (IDirect3DDevice8 *)object; + + /* Allocate an associated WineD3DDevice object */ + EnterCriticalSection(&d3d8_cs); + hr =IWineD3D_CreateDevice(This->WineD3D, Adapter, DeviceType, hFocusWindow, BehaviourFlags, &object->WineD3DDevice, (IUnknown *)object); + + if (hr != D3D_OK) { + HeapFree(GetProcessHeap(), 0, object); + *ppReturnedDeviceInterface = NULL; + LeaveCriticalSection(&d3d8_cs); + return hr; + } + + TRACE("(%p) : Created Device %p\n", This, object); + + localParameters.BackBufferWidth = pPresentationParameters->BackBufferWidth; + localParameters.BackBufferHeight = pPresentationParameters->BackBufferHeight; + localParameters.BackBufferFormat = pPresentationParameters->BackBufferFormat; + localParameters.BackBufferCount = pPresentationParameters->BackBufferCount; + localParameters.MultiSampleType = pPresentationParameters->MultiSampleType; + localParameters.MultiSampleQuality = 0; /* d3d9 only */ + localParameters.SwapEffect = pPresentationParameters->SwapEffect; + localParameters.hDeviceWindow = pPresentationParameters->hDeviceWindow; + localParameters.Windowed = pPresentationParameters->Windowed; + localParameters.EnableAutoDepthStencil = pPresentationParameters->EnableAutoDepthStencil; + localParameters.AutoDepthStencilFormat = pPresentationParameters->AutoDepthStencilFormat; + localParameters.Flags = pPresentationParameters->Flags; + localParameters.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz; + localParameters.PresentationInterval = pPresentationParameters->FullScreen_PresentationInterval; + + if(BehaviourFlags & D3DCREATE_MULTITHREADED) { + IWineD3DDevice_SetMultithreaded(object->WineD3DDevice); + } + + hr = IWineD3DDevice_Init3D(object->WineD3DDevice, &localParameters, D3D8CB_CreateAdditionalSwapChain); + LeaveCriticalSection(&d3d8_cs); + + pPresentationParameters->BackBufferWidth = localParameters.BackBufferWidth; + pPresentationParameters->BackBufferHeight = localParameters.BackBufferHeight; + pPresentationParameters->BackBufferFormat = localParameters.BackBufferFormat; + pPresentationParameters->BackBufferCount = localParameters.BackBufferCount; + pPresentationParameters->MultiSampleType = localParameters.MultiSampleType; + pPresentationParameters->SwapEffect = localParameters.SwapEffect; + pPresentationParameters->hDeviceWindow = localParameters.hDeviceWindow; + pPresentationParameters->Windowed = localParameters.Windowed; + pPresentationParameters->EnableAutoDepthStencil = localParameters.EnableAutoDepthStencil; + pPresentationParameters->AutoDepthStencilFormat = localParameters.AutoDepthStencilFormat; + pPresentationParameters->Flags = localParameters.Flags; + pPresentationParameters->FullScreen_RefreshRateInHz = localParameters.FullScreen_RefreshRateInHz; + pPresentationParameters->FullScreen_PresentationInterval = localParameters.PresentationInterval; + + if (hr != D3D_OK) { + FIXME("(%p) D3D Initialization failed for WineD3DDevice %p\n", This, object->WineD3DDevice); + HeapFree(GetProcessHeap(), 0, object); + *ppReturnedDeviceInterface = NULL; + } + + object->declArraySize = 16; + object->decls = HeapAlloc(GetProcessHeap(), 0, object->declArraySize * sizeof(*object->decls)); + if(!object->decls) { + ERR("Out of memory\n"); + IWineD3DDevice_Release(object->WineD3DDevice); + HeapFree(GetProcessHeap(), 0, object); + *ppReturnedDeviceInterface = NULL; + hr = E_OUTOFMEMORY; + } + return hr; +} + +const IDirect3D8Vtbl Direct3D8_Vtbl = +{ + /* IUnknown */ + IDirect3D8Impl_QueryInterface, + IDirect3D8Impl_AddRef, + IDirect3D8Impl_Release, + /* IDirect3D8 */ + IDirect3D8Impl_RegisterSoftwareDevice, + IDirect3D8Impl_GetAdapterCount, + IDirect3D8Impl_GetAdapterIdentifier, + IDirect3D8Impl_GetAdapterModeCount, + IDirect3D8Impl_EnumAdapterModes, + IDirect3D8Impl_GetAdapterDisplayMode, + IDirect3D8Impl_CheckDeviceType, + IDirect3D8Impl_CheckDeviceFormat, + IDirect3D8Impl_CheckDeviceMultiSampleType, + IDirect3D8Impl_CheckDepthStencilMatch, + IDirect3D8Impl_GetDeviceCaps, + IDirect3D8Impl_GetAdapterMonitor, + IDirect3D8Impl_CreateDevice +}; diff --git a/reactos/dll/directx/wine/d3d8/indexbuffer.c b/reactos/dll/directx/wine/d3d8/indexbuffer.c new file mode 100644 index 00000000000..c4bd83338b2 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/indexbuffer.c @@ -0,0 +1,209 @@ +/* + * IDirect3DIndexBuffer8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DIndexBuffer8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_QueryInterface(LPDIRECT3DINDEXBUFFER8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DIndexBuffer8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DIndexBuffer8Impl_AddRef(LPDIRECT3DINDEXBUFFER8 iface) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DIndexBuffer8Impl_Release(LPDIRECT3DINDEXBUFFER8 iface) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + EnterCriticalSection(&d3d8_cs); + IWineD3DIndexBuffer_Release(This->wineD3DIndexBuffer); + LeaveCriticalSection(&d3d8_cs); + IUnknown_Release(This->parentDevice); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DIndexBuffer8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_GetDevice(LPDIRECT3DINDEXBUFFER8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_SetPrivateData(LPDIRECT3DINDEXBUFFER8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DIndexBuffer_SetPrivateData(This->wineD3DIndexBuffer, refguid, pData, SizeOfData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_GetPrivateData(LPDIRECT3DINDEXBUFFER8 iface, REFGUID refguid, void *pData, DWORD *pSizeOfData) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DIndexBuffer_GetPrivateData(This->wineD3DIndexBuffer, refguid, pData, pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_FreePrivateData(LPDIRECT3DINDEXBUFFER8 iface, REFGUID refguid) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DIndexBuffer_FreePrivateData(This->wineD3DIndexBuffer, refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static DWORD WINAPI IDirect3DIndexBuffer8Impl_SetPriority(LPDIRECT3DINDEXBUFFER8 iface, DWORD PriorityNew) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DIndexBuffer_SetPriority(This->wineD3DIndexBuffer, PriorityNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DIndexBuffer8Impl_GetPriority(LPDIRECT3DINDEXBUFFER8 iface) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DIndexBuffer_GetPriority(This->wineD3DIndexBuffer); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static void WINAPI IDirect3DIndexBuffer8Impl_PreLoad(LPDIRECT3DINDEXBUFFER8 iface) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DIndexBuffer_PreLoad(This->wineD3DIndexBuffer); + LeaveCriticalSection(&d3d8_cs); +} + +static D3DRESOURCETYPE WINAPI IDirect3DIndexBuffer8Impl_GetType(LPDIRECT3DINDEXBUFFER8 iface) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + D3DRESOURCETYPE type; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + type = IWineD3DIndexBuffer_GetType(This->wineD3DIndexBuffer); + LeaveCriticalSection(&d3d8_cs); + return type; +} + +/* IDirect3DIndexBuffer8 Interface follow: */ +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_Lock(LPDIRECT3DINDEXBUFFER8 iface, UINT OffsetToLock, UINT SizeToLock, BYTE **ppbData, DWORD Flags) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DIndexBuffer_Lock(This->wineD3DIndexBuffer, OffsetToLock, SizeToLock, ppbData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_Unlock(LPDIRECT3DINDEXBUFFER8 iface) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DIndexBuffer_Unlock(This->wineD3DIndexBuffer); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DIndexBuffer8Impl_GetDesc(LPDIRECT3DINDEXBUFFER8 iface, D3DINDEXBUFFER_DESC *pDesc) { + IDirect3DIndexBuffer8Impl *This = (IDirect3DIndexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DIndexBuffer_GetDesc(This->wineD3DIndexBuffer, (WINED3DINDEXBUFFER_DESC *) pDesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + + +const IDirect3DIndexBuffer8Vtbl Direct3DIndexBuffer8_Vtbl = +{ + /* IUnknown */ + IDirect3DIndexBuffer8Impl_QueryInterface, + IDirect3DIndexBuffer8Impl_AddRef, + IDirect3DIndexBuffer8Impl_Release, + /* IDirect3DResource8 */ + IDirect3DIndexBuffer8Impl_GetDevice, + IDirect3DIndexBuffer8Impl_SetPrivateData, + IDirect3DIndexBuffer8Impl_GetPrivateData, + IDirect3DIndexBuffer8Impl_FreePrivateData, + IDirect3DIndexBuffer8Impl_SetPriority, + IDirect3DIndexBuffer8Impl_GetPriority, + IDirect3DIndexBuffer8Impl_PreLoad, + IDirect3DIndexBuffer8Impl_GetType, + /* IDirect3DIndexBuffer8 */ + IDirect3DIndexBuffer8Impl_Lock, + IDirect3DIndexBuffer8Impl_Unlock, + IDirect3DIndexBuffer8Impl_GetDesc +}; diff --git a/reactos/dll/directx/wine/d3d8/pixelshader.c b/reactos/dll/directx/wine/d3d8/pixelshader.c new file mode 100644 index 00000000000..3ad39e6a439 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/pixelshader.c @@ -0,0 +1,95 @@ +/* + * IDirect3DPixelShader8 implementation + * + * Copyright 2002-2003 Jason Edmeades + * Raphael Junqueira + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DPixelShader8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DPixelShader8Impl_QueryInterface(IDirect3DPixelShader8 *iface, REFIID riid, LPVOID *ppobj) { + IDirect3DPixelShader8Impl *This = (IDirect3DPixelShader8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DPixelShader8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DPixelShader8Impl_AddRef(IDirect3DPixelShader8 *iface) { + IDirect3DPixelShader8Impl *This = (IDirect3DPixelShader8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DPixelShader8Impl_Release(IDirect3DPixelShader8 * iface) { + IDirect3DPixelShader8Impl *This = (IDirect3DPixelShader8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + IWineD3DPixelShader_Release(This->wineD3DPixelShader); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DPixelShader8 Interface follow: */ +static HRESULT WINAPI IDirect3DPixelShader8Impl_GetDevice(IDirect3DPixelShader8 *iface, IDirect3DDevice8 **ppDevice) { + IDirect3DPixelShader8Impl *This = (IDirect3DPixelShader8Impl *)iface; + IWineD3DDevice *myDevice = NULL; + + TRACE("(%p) : Relay\n", This); + + IWineD3DPixelShader_GetDevice(This->wineD3DPixelShader, &myDevice); + IWineD3DDevice_GetParent(myDevice, (IUnknown **)ppDevice); + IWineD3DDevice_Release(myDevice); + TRACE("(%p) returning (%p)\n", This, *ppDevice); + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DPixelShader8Impl_GetFunction(IDirect3DPixelShader8 *iface, VOID *pData, UINT *pSizeOfData) { + IDirect3DPixelShader8Impl *This = (IDirect3DPixelShader8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DPixelShader_GetFunction(This->wineD3DPixelShader, pData, pSizeOfData); +} + + +const IDirect3DPixelShader8Vtbl Direct3DPixelShader8_Vtbl = +{ + /* IUnknown */ + IDirect3DPixelShader8Impl_QueryInterface, + IDirect3DPixelShader8Impl_AddRef, + IDirect3DPixelShader8Impl_Release, + /* IDirect3DPixelShader8 */ + IDirect3DPixelShader8Impl_GetDevice, + IDirect3DPixelShader8Impl_GetFunction +}; diff --git a/reactos/dll/directx/wine/d3d8/resource.c b/reactos/dll/directx/wine/d3d8/resource.c new file mode 100644 index 00000000000..7cf40899d61 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/resource.c @@ -0,0 +1,133 @@ +/* + * IDirect3DResource8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DResource8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DResource8Impl_QueryInterface(LPDIRECT3DRESOURCE8 iface, REFIID riid, LPVOID* ppobj) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DResource8Impl_AddRef(LPDIRECT3DRESOURCE8 iface) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DResource8Impl_Release(LPDIRECT3DRESOURCE8 iface) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + IWineD3DResource_Release(This->wineD3DResource); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DResource8 Interface follow: */ +HRESULT WINAPI IDirect3DResource8Impl_GetDevice(LPDIRECT3DRESOURCE8 iface, IDirect3DDevice8** ppDevice) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + IWineD3DDevice *myDevice = NULL; + + TRACE("(%p) Relay\n", This); + + IWineD3DResource_GetDevice(This->wineD3DResource, &myDevice); + IWineD3DDevice_GetParent(myDevice, (IUnknown **)ppDevice); + IWineD3DDevice_Release(myDevice); + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DResource8Impl_SetPrivateData(LPDIRECT3DRESOURCE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DResource_SetPrivateData(This->wineD3DResource, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IDirect3DResource8Impl_GetPrivateData(LPDIRECT3DRESOURCE8 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DResource_GetPrivateData(This->wineD3DResource, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IDirect3DResource8Impl_FreePrivateData(LPDIRECT3DRESOURCE8 iface, REFGUID refguid) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DResource_FreePrivateData(This->wineD3DResource, refguid); +} + +static DWORD WINAPI IDirect3DResource8Impl_SetPriority(LPDIRECT3DRESOURCE8 iface, DWORD PriorityNew) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DResource_SetPriority(This->wineD3DResource, PriorityNew); +} + +static DWORD WINAPI IDirect3DResource8Impl_GetPriority(LPDIRECT3DRESOURCE8 iface) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DResource_GetPriority(This->wineD3DResource); +} + +static void WINAPI IDirect3DResource8Impl_PreLoad(LPDIRECT3DRESOURCE8 iface) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + IWineD3DResource_PreLoad(This->wineD3DResource); + return; +} + +static D3DRESOURCETYPE WINAPI IDirect3DResource8Impl_GetType(LPDIRECT3DRESOURCE8 iface) { + IDirect3DResource8Impl *This = (IDirect3DResource8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DResource_GetType(This->wineD3DResource); +} + +const IDirect3DResource8Vtbl Direct3DResource8_Vtbl = +{ + IDirect3DResource8Impl_QueryInterface, + IDirect3DResource8Impl_AddRef, + IDirect3DResource8Impl_Release, + IDirect3DResource8Impl_GetDevice, + IDirect3DResource8Impl_SetPrivateData, + IDirect3DResource8Impl_GetPrivateData, + IDirect3DResource8Impl_FreePrivateData, + IDirect3DResource8Impl_SetPriority, + IDirect3DResource8Impl_GetPriority, + IDirect3DResource8Impl_PreLoad, + IDirect3DResource8Impl_GetType +}; diff --git a/reactos/dll/directx/wine/d3d8/stateblock.c b/reactos/dll/directx/wine/d3d8/stateblock.c new file mode 100644 index 00000000000..d42fb79f889 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/stateblock.c @@ -0,0 +1,96 @@ +/* + * IDirect3DStateBlock8 implementation + * + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2002-2003 Jason Edmeades + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* NOTE: DirectX8 doesn't export a IDirect3DStateBlock8, the interface is used internally to keep d3d8 and d3d9 as simila as possible */ +/* IDirect3DStateBlock8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DStateBlock8Impl_QueryInterface(IDirect3DStateBlock8 *iface, REFIID riid, LPVOID *ppobj) { + IDirect3DStateBlock8Impl *This = (IDirect3DStateBlock8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DStateBlock8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DStateBlock8Impl_AddRef(IDirect3DStateBlock8 *iface) { + IDirect3DStateBlock8Impl *This = (IDirect3DStateBlock8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DStateBlock8Impl_Release(IDirect3DStateBlock8 *iface) { + IDirect3DStateBlock8Impl *This = (IDirect3DStateBlock8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + IWineD3DStateBlock_Release(This->wineD3DStateBlock); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DStateBlock8 Interface follow: */ +static HRESULT WINAPI IDirect3DStateBlock8Impl_GetDevice(IDirect3DStateBlock8 *iface, IDirect3DDevice8 **ppDevice) { + IDirect3DStateBlock8Impl *This = (IDirect3DStateBlock8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); +} + +static HRESULT WINAPI IDirect3DStateBlock8Impl_Capture(IDirect3DStateBlock8 *iface) { + IDirect3DStateBlock8Impl *This = (IDirect3DStateBlock8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DStateBlock_Capture(This->wineD3DStateBlock); +} + +static HRESULT WINAPI IDirect3DStateBlock8Impl_Apply(IDirect3DStateBlock8 *iface) { + IDirect3DStateBlock8Impl *This = (IDirect3DStateBlock8Impl *)iface; + TRACE("(%p) Relay\n", This); + return IWineD3DStateBlock_Apply(This->wineD3DStateBlock); +} + +const IDirect3DStateBlock8Vtbl Direct3DStateBlock8_Vtbl = +{ + /* IUnknown */ + IDirect3DStateBlock8Impl_QueryInterface, + IDirect3DStateBlock8Impl_AddRef, + IDirect3DStateBlock8Impl_Release, + /* IDirect3DStateBlock8 */ + IDirect3DStateBlock8Impl_GetDevice, + IDirect3DStateBlock8Impl_Capture, + IDirect3DStateBlock8Impl_Apply +}; diff --git a/reactos/dll/directx/wine/d3d8/surface.c b/reactos/dll/directx/wine/d3d8/surface.c new file mode 100644 index 00000000000..6ecd7af8c8f --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/surface.c @@ -0,0 +1,228 @@ +/* + * IDirect3DSurface8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DSurface8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DSurface8Impl_QueryInterface(LPDIRECT3DSURFACE8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DSurface8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DSurface8Impl_AddRef(LPDIRECT3DSURFACE8 iface) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + + TRACE("(%p)\n", This); + + if (This->forwardReference) { + /* Forward refcounting */ + TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference); + return IUnknown_AddRef(This->forwardReference); + } else { + /* No container, handle our own refcounting */ + ULONG ref = InterlockedIncrement(&This->ref); + if(ref == 1 && This->parentDevice) IUnknown_AddRef(This->parentDevice); + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + return ref; + } +} + +static ULONG WINAPI IDirect3DSurface8Impl_Release(LPDIRECT3DSURFACE8 iface) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + + TRACE("(%p)\n", This); + + if (This->forwardReference) { + /* Forward refcounting */ + TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference); + return IUnknown_Release(This->forwardReference); + } else { + /* No container, handle our own refcounting */ + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + if (This->parentDevice) IUnknown_Release(This->parentDevice); + /* Implicit surfaces are destroyed with the device, not if refcount reaches 0. */ + if (!This->isImplicit) { + EnterCriticalSection(&d3d8_cs); + IWineD3DSurface_Release(This->wineD3DSurface); + LeaveCriticalSection(&d3d8_cs); + HeapFree(GetProcessHeap(), 0, This); + } + } + + return ref; + } +} + +/* IDirect3DSurface8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DSurface8Impl_GetDevice(LPDIRECT3DSURFACE8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT hr; + TRACE("(%p)->(%p)\n", This, ppDevice); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DSurface8Impl_SetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, CONST void *pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DSurface_SetPrivateData(This->wineD3DSurface, refguid, pData, SizeOfData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DSurface8Impl_GetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, void *pData, DWORD *pSizeOfData) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DSurface_GetPrivateData(This->wineD3DSurface, refguid, pData, pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DSurface8Impl_FreePrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DSurface_FreePrivateData(This->wineD3DSurface, refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +/* IDirect3DSurface8 Interface follow: */ +static HRESULT WINAPI IDirect3DSurface8Impl_GetContainer(LPDIRECT3DSURFACE8 iface, REFIID riid, void **ppContainer) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT res; + + TRACE("(%p) Relay\n", This); + + if (!This->container) return E_NOINTERFACE; + + res = IUnknown_QueryInterface(This->container, riid, ppContainer); + + TRACE("(%p) : returning %p\n", This, *ppContainer); + return res; +} + +static HRESULT WINAPI IDirect3DSurface8Impl_GetDesc(LPDIRECT3DSURFACE8 iface, D3DSURFACE_DESC *pDesc) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + WINED3DSURFACE_DESC wined3ddesc; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + /* As d3d8 and d3d9 structures differ, pass in ptrs to where data needs to go */ + memset(&wined3ddesc, 0, sizeof(wined3ddesc)); + wined3ddesc.Format = (WINED3DFORMAT *)&pDesc->Format; + wined3ddesc.Type = (WINED3DRESOURCETYPE *)&pDesc->Type; + wined3ddesc.Usage = &pDesc->Usage; + wined3ddesc.Pool = (WINED3DPOOL *) &pDesc->Pool; + wined3ddesc.Size = &pDesc->Size; + wined3ddesc.MultiSampleType = (WINED3DMULTISAMPLE_TYPE *) &pDesc->MultiSampleType; + wined3ddesc.Width = &pDesc->Width; + wined3ddesc.Height = &pDesc->Height; + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DSurface_GetDesc(This->wineD3DSurface, &wined3ddesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DSurface8Impl_LockRect(LPDIRECT3DSURFACE8 iface, D3DLOCKED_RECT *pLockedRect, CONST RECT *pRect, DWORD Flags) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + TRACE("(%p) calling IWineD3DSurface_LockRect %p %p %p %d\n", This, This->wineD3DSurface, pLockedRect, pRect, Flags); + + EnterCriticalSection(&d3d8_cs); + if (pRect) { + D3DSURFACE_DESC desc; + IDirect3DSurface8_GetDesc(iface, &desc); + + if ((pRect->left < 0) + || (pRect->top < 0) + || (pRect->left >= pRect->right) + || (pRect->top >= pRect->bottom) + || (pRect->right > desc.Width) + || (pRect->bottom > desc.Height)) { + WARN("Trying to lock an invalid rectangle, returning D3DERR_INVALIDCALL\n"); + LeaveCriticalSection(&d3d8_cs); + return D3DERR_INVALIDCALL; + } + } + + hr = IWineD3DSurface_LockRect(This->wineD3DSurface, (WINED3DLOCKED_RECT *) pLockedRect, pRect, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(LPDIRECT3DSURFACE8 iface) { + IDirect3DSurface8Impl *This = (IDirect3DSurface8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DSurface_UnlockRect(This->wineD3DSurface); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +const IDirect3DSurface8Vtbl Direct3DSurface8_Vtbl = +{ + /* IUnknown */ + IDirect3DSurface8Impl_QueryInterface, + IDirect3DSurface8Impl_AddRef, + IDirect3DSurface8Impl_Release, + /* IDirect3DResource8 */ + IDirect3DSurface8Impl_GetDevice, + IDirect3DSurface8Impl_SetPrivateData, + IDirect3DSurface8Impl_GetPrivateData, + IDirect3DSurface8Impl_FreePrivateData, + /* IDirect3DSurface8 */ + IDirect3DSurface8Impl_GetContainer, + IDirect3DSurface8Impl_GetDesc, + IDirect3DSurface8Impl_LockRect, + IDirect3DSurface8Impl_UnlockRect +}; diff --git a/reactos/dll/directx/wine/d3d8/swapchain.c b/reactos/dll/directx/wine/d3d8/swapchain.c new file mode 100644 index 00000000000..25d2a0ee346 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/swapchain.c @@ -0,0 +1,104 @@ +/* + * IDirect3DSwapChain8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DSwapChain IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DSwapChain8Impl_QueryInterface(LPDIRECT3DSWAPCHAIN8 iface, REFIID riid, LPVOID* ppobj) +{ + IDirect3DSwapChain8Impl *This = (IDirect3DSwapChain8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DSwapChain8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DSwapChain8Impl_AddRef(LPDIRECT3DSWAPCHAIN8 iface) { + IDirect3DSwapChain8Impl *This = (IDirect3DSwapChain8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DSwapChain8Impl_Release(LPDIRECT3DSWAPCHAIN8 iface) { + IDirect3DSwapChain8Impl *This = (IDirect3DSwapChain8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + EnterCriticalSection(&d3d8_cs); + IWineD3DSwapChain_Destroy(This->wineD3DSwapChain, D3D8CB_DestroyRenderTarget); + LeaveCriticalSection(&d3d8_cs); + if (This->parentDevice) IUnknown_Release(This->parentDevice); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DSwapChain8 parts follow: */ +static HRESULT WINAPI IDirect3DSwapChain8Impl_Present(LPDIRECT3DSWAPCHAIN8 iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion) { + IDirect3DSwapChain8Impl *This = (IDirect3DSwapChain8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DSwapChain_Present(This->wineD3DSwapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DSwapChain8Impl_GetBackBuffer(LPDIRECT3DSWAPCHAIN8 iface, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface8** ppBackBuffer) { + IDirect3DSwapChain8Impl *This = (IDirect3DSwapChain8Impl *)iface; + HRESULT hrc = D3D_OK; + IWineD3DSurface *mySurface = NULL; + + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DSwapChain_GetBackBuffer(This->wineD3DSwapChain, iBackBuffer, (WINED3DBACKBUFFER_TYPE )Type, &mySurface); + if (hrc == D3D_OK && NULL != mySurface) { + IWineD3DSurface_GetParent(mySurface, (IUnknown **)ppBackBuffer); + IWineD3DSurface_Release(mySurface); + } + LeaveCriticalSection(&d3d8_cs); + return hrc; +} + +const IDirect3DSwapChain8Vtbl Direct3DSwapChain8_Vtbl = +{ + IDirect3DSwapChain8Impl_QueryInterface, + IDirect3DSwapChain8Impl_AddRef, + IDirect3DSwapChain8Impl_Release, + IDirect3DSwapChain8Impl_Present, + IDirect3DSwapChain8Impl_GetBackBuffer +}; diff --git a/reactos/dll/directx/wine/d3d8/texture.c b/reactos/dll/directx/wine/d3d8/texture.c new file mode 100644 index 00000000000..03f26d50b63 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/texture.c @@ -0,0 +1,288 @@ +/* + * IDirect3DTexture8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DTexture8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DTexture8Impl_QueryInterface(LPDIRECT3DTEXTURE8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DBaseTexture8) + || IsEqualGUID(riid, &IID_IDirect3DTexture8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p) not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DTexture8Impl_AddRef(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DTexture8Impl_Release(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + EnterCriticalSection(&d3d8_cs); + IWineD3DTexture_Destroy(This->wineD3DTexture, D3D8CB_DestroySurface); + LeaveCriticalSection(&d3d8_cs); + IUnknown_Release(This->parentDevice); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DTexture8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DTexture8Impl_GetDevice(LPDIRECT3DTEXTURE8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_SetPrivateData(LPDIRECT3DTEXTURE8 iface, REFGUID refguid, CONST void *pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_SetPrivateData(This->wineD3DTexture, refguid, pData, SizeOfData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_GetPrivateData(LPDIRECT3DTEXTURE8 iface, REFGUID refguid, void *pData, DWORD* pSizeOfData) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_GetPrivateData(This->wineD3DTexture, refguid, pData, pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_FreePrivateData(LPDIRECT3DTEXTURE8 iface, REFGUID refguid) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_FreePrivateData(This->wineD3DTexture, refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static DWORD WINAPI IDirect3DTexture8Impl_SetPriority(LPDIRECT3DTEXTURE8 iface, DWORD PriorityNew) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DTexture_SetPriority(This->wineD3DTexture, PriorityNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DTexture8Impl_GetPriority(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DTexture_GetPriority(This->wineD3DTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static void WINAPI IDirect3DTexture8Impl_PreLoad(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DTexture_PreLoad(This->wineD3DTexture); + LeaveCriticalSection(&d3d8_cs); +} + +static D3DRESOURCETYPE WINAPI IDirect3DTexture8Impl_GetType(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + D3DRESOURCETYPE type; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + type = IWineD3DTexture_GetType(This->wineD3DTexture); + LeaveCriticalSection(&d3d8_cs); + return type; +} + +/* IDirect3DTexture8 IDirect3DBaseTexture8 Interface follow: */ +static DWORD WINAPI IDirect3DTexture8Impl_SetLOD(LPDIRECT3DTEXTURE8 iface, DWORD LODNew) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DTexture_SetLOD(This->wineD3DTexture, LODNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DTexture8Impl_GetLOD(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DTexture_GetLOD(This->wineD3DTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DTexture8Impl_GetLevelCount(LPDIRECT3DTEXTURE8 iface) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DTexture_GetLevelCount(This->wineD3DTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +/* IDirect3DTexture8 Interface follow: */ +static HRESULT WINAPI IDirect3DTexture8Impl_GetLevelDesc(LPDIRECT3DTEXTURE8 iface, UINT Level, D3DSURFACE_DESC *pDesc) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + + WINED3DSURFACE_DESC wined3ddesc; + TRACE("(%p) Relay\n", This); + + /* As d3d8 and d3d9 structures differ, pass in ptrs to where data needs to go */ + memset(&wined3ddesc, 0, sizeof(wined3ddesc)); + wined3ddesc.Format = (WINED3DFORMAT *)&pDesc->Format; + wined3ddesc.Type = (WINED3DRESOURCETYPE *)&pDesc->Type; + wined3ddesc.Usage = &pDesc->Usage; + wined3ddesc.Pool = (WINED3DPOOL *) &pDesc->Pool; + wined3ddesc.Size = &pDesc->Size; + wined3ddesc.MultiSampleType = (WINED3DMULTISAMPLE_TYPE *) &pDesc->MultiSampleType; + wined3ddesc.Width = &pDesc->Width; + wined3ddesc.Height = &pDesc->Height; + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_GetLevelDesc(This->wineD3DTexture, Level, &wined3ddesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_GetSurfaceLevel(LPDIRECT3DTEXTURE8 iface, UINT Level, IDirect3DSurface8 **ppSurfaceLevel) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hrc = D3D_OK; + IWineD3DSurface *mySurface = NULL; + + TRACE("(%p) Relay\n", This); + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DTexture_GetSurfaceLevel(This->wineD3DTexture, Level, &mySurface); + if (hrc == D3D_OK && NULL != ppSurfaceLevel) { + IWineD3DSurface_GetParent(mySurface, (IUnknown **)ppSurfaceLevel); + IWineD3DSurface_Release(mySurface); + } + LeaveCriticalSection(&d3d8_cs); + return hrc; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_LockRect(LPDIRECT3DTEXTURE8 iface, UINT Level, D3DLOCKED_RECT *pLockedRect, CONST RECT *pRect, DWORD Flags) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_LockRect(This->wineD3DTexture, Level, (WINED3DLOCKED_RECT *) pLockedRect, pRect, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_UnlockRect(LPDIRECT3DTEXTURE8 iface, UINT Level) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_UnlockRect(This->wineD3DTexture, Level); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DTexture8Impl_AddDirtyRect(LPDIRECT3DTEXTURE8 iface, CONST RECT *pDirtyRect) { + IDirect3DTexture8Impl *This = (IDirect3DTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DTexture_AddDirtyRect(This->wineD3DTexture, pDirtyRect); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +const IDirect3DTexture8Vtbl Direct3DTexture8_Vtbl = +{ + /* IUnknown */ + IDirect3DTexture8Impl_QueryInterface, + IDirect3DTexture8Impl_AddRef, + IDirect3DTexture8Impl_Release, + /* IDirect3DResource8 */ + IDirect3DTexture8Impl_GetDevice, + IDirect3DTexture8Impl_SetPrivateData, + IDirect3DTexture8Impl_GetPrivateData, + IDirect3DTexture8Impl_FreePrivateData, + IDirect3DTexture8Impl_SetPriority, + IDirect3DTexture8Impl_GetPriority, + IDirect3DTexture8Impl_PreLoad, + IDirect3DTexture8Impl_GetType, + /* IDirect3dBaseTexture8 */ + IDirect3DTexture8Impl_SetLOD, + IDirect3DTexture8Impl_GetLOD, + IDirect3DTexture8Impl_GetLevelCount, + /* IDirect3DTexture8 */ + IDirect3DTexture8Impl_GetLevelDesc, + IDirect3DTexture8Impl_GetSurfaceLevel, + IDirect3DTexture8Impl_LockRect, + IDirect3DTexture8Impl_UnlockRect, + IDirect3DTexture8Impl_AddDirtyRect +}; diff --git a/reactos/dll/directx/wine/d3d8/version.rc b/reactos/dll/directx/wine/d3d8/version.rc new file mode 100644 index 00000000000..15aa334911c --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/version.rc @@ -0,0 +1,26 @@ +/* + * Copyright 2001 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINE_FILEDESCRIPTION_STR "Wine Direct3D" +#define WINE_FILENAME_STR "d3d8.dll" +#define WINE_FILEVERSION 5,3,1,904 +#define WINE_FILEVERSION_STR "5.3.1.904" +#define WINE_PRODUCTVERSION 5,3,1,904 +#define WINE_PRODUCTVERSION_STR "5.3.1.904" + +#include "wine/wine_common_ver.rc" diff --git a/reactos/dll/directx/wine/d3d8/vertexbuffer.c b/reactos/dll/directx/wine/d3d8/vertexbuffer.c new file mode 100644 index 00000000000..5dda94f07fa --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/vertexbuffer.c @@ -0,0 +1,210 @@ +/* + * IDirect3DVertexBuffer8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DVertexBuffer8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_QueryInterface(LPDIRECT3DVERTEXBUFFER8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DVertexBuffer8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DVertexBuffer8Impl_AddRef(LPDIRECT3DVERTEXBUFFER8 iface) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DVertexBuffer8Impl_Release(LPDIRECT3DVERTEXBUFFER8 iface) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + EnterCriticalSection(&d3d8_cs); + IWineD3DVertexBuffer_Release(This->wineD3DVertexBuffer); + LeaveCriticalSection(&d3d8_cs); + IUnknown_Release(This->parentDevice); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/* IDirect3DVertexBuffer8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_GetDevice(LPDIRECT3DVERTEXBUFFER8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_SetPrivateData(LPDIRECT3DVERTEXBUFFER8 iface, REFGUID refguid, CONST void *pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVertexBuffer_SetPrivateData(This->wineD3DVertexBuffer, refguid, pData, SizeOfData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_GetPrivateData(LPDIRECT3DVERTEXBUFFER8 iface, REFGUID refguid, void *pData, DWORD *pSizeOfData) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVertexBuffer_GetPrivateData(This->wineD3DVertexBuffer, refguid, pData, pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_FreePrivateData(LPDIRECT3DVERTEXBUFFER8 iface, REFGUID refguid) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVertexBuffer_FreePrivateData(This->wineD3DVertexBuffer, refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static DWORD WINAPI IDirect3DVertexBuffer8Impl_SetPriority(LPDIRECT3DVERTEXBUFFER8 iface, DWORD PriorityNew) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVertexBuffer_SetPriority(This->wineD3DVertexBuffer, PriorityNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DVertexBuffer8Impl_GetPriority(LPDIRECT3DVERTEXBUFFER8 iface) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVertexBuffer_GetPriority(This->wineD3DVertexBuffer); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static void WINAPI IDirect3DVertexBuffer8Impl_PreLoad(LPDIRECT3DVERTEXBUFFER8 iface) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DVertexBuffer_PreLoad(This->wineD3DVertexBuffer); + LeaveCriticalSection(&d3d8_cs); +} + +static D3DRESOURCETYPE WINAPI IDirect3DVertexBuffer8Impl_GetType(LPDIRECT3DVERTEXBUFFER8 iface) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + D3DRESOURCETYPE type; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + type = IWineD3DVertexBuffer_GetType(This->wineD3DVertexBuffer); + LeaveCriticalSection(&d3d8_cs); + return type; +} + +/* IDirect3DVertexBuffer8 Interface follow: */ +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_Lock(LPDIRECT3DVERTEXBUFFER8 iface, UINT OffsetToLock, UINT SizeToLock, BYTE **ppbData, DWORD Flags) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVertexBuffer_Lock(This->wineD3DVertexBuffer, OffsetToLock, SizeToLock, ppbData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_Unlock(LPDIRECT3DVERTEXBUFFER8 iface) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVertexBuffer_Unlock(This->wineD3DVertexBuffer); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVertexBuffer8Impl_GetDesc(LPDIRECT3DVERTEXBUFFER8 iface, D3DVERTEXBUFFER_DESC *pDesc) { + IDirect3DVertexBuffer8Impl *This = (IDirect3DVertexBuffer8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVertexBuffer_GetDesc(This->wineD3DVertexBuffer, (WINED3DVERTEXBUFFER_DESC *) pDesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +const IDirect3DVertexBuffer8Vtbl Direct3DVertexBuffer8_Vtbl = +{ + /* IUnknown */ + IDirect3DVertexBuffer8Impl_QueryInterface, + IDirect3DVertexBuffer8Impl_AddRef, + IDirect3DVertexBuffer8Impl_Release, + /* IDirect3DResource8 */ + IDirect3DVertexBuffer8Impl_GetDevice, + IDirect3DVertexBuffer8Impl_SetPrivateData, + IDirect3DVertexBuffer8Impl_GetPrivateData, + IDirect3DVertexBuffer8Impl_FreePrivateData, + IDirect3DVertexBuffer8Impl_SetPriority, + IDirect3DVertexBuffer8Impl_GetPriority, + IDirect3DVertexBuffer8Impl_PreLoad, + IDirect3DVertexBuffer8Impl_GetType, + /* IDirect3DVertexBuffer8 */ + IDirect3DVertexBuffer8Impl_Lock, + IDirect3DVertexBuffer8Impl_Unlock, + IDirect3DVertexBuffer8Impl_GetDesc +}; diff --git a/reactos/dll/directx/wine/d3d8/vertexdeclaration.c b/reactos/dll/directx/wine/d3d8/vertexdeclaration.c new file mode 100644 index 00000000000..f2e5d576b0e --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/vertexdeclaration.c @@ -0,0 +1,340 @@ +/* + * IDirect3DVertexDeclaration8 implementation + * + * Copyright 2007 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* IDirect3DVertexDeclaration8 is internal to our implementation. + * It's not visible in the API. */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IUnknown */ +static HRESULT WINAPI IDirect3DVertexDeclaration8Impl_QueryInterface(IDirect3DVertexDeclaration8 *iface, REFIID riid, void **obj_ptr) +{ + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj_ptr); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DVertexDeclaration8)) + { + IUnknown_AddRef(iface); + *obj_ptr = iface; + return S_OK; + } + + *obj_ptr = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DVertexDeclaration8Impl_AddRef(IDirect3DVertexDeclaration8 *iface) +{ + IDirect3DVertexDeclaration8Impl *This = (IDirect3DVertexDeclaration8Impl *)iface; + + ULONG ref_count = InterlockedIncrement(&This->ref_count); + TRACE("(%p) : AddRef increasing to %d\n", This, ref_count); + + return ref_count; +} + +static ULONG WINAPI IDirect3DVertexDeclaration8Impl_Release(IDirect3DVertexDeclaration8 *iface) +{ + IDirect3DVertexDeclaration8Impl *This = (IDirect3DVertexDeclaration8Impl *)iface; + + ULONG ref_count = InterlockedDecrement(&This->ref_count); + TRACE("(%p) : Releasing to %d\n", This, ref_count); + + if (!ref_count) { + IWineD3DVertexDeclaration_Release(This->wined3d_vertex_declaration); + HeapFree(GetProcessHeap(), 0, This->elements); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref_count; +} + +static const char *debug_d3dvsdt_type(D3DVSDT_TYPE d3dvsdt_type) +{ + switch (d3dvsdt_type) + { +#define D3DVSDT_TYPE_TO_STR(u) case u: return #u + D3DVSDT_TYPE_TO_STR(D3DVSDT_FLOAT1); + D3DVSDT_TYPE_TO_STR(D3DVSDT_FLOAT2); + D3DVSDT_TYPE_TO_STR(D3DVSDT_FLOAT3); + D3DVSDT_TYPE_TO_STR(D3DVSDT_FLOAT4); + D3DVSDT_TYPE_TO_STR(D3DVSDT_D3DCOLOR); + D3DVSDT_TYPE_TO_STR(D3DVSDT_UBYTE4); + D3DVSDT_TYPE_TO_STR(D3DVSDT_SHORT2); + D3DVSDT_TYPE_TO_STR(D3DVSDT_SHORT4); +#undef D3DVSDT_TYPE_TO_STR + default: + FIXME("Unrecognized D3DVSDT_TYPE %#x\n", d3dvsdt_type); + return "unrecognized"; + } +} + +static const char *debug_d3dvsde_register(D3DVSDE_REGISTER d3dvsde_register) +{ + switch (d3dvsde_register) + { +#define D3DVSDE_REGISTER_TO_STR(u) case u: return #u + D3DVSDE_REGISTER_TO_STR(D3DVSDE_POSITION); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_BLENDWEIGHT); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_BLENDINDICES); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_NORMAL); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_PSIZE); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_DIFFUSE); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_SPECULAR); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD0); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD1); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD2); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD3); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD4); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD5); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD6); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_TEXCOORD7); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_POSITION2); + D3DVSDE_REGISTER_TO_STR(D3DVSDE_NORMAL2); +#undef D3DVSDE_REGISTER_TO_STR + default: + FIXME("Unrecognized D3DVSDE_REGISTER %#x\n", d3dvsde_register); + return "unrecognized"; + } +} + +static size_t parse_token(const DWORD* pToken) +{ + const DWORD token = *pToken; + size_t tokenlen = 1; + + switch ((token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT) { /* maybe a macro to inverse ... */ + case D3DVSD_TOKEN_NOP: + TRACE(" 0x%08x NOP()\n", token); + break; + + case D3DVSD_TOKEN_STREAM: + if (token & D3DVSD_STREAMTESSMASK) + { + TRACE(" 0x%08x STREAM_TESS()\n", token); + } else { + TRACE(" 0x%08x STREAM(%u)\n", token, ((token & D3DVSD_STREAMNUMBERMASK) >> D3DVSD_STREAMNUMBERSHIFT)); + } + break; + + case D3DVSD_TOKEN_STREAMDATA: + if (token & 0x10000000) + { + TRACE(" 0x%08x SKIP(%u)\n", token, ((token & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT)); + } else { + DWORD type = ((token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT); + DWORD reg = ((token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT); + TRACE(" 0x%08x REG(%s, %s)\n", token, debug_d3dvsde_register(reg), debug_d3dvsdt_type(type)); + } + break; + + case D3DVSD_TOKEN_TESSELLATOR: + if (token & 0x10000000) + { + DWORD type = ((token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT); + DWORD reg = ((token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT); + TRACE(" 0x%08x TESSUV(%s) as %s\n", token, debug_d3dvsde_register(reg), debug_d3dvsdt_type(type)); + } else { + DWORD type = ((token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT); + DWORD regout = ((token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT); + DWORD regin = ((token & D3DVSD_VERTEXREGINMASK) >> D3DVSD_VERTEXREGINSHIFT); + TRACE(" 0x%08x TESSNORMAL(%s, %s) as %s\n", token, debug_d3dvsde_register(regin), + debug_d3dvsde_register(regout), debug_d3dvsdt_type(type)); + } + break; + + case D3DVSD_TOKEN_CONSTMEM: + { + DWORD count = ((token & D3DVSD_CONSTCOUNTMASK) >> D3DVSD_CONSTCOUNTSHIFT); + tokenlen = (4 * count) + 1; + } + break; + + case D3DVSD_TOKEN_EXT: + { + DWORD count = ((token & D3DVSD_CONSTCOUNTMASK) >> D3DVSD_CONSTCOUNTSHIFT); + DWORD extinfo = ((token & D3DVSD_EXTINFOMASK) >> D3DVSD_EXTINFOSHIFT); + TRACE(" 0x%08x EXT(%u, %u)\n", token, count, extinfo); + /* todo ... print extension */ + tokenlen = count + 1; + } + break; + + case D3DVSD_TOKEN_END: + TRACE(" 0x%08x END()\n", token); + break; + + default: + TRACE(" 0x%08x UNKNOWN\n", token); + /* argg error */ + } + + return tokenlen; +} + +void load_local_constants(const DWORD *d3d8_elements, IWineD3DVertexShader *wined3d_vertex_shader) +{ + const DWORD *token = d3d8_elements; + + while (*token != D3DVSD_END()) + { + if (((*token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT) == D3DVSD_TOKEN_CONSTMEM) + { + DWORD count = ((*token & D3DVSD_CONSTCOUNTMASK) >> D3DVSD_CONSTCOUNTSHIFT); + DWORD constant_idx = ((*token & D3DVSD_CONSTADDRESSMASK) >> D3DVSD_CONSTADDRESSSHIFT); + HRESULT hr; + + if (TRACE_ON(d3d8)) + { + DWORD i; + for (i = 0; i < count; ++i) + { + TRACE("c[%u] = (%8f, %8f, %8f, %8f)\n", + constant_idx, + *(const float *)(token + i * 4 + 1), + *(const float *)(token + i * 4 + 2), + *(const float *)(token + i * 4 + 3), + *(const float *)(token + i * 4 + 4)); + } + } + hr = IWineD3DVertexShader_SetLocalConstantsF(wined3d_vertex_shader, constant_idx, (const float *)token+1, count); + if (FAILED(hr)) ERR("Failed setting shader constants\n"); + } + + token += parse_token(token); + } +} + +/* NOTE: Make sure these are in the correct numerical order. (see /include/wined3d_types.h) */ +static const size_t wined3d_type_sizes[WINED3DDECLTYPE_UNUSED] = { + /*WINED3DDECLTYPE_FLOAT1*/ 1 * sizeof(float), + /*WINED3DDECLTYPE_FLOAT2*/ 2 * sizeof(float), + /*WINED3DDECLTYPE_FLOAT3*/ 3 * sizeof(float), + /*WINED3DDECLTYPE_FLOAT4*/ 4 * sizeof(float), + /*WINED3DDECLTYPE_D3DCOLOR*/ 4 * sizeof(BYTE), + /*WINED3DDECLTYPE_UBYTE4*/ 4 * sizeof(BYTE), + /*WINED3DDECLTYPE_SHORT2*/ 2 * sizeof(short int), + /*WINED3DDECLTYPE_SHORT4*/ 4 * sizeof(short int), + /*WINED3DDECLTYPE_UBYTE4N*/ 4 * sizeof(BYTE), + /*WINED3DDECLTYPE_SHORT2N*/ 2 * sizeof(short int), + /*WINED3DDECLTYPE_SHORT4N*/ 4 * sizeof(short int), + /*WINED3DDECLTYPE_USHORT2N*/ 2 * sizeof(short int), + /*WINED3DDECLTYPE_USHORT4N*/ 4 * sizeof(short int), + /*WINED3DDECLTYPE_UDEC3*/ 3 * sizeof(short int), + /*WINED3DDECLTYPE_DEC3N*/ 3 * sizeof(short int), + /*WINED3DDECLTYPE_FLOAT16_2*/ 2 * sizeof(short int), + /*WINED3DDECLTYPE_FLOAT16_4*/ 4 * sizeof(short int) +}; + +typedef struct { + BYTE usage; + BYTE usage_idx; +} wined3d_usage_t; + +static const wined3d_usage_t wined3d_usage_lookup[] = { + /*D3DVSDE_POSITION*/ {WINED3DDECLUSAGE_POSITION, 0}, + /*D3DVSDE_BLENDWEIGHT*/ {WINED3DDECLUSAGE_BLENDWEIGHT, 0}, + /*D3DVSDE_BLENDINDICES*/ {WINED3DDECLUSAGE_BLENDINDICES, 0}, + /*D3DVSDE_NORMAL*/ {WINED3DDECLUSAGE_NORMAL, 0}, + /*D3DVSDE_PSIZE*/ {WINED3DDECLUSAGE_PSIZE, 0}, + /*D3DVSDE_DIFFUSE*/ {WINED3DDECLUSAGE_COLOR, 0}, + /*D3DVSDE_SPECULAR*/ {WINED3DDECLUSAGE_COLOR, 1}, + /*D3DVSDE_TEXCOORD0*/ {WINED3DDECLUSAGE_TEXCOORD, 0}, + /*D3DVSDE_TEXCOORD1*/ {WINED3DDECLUSAGE_TEXCOORD, 1}, + /*D3DVSDE_TEXCOORD2*/ {WINED3DDECLUSAGE_TEXCOORD, 2}, + /*D3DVSDE_TEXCOORD3*/ {WINED3DDECLUSAGE_TEXCOORD, 3}, + /*D3DVSDE_TEXCOORD4*/ {WINED3DDECLUSAGE_TEXCOORD, 4}, + /*D3DVSDE_TEXCOORD5*/ {WINED3DDECLUSAGE_TEXCOORD, 5}, + /*D3DVSDE_TEXCOORD6*/ {WINED3DDECLUSAGE_TEXCOORD, 6}, + /*D3DVSDE_TEXCOORD7*/ {WINED3DDECLUSAGE_TEXCOORD, 7}, + /*D3DVSDE_POSITION2*/ {WINED3DDECLUSAGE_POSITION, 1}, + /*D3DVSDE_NORMAL2*/ {WINED3DDECLUSAGE_NORMAL, 1}, +}; + +/* TODO: find out where rhw (or positionT) is for declaration8 */ +size_t convert_to_wined3d_declaration(const DWORD *d3d8_elements, DWORD *d3d8_elements_size, WINED3DVERTEXELEMENT **wined3d_elements) +{ + const DWORD *token = d3d8_elements; + WINED3DVERTEXELEMENT *element; + D3DVSD_TOKENTYPE token_type; + unsigned int element_count = 0; + DWORD stream = 0; + int offset = 0; + + TRACE("d3d8_elements %p, wined3d_elements %p\n", d3d8_elements, wined3d_elements); + + /* 128 should be enough for anyone... */ + *wined3d_elements = HeapAlloc(GetProcessHeap(), 0, 128 * sizeof(WINED3DVERTEXELEMENT)); + while (D3DVSD_END() != *token) + { + token_type = ((*token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT); + + if (token_type == D3DVSD_TOKEN_STREAM && !(*token & D3DVSD_STREAMTESSMASK)) + { + stream = ((*token & D3DVSD_STREAMNUMBERMASK) >> D3DVSD_STREAMNUMBERSHIFT); + offset = 0; + } else if (token_type == D3DVSD_TOKEN_STREAMDATA && !(token_type & 0x10000000)) { + DWORD type = ((*token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT); + DWORD reg = ((*token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT); + + TRACE("Adding element %d:\n", element_count); + + element = *wined3d_elements + element_count++; + element->Stream = stream; + element->Method = WINED3DDECLMETHOD_DEFAULT; + element->Usage = wined3d_usage_lookup[reg].usage; + element->UsageIndex = wined3d_usage_lookup[reg].usage_idx; + element->Type = type; + element->Offset = offset; + element->Reg = reg; + + offset += wined3d_type_sizes[type]; + } else if (token_type == D3DVSD_TOKEN_STREAMDATA && (token_type & 0x10000000)) { + TRACE(" 0x%08x SKIP(%u)\n", token_type, ((token_type & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT)); + offset += sizeof(DWORD) * ((token_type & D3DVSD_SKIPCOUNTMASK) >> D3DVSD_SKIPCOUNTSHIFT); + } + + if (element_count >= 127) { + ERR("More than 127 elements?\n"); + break; + } + + token += parse_token(token); + } + + /* END */ + element = *wined3d_elements + element_count++; + element->Stream = 0xFF; + element->Type = WINED3DDECLTYPE_UNUSED; + + *d3d8_elements_size = (++token - d3d8_elements) * sizeof(DWORD); + + return element_count; +} + +const IDirect3DVertexDeclaration8Vtbl Direct3DVertexDeclaration8_Vtbl = +{ + IDirect3DVertexDeclaration8Impl_QueryInterface, + IDirect3DVertexDeclaration8Impl_AddRef, + IDirect3DVertexDeclaration8Impl_Release +}; diff --git a/reactos/dll/directx/wine/d3d8/vertexshader.c b/reactos/dll/directx/wine/d3d8/vertexshader.c new file mode 100644 index 00000000000..89555bd7d98 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/vertexshader.c @@ -0,0 +1,100 @@ +/* + * IDirect3DVertexShader8 implementation + * + * Copyright 2002-2003 Jason Edmeades + * Raphael Junqueira + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DVertexShader8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DVertexShader8Impl_QueryInterface(IDirect3DVertexShader8 *iface, REFIID riid, LPVOID* ppobj) { + IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DVertexShader8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DVertexShader8Impl_AddRef(IDirect3DVertexShader8 *iface) { + IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DVertexShader8Impl_Release(IDirect3DVertexShader8 *iface) { + IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + IDirect3DVertexDeclaration8_Release(This->vertex_declaration); + IWineD3DVertexShader_Release(This->wineD3DVertexShader); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DVertexShader8 Interface follow: */ +static HRESULT WINAPI IDirect3DVertexShader8Impl_GetDevice(IDirect3DVertexShader8 *iface, IDirect3DDevice8** ppDevice) { + IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface; + IWineD3DDevice *myDevice = NULL; + HRESULT hr = D3D_OK; + TRACE("(%p) : Relay\n", This); + + if (D3D_OK == (hr = IWineD3DVertexShader_GetDevice(This->wineD3DVertexShader, &myDevice) && myDevice != NULL)) { + hr = IWineD3DDevice_GetParent(myDevice, (IUnknown **)ppDevice); + IWineD3DDevice_Release(myDevice); + } else { + *ppDevice = NULL; + } + TRACE("(%p) returning (%p)\n", This, *ppDevice); + return hr; +} + +static HRESULT WINAPI IDirect3DVertexShader8Impl_GetFunction(IDirect3DVertexShader8 *iface, VOID* pData, UINT* pSizeOfData) { + IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface; + + TRACE("(%p) : Relay\n", This); + return IWineD3DVertexShader_GetFunction(This->wineD3DVertexShader, pData, pSizeOfData); +} + + +const IDirect3DVertexShader8Vtbl Direct3DVertexShader8_Vtbl = +{ + /* IUnknown */ + IDirect3DVertexShader8Impl_QueryInterface, + IDirect3DVertexShader8Impl_AddRef, + IDirect3DVertexShader8Impl_Release, + /* IDirect3DVertexShader8 */ + IDirect3DVertexShader8Impl_GetDevice, + IDirect3DVertexShader8Impl_GetFunction +}; diff --git a/reactos/dll/directx/wine/d3d8/volume.c b/reactos/dll/directx/wine/d3d8/volume.c new file mode 100644 index 00000000000..bea2ea9f8bc --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/volume.c @@ -0,0 +1,256 @@ +/* + * IDirect3DVolume8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DVolume8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DVolume8Impl_QueryInterface(LPDIRECT3DVOLUME8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DVolume8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DVolume8Impl_AddRef(LPDIRECT3DVOLUME8 iface) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + + TRACE("(%p)\n", This); + + if (This->forwardReference) { + /* Forward to the containerParent */ + TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference); + return IUnknown_AddRef(This->forwardReference); + } else { + /* No container, handle our own refcounting */ + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + return ref; + } +} + +static ULONG WINAPI IDirect3DVolume8Impl_Release(LPDIRECT3DVOLUME8 iface) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + + TRACE("(%p)\n", This); + + if (This->forwardReference) { + /* Forward to the containerParent */ + TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference); + return IUnknown_Release(This->forwardReference); + } + else { + /* No container, handle our own refcounting */ + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + EnterCriticalSection(&d3d8_cs); + IWineD3DVolume_Release(This->wineD3DVolume); + LeaveCriticalSection(&d3d8_cs); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; + } +} + +/* IDirect3DVolume8 Interface follow: */ +static HRESULT WINAPI IDirect3DVolume8Impl_GetDevice(LPDIRECT3DVOLUME8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + IWineD3DDevice *myDevice = NULL; + + EnterCriticalSection(&d3d8_cs); + IWineD3DVolume_GetDevice(This->wineD3DVolume, &myDevice); + IWineD3DDevice_GetParent(myDevice, (IUnknown **)ppDevice); + IWineD3DDevice_Release(myDevice); + LeaveCriticalSection(&d3d8_cs); + return D3D_OK; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_SetPrivateData(LPDIRECT3DVOLUME8 iface, REFGUID refguid, CONST void *pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolume_SetPrivateData(This->wineD3DVolume, refguid, pData, SizeOfData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_GetPrivateData(LPDIRECT3DVOLUME8 iface, REFGUID refguid, void *pData, DWORD* pSizeOfData) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolume_GetPrivateData(This->wineD3DVolume, refguid, pData, pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_FreePrivateData(LPDIRECT3DVOLUME8 iface, REFGUID refguid) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolume_FreePrivateData(This->wineD3DVolume, refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_GetContainer(LPDIRECT3DVOLUME8 iface, REFIID riid, void **ppContainer) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT res; + + TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer); + + if (!This->container) return E_NOINTERFACE; + + if (!ppContainer) { + ERR("Called without a valid ppContainer.\n"); + } + + res = IUnknown_QueryInterface(This->container, riid, ppContainer); + + TRACE("Returning ppContainer %p, *ppContainer %p\n", ppContainer, *ppContainer); + + return res; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_GetDesc(LPDIRECT3DVOLUME8 iface, D3DVOLUME_DESC *pDesc) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT hr; + WINED3DVOLUME_DESC wined3ddesc; + + TRACE("(%p) Relay\n", This); + + /* As d3d8 and d3d9 structures differ, pass in ptrs to where data needs to go */ + wined3ddesc.Format = (WINED3DFORMAT *)&pDesc->Format; + wined3ddesc.Type = (WINED3DRESOURCETYPE *)&pDesc->Type; + wined3ddesc.Usage = &pDesc->Usage; + wined3ddesc.Pool = (WINED3DPOOL *) &pDesc->Pool; + wined3ddesc.Size = &pDesc->Size; + wined3ddesc.Width = &pDesc->Width; + wined3ddesc.Height = &pDesc->Height; + wined3ddesc.Depth = &pDesc->Depth; + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolume_GetDesc(This->wineD3DVolume, &wined3ddesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_LockBox(LPDIRECT3DVOLUME8 iface, D3DLOCKED_BOX *pLockedVolume, CONST D3DBOX *pBox, DWORD Flags) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT hr; + TRACE("(%p) relay %p %p %p %d\n", This, This->wineD3DVolume, pLockedVolume, pBox, Flags); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolume_LockBox(This->wineD3DVolume, (WINED3DLOCKED_BOX *) pLockedVolume, (CONST WINED3DBOX *) pBox, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolume8Impl_UnlockBox(LPDIRECT3DVOLUME8 iface) { + IDirect3DVolume8Impl *This = (IDirect3DVolume8Impl *)iface; + HRESULT hr; + TRACE("(%p) relay %p\n", This, This->wineD3DVolume); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolume_UnlockBox(This->wineD3DVolume); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static const IDirect3DVolume8Vtbl Direct3DVolume8_Vtbl = +{ + /* IUnknown */ + IDirect3DVolume8Impl_QueryInterface, + IDirect3DVolume8Impl_AddRef, + IDirect3DVolume8Impl_Release, + /* IDirect3DVolume8 */ + IDirect3DVolume8Impl_GetDevice, + IDirect3DVolume8Impl_SetPrivateData, + IDirect3DVolume8Impl_GetPrivateData, + IDirect3DVolume8Impl_FreePrivateData, + IDirect3DVolume8Impl_GetContainer, + IDirect3DVolume8Impl_GetDesc, + IDirect3DVolume8Impl_LockBox, + IDirect3DVolume8Impl_UnlockBox +}; + + +/* Internal function called back during the CreateVolumeTexture */ +HRESULT WINAPI D3D8CB_CreateVolume(IUnknown *pDevice, IUnknown *pSuperior, UINT Width, UINT Height, UINT Depth, + WINED3DFORMAT Format, WINED3DPOOL Pool, DWORD Usage, + IWineD3DVolume **ppVolume, + HANDLE * pSharedHandle) { + IDirect3DVolume8Impl *object; + IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)pDevice; + HRESULT hrc = D3D_OK; + + /* Allocate the storage for the device */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVolume8Impl)); + if (NULL == object) { + FIXME("Allocation of memory failed\n"); + *ppVolume = NULL; + return D3DERR_OUTOFVIDEOMEMORY; + } + + object->lpVtbl = &Direct3DVolume8_Vtbl; + object->ref = 1; + hrc = IWineD3DDevice_CreateVolume(This->WineD3DDevice, Width, Height, Depth, Usage, Format, + Pool, &object->wineD3DVolume, pSharedHandle, (IUnknown *)object); + if (hrc != D3D_OK) { + /* free up object */ + FIXME("(%p) call to IWineD3DDevice_CreateVolume failed\n", This); + HeapFree(GetProcessHeap(), 0, object); + *ppVolume = NULL; + } else { + *ppVolume = (IWineD3DVolume *)object->wineD3DVolume; + object->container = pSuperior; + object->forwardReference = pSuperior; + } + TRACE("(%p) Created volume %p\n", This, *ppVolume); + return hrc; +} + +ULONG WINAPI D3D8CB_DestroyVolume(IWineD3DVolume *pVolume) { + IDirect3DVolume8Impl* volumeParent; + + IWineD3DVolume_GetParent(pVolume, (IUnknown **) &volumeParent); + /* GetParent's AddRef was forwarded to an object in destruction. + * Releasing it here again would cause an endless recursion. */ + volumeParent->forwardReference = NULL; + return IDirect3DVolume8_Release((IDirect3DVolume8*) volumeParent); +} diff --git a/reactos/dll/directx/wine/d3d8/volumetexture.c b/reactos/dll/directx/wine/d3d8/volumetexture.c new file mode 100644 index 00000000000..fc35f3d9b95 --- /dev/null +++ b/reactos/dll/directx/wine/d3d8/volumetexture.c @@ -0,0 +1,291 @@ +/* + * IDirect3DVolumeTexture8 implementation + * + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "d3d8_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d8); + +/* IDirect3DVolumeTexture8 IUnknown parts follow: */ +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_QueryInterface(LPDIRECT3DVOLUMETEXTURE8 iface, REFIID riid, LPVOID *ppobj) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IDirect3DResource8) + || IsEqualGUID(riid, &IID_IDirect3DBaseTexture8) + || IsEqualGUID(riid, &IID_IDirect3DVolumeTexture8)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj); + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IDirect3DVolumeTexture8Impl_AddRef(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef from %d\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IDirect3DVolumeTexture8Impl_Release(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) : ReleaseRef to %d\n", This, ref); + + if (ref == 0) { + EnterCriticalSection(&d3d8_cs); + IWineD3DVolumeTexture_Destroy(This->wineD3DVolumeTexture, D3D8CB_DestroyVolume); + LeaveCriticalSection(&d3d8_cs); + IUnknown_Release(This->parentDevice); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* IDirect3DVolumeTexture8 IDirect3DResource8 Interface follow: */ +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_GetDevice(LPDIRECT3DVOLUMETEXTURE8 iface, IDirect3DDevice8 **ppDevice) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IDirect3DResource8Impl_GetDevice((LPDIRECT3DRESOURCE8) This, ppDevice); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_SetPrivateData(LPDIRECT3DVOLUMETEXTURE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_SetPrivateData(This->wineD3DVolumeTexture, refguid, pData, SizeOfData, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_GetPrivateData(LPDIRECT3DVOLUMETEXTURE8 iface, REFGUID refguid, void *pData, DWORD *pSizeOfData) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_GetPrivateData(This->wineD3DVolumeTexture, refguid, pData, pSizeOfData); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_FreePrivateData(LPDIRECT3DVOLUMETEXTURE8 iface, REFGUID refguid) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_FreePrivateData(This->wineD3DVolumeTexture, refguid); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static DWORD WINAPI IDirect3DVolumeTexture8Impl_SetPriority(LPDIRECT3DVOLUMETEXTURE8 iface, DWORD PriorityNew) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVolumeTexture_SetPriority(This->wineD3DVolumeTexture, PriorityNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DVolumeTexture8Impl_GetPriority(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVolumeTexture_GetPriority(This->wineD3DVolumeTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static void WINAPI IDirect3DVolumeTexture8Impl_PreLoad(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + IWineD3DVolumeTexture_PreLoad(This->wineD3DVolumeTexture); + LeaveCriticalSection(&d3d8_cs); +} + +static D3DRESOURCETYPE WINAPI IDirect3DVolumeTexture8Impl_GetType(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + D3DRESOURCETYPE type; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + type = IWineD3DVolumeTexture_GetType(This->wineD3DVolumeTexture); + LeaveCriticalSection(&d3d8_cs); + return type; +} + +/* IDirect3DVolumeTexture8 IDirect3DBaseTexture8 Interface follow: */ +static DWORD WINAPI IDirect3DVolumeTexture8Impl_SetLOD(LPDIRECT3DVOLUMETEXTURE8 iface, DWORD LODNew) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVolumeTexture_SetLOD(This->wineD3DVolumeTexture, LODNew); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DVolumeTexture8Impl_GetLOD(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVolumeTexture_GetLOD(This->wineD3DVolumeTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +static DWORD WINAPI IDirect3DVolumeTexture8Impl_GetLevelCount(LPDIRECT3DVOLUMETEXTURE8 iface) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + DWORD ret; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + ret = IWineD3DVolumeTexture_GetLevelCount(This->wineD3DVolumeTexture); + LeaveCriticalSection(&d3d8_cs); + return ret; +} + +/* IDirect3DVolumeTexture8 Interface follow: */ +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_GetLevelDesc(LPDIRECT3DVOLUMETEXTURE8 iface, UINT Level, D3DVOLUME_DESC* pDesc) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + WINED3DVOLUME_DESC wined3ddesc; + UINT tmpInt = -1; + HRESULT hr; + + TRACE("(%p) Relay\n", This); + + /* As d3d8 and d3d8 structures differ, pass in ptrs to where data needs to go */ + wined3ddesc.Format = (WINED3DFORMAT *)&pDesc->Format; + wined3ddesc.Type = (WINED3DRESOURCETYPE *)&pDesc->Type; + wined3ddesc.Usage = &pDesc->Usage; + wined3ddesc.Pool = (WINED3DPOOL *) &pDesc->Pool; + wined3ddesc.Size = &tmpInt; + wined3ddesc.Width = &pDesc->Width; + wined3ddesc.Height = &pDesc->Height; + wined3ddesc.Depth = &pDesc->Depth; + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_GetLevelDesc(This->wineD3DVolumeTexture, Level, &wined3ddesc); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_GetVolumeLevel(LPDIRECT3DVOLUMETEXTURE8 iface, UINT Level, IDirect3DVolume8 **ppVolumeLevel) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hrc = D3D_OK; + IWineD3DVolume *myVolume = NULL; + + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hrc = IWineD3DVolumeTexture_GetVolumeLevel(This->wineD3DVolumeTexture, Level, &myVolume); + if (hrc == D3D_OK && NULL != ppVolumeLevel) { + IWineD3DVolumeTexture_GetParent(myVolume, (IUnknown **)ppVolumeLevel); + IWineD3DVolumeTexture_Release(myVolume); + } + LeaveCriticalSection(&d3d8_cs); + return hrc; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_LockBox(LPDIRECT3DVOLUMETEXTURE8 iface, UINT Level, D3DLOCKED_BOX *pLockedVolume, CONST D3DBOX *pBox, DWORD Flags) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay %p %p %p %d\n", This, This->wineD3DVolumeTexture, pLockedVolume, pBox,Flags); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_LockBox(This->wineD3DVolumeTexture, Level, (WINED3DLOCKED_BOX *) pLockedVolume, (CONST WINED3DBOX *) pBox, Flags); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_UnlockBox(LPDIRECT3DVOLUMETEXTURE8 iface, UINT Level) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay %p %d\n", This, This->wineD3DVolumeTexture, Level); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_UnlockBox(This->wineD3DVolumeTexture, Level); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + +static HRESULT WINAPI IDirect3DVolumeTexture8Impl_AddDirtyBox(LPDIRECT3DVOLUMETEXTURE8 iface, CONST D3DBOX *pDirtyBox) { + IDirect3DVolumeTexture8Impl *This = (IDirect3DVolumeTexture8Impl *)iface; + HRESULT hr; + TRACE("(%p) Relay\n", This); + + EnterCriticalSection(&d3d8_cs); + hr = IWineD3DVolumeTexture_AddDirtyBox(This->wineD3DVolumeTexture, (CONST WINED3DBOX *) pDirtyBox); + LeaveCriticalSection(&d3d8_cs); + return hr; +} + + +const IDirect3DVolumeTexture8Vtbl Direct3DVolumeTexture8_Vtbl = +{ + /* IUnknown */ + IDirect3DVolumeTexture8Impl_QueryInterface, + IDirect3DVolumeTexture8Impl_AddRef, + IDirect3DVolumeTexture8Impl_Release, + /* IDirect3DResource8 */ + IDirect3DVolumeTexture8Impl_GetDevice, + IDirect3DVolumeTexture8Impl_SetPrivateData, + IDirect3DVolumeTexture8Impl_GetPrivateData, + IDirect3DVolumeTexture8Impl_FreePrivateData, + IDirect3DVolumeTexture8Impl_SetPriority, + IDirect3DVolumeTexture8Impl_GetPriority, + IDirect3DVolumeTexture8Impl_PreLoad, + IDirect3DVolumeTexture8Impl_GetType, + /* IDirect3DBaseTexture8 */ + IDirect3DVolumeTexture8Impl_SetLOD, + IDirect3DVolumeTexture8Impl_GetLOD, + IDirect3DVolumeTexture8Impl_GetLevelCount, + /* IDirect3DVolumeTexture8 */ + IDirect3DVolumeTexture8Impl_GetLevelDesc, + IDirect3DVolumeTexture8Impl_GetVolumeLevel, + IDirect3DVolumeTexture8Impl_LockBox, + IDirect3DVolumeTexture8Impl_UnlockBox, + IDirect3DVolumeTexture8Impl_AddDirtyBox +}; diff --git a/reactos/dll/directx/wine/readme.txt b/reactos/dll/directx/wine/readme.txt new file mode 100644 index 00000000000..2bb71f0b6b1 --- /dev/null +++ b/reactos/dll/directx/wine/readme.txt @@ -0,0 +1,21 @@ +This Is wine DirectX support. +It works in reactos and windows +When ReactOS own ReactX are inplace +this file will be remove from our SVN +for now they stay as tempary sovlotions + + +People that have help getting this thing +to working in ReactOS Building system + +Roderick Colenbrander - thunderbird2k at gmx dot net +The informations how to build it and done +the windows port in wine (wine devloper) + +Magnus Olsen aka GreatLord +Did import it to ReactOS and setupup +the build + +GedMurphy +Did help with minor issue, info how to +make DllMain being call diff --git a/reactos/dll/directx/wine/wine.rbuild b/reactos/dll/directx/wine/wine.rbuild new file mode 100644 index 00000000000..38152a88dba --- /dev/null +++ b/reactos/dll/directx/wine/wine.rbuild @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/reactos/dll/directx/wine/wined3d/Makefile.in b/reactos/dll/directx/wine/wined3d/Makefile.in new file mode 100644 index 00000000000..16587b3ba88 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/Makefile.in @@ -0,0 +1,42 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +MODULE = wined3d.dll +IMPORTLIB = libwined3d.$(IMPLIBEXT) +IMPORTS = user32 gdi32 advapi32 kernel32 +EXTRALIBS = -luuid + +C_SRCS = \ + arb_program_shader.c \ + baseshader.c \ + basetexture.c \ + clipper.c \ + context.c \ + cubetexture.c \ + device.c \ + directx.c \ + drawprim.c \ + glsl_shader.c \ + indexbuffer.c \ + palette.c \ + pixelshader.c \ + query.c \ + resource.c \ + state.c \ + stateblock.c \ + surface.c \ + surface_gdi.c \ + swapchain.c \ + texture.c \ + utils.c \ + vertexbuffer.c \ + vertexdeclaration.c \ + vertexshader.c \ + volume.c \ + volumetexture.c \ + wined3d_main.c + +@MAKE_DLL_RULES@ + +@DEPENDENCIES@ # everything below this line is overwritten by make depend diff --git a/reactos/dll/directx/wine/wined3d/arb_program_shader.c b/reactos/dll/directx/wine/wined3d/arb_program_shader.c new file mode 100644 index 00000000000..5cbadc2a528 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/arb_program_shader.c @@ -0,0 +1,1104 @@ +/* + * Pixel and vertex shaders implementation using ARB_vertex_program + * and ARB_fragment_program GL extensions. + * + * Copyright 2002-2003 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Ivan Gyurdiev + * Copyright 2006 Jason Green + * Copyright 2006 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include +#include + +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); +WINE_DECLARE_DEBUG_CHANNEL(d3d_constants); + +#define GLINFO_LOCATION (*gl_info) + +/******************************************************** + * ARB_[vertex/fragment]_program helper functions follow + ********************************************************/ + +/** + * Loads floating point constants into the currently set ARB_vertex/fragment_program. + * When constant_list == NULL, it will load all the constants. + * + * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders) + * or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders) + */ +static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, GLuint target_type, + unsigned int max_constants, float* constants, struct list *constant_list) { + constants_entry *constant; + local_constant* lconst; + DWORD i, j; + DWORD *idx; + + if (TRACE_ON(d3d_shader)) { + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + TRACE_(d3d_constants)("Loading constants %i: %f, %f, %f, %f\n", i, + constants[i * 4 + 0], constants[i * 4 + 1], + constants[i * 4 + 2], constants[i * 4 + 3]); + } + } + } + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4))); + } + } + checkGLcall("glProgramEnvParameter4fvARB()"); + + /* Load immediate constants */ + if (TRACE_ON(d3d_shader)) { + LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { + GLfloat* values = (GLfloat*)lconst->value; + TRACE_(d3d_constants)("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx, + values[0], values[1], values[2], values[3]); + } + } + LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { + GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value)); + } + checkGLcall("glProgramEnvParameter4fvARB()"); +} + +/** + * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs. + * + * We only support float constants in ARB at the moment, so don't + * worry about the Integers or Booleans + */ +void shader_arb_load_constants( + IWineD3DDevice* device, + char usePixelShader, + char useVertexShader) { + + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) device; + IWineD3DStateBlockImpl* stateBlock = deviceImpl->stateBlock; + WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info; + + if (useVertexShader) { + IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader; + + /* Load DirectX 9 float constants for vertex shader */ + shader_arb_load_constantsF(vshader, gl_info, GL_VERTEX_PROGRAM_ARB, + GL_LIMITS(vshader_constantsF), + stateBlock->vertexShaderConstantF, + &stateBlock->set_vconstantsF); + + /* Upload the position fixup */ + GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ARB_SHADER_PRIVCONST_POS, deviceImpl->posFixup)); + } + + if (usePixelShader) { + + IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader; + + /* Load DirectX 9 float constants for pixel shader */ + shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB, + GL_LIMITS(pshader_constantsF), + stateBlock->pixelShaderConstantF, + &stateBlock->set_pconstantsF); + if(((IWineD3DPixelShaderImpl *) pshader)->bumpenvmatconst) { + /* needsbumpmat stores the stage number from where to load the matrix. bumpenvmatconst stores the + * number of the constant to load the matrix into. + * The state manager takes care that this function is always called if the bump env matrix changes + */ + IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader; + float *data = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVMAT00]; + GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst, data)); + } + } +} + +/* Generate the variable & register declarations for the ARB_vertex_program output target */ +void shader_generate_arb_declarations( + IWineD3DBaseShader *iface, + shader_reg_maps* reg_maps, + SHADER_BUFFER* buffer, + WineD3D_GL_Info* gl_info) { + + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + DWORD i; + char pshader = shader_is_pshader_version(This->baseShader.hex_version); + unsigned max_constantsF = min(This->baseShader.limits.constant_float, + (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF))); + + /* Temporary Output register */ + shader_addline(buffer, "TEMP TMP_OUT;\n"); + + for(i = 0; i < This->baseShader.limits.temporary; i++) { + if (reg_maps->temporary[i]) + shader_addline(buffer, "TEMP R%u;\n", i); + } + + for (i = 0; i < This->baseShader.limits.address; i++) { + if (reg_maps->address[i]) + shader_addline(buffer, "ADDRESS A%d;\n", i); + } + + for(i = 0; i < This->baseShader.limits.texcoord; i++) { + if (reg_maps->texcoord[i]) + shader_addline(buffer,"TEMP T%u;\n", i); + } + + /* Texture coordinate registers must be pre-loaded */ + for (i = 0; i < This->baseShader.limits.texcoord; i++) { + if (reg_maps->texcoord[i]) + shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", i, i); + } + + if(reg_maps->bumpmat != -1 /* Only a pshader can use texbem */) { + /* If the shader does not use all available constants, use the next free constant to load the bump mapping environment matrix from + * the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying + * bump mapping. + */ + if(max_constantsF < GL_LIMITS(pshader_constantsF)) { + ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst = max_constantsF; + shader_addline(buffer, "PARAM bumpenvmat = program.env[%d];\n", ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst); + } else { + FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n"); + } + } + + /* Need to PARAM the environment parameters (constants) so we can use relative addressing */ + shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n", + max_constantsF, max_constantsF - 1); +} + +static const char * const shift_tab[] = { + "dummy", /* 0 (none) */ + "coefmul.x", /* 1 (x2) */ + "coefmul.y", /* 2 (x4) */ + "coefmul.z", /* 3 (x8) */ + "coefmul.w", /* 4 (x16) */ + "dummy", /* 5 (x32) */ + "dummy", /* 6 (x64) */ + "dummy", /* 7 (x128) */ + "dummy", /* 8 (d256) */ + "dummy", /* 9 (d128) */ + "dummy", /* 10 (d64) */ + "dummy", /* 11 (d32) */ + "coefdiv.w", /* 12 (d16) */ + "coefdiv.z", /* 13 (d8) */ + "coefdiv.y", /* 14 (d4) */ + "coefdiv.x" /* 15 (d2) */ +}; + +static void shader_arb_get_write_mask(const DWORD param, char *write_mask) { + char *ptr = write_mask; + + if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) { + *ptr++ = '.'; + if (param & WINED3DSP_WRITEMASK_0) *ptr++ = 'x'; + if (param & WINED3DSP_WRITEMASK_1) *ptr++ = 'y'; + if (param & WINED3DSP_WRITEMASK_2) *ptr++ = 'z'; + if (param & WINED3DSP_WRITEMASK_3) *ptr++ = 'w'; + } + + *ptr = '\0'; +} + +static void shader_arb_get_swizzle(const DWORD param, BOOL fixup, char *swizzle_str) { + /* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra", + * but addressed as "rgba". To fix this we need to swap the register's x + * and z components. */ + const char *swizzle_chars = fixup ? "zyxw" : "xyzw"; + char *ptr = swizzle_str; + + /* swizzle bits fields: wwzzyyxx */ + DWORD swizzle = (param & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT; + DWORD swizzle_x = swizzle & 0x03; + DWORD swizzle_y = (swizzle >> 2) & 0x03; + DWORD swizzle_z = (swizzle >> 4) & 0x03; + DWORD swizzle_w = (swizzle >> 6) & 0x03; + + /* If the swizzle is the default swizzle (ie, "xyzw"), we don't need to + * generate a swizzle string. Unless we need to our own swizzling. */ + if ((WINED3DSP_NOSWIZZLE >> WINED3DSP_SWIZZLE_SHIFT) != swizzle || fixup) { + *ptr++ = '.'; + if (swizzle_x == swizzle_y && swizzle_x == swizzle_z && swizzle_x == swizzle_w) { + *ptr++ = swizzle_chars[swizzle_x]; + } else { + *ptr++ = swizzle_chars[swizzle_x]; + *ptr++ = swizzle_chars[swizzle_y]; + *ptr++ = swizzle_chars[swizzle_z]; + *ptr++ = swizzle_chars[swizzle_w]; + } + } + + *ptr = '\0'; +} + +static void pshader_get_register_name( + const DWORD param, char* regstr) { + + DWORD reg = param & WINED3DSP_REGNUM_MASK; + DWORD regtype = shader_get_regtype(param); + + switch (regtype) { + case WINED3DSPR_TEMP: + sprintf(regstr, "R%u", reg); + break; + case WINED3DSPR_INPUT: + if (reg==0) { + strcpy(regstr, "fragment.color.primary"); + } else { + strcpy(regstr, "fragment.color.secondary"); + } + break; + case WINED3DSPR_CONST: + sprintf(regstr, "C[%u]", reg); + break; + case WINED3DSPR_TEXTURE: /* case WINED3DSPR_ADDR: */ + sprintf(regstr,"T%u", reg); + break; + case WINED3DSPR_COLOROUT: + if (reg == 0) + sprintf(regstr, "TMP_COLOR"); + else { + /* TODO: See GL_ARB_draw_buffers */ + FIXME("Unsupported write to render target %u\n", reg); + sprintf(regstr, "unsupported_register"); + } + break; + case WINED3DSPR_DEPTHOUT: + sprintf(regstr, "result.depth"); + break; + case WINED3DSPR_ATTROUT: + sprintf(regstr, "oD[%u]", reg); + break; + case WINED3DSPR_TEXCRDOUT: + sprintf(regstr, "oT[%u]", reg); + break; + default: + FIXME("Unhandled register name Type(%d)\n", regtype); + sprintf(regstr, "unrecognized_register"); + break; + } +} + +/* TODO: merge with pixel shader */ +static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, BOOL is_input, char *hwLine) { + + IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) arg->shader; + + /* oPos, oFog and oPts in D3D */ + static const char * const hwrastout_reg_names[] = { "TMP_OUT", "result.fogcoord", "result.pointsize" }; + + DWORD reg = param & WINED3DSP_REGNUM_MASK; + DWORD regtype = shader_get_regtype(param); + char tmpReg[255]; + BOOL is_color = FALSE; + + if ((param & WINED3DSP_SRCMOD_MASK) == WINED3DSPSM_NEG) { + strcat(hwLine, " -"); + } else { + strcat(hwLine, " "); + } + + switch (regtype) { + case WINED3DSPR_TEMP: + sprintf(tmpReg, "R%u", reg); + strcat(hwLine, tmpReg); + break; + case WINED3DSPR_INPUT: + + if (vshader_input_is_color((IWineD3DVertexShader*) This, reg)) + is_color = TRUE; + + sprintf(tmpReg, "vertex.attrib[%u]", reg); + strcat(hwLine, tmpReg); + break; + case WINED3DSPR_CONST: + sprintf(tmpReg, "C[%s%u]", (param & WINED3DSHADER_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg); + strcat(hwLine, tmpReg); + break; + case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/ + sprintf(tmpReg, "A%u", reg); + strcat(hwLine, tmpReg); + break; + case WINED3DSPR_RASTOUT: + sprintf(tmpReg, "%s", hwrastout_reg_names[reg]); + strcat(hwLine, tmpReg); + break; + case WINED3DSPR_ATTROUT: + if (reg==0) { + strcat(hwLine, "result.color.primary"); + } else { + strcat(hwLine, "result.color.secondary"); + } + break; + case WINED3DSPR_TEXCRDOUT: + sprintf(tmpReg, "result.texcoord[%u]", reg); + strcat(hwLine, tmpReg); + break; + default: + FIXME("Unknown reg type %d %d\n", regtype, reg); + strcat(hwLine, "unrecognized_register"); + break; + } + + if (!is_input) { + char write_mask[6]; + shader_arb_get_write_mask(param, write_mask); + strcat(hwLine, write_mask); + } else { + char swizzle[6]; + shader_arb_get_swizzle(param, is_color, swizzle); + strcat(hwLine, swizzle); + } +} + +static void shader_hw_sample(SHADER_OPCODE_ARG* arg, DWORD sampler_idx, const char *dst_str, const char *coord_reg, BOOL projective) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx]; + WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info; + + SHADER_BUFFER* buffer = arg->buffer; + DWORD sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; + const char *tex_type; + + switch(sampler_type) { + case WINED3DSTT_1D: + tex_type = "1D"; + break; + + case WINED3DSTT_2D: + tex_type = "2D"; + break; + + case WINED3DSTT_VOLUME: + tex_type = "3D"; + break; + + case WINED3DSTT_CUBE: + tex_type = "CUBE"; + break; + + default: + ERR("Unexpected texture type %d\n", sampler_type); + tex_type = ""; + } + + if (projective && deviceImpl->stateBlock->textureState[sampler_idx][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) { + shader_addline(buffer, "TXP %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type); + } else { + shader_addline(buffer, "TEX %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type); + } + + /* Signedness correction */ + if(!GL_SUPPORT(NV_TEXTURE_SHADER3) /* Provides signed formats */ && texture) { + WINED3DFORMAT format = texture->resource.format; + + if((format == WINED3DFMT_V8U8 && !GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) || + format == WINED3DFMT_Q8W8V8U8 || + format == WINED3DFMT_V16U16) { + shader_addline(buffer, "MAD %s, %s, coefmul.x, -one;\n", dst_str, dst_str); + } else if(format == WINED3DFMT_X8L8V8U8) { + shader_addline(buffer, "MAD %s.rg, %s, coefmul.x, -one;\n", dst_str, dst_str); + } + } +} + + +static void pshader_gen_input_modifier_line ( + SHADER_BUFFER* buffer, + const DWORD instr, + int tmpreg, + char *outregstr) { + + /* Generate a line that does the input modifier computation and return the input register to use */ + char regstr[256]; + char swzstr[20]; + int insert_line; + + /* Assume a new line will be added */ + insert_line = 1; + + /* Get register name */ + pshader_get_register_name(instr, regstr); + shader_arb_get_swizzle(instr, FALSE, swzstr); + + switch (instr & WINED3DSP_SRCMOD_MASK) { + case WINED3DSPSM_NONE: + sprintf(outregstr, "%s%s", regstr, swzstr); + insert_line = 0; + break; + case WINED3DSPSM_NEG: + sprintf(outregstr, "-%s%s", regstr, swzstr); + insert_line = 0; + break; + case WINED3DSPSM_BIAS: + shader_addline(buffer, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg, regstr); + break; + case WINED3DSPSM_BIASNEG: + shader_addline(buffer, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg, regstr); + break; + case WINED3DSPSM_SIGN: + shader_addline(buffer, "MAD T%c, %s, coefmul.x, -one.x;\n", 'A' + tmpreg, regstr); + break; + case WINED3DSPSM_SIGNNEG: + shader_addline(buffer, "MAD T%c, %s, -coefmul.x, one.x;\n", 'A' + tmpreg, regstr); + break; + case WINED3DSPSM_COMP: + shader_addline(buffer, "SUB T%c, one.x, %s;\n", 'A' + tmpreg, regstr); + break; + case WINED3DSPSM_X2: + shader_addline(buffer, "ADD T%c, %s, %s;\n", 'A' + tmpreg, regstr, regstr); + break; + case WINED3DSPSM_X2NEG: + shader_addline(buffer, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg, regstr, regstr); + break; + case WINED3DSPSM_DZ: + shader_addline(buffer, "RCP T%c, %s.z;\n", 'A' + tmpreg, regstr); + shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg); + break; + case WINED3DSPSM_DW: + shader_addline(buffer, "RCP T%c, %s.w;\n", 'A' + tmpreg, regstr); + shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg); + break; + default: + sprintf(outregstr, "%s%s", regstr, swzstr); + insert_line = 0; + } + + /* Return modified or original register, with swizzle */ + if (insert_line) + sprintf(outregstr, "T%c%s", 'A' + tmpreg, swzstr); +} + +static inline void pshader_gen_output_modifier_line( + SHADER_BUFFER* buffer, + int saturate, + char *write_mask, + int shift, + char *regstr) { + + /* Generate a line that does the output modifier computation */ + shader_addline(buffer, "MUL%s %s%s, %s, %s;\n", saturate ? "_SAT" : "", + regstr, write_mask, regstr, shift_tab[shift]); +} + +void pshader_hw_bem(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + + SHADER_BUFFER* buffer = arg->buffer; + char dst_name[50]; + char src_name[2][50]; + char dst_wmask[20]; + + pshader_get_register_name(arg->dst, dst_name); + shader_arb_get_write_mask(arg->dst, dst_wmask); + strcat(dst_name, dst_wmask); + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); + pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); + + if(This->bumpenvmatconst != -1) { + /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed */ + shader_addline(buffer, "SWZ TMP2, bumpenvmat, x, z, 0, 0;\n"); + shader_addline(buffer, "DP3 TMP.r, TMP2, %s;\n", src_name[1]); + shader_addline(buffer, "SWZ TMP2, bumpenvmat, y, w, 0, 0;\n"); + shader_addline(buffer, "DP3 TMP.g, TMP2, %s;\n", src_name[1]); + + shader_addline(buffer, "ADD %s, %s, TMP;\n", dst_name, src_name[0]); + } else { + shader_addline(buffer, "MOV %s, %s;\n", dst_name, src_name[0]); + } +} + +void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) { + + SHADER_BUFFER* buffer = arg->buffer; + char dst_wmask[20]; + char dst_name[50]; + char src_name[3][50]; + + /* FIXME: support output modifiers */ + + /* Handle output register */ + pshader_get_register_name(arg->dst, dst_name); + shader_arb_get_write_mask(arg->dst, dst_wmask); + strcat(dst_name, dst_wmask); + + /* Generate input register names (with modifiers) */ + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); + pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); + pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]); + + shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]); + shader_addline(buffer, "CMP %s, TMP, %s, %s;\n", dst_name, src_name[1], src_name[2]); +} + +void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) { + + SHADER_BUFFER* buffer = arg->buffer; + char dst_wmask[20]; + char dst_name[50]; + char src_name[3][50]; + + /* FIXME: support output modifiers */ + + /* Handle output register */ + pshader_get_register_name(arg->dst, dst_name); + shader_arb_get_write_mask(arg->dst, dst_wmask); + strcat(dst_name, dst_wmask); + + /* Generate input register names (with modifiers) */ + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]); + pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]); + pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]); + + shader_addline(buffer, "CMP %s, %s, %s, %s;\n", dst_name, + src_name[0], src_name[2], src_name[1]); +} + +/* Map the opcode 1-to-1 to the GL code */ +void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { + + CONST SHADER_OPCODE* curOpcode = arg->opcode; + SHADER_BUFFER* buffer = arg->buffer; + DWORD dst = arg->dst; + DWORD* src = arg->src; + + unsigned int i; + char tmpLine[256]; + + /* Output token related */ + char output_rname[256]; + char output_wmask[20]; + BOOL saturate = FALSE; + BOOL centroid = FALSE; + BOOL partialprecision = FALSE; + DWORD shift; + + strcpy(tmpLine, curOpcode->glname); + + /* Process modifiers */ + if (0 != (dst & WINED3DSP_DSTMOD_MASK)) { + DWORD mask = dst & WINED3DSP_DSTMOD_MASK; + + saturate = mask & WINED3DSPDM_SATURATE; + centroid = mask & WINED3DSPDM_MSAMPCENTROID; + partialprecision = mask & WINED3DSPDM_PARTIALPRECISION; + mask &= ~(WINED3DSPDM_MSAMPCENTROID | WINED3DSPDM_PARTIALPRECISION | WINED3DSPDM_SATURATE); + if (mask) + FIXME("Unrecognized modifier(%#x)\n", mask >> WINED3DSP_DSTMOD_SHIFT); + + if (centroid) + FIXME("Unhandled modifier(%#x)\n", mask >> WINED3DSP_DSTMOD_SHIFT); + } + shift = (dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + + /* Generate input and output registers */ + if (curOpcode->num_params > 0) { + char operands[4][100]; + + /* Generate input register names (with modifiers) */ + for (i = 1; i < curOpcode->num_params; ++i) + pshader_gen_input_modifier_line(buffer, src[i-1], i-1, operands[i]); + + /* Handle output register */ + pshader_get_register_name(dst, output_rname); + strcpy(operands[0], output_rname); + shader_arb_get_write_mask(dst, output_wmask); + strcat(operands[0], output_wmask); + + if (saturate && (shift == 0)) + strcat(tmpLine, "_SAT"); + strcat(tmpLine, " "); + strcat(tmpLine, operands[0]); + for (i = 1; i < curOpcode->num_params; i++) { + strcat(tmpLine, ", "); + strcat(tmpLine, operands[i]); + } + strcat(tmpLine,";\n"); + shader_addline(buffer, tmpLine); + + /* A shift requires another line. */ + if (shift != 0) + pshader_gen_output_modifier_line(buffer, saturate, output_wmask, shift, output_rname); + } +} + +void pshader_hw_tex(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + + DWORD dst = arg->dst; + DWORD* src = arg->src; + SHADER_BUFFER* buffer = arg->buffer; + DWORD hex_version = This->baseShader.hex_version; + + char reg_dest[40]; + char reg_coord[40]; + DWORD reg_dest_code; + DWORD reg_sampler_code; + + /* All versions have a destination register */ + reg_dest_code = dst & WINED3DSP_REGNUM_MASK; + pshader_get_register_name(dst, reg_dest); + + /* 1.0-1.3: Use destination register as coordinate source. + 1.4+: Use provided coordinate source register. */ + if (hex_version < WINED3DPS_VERSION(1,4)) + strcpy(reg_coord, reg_dest); + else + pshader_gen_input_modifier_line(buffer, src[0], 0, reg_coord); + + /* 1.0-1.4: Use destination register number as texture code. + 2.0+: Use provided sampler number as texure code. */ + if (hex_version < WINED3DPS_VERSION(2,0)) + reg_sampler_code = reg_dest_code; + else + reg_sampler_code = src[1] & WINED3DSP_REGNUM_MASK; + + shader_hw_sample(arg, reg_sampler_code, reg_dest, reg_coord, TRUE); +} + +void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD dst = arg->dst; + SHADER_BUFFER* buffer = arg->buffer; + DWORD hex_version = This->baseShader.hex_version; + + char tmp[20]; + shader_arb_get_write_mask(dst, tmp); + if (hex_version != WINED3DPS_VERSION(1,4)) { + DWORD reg = dst & WINED3DSP_REGNUM_MASK; + shader_addline(buffer, "MOV_SAT T%u%s, fragment.texcoord[%u];\n", reg, tmp, reg); + } else { + DWORD reg1 = dst & WINED3DSP_REGNUM_MASK; + char reg_src[40]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, reg_src); + shader_addline(buffer, "MOV R%u%s, %s;\n", reg1, tmp, reg_src); + } +} + +void pshader_hw_texreg2ar(SHADER_OPCODE_ARG* arg) { + + SHADER_BUFFER* buffer = arg->buffer; + + DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK; + char dst_str[8]; + + sprintf(dst_str, "T%u", reg1); + shader_addline(buffer, "MOV TMP.r, T%u.a;\n", reg2); + shader_addline(buffer, "MOV TMP.g, T%u.r;\n", reg2); + shader_hw_sample(arg, reg1, dst_str, "TMP", TRUE); +} + +void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) { + + SHADER_BUFFER* buffer = arg->buffer; + + DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK; + char dst_str[8]; + + sprintf(dst_str, "T%u", reg1); + shader_addline(buffer, "MOV TMP.r, T%u.g;\n", reg2); + shader_addline(buffer, "MOV TMP.g, T%u.b;\n", reg2); + shader_hw_sample(arg, reg1, dst_str, "TMP", TRUE); +} + +void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + + DWORD dst = arg->dst; + DWORD src = arg->src[0] & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + + char reg_coord[40]; + DWORD reg_dest_code; + + /* All versions have a destination register */ + reg_dest_code = dst & WINED3DSP_REGNUM_MASK; + /* Can directly use the name because texbem is only valid for <= 1.3 shaders */ + pshader_get_register_name(dst, reg_coord); + + if(This->bumpenvmatconst != -1) { + /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed */ + + shader_addline(buffer, "SWZ TMP2, bumpenvmat, x, z, 0, 0;\n"); + shader_addline(buffer, "DP3 TMP.r, TMP2, T%u;\n", src); + shader_addline(buffer, "SWZ TMP2, bumpenvmat, y, w, 0, 0;\n"); + shader_addline(buffer, "DP3 TMP.g, TMP2, T%u;\n", src); + + /* with projective textures, texbem only divides the static texture coord, not the displacement, + * so we can't let the GL handle this. + */ + if (((IWineD3DDeviceImpl*) This->baseShader.device)->stateBlock->textureState[reg_dest_code][WINED3DTSS_TEXTURETRANSFORMFLAGS] + & WINED3DTTFF_PROJECTED) { + shader_addline(buffer, "RCP TMP2.a, %s.a;\n", reg_coord); + shader_addline(buffer, "MUL TMP2.rg, %s, TMP2.a;\n", reg_coord); + shader_addline(buffer, "ADD TMP.rg, TMP, TMP2;\n"); + } else { + shader_addline(buffer, "ADD TMP.rg, TMP, %s;\n", reg_coord); + } + + shader_hw_sample(arg, reg_dest_code, reg_coord, "TMP", FALSE); + } else { + /* Without a bump matrix loaded, just sample with the unmodified coordinates */ + shader_hw_sample(arg, reg_dest_code, reg_coord, reg_coord, TRUE); + } +} + +void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) { + + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + char src0_name[50]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); + shader_addline(buffer, "DP3 TMP.x, T%u, %s;\n", reg, src0_name); +} + +void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg) { + + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + char dst_str[8]; + char src0_name[50]; + + sprintf(dst_str, "T%u", reg); + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); + shader_addline(buffer, "DP3 TMP.y, T%u, %s;\n", reg, src0_name); + shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); +} + +void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; + char src0_name[50]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); + shader_addline(buffer, "DP3 TMP.%c, T%u, %s;\n", 'x' + current_state->current_row, reg, src0_name); + current_state->texcoord_w[current_state->current_row++] = reg; +} + +void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; + char dst_str[8]; + char src0_name[50]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); + shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name); + + /* Sample the texture using the calculated coordinates */ + sprintf(dst_str, "T%u", reg); + shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + current_state->current_row = 0; +} + +void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; + char dst_str[8]; + char src0_name[50]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); + shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name); + + /* Construct the eye-ray vector from w coordinates */ + shader_addline(buffer, "MOV TMP2.x, fragment.texcoord[%u].w;\n", current_state->texcoord_w[0]); + shader_addline(buffer, "MOV TMP2.y, fragment.texcoord[%u].w;\n", current_state->texcoord_w[1]); + shader_addline(buffer, "MOV TMP2.z, fragment.texcoord[%u].w;\n", reg); + + /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */ + shader_addline(buffer, "DP3 TMP.w, TMP, TMP2;\n"); + shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n"); + shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -TMP2;\n"); + + /* Sample the texture using the calculated coordinates */ + sprintf(dst_str, "T%u", reg); + shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + current_state->current_row = 0; +} + +void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD reg3 = arg->src[1] & WINED3DSP_REGNUM_MASK; + SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; + SHADER_BUFFER* buffer = arg->buffer; + char dst_str[8]; + char src0_name[50]; + + pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name); + shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name); + + /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */ + shader_addline(buffer, "DP3 TMP.w, TMP, C[%u];\n", reg3); + shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n"); + shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -C[%u];\n", reg3); + + /* Sample the texture using the calculated coordinates */ + sprintf(dst_str, "T%u", reg); + shader_hw_sample(arg, reg, dst_str, "TMP", TRUE); + current_state->current_row = 0; +} + +/** Handles transforming all WINED3DSIO_M?x? opcodes for + Vertex shaders to ARB_vertex_program codes */ +void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg) { + + int i; + int nComponents = 0; + SHADER_OPCODE_ARG tmpArg; + + memset(&tmpArg, 0, sizeof(SHADER_OPCODE_ARG)); + + /* Set constants for the temporary argument */ + tmpArg.shader = arg->shader; + tmpArg.buffer = arg->buffer; + tmpArg.src[0] = arg->src[0]; + tmpArg.src_addr[0] = arg->src_addr[0]; + tmpArg.src_addr[1] = arg->src_addr[1]; + tmpArg.reg_maps = arg->reg_maps; + + switch(arg->opcode->opcode) { + case WINED3DSIO_M4x4: + nComponents = 4; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP4); + break; + case WINED3DSIO_M4x3: + nComponents = 3; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP4); + break; + case WINED3DSIO_M3x4: + nComponents = 4; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3); + break; + case WINED3DSIO_M3x3: + nComponents = 3; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3); + break; + case WINED3DSIO_M3x2: + nComponents = 2; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3); + break; + default: + break; + } + + for (i = 0; i < nComponents; i++) { + tmpArg.dst = ((arg->dst) & ~WINED3DSP_WRITEMASK_ALL)|(WINED3DSP_WRITEMASK_0<src[1]+i; + vshader_hw_map2gl(&tmpArg); + } +} + +void vshader_hw_rsq_rcp(SHADER_OPCODE_ARG* arg) { + CONST SHADER_OPCODE* curOpcode = arg->opcode; + SHADER_BUFFER* buffer = arg->buffer; + DWORD dst = arg->dst; + DWORD src = arg->src[0]; + DWORD swizzle = (src & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT; + + char tmpLine[256]; + + strcpy(tmpLine, curOpcode->glname); /* Opcode */ + vshader_program_add_param(arg, dst, FALSE, tmpLine); /* Destination */ + strcat(tmpLine, ","); + vshader_program_add_param(arg, src, TRUE, tmpLine); + if ((WINED3DSP_NOSWIZZLE >> WINED3DSP_SWIZZLE_SHIFT) == swizzle) { + /* Dx sdk says .x is used if no swizzle is given, but our test shows that + * .w is used + */ + strcat(tmpLine, ".w"); + } + + shader_addline(buffer, "%s;\n", tmpLine); +} + +/* TODO: merge with pixel shader */ +/* Map the opcode 1-to-1 to the GL code */ +void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { + + CONST SHADER_OPCODE* curOpcode = arg->opcode; + SHADER_BUFFER* buffer = arg->buffer; + DWORD dst = arg->dst; + DWORD* src = arg->src; + + DWORD dst_regtype = shader_get_regtype(dst); + char tmpLine[256]; + unsigned int i; + + if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) + strcpy(tmpLine, "ARL"); + else + strcpy(tmpLine, curOpcode->glname); + + if (curOpcode->num_params > 0) { + vshader_program_add_param(arg, dst, FALSE, tmpLine); + for (i = 1; i < curOpcode->num_params; ++i) { + strcat(tmpLine, ","); + vshader_program_add_param(arg, src[i-1], TRUE, tmpLine); + } + } + shader_addline(buffer, "%s;\n", tmpLine); +} + +static GLuint create_arb_blt_vertex_program(WineD3D_GL_Info *gl_info) { + GLuint program_id = 0; + const char *blt_vprogram = + "!!ARBvp1.0\n" + "PARAM c[1] = { { 1, 0.5 } };\n" + "MOV result.position, vertex.position;\n" + "MOV result.color, c[0].x;\n" + "MAD result.texcoord[0].y, -vertex.position, c[0], c[0];\n" + "MAD result.texcoord[0].x, vertex.position, c[0].y, c[0].y;\n" + "END\n"; + + GL_EXTCALL(glGenProgramsARB(1, &program_id)); + GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, program_id)); + GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_vprogram), blt_vprogram)); + + if (glGetError() == GL_INVALID_OPERATION) { + GLint pos; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); + FIXME("Vertex program error at position %d: %s\n", pos, + debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); + } + + return program_id; +} + +static GLuint create_arb_blt_fragment_program(WineD3D_GL_Info *gl_info) { + GLuint program_id = 0; + const char *blt_fprogram = + "!!ARBfp1.0\n" + "TEMP R0;\n" + "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n" + "MOV result.depth.z, R0.x;\n" + "END\n"; + + GL_EXTCALL(glGenProgramsARB(1, &program_id)); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id)); + GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_fprogram), blt_fprogram)); + + if (glGetError() == GL_INVALID_OPERATION) { + GLint pos; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos); + FIXME("Fragment program error at position %d: %s\n", pos, + debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); + } + + return program_id; +} + +static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + + if (useVS) { + TRACE("Using vertex shader\n"); + + /* Bind the vertex program */ + GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, + ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId)); + checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);"); + + /* Enable OpenGL vertex programs */ + glEnable(GL_VERTEX_PROGRAM_ARB); + checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);"); + TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n", + This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId); + } else if(GL_SUPPORT(ARB_VERTEX_PROGRAM)) { + glDisable(GL_VERTEX_PROGRAM_ARB); + checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)"); + } + + if (usePS) { + TRACE("Using pixel shader\n"); + + /* Bind the fragment program */ + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, + ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId)); + checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);"); + + /* Enable OpenGL fragment programs */ + glEnable(GL_FRAGMENT_PROGRAM_ARB); + checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);"); + TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n", + This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId); + } else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { + glDisable(GL_FRAGMENT_PROGRAM_ARB); + checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)"); + } +} + +static void shader_arb_select_depth_blt(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + static GLuint vprogram_id = 0; + static GLuint fprogram_id = 0; + + if (!vprogram_id) vprogram_id = create_arb_blt_vertex_program(gl_info); + GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vprogram_id)); + glEnable(GL_VERTEX_PROGRAM_ARB); + + if (!fprogram_id) fprogram_id = create_arb_blt_fragment_program(gl_info); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, fprogram_id)); + glEnable(GL_FRAGMENT_PROGRAM_ARB); +} + +static void shader_arb_cleanup(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + if (GL_SUPPORT(ARB_VERTEX_PROGRAM)) glDisable(GL_VERTEX_PROGRAM_ARB); + if (GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) glDisable(GL_FRAGMENT_PROGRAM_ARB); +} + +const shader_backend_t arb_program_shader_backend = { + &shader_arb_select, + &shader_arb_select_depth_blt, + &shader_arb_load_constants, + &shader_arb_cleanup +}; diff --git a/reactos/dll/directx/wine/wined3d/baseshader.c b/reactos/dll/directx/wine/wined3d/baseshader.c new file mode 100644 index 00000000000..8035abb0f40 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/baseshader.c @@ -0,0 +1,1018 @@ +/* + * shaders implementation + * + * Copyright 2002-2003 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Ivan Gyurdiev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#include +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); + +#define GLNAME_REQUIRE_GLSL ((const char *)1) + +static inline BOOL shader_is_version_token(DWORD token) { + return shader_is_pshader_version(token) || + shader_is_vshader_version(token); +} + +int shader_addline( + SHADER_BUFFER* buffer, + const char *format, ...) { + + char* base = buffer->buffer + buffer->bsize; + int rc; + + va_list args; + va_start(args, format); + rc = vsnprintf(base, SHADER_PGMSIZE - 1 - buffer->bsize, format, args); + va_end(args); + + if (rc < 0 || /* C89 */ + rc > SHADER_PGMSIZE - 1 - buffer->bsize) { /* C99 */ + + ERR("The buffer allocated for the shader program string " + "is too small at %d bytes.\n", SHADER_PGMSIZE); + buffer->bsize = SHADER_PGMSIZE - 1; + return -1; + } + + if (buffer->newline) { + TRACE("GL HW (%u, %u) : %s", buffer->lineNo + 1, buffer->bsize, base); + buffer->newline = FALSE; + } else { + TRACE("%s", base); + } + + buffer->bsize += rc; + if (buffer->buffer[buffer->bsize-1] == '\n') { + buffer->lineNo++; + buffer->newline = TRUE; + } + return 0; +} + +const SHADER_OPCODE* shader_get_opcode( + IWineD3DBaseShader *iface, const DWORD code) { + + IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl*) iface; + + DWORD i = 0; + DWORD hex_version = This->baseShader.hex_version; + const SHADER_OPCODE *shader_ins = This->baseShader.shader_ins; + + /** TODO: use dichotomic search */ + while (NULL != shader_ins[i].name) { + if (((code & WINED3DSI_OPCODE_MASK) == shader_ins[i].opcode) && + (((hex_version >= shader_ins[i].min_version) && (hex_version <= shader_ins[i].max_version)) || + ((shader_ins[i].min_version == 0) && (shader_ins[i].max_version == 0)))) { + return &shader_ins[i]; + } + ++i; + } + FIXME("Unsupported opcode %#x(%d) masked %#x, shader version %#x\n", + code, code, code & WINED3DSI_OPCODE_MASK, hex_version); + return NULL; +} + +/* Read a parameter opcode from the input stream, + * and possibly a relative addressing token. + * Return the number of tokens read */ +int shader_get_param( + IWineD3DBaseShader* iface, + const DWORD* pToken, + DWORD* param, + DWORD* addr_token) { + + /* PS >= 3.0 have relative addressing (with token) + * VS >= 2.0 have relative addressing (with token) + * VS >= 1.0 < 2.0 have relative addressing (without token) + * The version check below should work in general */ + + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + char rel_token = WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2 && + ((*pToken & WINED3DSHADER_ADDRESSMODE_MASK) == WINED3DSHADER_ADDRMODE_RELATIVE); + + *param = *pToken; + *addr_token = rel_token? *(pToken + 1): 0; + return rel_token? 2:1; +} + +/* Return the number of parameters to skip for an opcode */ +static inline int shader_skip_opcode( + IWineD3DBaseShaderImpl* This, + const SHADER_OPCODE* curOpcode, + DWORD opcode_token) { + + /* Shaders >= 2.0 may contain address tokens, but fortunately they + * have a useful legnth mask - use it here. Shaders 1.0 contain no such tokens */ + + return (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2)? + ((opcode_token & WINED3DSI_INSTLENGTH_MASK) >> WINED3DSI_INSTLENGTH_SHIFT): + curOpcode->num_params; +} + +/* Read the parameters of an unrecognized opcode from the input stream + * Return the number of tokens read. + * + * Note: This function assumes source or destination token format. + * It will not work with specially-formatted tokens like DEF or DCL, + * but hopefully those would be recognized */ + +int shader_skip_unrecognized( + IWineD3DBaseShader* iface, + const DWORD* pToken) { + + int tokens_read = 0; + int i = 0; + + /* TODO: Think of a good name for 0x80000000 and replace it with a constant */ + while (*pToken & 0x80000000) { + + DWORD param, addr_token; + tokens_read += shader_get_param(iface, pToken, ¶m, &addr_token); + pToken += tokens_read; + + FIXME("Unrecognized opcode param: token=%08x " + "addr_token=%08x name=", param, addr_token); + shader_dump_param(iface, param, addr_token, i); + FIXME("\n"); + ++i; + } + return tokens_read; +} + +/* Convert floating point offset relative + * to a register file to an absolute offset for float constants */ + +unsigned int shader_get_float_offset(const DWORD reg) { + + unsigned int regnum = reg & WINED3DSP_REGNUM_MASK; + int regtype = shader_get_regtype(reg); + + switch (regtype) { + case WINED3DSPR_CONST: return regnum; + case WINED3DSPR_CONST2: return 2048 + regnum; + case WINED3DSPR_CONST3: return 4096 + regnum; + case WINED3DSPR_CONST4: return 6144 + regnum; + default: + FIXME("Unsupported register type: %d\n", regtype); + return regnum; + } +} + +/* Note that this does not count the loop register + * as an address register. */ + +HRESULT shader_get_registers_used( + IWineD3DBaseShader *iface, + shader_reg_maps* reg_maps, + semantic* semantics_in, + semantic* semantics_out, + CONST DWORD* pToken, + IWineD3DStateBlockImpl *stateBlock) { + + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + + /* There are some minor differences between pixel and vertex shaders */ + char pshader = shader_is_pshader_version(This->baseShader.hex_version); + + reg_maps->bumpmat = -1; + + if (pToken == NULL) + return WINED3D_OK; + + while (WINED3DVS_END() != *pToken) { + CONST SHADER_OPCODE* curOpcode; + DWORD opcode_token; + + /* Skip version */ + if (shader_is_version_token(*pToken)) { + ++pToken; + continue; + + /* Skip comments */ + } else if (shader_is_comment(*pToken)) { + DWORD comment_len = (*pToken & WINED3DSI_COMMENTSIZE_MASK) >> WINED3DSI_COMMENTSIZE_SHIFT; + ++pToken; + pToken += comment_len; + continue; + } + + /* Fetch opcode */ + opcode_token = *pToken++; + curOpcode = shader_get_opcode(iface, opcode_token); + + /* Unhandled opcode, and its parameters */ + if (NULL == curOpcode) { + while (*pToken & 0x80000000) + ++pToken; + + /* Handle declarations */ + } else if (WINED3DSIO_DCL == curOpcode->opcode) { + + DWORD usage = *pToken++; + DWORD param = *pToken++; + DWORD regtype = shader_get_regtype(param); + unsigned int regnum = param & WINED3DSP_REGNUM_MASK; + + /* Vshader: mark attributes used + Pshader: mark 3.0 input registers used, save token */ + if (WINED3DSPR_INPUT == regtype) { + + if (!pshader) + reg_maps->attributes[regnum] = 1; + else + reg_maps->packed_input[regnum] = 1; + + semantics_in[regnum].usage = usage; + semantics_in[regnum].reg = param; + + /* Vshader: mark 3.0 output registers used, save token */ + } else if (WINED3DSPR_OUTPUT == regtype) { + reg_maps->packed_output[regnum] = 1; + semantics_out[regnum].usage = usage; + semantics_out[regnum].reg = param; + if (usage & (WINED3DDECLUSAGE_FOG << WINED3DSP_DCL_USAGE_SHIFT)) + reg_maps->fog = 1; + + /* Save sampler usage token */ + } else if (WINED3DSPR_SAMPLER == regtype) + reg_maps->samplers[regnum] = usage; + + } else if (WINED3DSIO_DEF == curOpcode->opcode) { + + local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant)); + if (!lconst) return E_OUTOFMEMORY; + lconst->idx = *pToken & WINED3DSP_REGNUM_MASK; + memcpy(&lconst->value, pToken + 1, 4 * sizeof(DWORD)); + list_add_head(&This->baseShader.constantsF, &lconst->entry); + pToken += curOpcode->num_params; + + } else if (WINED3DSIO_DEFI == curOpcode->opcode) { + + local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant)); + if (!lconst) return E_OUTOFMEMORY; + lconst->idx = *pToken & WINED3DSP_REGNUM_MASK; + memcpy(&lconst->value, pToken + 1, 4 * sizeof(DWORD)); + list_add_head(&This->baseShader.constantsI, &lconst->entry); + pToken += curOpcode->num_params; + + } else if (WINED3DSIO_DEFB == curOpcode->opcode) { + + local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant)); + if (!lconst) return E_OUTOFMEMORY; + lconst->idx = *pToken & WINED3DSP_REGNUM_MASK; + memcpy(&lconst->value, pToken + 1, 1 * sizeof(DWORD)); + list_add_head(&This->baseShader.constantsB, &lconst->entry); + pToken += curOpcode->num_params; + + /* If there's a loop in the shader */ + } else if (WINED3DSIO_LOOP == curOpcode->opcode || + WINED3DSIO_REP == curOpcode->opcode) { + reg_maps->loop = 1; + pToken += curOpcode->num_params; + + /* For subroutine prototypes */ + } else if (WINED3DSIO_LABEL == curOpcode->opcode) { + + DWORD snum = *pToken & WINED3DSP_REGNUM_MASK; + reg_maps->labels[snum] = 1; + pToken += curOpcode->num_params; + + } else if(WINED3DSIO_BEM == curOpcode->opcode) { + DWORD regnum = *pToken & WINED3DSP_REGNUM_MASK; + if(reg_maps->bumpmat != -1 && reg_maps->bumpmat != regnum) { + FIXME("Pixel shader uses bem or texbem instruction on more than 1 sampler\n"); + } else { + reg_maps->bumpmat = regnum; + } + + /* Set texture, address, temporary registers */ + } else { + int i, limit; + + /* Declare 1.X samplers implicitly, based on the destination reg. number */ + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 && + (WINED3DSIO_TEX == curOpcode->opcode || + WINED3DSIO_TEXBEM == curOpcode->opcode || + WINED3DSIO_TEXBEML == curOpcode->opcode || + WINED3DSIO_TEXDP3TEX == curOpcode->opcode || + WINED3DSIO_TEXM3x2TEX == curOpcode->opcode || + WINED3DSIO_TEXM3x3SPEC == curOpcode->opcode || + WINED3DSIO_TEXM3x3TEX == curOpcode->opcode || + WINED3DSIO_TEXM3x3VSPEC == curOpcode->opcode || + WINED3DSIO_TEXREG2AR == curOpcode->opcode || + WINED3DSIO_TEXREG2GB == curOpcode->opcode || + WINED3DSIO_TEXREG2RGB == curOpcode->opcode)) { + + /* Fake sampler usage, only set reserved bit and ttype */ + DWORD sampler_code = *pToken & WINED3DSP_REGNUM_MASK; + + if(!stateBlock->textures[sampler_code]) { + ERR("No texture bound to sampler %d\n", sampler_code); + reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D; + } else { + int texType = IWineD3DBaseTexture_GetTextureDimensions(stateBlock->textures[sampler_code]); + switch(texType) { + case GL_TEXTURE_2D: + reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D; + break; + + case GL_TEXTURE_3D: + reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_VOLUME; + break; + + case GL_TEXTURE_CUBE_MAP_ARB: + reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_CUBE; + break; + + default: + ERR("Unexpected gl texture type found: %d\n", texType); + reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D; + } + } + + /* texbem is only valid with < 1.4 pixel shaders */ + if(WINED3DSIO_TEXBEM == curOpcode->opcode) { + if(reg_maps->bumpmat != -1 && reg_maps->bumpmat != sampler_code) { + FIXME("Pixel shader uses texbem instruction on more than 1 sampler\n"); + } else { + reg_maps->bumpmat = sampler_code; + } + } + } + + /* This will loop over all the registers and try to + * make a bitmask of the ones we're interested in. + * + * Relative addressing tokens are ignored, but that's + * okay, since we'll catch any address registers when + * they are initialized (required by spec) */ + + limit = (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED)? + curOpcode->num_params + 1: curOpcode->num_params; + + for (i = 0; i < limit; ++i) { + + DWORD param, addr_token, reg, regtype; + pToken += shader_get_param(iface, pToken, ¶m, &addr_token); + + regtype = shader_get_regtype(param); + reg = param & WINED3DSP_REGNUM_MASK; + + if (WINED3DSPR_TEXTURE == regtype) { /* vs: WINED3DSPR_ADDR */ + + if (pshader) + reg_maps->texcoord[reg] = 1; + else + reg_maps->address[reg] = 1; + } + + else if (WINED3DSPR_TEMP == regtype) + reg_maps->temporary[reg] = 1; + + else if (WINED3DSPR_INPUT == regtype && !pshader) + reg_maps->attributes[reg] = 1; + + else if (WINED3DSPR_RASTOUT == regtype && reg == 1) + reg_maps->fog = 1; + } + } + } + + return WINED3D_OK; +} + +static void shader_dump_decl_usage( + IWineD3DBaseShaderImpl* This, + DWORD decl, + DWORD param) { + + DWORD regtype = shader_get_regtype(param); + + TRACE("dcl"); + + if (regtype == WINED3DSPR_SAMPLER) { + DWORD ttype = decl & WINED3DSP_TEXTURETYPE_MASK; + + switch (ttype) { + case WINED3DSTT_2D: TRACE("_2d"); break; + case WINED3DSTT_CUBE: TRACE("_cube"); break; + case WINED3DSTT_VOLUME: TRACE("_volume"); break; + default: TRACE("_unknown_ttype(%08x)", ttype); + } + + } else { + + DWORD usage = decl & WINED3DSP_DCL_USAGE_MASK; + DWORD idx = (decl & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + + /* Pixel shaders 3.0 don't have usage semantics */ + char pshader = shader_is_pshader_version(This->baseShader.hex_version); + if (pshader && This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) + return; + else + TRACE("_"); + + switch(usage) { + case WINED3DDECLUSAGE_POSITION: + TRACE("position%d", idx); + break; + case WINED3DDECLUSAGE_BLENDINDICES: + TRACE("blend"); + break; + case WINED3DDECLUSAGE_BLENDWEIGHT: + TRACE("weight"); + break; + case WINED3DDECLUSAGE_NORMAL: + TRACE("normal%d", idx); + break; + case WINED3DDECLUSAGE_PSIZE: + TRACE("psize"); + break; + case WINED3DDECLUSAGE_COLOR: + if(idx == 0) { + TRACE("color"); + } else { + TRACE("specular%d", (idx - 1)); + } + break; + case WINED3DDECLUSAGE_TEXCOORD: + TRACE("texture%d", idx); + break; + case WINED3DDECLUSAGE_TANGENT: + TRACE("tangent"); + break; + case WINED3DDECLUSAGE_BINORMAL: + TRACE("binormal"); + break; + case WINED3DDECLUSAGE_TESSFACTOR: + TRACE("tessfactor"); + break; + case WINED3DDECLUSAGE_POSITIONT: + TRACE("positionT%d", idx); + break; + case WINED3DDECLUSAGE_FOG: + TRACE("fog"); + break; + case WINED3DDECLUSAGE_DEPTH: + TRACE("depth"); + break; + case WINED3DDECLUSAGE_SAMPLE: + TRACE("sample"); + break; + default: + FIXME("unknown_semantics(%08x)", usage); + } + } +} + +static void shader_dump_arr_entry( + IWineD3DBaseShader *iface, + const DWORD param, + const DWORD addr_token, + unsigned int reg, + int input) { + + char relative = + ((param & WINED3DSHADER_ADDRESSMODE_MASK) == WINED3DSHADER_ADDRMODE_RELATIVE); + + if (relative) { + TRACE("["); + if (addr_token) + shader_dump_param(iface, addr_token, 0, input); + else + TRACE("a0.x"); + TRACE(" + "); + } + TRACE("%u", reg); + if (relative) + TRACE("]"); +} + +void shader_dump_param( + IWineD3DBaseShader *iface, + const DWORD param, + const DWORD addr_token, + int input) { + + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + static const char * const rastout_reg_names[] = { "oPos", "oFog", "oPts" }; + static const char * const misctype_reg_names[] = { "vPos", "vFace"}; + char swizzle_reg_chars[4]; + + DWORD reg = param & WINED3DSP_REGNUM_MASK; + DWORD regtype = shader_get_regtype(param); + DWORD modifier = param & WINED3DSP_SRCMOD_MASK; + + /* There are some minor differences between pixel and vertex shaders */ + char pshader = shader_is_pshader_version(This->baseShader.hex_version); + + /* For one, we'd prefer color components to be shown for pshaders. + * FIXME: use the swizzle function for this */ + + swizzle_reg_chars[0] = pshader? 'r': 'x'; + swizzle_reg_chars[1] = pshader? 'g': 'y'; + swizzle_reg_chars[2] = pshader? 'b': 'z'; + swizzle_reg_chars[3] = pshader? 'a': 'w'; + + if (input) { + if ( (modifier == WINED3DSPSM_NEG) || + (modifier == WINED3DSPSM_BIASNEG) || + (modifier == WINED3DSPSM_SIGNNEG) || + (modifier == WINED3DSPSM_X2NEG) || + (modifier == WINED3DSPSM_ABSNEG) ) + TRACE("-"); + else if (modifier == WINED3DSPSM_COMP) + TRACE("1-"); + else if (modifier == WINED3DSPSM_NOT) + TRACE("!"); + + if (modifier == WINED3DSPSM_ABS || modifier == WINED3DSPSM_ABSNEG) + TRACE("abs("); + } + + switch (regtype) { + case WINED3DSPR_TEMP: + TRACE("r%u", reg); + break; + case WINED3DSPR_INPUT: + TRACE("v"); + shader_dump_arr_entry(iface, param, addr_token, reg, input); + break; + case WINED3DSPR_CONST: + case WINED3DSPR_CONST2: + case WINED3DSPR_CONST3: + case WINED3DSPR_CONST4: + TRACE("c"); + shader_dump_arr_entry(iface, param, addr_token, shader_get_float_offset(param), input); + break; + case WINED3DSPR_TEXTURE: /* vs: case D3DSPR_ADDR */ + TRACE("%c%u", (pshader? 't':'a'), reg); + break; + case WINED3DSPR_RASTOUT: + TRACE("%s", rastout_reg_names[reg]); + break; + case WINED3DSPR_COLOROUT: + TRACE("oC%u", reg); + break; + case WINED3DSPR_DEPTHOUT: + TRACE("oDepth"); + break; + case WINED3DSPR_ATTROUT: + TRACE("oD%u", reg); + break; + case WINED3DSPR_TEXCRDOUT: + + /* Vertex shaders >= 3.0 use general purpose output registers + * (WINED3DSPR_OUTPUT), which can include an address token */ + + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) { + TRACE("o"); + shader_dump_arr_entry(iface, param, addr_token, reg, input); + } + else + TRACE("oT%u", reg); + break; + case WINED3DSPR_CONSTINT: + TRACE("i"); + shader_dump_arr_entry(iface, param, addr_token, reg, input); + break; + case WINED3DSPR_CONSTBOOL: + TRACE("b"); + shader_dump_arr_entry(iface, param, addr_token, reg, input); + break; + case WINED3DSPR_LABEL: + TRACE("l%u", reg); + break; + case WINED3DSPR_LOOP: + TRACE("aL"); + break; + case WINED3DSPR_SAMPLER: + TRACE("s%u", reg); + break; + case WINED3DSPR_MISCTYPE: + if (reg > 1) { + FIXME("Unhandled misctype register %d\n", reg); + } else { + TRACE("%s", misctype_reg_names[reg]); + } + break; + case WINED3DSPR_PREDICATE: + TRACE("p%u", reg); + break; + default: + TRACE("unhandled_rtype(%#x)", regtype); + break; + } + + if (!input) { + /* operand output (for modifiers and shift, see dump_ins_modifiers) */ + + if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) { + TRACE("."); + if (param & WINED3DSP_WRITEMASK_0) TRACE("%c", swizzle_reg_chars[0]); + if (param & WINED3DSP_WRITEMASK_1) TRACE("%c", swizzle_reg_chars[1]); + if (param & WINED3DSP_WRITEMASK_2) TRACE("%c", swizzle_reg_chars[2]); + if (param & WINED3DSP_WRITEMASK_3) TRACE("%c", swizzle_reg_chars[3]); + } + + } else { + /** operand input */ + DWORD swizzle = (param & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT; + DWORD swizzle_r = swizzle & 0x03; + DWORD swizzle_g = (swizzle >> 2) & 0x03; + DWORD swizzle_b = (swizzle >> 4) & 0x03; + DWORD swizzle_a = (swizzle >> 6) & 0x03; + + if (0 != modifier) { + switch (modifier) { + case WINED3DSPSM_NONE: break; + case WINED3DSPSM_NEG: break; + case WINED3DSPSM_NOT: break; + case WINED3DSPSM_BIAS: TRACE("_bias"); break; + case WINED3DSPSM_BIASNEG: TRACE("_bias"); break; + case WINED3DSPSM_SIGN: TRACE("_bx2"); break; + case WINED3DSPSM_SIGNNEG: TRACE("_bx2"); break; + case WINED3DSPSM_COMP: break; + case WINED3DSPSM_X2: TRACE("_x2"); break; + case WINED3DSPSM_X2NEG: TRACE("_x2"); break; + case WINED3DSPSM_DZ: TRACE("_dz"); break; + case WINED3DSPSM_DW: TRACE("_dw"); break; + case WINED3DSPSM_ABSNEG: TRACE(")"); break; + case WINED3DSPSM_ABS: TRACE(")"); break; + default: + TRACE("_unknown_modifier(%#x)", modifier >> WINED3DSP_SRCMOD_SHIFT); + } + } + + /** + * swizzle bits fields: + * RRGGBBAA + */ + if ((WINED3DVS_NOSWIZZLE >> WINED3DVS_SWIZZLE_SHIFT) != swizzle) { + if (swizzle_r == swizzle_g && + swizzle_r == swizzle_b && + swizzle_r == swizzle_a) { + TRACE(".%c", swizzle_reg_chars[swizzle_r]); + } else { + TRACE(".%c%c%c%c", + swizzle_reg_chars[swizzle_r], + swizzle_reg_chars[swizzle_g], + swizzle_reg_chars[swizzle_b], + swizzle_reg_chars[swizzle_a]); + } + } + } +} + +/** Shared code in order to generate the bulk of the shader string. + Use the shader_header_fct & shader_footer_fct to add strings + that are specific to pixel or vertex functions + NOTE: A description of how to parse tokens can be found at: + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/graphics/hh/graphics/usermodedisplaydriver_shader_cc8e4e05-f5c3-4ec0-8853-8ce07c1551b2.xml.asp */ +void shader_generate_main( + IWineD3DBaseShader *iface, + SHADER_BUFFER* buffer, + shader_reg_maps* reg_maps, + CONST DWORD* pFunction) { + + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + const DWORD *pToken = pFunction; + const SHADER_OPCODE *curOpcode = NULL; + SHADER_HANDLER hw_fct = NULL; + DWORD i; + SHADER_OPCODE_ARG hw_arg; + + /* Initialize current parsing state */ + hw_arg.shader = iface; + hw_arg.buffer = buffer; + hw_arg.reg_maps = reg_maps; + This->baseShader.parse_state.current_row = 0; + + /* Second pass, process opcodes */ + if (NULL != pToken) { + while (WINED3DPS_END() != *pToken) { + + /* Skip version token */ + if (shader_is_version_token(*pToken)) { + ++pToken; + continue; + } + + /* Skip comment tokens */ + if (shader_is_comment(*pToken)) { + DWORD comment_len = (*pToken & WINED3DSI_COMMENTSIZE_MASK) >> WINED3DSI_COMMENTSIZE_SHIFT; + ++pToken; + TRACE("#%s\n", (const char*)pToken); + pToken += comment_len; + continue; + } + + /* Read opcode */ + hw_arg.opcode_token = *pToken++; + curOpcode = shader_get_opcode(iface, hw_arg.opcode_token); + + /* Select handler */ + if (curOpcode == NULL) + hw_fct = NULL; + else if (This->baseShader.shader_mode == SHADER_GLSL) + hw_fct = curOpcode->hw_glsl_fct; + else if (This->baseShader.shader_mode == SHADER_ARB) + hw_fct = curOpcode->hw_fct; + + /* Unknown opcode and its parameters */ + if (NULL == curOpcode) { + FIXME("Unrecognized opcode: token=%08x\n", hw_arg.opcode_token); + pToken += shader_skip_unrecognized(iface, pToken); + + /* Nothing to do */ + } else if (WINED3DSIO_DCL == curOpcode->opcode || + WINED3DSIO_NOP == curOpcode->opcode || + WINED3DSIO_DEF == curOpcode->opcode || + WINED3DSIO_DEFI == curOpcode->opcode || + WINED3DSIO_DEFB == curOpcode->opcode || + WINED3DSIO_PHASE == curOpcode->opcode || + WINED3DSIO_RET == curOpcode->opcode) { + + pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token); + + /* If a generator function is set for current shader target, use it */ + } else if (hw_fct != NULL) { + + hw_arg.opcode = curOpcode; + + /* Destination token */ + if (curOpcode->dst_token) { + + DWORD param, addr_token = 0; + pToken += shader_get_param(iface, pToken, ¶m, &addr_token); + hw_arg.dst = param; + hw_arg.dst_addr = addr_token; + } + + /* Predication token */ + if (hw_arg.opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED) + hw_arg.predicate = *pToken++; + + /* Other source tokens */ + for (i = 0; i < (curOpcode->num_params - curOpcode->dst_token); i++) { + + DWORD param, addr_token = 0; + pToken += shader_get_param(iface, pToken, ¶m, &addr_token); + hw_arg.src[i] = param; + hw_arg.src_addr[i] = addr_token; + } + + /* Call appropriate function for output target */ + hw_fct(&hw_arg); + + /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */ + if (This->baseShader.shader_mode == SHADER_GLSL) + shader_glsl_add_instruction_modifiers(&hw_arg); + + /* Unhandled opcode */ + } else { + + FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name); + pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token); + } + } + /* TODO: What about result.depth? */ + + } +} + +void shader_dump_ins_modifiers(const DWORD output) { + + DWORD shift = (output & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + DWORD mmask = output & WINED3DSP_DSTMOD_MASK; + + switch (shift) { + case 0: break; + case 13: TRACE("_d8"); break; + case 14: TRACE("_d4"); break; + case 15: TRACE("_d2"); break; + case 1: TRACE("_x2"); break; + case 2: TRACE("_x4"); break; + case 3: TRACE("_x8"); break; + default: TRACE("_unhandled_shift(%d)", shift); break; + } + + if (mmask & WINED3DSPDM_SATURATE) TRACE("_sat"); + if (mmask & WINED3DSPDM_PARTIALPRECISION) TRACE("_pp"); + if (mmask & WINED3DSPDM_MSAMPCENTROID) TRACE("_centroid"); + + mmask &= ~(WINED3DSPDM_SATURATE | WINED3DSPDM_PARTIALPRECISION | WINED3DSPDM_MSAMPCENTROID); + if (mmask) + FIXME("_unrecognized_modifier(%#x)", mmask >> WINED3DSP_DSTMOD_SHIFT); +} + +/* First pass: trace shader, initialize length and version */ +void shader_trace_init( + IWineD3DBaseShader *iface, + const DWORD* pFunction) { + + IWineD3DBaseShaderImpl *This =(IWineD3DBaseShaderImpl *)iface; + + const DWORD* pToken = pFunction; + const SHADER_OPCODE* curOpcode = NULL; + DWORD opcode_token; + unsigned int len = 0; + DWORD i; + + TRACE("(%p) : Parsing programme\n", This); + + if (NULL != pToken) { + while (WINED3DVS_END() != *pToken) { + if (shader_is_version_token(*pToken)) { /** version */ + This->baseShader.hex_version = *pToken; + TRACE("%s_%u_%u\n", shader_is_pshader_version(This->baseShader.hex_version)? "ps": "vs", + WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version), + WINED3DSHADER_VERSION_MINOR(This->baseShader.hex_version)); + ++pToken; + ++len; + continue; + } + if (shader_is_comment(*pToken)) { /** comment */ + DWORD comment_len = (*pToken & WINED3DSI_COMMENTSIZE_MASK) >> WINED3DSI_COMMENTSIZE_SHIFT; + ++pToken; + TRACE("//%s\n", (const char*)pToken); + pToken += comment_len; + len += comment_len + 1; + continue; + } + opcode_token = *pToken++; + curOpcode = shader_get_opcode(iface, opcode_token); + len++; + + if (NULL == curOpcode) { + int tokens_read; + FIXME("Unrecognized opcode: token=%08x\n", opcode_token); + tokens_read = shader_skip_unrecognized(iface, pToken); + pToken += tokens_read; + len += tokens_read; + + } else { + if (curOpcode->opcode == WINED3DSIO_DCL) { + + DWORD usage = *pToken; + DWORD param = *(pToken + 1); + + shader_dump_decl_usage(This, usage, param); + shader_dump_ins_modifiers(param); + TRACE(" "); + shader_dump_param(iface, param, 0, 0); + pToken += 2; + len += 2; + + } else if (curOpcode->opcode == WINED3DSIO_DEF) { + + unsigned int offset = shader_get_float_offset(*pToken); + + TRACE("def c%u = %f, %f, %f, %f", offset, + *(const float *)(pToken + 1), + *(const float *)(pToken + 2), + *(const float *)(pToken + 3), + *(const float *)(pToken + 4)); + + pToken += 5; + len += 5; + } else if (curOpcode->opcode == WINED3DSIO_DEFI) { + + TRACE("defi i%u = %d, %d, %d, %d", *pToken & WINED3DSP_REGNUM_MASK, + *(pToken + 1), + *(pToken + 2), + *(pToken + 3), + *(pToken + 4)); + + pToken += 5; + len += 5; + + } else if (curOpcode->opcode == WINED3DSIO_DEFB) { + + TRACE("defb b%u = %s", *pToken & WINED3DSP_REGNUM_MASK, + *(pToken + 1)? "true": "false"); + + pToken += 2; + len += 2; + + } else { + + DWORD param, addr_token; + int tokens_read; + + /* Print out predication source token first - it follows + * the destination token. */ + if (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED) { + TRACE("("); + shader_dump_param(iface, *(pToken + 2), 0, 1); + TRACE(") "); + } + + TRACE("%s", curOpcode->name); + + if (curOpcode->opcode == WINED3DSIO_IFC || + curOpcode->opcode == WINED3DSIO_BREAKC) { + + DWORD op = (opcode_token & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT; + switch (op) { + case COMPARISON_GT: TRACE("_gt"); break; + case COMPARISON_EQ: TRACE("_eq"); break; + case COMPARISON_GE: TRACE("_ge"); break; + case COMPARISON_LT: TRACE("_lt"); break; + case COMPARISON_NE: TRACE("_ne"); break; + case COMPARISON_LE: TRACE("_le"); break; + default: + TRACE("_(%u)", op); + } + } else if (curOpcode->opcode == WINED3DSIO_TEX && + This->baseShader.hex_version >= WINED3DPS_VERSION(2,0)) { + if(opcode_token & WINED3DSI_TEXLD_PROJECT) TRACE("p"); + } + + /* Destination token */ + if (curOpcode->dst_token) { + + /* Destination token */ + tokens_read = shader_get_param(iface, pToken, ¶m, &addr_token); + pToken += tokens_read; + len += tokens_read; + + shader_dump_ins_modifiers(param); + TRACE(" "); + shader_dump_param(iface, param, addr_token, 0); + } + + /* Predication token - already printed out, just skip it */ + if (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED) { + pToken++; + len++; + } + + /* Other source tokens */ + for (i = curOpcode->dst_token; i < curOpcode->num_params; ++i) { + + tokens_read = shader_get_param(iface, pToken, ¶m, &addr_token); + pToken += tokens_read; + len += tokens_read; + + TRACE((i == 0)? " " : ", "); + shader_dump_param(iface, param, addr_token, 1); + } + } + TRACE("\n"); + } + } + This->baseShader.functionLength = (len + 1) * sizeof(DWORD); + } else { + This->baseShader.functionLength = 1; /* no Function defined use fixed function vertex processing */ + } +} + +void shader_delete_constant_list( + struct list* clist) { + + struct list *ptr; + struct local_constant* constant; + + ptr = list_head(clist); + while (ptr) { + constant = LIST_ENTRY(ptr, struct local_constant, entry); + ptr = list_next(clist, ptr); + HeapFree(GetProcessHeap(), 0, constant); + } +} + +static void shader_none_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {} +static void shader_none_select_depth_blt(IWineD3DDevice *iface) {} +static void shader_none_load_constants(IWineD3DDevice *iface, char usePS, char useVS) {} +static void shader_none_cleanup(IWineD3DDevice *iface) {} + +const shader_backend_t none_shader_backend = { + &shader_none_select, + &shader_none_select_depth_blt, + &shader_none_load_constants, + &shader_none_cleanup +}; diff --git a/reactos/dll/directx/wine/wined3d/basetexture.c b/reactos/dll/directx/wine/wined3d/basetexture.c new file mode 100644 index 00000000000..8df0b3e8bc3 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/basetexture.c @@ -0,0 +1,465 @@ +/* + * IWineD3DBaseTexture Implementation + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2002-2004 Raphael Junqueira + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +/* ******************************************* + IWineD3DBaseTexture IUnknown parts follow + ******************************************* */ +HRESULT WINAPI IWineD3DBaseTextureImpl_QueryInterface(IWineD3DBaseTexture *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DBaseTexture)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI IWineD3DBaseTextureImpl_AddRef(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + ULONG ref = InterlockedIncrement(&This->resource.ref); + + TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1); + return ref; +} + +ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + ULONG ref = InterlockedDecrement(&This->resource.ref); + TRACE("(%p) : Releasing from %d\n", This, ref + 1); + if (ref == 0) { + IWineD3DBaseTextureImpl_CleanUp(iface); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* class static */ +void IWineD3DBaseTextureImpl_CleanUp(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + TRACE("(%p) : textureName(%d)\n", This, This->baseTexture.textureName); + if (This->baseTexture.textureName != 0) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + TRACE("(%p) : Deleting texture %d\n", This, This->baseTexture.textureName); + glDeleteTextures(1, &This->baseTexture.textureName); + LEAVE_GL(); + } + IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface); +} + +/* **************************************************** + IWineD3DBaseTexture IWineD3DResource parts follow + **************************************************** */ +HRESULT WINAPI IWineD3DBaseTextureImpl_GetDevice(IWineD3DBaseTexture *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_SetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_GetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_FreePrivateData(IWineD3DBaseTexture *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +DWORD WINAPI IWineD3DBaseTextureImpl_SetPriority(IWineD3DBaseTexture *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +DWORD WINAPI IWineD3DBaseTextureImpl_GetPriority(IWineD3DBaseTexture *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +void WINAPI IWineD3DBaseTextureImpl_PreLoad(IWineD3DBaseTexture *iface) { + IWineD3DResourceImpl_PreLoad((IWineD3DResource *)iface); +} + +WINED3DRESOURCETYPE WINAPI IWineD3DBaseTextureImpl_GetType(IWineD3DBaseTexture *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_GetParent(IWineD3DBaseTexture *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DBaseTexture IWineD3DBaseTexture parts follow + ****************************************************** */ + +/* There is no OpenGL equivilent of setLOD, getLOD, all they do it priortise testure loading + * so just pretend that they work unless something really needs a failure. */ +DWORD WINAPI IWineD3DBaseTextureImpl_SetLOD(IWineD3DBaseTexture *iface, DWORD LODNew) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + + if (This->resource.pool != WINED3DPOOL_MANAGED) { + return WINED3DERR_INVALIDCALL; + } + + if(LODNew >= This->baseTexture.levels) + LODNew = This->baseTexture.levels - 1; + This->baseTexture.LOD = LODNew; + + TRACE("(%p) : set bogus LOD to %d\n", This, This->baseTexture.LOD); + + return This->baseTexture.LOD; +} + +DWORD WINAPI IWineD3DBaseTextureImpl_GetLOD(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + + if (This->resource.pool != WINED3DPOOL_MANAGED) { + return WINED3DERR_INVALIDCALL; + } + + TRACE("(%p) : returning %d\n", This, This->baseTexture.LOD); + + return This->baseTexture.LOD; +} + +DWORD WINAPI IWineD3DBaseTextureImpl_GetLevelCount(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + TRACE("(%p) : returning %d\n", This, This->baseTexture.levels); + return This->baseTexture.levels; +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_SetAutoGenFilterType(IWineD3DBaseTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + + if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) { + TRACE("(%p) : returning invalid call\n", This); + return WINED3DERR_INVALIDCALL; + } + This->baseTexture.filterType = FilterType; + TRACE("(%p) :\n", This); + return WINED3D_OK; +} + +WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DBaseTextureImpl_GetAutoGenFilterType(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + FIXME("(%p) : stub\n", This); + if (!(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP)) { + return WINED3DTEXF_NONE; + } + return This->baseTexture.filterType; +} + +void WINAPI IWineD3DBaseTextureImpl_GenerateMipSubLevels(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + /* TODO: implement filters using GL_SGI_generate_mipmaps http://oss.sgi.com/projects/ogl-sample/registry/SGIS/generate_mipmap.txt */ + FIXME("(%p) : stub\n", This); + return ; +} + +/* Internal function, No d3d mapping */ +BOOL WINAPI IWineD3DBaseTextureImpl_SetDirty(IWineD3DBaseTexture *iface, BOOL dirty) { + BOOL old; + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + old = This->baseTexture.dirty; + This->baseTexture.dirty = dirty; + return old; +} + +BOOL WINAPI IWineD3DBaseTextureImpl_GetDirty(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + return This->baseTexture.dirty; +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + HRESULT hr = WINED3D_OK; + UINT textureDimensions; + BOOL isNewTexture = FALSE; + TRACE("(%p) : About to bind texture\n", This); + + textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); + ENTER_GL(); + /* Generate a texture name if we don't already have one */ + if (This->baseTexture.textureName == 0) { + glGenTextures(1, &This->baseTexture.textureName); + checkGLcall("glGenTextures"); + TRACE("Generated texture %d\n", This->baseTexture.textureName); + if (This->resource.pool == WINED3DPOOL_DEFAULT) { + /* Tell opengl to try and keep this texture in video ram (well mostly) */ + GLclampf tmp; + tmp = 0.9f; + glPrioritizeTextures(1, &This->baseTexture.textureName, &tmp); + + } + /* Initialise the state of the texture object + to the openGL defaults, not the directx defaults */ + This->baseTexture.states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_WRAP; + This->baseTexture.states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_WRAP; + This->baseTexture.states[WINED3DTEXSTA_ADDRESSW] = WINED3DTADDRESS_WRAP; + This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR] = 0; + This->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_LINEAR; + This->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ + This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ + This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] = 0; + This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = 0; + This->baseTexture.states[WINED3DTEXSTA_SRGBTEXTURE] = 0; + This->baseTexture.states[WINED3DTEXSTA_ELEMENTINDEX] = 0; + This->baseTexture.states[WINED3DTEXSTA_DMAPOFFSET] = 0; + This->baseTexture.states[WINED3DTEXSTA_TSSADDRESSW] = WINED3DTADDRESS_WRAP; + IWineD3DBaseTexture_SetDirty(iface, TRUE); + isNewTexture = TRUE; + } + + /* Bind the texture */ + if (This->baseTexture.textureName != 0) { + glBindTexture(textureDimensions, This->baseTexture.textureName); + checkGLcall("glBindTexture"); + if (isNewTexture) { + /* For a new texture we have to set the textures levels after binding the texture. + * In theory this is all we should ever have to do, but because ATI's drivers are broken, we + * also need to set the texture dimensions before the texture is set */ + TRACE("Setting GL_TEXTURE_MAX_LEVEL to %d\n", This->baseTexture.levels - 1); + glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels - 1); + checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels)"); + if(textureDimensions==GL_TEXTURE_CUBE_MAP_ARB) { + /* Cubemaps are always set to clamp, regardeless of the sampler state. */ + glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + } + + } else { /* this only happened if we've run out of openGL textures */ + WARN("This texture doesn't have an openGL texture assigned to it\n"); + hr = WINED3DERR_INVALIDCALL; + } + + LEAVE_GL(); + return hr; +} + +HRESULT WINAPI IWineD3DBaseTextureImpl_UnBindTexture(IWineD3DBaseTexture *iface) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + UINT textureDimensions; + + TRACE("(%p) : About to bind texture\n", This); + textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); + + ENTER_GL(); + + glBindTexture(textureDimensions, 0); +#if 0 /* TODO: context manager support */ + IWineD3DContextManager_PopState(This->contextManager, textureDimensions, ENABLED, NOW /* make sure the state is applied now */); +#else + glDisable(textureDimensions); +#endif + + LEAVE_GL(); + return WINED3D_OK; +} + +UINT WINAPI IWineD3DBaseTextureImpl_GetTextureDimensions(IWineD3DBaseTexture *iface){ + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + FIXME("(%p) : This shouldn't be called\n", This); + return WINED3D_OK; +} + +static inline GLenum warpLookupType(WINED3DSAMPLERSTATETYPE Type) { + switch(Type) { + case WINED3DSAMP_ADDRESSU: + return GL_TEXTURE_WRAP_S; + case WINED3DSAMP_ADDRESSV: + return GL_TEXTURE_WRAP_T; + case WINED3DSAMP_ADDRESSW: + return GL_TEXTURE_WRAP_R; + default: + FIXME("Unexpected warp type %d\n", Type); + return 0; + } +} + +static inline void apply_wrap(const GLint textureDimensions, const DWORD state, const GLint type) { + GLint wrapParm; + + if (state < minLookup[WINELOOKUP_WARPPARAM] || state > maxLookup[WINELOOKUP_WARPPARAM]) { + FIXME("Unrecognized or unsupported WINED3DTADDRESS_U value %d\n", state); + } else { + if(textureDimensions==GL_TEXTURE_CUBE_MAP_ARB) { + /* Cubemaps are always set to clamp, regardeless of the sampler state. */ + wrapParm = GL_CLAMP_TO_EDGE; + } else { + wrapParm = stateLookup[WINELOOKUP_WARPPARAM][state - minLookup[WINELOOKUP_WARPPARAM]]; + } + TRACE("Setting WRAP_S to %d for %x\n", wrapParm, textureDimensions); + glTexParameteri(textureDimensions, type, wrapParm); + checkGLcall("glTexParameteri(..., type, wrapParm)"); + } +} + +void WINAPI IWineD3DBaseTextureImpl_ApplyStateChanges(IWineD3DBaseTexture *iface, + const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], + const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + DWORD state; + GLint textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); + + IWineD3DBaseTexture_PreLoad(iface); + + if(samplerStates[WINED3DSAMP_ADDRESSU] != This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]) { + state = samplerStates[WINED3DSAMP_ADDRESSU]; + apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_S); + This->baseTexture.states[WINED3DTEXSTA_ADDRESSU] = state; + } + + if(samplerStates[WINED3DSAMP_ADDRESSV] != This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]) { + state = samplerStates[WINED3DSAMP_ADDRESSV]; + apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_T); + This->baseTexture.states[WINED3DTEXSTA_ADDRESSV] = state; + } + + if(samplerStates[WINED3DSAMP_ADDRESSW] != This->baseTexture.states[WINED3DTEXSTA_ADDRESSW]) { + state = samplerStates[WINED3DSAMP_ADDRESSW]; + apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_R); + This->baseTexture.states[WINED3DTEXSTA_ADDRESSW] = state; + } + + if(samplerStates[WINED3DSAMP_BORDERCOLOR] != This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR]) { + float col[4]; + + state = samplerStates[WINED3DSAMP_BORDERCOLOR]; + D3DCOLORTOGLFLOAT4(state, col); + TRACE("Setting border color for %u to %x\n", textureDimensions, state); + glTexParameterfv(textureDimensions, GL_TEXTURE_BORDER_COLOR, &col[0]); + checkGLcall("glTexParameteri(..., GL_TEXTURE_BORDER_COLOR, ...)"); + This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR] = state; + } + + if(samplerStates[WINED3DSAMP_MAGFILTER] != This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]) { + GLint glValue; + state = samplerStates[WINED3DSAMP_MAGFILTER]; + if (state < minLookup[WINELOOKUP_MAGFILTER] || state > maxLookup[WINELOOKUP_MAGFILTER]) { + FIXME("Unrecognized or unsupported MAGFILTER* value %d\n", state); + } + glValue = stateLookup[WINELOOKUP_MAGFILTER][state - minLookup[WINELOOKUP_MAGFILTER]]; + TRACE("ValueMAG=%d setting MAGFILTER to %x\n", state, glValue); + glTexParameteri(textureDimensions, GL_TEXTURE_MAG_FILTER, glValue); + /* We need to reset the Aniotropic filtering state when we change the mag filter to WINED3DTEXF_ANISOTROPIC (this seems a bit weird, check the documentataion to see how it should be switched off. */ + if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && WINED3DTEXF_ANISOTROPIC == state) { + glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]); + } + This->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = state; + } + + if(samplerStates[WINED3DSAMP_MINFILTER] != This->baseTexture.states[WINED3DTEXSTA_MINFILTER] || + samplerStates[WINED3DSAMP_MIPFILTER] != This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] || + samplerStates[WINED3DSAMP_MAXMIPLEVEL] != This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL]) { + GLint glValue; + + This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = samplerStates[WINED3DSAMP_MIPFILTER]; + This->baseTexture.states[WINED3DTEXSTA_MINFILTER] = samplerStates[WINED3DSAMP_MINFILTER]; + This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] = samplerStates[WINED3DSAMP_MAXMIPLEVEL]; + + if (This->baseTexture.states[WINED3DTEXSTA_MINFILTER] < WINED3DTEXF_NONE || + This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] < WINED3DTEXF_NONE || + This->baseTexture.states[WINED3DTEXSTA_MINFILTER] > WINED3DTEXF_ANISOTROPIC || + This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] > WINED3DTEXF_LINEAR) + { + + FIXME("Unrecognized or unsupported D3DSAMP_MINFILTER value %d D3DSAMP_MIPFILTER value %d\n", + This->baseTexture.states[WINED3DTEXSTA_MINFILTER], + This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]); + } + glValue = minMipLookup[min(max(samplerStates[WINED3DSAMP_MINFILTER],WINED3DTEXF_NONE), WINED3DTEXF_ANISOTROPIC)] + [min(max(samplerStates[WINED3DSAMP_MIPFILTER],WINED3DTEXF_NONE), WINED3DTEXF_LINEAR)]; + + TRACE("ValueMIN=%d, ValueMIP=%d, setting MINFILTER to %x\n", + samplerStates[WINED3DSAMP_MINFILTER], + samplerStates[WINED3DSAMP_MIPFILTER], glValue); + glTexParameteri(textureDimensions, GL_TEXTURE_MIN_FILTER, glValue); + checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ..."); + + if(This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] == WINED3DTEXF_NONE) { + glValue = 0; + } else if(This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] >= This->baseTexture.levels) { + glValue = This->baseTexture.levels - 1; + } else { + glValue = This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL]; + } + glTexParameteri(textureDimensions, GL_TEXTURE_BASE_LEVEL, glValue); + } + + if(samplerStates[WINED3DSAMP_MAXANISOTROPY] != This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY]) { + if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { + glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]); + checkGLcall("glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT ..."); + } else { + WARN("Unsupported in local OpenGL implementation: glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT\n"); + } + This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = samplerStates[WINED3DSAMP_MAXANISOTROPY]; + } +} + + +static const IWineD3DBaseTextureVtbl IWineD3DBaseTexture_Vtbl = +{ + /* IUnknown */ + IWineD3DBaseTextureImpl_QueryInterface, + IWineD3DBaseTextureImpl_AddRef, + IWineD3DBaseTextureImpl_Release, + /* IWineD3DResource */ + IWineD3DBaseTextureImpl_GetParent, + IWineD3DBaseTextureImpl_GetDevice, + IWineD3DBaseTextureImpl_SetPrivateData, + IWineD3DBaseTextureImpl_GetPrivateData, + IWineD3DBaseTextureImpl_FreePrivateData, + IWineD3DBaseTextureImpl_SetPriority, + IWineD3DBaseTextureImpl_GetPriority, + IWineD3DBaseTextureImpl_PreLoad, + IWineD3DBaseTextureImpl_GetType, + /*IWineD3DBaseTexture*/ + IWineD3DBaseTextureImpl_SetLOD, + IWineD3DBaseTextureImpl_GetLOD, + IWineD3DBaseTextureImpl_GetLevelCount, + IWineD3DBaseTextureImpl_SetAutoGenFilterType, + IWineD3DBaseTextureImpl_GetAutoGenFilterType, + IWineD3DBaseTextureImpl_GenerateMipSubLevels, + IWineD3DBaseTextureImpl_SetDirty, + IWineD3DBaseTextureImpl_GetDirty, + /* internal */ + IWineD3DBaseTextureImpl_BindTexture, + IWineD3DBaseTextureImpl_UnBindTexture, + IWineD3DBaseTextureImpl_GetTextureDimensions, + IWineD3DBaseTextureImpl_ApplyStateChanges + +}; diff --git a/reactos/dll/directx/wine/wined3d/clipper.c b/reactos/dll/directx/wine/wined3d/clipper.c new file mode 100644 index 00000000000..75bbbd00d96 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/clipper.c @@ -0,0 +1,203 @@ +/* IWineD3DClipper implementation + * + * Copyright 2000 (c) Marcus Meissner + * Copyright 2000 (c) TransGaming Technologies Inc. + * Copyright 2006 (c) Stefan Dösinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#ifdef HAVE_FLOAT_H +# include +#endif +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); + +static HRESULT WINAPI IWineD3DClipperImpl_QueryInterface(IWineD3DClipper *iface, REFIID riid, void **Obj) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + + TRACE("(%p)->(%p,%p)\n", This, riid, Obj); + if (IsEqualGUID(&IID_IUnknown, riid) + || IsEqualGUID(&IID_IWineD3DClipper, riid)) + { + *Obj = iface; + IWineD3DClipper_AddRef(iface); + return S_OK; + } + else + { + return E_NOINTERFACE; + } +} + +static ULONG WINAPI IWineD3DClipperImpl_AddRef(IWineD3DClipper *iface ) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->() incrementing from %u.\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IWineD3DClipperImpl_Release(IWineD3DClipper *iface) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->() decrementing from %u.\n", This, ref + 1); + + if (ref == 0) + { + HeapFree(GetProcessHeap(), 0, This); + return 0; + } + else return ref; +} + +static HRESULT WINAPI IWineD3DClipperImpl_GetParent(IWineD3DClipper *iface, IUnknown **Parent) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + TRACE("(%p)->(%p)\n", This, Parent); + + *Parent = This->Parent; + IUnknown_AddRef(*Parent); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DClipperImpl_SetHwnd(IWineD3DClipper *iface, DWORD Flags, HWND hWnd) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + + TRACE("(%p)->(0x%08x,%p)\n", This, Flags, hWnd); + if( Flags ) + { + FIXME("Flags = 0x%08x, not supported.\n",Flags); + return WINED3DERR_INVALIDCALL; + } + + This->hWnd = hWnd; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DClipperImpl_GetClipList(IWineD3DClipper *iface, RECT *Rect, RGNDATA *ClipList, DWORD *Size) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + TRACE("(%p,%p,%p,%p)\n", This, Rect, ClipList, Size); + + if (This->hWnd) + { + HDC hDC = GetDCEx(This->hWnd, NULL, DCX_WINDOW); + if (hDC) + { + HRGN hRgn = CreateRectRgn(0,0,0,0); + if (GetRandomRgn(hDC, hRgn, SYSRGN)) + { + if (GetVersion() & 0x80000000) + { + /* map region to screen coordinates */ + POINT org; + GetDCOrgEx( hDC, &org ); + OffsetRgn( hRgn, org.x, org.y ); + } + if (Rect) + { + HRGN hRgnClip = CreateRectRgn(Rect->left, Rect->top, + Rect->right, Rect->bottom); + CombineRgn(hRgn, hRgn, hRgnClip, RGN_AND); + DeleteObject(hRgnClip); + } + *Size = GetRegionData(hRgn, *Size, ClipList); + } + DeleteObject(hRgn); + ReleaseDC(This->hWnd, hDC); + } + return WINED3D_OK; + } + else + { + static int warned = 0; + if (warned++ < 10) + FIXME("(%p,%p,%p,%p),stub!\n",This,Rect,ClipList,Size); + if (Size) *Size=0; + return WINEDDERR_NOCLIPLIST; + } +} + +static HRESULT WINAPI IWineD3DClipperImpl_SetClipList(IWineD3DClipper *iface, RGNDATA *rgn, DWORD Flags) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + static int warned = 0; + + if (warned++ < 10 || rgn == NULL) + FIXME("(%p,%p,%d),stub!\n",This,rgn,Flags); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DClipperImpl_GetHwnd(IWineD3DClipper *iface, HWND *hwnd) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + TRACE("(%p)->(%p)\n", This, hwnd); + + *hwnd = This->hWnd; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DClipperImpl_IsClipListChanged(IWineD3DClipper *iface, BOOL *changed) +{ + IWineD3DClipperImpl *This = (IWineD3DClipperImpl *)iface; + FIXME("(%p)->(%p),stub!\n",This,changed); + + /* XXX What is safest? */ + *changed = FALSE; + + return WINED3D_OK; +} + +static const IWineD3DClipperVtbl IWineD3DClipper_Vtbl = +{ + IWineD3DClipperImpl_QueryInterface, + IWineD3DClipperImpl_AddRef, + IWineD3DClipperImpl_Release, + IWineD3DClipperImpl_GetParent, + IWineD3DClipperImpl_GetClipList, + IWineD3DClipperImpl_GetHwnd, + IWineD3DClipperImpl_IsClipListChanged, + IWineD3DClipperImpl_SetClipList, + IWineD3DClipperImpl_SetHwnd +}; + +IWineD3DClipper* WINAPI WineDirect3DCreateClipper(IUnknown *Parent) +{ + IWineD3DClipperImpl *obj; + + TRACE("Creating clipper, parent %p\n", Parent); + obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj)); + if(!obj) + { + ERR("Out of memory when trying to allocate a WineD3D Clipper\n"); + return NULL; + } + + obj->lpVtbl = &IWineD3DClipper_Vtbl; + obj->Parent = Parent; + + IWineD3DClipper_AddRef((IWineD3DClipper *)obj); + return (IWineD3DClipper *) obj; +} diff --git a/reactos/dll/directx/wine/wined3d/context.c b/reactos/dll/directx/wine/wined3d/context.c new file mode 100644 index 00000000000..25078353e23 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/context.c @@ -0,0 +1,890 @@ +/* + * Context and render target management in wined3d + * + * Copyright 2007 Stefan Dösinger for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#ifdef HAVE_FLOAT_H +# include +#endif +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); + +#define GLINFO_LOCATION This->adapter->gl_info + +/***************************************************************************** + * Context_MarkStateDirty + * + * Marks a state in a context dirty. Only one context, opposed to + * IWineD3DDeviceImpl_MarkStateDirty, which marks the state dirty in all + * contexts + * + * Params: + * context: Context to mark the state dirty in + * state: State to mark dirty + * + *****************************************************************************/ +static void Context_MarkStateDirty(WineD3DContext *context, DWORD state) { + DWORD rep = StateTable[state].representative; + DWORD idx; + BYTE shift; + + if(!rep || isStateDirty(context, rep)) return; + + context->dirtyArray[context->numDirtyEntries++] = rep; + idx = rep >> 5; + shift = rep & 0x1f; + context->isStateDirty[idx] |= (1 << shift); +} + +/***************************************************************************** + * AddContextToArray + * + * Adds a context to the context array. Helper function for CreateContext + * + * This method is not called in performance-critical code paths, only when a + * new render target or swapchain is created. Thus performance is not an issue + * here. + * + * Params: + * This: Device to add the context for + * hdc: device context + * glCtx: WGL context to add + * pbuffer: optional pbuffer used with this context + * + *****************************************************************************/ +static WineD3DContext *AddContextToArray(IWineD3DDeviceImpl *This, HWND win_handle, HDC hdc, HGLRC glCtx, HPBUFFERARB pbuffer) { + WineD3DContext **oldArray = This->contexts; + DWORD state; + + This->contexts = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->contexts) * (This->numContexts + 1)); + if(This->contexts == NULL) { + ERR("Unable to grow the context array\n"); + This->contexts = oldArray; + return NULL; + } + if(oldArray) { + memcpy(This->contexts, oldArray, sizeof(*This->contexts) * This->numContexts); + } + + This->contexts[This->numContexts] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineD3DContext)); + if(This->contexts[This->numContexts] == NULL) { + ERR("Unable to allocate a new context\n"); + HeapFree(GetProcessHeap(), 0, This->contexts); + This->contexts = oldArray; + return NULL; + } + + This->contexts[This->numContexts]->hdc = hdc; + This->contexts[This->numContexts]->glCtx = glCtx; + This->contexts[This->numContexts]->pbuffer = pbuffer; + This->contexts[This->numContexts]->win_handle = win_handle; + HeapFree(GetProcessHeap(), 0, oldArray); + + /* Mark all states dirty to force a proper initialization of the states on the first use of the context + */ + for(state = 0; state <= STATE_HIGHEST; state++) { + Context_MarkStateDirty(This->contexts[This->numContexts], state); + } + + This->numContexts++; + TRACE("Created context %p\n", This->contexts[This->numContexts - 1]); + return This->contexts[This->numContexts - 1]; +} + +/***************************************************************************** + * CreateContext + * + * Creates a new context for a window, or a pbuffer context. + * + * * Params: + * This: Device to activate the context for + * target: Surface this context will render to + * win_handle: handle to the window which we are drawing to + * create_pbuffer: tells whether to create a pbuffer or not + * pPresentParameters: contains the pixelformats to use for onscreen rendering + * + *****************************************************************************/ +WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, HWND win_handle, BOOL create_pbuffer, const WINED3DPRESENT_PARAMETERS *pPresentParms) { + HDC oldDrawable, hdc; + HPBUFFERARB pbuffer = NULL; + HGLRC ctx = NULL, oldCtx; + WineD3DContext *ret = NULL; + int s; + + TRACE("(%p): Creating a %s context for render target %p\n", This, create_pbuffer ? "offscreen" : "onscreen", target); + + if(create_pbuffer) { + HDC hdc_parent = GetDC(win_handle); + int iPixelFormat = 0; + short red, green, blue, alphaBits, colorBits; + short depthBits, stencilBits; + + IWineD3DSurface *StencilSurface = This->stencilBufferTarget; + WINED3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0; + + int attribs[256]; + int nAttribs = 0; + unsigned int nFormats; + +#define PUSH1(att) attribs[nAttribs++] = (att); +#define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value); + + /* Retrieve the specifications for the pixelformat from the backbuffer / stencilbuffer */ + getColorBits(target->resource.format, &red, &green, &blue, &alphaBits, &colorBits); + getDepthStencilBits(StencilBufferFormat, &depthBits, &stencilBits); + PUSH2(WGL_DRAW_TO_PBUFFER_ARB, 1); /* We need pbuffer support; doublebuffering isn't needed */ + PUSH2(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); /* Make sure we don't get a float or color index format */ + PUSH2(WGL_COLOR_BITS_ARB, colorBits); + PUSH2(WGL_ALPHA_BITS_ARB, alphaBits); + PUSH2(WGL_DEPTH_BITS_ARB, depthBits); + PUSH2(WGL_STENCIL_BITS_ARB, stencilBits); + PUSH1(0); /* end the list */ + +#undef PUSH1 +#undef PUSH2 + + /* Try to find a pixelformat that matches exactly. If that fails let ChoosePixelFormat try to find a close match */ + if(!GL_EXTCALL(wglChoosePixelFormatARB(hdc_parent, (const int*)&attribs, NULL, 1, &iPixelFormat, &nFormats))) + { + PIXELFORMATDESCRIPTOR pfd; + + TRACE("Falling back to ChoosePixelFormat as wglChoosePixelFormatARB failed\n"); + + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER_DONTCARE | PFD_DRAW_TO_WINDOW; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = colorBits; + pfd.cDepthBits = depthBits; + pfd.cStencilBits = stencilBits; + pfd.iLayerType = PFD_MAIN_PLANE; + + iPixelFormat = ChoosePixelFormat(hdc_parent, &pfd); + if(!iPixelFormat) { + /* If this happens something is very wrong as ChoosePixelFormat barely fails */ + ERR("Can't find a suitable iPixelFormat for the pbuffer\n"); + } + } + + TRACE("Creating a pBuffer drawable for the new context\n"); + pbuffer = GL_EXTCALL(wglCreatePbufferARB(hdc_parent, iPixelFormat, target->currentDesc.Width, target->currentDesc.Height, 0)); + if(!pbuffer) { + ERR("Cannot create a pbuffer\n"); + ReleaseDC(win_handle, hdc_parent); + goto out; + } + + /* In WGL a pbuffer is 'wrapped' inside a HDC to 'fool' wglMakeCurrent */ + hdc = GL_EXTCALL(wglGetPbufferDCARB(pbuffer)); + if(!hdc) { + ERR("Cannot get a HDC for pbuffer (%p)\n", pbuffer); + GL_EXTCALL(wglDestroyPbufferARB(pbuffer)); + ReleaseDC(win_handle, hdc_parent); + goto out; + } + ReleaseDC(win_handle, hdc_parent); + } else { + PIXELFORMATDESCRIPTOR pfd; + int iPixelFormat; + short red, green, blue, alpha; + short colorBits; + short depthBits, stencilBits; + int res; + + hdc = GetDC(win_handle); + if(hdc == NULL) { + ERR("Cannot retrieve a device context!\n"); + goto out; + } + + /* PixelFormat selection */ + /* TODO: fill cColorBits/cDepthBits with target->resource.format */ + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/ + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.cDepthBits = 0; + pfd.cStencilBits = 0; + pfd.iLayerType = PFD_MAIN_PLANE; + + /* Try to match the colorBits of the d3d format */ + if(getColorBits(target->resource.format, &red, &green, &blue, &alpha, &colorBits)) + pfd.cColorBits = colorBits; + + /* Retrieve the depth stencil format from the present parameters. + * The choice of the proper format can give a nice performance boost + * in case of GPU limited programs. */ + if(pPresentParms->EnableAutoDepthStencil) { + TRACE("pPresentParms->EnableAutoDepthStencil=enabled; using AutoDepthStencilFormat=%s\n", debug_d3dformat(pPresentParms->AutoDepthStencilFormat)); + if(getDepthStencilBits(pPresentParms->AutoDepthStencilFormat, &depthBits, &stencilBits)) { + pfd.cDepthBits = depthBits; + pfd.cStencilBits = stencilBits; + } + } + + iPixelFormat = ChoosePixelFormat(hdc, &pfd); + if(!iPixelFormat) { + /* If this happens something is very wrong as ChoosePixelFormat barely fails */ + ERR("Can't find a suitable iPixelFormat\n"); + } + + DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd); + res = SetPixelFormat(hdc, iPixelFormat, NULL); + if(!res) { + int oldPixelFormat = GetPixelFormat(hdc); + + if(oldPixelFormat) { + /* OpenGL doesn't allow pixel format adjustments. Print an error and continue using the old format. + * There's a big chance that the old format works although with a performance hit and perhaps rendering errors. */ + ERR("HDC=%p is already set to iPixelFormat=%d and OpenGL doesn't allow changes!\n", hdc, oldPixelFormat); + } + else { + ERR("SetPixelFormat failed on HDC=%p for iPixelFormat=%d\n", hdc, iPixelFormat); + return FALSE; + } + } + } + + ctx = pwglCreateContext(hdc); + if(This->numContexts) pwglShareLists(This->contexts[0]->glCtx, ctx); + + if(!ctx) { + ERR("Failed to create a WGL context\n"); + if(create_pbuffer) { + GL_EXTCALL(wglReleasePbufferDCARB(pbuffer, hdc)); + GL_EXTCALL(wglDestroyPbufferARB(pbuffer)); + } + goto out; + } + ret = AddContextToArray(This, win_handle, hdc, ctx, pbuffer); + if(!ret) { + ERR("Failed to add the newly created context to the context list\n"); + pwglDeleteContext(ctx); + if(create_pbuffer) { + GL_EXTCALL(wglReleasePbufferDCARB(pbuffer, hdc)); + GL_EXTCALL(wglDestroyPbufferARB(pbuffer)); + } + goto out; + } + ret->surface = (IWineD3DSurface *) target; + ret->isPBuffer = create_pbuffer; + ret->tid = GetCurrentThreadId(); + + TRACE("Successfully created new context %p\n", ret); + + /* Set up the context defaults */ + oldCtx = pwglGetCurrentContext(); + oldDrawable = pwglGetCurrentDC(); + if(pwglMakeCurrent(hdc, ctx) == FALSE) { + ERR("Cannot activate context to set up defaults\n"); + goto out; + } + + TRACE("Setting up the screen\n"); + /* Clear the screen */ + glClearColor(1.0, 0.0, 0.0, 0.0); + checkGLcall("glClearColor"); + glClearIndex(0); + glClearDepth(1); + glClearStencil(0xffff); + + checkGLcall("glClear"); + + glColor3f(1.0, 1.0, 1.0); + checkGLcall("glColor3f"); + + glEnable(GL_LIGHTING); + checkGLcall("glEnable"); + + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); + checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);"); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + checkGLcall("glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);"); + + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); + checkGLcall("glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);"); + + glPixelStorei(GL_PACK_ALIGNMENT, This->surface_alignment); + checkGLcall("glPixelStorei(GL_PACK_ALIGNMENT, This->surface_alignment);"); + glPixelStorei(GL_UNPACK_ALIGNMENT, This->surface_alignment); + checkGLcall("glPixelStorei(GL_UNPACK_ALIGNMENT, This->surface_alignment);"); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* Most textures will use client storage if supported. Exceptions are non-native power of 2 textures + * and textures in DIB sections(due to the memory protection). + */ + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } + if(GL_SUPPORT(ARB_VERTEX_BLEND)) { + /* Direct3D always uses n-1 weights for n world matrices and uses 1 - sum for the last one + * this is equal to GL_WEIGHT_SUM_UNITY_ARB. Enabling it doesn't do anything unless + * GL_VERTEX_BLEND_ARB isn't enabled too + */ + glEnable(GL_WEIGHT_SUM_UNITY_ARB); + checkGLcall("glEnable(GL_WEIGHT_SUM_UNITY_ARB)"); + } + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glEnable(GL_TEXTURE_SHADER_NV); + checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)"); + + /* Set up the previous texture input for all shader units. This applies to bump mapping, and in d3d + * the previous texture where to source the offset from is always unit - 1. + */ + for(s = 1; s < GL_LIMITS(textures); s++) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s)); + glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB + s - 1); + checkGLcall("glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, ...\n"); + } + } + if(GL_SUPPORT(ARB_POINT_SPRITE)) { + for(s = 0; s < GL_LIMITS(textures); s++) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + s)); + glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE); + checkGLcall("glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE)\n"); + } + } + + if(oldDrawable && oldCtx) { + pwglMakeCurrent(oldDrawable, oldCtx); + } + +out: + return ret; +} + +/***************************************************************************** + * RemoveContextFromArray + * + * Removes a context from the context manager. The opengl context is not + * destroyed or unset. context is not a valid pointer after that call. + * + * Similar to the former call this isn't a performance critical function. A + * helper function for DestroyContext. + * + * Params: + * This: Device to activate the context for + * context: Context to remove + * + *****************************************************************************/ +static void RemoveContextFromArray(IWineD3DDeviceImpl *This, WineD3DContext *context) { + UINT t, s; + WineD3DContext **oldArray = This->contexts; + + TRACE("Removing ctx %p\n", context); + + This->numContexts--; + + if(This->numContexts) { + This->contexts = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->contexts) * This->numContexts); + if(!This->contexts) { + ERR("Cannot allocate a new context array, PANIC!!!\n"); + } + t = 0; + for(s = 0; s < This->numContexts; s++) { + if(oldArray[s] == context) continue; + This->contexts[t] = oldArray[s]; + t++; + } + } else { + This->contexts = NULL; + } + + HeapFree(GetProcessHeap(), 0, context); + HeapFree(GetProcessHeap(), 0, oldArray); +} + +/***************************************************************************** + * DestroyContext + * + * Destroys a wineD3DContext + * + * Params: + * This: Device to activate the context for + * context: Context to destroy + * + *****************************************************************************/ +void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context) { + + /* check that we are the current context first */ + TRACE("Destroying ctx %p\n", context); + if(pwglGetCurrentContext() == context->glCtx){ + pwglMakeCurrent(NULL, NULL); + } + + if(context->isPBuffer) { + GL_EXTCALL(wglReleasePbufferDCARB(context->pbuffer, context->hdc)); + GL_EXTCALL(wglDestroyPbufferARB(context->pbuffer)); + } else ReleaseDC(context->win_handle, context->hdc); + pwglDeleteContext(context->glCtx); + + RemoveContextFromArray(This, context); +} + +/***************************************************************************** + * SetupForBlit + * + * Sets up a context for DirectDraw blitting. + * All texture units are disabled, except unit 0 + * Texture unit 0 is activted where GL_TEXTURE_2D is activated + * fog, lighting, blending, alpha test, z test, scissor test, culling diabled + * color writing enabled for all channels + * register combiners disabled, shaders disabled + * world matris is set to identity, texture matrix 0 too + * projection matrix is setup for drawing screen coordinates + * + * Params: + * This: Device to activate the context for + * context: Context to setup + * width: render target width + * height: render target height + * + *****************************************************************************/ +static inline void SetupForBlit(IWineD3DDeviceImpl *This, WineD3DContext *context, UINT width, UINT height) { + int i; + + TRACE("Setting up context %p for blitting\n", context); + if(context->last_was_blit) { + TRACE("Context is already set up for blitting, nothing to do\n"); + return; + } + context->last_was_blit = TRUE; + + /* TODO: Use a display list */ + + /* Disable shaders */ + This->shader_backend->shader_cleanup((IWineD3DDevice *) This); + Context_MarkStateDirty(context, STATE_VSHADER); + Context_MarkStateDirty(context, STATE_PIXELSHADER); + + /* Disable all textures. The caller can then bind a texture it wants to blit + * from + */ + if(GL_SUPPORT(NV_REGISTER_COMBINERS)) { + glDisable(GL_REGISTER_COMBINERS_NV); + checkGLcall("glDisable(GL_REGISTER_COMBINERS_NV)"); + } + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + /* The blitting code uses (for now) the fixed function pipeline, so make sure to reset all fixed + * function texture unit. No need to care for higher samplers + */ + for(i = GL_LIMITS(textures) - 1; i > 0 ; i--) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i)); + checkGLcall("glActiveTextureARB"); + + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB"); + } + glDisable(GL_TEXTURE_3D); + checkGLcall("glDisable GL_TEXTURE_3D"); + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable GL_TEXTURE_2D"); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);"); + + Context_MarkStateDirty(context, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP)); + Context_MarkStateDirty(context, STATE_SAMPLER(i)); + } + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); + checkGLcall("glActiveTextureARB"); + } + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable GL_TEXTURE_CUBE_MAP_ARB"); + } + glDisable(GL_TEXTURE_3D); + checkGLcall("glDisable GL_TEXTURE_3D"); + glEnable(GL_TEXTURE_2D); + checkGLcall("glEnable GL_TEXTURE_2D"); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + glMatrixMode(GL_TEXTURE); + checkGLcall("glMatrixMode(GL_TEXTURE)"); + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0)); + + if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) { + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, + GL_TEXTURE_LOD_BIAS_EXT, + 0.0); + checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ..."); + } + Context_MarkStateDirty(context, STATE_SAMPLER(0)); + Context_MarkStateDirty(context, STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)); + + /* Other misc states */ + glDisable(GL_ALPHA_TEST); + checkGLcall("glDisable(GL_ALPHA_TEST)"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHATESTENABLE)); + glDisable(GL_LIGHTING); + checkGLcall("glDisable GL_LIGHTING"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_LIGHTING)); + glDisable(GL_DEPTH_TEST); + checkGLcall("glDisable GL_DEPTH_TEST"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ZENABLE)); + glDisable(GL_FOG); + checkGLcall("glDisable GL_FOG"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_FOGENABLE)); + glDisable(GL_BLEND); + checkGLcall("glDisable GL_BLEND"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE)); + glDisable(GL_CULL_FACE); + checkGLcall("glDisable GL_CULL_FACE"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CULLMODE)); + glDisable(GL_STENCIL_TEST); + checkGLcall("glDisable GL_STENCIL_TEST"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_STENCILENABLE)); + if(GL_SUPPORT(ARB_POINT_SPRITE)) { + glDisable(GL_POINT_SPRITE_ARB); + checkGLcall("glDisable GL_POINT_SPRITE_ARB"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_POINTSPRITEENABLE)); + } + glColorMask(GL_TRUE, GL_TRUE,GL_TRUE,GL_TRUE); + checkGLcall("glColorMask"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPING)); + + /* Setup transforms */ + glMatrixMode(GL_MODELVIEW); + checkGLcall("glMatrixMode(GL_MODELVIEW)"); + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))); + + glMatrixMode(GL_PROJECTION); + checkGLcall("glMatrixMode(GL_PROJECTION)"); + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + glOrtho(0, width, height, 0, 0.0, -1.0); + checkGLcall("glOrtho"); + Context_MarkStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION)); + + context->last_was_rhw = TRUE; + Context_MarkStateDirty(context, STATE_VDECL); /* because of last_was_rhw = TRUE */ + + glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); + glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); + glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); + glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); + glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); + glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPING)); + + glViewport(0, 0, width, height); + checkGLcall("glViewport"); + Context_MarkStateDirty(context, STATE_VIEWPORT); + + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glDisable(GL_TEXTURE_SHADER_NV); + checkGLcall("glDisable(GL_TEXTURE_SHADER_NV)"); + } +} + +/***************************************************************************** + * findThreadContextForSwapChain + * + * Searches a swapchain for all contexts and picks one for the thread tid. + * If none can be found the swapchain is requested to create a new context + * + *****************************************************************************/ +static WineD3DContext *findThreadContextForSwapChain(IWineD3DSwapChain *swapchain, DWORD tid) { + int i; + + for(i = 0; i < ((IWineD3DSwapChainImpl *) swapchain)->num_contexts; i++) { + if(((IWineD3DSwapChainImpl *) swapchain)->context[i]->tid == tid) { + return ((IWineD3DSwapChainImpl *) swapchain)->context[i]; + } + + } + + /* Create a new context for the thread */ + return IWineD3DSwapChainImpl_CreateContextForThread(swapchain); +} + +/***************************************************************************** + * FindContext + * + * Finds a context for the current render target and thread + * + * Parameters: + * target: Render target to find the context for + * tid: Thread to activate the context for + * + * Returns: The needed context + * + *****************************************************************************/ +static inline WineD3DContext *FindContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, DWORD tid) { + IWineD3DSwapChain *swapchain = NULL; + HRESULT hr; + BOOL readTexture = wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->render_offscreen; + WineD3DContext *context = This->activeContext; + BOOL oldRenderOffscreen = This->render_offscreen; + + hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **) &swapchain); + if(hr == WINED3D_OK && swapchain) { + TRACE("Rendering onscreen\n"); + + context = findThreadContextForSwapChain(swapchain, tid); + + This->render_offscreen = FALSE; + /* The context != This->activeContext will catch a NOP context change. This can occur + * if we are switching back to swapchain rendering in case of FBO or Back Buffer offscreen + * rendering. No context change is needed in that case + */ + + if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER) { + if(((IWineD3DSwapChainImpl *) swapchain)->backBuffer) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer(GL_BACK)"); + } else { + glDrawBuffer(GL_FRONT); + checkGLcall("glDrawBuffer(GL_FRONT)"); + } + } else if(wined3d_settings.offscreen_rendering_mode == ORM_PBUFFER) { + if(This->pbufferContext && tid == This->pbufferContext->tid) { + This->pbufferContext->tid = 0; + } + } + IWineD3DSwapChain_Release(swapchain); + + if(oldRenderOffscreen) { + Context_MarkStateDirty(context, WINED3DRS_CULLMODE); + Context_MarkStateDirty(context, WINED3DTS_PROJECTION); + Context_MarkStateDirty(context, STATE_VDECL); + Context_MarkStateDirty(context, STATE_VIEWPORT); + Context_MarkStateDirty(context, STATE_SCISSORRECT); + } + + } else { + TRACE("Rendering offscreen\n"); + This->render_offscreen = TRUE; + + switch(wined3d_settings.offscreen_rendering_mode) { + case ORM_FBO: + /* FBOs do not need a different context. Stay with whatever context is active at the moment */ + if(This->activeContext && tid == This->lastThread) { + context = This->activeContext; + } else { + /* This may happen if the app jumps streight into offscreen rendering + * Start using the context of the primary swapchain. tid == 0 is no problem + * for findThreadContextForSwapChain. + * + * Can also happen on thread switches - in that case findThreadContextForSwapChain + * is perfect to call. + */ + context = findThreadContextForSwapChain(This->swapchains[0], tid); + } + break; + + case ORM_PBUFFER: + { + IWineD3DSurfaceImpl *targetimpl = (IWineD3DSurfaceImpl *) target; + if(This->pbufferContext == NULL || + This->pbufferWidth < targetimpl->currentDesc.Width || + This->pbufferHeight < targetimpl->currentDesc.Height) { + if(This->pbufferContext) { + DestroyContext(This, This->pbufferContext); + } + + /* The display is irrelevant here, the window is 0. But CreateContext needs a valid X connection. + * Create the context on the same server as the primary swapchain. The primary swapchain is exists at this point. + */ + This->pbufferContext = CreateContext(This, targetimpl, + ((IWineD3DSwapChainImpl *) This->swapchains[0])->context[0]->win_handle, + TRUE /* pbuffer */, &((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms); + This->pbufferWidth = targetimpl->currentDesc.Width; + This->pbufferHeight = targetimpl->currentDesc.Height; + } + + if(This->pbufferContext) { + if(This->pbufferContext->tid != 0 && This->pbufferContext->tid != tid) { + FIXME("The PBuffr context is only supported for one thread for now!\n"); + } + This->pbufferContext->tid = tid; + context = This->pbufferContext; + break; + } else { + ERR("Failed to create a buffer context and drawable, falling back to back buffer offscreen rendering\n"); + wined3d_settings.offscreen_rendering_mode = ORM_BACKBUFFER; + } + } + + case ORM_BACKBUFFER: + /* Stay with the currently active context for back buffer rendering */ + if(This->activeContext && tid == This->lastThread) { + context = This->activeContext; + } else { + /* This may happen if the app jumps streight into offscreen rendering + * Start using the context of the primary swapchain. tid == 0 is no problem + * for findThreadContextForSwapChain. + * + * Can also happen on thread switches - in that case findThreadContextForSwapChain + * is perfect to call. + */ + context = findThreadContextForSwapChain(This->swapchains[0], tid); + } + glDrawBuffer(This->offscreenBuffer); + checkGLcall("glDrawBuffer(This->offscreenBuffer)"); + break; + } + + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) { + /* Make sure we have a OpenGL texture name so the PreLoad() used to read the buffer + * back when we are done won't mark us dirty. + */ + IWineD3DSurface_PreLoad(target); + } + + if(!oldRenderOffscreen) { + Context_MarkStateDirty(context, WINED3DRS_CULLMODE); + Context_MarkStateDirty(context, WINED3DTS_PROJECTION); + Context_MarkStateDirty(context, STATE_VDECL); + Context_MarkStateDirty(context, STATE_VIEWPORT); + Context_MarkStateDirty(context, STATE_SCISSORRECT); + } + } + if (readTexture) { + BOOL oldInDraw = This->isInDraw; + + /* PreLoad requires a context to load the texture, thus it will call ActivateContext. + * Set the isInDraw to true to signal PreLoad that it has a context. Will be tricky + * when using offscreen rendering with multithreading + */ + This->isInDraw = TRUE; + + /* Do that before switching the context: + * Read the back buffer of the old drawable into the destination texture + */ + IWineD3DSurface_PreLoad(This->lastActiveRenderTarget); + + /* Assume that the drawable will be modified by some other things now */ + ((IWineD3DSurfaceImpl *) This->lastActiveRenderTarget)->Flags &= ~SFLAG_INDRAWABLE; + + This->isInDraw = oldInDraw; + } + + if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) { + This->depth_copy_state = WINED3D_DCS_COPY; + } + return context; +} + +/***************************************************************************** + * ActivateContext + * + * Finds a rendering context and drawable matching the device and render + * target for the current thread, activates them and puts them into the + * requested state. + * + * Params: + * This: Device to activate the context for + * target: Requested render target + * usage: Prepares the context for blitting, drawing or other actions + * + *****************************************************************************/ +void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextUsage usage) { + DWORD tid = GetCurrentThreadId(); + int i; + DWORD dirtyState, idx; + BYTE shift; + WineD3DContext *context; + + TRACE("(%p): Selecting context for render target %p, thread %d\n", This, target, tid); + + ENTER_GL(); + if(This->lastActiveRenderTarget != target || tid != This->lastThread) { + context = FindContext(This, target, tid); + This->lastActiveRenderTarget = target; + This->lastThread = tid; + } else { + /* Stick to the old context */ + context = This->activeContext; + } + + /* Activate the opengl context */ + if(context != This->activeContext) { + BOOL ret; + TRACE("Switching gl ctx to %p, hdc=%p ctx=%p\n", context, context->hdc, context->glCtx); + LEAVE_GL(); + ret = pwglMakeCurrent(context->hdc, context->glCtx); + ENTER_GL(); + if(ret == FALSE) { + ERR("Failed to activate the new context\n"); + } + This->activeContext = context; + } + + switch(usage) { + case CTXUSAGE_RESOURCELOAD: + /* This does not require any special states to be set up */ + break; + + case CTXUSAGE_CLEAR: + if(context->last_was_blit && GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glEnable(GL_TEXTURE_SHADER_NV); + checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)"); + } + + glEnable(GL_SCISSOR_TEST); + checkGLcall("glEnable GL_SCISSOR_TEST"); + context->last_was_blit = FALSE; + Context_MarkStateDirty(context, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); + Context_MarkStateDirty(context, STATE_SCISSORRECT); + break; + + case CTXUSAGE_DRAWPRIM: + /* This needs all dirty states applied */ + if(context->last_was_blit && GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glEnable(GL_TEXTURE_SHADER_NV); + checkGLcall("glEnable(GL_TEXTURE_SHADER_NV)"); + } + + IWineD3DDeviceImpl_FindTexUnitMap(This); + + for(i=0; i < context->numDirtyEntries; i++) { + dirtyState = context->dirtyArray[i]; + idx = dirtyState >> 5; + shift = dirtyState & 0x1f; + context->isStateDirty[idx] &= ~(1 << shift); + StateTable[dirtyState].apply(dirtyState, This->stateBlock, context); + } + context->numDirtyEntries = 0; /* This makes the whole list clean */ + context->last_was_blit = FALSE; + break; + + case CTXUSAGE_BLIT: + SetupForBlit(This, context, + ((IWineD3DSurfaceImpl *)target)->currentDesc.Width, + ((IWineD3DSurfaceImpl *)target)->currentDesc.Height); + break; + + default: + FIXME("Unexpected context usage requested\n"); + } + LEAVE_GL(); +} diff --git a/reactos/dll/directx/wine/wined3d/cubetexture.c b/reactos/dll/directx/wine/wined3d/cubetexture.c new file mode 100644 index 00000000000..d91ee6ce9e5 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/cubetexture.c @@ -0,0 +1,406 @@ +/* + * IWineD3DCubeTexture implementation + * + * Copyright 2002-2005 Jason Edmeades + * Copyright 2002-2005 Raphael Junqueira + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +static const GLenum cube_targets[6] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB +}; + +/* ******************************************* + IWineD3DCubeTexture IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DCubeTextureImpl_QueryInterface(IWineD3DCubeTexture *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DBaseTexture) + || IsEqualGUID(riid, &IID_IWineD3DTexture)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DCubeTextureImpl_AddRef(IWineD3DCubeTexture *iface) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref); + return InterlockedIncrement(&This->resource.ref); +} + +static ULONG WINAPI IWineD3DCubeTextureImpl_Release(IWineD3DCubeTexture *iface) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->resource.ref); + ref = InterlockedDecrement(&This->resource.ref); + if (ref == 0) { + IWineD3DCubeTexture_Destroy(iface, D3DCB_DefaultDestroySurface); + } + return ref; +} + +/* **************************************************** + IWineD3DCubeTexture IWineD3DResource parts follow + **************************************************** */ +static HRESULT WINAPI IWineD3DCubeTextureImpl_GetDevice(IWineD3DCubeTexture *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_SetPrivateData(IWineD3DCubeTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_GetPrivateData(IWineD3DCubeTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_FreePrivateData(IWineD3DCubeTexture *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +static DWORD WINAPI IWineD3DCubeTextureImpl_SetPriority(IWineD3DCubeTexture *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +static DWORD WINAPI IWineD3DCubeTextureImpl_GetPriority(IWineD3DCubeTexture *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface) { + /* Override the IWineD3DResource Preload method */ + unsigned int i,j; + BOOL setGlTextureDesc = FALSE; + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + BOOL srgb_mode = This->baseTexture.is_srgb; + BOOL srgb_was_toggled = FALSE; + + TRACE("(%p) : About to load texture: dirtified(%d)\n", This, This->baseTexture.dirty); + + if (This->baseTexture.textureName == 0) setGlTextureDesc = TRUE; + + /* We only have to activate a context for gl when we're not drawing. In most cases PreLoad will be called during draw + * and a context was activated at the beginning of drawPrimitive + */ + if(!device->isInDraw) { + /* No danger of recursive calls, ActivateContext sets isInDraw to true when loading + * offscreen render targets into their texture + */ + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } else if (GL_SUPPORT(EXT_TEXTURE_SRGB) && This->baseTexture.bindCount > 0) { + srgb_mode = device->stateBlock->samplerState[This->baseTexture.sampler][WINED3DSAMP_SRGBTEXTURE]; + srgb_was_toggled = (This->baseTexture.is_srgb != srgb_mode); + This->baseTexture.is_srgb = srgb_mode; + } + IWineD3DCubeTexture_BindTexture(iface); + + ENTER_GL(); + /* If the texture is marked dirty or the srgb sampler setting has changed since the last load then reload the surfaces */ + if (This->baseTexture.dirty) { + for (i = 0; i < This->baseTexture.levels; i++) { + for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z ; j++) { + if(setGlTextureDesc) + IWineD3DSurface_SetGlTextureDesc(This->surfaces[j][i], This->baseTexture.textureName, cube_targets[j]); + IWineD3DSurface_LoadTexture(This->surfaces[j][i], srgb_mode); + } + } + } else if (srgb_was_toggled) { + /* Loop is repeated in the else block with the extra AddDirtyRect line to avoid the alternative of + * checking srgb_was_toggled in every iteration, even when the texture is just dirty + */ + if (This->baseTexture.srgb_mode_change_count < 20) + ++This->baseTexture.srgb_mode_change_count; + else + FIXME("Cubetexture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); + + for (i = 0; i < This->baseTexture.levels; i++) { + for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z ; j++) { + IWineD3DSurfaceImpl_AddDirtyRect(This->surfaces[j][i], NULL); + IWineD3DSurface_SetGlTextureDesc(This->surfaces[j][i], This->baseTexture.textureName, cube_targets[j]); + IWineD3DSurface_LoadTexture(This->surfaces[j][i], srgb_mode); + } + } + } else { + TRACE("(%p) Texture not dirty, nothing to do\n" , iface); + } + LEAVE_GL(); + + /* No longer dirty */ + This->baseTexture.dirty = FALSE; + return ; +} + +static WINED3DRESOURCETYPE WINAPI IWineD3DCubeTextureImpl_GetType(IWineD3DCubeTexture *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_GetParent(IWineD3DCubeTexture *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DCubeTexture IWineD3DBaseTexture parts follow + ****************************************************** */ +static DWORD WINAPI IWineD3DCubeTextureImpl_SetLOD(IWineD3DCubeTexture *iface, DWORD LODNew) { + return IWineD3DBaseTextureImpl_SetLOD((IWineD3DBaseTexture *)iface, LODNew); +} + +static DWORD WINAPI IWineD3DCubeTextureImpl_GetLOD(IWineD3DCubeTexture *iface) { + return IWineD3DBaseTextureImpl_GetLOD((IWineD3DBaseTexture *)iface); +} + +static DWORD WINAPI IWineD3DCubeTextureImpl_GetLevelCount(IWineD3DCubeTexture *iface) { + return IWineD3DBaseTextureImpl_GetLevelCount((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_SetAutoGenFilterType(IWineD3DCubeTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) { + return IWineD3DBaseTextureImpl_SetAutoGenFilterType((IWineD3DBaseTexture *)iface, FilterType); +} + +static WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DCubeTextureImpl_GetAutoGenFilterType(IWineD3DCubeTexture *iface) { + return IWineD3DBaseTextureImpl_GetAutoGenFilterType((IWineD3DBaseTexture *)iface); +} + +static void WINAPI IWineD3DCubeTextureImpl_GenerateMipSubLevels(IWineD3DCubeTexture *iface) { + IWineD3DBaseTextureImpl_GenerateMipSubLevels((IWineD3DBaseTexture *)iface); +} + +/* Internal function, No d3d mapping */ +static BOOL WINAPI IWineD3DCubeTextureImpl_SetDirty(IWineD3DCubeTexture *iface, BOOL dirty) { + return IWineD3DBaseTextureImpl_SetDirty((IWineD3DBaseTexture *)iface, dirty); +} + +/* Internal function, No d3d mapping */ +static BOOL WINAPI IWineD3DCubeTextureImpl_GetDirty(IWineD3DCubeTexture *iface) { + return IWineD3DBaseTextureImpl_GetDirty((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_BindTexture(IWineD3DCubeTexture *iface) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + TRACE("(%p) : relay to BaseTexture\n", This); + return IWineD3DBaseTextureImpl_BindTexture((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_UnBindTexture(IWineD3DCubeTexture *iface) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + TRACE("(%p) : relay to BaseTexture\n", This); + return IWineD3DBaseTextureImpl_UnBindTexture((IWineD3DBaseTexture *)iface); +} + +static UINT WINAPI IWineD3DCubeTextureImpl_GetTextureDimensions(IWineD3DCubeTexture *iface){ + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + TRACE("(%p)\n", This); + + return GL_TEXTURE_CUBE_MAP_ARB; +} + +static void WINAPI IWineD3DCubeTextureImpl_ApplyStateChanges(IWineD3DCubeTexture *iface, + const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], + const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + float matrix[16]; + IWineD3DBaseTextureImpl_ApplyStateChanges((IWineD3DBaseTexture *)iface, textureStates, samplerStates); + + + /* Apply non-power2 mappings and texture offsets so long as the texture coords aren't projected or generated */ + if(This->pow2scalingFactor != 1.0f) { + if((textureStates[WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) == WINED3DTSS_TCI_PASSTHRU && + (~textureStates[WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) { + + glMatrixMode(GL_TEXTURE); + memset(matrix, 0 , sizeof(matrix)); + + matrix[0] = This->pow2scalingFactor; + matrix[5] = This->pow2scalingFactor; + matrix[10] = This->pow2scalingFactor; +#if 0 /* Translation fixup is no longer required (here for reminder) */ + matrix[12] = -0.25f / (float)This->edgeLength; + matrix[13] = -0.75f / (float)This->edgeLength; + matrix[14] = -0.25f / (float)This->edgeLength; +#endif + TRACE("(%p) Setup Matrix:\n", This); + TRACE(" %f %f %f %f\n", matrix[0], matrix[1], matrix[2], matrix[3]); + TRACE(" %f %f %f %f\n", matrix[4], matrix[5], matrix[6], matrix[7]); + TRACE(" %f %f %f %f\n", matrix[8], matrix[9], matrix[10], matrix[11]); + TRACE(" %f %f %f %f\n", matrix[12], matrix[13], matrix[14], matrix[15]); + TRACE("\n"); + glMultMatrixf(matrix); + } else { + /* I don't expect nonpower 2 textures to be used with generated texture coordinates, but if they are present a fixme. */ + FIXME("Non-power2 texture being used with generated texture coords\n"); + } + } + +} + + +/* ******************************************* + IWineD3DCubeTexture IWineD3DCubeTexture parts follow + ******************************************* */ +static void WINAPI IWineD3DCubeTextureImpl_Destroy(IWineD3DCubeTexture *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroySurface) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + int i,j; + TRACE("(%p) : Cleaning up\n",This); + for (i = 0; i < This->baseTexture.levels; i++) { + for (j = 0; j < 6; j++) { + if (This->surfaces[j][i] != NULL) { + /* Clean out the texture name we gave to the surface so that the surface doesn't try and release it */ + IWineD3DSurface_SetGlTextureDesc(This->surfaces[j][i], 0, 0); + /* Cleanup the container */ + IWineD3DSurface_SetContainer(This->surfaces[j][i], 0); + D3DCB_DestroySurface(This->surfaces[j][i]); + } + } + } + IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *) iface); + /* finally delete the object */ + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_GetLevelDesc(IWineD3DCubeTexture *iface, UINT Level, WINED3DSURFACE_DESC* pDesc) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + + if (Level < This->baseTexture.levels) { + TRACE("(%p) level (%d)\n", This, Level); + return IWineD3DSurface_GetDesc(This->surfaces[0][Level], pDesc); + } + FIXME("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + return WINED3DERR_INVALIDCALL; +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_GetCubeMapSurface(IWineD3DCubeTexture *iface, WINED3DCUBEMAP_FACES FaceType, UINT Level, IWineD3DSurface** ppCubeMapSurface) { + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + HRESULT hr = WINED3DERR_INVALIDCALL; + + if (Level < This->baseTexture.levels && FaceType >= WINED3DCUBEMAP_FACE_POSITIVE_X && FaceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z) { + *ppCubeMapSurface = This->surfaces[FaceType][Level]; + IWineD3DSurface_AddRef(*ppCubeMapSurface); + + hr = WINED3D_OK; + } + if (WINED3D_OK == hr) { + TRACE("(%p) -> faceType(%d) level(%d) returning surface@%p\n", This, FaceType, Level, This->surfaces[FaceType][Level]); + } else { + WARN("(%p) level(%d) overflow Levels(%d) Or FaceType(%d)\n", This, Level, This->baseTexture.levels, FaceType); + } + + return hr; +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_LockRect(IWineD3DCubeTexture *iface, WINED3DCUBEMAP_FACES FaceType, UINT Level, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { + HRESULT hr = WINED3DERR_INVALIDCALL; + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + + if (Level < This->baseTexture.levels && FaceType >= WINED3DCUBEMAP_FACE_POSITIVE_X && FaceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z) { + hr = IWineD3DSurface_LockRect(This->surfaces[FaceType][Level], pLockedRect, pRect, Flags); + } + + if (WINED3D_OK == hr) { + TRACE("(%p) -> faceType(%d) level(%d) returning memory@%p success(%u)\n", This, FaceType, Level, pLockedRect->pBits, hr); + } else { + WARN("(%p) level(%d) overflow Levels(%d) Or FaceType(%d)\n", This, Level, This->baseTexture.levels, FaceType); + } + + return hr; +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_UnlockRect(IWineD3DCubeTexture *iface, WINED3DCUBEMAP_FACES FaceType, UINT Level) { + HRESULT hr = WINED3DERR_INVALIDCALL; + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + + if (Level < This->baseTexture.levels && FaceType >= WINED3DCUBEMAP_FACE_POSITIVE_X && FaceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z) { + hr = IWineD3DSurface_UnlockRect(This->surfaces[FaceType][Level]); + } + + if (WINED3D_OK == hr) { + TRACE("(%p) -> faceType(%d) level(%d) success(%u)\n", This, FaceType, Level, hr); + } else { + WARN("(%p) level(%d) overflow Levels(%d) Or FaceType(%d)\n", This, Level, This->baseTexture.levels, FaceType); + } + return hr; +} + +static HRESULT WINAPI IWineD3DCubeTextureImpl_AddDirtyRect(IWineD3DCubeTexture *iface, WINED3DCUBEMAP_FACES FaceType, CONST RECT* pDirtyRect) { + HRESULT hr = WINED3DERR_INVALIDCALL; + IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; + This->baseTexture.dirty = TRUE; + TRACE("(%p) : dirtyfication of faceType(%d) Level (0)\n", This, FaceType); + if (FaceType >= WINED3DCUBEMAP_FACE_POSITIVE_X && FaceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z) { + hr = IWineD3DSurface_AddDirtyRect(This->surfaces[FaceType][0], pDirtyRect); + } else { + WARN("(%p) overflow FaceType(%d)\n", This, FaceType); + } + return hr; +} + + +const IWineD3DCubeTextureVtbl IWineD3DCubeTexture_Vtbl = +{ + /* IUnknown */ + IWineD3DCubeTextureImpl_QueryInterface, + IWineD3DCubeTextureImpl_AddRef, + IWineD3DCubeTextureImpl_Release, + /* IWineD3DResource */ + IWineD3DCubeTextureImpl_GetParent, + IWineD3DCubeTextureImpl_GetDevice, + IWineD3DCubeTextureImpl_SetPrivateData, + IWineD3DCubeTextureImpl_GetPrivateData, + IWineD3DCubeTextureImpl_FreePrivateData, + IWineD3DCubeTextureImpl_SetPriority, + IWineD3DCubeTextureImpl_GetPriority, + IWineD3DCubeTextureImpl_PreLoad, + IWineD3DCubeTextureImpl_GetType, + /* IWineD3DBaseTexture */ + IWineD3DCubeTextureImpl_SetLOD, + IWineD3DCubeTextureImpl_GetLOD, + IWineD3DCubeTextureImpl_GetLevelCount, + IWineD3DCubeTextureImpl_SetAutoGenFilterType, + IWineD3DCubeTextureImpl_GetAutoGenFilterType, + IWineD3DCubeTextureImpl_GenerateMipSubLevels, + IWineD3DCubeTextureImpl_SetDirty, + IWineD3DCubeTextureImpl_GetDirty, + IWineD3DCubeTextureImpl_BindTexture, + IWineD3DCubeTextureImpl_UnBindTexture, + IWineD3DCubeTextureImpl_GetTextureDimensions, + IWineD3DCubeTextureImpl_ApplyStateChanges, + /* IWineD3DCubeTexture */ + IWineD3DCubeTextureImpl_Destroy, + IWineD3DCubeTextureImpl_GetLevelDesc, + IWineD3DCubeTextureImpl_GetCubeMapSurface, + IWineD3DCubeTextureImpl_LockRect, + IWineD3DCubeTextureImpl_UnlockRect, + IWineD3DCubeTextureImpl_AddDirtyRect +}; diff --git a/reactos/dll/directx/wine/wined3d/device.c b/reactos/dll/directx/wine/wined3d/device.c new file mode 100644 index 00000000000..7b9d92ebae6 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/device.c @@ -0,0 +1,6943 @@ +/* + * IWineD3DDevice implementation + * + * Copyright 2002 Lionel Ulmer + * Copyright 2002-2005 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006-2007 Stefan Dösinger for CodeWeavers + * Copyright 2006-2007 Henri Verbeet + * Copyright 2007 Andrew Riedi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#ifdef HAVE_FLOAT_H +# include +#endif +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->adapter->gl_info + +/* Define the default light parameters as specified by MSDN */ +const WINED3DLIGHT WINED3D_default_light = { + + WINED3DLIGHT_DIRECTIONAL, /* Type */ + { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */ + { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */ + { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */ + { 0.0, 0.0, 0.0 }, /* Position x,y,z */ + { 0.0, 0.0, 1.0 }, /* Direction x,y,z */ + 0.0, /* Range */ + 0.0, /* Falloff */ + 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */ + 0.0, /* Theta */ + 0.0 /* Phi */ +}; + +/* static function declarations */ +static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource); + +/* helper macros */ +#define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;} + +#define D3DCREATEOBJECTINSTANCE(object, type) { \ + object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \ + D3DMEMCHECK(object, pp##type); \ + object->lpVtbl = &IWineD3D##type##_Vtbl; \ + object->wineD3DDevice = This; \ + object->parent = parent; \ + object->ref = 1; \ + *pp##type = (IWineD3D##type *) object; \ +} + +#define D3DCREATESHADEROBJECTINSTANCE(object, type) { \ + object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \ + D3DMEMCHECK(object, pp##type); \ + object->lpVtbl = &IWineD3D##type##_Vtbl; \ + object->parent = parent; \ + object->ref = 1; \ + object->baseShader.device = (IWineD3DDevice*) This; \ + list_init(&object->baseShader.linked_programs); \ + *pp##type = (IWineD3D##type *) object; \ +} + +#define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \ + object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \ + D3DMEMCHECK(object, pp##type); \ + object->lpVtbl = &IWineD3D##type##_Vtbl; \ + object->resource.wineD3DDevice = This; \ + object->resource.parent = parent; \ + object->resource.resourceType = d3dtype; \ + object->resource.ref = 1; \ + object->resource.pool = Pool; \ + object->resource.format = Format; \ + object->resource.usage = Usage; \ + object->resource.size = _size; \ + list_init(&object->resource.privateData); \ + /* Check that we have enough video ram left */ \ + if (Pool == WINED3DPOOL_DEFAULT) { \ + if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \ + WARN("Out of 'bogus' video memory\n"); \ + HeapFree(GetProcessHeap(), 0, object); \ + *pp##type = NULL; \ + return WINED3DERR_OUTOFVIDEOMEMORY; \ + } \ + globalChangeGlRam(_size); \ + } \ + object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \ + if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \ + FIXME("Out of memory!\n"); \ + HeapFree(GetProcessHeap(), 0, object); \ + *pp##type = NULL; \ + return WINED3DERR_OUTOFVIDEOMEMORY; \ + } \ + *pp##type = (IWineD3D##type *) object; \ + IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\ + TRACE("(%p) : Created resource %p\n", This, object); \ +} + +#define D3DINITIALIZEBASETEXTURE(_basetexture) { \ + _basetexture.levels = Levels; \ + _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \ + _basetexture.LOD = 0; \ + _basetexture.dirty = TRUE; \ + _basetexture.is_srgb = FALSE; \ + _basetexture.srgb_mode_change_count = 0; \ +} + +/********************************************************** + * Global variable / Constants follow + **********************************************************/ +const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */ + +/********************************************************** + * IUnknown parts follows + **********************************************************/ + +static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj) +{ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DDevice)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1); + return refCount; +} + +static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p) : Releasing from %d\n", This, refCount + 1); + + if (!refCount) { + if (This->fbo) { + GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo)); + } + if (This->src_fbo) { + GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo)); + } + if (This->dst_fbo) { + GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo)); + } + + if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup); + + /* TODO: Clean up all the surfaces and textures! */ + /* NOTE: You must release the parent if the object was created via a callback + ** ***************************/ + + if (This->resources != NULL ) { + FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This); + dumpResources(This->resources); + } + + if(This->contexts) ERR("Context array not freed!\n"); + if (This->hardwareCursor) DestroyCursor(This->hardwareCursor); + This->haveHardwareCursor = FALSE; + + IWineD3D_Release(This->wineD3D); + This->wineD3D = NULL; + HeapFree(GetProcessHeap(), 0, This); + TRACE("Freed device %p\n", This); + This = NULL; + } + return refCount; +} + +/********************************************************** + * IWineD3DDevice implementation follows + **********************************************************/ +static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + *pParent = This->parent; + IUnknown_AddRef(This->parent); + return WINED3D_OK; +} + +static void CreateVBO(IWineD3DVertexBufferImpl *object) { + IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */ + GLenum error, glUsage; + DWORD vboUsage = object->resource.usage; + if(object->Flags & VBFLAG_VBOCREATEFAIL) { + WARN("Creating a vbo failed once, not trying again\n"); + return; + } + + TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage)); + + /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */ + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + + /* Make sure that the gl error is cleared. Do not use checkGLcall + * here because checkGLcall just prints a fixme and continues. However, + * if an error during VBO creation occurs we can fall back to non-vbo operation + * with full functionality(but performance loss) + */ + while(glGetError() != GL_NO_ERROR); + + /* Basically the FVF parameter passed to CreateVertexBuffer is no good + * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with + * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer + * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified + * to check if the rhw and color values are in the correct format. + */ + + GL_EXTCALL(glGenBuffersARB(1, &object->vbo)); + error = glGetError(); + if(object->vbo == 0 || error != GL_NO_ERROR) { + WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error); + goto error; + } + + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo)); + error = glGetError(); + if(error != GL_NO_ERROR) { + WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error); + goto error; + } + + /* Don't use static, because dx apps tend to update the buffer + * quite often even if they specify 0 usage. Because we always keep the local copy + * we never read from the vbo and can create a write only opengl buffer. + */ + switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) { + case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC: + case WINED3DUSAGE_DYNAMIC: + TRACE("Gl usage = GL_STREAM_DRAW\n"); + glUsage = GL_STREAM_DRAW_ARB; + break; + case WINED3DUSAGE_WRITEONLY: + default: + TRACE("Gl usage = GL_DYNAMIC_DRAW\n"); + glUsage = GL_DYNAMIC_DRAW_ARB; + break; + } + + /* Reserve memory for the buffer. The amount of data won't change + * so we are safe with calling glBufferData once with a NULL ptr and + * calling glBufferSubData on updates + */ + GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage)); + error = glGetError(); + if(error != GL_NO_ERROR) { + WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error); + goto error; + } + + LEAVE_GL(); + + return; + error: + /* Clean up all vbo init, but continue because we can work without a vbo :-) */ + FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n"); + if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo)); + object->vbo = 0; + object->Flags |= VBFLAG_VBOCREATEFAIL; + LEAVE_GL(); + return; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage, + DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle, + IUnknown *parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexBufferImpl *object; + WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */ + int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion; + BOOL conv; + + if(Size == 0) { + WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n"); + *ppVertexBuffer = NULL; + return WINED3DERR_INVALIDCALL; + } + + D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size) + + TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object); + *ppVertexBuffer = (IWineD3DVertexBuffer *)object; + + if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */ + object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size); + } + object->fvf = FVF; + + /* Observations show that drawStridedSlow is faster on dynamic VBs than converting + + * drawStridedFast (half-life 2). + * + * Basically converting the vertices in the buffer is quite expensive, and observations + * show that drawStridedSlow is faster than converting + uploading + drawStridedFast. + * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers. + * + * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify + * the range of vertices being locked, so each lock will require the whole buffer to be transformed. + * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus + * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for + * dx7 apps. + * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any + * more. In this call we can convert dx7 buffers too. + */ + conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR)); + if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && + (dxVersion > 7 || !conv) ) { + CreateVBO(object); + } + return WINED3D_OK; +} + +static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) { + GLenum error, glUsage; + TRACE("Creating VBO for Index Buffer %p\n", object); + + /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is + * restored on the next draw + */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + + /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */ + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + + while(glGetError()); + + GL_EXTCALL(glGenBuffersARB(1, &object->vbo)); + error = glGetError(); + if(error != GL_NO_ERROR || object->vbo == 0) { + ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error); + goto out; + } + + GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo)); + error = glGetError(); + if(error != GL_NO_ERROR) { + ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error); + goto out; + } + + /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem + * copy no readback will be needed + */ + glUsage = GL_STATIC_DRAW_ARB; + GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage)); + error = glGetError(); + if(error != GL_NO_ERROR) { + ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error); + goto out; + } + LEAVE_GL(); + TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object); + return; + +out: + GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0)); + GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo)); + LEAVE_GL(); + object->vbo = 0; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage, + WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer, + HANDLE *sharedHandle, IUnknown *parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DIndexBufferImpl *object; + TRACE("(%p) Creating index buffer\n", This); + + /* Allocate the storage for the device */ + D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length) + + if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */ + object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size); + } + + if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) { + CreateIndexBufferVBO(This, object); + } + + TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format, + debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory); + *ppIndexBuffer = (IWineD3DIndexBuffer *) object; + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DStateBlockImpl *object; + int i, j; + HRESULT temp_result; + + D3DCREATEOBJECTINSTANCE(object, StateBlock) + object->blockType = Type; + + for(i = 0; i < LIGHTMAP_SIZE; i++) { + list_init(&object->lightMap[i]); + } + + /* Special case - Used during initialization to produce a placeholder stateblock + so other functions called can update a state block */ + if (Type == WINED3DSBT_INIT) { + /* Don't bother increasing the reference count otherwise a device will never + be freed due to circular dependencies */ + return WINED3D_OK; + } + + temp_result = allocate_shader_constants(object); + if (WINED3D_OK != temp_result) + return temp_result; + + /* Otherwise, might as well set the whole state block to the appropriate values */ + if (This->stateBlock != NULL) + stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock); + else + memset(object->streamFreq, 1, sizeof(object->streamFreq)); + + /* Reset the ref and type after kludging it */ + object->wineD3DDevice = This; + object->ref = 1; + object->blockType = Type; + + TRACE("Updating changed flags appropriate for type %d\n", Type); + + if (Type == WINED3DSBT_ALL) { + + TRACE("ALL => Pretend everything has changed\n"); + stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE); + + /* Lights are not part of the changed / set structure */ + for(j = 0; j < LIGHTMAP_SIZE; j++) { + struct list *e; + LIST_FOR_EACH(e, &object->lightMap[j]) { + PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry); + light->changed = TRUE; + light->enabledChanged = TRUE; + } + } + for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) { + object->contained_render_states[j - 1] = j; + } + /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */ + for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) { + object->contained_transform_states[j - 1] = j; + } + object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE; + for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) { + object->contained_vs_consts_f[j] = j; + } + object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF); + for(j = 0; j < MAX_CONST_I; j++) { + object->contained_vs_consts_i[j] = j; + } + object->num_contained_vs_consts_i = MAX_CONST_I; + for(j = 0; j < MAX_CONST_B; j++) { + object->contained_vs_consts_b[j] = j; + } + object->num_contained_vs_consts_b = MAX_CONST_B; + for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) { + object->contained_ps_consts_f[j] = j; + } + object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF); + for(j = 0; j < MAX_CONST_I; j++) { + object->contained_ps_consts_i[j] = j; + } + object->num_contained_ps_consts_i = MAX_CONST_I; + for(j = 0; j < MAX_CONST_B; j++) { + object->contained_ps_consts_b[j] = j; + } + object->num_contained_ps_consts_b = MAX_CONST_B; + for(i = 0; i < MAX_TEXTURES; i++) { + for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) { + object->contained_tss_states[object->num_contained_tss_states].stage = i; + object->contained_tss_states[object->num_contained_tss_states].state = j; + object->num_contained_tss_states++; + } + } + for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) { + for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) { + object->contained_sampler_states[object->num_contained_sampler_states].stage = i; + object->contained_sampler_states[object->num_contained_sampler_states].state = j; + object->num_contained_sampler_states++; + } + } + + } else if (Type == WINED3DSBT_PIXELSTATE) { + + TRACE("PIXELSTATE => Pretend all pixel shates have changed\n"); + stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE); + + object->changed.pixelShader = TRUE; + + /* Pixel Shader Constants */ + for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) { + object->contained_ps_consts_f[i] = i; + object->changed.pixelShaderConstantsF[i] = TRUE; + } + object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF); + for (i = 0; i < MAX_CONST_B; ++i) { + object->contained_ps_consts_b[i] = i; + object->changed.pixelShaderConstantsB[i] = TRUE; + } + object->num_contained_ps_consts_b = MAX_CONST_B; + for (i = 0; i < MAX_CONST_I; ++i) { + object->contained_ps_consts_i[i] = i; + object->changed.pixelShaderConstantsI[i] = TRUE; + } + object->num_contained_ps_consts_i = MAX_CONST_I; + + for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) { + object->changed.renderState[SavedPixelStates_R[i]] = TRUE; + object->contained_render_states[i] = SavedPixelStates_R[i]; + } + object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R; + for (j = 0; j < MAX_TEXTURES; j++) { + for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) { + object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE; + object->contained_tss_states[object->num_contained_tss_states].stage = j; + object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i]; + object->num_contained_tss_states++; + } + } + for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) { + for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) { + object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE; + object->contained_sampler_states[object->num_contained_sampler_states].stage = j; + object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i]; + object->num_contained_sampler_states++; + } + } + + } else if (Type == WINED3DSBT_VERTEXSTATE) { + + TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n"); + stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE); + + object->changed.vertexShader = TRUE; + + /* Vertex Shader Constants */ + for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) { + object->changed.vertexShaderConstantsF[i] = TRUE; + object->contained_vs_consts_f[i] = i; + } + object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF); + for (i = 0; i < MAX_CONST_B; ++i) { + object->changed.vertexShaderConstantsB[i] = TRUE; + object->contained_vs_consts_b[i] = i; + } + object->num_contained_vs_consts_b = MAX_CONST_B; + for (i = 0; i < MAX_CONST_I; ++i) { + object->changed.vertexShaderConstantsI[i] = TRUE; + object->contained_vs_consts_i[i] = i; + } + object->num_contained_vs_consts_i = MAX_CONST_I; + for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) { + object->changed.renderState[SavedVertexStates_R[i]] = TRUE; + object->contained_render_states[i] = SavedVertexStates_R[i]; + } + object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R; + for (j = 0; j < MAX_TEXTURES; j++) { + for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) { + object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE; + object->contained_tss_states[object->num_contained_tss_states].stage = j; + object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i]; + object->num_contained_tss_states++; + } + } + for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){ + for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) { + object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE; + object->contained_sampler_states[object->num_contained_sampler_states].stage = j; + object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i]; + object->num_contained_sampler_states++; + } + } + + for(j = 0; j < LIGHTMAP_SIZE; j++) { + struct list *e; + LIST_FOR_EACH(e, &object->lightMap[j]) { + PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry); + light->changed = TRUE; + light->enabledChanged = TRUE; + } + } + } else { + FIXME("Unrecognized state block type %d\n", Type); + } + + TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object); + return WINED3D_OK; +} + +/* ************************************ +MSDN: +[in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware. + +Discard + [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise. + +If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface. + +******************************** */ + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */ + unsigned int Size = 1; + const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL); + TRACE("(%p) Create surface\n",This); + + /** FIXME: Check ranges on the inputs are valid + * MSDN + * MultisampleQuality + * [in] Quality level. The valid range is between zero and one less than the level + * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType. + * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality + * values of paired render targets, depth stencil surfaces, and the MultiSample type + * must all match. + *******************************/ + + + /** + * TODO: Discard MSDN + * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise. + * + * If this flag is set, the contents of the depth stencil buffer will be + * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface + * with a different depth surface. + * + *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG. + ***************************/ + + if(MultisampleQuality < 0) { + FIXME("Invalid multisample level %d\n", MultisampleQuality); + return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */ + } + + if(MultisampleQuality > 0) { + FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality); + MultisampleQuality=0; + } + + /** FIXME: Check that the format is supported + * by the device. + *******************************/ + + /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since + * it is based around 4x4 pixel blocks it requires padding, so allocate enough + * space! + *********************************/ + if (WINED3DFMT_UNKNOWN == Format) { + Size = 0; + } else if (Format == WINED3DFMT_DXT1) { + /* DXT1 is half byte per pixel */ + Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1; + + } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 || + Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) { + Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)); + } else { + /* The pitch is a multiple of 4 bytes */ + Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1); + Size *= Height; + } + + /** Create and initialise the surface resource **/ + D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size) + /* "Standalone" surface */ + IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL); + + object->currentDesc.Width = Width; + object->currentDesc.Height = Height; + object->currentDesc.MultiSampleType = MultiSample; + object->currentDesc.MultiSampleQuality = MultisampleQuality; + object->glDescription.level = Level; + + /* Flags */ + object->Flags = 0; + object->Flags |= Discard ? SFLAG_DISCARD : 0; + object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0; + object->Flags |= Lockable ? SFLAG_LOCKABLE : 0; + + + if (WINED3DFMT_UNKNOWN != Format) { + object->bytesPerPixel = tableEntry->bpp; + } else { + object->bytesPerPixel = 0; + } + + /** TODO: change this into a texture transform matrix so that it's processed in hardware **/ + + TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM); + + /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly + * this function is too deep to need to care about things like this. + * Levels need to be checked too, and possibly Type since they all affect what can be done. + * ****************************************/ + switch(Pool) { + case WINED3DPOOL_SCRATCH: + if(!Lockable) + FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE " + "which are mutually exclusive, setting lockable to TRUE\n"); + Lockable = TRUE; + break; + case WINED3DPOOL_SYSTEMMEM: + if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, " + "this is acceptable but unexpected (I can't know how the surface can be usable!)\n"); + case WINED3DPOOL_MANAGED: + if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a " + "Usage of DYNAMIC which are mutually exclusive, not doing " + "anything just telling you.\n"); + break; + case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */ + if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET) + && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable) + WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n"); + break; + default: + FIXME("(%p) Unknown pool %d\n", This, Pool); + break; + }; + + if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) { + FIXME("Trying to create a render target that isn't in the default pool\n"); + } + + /* mark the texture as dirty so that it gets loaded first time around*/ + IWineD3DSurface_AddDirtyRect(*ppSurface, NULL); + TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n", + This, Width, Height, Format, debug_d3dformat(Format), + (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size); + + /* Store the DirectDraw primary surface. This is the first rendertarget surface created */ + if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) ) + This->ddraw_primary = (IWineD3DSurface *) object; + + /* Look at the implementation and set the correct Vtable */ + switch(Impl) { + case SURFACE_OPENGL: + /* Check if a 3D adapter is available when creating gl surfaces */ + if(!This->adapter) { + ERR("OpenGL surfaces are not available without opengl\n"); + HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory); + HeapFree(GetProcessHeap(), 0, object); + return WINED3DERR_NOTAVAILABLE; + } + break; + + case SURFACE_GDI: + object->lpVtbl = &IWineGDISurface_Vtbl; + break; + + default: + /* To be sure to catch this */ + ERR("Unknown requested surface implementation %d!\n", Impl); + IWineD3DSurface_Release((IWineD3DSurface *) object); + return WINED3DERR_INVALIDCALL; + } + + list_init(&object->renderbuffers); + + /* Call the private setup routine */ + return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object ); + +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels, + DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, + IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent, + D3DCB_CREATESURFACEFN D3DCB_CreateSurface) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DTextureImpl *object; + unsigned int i; + UINT tmpW; + UINT tmpH; + HRESULT hr; + unsigned int pow2Width; + unsigned int pow2Height; + + + TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage); + TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n", + Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent); + + /* TODO: It should only be possible to create textures for formats + that are reported as supported */ + if (WINED3DFMT_UNKNOWN >= Format) { + WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This); + return WINED3DERR_INVALIDCALL; + } + + D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0); + D3DINITIALIZEBASETEXTURE(object->baseTexture); + object->width = Width; + object->height = Height; + + /** Non-power2 support **/ + if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) { + pow2Width = Width; + pow2Height = Height; + } else { + /* Find the nearest pow2 match */ + pow2Width = pow2Height = 1; + while (pow2Width < Width) pow2Width <<= 1; + while (pow2Height < Height) pow2Height <<= 1; + } + + /** FIXME: add support for real non-power-two if it's provided by the video card **/ + /* Precalculated scaling for 'faked' non power of two texture coords */ + object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width)); + object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height)); + TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY); + + /* Calculate levels for mip mapping */ + if (Levels == 0) { + TRACE("calculating levels %d\n", object->baseTexture.levels); + object->baseTexture.levels++; + tmpW = Width; + tmpH = Height; + while (tmpW > 1 || tmpH > 1) { + tmpW = max(1, tmpW >> 1); + tmpH = max(1, tmpH >> 1); + object->baseTexture.levels++; + } + TRACE("Calculated levels = %d\n", object->baseTexture.levels); + } + + /* Generate all the surfaces */ + tmpW = Width; + tmpH = Height; + for (i = 0; i < object->baseTexture.levels; i++) + { + /* use the callback to create the texture surface */ + hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL); + if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) { + FIXME("Failed to create surface %p\n", object); + /* clean up */ + object->surfaces[i] = NULL; + IWineD3DTexture_Release((IWineD3DTexture *)object); + + *ppTexture = NULL; + return hr; + } + + IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object); + TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]); + /* calculate the next mipmap level */ + tmpW = max(1, tmpW >> 1); + tmpH = max(1, tmpH >> 1); + } + + TRACE("(%p) : Created texture %p\n", This, object); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface, + UINT Width, UINT Height, UINT Depth, + UINT Levels, DWORD Usage, + WINED3DFORMAT Format, WINED3DPOOL Pool, + IWineD3DVolumeTexture **ppVolumeTexture, + HANDLE *pSharedHandle, IUnknown *parent, + D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVolumeTextureImpl *object; + unsigned int i; + UINT tmpW; + UINT tmpH; + UINT tmpD; + + /* TODO: It should only be possible to create textures for formats + that are reported as supported */ + if (WINED3DFMT_UNKNOWN >= Format) { + WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This); + return WINED3DERR_INVALIDCALL; + } + + D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0); + D3DINITIALIZEBASETEXTURE(object->baseTexture); + + TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height, + Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool)); + + object->width = Width; + object->height = Height; + object->depth = Depth; + + /* Calculate levels for mip mapping */ + if (Levels == 0) { + object->baseTexture.levels++; + tmpW = Width; + tmpH = Height; + tmpD = Depth; + while (tmpW > 1 || tmpH > 1 || tmpD > 1) { + tmpW = max(1, tmpW >> 1); + tmpH = max(1, tmpH >> 1); + tmpD = max(1, tmpD >> 1); + object->baseTexture.levels++; + } + TRACE("Calculated levels = %d\n", object->baseTexture.levels); + } + + /* Generate all the surfaces */ + tmpW = Width; + tmpH = Height; + tmpD = Depth; + + for (i = 0; i < object->baseTexture.levels; i++) + { + HRESULT hr; + /* Create the volume */ + hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage, + (IWineD3DVolume **)&object->volumes[i], pSharedHandle); + + if(FAILED(hr)) { + ERR("Creating a volume for the volume texture failed(%08x)\n", hr); + IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object); + *ppVolumeTexture = NULL; + return hr; + } + + /* Set its container to this object */ + IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object); + + /* calcualte the next mipmap level */ + tmpW = max(1, tmpW >> 1); + tmpH = max(1, tmpH >> 1); + tmpD = max(1, tmpD >> 1); + } + + *ppVolumeTexture = (IWineD3DVolumeTexture *) object; + TRACE("(%p) : Created volume texture %p\n", This, object); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, + UINT Width, UINT Height, UINT Depth, + DWORD Usage, + WINED3DFORMAT Format, WINED3DPOOL Pool, + IWineD3DVolume** ppVolume, + HANDLE* pSharedHandle, IUnknown *parent) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/ + const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL); + + D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth)) + + TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height, + Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool)); + + object->currentDesc.Width = Width; + object->currentDesc.Height = Height; + object->currentDesc.Depth = Depth; + object->bytesPerPixel = formatDesc->bpp; + + /** Note: Volume textures cannot be dxtn, hence no need to check here **/ + object->lockable = TRUE; + object->locked = FALSE; + memset(&object->lockedBox, 0, sizeof(WINED3DBOX)); + object->dirty = TRUE; + + return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL); +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, + UINT Levels, DWORD Usage, + WINED3DFORMAT Format, WINED3DPOOL Pool, + IWineD3DCubeTexture **ppCubeTexture, + HANDLE *pSharedHandle, IUnknown *parent, + D3DCB_CREATESURFACEFN D3DCB_CreateSurface) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/ + unsigned int i, j; + UINT tmpW; + HRESULT hr; + unsigned int pow2EdgeLength = EdgeLength; + + /* TODO: It should only be possible to create textures for formats + that are reported as supported */ + if (WINED3DFMT_UNKNOWN >= Format) { + WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This); + return WINED3DERR_INVALIDCALL; + } + + if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) { + WARN("(%p) : Tried to create not supported cube texture\n", This); + return WINED3DERR_INVALIDCALL; + } + + D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0); + D3DINITIALIZEBASETEXTURE(object->baseTexture); + + TRACE("(%p) Create Cube Texture\n", This); + + /** Non-power2 support **/ + + /* Find the nearest pow2 match */ + pow2EdgeLength = 1; + while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1; + + object->edgeLength = EdgeLength; + /* TODO: support for native non-power 2 */ + /* Precalculated scaling for 'faked' non power of two texture coords */ + object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength); + + /* Calculate levels for mip mapping */ + if (Levels == 0) { + object->baseTexture.levels++; + tmpW = EdgeLength; + while (tmpW > 1) { + tmpW = max(1, tmpW >> 1); + object->baseTexture.levels++; + } + TRACE("Calculated levels = %d\n", object->baseTexture.levels); + } + + /* Generate all the surfaces */ + tmpW = EdgeLength; + for (i = 0; i < object->baseTexture.levels; i++) { + + /* Create the 6 faces */ + for (j = 0; j < 6; j++) { + + hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool, + i /* Level */, j, &object->surfaces[j][i],pSharedHandle); + + if(hr!= WINED3D_OK) { + /* clean up */ + int k; + int l; + for (l = 0; l < j; l++) { + IWineD3DSurface_Release(object->surfaces[j][i]); + } + for (k = 0; k < i; k++) { + for (l = 0; l < 6; l++) { + IWineD3DSurface_Release(object->surfaces[l][j]); + } + } + + FIXME("(%p) Failed to create surface\n",object); + HeapFree(GetProcessHeap(),0,object); + *ppCubeTexture = NULL; + return hr; + } + IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object); + TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]); + } + tmpW = max(1, tmpW >> 1); + } + + TRACE("(%p) : Created Cube Texture %p\n", This, object); + *ppCubeTexture = (IWineD3DCubeTexture *) object; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */ + HRESULT hr = WINED3DERR_NOTAVAILABLE; + + /* Just a check to see if we support this type of query */ + switch(Type) { + case WINED3DQUERYTYPE_OCCLUSION: + TRACE("(%p) occlusion query\n", This); + if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) + hr = WINED3D_OK; + else + WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n"); + break; + + case WINED3DQUERYTYPE_EVENT: + if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) { + /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise + * Pretend to support it, faking this query does not do much harm except potentially lowering performance + */ + FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This); + } + hr = WINED3D_OK; + break; + + case WINED3DQUERYTYPE_VCACHE: + case WINED3DQUERYTYPE_RESOURCEMANAGER: + case WINED3DQUERYTYPE_VERTEXSTATS: + case WINED3DQUERYTYPE_TIMESTAMP: + case WINED3DQUERYTYPE_TIMESTAMPDISJOINT: + case WINED3DQUERYTYPE_TIMESTAMPFREQ: + case WINED3DQUERYTYPE_PIPELINETIMINGS: + case WINED3DQUERYTYPE_INTERFACETIMINGS: + case WINED3DQUERYTYPE_VERTEXTIMINGS: + case WINED3DQUERYTYPE_PIXELTIMINGS: + case WINED3DQUERYTYPE_BANDWIDTHTIMINGS: + case WINED3DQUERYTYPE_CACHEUTILIZATION: + default: + FIXME("(%p) Unhandled query type %d\n", This, Type); + } + if(NULL == ppQuery || hr != WINED3D_OK) { + return hr; + } + + D3DCREATEOBJECTINSTANCE(object, Query) + object->type = Type; + /* allocated the 'extended' data based on the type of query requested */ + switch(Type){ + case WINED3DQUERYTYPE_OCCLUSION: + if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) { + TRACE("(%p) Allocating data for an occlusion query\n", This); + object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData)); + GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId)); + break; + } + case WINED3DQUERYTYPE_EVENT: + /* TODO: GL_APPLE_fence */ + if(GL_SUPPORT(APPLE_FENCE)) { + object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); + GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId)); + checkGLcall("glGenFencesAPPLE"); + } else if(GL_SUPPORT(NV_FENCE)) { + object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData)); + GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId)); + checkGLcall("glGenFencesNV"); + } + break; + + case WINED3DQUERYTYPE_VCACHE: + case WINED3DQUERYTYPE_RESOURCEMANAGER: + case WINED3DQUERYTYPE_VERTEXSTATS: + case WINED3DQUERYTYPE_TIMESTAMP: + case WINED3DQUERYTYPE_TIMESTAMPDISJOINT: + case WINED3DQUERYTYPE_TIMESTAMPFREQ: + case WINED3DQUERYTYPE_PIPELINETIMINGS: + case WINED3DQUERYTYPE_INTERFACETIMINGS: + case WINED3DQUERYTYPE_VERTEXTIMINGS: + case WINED3DQUERYTYPE_PIXELTIMINGS: + case WINED3DQUERYTYPE_BANDWIDTHTIMINGS: + case WINED3DQUERYTYPE_CACHEUTILIZATION: + default: + object->extendedData = 0; + FIXME("(%p) Unhandled query type %d\n",This , Type); + } + TRACE("(%p) : Created Query %p\n", This, object); + return WINED3D_OK; +} + +/***************************************************************************** + * IWineD3DDeviceImpl_SetupFullscreenWindow + * + * Helper function that modifies a HWND's Style and ExStyle for proper + * fullscreen use. + * + * Params: + * iface: Pointer to the IWineD3DDevice interface + * window: Window to setup + * + *****************************************************************************/ +static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + LONG style, exStyle; + /* Don't do anything if an original style is stored. + * That shouldn't happen + */ + TRACE("(%p): Setting up window %p for exclusive mode\n", This, window); + if (This->style || This->exStyle) { + ERR("(%p): Want to change the window parameters of HWND %p, but " + "another style is stored for restoration afterwards\n", This, window); + } + + /* Get the parameters and save them */ + style = GetWindowLongW(window, GWL_STYLE); + exStyle = GetWindowLongW(window, GWL_EXSTYLE); + This->style = style; + This->exStyle = exStyle; + + /* Filter out window decorations */ + style &= ~WS_CAPTION; + style &= ~WS_THICKFRAME; + exStyle &= ~WS_EX_WINDOWEDGE; + exStyle &= ~WS_EX_CLIENTEDGE; + + /* Make sure the window is managed, otherwise we won't get keyboard input */ + style |= WS_POPUP | WS_SYSMENU; + + TRACE("Old style was %08x,%08x, setting to %08x,%08x\n", + This->style, This->exStyle, style, exStyle); + + SetWindowLongW(window, GWL_STYLE, style); + SetWindowLongW(window, GWL_EXSTYLE, exStyle); + + /* Inform the window about the update. */ + SetWindowPos(window, HWND_TOP, 0, 0, + This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED); + ShowWindow(window, SW_NORMAL); +} + +/***************************************************************************** + * IWineD3DDeviceImpl_RestoreWindow + * + * Helper function that restores a windows' properties when taking it out + * of fullscreen mode + * + * Params: + * iface: Pointer to the IWineD3DDevice interface + * window: Window to setup + * + *****************************************************************************/ +static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL + * switch, do nothing + */ + if (!This->style && !This->exStyle) return; + + TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n", + This, window, This->style, This->exStyle); + + SetWindowLongW(window, GWL_STYLE, This->style); + SetWindowLongW(window, GWL_EXSTYLE, This->exStyle); + + /* Delete the old values */ + This->style = 0; + This->exStyle = 0; + + /* Inform the window about the update */ + SetWindowPos(window, 0 /* InsertAfter, ignored */, + 0, 0, 0, 0, /* Pos, Size, ignored */ + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); +} + +/* example at http://www.fairyengine.com/articles/dxmultiviews.htm */ +static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain, + IUnknown* parent, + D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget, + D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + HDC hDc; + IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/ + HRESULT hr = WINED3D_OK; + IUnknown *bufferParent; + + TRACE("(%p) : Created Aditional Swap Chain\n", This); + + /** FIXME: Test under windows to find out what the life cycle of a swap chain is, + * does a device hold a reference to a swap chain giving them a lifetime of the device + * or does the swap chain notify the device of its destruction. + *******************************/ + + /* Check the params */ + if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) { + ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount); + return WINED3DERR_INVALIDCALL; + } else if (pPresentationParameters->BackBufferCount > 1) { + FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n"); + } + + D3DCREATEOBJECTINSTANCE(object, SwapChain) + + /********************* + * Lookup the window Handle and the relating X window handle + ********************/ + + /* Setup hwnd we are using, plus which display this equates to */ + object->win_handle = pPresentationParameters->hDeviceWindow; + if (!object->win_handle) { + object->win_handle = This->createParms.hFocusWindow; + } + + object->win_handle = GetAncestor(object->win_handle, GA_ROOT); + hDc = GetDC(object->win_handle); + TRACE("Using hDc %p\n", hDc); + + if (NULL == hDc) { + WARN("Failed to get a HDc for Window %p\n", object->win_handle); + return WINED3DERR_NOTAVAILABLE; + } + + object->orig_width = GetSystemMetrics(SM_CXSCREEN); + object->orig_height = GetSystemMetrics(SM_CYSCREEN); + object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES)); + ReleaseDC(object->win_handle, hDc); + + /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero, + * then the corresponding dimension of the client area of the hDeviceWindow + * (or the focus window, if hDeviceWindow is NULL) is taken. + **********************/ + + if (pPresentationParameters->Windowed && + ((pPresentationParameters->BackBufferWidth == 0) || + (pPresentationParameters->BackBufferHeight == 0))) { + + RECT Rect; + GetClientRect(object->win_handle, &Rect); + + if (pPresentationParameters->BackBufferWidth == 0) { + pPresentationParameters->BackBufferWidth = Rect.right; + TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth); + } + if (pPresentationParameters->BackBufferHeight == 0) { + pPresentationParameters->BackBufferHeight = Rect.bottom; + TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight); + } + } + + /* Put the correct figures in the presentation parameters */ + TRACE("Copying across presentation parameters\n"); + object->presentParms = *pPresentationParameters; + + TRACE("calling rendertarget CB\n"); + hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent, + parent, + object->presentParms.BackBufferWidth, + object->presentParms.BackBufferHeight, + object->presentParms.BackBufferFormat, + object->presentParms.MultiSampleType, + object->presentParms.MultiSampleQuality, + TRUE /* Lockable */, + &object->frontBuffer, + NULL /* pShared (always null)*/); + if (object->frontBuffer != NULL) { + IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object); + } else { + ERR("Failed to create the front buffer\n"); + goto error; + } + + /** + * Create an opengl context for the display visual + * NOTE: the visual is chosen as the window is created and the glcontext cannot + * use different properties after that point in time. FIXME: How to handle when requested format + * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one + * it chooses is identical to the one already being used! + **********************************/ + /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/ + + object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context)); + if(!object->context) + return E_OUTOFMEMORY; + object->num_contexts = 1; + + ENTER_GL(); + object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters); + LEAVE_GL(); + + if (!object->context[0]) { + ERR("Failed to create a new context\n"); + hr = WINED3DERR_NOTAVAILABLE; + goto error; + } else { + TRACE("Context created (HWND=%p, glContext=%p)\n", + object->win_handle, object->context[0]->glCtx); + } + + /********************* + * Windowed / Fullscreen + *******************/ + + /** + * TODO: MSDN says that we are only allowed one fullscreen swapchain per device, + * so we should really check to see if there is a fullscreen swapchain already + * I think Windows and X have different ideas about fullscreen, does a single head count as full screen? + **************************************/ + + if (!pPresentationParameters->Windowed) { + + DEVMODEW devmode; + HDC hdc; + int bpp = 0; + RECT clip_rc; + + /* Get info on the current display setup */ + hdc = GetDC(0); + bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(0, hdc); + + /* Change the display settings */ + memset(&devmode, 0, sizeof(devmode)); + devmode.dmSize = sizeof(devmode); + devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */ + devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth; + devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight; + ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL); + + /* For GetDisplayMode */ + This->ddraw_width = devmode.dmPelsWidth; + This->ddraw_height = devmode.dmPelsHeight; + This->ddraw_format = pPresentationParameters->BackBufferFormat; + + IWineD3DDevice_SetFullscreen(iface, TRUE); + + /* And finally clip mouse to our screen */ + SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight); + ClipCursor(&clip_rc); + } + + /********************* + * Create the back, front and stencil buffers + *******************/ + if(object->presentParms.BackBufferCount > 0) { + int i; + + object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount); + if(!object->backBuffer) { + ERR("Out of memory\n"); + hr = E_OUTOFMEMORY; + goto error; + } + + for(i = 0; i < object->presentParms.BackBufferCount; i++) { + TRACE("calling rendertarget CB\n"); + hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent, + parent, + object->presentParms.BackBufferWidth, + object->presentParms.BackBufferHeight, + object->presentParms.BackBufferFormat, + object->presentParms.MultiSampleType, + object->presentParms.MultiSampleQuality, + TRUE /* Lockable */, + &object->backBuffer[i], + NULL /* pShared (always null)*/); + if(hr == WINED3D_OK && object->backBuffer[i]) { + IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object); + } else { + ERR("Cannot create new back buffer\n"); + goto error; + } + ENTER_GL(); + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer(GL_BACK)"); + LEAVE_GL(); + } + } else { + object->backBuffer = NULL; + + /* Single buffering - draw to front buffer */ + ENTER_GL(); + glDrawBuffer(GL_FRONT); + checkGLcall("glDrawBuffer(GL_FRONT)"); + LEAVE_GL(); + } + + /* Under directX swapchains share the depth stencil, so only create one depth-stencil */ + if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) { + TRACE("Creating depth stencil buffer\n"); + if (This->depthStencilBuffer == NULL ) { + hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent, + parent, + object->presentParms.BackBufferWidth, + object->presentParms.BackBufferHeight, + object->presentParms.AutoDepthStencilFormat, + object->presentParms.MultiSampleType, + object->presentParms.MultiSampleQuality, + FALSE /* FIXME: Discard */, + &This->depthStencilBuffer, + NULL /* pShared (always null)*/ ); + if (This->depthStencilBuffer != NULL) + IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0); + } + + /** TODO: A check on width, height and multisample types + *(since the zbuffer must be at least as large as the render target and have the same multisample parameters) + ****************************/ + object->wantsDepthStencilBuffer = TRUE; + } else { + object->wantsDepthStencilBuffer = FALSE; + } + + TRACE("Created swapchain %p\n", object); + TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer); + return WINED3D_OK; + +error: + if (object->backBuffer) { + int i; + for(i = 0; i < object->presentParms.BackBufferCount; i++) { + if(object->backBuffer[i]) { + IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent); + IUnknown_Release(bufferParent); /* once for the get parent */ + if (IUnknown_Release(bufferParent) > 0) { + FIXME("(%p) Something's still holding the back buffer\n",This); + } + } + } + HeapFree(GetProcessHeap(), 0, object->backBuffer); + object->backBuffer = NULL; + } + if(object->context[0]) + DestroyContext(This, object->context[0]); + if(object->frontBuffer) { + IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent); + IUnknown_Release(bufferParent); /* once for the get parent */ + if (IUnknown_Release(bufferParent) > 0) { + FIXME("(%p) Something's still holding the front buffer\n",This); + } + } + HeapFree(GetProcessHeap(), 0, object); + return hr; +} + +/** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/ +static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)\n", This); + + return This->NumberOfSwapChains; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : swapchain %d\n", This, iSwapChain); + + if(iSwapChain < This->NumberOfSwapChains) { + *pSwapChain = This->swapchains[iSwapChain]; + IWineD3DSwapChain_AddRef(*pSwapChain); + TRACE("(%p) returning %p\n", This, *pSwapChain); + return WINED3D_OK; + } else { + TRACE("Swapchain out of range\n"); + *pSwapChain = NULL; + return WINED3DERR_INVALIDCALL; + } +} + +/***** + * Vertex Declaration + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, + IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexDeclarationImpl *object = NULL; + HRESULT hr = WINED3D_OK; + + TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n", + This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration); + + D3DCREATEOBJECTINSTANCE(object, VertexDeclaration) + + hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count); + + return hr; +} + +static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) { + + unsigned int idx, idx2; + unsigned int offset; + BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0; + BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW; + BOOL has_blend_idx = has_blend && + (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) || + (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) || + (fvf & WINED3DFVF_LASTBETA_UBYTE4)); + BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0; + BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0; + BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0; + BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0; + + DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT; + DWORD texcoords = (fvf & 0x00FF0000) >> 16; + + WINED3DVERTEXELEMENT end_element = WINED3DDECL_END(); + WINED3DVERTEXELEMENT *elements = NULL; + + unsigned int size; + DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1); + if (has_blend_idx) num_blends--; + + /* Compute declaration size */ + size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal + + has_psize + has_diffuse + has_specular + num_textures + 1; + + /* convert the declaration */ + elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT)); + if (!elements) + return 0; + + memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT)); + idx = 0; + if (has_pos) { + if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) { + elements[idx].Type = WINED3DDECLTYPE_FLOAT4; + elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT; + } + else { + elements[idx].Type = WINED3DDECLTYPE_FLOAT3; + elements[idx].Usage = WINED3DDECLUSAGE_POSITION; + } + elements[idx].UsageIndex = 0; + idx++; + } + if (has_blend && (num_blends > 0)) { + if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)) + elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR; + else + elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1; + elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_blend_idx) { + if (fvf & WINED3DFVF_LASTBETA_UBYTE4 || + (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))) + elements[idx].Type = WINED3DDECLTYPE_UBYTE4; + else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) + elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR; + else + elements[idx].Type = WINED3DDECLTYPE_FLOAT1; + elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_normal) { + elements[idx].Type = WINED3DDECLTYPE_FLOAT3; + elements[idx].Usage = WINED3DDECLUSAGE_NORMAL; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_psize) { + elements[idx].Type = WINED3DDECLTYPE_FLOAT1; + elements[idx].Usage = WINED3DDECLUSAGE_PSIZE; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_diffuse) { + elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR; + elements[idx].Usage = WINED3DDECLUSAGE_COLOR; + elements[idx].UsageIndex = 0; + idx++; + } + if (has_specular) { + elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR; + elements[idx].Usage = WINED3DDECLUSAGE_COLOR; + elements[idx].UsageIndex = 1; + idx++; + } + for (idx2 = 0; idx2 < num_textures; idx2++) { + unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03; + switch (numcoords) { + case WINED3DFVF_TEXTUREFORMAT1: + elements[idx].Type = WINED3DDECLTYPE_FLOAT1; + break; + case WINED3DFVF_TEXTUREFORMAT2: + elements[idx].Type = WINED3DDECLTYPE_FLOAT2; + break; + case WINED3DFVF_TEXTUREFORMAT3: + elements[idx].Type = WINED3DDECLTYPE_FLOAT3; + break; + case WINED3DFVF_TEXTUREFORMAT4: + elements[idx].Type = WINED3DDECLTYPE_FLOAT4; + break; + } + elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD; + elements[idx].UsageIndex = idx2; + idx++; + } + + /* Now compute offsets, and initialize the rest of the fields */ + for (idx = 0, offset = 0; idx < size-1; idx++) { + elements[idx].Stream = 0; + elements[idx].Method = WINED3DDECLMETHOD_DEFAULT; + elements[idx].Offset = offset; + offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type); + } + + *ppVertexElements = elements; + return size; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) { + WINED3DVERTEXELEMENT* elements = NULL; + size_t size; + DWORD hr; + + size = ConvertFvfToDeclaration(Fvf, &elements); + if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY; + + hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size); + HeapFree(GetProcessHeap(), 0, elements); + if (hr != S_OK) return hr; + + return WINED3D_OK; +} + +/* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */ +static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */ + HRESULT hr = WINED3D_OK; + D3DCREATESHADEROBJECTINSTANCE(object, VertexShader) + object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins; + + TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader); + + if (vertex_declaration) { + IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration); + } + + hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction); + + if (WINED3D_OK != hr) { + FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface); + IWineD3DVertexShader_Release(*ppVertexShader); + return WINED3DERR_INVALIDCALL; + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */ + HRESULT hr = WINED3D_OK; + + D3DCREATESHADEROBJECTINSTANCE(object, PixelShader) + object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins; + hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction); + if (WINED3D_OK == hr) { + TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader); + } else { + WARN("(%p) : Failed to create pixel shader\n", This); + } + + return hr; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DPaletteImpl *object; + HRESULT hr; + TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent); + + /* Create the new object */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl)); + if(!object) { + ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n"); + return E_OUTOFMEMORY; + } + + object->lpVtbl = &IWineD3DPalette_Vtbl; + object->ref = 1; + object->Flags = Flags; + object->parent = Parent; + object->wineD3DDevice = This; + object->palNumEntries = IWineD3DPaletteImpl_Size(Flags); + + object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion)); + + if(!object->hpal) { + HeapFree( GetProcessHeap(), 0, object); + return E_OUTOFMEMORY; + } + + hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt); + if(FAILED(hr)) { + IWineD3DPalette_Release((IWineD3DPalette *) object); + return hr; + } + + *Palette = (IWineD3DPalette *) object; + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DSwapChainImpl *swapchain; + HRESULT hr; + DWORD state; + + TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain); + if(This->d3d_initialized) return WINED3DERR_INVALIDCALL; + + /* TODO: Test if OpenGL is compiled in and loaded */ + + TRACE("(%p) : Creating stateblock\n", This); + /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */ + hr = IWineD3DDevice_CreateStateBlock(iface, + WINED3DSBT_INIT, + (IWineD3DStateBlock **)&This->stateBlock, + NULL); + if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */ + WARN("Failed to create stateblock\n"); + return hr; + } + TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock); + This->updateStateBlock = This->stateBlock; + IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock); + + hr = allocate_shader_constants(This->updateStateBlock); + if (WINED3D_OK != hr) + return hr; + + This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers)); + This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers)); + This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers)); + + /* Initialize the texture unit mapping to a 1:1 mapping */ + for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) { + if (state < GL_LIMITS(fragment_samplers)) { + This->texUnitMap[state] = state; + This->rev_tex_unit_map[state] = state; + } else { + This->texUnitMap[state] = -1; + This->rev_tex_unit_map[state] = -1; + } + } + + /* Setup the implicit swapchain */ + TRACE("Creating implicit swapchain\n"); + hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain); + if (FAILED(hr) || !swapchain) { + WARN("Failed to create implicit swapchain\n"); + return hr; + } + + This->NumberOfSwapChains = 1; + This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *)); + if(!This->swapchains) { + ERR("Out of memory!\n"); + IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain); + return E_OUTOFMEMORY; + } + This->swapchains[0] = (IWineD3DSwapChain *) swapchain; + + if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle); + + if(swapchain->backBuffer && swapchain->backBuffer[0]) { + TRACE("Setting rendertarget to %p\n", swapchain->backBuffer); + This->render_targets[0] = swapchain->backBuffer[0]; + This->lastActiveRenderTarget = swapchain->backBuffer[0]; + } + else { + TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer); + This->render_targets[0] = swapchain->frontBuffer; + This->lastActiveRenderTarget = swapchain->frontBuffer; + } + IWineD3DSurface_AddRef(This->render_targets[0]); + This->activeContext = swapchain->context[0]; + This->lastThread = GetCurrentThreadId(); + + /* Depth Stencil support */ + This->stencilBufferTarget = This->depthStencilBuffer; + if (NULL != This->stencilBufferTarget) { + IWineD3DSurface_AddRef(This->stencilBufferTarget); + } + + /* Set up some starting GL setup */ + ENTER_GL(); + + /* Setup all the devices defaults */ + IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock); +#if 0 + IWineD3DImpl_CheckGraphicsMemory(); +#endif + + { /* Set a default viewport */ + WINED3DVIEWPORT vp; + vp.X = 0; + vp.Y = 0; + vp.Width = pPresentationParameters->BackBufferWidth; + vp.Height = pPresentationParameters->BackBufferHeight; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp); + } + + /* Initialize the current view state */ + This->view_ident = 1; + This->contexts[0]->last_was_rhw = 0; + glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights); + checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)"); + + switch(wined3d_settings.offscreen_rendering_mode) { + case ORM_FBO: + case ORM_PBUFFER: + This->offscreenBuffer = GL_BACK; + break; + + case ORM_BACKBUFFER: + { + if(GL_LIMITS(aux_buffers) > 0) { + TRACE("Using auxilliary buffer for offscreen rendering\n"); + This->offscreenBuffer = GL_AUX0; + } else { + TRACE("Using back buffer for offscreen rendering\n"); + This->offscreenBuffer = GL_BACK; + } + } + } + + TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This); + LEAVE_GL(); + + /* Clear the screen */ + IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, + WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0, + 0x00, 1.0, 0); + + This->d3d_initialized = TRUE; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + int sampler; + UINT i; + TRACE("(%p)\n", This); + + if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL; + + /* I don't think that the interface guarants that the device is destroyed from the same thread + * it was created. Thus make sure a context is active for the glDelete* calls + */ + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + + TRACE("Deleting high order patches\n"); + for(i = 0; i < PATCHMAP_SIZE; i++) { + struct list *e1, *e2; + struct WineD3DRectPatch *patch; + LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) { + patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry); + IWineD3DDevice_DeletePatch(iface, patch->Handle); + } + } + + /* Delete the pbuffer context if there is any */ + if(This->pbufferContext) DestroyContext(This, This->pbufferContext); + + /* Delete the mouse cursor texture */ + if(This->cursorTexture) { + ENTER_GL(); + glDeleteTextures(1, &This->cursorTexture); + LEAVE_GL(); + This->cursorTexture = 0; + } + + for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) { + IWineD3DDevice_SetTexture(iface, sampler, NULL); + } + for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) { + IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL); + } + + /* Release the update stateblock */ + if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){ + if(This->updateStateBlock != This->stateBlock) + FIXME("(%p) Something's still holding the Update stateblock\n",This); + } + This->updateStateBlock = NULL; + + { /* because were not doing proper internal refcounts releasing the primary state block + causes recursion with the extra checks in ResourceReleased, to avoid this we have + to set this->stateBlock = NULL; first */ + IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock; + This->stateBlock = NULL; + + /* Release the stateblock */ + if(IWineD3DStateBlock_Release(stateBlock) > 0){ + FIXME("(%p) Something's still holding the Update stateblock\n",This); + } + } + + /* Release the buffers (with sanity checks)*/ + TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget); + if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){ + if(This->depthStencilBuffer != This->stencilBufferTarget) + FIXME("(%p) Something's still holding the depthStencilBuffer\n",This); + } + This->stencilBufferTarget = NULL; + + TRACE("Releasing the render target at %p\n", This->render_targets[0]); + if(IWineD3DSurface_Release(This->render_targets[0]) >0){ + /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */ + } + TRACE("Setting rendertarget to NULL\n"); + This->render_targets[0] = NULL; + + if (This->depthStencilBuffer) { + if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) { + FIXME("(%p) Something's still holding the depthStencilBuffer\n", This); + } + This->depthStencilBuffer = NULL; + } + + for(i=0; i < This->NumberOfSwapChains; i++) { + TRACE("Releasing the implicit swapchain %d\n", i); + if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) { + FIXME("(%p) Something's still holding the implicit swapchain\n", This); + } + } + + HeapFree(GetProcessHeap(), 0, This->swapchains); + This->swapchains = NULL; + This->NumberOfSwapChains = 0; + + HeapFree(GetProcessHeap(), 0, This->render_targets); + HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments); + HeapFree(GetProcessHeap(), 0, This->draw_buffers); + This->render_targets = NULL; + This->fbo_color_attachments = NULL; + This->draw_buffers = NULL; + + + This->d3d_initialized = FALSE; + return WINED3D_OK; +} + +static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false"); + + /* Setup the window for fullscreen mode */ + if(fullscreen && !This->ddraw_fullscreen) { + IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window); + } else if(!fullscreen && This->ddraw_fullscreen) { + IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window); + } + + /* DirectDraw apps can change between fullscreen and windowed mode after device creation with + * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this. + * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag + * separately. + */ + This->ddraw_fullscreen = fullscreen; +} + +/* Enables thead safety in the wined3d device and its resources. Called by DirectDraw + * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from + * CreateDevice if D3DCREATE_MULTITHREADED is passed. + * + * There is no way to deactivate thread safety once it is enabled + */ +static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + + /*For now just store the flag(needed in case of ddraw) */ + This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED; + + return; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) { + DEVMODEW devmode; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + LONG ret; + const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL); + RECT clip_rc; + + TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format)); + + /* Resize the screen even without a window: + * The app could have unset it with SetCooperativeLevel, but not called + * RestoreDisplayMode first. Then the release will call RestoreDisplayMode, + * but we don't have any hwnd + */ + + memset(&devmode, 0, sizeof(devmode)); + devmode.dmSize = sizeof(devmode); + devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + devmode.dmBitsPerPel = formatDesc->bpp * 8; + if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32; + devmode.dmPelsWidth = pMode->Width; + devmode.dmPelsHeight = pMode->Height; + + devmode.dmDisplayFrequency = pMode->RefreshRate; + if (pMode->RefreshRate != 0) { + devmode.dmFields |= DM_DISPLAYFREQUENCY; + } + + /* Only change the mode if necessary */ + if( (This->ddraw_width == pMode->Width) && + (This->ddraw_height == pMode->Height) && + (This->ddraw_format == pMode->Format) && + (pMode->RefreshRate == 0) ) { + return WINED3D_OK; + } + + ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL); + if (ret != DISP_CHANGE_SUCCESSFUL) { + if(devmode.dmDisplayFrequency != 0) { + WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n"); + devmode.dmFields &= ~DM_DISPLAYFREQUENCY; + devmode.dmDisplayFrequency = 0; + ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL; + } + if(ret != DISP_CHANGE_SUCCESSFUL) { + return WINED3DERR_NOTAVAILABLE; + } + } + + /* Store the new values */ + This->ddraw_width = pMode->Width; + This->ddraw_height = pMode->Height; + This->ddraw_format = pMode->Format; + + /* Only do this with a window of course */ + if(This->ddraw_window) + MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE); + + /* And finally clip mouse to our screen */ + SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height); + ClipCursor(&clip_rc); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + *ppD3D= This->wineD3D; + TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D); + IWineD3D_AddRef(*ppD3D); + return WINED3D_OK; +} + +static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) { + /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever) + * into the video ram as possible and seeing how many fit + * you can also get the correct initial value from nvidia and ATI's driver via X + * texture memory is video memory + AGP memory + *******************/ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + static BOOL showfixmes = TRUE; + if (showfixmes) { + FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This, + (wined3d_settings.emulated_textureram/(1024*1024)), + ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); + showfixmes = FALSE; + } + TRACE("(%p) : simulating %dMB, returning %dMB left\n", This, + (wined3d_settings.emulated_textureram/(1024*1024)), + ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024))); + /* return simulated texture memory left */ + return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram); +} + + + +/***** + * Get / Set FVF + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + /* Update the current state block */ + This->updateStateBlock->changed.fvf = TRUE; + + if(This->updateStateBlock->fvf == fvf) { + TRACE("Application is setting the old fvf over, nothing to do\n"); + return WINED3D_OK; + } + + This->updateStateBlock->fvf = fvf; + TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL); + return WINED3D_OK; +} + + +static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf); + *pfvf = This->stateBlock->fvf; + return WINED3D_OK; +} + +/***** + * Get / Set Stream Source + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexBuffer *oldSrc; + + if (StreamNumber >= MAX_STREAMS) { + WARN("Stream out of range %d\n", StreamNumber); + return WINED3DERR_INVALIDCALL; + } + + oldSrc = This->stateBlock->streamSource[StreamNumber]; + TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride); + + This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE; + + if(oldSrc == pStreamData && + This->updateStateBlock->streamStride[StreamNumber] == Stride && + This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) { + TRACE("Application is setting the old values over, nothing to do\n"); + return WINED3D_OK; + } + + This->updateStateBlock->streamSource[StreamNumber] = pStreamData; + if (pStreamData) { + This->updateStateBlock->streamStride[StreamNumber] = Stride; + This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes; + } + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + /* Need to do a getParent and pass the reffs up */ + /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed. + which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source + so for now, just count internally */ + if (pStreamData != NULL) { + IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData; + InterlockedIncrement(&vbImpl->bindCount); + } + if (oldSrc != NULL) { + InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount); + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber, + This->stateBlock->streamSource[StreamNumber], + This->stateBlock->streamOffset[StreamNumber], + This->stateBlock->streamStride[StreamNumber]); + + if (StreamNumber >= MAX_STREAMS) { + WARN("Stream out of range %d\n", StreamNumber); + return WINED3DERR_INVALIDCALL; + } + *pStream = This->stateBlock->streamSource[StreamNumber]; + *pStride = This->stateBlock->streamStride[StreamNumber]; + if (pOffset) { + *pOffset = This->stateBlock->streamOffset[StreamNumber]; + } + + if (*pStream != NULL) { + IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */ + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber]; + UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber]; + + TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider); + This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA ); + + This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE; + This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF; + + if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq || + This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider); + *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber]; + + TRACE("(%p) : returning %d\n", This, *Divider); + + return WINED3D_OK; +} + +/***** + * Get / Set & Multiply Transform + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + /* Most of this routine, comments included copied from ddraw tree initially: */ + TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts)); + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + This->updateStateBlock->changed.transform[d3dts] = TRUE; + memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX)); + return WINED3D_OK; + } + + /* + * If the new matrix is the same as the current one, + * we cut off any further processing. this seems to be a reasonable + * optimization because as was noticed, some apps (warcraft3 for example) + * tend towards setting the same matrix repeatedly for some reason. + * + * From here on we assume that the new matrix is different, wherever it matters. + */ + if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) { + TRACE("The app is setting the same matrix over again\n"); + return WINED3D_OK; + } else { + conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]); + } + + /* + ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord + where ViewMat = Camera space, WorldMat = world space. + + In OpenGL, camera and world space is combined into GL_MODELVIEW + matrix. The Projection matrix stay projection matrix. + */ + + /* Capture the times we can just ignore the change for now */ + if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */ + This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float)); + /* Handled by the state manager */ + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts)); + return WINED3D_OK; + +} +static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State)); + memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX)); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) { + WINED3DMATRIX *mat = NULL; + WINED3DMATRIX temp; + + /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code + * below means it will be recorded in a state block change, but it + * works regardless where it is recorded. + * If this is found to be wrong, change to StateBlock. + */ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State)); + + if (State < HIGHEST_TRANSFORMSTATE) + { + mat = &This->updateStateBlock->transforms[State]; + } else { + FIXME("Unhandled transform state!!\n"); + } + + multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix); + + /* Apply change via set transform - will reapply to eg. lights this way */ + return IWineD3DDeviceImpl_SetTransform(iface, State, &temp); +} + +/***** + * Get / Set Light + *****/ +/* Note lights are real special cases. Although the device caps state only eg. 8 are supported, + you can reference any indexes you want as long as that number max are enabled at any + one point in time! Therefore since the indexes can be anything, we need a hashmap of them. + However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap, + but when recording, just build a chain pretty much of commands to be replayed. */ + +static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) { + float rho; + PLIGHTINFOEL *object = NULL; + UINT Hi = LIGHTMAP_HASHFUNC(Index); + struct list *e; + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi); + + /* Check the parameter range. Need for speed most wanted sets junk lights which confuse + * the gl driver. + */ + if(!pLight) { + WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + + switch(pLight->Type) { + case WINED3DLIGHT_POINT: + case WINED3DLIGHT_SPOT: + case WINED3DLIGHT_PARALLELPOINT: + case WINED3DLIGHT_GLSPOT: + /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed + * most wanted + */ + if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) { + WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + break; + + case WINED3DLIGHT_DIRECTIONAL: + /* Ignores attenuation */ + break; + + default: + WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + + LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) { + object = LIST_ENTRY(e, PLIGHTINFOEL, entry); + if(object->OriginalIndex == Index) break; + object = NULL; + } + + if(!object) { + TRACE("Adding new light\n"); + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + if(!object) { + ERR("Out of memory error when allocating a light\n"); + return E_OUTOFMEMORY; + } + list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry); + object->glIndex = -1; + object->OriginalIndex = Index; + object->changed = TRUE; + } + + /* Initialize the object */ + TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type, + pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a, + pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a, + pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a); + TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z, + pLight->Direction.x, pLight->Direction.y, pLight->Direction.z); + TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi); + + /* Save away the information */ + memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT)); + + switch (pLight->Type) { + case WINED3DLIGHT_POINT: + /* Position */ + object->lightPosn[0] = pLight->Position.x; + object->lightPosn[1] = pLight->Position.y; + object->lightPosn[2] = pLight->Position.z; + object->lightPosn[3] = 1.0f; + object->cutoff = 180.0f; + /* FIXME: Range */ + break; + + case WINED3DLIGHT_DIRECTIONAL: + /* Direction */ + object->lightPosn[0] = -pLight->Direction.x; + object->lightPosn[1] = -pLight->Direction.y; + object->lightPosn[2] = -pLight->Direction.z; + object->lightPosn[3] = 0.0; + object->exponent = 0.0f; + object->cutoff = 180.0f; + break; + + case WINED3DLIGHT_SPOT: + /* Position */ + object->lightPosn[0] = pLight->Position.x; + object->lightPosn[1] = pLight->Position.y; + object->lightPosn[2] = pLight->Position.z; + object->lightPosn[3] = 1.0; + + /* Direction */ + object->lightDirn[0] = pLight->Direction.x; + object->lightDirn[1] = pLight->Direction.y; + object->lightDirn[2] = pLight->Direction.z; + object->lightDirn[3] = 1.0; + + /* + * opengl-ish and d3d-ish spot lights use too different models for the + * light "intensity" as a function of the angle towards the main light direction, + * so we only can approximate very roughly. + * however spot lights are rather rarely used in games (if ever used at all). + * furthermore if still used, probably nobody pays attention to such details. + */ + if (pLight->Falloff == 0) { + rho = 6.28f; + } else { + rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff); + } + if (rho < 0.0001) rho = 0.0001f; + object->exponent = -0.3/log(cos(rho/2)); + if (object->exponent > 128.0) { + object->exponent = 128.0; + } + object->cutoff = pLight->Phi*90/M_PI; + + /* FIXME: Range */ + break; + + default: + FIXME("Unrecognized light type %d\n", pLight->Type); + } + + /* Update the live definitions if the light is currently assigned a glIndex */ + if (object->glIndex != -1 && !This->isRecordingState) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex)); + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) { + PLIGHTINFOEL *lightInfo = NULL; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + DWORD Hi = LIGHTMAP_HASHFUNC(Index); + struct list *e; + TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight); + + LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) { + lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry); + if(lightInfo->OriginalIndex == Index) break; + lightInfo = NULL; + } + + if (lightInfo == NULL) { + TRACE("Light information requested but light not defined\n"); + return WINED3DERR_INVALIDCALL; + } + + memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT)); + return WINED3D_OK; +} + +/***** + * Get / Set Light Enable + * (Note for consistency, renamed d3dx function by adding the 'set' prefix) + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) { + PLIGHTINFOEL *lightInfo = NULL; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + UINT Hi = LIGHTMAP_HASHFUNC(Index); + struct list *e; + TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable); + + /* Tests show true = 128...not clear why */ + Enable = Enable? 128: 0; + + LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) { + lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry); + if(lightInfo->OriginalIndex == Index) break; + lightInfo = NULL; + } + TRACE("Found light: %p\n", lightInfo); + + /* Special case - enabling an undefined light creates one with a strict set of parms! */ + if (lightInfo == NULL) { + + TRACE("Light enabled requested but light not defined, so defining one!\n"); + IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light); + + /* Search for it again! Should be fairly quick as near head of list */ + LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) { + lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry); + if(lightInfo->OriginalIndex == Index) break; + lightInfo = NULL; + } + if (lightInfo == NULL) { + FIXME("Adding default lights has failed dismally\n"); + return WINED3DERR_INVALIDCALL; + } + } + + lightInfo->enabledChanged = TRUE; + if(!Enable) { + if(lightInfo->glIndex != -1) { + if(!This->isRecordingState) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex)); + } + + This->stateBlock->activeLights[lightInfo->glIndex] = NULL; + lightInfo->glIndex = -1; + } else { + TRACE("Light already disabled, nothing to do\n"); + } + } else { + if (lightInfo->glIndex != -1) { + /* nop */ + TRACE("Nothing to do as light was enabled\n"); + } else { + int i; + /* Find a free gl light */ + for(i = 0; i < This->maxConcurrentLights; i++) { + if(This->stateBlock->activeLights[i] == NULL) { + This->stateBlock->activeLights[i] = lightInfo; + lightInfo->glIndex = i; + break; + } + } + if(lightInfo->glIndex == -1) { + ERR("Too many concurrently active lights\n"); + return WINED3DERR_INVALIDCALL; + } + + /* i == lightInfo->glIndex */ + if(!This->isRecordingState) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i)); + } + } + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) { + + PLIGHTINFOEL *lightInfo = NULL; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + struct list *e; + UINT Hi = LIGHTMAP_HASHFUNC(Index); + TRACE("(%p) : for idx(%d)\n", This, Index); + + LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) { + lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry); + if(lightInfo->OriginalIndex == Index) break; + lightInfo = NULL; + } + + if (lightInfo == NULL) { + TRACE("Light enabled state requested but light not defined\n"); + return WINED3DERR_INVALIDCALL; + } + /* true is 128 according to SetLightEnable */ + *pEnable = lightInfo->glIndex != -1 ? 128 : 0; + return WINED3D_OK; +} + +/***** + * Get / Set Clip Planes + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane); + + /* Validate Index */ + if (Index >= GL_LIMITS(clipplanes)) { + TRACE("Application has requested clipplane this device doesn't support\n"); + return WINED3DERR_INVALIDCALL; + } + + This->updateStateBlock->changed.clipplane[Index] = TRUE; + + if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] && + This->updateStateBlock->clipplane[Index][1] == pPlane[1] && + This->updateStateBlock->clipplane[Index][2] == pPlane[2] && + This->updateStateBlock->clipplane[Index][3] == pPlane[3]) { + TRACE("Application is setting old values over, nothing to do\n"); + return WINED3D_OK; + } + + This->updateStateBlock->clipplane[Index][0] = pPlane[0]; + This->updateStateBlock->clipplane[Index][1] = pPlane[1]; + This->updateStateBlock->clipplane[Index][2] = pPlane[2]; + This->updateStateBlock->clipplane[Index][3] = pPlane[3]; + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index)); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : for idx %d\n", This, Index); + + /* Validate Index */ + if (Index >= GL_LIMITS(clipplanes)) { + TRACE("Application has requested clipplane this device doesn't support\n"); + return WINED3DERR_INVALIDCALL; + } + + pPlane[0] = This->stateBlock->clipplane[Index][0]; + pPlane[1] = This->stateBlock->clipplane[Index][1]; + pPlane[2] = This->stateBlock->clipplane[Index][2]; + pPlane[3] = This->stateBlock->clipplane[Index][3]; + return WINED3D_OK; +} + +/***** + * Get / Set Clip Plane Status + * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9 + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + FIXME("(%p) : stub\n", This); + if (NULL == pClipStatus) { + return WINED3DERR_INVALIDCALL; + } + This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion; + This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + FIXME("(%p) : stub\n", This); + if (NULL == pClipStatus) { + return WINED3DERR_INVALIDCALL; + } + pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion; + pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection; + return WINED3D_OK; +} + +/***** + * Get / Set Material + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + This->updateStateBlock->changed.material = TRUE; + memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL)); + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL)); + TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g, + pMaterial->Diffuse.b, pMaterial->Diffuse.a); + TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g, + pMaterial->Ambient.b, pMaterial->Ambient.a); + TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g, + pMaterial->Specular.b, pMaterial->Specular.a); + TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g, + pMaterial->Emissive.b, pMaterial->Emissive.a); + TRACE("(%p) : Power (%f)\n", This, pMaterial->Power); + + return WINED3D_OK; +} + +/***** + * Get / Set Indices + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DIndexBuffer *oldIdxs; + + TRACE("(%p) : Setting to %p\n", This, pIndexData); + oldIdxs = This->updateStateBlock->pIndexData; + + This->updateStateBlock->changed.indices = TRUE; + This->updateStateBlock->pIndexData = pIndexData; + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + if(oldIdxs != pIndexData) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData); + if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs); + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + *ppIndexData = This->stateBlock->pIndexData; + + /* up ref count on ppindexdata */ + if (*ppIndexData) { + IWineD3DIndexBuffer_AddRef(*ppIndexData); + TRACE("(%p) index data set to %p\n", This, ppIndexData); + }else{ + TRACE("(%p) No index data set\n", This); + } + TRACE("Returning %p\n", *ppIndexData); + + return WINED3D_OK; +} + +/* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */ +static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)->(%d)\n", This, BaseIndex); + + if(This->updateStateBlock->baseVertexIndex == BaseIndex) { + TRACE("Application is setting the old value over, nothing to do\n"); + return WINED3D_OK; + } + + This->updateStateBlock->baseVertexIndex = BaseIndex; + + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + /* The base vertex index affects the stream sources */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : base_index %p\n", This, base_index); + + *base_index = This->stateBlock->baseVertexIndex; + + TRACE("Returning %u\n", *base_index); + + return WINED3D_OK; +} + +/***** + * Get / Set Viewports + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p)\n", This); + This->updateStateBlock->changed.viewport = TRUE; + memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT)); + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This, + pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ); + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT); + return WINED3D_OK; + +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)\n", This); + memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT)); + return WINED3D_OK; +} + +/***** + * Get / Set Render States + * TODO: Verify against dx9 definitions + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + DWORD oldValue = This->stateBlock->renderState[State]; + + TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value); + + This->updateStateBlock->changed.renderState[State] = TRUE; + This->updateStateBlock->renderState[State] = Value; + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + /* Compared here and not before the assignment to allow proper stateblock recording */ + if(Value == oldValue) { + TRACE("Application is setting the old value over, nothing to do\n"); + } else { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State)); + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]); + *pValue = This->stateBlock->renderState[State]; + return WINED3D_OK; +} + +/***** + * Get / Set Sampler States + * TODO: Verify against dx9 definitions + *****/ + +static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + DWORD oldValue; + + TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n", + This, Sampler, debug_d3dsamplerstate(Type), Type, Value); + + if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) { + Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); + } + + /** + * SetSampler is designed to allow for more than the standard up to 8 textures + * and Geforce has stopped supporting more than 6 standard textures in openGL. + * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?) + * + * http://developer.nvidia.com/object/General_FAQ.html#t6 + * + * There are two new settings for GForce + * the sampler one: + * GL_MAX_TEXTURE_IMAGE_UNITS_ARB + * and the texture one: + * GL_MAX_TEXTURE_COORDS_ARB. + * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...). + ******************/ + + oldValue = This->stateBlock->samplerState[Sampler][Type]; + This->updateStateBlock->samplerState[Sampler][Type] = Value; + This->updateStateBlock->changed.samplerState[Sampler][Type] = Value; + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + if(oldValue == Value) { + TRACE("Application is setting the old value over, nothing to do\n"); + return WINED3D_OK; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler)); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) : Sampler %#x, Type %s (%#x)\n", + This, Sampler, debug_d3dsamplerstate(Type), Type); + + if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) { + Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); + } + + *Value = This->stateBlock->samplerState[Sampler][Type]; + TRACE("(%p) : Returning %#x\n", This, *Value); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + This->updateStateBlock->changed.scissorRect = TRUE; + if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) { + TRACE("App is setting the old scissor rectangle over, nothing to do\n"); + return WINED3D_OK; + } + CopyRect(&This->updateStateBlock->scissorRect, pRect); + + if(This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect)); + TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl; + + TRACE("(%p) : pDecl=%p\n", This, pDecl); + + This->updateStateBlock->vertexDecl = pDecl; + This->updateStateBlock->changed.vertexDecl = TRUE; + + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } else if(pDecl == oldDecl) { + /* Checked after the assignment to allow proper stateblock recording */ + TRACE("Application is setting the old declaration over, nothing to do\n"); + return WINED3D_OK; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) : ppDecl=%p\n", This, ppDecl); + + *ppDecl = This->stateBlock->vertexDecl; + if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader; + + This->updateStateBlock->vertexShader = pShader; + This->updateStateBlock->changed.vertexShader = TRUE; + + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } else if(oldShader == pShader) { + /* Checked here to allow proper stateblock recording */ + TRACE("App is setting the old shader over, nothing to do\n"); + return WINED3D_OK; + } + + TRACE("(%p) : setting pShader(%p)\n", This, pShader); + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + if (NULL == ppShader) { + return WINED3DERR_INVALIDCALL; + } + *ppShader = This->stateBlock->vertexShader; + if( NULL != *ppShader) + IWineD3DVertexShader_AddRef(*ppShader); + + TRACE("(%p) : returning %p\n", This, *ppShader); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB( + IWineD3DDevice *iface, + UINT start, + CONST BOOL *srcData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i, cnt = min(count, MAX_CONST_B - start); + + TRACE("(iface %p, srcData %p, start %d, count %d)\n", + iface, srcData, start, count); + + if (srcData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL)); + for (i = 0; i < cnt; i++) + TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false"); + + for (i = start; i < cnt + start; ++i) { + This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB( + IWineD3DDevice *iface, + UINT start, + BOOL *dstData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int cnt = min(count, MAX_CONST_B - start); + + TRACE("(iface %p, dstData %p, start %d, count %d)\n", + iface, dstData, start, count); + + if (dstData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL)); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI( + IWineD3DDevice *iface, + UINT start, + CONST int *srcData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i, cnt = min(count, MAX_CONST_I - start); + + TRACE("(iface %p, srcData %p, start %d, count %d)\n", + iface, srcData, start, count); + + if (srcData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4); + for (i = 0; i < cnt; i++) + TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i, + srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]); + + for (i = start; i < cnt + start; ++i) { + This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI( + IWineD3DDevice *iface, + UINT start, + int *dstData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int cnt = min(count, MAX_CONST_I - start); + + TRACE("(iface %p, dstData %p, start %d, count %d)\n", + iface, dstData, start, count); + + if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0) + return WINED3DERR_INVALIDCALL; + + memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF( + IWineD3DDevice *iface, + UINT start, + CONST float *srcData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i; + + TRACE("(iface %p, srcData %p, start %d, count %d)\n", + iface, srcData, start, count); + + /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */ + if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF)) + return WINED3DERR_INVALIDCALL; + + memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4); + if(TRACE_ON(d3d)) { + for (i = 0; i < count; i++) + TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i, + srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]); + } + + for (i = start; i < count + start; ++i) { + if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) { + constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry); + if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) { + ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry)); + list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry); + } + ptr->idx[ptr->count++] = i; + This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE; + } + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF( + IWineD3DDevice *iface, + UINT start, + float *dstData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int cnt = min(count, GL_LIMITS(vshader_constantsF) - start); + + TRACE("(iface %p, dstData %p, start %d, count %d)\n", + iface, dstData, start, count); + + if (dstData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4); + return WINED3D_OK; +} + +static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) { + DWORD i; + for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i)); + } +} + +static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) { + int i = This->rev_tex_unit_map[unit]; + int j = This->texUnitMap[stage]; + + This->texUnitMap[stage] = unit; + if (i != -1 && i != stage) { + This->texUnitMap[i] = -1; + } + + This->rev_tex_unit_map[unit] = stage; + if (j != -1 && j != unit) { + This->rev_tex_unit_map[j] = -1; + } +} + +static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) { + int i; + + for (i = 0; i < MAX_TEXTURES; ++i) { + WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP]; + WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP]; + DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK; + DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK; + DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK; + DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK; + DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK; + DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK; + + if (color_op == WINED3DTOP_DISABLE) { + /* Not used, and disable higher stages */ + while (i < MAX_TEXTURES) { + This->fixed_function_usage_map[i] = FALSE; + ++i; + } + break; + } + + if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2) + || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1) + || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP)) + || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2) + || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1) + || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) { + This->fixed_function_usage_map[i] = TRUE; + } else { + This->fixed_function_usage_map[i] = FALSE; + } + + if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) { + This->fixed_function_usage_map[i+1] = TRUE; + } + } +} + +static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) { + int i, tex; + + device_update_fixed_function_usage_map(This); + + if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) { + for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) { + if (!This->fixed_function_usage_map[i]) continue; + + if (This->texUnitMap[i] != i) { + device_map_stage(This, i, i); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i)); + markTextureStagesDirty(This, i); + } + } + return; + } + + /* Now work out the mapping */ + tex = 0; + for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) { + if (!This->fixed_function_usage_map[i]) continue; + + if (This->texUnitMap[i] != tex) { + device_map_stage(This, i, tex); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i)); + markTextureStagesDirty(This, i); + } + + ++tex; + } +} + +static void device_map_psamplers(IWineD3DDeviceImpl *This) { + DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers; + int i; + + for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) { + if (sampler_tokens[i] && This->texUnitMap[i] != i) { + device_map_stage(This, i, i); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i)); + if (i < MAX_TEXTURES) { + markTextureStagesDirty(This, i); + } + } + } +} + +static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) { + int current_mapping = This->rev_tex_unit_map[unit]; + + if (current_mapping == -1) { + /* Not currently used */ + return TRUE; + } + + if (current_mapping < MAX_FRAGMENT_SAMPLERS) { + /* Used by a fragment sampler */ + + if (!pshader_sampler_tokens) { + /* No pixel shader, check fixed function */ + return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping]; + } + + /* Pixel shader, check the shader's sampler map */ + return !pshader_sampler_tokens[current_mapping]; + } + + /* Used by a vertex sampler */ + return !vshader_sampler_tokens[current_mapping]; +} + +static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) { + DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers; + DWORD *pshader_sampler_tokens = NULL; + int start = GL_LIMITS(combined_samplers) - 1; + int i; + + if (ps) { + IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader; + + /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */ + IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader); + pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers; + } + + for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) { + int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS; + if (vshader_sampler_tokens[i]) { + if (This->texUnitMap[vsampler_idx] != -1) { + /* Already mapped somewhere */ + continue; + } + + while (start >= 0) { + if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) { + device_map_stage(This, vsampler_idx, start); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx)); + + --start; + break; + } + + --start; + } + } + } +} + +void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) { + BOOL vs = use_vs(This); + BOOL ps = use_ps(This); + /* + * Rules are: + * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but + * that would be really messy and require shader recompilation + * -> When the mapping of a stage is changed, sampler and ALL texture stage states have + * to be reset. Because of that try to work with a 1:1 mapping as much as possible + */ + if (ps) { + device_map_psamplers(This); + } else { + device_map_fixed_function_samplers(This); + } + + if (vs) { + device_map_vsamplers(This, ps); + } +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader; + This->updateStateBlock->pixelShader = pShader; + This->updateStateBlock->changed.pixelShader = TRUE; + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + } + + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + if(pShader == oldShader) { + TRACE("App is setting the old pixel shader over, nothing to do\n"); + return WINED3D_OK; + } + + TRACE("(%p) : setting pShader(%p)\n", This, pShader); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + if (NULL == ppShader) { + WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This); + return WINED3DERR_INVALIDCALL; + } + + *ppShader = This->stateBlock->pixelShader; + if (NULL != *ppShader) { + IWineD3DPixelShader_AddRef(*ppShader); + } + TRACE("(%p) : returning %p\n", This, *ppShader); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB( + IWineD3DDevice *iface, + UINT start, + CONST BOOL *srcData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i, cnt = min(count, MAX_CONST_B - start); + + TRACE("(iface %p, srcData %p, start %d, count %d)\n", + iface, srcData, start, count); + + if (srcData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL)); + for (i = 0; i < cnt; i++) + TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false"); + + for (i = start; i < cnt + start; ++i) { + This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB( + IWineD3DDevice *iface, + UINT start, + BOOL *dstData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int cnt = min(count, MAX_CONST_B - start); + + TRACE("(iface %p, dstData %p, start %d, count %d)\n", + iface, dstData, start, count); + + if (dstData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL)); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI( + IWineD3DDevice *iface, + UINT start, + CONST int *srcData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i, cnt = min(count, MAX_CONST_I - start); + + TRACE("(iface %p, srcData %p, start %d, count %d)\n", + iface, srcData, start, count); + + if (srcData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4); + for (i = 0; i < cnt; i++) + TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i, + srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]); + + for (i = start; i < cnt + start; ++i) { + This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE; + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI( + IWineD3DDevice *iface, + UINT start, + int *dstData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int cnt = min(count, MAX_CONST_I - start); + + TRACE("(iface %p, dstData %p, start %d, count %d)\n", + iface, dstData, start, count); + + if (dstData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF( + IWineD3DDevice *iface, + UINT start, + CONST float *srcData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i; + + TRACE("(iface %p, srcData %p, start %d, count %d)\n", + iface, srcData, start, count); + + /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */ + if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF)) + return WINED3DERR_INVALIDCALL; + + memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4); + if(TRACE_ON(d3d)) { + for (i = 0; i < count; i++) + TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i, + srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]); + } + + for (i = start; i < count + start; ++i) { + if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) { + constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry); + if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) { + ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry)); + list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry); + } + ptr->idx[ptr->count++] = i; + This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE; + } + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF( + IWineD3DDevice *iface, + UINT start, + float *dstData, + UINT count) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int cnt = min(count, GL_LIMITS(pshader_constantsF) - start); + + TRACE("(iface %p, dstData %p, start %d, count %d)\n", + iface, dstData, start, count); + + if (dstData == NULL || cnt < 0) + return WINED3DERR_INVALIDCALL; + + memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4); + return WINED3D_OK; +} + +#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size) +static HRESULT +process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) { + char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL; + unsigned int i; + DWORD DestFVF = dest->fvf; + WINED3DVIEWPORT vp; + WINED3DMATRIX mat, proj_mat, view_mat, world_mat; + BOOL doClip; + int numTextures; + + if (lpStrideData->u.s.normal.lpData) { + WARN(" lighting state not saved yet... Some strange stuff may happen !\n"); + } + + if (lpStrideData->u.s.position.lpData == NULL) { + ERR("Source has no position mask\n"); + return WINED3DERR_INVALIDCALL; + } + + /* We might access VBOs from this code, so hold the lock */ + ENTER_GL(); + + if (dest->resource.allocatedMemory == NULL) { + /* This may happen if we do direct locking into a vbo. Unlikely, + * but theoretically possible(ddraw processvertices test) + */ + dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size); + if(!dest->resource.allocatedMemory) { + LEAVE_GL(); + ERR("Out of memory\n"); + return E_OUTOFMEMORY; + } + if(dest->vbo) { + void *src; + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo)); + checkGLcall("glBindBufferARB"); + src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB)); + if(src) { + memcpy(dest->resource.allocatedMemory, src, dest->resource.size); + } + GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)); + checkGLcall("glUnmapBufferARB"); + } + } + + /* Get a pointer into the destination vbo(create one if none exists) and + * write correct opengl data into it. It's cheap and allows us to run drawStridedFast + */ + if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) { + CreateVBO(dest); + } + + if(dest->vbo) { + unsigned char extrabytes = 0; + /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW + * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data, + * this may write 4 extra bytes beyond the area that should be written + */ + if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4; + dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes); + if(!dest_conv_addr) { + ERR("Out of memory\n"); + /* Continue without storing converted vertices */ + } + dest_conv = dest_conv_addr; + } + + /* Should I clip? + * a) WINED3DRS_CLIPPING is enabled + * b) WINED3DVOP_CLIP is passed + */ + if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) { + static BOOL warned = FALSE; + /* + * The clipping code is not quite correct. Some things need + * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9, + * so disable clipping for now. + * (The graphics in Half-Life are broken, and my processvertices + * test crashes with IDirect3DDevice3) + doClip = TRUE; + */ + doClip = FALSE; + if(!warned) { + warned = TRUE; + FIXME("Clipping is broken and disabled for now\n"); + } + } else doClip = FALSE; + dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF); + + IWineD3DDevice_GetTransform( (IWineD3DDevice *) This, + WINED3DTS_VIEW, + &view_mat); + IWineD3DDevice_GetTransform( (IWineD3DDevice *) This, + WINED3DTS_PROJECTION, + &proj_mat); + IWineD3DDevice_GetTransform( (IWineD3DDevice *) This, + WINED3DTS_WORLDMATRIX(0), + &world_mat); + + TRACE("View mat:\n"); + TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14); + TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24); + TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34); + TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44); + + TRACE("Proj mat:\n"); + TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14); + TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24); + TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34); + TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44); + + TRACE("World mat:\n"); + TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14); + TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24); + TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34); + TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44); + + /* Get the viewport */ + IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp); + TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n", + vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ); + + multiply_matrix(&mat,&view_mat,&world_mat); + multiply_matrix(&mat,&proj_mat,&mat); + + numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT; + + for (i = 0; i < dwCount; i+= 1) { + unsigned int tex_index; + + if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) || + ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) { + /* The position first */ + float *p = + (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride); + float x, y, z, rhw; + TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]); + + /* Multiplication with world, view and projection matrix */ + x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41); + y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42); + z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43); + rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44); + + TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw); + + /* WARNING: The following things are taken from d3d7 and were not yet checked + * against d3d8 or d3d9! + */ + + /* Clipping conditions: From + * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp + * + * A vertex is clipped if it does not match the following requirements + * -rhw < x <= rhw + * -rhw < y <= rhw + * 0 < z <= rhw + * 0 < rhw ( Not in d3d7, but tested in d3d7) + * + * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and + * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked) + * + */ + + if( !doClip || + ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) && + (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) && + ( rhw > eps ) ) ) { + + /* "Normal" viewport transformation (not clipped) + * 1) The values are divided by rhw + * 2) The y axis is negative, so multiply it with -1 + * 3) Screen coordinates go from -(Width/2) to +(Width/2) and + * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ + * 4) Multiply x with Width/2 and add Width/2 + * 5) The same for the height + * 6) Add the viewpoint X and Y to the 2D coordinates and + * The minimum Z value to z + * 7) rhw = 1 / rhw Reciprocal of Homogeneous W.... + * + * Well, basically it's simply a linear transformation into viewport + * coordinates + */ + + x /= rhw; + y /= rhw; + z /= rhw; + + y *= -1; + + x *= vp.Width / 2; + y *= vp.Height / 2; + z *= vp.MaxZ - vp.MinZ; + + x += vp.Width / 2 + vp.X; + y += vp.Height / 2 + vp.Y; + z += vp.MinZ; + + rhw = 1 / rhw; + } else { + /* That vertex got clipped + * Contrary to OpenGL it is not dropped completely, it just + * undergoes a different calculation. + */ + TRACE("Vertex got clipped\n"); + x += rhw; + y += rhw; + + x /= 2; + y /= 2; + + /* Msdn mentions that Direct3D9 keeps a list of clipped vertices + * outside of the main vertex buffer memory. That needs some more + * investigation... + */ + } + + TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw); + + + ( (float *) dest_ptr)[0] = x; + ( (float *) dest_ptr)[1] = y; + ( (float *) dest_ptr)[2] = z; + ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */ + + dest_ptr += 3 * sizeof(float); + + if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) { + dest_ptr += sizeof(float); + } + + if(dest_conv) { + float w = 1 / rhw; + ( (float *) dest_conv)[0] = x * w; + ( (float *) dest_conv)[1] = y * w; + ( (float *) dest_conv)[2] = z * w; + ( (float *) dest_conv)[3] = w; + + dest_conv += 3 * sizeof(float); + + if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) { + dest_conv += sizeof(float); + } + } + } + if (DestFVF & WINED3DFVF_PSIZE) { + dest_ptr += sizeof(DWORD); + if(dest_conv) dest_conv += sizeof(DWORD); + } + if (DestFVF & WINED3DFVF_NORMAL) { + float *normal = + (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride); + /* AFAIK this should go into the lighting information */ + FIXME("Didn't expect the destination to have a normal\n"); + copy_and_next(dest_ptr, normal, 3 * sizeof(float)); + if(dest_conv) { + copy_and_next(dest_conv, normal, 3 * sizeof(float)); + } + } + + if (DestFVF & WINED3DFVF_DIFFUSE) { + DWORD *color_d = + (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride); + if(!color_d) { + static BOOL warned = FALSE; + + if(!warned) { + ERR("No diffuse color in source, but destination has one\n"); + warned = TRUE; + } + + *( (DWORD *) dest_ptr) = 0xffffffff; + dest_ptr += sizeof(DWORD); + + if(dest_conv) { + *( (DWORD *) dest_conv) = 0xffffffff; + dest_conv += sizeof(DWORD); + } + } + else { + copy_and_next(dest_ptr, color_d, sizeof(DWORD)); + if(dest_conv) { + *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */ + *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */ + *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */ + dest_conv += sizeof(DWORD); + } + } + } + + if (DestFVF & WINED3DFVF_SPECULAR) { + /* What's the color value in the feedback buffer? */ + DWORD *color_s = + (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride); + if(!color_s) { + static BOOL warned = FALSE; + + if(!warned) { + ERR("No specular color in source, but destination has one\n"); + warned = TRUE; + } + + *( (DWORD *) dest_ptr) = 0xFF000000; + dest_ptr += sizeof(DWORD); + + if(dest_conv) { + *( (DWORD *) dest_conv) = 0xFF000000; + dest_conv += sizeof(DWORD); + } + } + else { + copy_and_next(dest_ptr, color_s, sizeof(DWORD)); + if(dest_conv) { + *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */ + *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */ + *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */ + dest_conv += sizeof(DWORD); + } + } + } + + for (tex_index = 0; tex_index < numTextures; tex_index++) { + float *tex_coord = + (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) + + i * lpStrideData->u.s.texCoords[tex_index].dwStride); + if(!tex_coord) { + ERR("No source texture, but destination requests one\n"); + dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float); + if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float); + } + else { + copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float)); + if(dest_conv) { + copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float)); + } + } + } + } + + if(dest_conv) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo)); + checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)"); + GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF), + dwCount * get_flexible_vertex_size(DestFVF), + dest_conv_addr)); + checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)"); + HeapFree(GetProcessHeap(), 0, dest_conv_addr); + } + + LEAVE_GL(); + + return WINED3D_OK; +} +#undef copy_and_next + +static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineDirect3DVertexStridedData strided; + BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP; + TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags); + + if(pVertexDecl) { + ERR("Output vertex declaration not implemented yet\n"); + } + + /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway, + * and this call is quite performance critical, so don't call needlessly + */ + if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) { + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP + * control the streamIsUP flag, thus restore it afterwards. + */ + This->stateBlock->streamIsUP = FALSE; + memset(&strided, 0, sizeof(strided)); + primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo); + This->stateBlock->streamIsUP = streamWasUP; + + if(vbo || SrcStartIndex) { + unsigned int i; + /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are + * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure + * + * Also get the start index in, but only loop over all elements if there's something to add at all. + */ +#define FIXSRC(type) \ + if(strided.u.s.type.VBO) { \ + IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \ + strided.u.s.type.VBO = 0; \ + strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \ + ENTER_GL(); \ + GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \ + vb->vbo = 0; \ + LEAVE_GL(); \ + } \ + if(strided.u.s.type.lpData) { \ + strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \ + } + FIXSRC(position); + FIXSRC(blendWeights); + FIXSRC(blendMatrixIndices); + FIXSRC(normal); + FIXSRC(pSize); + FIXSRC(diffuse); + FIXSRC(specular); + for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) { + FIXSRC(texCoords[i]); + } + FIXSRC(position2); + FIXSRC(normal2); + FIXSRC(tangent); + FIXSRC(binormal); + FIXSRC(tessFactor); + FIXSRC(fog); + FIXSRC(depth); + FIXSRC(sample); +#undef FIXSRC + } + + return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags); +} + +/***** + * Get / Set Texture Stage States + * TODO: Verify against dx9 definitions + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + DWORD oldValue = This->updateStateBlock->textureState[Stage][Type]; + + TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value); + + if (Stage >= MAX_TEXTURES) { + WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1); + return WINED3D_OK; + } + + This->updateStateBlock->changed.textureState[Stage][Type] = TRUE; + This->updateStateBlock->textureState[Stage][Type] = Value; + + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + /* Checked after the assignments to allow proper stateblock recording */ + if(oldValue == Value) { + TRACE("App is setting the old value over, nothing to do\n"); + return WINED3D_OK; + } + + if(Stage > This->stateBlock->lowest_disabled_stage && + StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) { + /* Colorop change above lowest disabled stage? That won't change anything in the gl setup + * Changes in other states are important on disabled stages too + */ + return WINED3D_OK; + } + + if(Type == WINED3DTSS_COLOROP) { + int i; + + if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) { + /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage, + * they have to be disabled + * + * The current stage is dirtified below. + */ + for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) { + TRACE("Additionally dirtifying stage %d\n", i); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP)); + } + This->stateBlock->lowest_disabled_stage = Stage; + TRACE("New lowest disabled: %d\n", Stage); + } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) { + /* Previously disabled stage enabled. Stages above it may need enabling + * stage must be lowest_disabled_stage here, if it's bigger success is returned above, + * and stages below the lowest disabled stage can't be enabled(because they are enabled already). + * + * Again stage Stage doesn't need to be dirtified here, it is handled below. + */ + + for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) { + if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) { + break; + } + TRACE("Additionally dirtifying stage %d due to enable\n", i); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP)); + } + This->stateBlock->lowest_disabled_stage = i; + TRACE("New lowest disabled: %d\n", i); + } + if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) { + /* TODO: Built a stage -> texture unit mapping for register combiners */ + } + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type)); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]); + *pValue = This->updateStateBlock->textureState[Stage][Type]; + return WINED3D_OK; +} + +/***** + * Get / Set Texture + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DBaseTexture *oldTexture; + + TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture); + + if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) { + Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); + } + + oldTexture = This->updateStateBlock->textures[Stage]; + + if(pTexture != NULL) { + /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH; + */ + if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) { + WARN("(%p) Attempt to set scratch texture rejected\n", pTexture); + return WINED3DERR_INVALIDCALL; + } + This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture); + } + + TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages)); + TRACE("(%p) : oldtexture(%p)\n", This,oldTexture); + + This->updateStateBlock->changed.textures[Stage] = TRUE; + TRACE("(%p) : setting new texture to %p\n", This, pTexture); + This->updateStateBlock->textures[Stage] = pTexture; + + /* Handle recording of state blocks */ + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; + } + + if(oldTexture == pTexture) { + TRACE("App is setting the same texture again, nothing to do\n"); + return WINED3D_OK; + } + + /** NOTE: MSDN says that setTexture increases the reference count, + * and the the application must set the texture back to null (or have a leaky application), + * This means we should pass the refcount up to the parent + *******************************/ + if (NULL != This->updateStateBlock->textures[Stage]) { + IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage]; + ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount); + + IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]); + if(oldTexture == NULL && Stage < MAX_TEXTURES) { + /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound, + * so the COLOROP and ALPHAOP have to be dirtified. + */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP)); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP)); + } + if(bindCount == 1) { + new->baseTexture.sampler = Stage; + } + /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */ + + } + + if (NULL != oldTexture) { + IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture; + LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount); + + IWineD3DBaseTexture_Release(oldTexture); + if(pTexture == NULL && Stage < MAX_TEXTURES) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP)); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP)); + } + + if(bindCount && old->baseTexture.sampler == Stage) { + int i; + /* Have to do a search for the other sampler(s) where the texture is bound to + * Shouldn't happen as long as apps bind a texture only to one stage + */ + TRACE("Searcing for other sampler / stage id where the texture is bound to\n"); + for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) { + if(This->updateStateBlock->textures[i] == oldTexture) { + old->baseTexture.sampler = i; + break; + } + } + } + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage)); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture); + + if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) { + Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS); + } + + *ppTexture=This->stateBlock->textures[Stage]; + if (*ppTexture) + IWineD3DBaseTexture_AddRef(*ppTexture); + + TRACE("(%p) : Returning %p\n", This, *ppTexture); + + return WINED3D_OK; +} + +/***** + * Get Back Buffer + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type, + IWineD3DSurface **ppBackBuffer) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSwapChain *swapChain; + HRESULT hr; + + TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer); + + hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain); + if (hr == WINED3D_OK) { + hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer); + IWineD3DSwapChain_Release(swapChain); + } else { + *ppBackBuffer = NULL; + } + return hr; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WARN("(%p) : stub, calling idirect3d for now\n", This); + return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps); +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSwapChain *swapChain; + HRESULT hr; + + if(iSwapChain > 0) { + hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain); + if (hr == WINED3D_OK) { + hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode); + IWineD3DSwapChain_Release(swapChain); + } else { + FIXME("(%p) Error getting display mode\n", This); + } + } else { + /* Don't read the real display mode, + but return the stored mode instead. X11 can't change the color + depth, and some apps are pretty angry if they SetDisplayMode from + 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp + + Also don't relay to the swapchain because with ddraw it's possible + that there isn't a swapchain at all */ + pMode->Width = This->ddraw_width; + pMode->Height = This->ddraw_height; + pMode->Format = This->ddraw_format; + pMode->RefreshRate = 0; + hr = WINED3D_OK; + } + + return hr; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)->(%p)\n", This, hWnd); + + if(This->ddraw_fullscreen) { + if(This->ddraw_window && This->ddraw_window != hWnd) { + IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window); + } + if(hWnd && This->ddraw_window != hWnd) { + IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd); + } + } + + This->ddraw_window = hWnd; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)->(%p)\n", This, hWnd); + + *hWnd = This->ddraw_window; + return WINED3D_OK; +} + +/***** + * Stateblock related functions + *****/ + +static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DStateBlockImpl *object; + HRESULT temp_result; + int i; + + ERR("(%p)\n", This); + + if (This->isRecordingState) { + return WINED3DERR_INVALIDCALL; + } + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl)); + if (NULL == object ) { + FIXME("(%p)Error allocating memory for stateblock\n", This); + return E_OUTOFMEMORY; + } + TRACE("(%p) created object %p\n", This, object); + object->wineD3DDevice= This; + /** FIXME: object->parent = parent; **/ + object->parent = NULL; + object->blockType = WINED3DSBT_RECORDED; + object->ref = 1; + object->lpVtbl = &IWineD3DStateBlock_Vtbl; + + for(i = 0; i < LIGHTMAP_SIZE; i++) { + list_init(&object->lightMap[i]); + } + + temp_result = allocate_shader_constants(object); + if (WINED3D_OK != temp_result) + return temp_result; + + IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock); + This->updateStateBlock = object; + This->isRecordingState = TRUE; + + TRACE("(%p) recording stateblock %p\n",This , object); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + unsigned int i, j; + IWineD3DStateBlockImpl *object = This->updateStateBlock; + + if (!This->isRecordingState) { + FIXME("(%p) not recording! returning error\n", This); + *ppStateBlock = NULL; + return WINED3DERR_INVALIDCALL; + } + + for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) { + if(object->changed.renderState[i]) { + object->contained_render_states[object->num_contained_render_states] = i; + object->num_contained_render_states++; + } + } + for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) { + if(object->changed.transform[i]) { + object->contained_transform_states[object->num_contained_transform_states] = i; + object->num_contained_transform_states++; + } + } + for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) { + if(object->changed.vertexShaderConstantsF[i]) { + object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i; + object->num_contained_vs_consts_f++; + } + } + for(i = 0; i < MAX_CONST_I; i++) { + if(object->changed.vertexShaderConstantsI[i]) { + object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i; + object->num_contained_vs_consts_i++; + } + } + for(i = 0; i < MAX_CONST_B; i++) { + if(object->changed.vertexShaderConstantsB[i]) { + object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i; + object->num_contained_vs_consts_b++; + } + } + for(i = 0; i < MAX_CONST_I; i++) { + if(object->changed.pixelShaderConstantsI[i]) { + object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i; + object->num_contained_ps_consts_i++; + } + } + for(i = 0; i < MAX_CONST_B; i++) { + if(object->changed.pixelShaderConstantsB[i]) { + object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i; + object->num_contained_ps_consts_b++; + } + } + for(i = 0; i < MAX_TEXTURES; i++) { + for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) { + if(object->changed.textureState[i][j]) { + object->contained_tss_states[object->num_contained_tss_states].stage = i; + object->contained_tss_states[object->num_contained_tss_states].state = j; + object->num_contained_tss_states++; + } + } + } + for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){ + for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) { + if(object->changed.samplerState[i][j]) { + object->contained_sampler_states[object->num_contained_sampler_states].stage = i; + object->contained_sampler_states[object->num_contained_sampler_states].state = j; + object->num_contained_sampler_states++; + } + } + } + + *ppStateBlock = (IWineD3DStateBlock*) object; + This->isRecordingState = FALSE; + This->updateStateBlock = This->stateBlock; + IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock); + /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */ + TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock); + return WINED3D_OK; +} + +/***** + * Scene related functions + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) { + /* At the moment we have no need for any functionality at the beginning + of a scene */ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)\n", This); + + if(This->inScene) { + TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + This->inScene = TRUE; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p)\n", This); + + if(!This->inScene) { + TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + + if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) { + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + /* We only have to do this if we need to read the, swapbuffers performs a flush for us */ + ENTER_GL(); + glFlush(); + checkGLcall("glFlush"); + LEAVE_GL(); + + This->inScene = FALSE; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface, + CONST RECT* pSourceRect, CONST RECT* pDestRect, + HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSwapChain *swapChain = NULL; + int i; + int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface); + + TRACE("(%p) Presenting the frame\n", This); + + for(i = 0 ; i < swapchains ; i ++) { + + IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain); + TRACE("presentinng chain %d, %p\n", i, swapChain); + IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0); + IWineD3DSwapChain_Release(swapChain); + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects, + DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0]; + + GLbitfield glMask = 0; + unsigned int i; + CONST WINED3DRECT* curRect; + + TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This, + Count, pRects, Flags, Color, Z, Stencil); + + if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) { + WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n"); + /* TODO: What about depth stencil buffers without stencil bits? */ + return WINED3DERR_INVALIDCALL; + } + + /* This is for offscreen rendering as well as for multithreading, thus activate the set render target + * and not the last active one. + */ + ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR); + ENTER_GL(); + + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { + apply_fbo_state(iface); + } + + if (Count > 0 && pRects) { + curRect = pRects; + } else { + curRect = NULL; + } + + /* Only set the values up once, as they are not changing */ + if (Flags & WINED3DCLEAR_STENCIL) { + glClearStencil(Stencil); + checkGLcall("glClearStencil"); + glMask = glMask | GL_STENCIL_BUFFER_BIT; + glStencilMask(0xFFFFFFFF); + } + + if (Flags & WINED3DCLEAR_ZBUFFER) { + glDepthMask(GL_TRUE); + glClearDepth(Z); + checkGLcall("glClearDepth"); + glMask = glMask | GL_DEPTH_BUFFER_BIT; + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE)); + } + + if (Flags & WINED3DCLEAR_TARGET) { + TRACE("Clearing screen with glClear to color %x\n", Color); + glClearColor(D3DCOLOR_R(Color), + D3DCOLOR_G(Color), + D3DCOLOR_B(Color), + D3DCOLOR_A(Color)); + checkGLcall("glClearColor"); + + /* Clear ALL colors! */ + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glMask = glMask | GL_COLOR_BUFFER_BIT; + } + + if (!curRect) { + /* In drawable flag is set below */ + + if (This->render_offscreen) { + glScissor(This->stateBlock->viewport.X, + This->stateBlock->viewport.Y, + This->stateBlock->viewport.Width, + This->stateBlock->viewport.Height); + } else { + glScissor(This->stateBlock->viewport.X, + (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - + (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)), + This->stateBlock->viewport.Width, + This->stateBlock->viewport.Height); + } + checkGLcall("glScissor"); + glClear(glMask); + checkGLcall("glClear"); + } else { + if(!(target->Flags & SFLAG_INDRAWABLE) && + !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) { + + if(curRect[0].x1 > 0 || curRect[0].y1 > 0 || + curRect[0].x2 < target->currentDesc.Width || + curRect[0].y2 < target->currentDesc.Height) { + TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n"); + blt_to_drawable(This, target); + } + } + + /* Now process each rect in turn */ + for (i = 0; i < Count; i++) { + /* Note gl uses lower left, width/height */ + TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect, + curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2, + curRect[i].x1, (target->currentDesc.Height - curRect[i].y2), + curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + + /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently. + * The rectangle is not cleared, no error is returned, but further rectanlges are + * still cleared if they are valid + */ + if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) { + TRACE("Rectangle with negative dimensions, ignoring\n"); + continue; + } + + if(This->render_offscreen) { + glScissor(curRect[i].x1, curRect[i].y1, + curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + } else { + glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2, + curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1); + } + checkGLcall("glScissor"); + + glClear(glMask); + checkGLcall("glClear"); + } + } + + /* Restore the old values (why..?) */ + if (Flags & WINED3DCLEAR_STENCIL) { + glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]); + } + if (Flags & WINED3DCLEAR_TARGET) { + DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE]; + glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE, + mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE, + mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE, + mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE); + } + + LEAVE_GL(); + + /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists, + * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it + */ + if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { + target->Flags |= SFLAG_INTEXTURE; + target->Flags &= ~SFLAG_INSYSMEM; + } else { + target->Flags |= SFLAG_INDRAWABLE; + target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM); + } + return WINED3D_OK; +} + +/***** + * Drawing functions + *****/ +static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, + UINT PrimitiveCount) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType, + debug_d3dprimitivetype(PrimitiveType), + StartVertex, PrimitiveCount); + + /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */ + if(This->stateBlock->streamIsUP) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + This->stateBlock->streamIsUP = FALSE; + } + + if(This->stateBlock->loadBaseVertexIndex != 0) { + This->stateBlock->loadBaseVertexIndex = 0; + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); + } + /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */ + drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */, + 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */); + return WINED3D_OK; +} + +/* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */ +static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, + WINED3DPRIMITIVETYPE PrimitiveType, + UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + UINT idxStride = 2; + IWineD3DIndexBuffer *pIB; + WINED3DINDEXBUFFER_DESC IdxBufDsc; + GLuint vbo; + + pIB = This->stateBlock->pIndexData; + if (!pIB) { + /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called + * without an index buffer set. (The first time at least...) + * D3D8 simply dies, but I doubt it can do much harm to return + * D3DERR_INVALIDCALL there as well. */ + ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This); + return WINED3DERR_INVALIDCALL; + } + + if(This->stateBlock->streamIsUP) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + This->stateBlock->streamIsUP = FALSE; + } + vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo; + + TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This, + PrimitiveType, debug_d3dprimitivetype(PrimitiveType), + minIndex, NumVertices, startIndex, primCount); + + IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc); + if (IdxBufDsc.Format == WINED3DFMT_INDEX16) { + idxStride = 2; + } else { + idxStride = 4; + } + + if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) { + This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex; + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); + } + + drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex, + idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, + UINT PrimitiveCount, CONST void* pVertexStreamZeroData, + UINT VertexStreamZeroStride) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType, + debug_d3dprimitivetype(PrimitiveType), + PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); + + /* Note in the following, it's not this type, but that's the purpose of streamIsUP */ + This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData; + This->stateBlock->streamOffset[0] = 0; + This->stateBlock->streamStride[0] = VertexStreamZeroStride; + This->stateBlock->streamIsUP = TRUE; + This->stateBlock->loadBaseVertexIndex = 0; + + /* TODO: Only mark dirty if drawing from a different UP address */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC); + + drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */, + 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */); + + /* MSDN specifies stream zero settings must be set to NULL */ + This->stateBlock->streamStride[0] = 0; + This->stateBlock->streamSource[0] = NULL; + + /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set + * the new stream sources or use UP drawing again + */ + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, + UINT MinVertexIndex, UINT NumVertices, + UINT PrimitiveCount, CONST void* pIndexData, + WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData, + UINT VertexStreamZeroStride) { + int idxStride; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DIndexBuffer *ib; + + TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n", + This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType), + MinVertexIndex, NumVertices, PrimitiveCount, pIndexData, + IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); + + if (IndexDataFormat == WINED3DFMT_INDEX16) { + idxStride = 2; + } else { + idxStride = 4; + } + + /* Note in the following, it's not this type, but that's the purpose of streamIsUP */ + This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData; + This->stateBlock->streamIsUP = TRUE; + This->stateBlock->streamOffset[0] = 0; + This->stateBlock->streamStride[0] = VertexStreamZeroStride; + + /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */ + This->stateBlock->baseVertexIndex = 0; + This->stateBlock->loadBaseVertexIndex = 0; + /* Mark the state dirty until we have nicer tracking of the stream source pointers */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + + drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex); + + /* MSDN specifies stream zero settings and index buffer must be set to NULL */ + This->stateBlock->streamSource[0] = NULL; + This->stateBlock->streamStride[0] = 0; + ib = This->stateBlock->pIndexData; + if(ib) { + IWineD3DIndexBuffer_Release(ib); + This->stateBlock->pIndexData = NULL; + } + /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call + * SetStreamSource to specify a vertex buffer + */ + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + + /* Mark the state dirty until we have nicer tracking + * its fine to change baseVertexIndex because that call is only called by ddraw which does not need + * that value. + */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + This->stateBlock->baseVertexIndex = 0; + This->up_strided = DrawPrimStrideData; + drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0); + This->up_strided = NULL; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2); + + /* Mark the state dirty until we have nicer tracking + * its fine to change baseVertexIndex because that call is only called by ddraw which does not need + * that value. + */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER); + This->stateBlock->streamIsUP = TRUE; + This->stateBlock->baseVertexIndex = 0; + This->up_strided = DrawPrimStrideData; + drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */); + This->up_strided = NULL; + return WINED3D_OK; +} + + +/* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */ +static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + HRESULT hr = WINED3D_OK; + WINED3DRESOURCETYPE sourceType; + WINED3DRESOURCETYPE destinationType; + int i ,levels; + + /* TODO: think about moving the code into IWineD3DBaseTexture */ + + TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture); + + /* verify that the source and destination textures aren't NULL */ + if (NULL == pSourceTexture || NULL == pDestinationTexture) { + WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n", + This, pSourceTexture, pDestinationTexture); + hr = WINED3DERR_INVALIDCALL; + } + + if (pSourceTexture == pDestinationTexture) { + WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n", + This, pSourceTexture, pDestinationTexture); + hr = WINED3DERR_INVALIDCALL; + } + /* Verify that the source and destination textures are the same type */ + sourceType = IWineD3DBaseTexture_GetType(pSourceTexture); + destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture); + + if (sourceType != destinationType) { + WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n", + This); + hr = WINED3DERR_INVALIDCALL; + } + + /* check that both textures have the identical numbers of levels */ + if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) { + WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture); + hr = WINED3DERR_INVALIDCALL; + } + + if (WINED3D_OK == hr) { + + /* Make sure that the destination texture is loaded */ + IWineD3DBaseTexture_PreLoad(pDestinationTexture); + + /* Update every surface level of the texture */ + levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture); + + switch (sourceType) { + case WINED3DRTYPE_TEXTURE: + { + IWineD3DSurface *srcSurface; + IWineD3DSurface *destSurface; + + for (i = 0 ; i < levels ; ++i) { + IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface); + IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface); + hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL); + IWineD3DSurface_Release(srcSurface); + IWineD3DSurface_Release(destSurface); + if (WINED3D_OK != hr) { + WARN("(%p) : Call to update surface failed\n", This); + return hr; + } + } + } + break; + case WINED3DRTYPE_CUBETEXTURE: + { + IWineD3DSurface *srcSurface; + IWineD3DSurface *destSurface; + WINED3DCUBEMAP_FACES faceType; + + for (i = 0 ; i < levels ; ++i) { + /* Update each cube face */ + for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){ + hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface); + if (WINED3D_OK != hr) { + FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i); + } else { + TRACE("Got srcSurface %p\n", srcSurface); + } + hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface); + if (WINED3D_OK != hr) { + FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i); + } else { + TRACE("Got desrSurface %p\n", destSurface); + } + hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL); + IWineD3DSurface_Release(srcSurface); + IWineD3DSurface_Release(destSurface); + if (WINED3D_OK != hr) { + WARN("(%p) : Call to update surface failed\n", This); + return hr; + } + } + } + } + break; +#if 0 /* TODO: Add support for volume textures */ + case WINED3DRTYPE_VOLUMETEXTURE: + { + IWineD3DVolume srcVolume = NULL; + IWineD3DSurface destVolume = NULL; + + for (i = 0 ; i < levels ; ++i) { + IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume); + IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume); + hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL); + IWineD3DVolume_Release(srcSurface); + IWineD3DVolume_Release(destSurface); + if (WINED3D_OK != hr) { + WARN("(%p) : Call to update volume failed\n", This); + return hr; + } + } + } + break; +#endif + default: + FIXME("(%p) : Unsupported source and destination type\n", This); + hr = WINED3DERR_INVALIDCALL; + } + } + + return hr; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) { + IWineD3DSwapChain *swapChain; + HRESULT hr; + hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain); + if(hr == WINED3D_OK) { + hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface); + IWineD3DSwapChain_Release(swapChain); + } + return hr; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + /* return a sensible default */ + *pNumPasses = 1; + /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */ + FIXME("(%p) : stub\n", This); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int j; + TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber); + if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) { + WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES); + return WINED3DERR_INVALIDCALL; + } + for (j = 0; j < 256; ++j) { + This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed; + This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen; + This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue; + This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags; + } + TRACE("(%p) : returning\n", This); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int j; + TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber); + if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) { + WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES); + return WINED3DERR_INVALIDCALL; + } + for (j = 0; j < 256; ++j) { + pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed; + pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen; + pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue; + pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags; + } + TRACE("(%p) : returning\n", This); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber); + if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) { + WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES); + return WINED3DERR_INVALIDCALL; + } + /*TODO: stateblocks */ + This->currentPalette = PaletteNumber; + TRACE("(%p) : returning\n", This); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + if (PaletteNumber == NULL) { + WARN("(%p) : returning Invalid Call\n", This); + return WINED3DERR_INVALIDCALL; + } + /*TODO: stateblocks */ + *PaletteNumber = This->currentPalette; + TRACE("(%p) : returning %u\n", This, *PaletteNumber); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + static BOOL showFixmes = TRUE; + if (showFixmes) { + FIXME("(%p) : stub\n", This); + showFixmes = FALSE; + } + + This->softwareVertexProcessing = bSoftware; + return WINED3D_OK; +} + + +static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + static BOOL showFixmes = TRUE; + if (showFixmes) { + FIXME("(%p) : stub\n", This); + showFixmes = FALSE; + } + return This->softwareVertexProcessing; +} + + +static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSwapChain *swapChain; + HRESULT hr; + + TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus); + + hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain); + if(hr == WINED3D_OK){ + hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus); + IWineD3DSwapChain_Release(swapChain); + }else{ + FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This); + } + return hr; +} + + +static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + static BOOL showfixmes = TRUE; + if(nSegments != 0.0f) { + if( showfixmes) { + FIXME("(%p) : stub nSegments(%f)\n", This, nSegments); + showfixmes = FALSE; + } + } + return WINED3D_OK; +} + +static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + static BOOL showfixmes = TRUE; + if( showfixmes) { + FIXME("(%p) : stub returning(%f)\n", This, 0.0f); + showfixmes = FALSE; + } + return 0.0f; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + /** TODO: remove casts to IWineD3DSurfaceImpl + * NOTE: move code to surface to accomplish this + ****************************************/ + IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface; + int srcWidth, srcHeight; + unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight; + WINED3DFORMAT destFormat, srcFormat; + UINT destSize; + int srcLeft, destLeft, destTop; + WINED3DPOOL srcPool, destPool; + int offset = 0; + int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */ + glDescriptor *glDescription = NULL; + GLenum dummy; + int bpp; + CONVERT_TYPES convert = NO_CONVERSION; + + WINED3DSURFACE_DESC winedesc; + + TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint); + memset(&winedesc, 0, sizeof(winedesc)); + winedesc.Width = &srcSurfaceWidth; + winedesc.Height = &srcSurfaceHeight; + winedesc.Pool = &srcPool; + winedesc.Format = &srcFormat; + + IWineD3DSurface_GetDesc(pSourceSurface, &winedesc); + + winedesc.Width = &destSurfaceWidth; + winedesc.Height = &destSurfaceHeight; + winedesc.Pool = &destPool; + winedesc.Format = &destFormat; + winedesc.Size = &destSize; + + IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); + + if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){ + WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface); + return WINED3DERR_INVALIDCALL; + } + + /* This call loads the opengl surface directly, instead of copying the surface to the + * destination's sysmem copy. If surface conversion is needed, use BltFast instead to + * copy in sysmem and use regular surface loading. + */ + d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE, + &dummy, &dummy, &dummy, &convert, &bpp, FALSE); + if(convert != NO_CONVERSION) { + return IWineD3DSurface_BltFast(pDestinationSurface, + pDestPoint ? pDestPoint->x : 0, + pDestPoint ? pDestPoint->y : 0, + pSourceSurface, (RECT *) pSourceRect, 0); + } + + if (destFormat == WINED3DFMT_UNKNOWN) { + TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This); + IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat); + + /* Get the update surface description */ + IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc); + } + + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + + ENTER_GL(); + + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); + checkGLcall("glActiveTextureARB"); + } + + /* Make sure the surface is loaded and up to date */ + IWineD3DSurface_PreLoad(pDestinationSurface); + + IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription); + + /* this needs to be done in lines if the sourceRect != the sourceWidth */ + srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth; + srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight; + srcLeft = pSourceRect ? pSourceRect->left : 0; + destLeft = pDestPoint ? pDestPoint->x : 0; + destTop = pDestPoint ? pDestPoint->y : 0; + + + /* This function doesn't support compressed textures + the pitch is just bytesPerPixel * width */ + if(srcWidth != srcSurfaceWidth || srcLeft ){ + rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel; + offset += srcLeft * pSrcSurface->bytesPerPixel; + /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */ + } + /* TODO DXT formats */ + + if(pSourceRect != NULL && pSourceRect->top != 0){ + offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel; + } + TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n" + ,This + ,glDescription->level + ,destLeft + ,destTop + ,srcWidth + ,srcHeight + ,glDescription->glFormat + ,glDescription->glType + ,IWineD3DSurface_GetData(pSourceSurface) + ); + + /* Sanity check */ + if (IWineD3DSurface_GetData(pSourceSurface) == NULL) { + + /* need to lock the surface to get the data */ + FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n"); + } + + /* TODO: Cube and volume support */ + if(rowoffset != 0){ + /* not a whole row so we have to do it a line at a time */ + int j; + + /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */ + const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset; + + for(j = destTop ; j < (srcHeight + destTop) ; j++){ + + glTexSubImage2D(glDescription->target + ,glDescription->level + ,destLeft + ,j + ,srcWidth + ,1 + ,glDescription->glFormat + ,glDescription->glType + ,data /* could be quicker using */ + ); + data += rowoffset; + } + + } else { /* Full width, so just write out the whole texture */ + + if (WINED3DFMT_DXT1 == destFormat || + WINED3DFMT_DXT2 == destFormat || + WINED3DFMT_DXT3 == destFormat || + WINED3DFMT_DXT4 == destFormat || + WINED3DFMT_DXT5 == destFormat) { + if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { + if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) { + /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */ + FIXME("Updating part of a compressed texture is not supported at the moment\n"); + } if (destFormat != srcFormat) { + FIXME("Updating mixed format compressed texture is not curretly support\n"); + } else { + GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target, + glDescription->level, + glDescription->glFormatInternal, + srcWidth, + srcHeight, + 0, + destSize, + IWineD3DSurface_GetData(pSourceSurface)); + } + } else { + FIXME("Attempting to update a DXT compressed texture without hardware support\n"); + } + + + } else { + glTexSubImage2D(glDescription->target + ,glDescription->level + ,destLeft + ,destTop + ,srcWidth + ,srcHeight + ,glDescription->glFormat + ,glDescription->glType + ,IWineD3DSurface_GetData(pSourceSurface) + ); + } + } + checkGLcall("glTexSubImage2D"); + + LEAVE_GL(); + + ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM; + ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE; + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0)); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + struct WineD3DRectPatch *patch; + unsigned int i; + struct list *e; + BOOL found; + TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo); + + if(!(Handle || pRectPatchInfo)) { + /* TODO: Write a test for the return value, thus the FIXME */ + FIXME("Both Handle and pRectPatchInfo are NULL\n"); + return WINED3DERR_INVALIDCALL; + } + + if(Handle) { + i = PATCHMAP_HASHFUNC(Handle); + found = FALSE; + LIST_FOR_EACH(e, &This->patches[i]) { + patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry); + if(patch->Handle == Handle) { + found = TRUE; + break; + } + } + + if(!found) { + TRACE("Patch does not exist. Creating a new one\n"); + patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch)); + patch->Handle = Handle; + list_add_head(&This->patches[i], &patch->entry); + } else { + TRACE("Found existing patch %p\n", patch); + } + } else { + /* Since opengl does not load tesselated vertex attributes into numbered vertex + * attributes we have to tesselate, read back, and draw. This needs a patch + * management structure instance. Create one. + * + * A possible improvement is to check if a vertex shader is used, and if not directly + * draw the patch. + */ + FIXME("Drawing an uncached patch. This is slow\n"); + patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch)); + } + + if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] || + pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] || + (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) { + HRESULT hr; + TRACE("Tesselation density or patch info changed, retesselating\n"); + + if(pRectPatchInfo) { + memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo)); + } + patch->numSegs[0] = pNumSegs[0]; + patch->numSegs[1] = pNumSegs[1]; + patch->numSegs[2] = pNumSegs[2]; + patch->numSegs[3] = pNumSegs[3]; + + hr = tesselate_rectpatch(This, patch); + if(FAILED(hr)) { + WARN("Patch tesselation failed\n"); + + /* Do not release the handle to store the params of the patch */ + if(!Handle) { + HeapFree(GetProcessHeap(), 0, patch); + } + return hr; + } + } + + This->currentPatch = patch; + IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided); + This->currentPatch = NULL; + + /* Destroy uncached patches */ + if(!Handle) { + HeapFree(GetProcessHeap(), 0, patch->mem); + HeapFree(GetProcessHeap(), 0, patch); + } + return WINED3D_OK; +} + +/* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */ +static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo); + FIXME("(%p) : Stub\n", This); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + int i; + struct WineD3DRectPatch *patch; + struct list *e; + TRACE("(%p) Handle(%d)\n", This, Handle); + + i = PATCHMAP_HASHFUNC(Handle); + LIST_FOR_EACH(e, &This->patches[i]) { + patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry); + if(patch->Handle == Handle) { + TRACE("Deleting patch %p\n", patch); + list_remove(&patch->entry); + HeapFree(GetProcessHeap(), 0, patch->mem); + HeapFree(GetProcessHeap(), 0, patch); + return WINED3D_OK; + } + } + + /* TODO: Write a test for the return value */ + FIXME("Attempt to destroy nonexistant patch\n"); + return WINED3DERR_INVALIDCALL; +} + +static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) { + HRESULT hr; + IWineD3DSwapChain *swapchain; + + hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain); + if (SUCCEEDED(hr)) { + IWineD3DSwapChain_Release((IUnknown *)swapchain); + return swapchain; + } + + return NULL; +} + +static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + if (!*fbo) { + GL_EXTCALL(glGenFramebuffersEXT(1, fbo)); + checkGLcall("glGenFramebuffersEXT()"); + } + GL_EXTCALL(glBindFramebufferEXT(target, *fbo)); + checkGLcall("glBindFramebuffer()"); +} + +static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) { + const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface; + IWineD3DBaseTextureImpl *texture_impl; + GLenum texttarget, target; + GLint old_binding; + + texttarget = surface_impl->glDescription.target; + target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB; + glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding); + + IWineD3DSurface_PreLoad(surface); + + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(target, old_binding); + + /* Update base texture states array */ + if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) { + texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; + texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; + if (texture_impl->baseTexture.bindCount) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler)); + } + + IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl); + } + + GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0)); + + checkGLcall("attach_surface_fbo"); +} + +static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DSwapChain *swapchain; + + swapchain = get_swapchain(surface); + if (swapchain) { + GLenum buffer; + + TRACE("Surface %p is onscreen\n", surface); + + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + buffer = surface_get_gl_buffer(surface, swapchain); + glDrawBuffer(buffer); + checkGLcall("glDrawBuffer()"); + } else { + TRACE("Surface %p is offscreen\n", surface); + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo); + attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface); + } + + if (rect) { + glEnable(GL_SCISSOR_TEST); + if(!swapchain) { + glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1); + } else { + glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2, + rect->x2 - rect->x1, rect->y2 - rect->y1); + } + checkGLcall("glScissor"); + } else { + glDisable(GL_SCISSOR_TEST); + } + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE)); + + glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)); + glClear(GL_COLOR_BUFFER_BIT); + checkGLcall("glClear"); + + if (This->render_offscreen) { + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); + } else { + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + checkGLcall("glBindFramebuffer()"); + } + + if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer + && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer()"); + } +} + +static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface; + WINEDDBLTFX BltFx; + TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color); + + if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) { + FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n"); + return WINED3DERR_INVALIDCALL; + } + + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { + color_fill_fbo(iface, pSurface, pRect, color); + return WINED3D_OK; + } else { + /* Just forward this to the DirectDraw blitting engine */ + memset(&BltFx, 0, sizeof(BltFx)); + BltFx.dwSize = sizeof(BltFx); + BltFx.u5.dwFillColor = color; + return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE); + } +} + +/* rendertarget and deptth stencil functions */ +static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + if (RenderTargetIndex >= GL_LIMITS(buffers)) { + ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers)); + return WINED3DERR_INVALIDCALL; + } + + *ppRenderTarget = This->render_targets[RenderTargetIndex]; + TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget); + /* Note inc ref on returned surface */ + if(*ppRenderTarget != NULL) + IWineD3DSurface_AddRef(*ppRenderTarget); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front; + IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back; + IWineD3DSwapChainImpl *Swapchain; + HRESULT hr; + + TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl); + + hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain); + if(hr != WINED3D_OK) { + ERR("Can't get the swapchain\n"); + return hr; + } + + /* Make sure to release the swapchain */ + IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain); + + if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) { + ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n"); + return WINED3DERR_INVALIDCALL; + } + else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) { + ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n"); + return WINED3DERR_INVALIDCALL; + } + + if(Swapchain->frontBuffer != Front) { + TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front); + + if(Swapchain->frontBuffer) + IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL); + Swapchain->frontBuffer = Front; + + if(Swapchain->frontBuffer) { + IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain); + } + } + + if(Back && !Swapchain->backBuffer) { + /* We need memory for the back buffer array - only one back buffer this way */ + Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *)); + if(!Swapchain->backBuffer) { + ERR("Out of memory\n"); + return E_OUTOFMEMORY; + } + } + + if(Swapchain->backBuffer[0] != Back) { + TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back); + + /* What to do about the context here in the case of multithreading? Not sure. + * This function is called by IDirect3D7::CreateDevice so in theory its initialization code + */ + ENTER_GL(); + if(!Swapchain->backBuffer[0]) { + /* GL was told to draw to the front buffer at creation, + * undo that + */ + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer(GL_BACK)"); + /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */ + Swapchain->presentParms.BackBufferCount = 1; + } else if (!Back) { + /* That makes problems - disable for now */ + /* glDrawBuffer(GL_FRONT); */ + checkGLcall("glDrawBuffer(GL_FRONT)"); + /* We have lost our back buffer, set this to 0 to avoid confusing other code */ + Swapchain->presentParms.BackBufferCount = 0; + } + LEAVE_GL(); + + if(Swapchain->backBuffer[0]) + IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL); + Swapchain->backBuffer[0] = Back; + + if(Swapchain->backBuffer[0]) { + IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain); + } else { + HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer); + } + + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + *ppZStencilSurface = This->depthStencilBuffer; + TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface); + + if(*ppZStencilSurface != NULL) { + /* Note inc ref on returned surface */ + IWineD3DSurface_AddRef(*ppZStencilSurface); + } + return WINED3D_OK; +} + +/* TODO: Handle stencil attachments */ +static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil; + + TRACE("Set depth stencil to %p\n", depth_stencil); + + if (depth_stencil_impl) { + if (depth_stencil_impl->current_renderbuffer) { + GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id)); + checkGLcall("glFramebufferRenderbufferEXT()"); + } else { + IWineD3DBaseTextureImpl *texture_impl; + GLenum texttarget, target; + GLint old_binding = 0; + + texttarget = depth_stencil_impl->glDescription.target; + target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB; + glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding); + + IWineD3DSurface_PreLoad(depth_stencil); + + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); + glBindTexture(target, old_binding); + + /* Update base texture states array */ + if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) { + texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; + texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT; + if (texture_impl->baseTexture.bindCount) { + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler)); + } + + IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl); + } + + GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0)); + checkGLcall("glFramebufferTexture2DEXT()"); + } + } else { + GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0)); + checkGLcall("glFramebufferTexture2DEXT()"); + } +} + +static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target; + + TRACE("Set render target %u to %p\n", idx, render_target); + + if (rtimpl) { + attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target); + This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx; + } else { + GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0)); + checkGLcall("glFramebufferTexture2DEXT()"); + + This->draw_buffers[idx] = GL_NONE; + } +} + +static void check_fbo_status(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + GLenum status; + + status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)); + if (status == GL_FRAMEBUFFER_COMPLETE_EXT) { + TRACE("FBO complete\n"); + } else { + FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status); + + /* Dump the FBO attachments */ + if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) { + IWineD3DSurfaceImpl *attachment; + int i; + + for (i = 0; i < GL_LIMITS(buffers); ++i) { + attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i]; + if (attachment) { + FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format), + attachment->pow2Width, attachment->pow2Height); + } + } + attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment; + if (attachment) { + FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format), + attachment->pow2Width, attachment->pow2Height); + } + } + } +} + +static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0]; + IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget; + + if (!ds_impl) return FALSE; + + if (ds_impl->current_renderbuffer) { + return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width || + rt_impl->pow2Height != ds_impl->current_renderbuffer->height); + } + + return (rt_impl->pow2Width != ds_impl->pow2Width || + rt_impl->pow2Height != ds_impl->pow2Height); +} + +void apply_fbo_state(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + unsigned int i; + + if (This->render_offscreen) { + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); + + /* Apply render targets */ + for (i = 0; i < GL_LIMITS(buffers); ++i) { + IWineD3DSurface *render_target = This->render_targets[i]; + if (This->fbo_color_attachments[i] != render_target) { + set_render_target_fbo(iface, i, render_target); + This->fbo_color_attachments[i] = render_target; + } + } + + /* Apply depth targets */ + if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) { + unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width; + unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height; + + if (This->stencilBufferTarget) { + surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h); + } + set_depth_stencil_fbo(iface, This->stencilBufferTarget); + This->fbo_depth_attachment = This->stencilBufferTarget; + } + + if (GL_SUPPORT(ARB_DRAW_BUFFERS)) { + GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers)); + checkGLcall("glDrawBuffers()"); + } else { + glDrawBuffer(This->draw_buffers[0]); + checkGLcall("glDrawBuffer()"); + } + } else { + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + } + + check_fbo_status(iface); +} + +void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect, + IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */ + IWineD3DSwapChain *src_swapchain, *dst_swapchain; + GLenum gl_filter; + + TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n", + This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip); + TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2); + TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2); + + switch (filter) { + case WINED3DTEXF_LINEAR: + gl_filter = GL_LINEAR; + break; + + default: + FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter); + case WINED3DTEXF_NONE: + case WINED3DTEXF_POINT: + gl_filter = GL_NEAREST; + break; + } + + /* Attach src surface to src fbo */ + src_swapchain = get_swapchain(src_surface); + if (src_swapchain) { + GLenum buffer; + + TRACE("Source surface %p is onscreen\n", src_surface); + ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD); + + ENTER_GL(); + GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0)); + buffer = surface_get_gl_buffer(src_surface, src_swapchain); + glReadBuffer(buffer); + checkGLcall("glReadBuffer()"); + + src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1; + src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2; + } else { + TRACE("Source surface %p is offscreen\n", src_surface); + ENTER_GL(); + bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo); + attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + checkGLcall("glReadBuffer()"); + } + LEAVE_GL(); + + /* Attach dst surface to dst fbo */ + dst_swapchain = get_swapchain(dst_surface); + if (dst_swapchain) { + GLenum buffer; + + TRACE("Destination surface %p is onscreen\n", dst_surface); + ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD); + + ENTER_GL(); + GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0)); + buffer = surface_get_gl_buffer(dst_surface, dst_swapchain); + glDrawBuffer(buffer); + checkGLcall("glDrawBuffer()"); + + dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1; + dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2; + } else { + TRACE("Destination surface %p is offscreen\n", dst_surface); + + /* No src or dst swapchain? Make sure some context is active(multithreading) */ + if(!src_swapchain) { + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + ENTER_GL(); + bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo); + attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + checkGLcall("glDrawBuffer()"); + } + glDisable(GL_SCISSOR_TEST); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE)); + + if (flip) { + GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2, + dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter)); + checkGLcall("glBlitFramebuffer()"); + } else { + GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2, + dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter)); + checkGLcall("glBlitFramebuffer()"); + } + + if (This->render_offscreen) { + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); + } else { + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + checkGLcall("glBindFramebuffer()"); + } + + /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */ + if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer + && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer()"); + } + LEAVE_GL(); +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WINED3DVIEWPORT viewport; + + TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget); + + if (RenderTargetIndex >= GL_LIMITS(buffers)) { + ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers)); + return WINED3DERR_INVALIDCALL; + } + + /* MSDN says that null disables the render target + but a device must always be associated with a render target + nope MSDN says that we return invalid call to a null rendertarget with an index of 0 + + see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp + for more details + */ + if (RenderTargetIndex == 0 && pRenderTarget == NULL) { + FIXME("Trying to set render target 0 to NULL\n"); + return WINED3DERR_INVALIDCALL; + } + if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) { + FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget); + return WINED3DERR_INVALIDCALL; + } + + /* If we are trying to set what we already have, don't bother */ + if (pRenderTarget == This->render_targets[RenderTargetIndex]) { + TRACE("Trying to do a NOP SetRenderTarget operation\n"); + return WINED3D_OK; + } + if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget); + if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]); + This->render_targets[RenderTargetIndex] = pRenderTarget; + + /* Render target 0 is special */ + if(RenderTargetIndex == 0) { + /* Finally, reset the viewport as the MSDN states. */ + viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height; + viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width; + viewport.X = 0; + viewport.Y = 0; + viewport.MaxZ = 1.0f; + viewport.MinZ = 0.0f; + IWineD3DDeviceImpl_SetViewport(iface, &viewport); + /* Make sure the viewport state is dirty, because the render_offscreen thing affects it. + * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets + */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT); + + /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the + * ctx properly. + * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be + * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called. + */ + ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD); + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + HRESULT hr = WINED3D_OK; + IWineD3DSurface *tmp; + + TRACE("(%p) Swapping z-buffer\n",This); + + if (pNewZStencil == This->stencilBufferTarget) { + TRACE("Trying to do a NOP SetRenderTarget operation\n"); + } else { + /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead + * depending on the renter target implementation being used. + * A shared context implementation will share all buffers between all rendertargets (including swapchains), + * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the + * stencil buffer and incure an extra memory overhead + ******************************************************/ + + tmp = This->stencilBufferTarget; + This->stencilBufferTarget = pNewZStencil; + This->depth_copy_state = WINED3D_DCS_NO_COPY; + /* should we be calling the parent or the wined3d surface? */ + if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget); + if (NULL != tmp) IWineD3DSurface_Release(tmp); + hr = WINED3D_OK; + + if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) { + /* Swapping NULL / non NULL depth stencil affects the depth and tests */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE)); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE)); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK)); + } + } + + return hr; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot, + UINT YHotSpot, IWineD3DSurface *pCursorBitmap) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + /* TODO: the use of Impl is deprecated. */ + IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap; + WINED3DLOCKED_RECT lockedRect; + + TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot); + + /* some basic validation checks */ + if(This->cursorTexture) { + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + glDeleteTextures(1, &This->cursorTexture); + LEAVE_GL(); + This->cursorTexture = 0; + } + + if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) ) + This->haveHardwareCursor = TRUE; + else + This->haveHardwareCursor = FALSE; + + if(pCursorBitmap) { + WINED3DLOCKED_RECT rect; + + /* MSDN: Cursor must be A8R8G8B8 */ + if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) { + ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap); + return WINED3DERR_INVALIDCALL; + } + + /* MSDN: Cursor must be smaller than the display mode */ + if(pSur->currentDesc.Width > This->ddraw_width || + pSur->currentDesc.Height > This->ddraw_height) { + ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height); + return WINED3DERR_INVALIDCALL; + } + + if (!This->haveHardwareCursor) { + /* TODO: MSDN: Cursor sizes must be a power of 2 */ + + /* Do not store the surface's pointer because the application may + * release it after setting the cursor image. Windows doesn't + * addref the set surface, so we can't do this either without + * creating circular refcount dependencies. Copy out the gl texture + * instead. + */ + This->cursorWidth = pSur->currentDesc.Width; + This->cursorHeight = pSur->currentDesc.Height; + if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY))) + { + const GlPixelFormatDesc *glDesc; + const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc); + char *mem, *bits = (char *)rect.pBits; + GLint intfmt = glDesc->glInternal; + GLint format = glDesc->glFormat; + GLint type = glDesc->glType; + INT height = This->cursorHeight; + INT width = This->cursorWidth; + INT bpp = tableEntry->bpp; + INT i; + + /* Reformat the texture memory (pitch and width can be + * different) */ + mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp); + for(i = 0; i < height; i++) + memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp); + IWineD3DSurface_UnlockRect(pCursorBitmap); + ENTER_GL(); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); + } + + /* Make sure that a proper texture unit is selected */ + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); + checkGLcall("glActiveTextureARB"); + } + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0)); + /* Create a new cursor texture */ + glGenTextures(1, &This->cursorTexture); + checkGLcall("glGenTextures"); + glBindTexture(GL_TEXTURE_2D, This->cursorTexture); + checkGLcall("glBindTexture"); + /* Copy the bitmap memory into the cursor texture */ + glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem); + HeapFree(GetProcessHeap(), 0, mem); + checkGLcall("glTexImage2D"); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } + + LEAVE_GL(); + } + else + { + FIXME("A cursor texture was not returned.\n"); + This->cursorTexture = 0; + } + } + else + { + /* Draw a hardware cursor */ + ICONINFO cursorInfo; + HCURSOR cursor; + /* Create and clear maskBits because it is not needed for + * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32 + * chunks. */ + DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + (pSur->currentDesc.Width * pSur->currentDesc.Height / 8)); + IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL, + WINED3DLOCK_NO_DIRTY_UPDATE | + WINED3DLOCK_READONLY + ); + TRACE("width: %i height: %i\n", pSur->currentDesc.Width, + pSur->currentDesc.Height); + + cursorInfo.fIcon = FALSE; + cursorInfo.xHotspot = XHotSpot; + cursorInfo.yHotspot = YHotSpot; + cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, + pSur->currentDesc.Height, 1, + 1, &maskBits); + cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, + pSur->currentDesc.Height, 1, + 32, lockedRect.pBits); + IWineD3DSurface_UnlockRect(pCursorBitmap); + /* Create our cursor and clean up. */ + cursor = CreateIconIndirect(&cursorInfo); + SetCursor(cursor); + if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask); + if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor); + if (This->hardwareCursor) DestroyCursor(This->hardwareCursor); + This->hardwareCursor = cursor; + HeapFree(GetProcessHeap(), 0, maskBits); + } + } + + This->xHotSpot = XHotSpot; + This->yHotSpot = YHotSpot; + return WINED3D_OK; +} + +static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace); + + This->xScreenSpace = XScreenSpace; + This->yScreenSpace = YScreenSpace; + + return; + +} + +static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + BOOL oldVisible = This->bCursorVisible; + POINT pt; + + TRACE("(%p) : visible(%d)\n", This, bShow); + + /* + * When ShowCursor is first called it should make the cursor appear at the OS's last + * known cursor position. Because of this, some applications just repetitively call + * ShowCursor in order to update the cursor's position. This behavior is undocumented. + */ + GetCursorPos(&pt); + This->xScreenSpace = pt.x; + This->yScreenSpace = pt.y; + + if (This->haveHardwareCursor) { + This->bCursorVisible = bShow; + if (bShow) + SetCursor(This->hardwareCursor); + else + SetCursor(NULL); + } + else + { + if (This->cursorTexture) + This->bCursorVisible = bShow; + } + + return oldVisible; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + TRACE("(%p) : state (%u)\n", This, This->state); + /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */ + switch (This->state) { + case WINED3D_OK: + return WINED3D_OK; + case WINED3DERR_DEVICELOST: + { + ResourceList *resourceList = This->resources; + while (NULL != resourceList) { + if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/) + return WINED3DERR_DEVICENOTRESET; + resourceList = resourceList->next; + } + return WINED3DERR_DEVICELOST; + } + case WINED3DERR_DRIVERINTERNALERROR: + return WINED3DERR_DRIVERINTERNALERROR; + } + + /* Unknown state */ + return WINED3DERR_DRIVERINTERNALERROR; +} + + +static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + /** FIXME: Resource tracking needs to be done, + * The closes we can do to this is set the priorities of all managed textures low + * and then reset them. + ***********************************************************/ + FIXME("(%p) : stub\n", This); + return WINED3D_OK; +} + +static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) { + IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */ + + /* Reallocate proper memory for the front and back buffer and adjust their sizes */ + if(surface->Flags & SFLAG_DIBSECTION) { + /* Release the DC */ + SelectObject(surface->hDC, surface->dib.holdbitmap); + DeleteDC(surface->hDC); + /* Release the DIB section */ + DeleteObject(surface->dib.DIBsection); + surface->dib.bitmap_data = NULL; + surface->resource.allocatedMemory = NULL; + surface->Flags &= ~SFLAG_DIBSECTION; + } + surface->currentDesc.Width = pPresentationParameters->BackBufferWidth; + surface->currentDesc.Height = pPresentationParameters->BackBufferHeight; + if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) { + surface->pow2Width = pPresentationParameters->BackBufferWidth; + surface->pow2Height = pPresentationParameters->BackBufferHeight; + } else { + surface->pow2Width = surface->pow2Height = 1; + while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1; + while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1; + } + if(surface->glDescription.textureName) { + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + glDeleteTextures(1, &surface->glDescription.textureName); + LEAVE_GL(); + surface->glDescription.textureName = 0; + surface->Flags &= ~SFLAG_CLIENT; + } + if(surface->pow2Width != pPresentationParameters->BackBufferWidth || + surface->pow2Height != pPresentationParameters->BackBufferHeight) { + surface->Flags |= SFLAG_NONPOW2; + } else { + surface->Flags &= ~SFLAG_NONPOW2; + } + HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory); + surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DSwapChainImpl *swapchain; + HRESULT hr; + BOOL DisplayModeChanged = FALSE; + WINED3DDISPLAYMODE mode; + TRACE("(%p)\n", This); + + hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain); + if(FAILED(hr)) { + ERR("Failed to get the first implicit swapchain\n"); + return hr; + } + + /* Is it necessary to recreate the gl context? Actually every setting can be changed + * on an existing gl context, so there's no real need for recreation. + * + * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED + * + * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain + */ + TRACE("New params:\n"); + TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth); + TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight); + TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat)); + TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount); + TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType); + TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality); + TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect); + TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow); + TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false"); + TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false"); + TRACE("Flags = %08x\n", pPresentationParameters->Flags); + TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz); + TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval); + + /* No special treatment of these parameters. Just store them */ + swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect; + swapchain->presentParms.Flags = pPresentationParameters->Flags; + swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval; + swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz; + + /* What to do about these? */ + if(pPresentationParameters->BackBufferCount != 0 && + pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) { + ERR("Cannot change the back buffer count yet\n"); + } + if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN && + pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) { + ERR("Cannot change the back buffer format yet\n"); + } + if(pPresentationParameters->hDeviceWindow != NULL && + pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) { + ERR("Cannot change the device window yet\n"); + } + if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) { + ERR("What do do about a changed auto depth stencil parameter?\n"); + } + + if(pPresentationParameters->Windowed) { + mode.Width = swapchain->orig_width; + mode.Height = swapchain->orig_height; + mode.RefreshRate = 0; + mode.Format = swapchain->presentParms.BackBufferFormat; + } else { + mode.Width = pPresentationParameters->BackBufferWidth; + mode.Height = pPresentationParameters->BackBufferHeight; + mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz; + mode.Format = swapchain->presentParms.BackBufferFormat; + } + + /* Should Width == 800 && Height == 0 set 800x600? */ + if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 && + (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth || + pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight)) + { + WINED3DVIEWPORT vp; + int i; + + vp.X = 0; + vp.Y = 0; + vp.Width = pPresentationParameters->BackBufferWidth; + vp.Height = pPresentationParameters->BackBufferHeight; + vp.MinZ = 0; + vp.MaxZ = 1; + + if(!pPresentationParameters->Windowed) { + DisplayModeChanged = TRUE; + } + swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth; + swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight; + + updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters); + for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) { + updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters); + } + + /* Now set the new viewport */ + IWineD3DDevice_SetViewport(iface, &vp); + } + + if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) || + (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) || + DisplayModeChanged) { + + /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */ + if(!pPresentationParameters->Windowed) { + IWineD3DDevice_SetFullscreen(iface, TRUE); + } + + IWineD3DDevice_SetDisplayMode(iface, 0, &mode); + + /* Switching out of fullscreen mode? First set the original res, then change the window */ + if(pPresentationParameters->Windowed) { + IWineD3DDevice_SetFullscreen(iface, FALSE); + } + swapchain->presentParms.Windowed = pPresentationParameters->Windowed; + } + + IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + /** FIXME: always true at the moment **/ + if(!bEnableDialogs) { + FIXME("(%p) Dialogs cannot be disabled yet\n", This); + } + return WINED3D_OK; +} + + +static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + TRACE("(%p) : pParameters %p\n", This, pParameters); + + *pParameters = This->createParms; + return WINED3D_OK; +} + +static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) { + IWineD3DSwapChain *swapchain; + HRESULT hrc = WINED3D_OK; + + TRACE("Relaying to swapchain\n"); + + if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) { + IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp); + IWineD3DSwapChain_Release(swapchain); + } + return; +} + +static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) { + IWineD3DSwapChain *swapchain; + HRESULT hrc = WINED3D_OK; + + TRACE("Relaying to swapchain\n"); + + if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) { + hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp); + IWineD3DSwapChain_Release(swapchain); + } + return; +} + + +/** ******************************************************** +* Notification functions +** ********************************************************/ +/** This function must be called in the release of a resource when ref == 0, +* the contents of resource must still be correct, +* any handels to other resource held by the caller must be closed +* (e.g. a texture should release all held surfaces because telling the device that it's been released.) + *****************************************************/ +static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + ResourceList* resourceList; + + TRACE("(%p) : resource %p\n", This, resource); + /* add a new texture to the frot of the linked list */ + resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList)); + resourceList->resource = resource; + + /* Get the old head */ + resourceList->next = This->resources; + + This->resources = resourceList; + TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next); + + return; +} + +static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + ResourceList* resourceList = NULL; + ResourceList* previousResourceList = NULL; + + TRACE("(%p) : resource %p\n", This, resource); + + resourceList = This->resources; + + while (resourceList != NULL) { + if(resourceList->resource == resource) break; + previousResourceList = resourceList; + resourceList = resourceList->next; + } + + if (resourceList == NULL) { + FIXME("Attempted to remove resource %p that hasn't been stored\n", resource); + return; + } else { + TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList); + } + /* make sure we don't leave a hole in the list */ + if (previousResourceList != NULL) { + previousResourceList->next = resourceList->next; + } else { + This->resources = resourceList->next; + } + + return; +} + + +static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + int counter; + + TRACE("(%p) : resource %p\n", This, resource); + switch(IWineD3DResource_GetType(resource)){ + /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */ + case WINED3DRTYPE_SURFACE: { + unsigned int i; + + /* Cleanup any FBO attachments if d3d is enabled */ + if(This->d3d_initialized) { + for (i = 0; i < GL_LIMITS(buffers); ++i) { + if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) { + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); + set_render_target_fbo(iface, i, NULL); + This->fbo_color_attachments[i] = NULL; + } + } + if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) { + bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo); + set_depth_stencil_fbo(iface, NULL); + This->fbo_depth_attachment = NULL; + } + } + + break; + } + case WINED3DRTYPE_TEXTURE: + case WINED3DRTYPE_CUBETEXTURE: + case WINED3DRTYPE_VOLUMETEXTURE: + for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) { + if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) { + WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource); + This->stateBlock->textures[counter] = NULL; + } + if (This->updateStateBlock != This->stateBlock ){ + if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) { + WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource); + This->updateStateBlock->textures[counter] = NULL; + } + } + } + break; + case WINED3DRTYPE_VOLUME: + /* TODO: nothing really? */ + break; + case WINED3DRTYPE_VERTEXBUFFER: + /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */ + { + int streamNumber; + TRACE("Cleaning up stream pointers\n"); + + for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){ + /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost? + FINDOUT: should changes.streamSource[StreamNumber] be set ? + */ + if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */ + if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) { + FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber); + This->updateStateBlock->streamSource[streamNumber] = 0; + /* Set changed flag? */ + } + } + if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */ + if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) { + TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber); + This->stateBlock->streamSource[streamNumber] = 0; + } + } +#if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */ + else { /* This shouldn't happen */ + FIXME("Calling application has released the device before relasing all the resources bound to the device\n"); + } +#endif + + } + } + break; + case WINED3DRTYPE_INDEXBUFFER: + /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/ + if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */ + if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) { + This->updateStateBlock->pIndexData = NULL; + } + } + if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */ + if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) { + This->stateBlock->pIndexData = NULL; + } + } + + break; + default: + FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource)); + break; + } + + + /* Remove the resoruce from the resourceStore */ + IWineD3DDeviceImpl_RemoveResource(iface, resource); + + TRACE("Resource released\n"); + +} + +/********************************************************** + * IWineD3DDevice VTbl follows + **********************************************************/ + +const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl = +{ + /*** IUnknown methods ***/ + IWineD3DDeviceImpl_QueryInterface, + IWineD3DDeviceImpl_AddRef, + IWineD3DDeviceImpl_Release, + /*** IWineD3DDevice methods ***/ + IWineD3DDeviceImpl_GetParent, + /*** Creation methods**/ + IWineD3DDeviceImpl_CreateVertexBuffer, + IWineD3DDeviceImpl_CreateIndexBuffer, + IWineD3DDeviceImpl_CreateStateBlock, + IWineD3DDeviceImpl_CreateSurface, + IWineD3DDeviceImpl_CreateTexture, + IWineD3DDeviceImpl_CreateVolumeTexture, + IWineD3DDeviceImpl_CreateVolume, + IWineD3DDeviceImpl_CreateCubeTexture, + IWineD3DDeviceImpl_CreateQuery, + IWineD3DDeviceImpl_CreateAdditionalSwapChain, + IWineD3DDeviceImpl_CreateVertexDeclaration, + IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF, + IWineD3DDeviceImpl_CreateVertexShader, + IWineD3DDeviceImpl_CreatePixelShader, + IWineD3DDeviceImpl_CreatePalette, + /*** Odd functions **/ + IWineD3DDeviceImpl_Init3D, + IWineD3DDeviceImpl_Uninit3D, + IWineD3DDeviceImpl_SetFullscreen, + IWineD3DDeviceImpl_SetMultithreaded, + IWineD3DDeviceImpl_EvictManagedResources, + IWineD3DDeviceImpl_GetAvailableTextureMem, + IWineD3DDeviceImpl_GetBackBuffer, + IWineD3DDeviceImpl_GetCreationParameters, + IWineD3DDeviceImpl_GetDeviceCaps, + IWineD3DDeviceImpl_GetDirect3D, + IWineD3DDeviceImpl_GetDisplayMode, + IWineD3DDeviceImpl_SetDisplayMode, + IWineD3DDeviceImpl_GetHWND, + IWineD3DDeviceImpl_SetHWND, + IWineD3DDeviceImpl_GetNumberOfSwapChains, + IWineD3DDeviceImpl_GetRasterStatus, + IWineD3DDeviceImpl_GetSwapChain, + IWineD3DDeviceImpl_Reset, + IWineD3DDeviceImpl_SetDialogBoxMode, + IWineD3DDeviceImpl_SetCursorProperties, + IWineD3DDeviceImpl_SetCursorPosition, + IWineD3DDeviceImpl_ShowCursor, + IWineD3DDeviceImpl_TestCooperativeLevel, + /*** Getters and setters **/ + IWineD3DDeviceImpl_SetClipPlane, + IWineD3DDeviceImpl_GetClipPlane, + IWineD3DDeviceImpl_SetClipStatus, + IWineD3DDeviceImpl_GetClipStatus, + IWineD3DDeviceImpl_SetCurrentTexturePalette, + IWineD3DDeviceImpl_GetCurrentTexturePalette, + IWineD3DDeviceImpl_SetDepthStencilSurface, + IWineD3DDeviceImpl_GetDepthStencilSurface, + IWineD3DDeviceImpl_SetFVF, + IWineD3DDeviceImpl_GetFVF, + IWineD3DDeviceImpl_SetGammaRamp, + IWineD3DDeviceImpl_GetGammaRamp, + IWineD3DDeviceImpl_SetIndices, + IWineD3DDeviceImpl_GetIndices, + IWineD3DDeviceImpl_SetBaseVertexIndex, + IWineD3DDeviceImpl_GetBaseVertexIndex, + IWineD3DDeviceImpl_SetLight, + IWineD3DDeviceImpl_GetLight, + IWineD3DDeviceImpl_SetLightEnable, + IWineD3DDeviceImpl_GetLightEnable, + IWineD3DDeviceImpl_SetMaterial, + IWineD3DDeviceImpl_GetMaterial, + IWineD3DDeviceImpl_SetNPatchMode, + IWineD3DDeviceImpl_GetNPatchMode, + IWineD3DDeviceImpl_SetPaletteEntries, + IWineD3DDeviceImpl_GetPaletteEntries, + IWineD3DDeviceImpl_SetPixelShader, + IWineD3DDeviceImpl_GetPixelShader, + IWineD3DDeviceImpl_SetPixelShaderConstantB, + IWineD3DDeviceImpl_GetPixelShaderConstantB, + IWineD3DDeviceImpl_SetPixelShaderConstantI, + IWineD3DDeviceImpl_GetPixelShaderConstantI, + IWineD3DDeviceImpl_SetPixelShaderConstantF, + IWineD3DDeviceImpl_GetPixelShaderConstantF, + IWineD3DDeviceImpl_SetRenderState, + IWineD3DDeviceImpl_GetRenderState, + IWineD3DDeviceImpl_SetRenderTarget, + IWineD3DDeviceImpl_GetRenderTarget, + IWineD3DDeviceImpl_SetFrontBackBuffers, + IWineD3DDeviceImpl_SetSamplerState, + IWineD3DDeviceImpl_GetSamplerState, + IWineD3DDeviceImpl_SetScissorRect, + IWineD3DDeviceImpl_GetScissorRect, + IWineD3DDeviceImpl_SetSoftwareVertexProcessing, + IWineD3DDeviceImpl_GetSoftwareVertexProcessing, + IWineD3DDeviceImpl_SetStreamSource, + IWineD3DDeviceImpl_GetStreamSource, + IWineD3DDeviceImpl_SetStreamSourceFreq, + IWineD3DDeviceImpl_GetStreamSourceFreq, + IWineD3DDeviceImpl_SetTexture, + IWineD3DDeviceImpl_GetTexture, + IWineD3DDeviceImpl_SetTextureStageState, + IWineD3DDeviceImpl_GetTextureStageState, + IWineD3DDeviceImpl_SetTransform, + IWineD3DDeviceImpl_GetTransform, + IWineD3DDeviceImpl_SetVertexDeclaration, + IWineD3DDeviceImpl_GetVertexDeclaration, + IWineD3DDeviceImpl_SetVertexShader, + IWineD3DDeviceImpl_GetVertexShader, + IWineD3DDeviceImpl_SetVertexShaderConstantB, + IWineD3DDeviceImpl_GetVertexShaderConstantB, + IWineD3DDeviceImpl_SetVertexShaderConstantI, + IWineD3DDeviceImpl_GetVertexShaderConstantI, + IWineD3DDeviceImpl_SetVertexShaderConstantF, + IWineD3DDeviceImpl_GetVertexShaderConstantF, + IWineD3DDeviceImpl_SetViewport, + IWineD3DDeviceImpl_GetViewport, + IWineD3DDeviceImpl_MultiplyTransform, + IWineD3DDeviceImpl_ValidateDevice, + IWineD3DDeviceImpl_ProcessVertices, + /*** State block ***/ + IWineD3DDeviceImpl_BeginStateBlock, + IWineD3DDeviceImpl_EndStateBlock, + /*** Scene management ***/ + IWineD3DDeviceImpl_BeginScene, + IWineD3DDeviceImpl_EndScene, + IWineD3DDeviceImpl_Present, + IWineD3DDeviceImpl_Clear, + /*** Drawing ***/ + IWineD3DDeviceImpl_DrawPrimitive, + IWineD3DDeviceImpl_DrawIndexedPrimitive, + IWineD3DDeviceImpl_DrawPrimitiveUP, + IWineD3DDeviceImpl_DrawIndexedPrimitiveUP, + IWineD3DDeviceImpl_DrawPrimitiveStrided, + IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided, + IWineD3DDeviceImpl_DrawRectPatch, + IWineD3DDeviceImpl_DrawTriPatch, + IWineD3DDeviceImpl_DeletePatch, + IWineD3DDeviceImpl_ColorFill, + IWineD3DDeviceImpl_UpdateTexture, + IWineD3DDeviceImpl_UpdateSurface, + IWineD3DDeviceImpl_GetFrontBufferData, + /*** object tracking ***/ + IWineD3DDeviceImpl_ResourceReleased +}; + + +const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = { + WINED3DRS_ALPHABLENDENABLE , + WINED3DRS_ALPHAFUNC , + WINED3DRS_ALPHAREF , + WINED3DRS_ALPHATESTENABLE , + WINED3DRS_BLENDOP , + WINED3DRS_COLORWRITEENABLE , + WINED3DRS_DESTBLEND , + WINED3DRS_DITHERENABLE , + WINED3DRS_FILLMODE , + WINED3DRS_FOGDENSITY , + WINED3DRS_FOGEND , + WINED3DRS_FOGSTART , + WINED3DRS_LASTPIXEL , + WINED3DRS_SHADEMODE , + WINED3DRS_SRCBLEND , + WINED3DRS_STENCILENABLE , + WINED3DRS_STENCILFAIL , + WINED3DRS_STENCILFUNC , + WINED3DRS_STENCILMASK , + WINED3DRS_STENCILPASS , + WINED3DRS_STENCILREF , + WINED3DRS_STENCILWRITEMASK , + WINED3DRS_STENCILZFAIL , + WINED3DRS_TEXTUREFACTOR , + WINED3DRS_WRAP0 , + WINED3DRS_WRAP1 , + WINED3DRS_WRAP2 , + WINED3DRS_WRAP3 , + WINED3DRS_WRAP4 , + WINED3DRS_WRAP5 , + WINED3DRS_WRAP6 , + WINED3DRS_WRAP7 , + WINED3DRS_ZENABLE , + WINED3DRS_ZFUNC , + WINED3DRS_ZWRITEENABLE +}; + +const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = { + WINED3DTSS_ADDRESSW , + WINED3DTSS_ALPHAARG0 , + WINED3DTSS_ALPHAARG1 , + WINED3DTSS_ALPHAARG2 , + WINED3DTSS_ALPHAOP , + WINED3DTSS_BUMPENVLOFFSET , + WINED3DTSS_BUMPENVLSCALE , + WINED3DTSS_BUMPENVMAT00 , + WINED3DTSS_BUMPENVMAT01 , + WINED3DTSS_BUMPENVMAT10 , + WINED3DTSS_BUMPENVMAT11 , + WINED3DTSS_COLORARG0 , + WINED3DTSS_COLORARG1 , + WINED3DTSS_COLORARG2 , + WINED3DTSS_COLOROP , + WINED3DTSS_RESULTARG , + WINED3DTSS_TEXCOORDINDEX , + WINED3DTSS_TEXTURETRANSFORMFLAGS +}; + +const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = { + WINED3DSAMP_ADDRESSU , + WINED3DSAMP_ADDRESSV , + WINED3DSAMP_ADDRESSW , + WINED3DSAMP_BORDERCOLOR , + WINED3DSAMP_MAGFILTER , + WINED3DSAMP_MINFILTER , + WINED3DSAMP_MIPFILTER , + WINED3DSAMP_MIPMAPLODBIAS , + WINED3DSAMP_MAXMIPLEVEL , + WINED3DSAMP_MAXANISOTROPY , + WINED3DSAMP_SRGBTEXTURE , + WINED3DSAMP_ELEMENTINDEX +}; + +const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = { + WINED3DRS_AMBIENT , + WINED3DRS_AMBIENTMATERIALSOURCE , + WINED3DRS_CLIPPING , + WINED3DRS_CLIPPLANEENABLE , + WINED3DRS_COLORVERTEX , + WINED3DRS_DIFFUSEMATERIALSOURCE , + WINED3DRS_EMISSIVEMATERIALSOURCE , + WINED3DRS_FOGDENSITY , + WINED3DRS_FOGEND , + WINED3DRS_FOGSTART , + WINED3DRS_FOGTABLEMODE , + WINED3DRS_FOGVERTEXMODE , + WINED3DRS_INDEXEDVERTEXBLENDENABLE , + WINED3DRS_LIGHTING , + WINED3DRS_LOCALVIEWER , + WINED3DRS_MULTISAMPLEANTIALIAS , + WINED3DRS_MULTISAMPLEMASK , + WINED3DRS_NORMALIZENORMALS , + WINED3DRS_PATCHEDGESTYLE , + WINED3DRS_POINTSCALE_A , + WINED3DRS_POINTSCALE_B , + WINED3DRS_POINTSCALE_C , + WINED3DRS_POINTSCALEENABLE , + WINED3DRS_POINTSIZE , + WINED3DRS_POINTSIZE_MAX , + WINED3DRS_POINTSIZE_MIN , + WINED3DRS_POINTSPRITEENABLE , + WINED3DRS_RANGEFOGENABLE , + WINED3DRS_SPECULARMATERIALSOURCE , + WINED3DRS_TWEENFACTOR , + WINED3DRS_VERTEXBLEND +}; + +const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = { + WINED3DTSS_TEXCOORDINDEX , + WINED3DTSS_TEXTURETRANSFORMFLAGS +}; + +const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = { + WINED3DSAMP_DMAPOFFSET +}; + +void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) { + DWORD rep = StateTable[state].representative; + DWORD idx; + BYTE shift; + UINT i; + WineD3DContext *context; + + if(!rep) return; + for(i = 0; i < This->numContexts; i++) { + context = This->contexts[i]; + if(isStateDirty(context, rep)) continue; + + context->dirtyArray[context->numDirtyEntries++] = rep; + idx = rep >> 5; + shift = rep & 0x1f; + context->isStateDirty[idx] |= (1 << shift); + } +} diff --git a/reactos/dll/directx/wine/wined3d/directx.c b/reactos/dll/directx/wine/wined3d/directx.c new file mode 100644 index 00000000000..e9b2acada7d --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/directx.c @@ -0,0 +1,2604 @@ +/* + * IWineD3D implementation + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* Compile time diagnostics: */ + +#ifndef DEBUG_SINGLE_MODE +/* Set to 1 to force only a single display mode to be exposed: */ +#define DEBUG_SINGLE_MODE 0 +#endif + + +#include "config.h" +#include +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +WINE_DECLARE_DEBUG_CHANNEL(d3d_caps); + +/* Extension detection */ +static const struct { + const char *extension_string; + GL_SupportedExt extension; +} EXTENSION_MAP[] = { + /* APPLE */ + {"GL_APPLE_client_storage", APPLE_CLIENT_STORAGE}, + {"GL_APPLE_fence", APPLE_FENCE}, + + /* ATI */ + {"GL_ATI_separate_stencil", ATI_SEPARATE_STENCIL}, + {"GL_ATI_texture_env_combine3", ATI_TEXTURE_ENV_COMBINE3}, + {"GL_ATI_texture_mirror_once", ATI_TEXTURE_MIRROR_ONCE}, + {"GL_ATI_envmap_bumpmap", ATI_ENVMAP_BUMPMAP}, + + /* ARB */ + {"GL_ARB_draw_buffers", ARB_DRAW_BUFFERS}, + {"GL_ARB_fragment_program", ARB_FRAGMENT_PROGRAM}, + {"GL_ARB_fragment_shader", ARB_FRAGMENT_SHADER}, + {"GL_ARB_half_float_pixel", ARB_HALF_FLOAT_PIXEL}, + {"GL_ARB_imaging", ARB_IMAGING}, + {"GL_ARB_multisample", ARB_MULTISAMPLE}, /* needs GLX_ARB_MULTISAMPLE as well */ + {"GL_ARB_multitexture", ARB_MULTITEXTURE}, + {"GL_ARB_occlusion_query", ARB_OCCLUSION_QUERY}, + {"GL_ARB_pixel_buffer_object", ARB_PIXEL_BUFFER_OBJECT}, + {"GL_ARB_point_parameters", ARB_POINT_PARAMETERS}, + {"GL_ARB_point_sprite", ARB_POINT_SPRITE}, + {"GL_ARB_texture_border_clamp", ARB_TEXTURE_BORDER_CLAMP}, + {"GL_ARB_texture_compression", ARB_TEXTURE_COMPRESSION}, + {"GL_ARB_texture_cube_map", ARB_TEXTURE_CUBE_MAP}, + {"GL_ARB_texture_env_add", ARB_TEXTURE_ENV_ADD}, + {"GL_ARB_texture_env_combine", ARB_TEXTURE_ENV_COMBINE}, + {"GL_ARB_texture_env_dot3", ARB_TEXTURE_ENV_DOT3}, + {"GL_ARB_texture_float", ARB_TEXTURE_FLOAT}, + {"GL_ARB_texture_mirrored_repeat", ARB_TEXTURE_MIRRORED_REPEAT}, + {"GL_ARB_texture_non_power_of_two", ARB_TEXTURE_NON_POWER_OF_TWO}, + {"GL_ARB_vertex_blend", ARB_VERTEX_BLEND}, + {"GL_ARB_vertex_buffer_object", ARB_VERTEX_BUFFER_OBJECT}, + {"GL_ARB_vertex_program", ARB_VERTEX_PROGRAM}, + {"GL_ARB_vertex_shader", ARB_VERTEX_SHADER}, + + /* EXT */ + {"GL_EXT_blend_minmax", EXT_BLEND_MINMAX}, + {"GL_EXT_fog_coord", EXT_FOG_COORD}, + {"GL_EXT_framebuffer_blit", EXT_FRAMEBUFFER_BLIT}, + {"GL_EXT_framebuffer_object", EXT_FRAMEBUFFER_OBJECT}, + {"GL_EXT_paletted_texture", EXT_PALETTED_TEXTURE}, + {"GL_EXT_point_parameters", EXT_POINT_PARAMETERS}, + {"GL_EXT_secondary_color", EXT_SECONDARY_COLOR}, + {"GL_EXT_stencil_two_side", EXT_STENCIL_TWO_SIDE}, + {"GL_EXT_stencil_wrap", EXT_STENCIL_WRAP}, + {"GL_EXT_texture3D", EXT_TEXTURE3D}, + {"GL_EXT_texture_compression_s3tc", EXT_TEXTURE_COMPRESSION_S3TC}, + {"GL_EXT_texture_env_add", EXT_TEXTURE_ENV_ADD}, + {"GL_EXT_texture_env_combine", EXT_TEXTURE_ENV_COMBINE}, + {"GL_EXT_texture_env_dot3", EXT_TEXTURE_ENV_DOT3}, + {"GL_EXT_texture_sRGB", EXT_TEXTURE_SRGB}, + {"GL_EXT_texture_filter_anisotropic", EXT_TEXTURE_FILTER_ANISOTROPIC}, + {"GL_EXT_texture_lod", EXT_TEXTURE_LOD}, + {"GL_EXT_texture_lod_bias", EXT_TEXTURE_LOD_BIAS}, + {"GL_EXT_vertex_shader", EXT_VERTEX_SHADER}, + {"GL_EXT_vertex_weighting", EXT_VERTEX_WEIGHTING}, + + /* NV */ + {"GL_NV_half_float", NV_HALF_FLOAT}, + {"GL_NV_fence", NV_FENCE}, + {"GL_NV_fog_distance", NV_FOG_DISTANCE}, + {"GL_NV_fragment_program", NV_FRAGMENT_PROGRAM}, + {"GL_NV_fragment_program2", NV_FRAGMENT_PROGRAM2}, + {"GL_NV_register_combiners", NV_REGISTER_COMBINERS}, + {"GL_NV_register_combiners2", NV_REGISTER_COMBINERS2}, + {"GL_NV_texgen_reflection", NV_TEXGEN_REFLECTION}, + {"GL_NV_texture_env_combine4", NV_TEXTURE_ENV_COMBINE4}, + {"GL_NV_texture_shader", NV_TEXTURE_SHADER}, + {"GL_NV_texture_shader2", NV_TEXTURE_SHADER2}, + {"GL_NV_texture_shader3", NV_TEXTURE_SHADER3}, + {"GL_NV_occlusion_query", NV_OCCLUSION_QUERY}, + {"GL_NV_vertex_program", NV_VERTEX_PROGRAM}, + {"GL_NV_vertex_program1_1", NV_VERTEX_PROGRAM1_1}, + {"GL_NV_vertex_program2", NV_VERTEX_PROGRAM2}, + {"GL_NV_vertex_program3", NV_VERTEX_PROGRAM3}, +}; + +/********************************************************** + * Utility functions follow + **********************************************************/ + +/* Adapters */ +static int numAdapters = 0; +static struct WineD3DAdapter Adapters[1]; + +/* lookup tables */ +int minLookup[MAX_LOOKUPS]; +int maxLookup[MAX_LOOKUPS]; +DWORD *stateLookup[MAX_LOOKUPS]; + +DWORD minMipLookup[WINED3DTEXF_ANISOTROPIC + 1][WINED3DTEXF_LINEAR + 1]; + + +/** + * Note: GL seems to trap if GetDeviceCaps is called before any HWND's created + * ie there is no GL Context - Get a default rendering context to enable the + * function query some info from GL + */ + +static int wined3d_fake_gl_context_ref = 0; +static BOOL wined3d_fake_gl_context_foreign; +static BOOL wined3d_fake_gl_context_available = FALSE; +static HDC wined3d_fake_gl_context_hdc = NULL; +static HWND wined3d_fake_gl_context_hwnd = NULL; + +static CRITICAL_SECTION wined3d_fake_gl_context_cs; +static CRITICAL_SECTION_DEBUG wined3d_fake_gl_context_cs_debug = +{ + 0, 0, &wined3d_fake_gl_context_cs, + { &wined3d_fake_gl_context_cs_debug.ProcessLocksList, + &wined3d_fake_gl_context_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": wined3d_fake_gl_context_cs") } +}; +static CRITICAL_SECTION wined3d_fake_gl_context_cs = { &wined3d_fake_gl_context_cs_debug, -1, 0, 0, 0, 0 }; + +static void WineD3D_ReleaseFakeGLContext(void) { + HGLRC glCtx; + + EnterCriticalSection(&wined3d_fake_gl_context_cs); + + if(!wined3d_fake_gl_context_available) { + TRACE_(d3d_caps)("context not available\n"); + LeaveCriticalSection(&wined3d_fake_gl_context_cs); + return; + } + + glCtx = pwglGetCurrentContext(); + + TRACE_(d3d_caps)("decrementing ref from %i\n", wined3d_fake_gl_context_ref); + if (0 == (--wined3d_fake_gl_context_ref) ) { + if(!wined3d_fake_gl_context_foreign && glCtx) { + TRACE_(d3d_caps)("destroying fake GL context\n"); + pwglMakeCurrent(NULL, NULL); + pwglDeleteContext(glCtx); + } + if(wined3d_fake_gl_context_hdc) + ReleaseDC(wined3d_fake_gl_context_hwnd, wined3d_fake_gl_context_hdc); + wined3d_fake_gl_context_hdc = NULL; /* Make sure we don't think that it is still around */ + if(wined3d_fake_gl_context_hwnd) + DestroyWindow(wined3d_fake_gl_context_hwnd); + wined3d_fake_gl_context_hwnd = NULL; + wined3d_fake_gl_context_available = FALSE; + } + assert(wined3d_fake_gl_context_ref >= 0); + + LeaveCriticalSection(&wined3d_fake_gl_context_cs); + LEAVE_GL(); +} + +static BOOL WineD3D_CreateFakeGLContext(void) { + HGLRC glCtx = NULL; + + ENTER_GL(); + EnterCriticalSection(&wined3d_fake_gl_context_cs); + + TRACE("getting context...\n"); + if(wined3d_fake_gl_context_ref > 0) goto ret; + assert(0 == wined3d_fake_gl_context_ref); + + wined3d_fake_gl_context_foreign = TRUE; + + glCtx = pwglGetCurrentContext(); + if (!glCtx) { + PIXELFORMATDESCRIPTOR pfd; + int iPixelFormat; + + wined3d_fake_gl_context_foreign = FALSE; + + /* We need a fake window as a hdc retrieved using GetDC(0) can't be used for much GL purposes */ + wined3d_fake_gl_context_hwnd = CreateWindowA("WineD3D_OpenGL", "WineD3D fake window", WS_OVERLAPPEDWINDOW, 10, 10, 10, 10, NULL, NULL, NULL, NULL); + if(!wined3d_fake_gl_context_hwnd) { + ERR("HWND creation failed!\n"); + goto fail; + } + wined3d_fake_gl_context_hdc = GetDC(wined3d_fake_gl_context_hwnd); + if(!wined3d_fake_gl_context_hdc) { + ERR("GetDC failed!\n"); + goto fail; + } + + /* PixelFormat selection */ + ZeroMemory(&pfd, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;/*PFD_GENERIC_ACCELERATED*/ + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = 32; + pfd.iLayerType = PFD_MAIN_PLANE; + + iPixelFormat = ChoosePixelFormat(wined3d_fake_gl_context_hdc, &pfd); + if(!iPixelFormat) { + /* If this happens something is very wrong as ChoosePixelFormat barely fails */ + ERR("Can't find a suitable iPixelFormat\n"); + goto fail; + } + DescribePixelFormat(wined3d_fake_gl_context_hdc, iPixelFormat, sizeof(pfd), &pfd); + SetPixelFormat(wined3d_fake_gl_context_hdc, iPixelFormat, &pfd); + + /* Create a GL context */ + glCtx = pwglCreateContext(wined3d_fake_gl_context_hdc); + if (!glCtx) { + WARN_(d3d_caps)("Error creating default context for capabilities initialization\n"); + goto fail; + } + + /* Make it the current GL context */ + if (!pwglMakeCurrent(wined3d_fake_gl_context_hdc, glCtx)) { + WARN_(d3d_caps)("Error setting default context as current for capabilities initialization\n"); + goto fail; + } + } + + ret: + TRACE("incrementing ref from %i\n", wined3d_fake_gl_context_ref); + wined3d_fake_gl_context_ref++; + wined3d_fake_gl_context_available = TRUE; + LeaveCriticalSection(&wined3d_fake_gl_context_cs); + return TRUE; + fail: + if(wined3d_fake_gl_context_hdc) + ReleaseDC(wined3d_fake_gl_context_hwnd, wined3d_fake_gl_context_hdc); + wined3d_fake_gl_context_hdc = NULL; + if(wined3d_fake_gl_context_hwnd) + DestroyWindow(wined3d_fake_gl_context_hwnd); + wined3d_fake_gl_context_hwnd = NULL; + if(glCtx) pwglDeleteContext(glCtx); + LeaveCriticalSection(&wined3d_fake_gl_context_cs); + LEAVE_GL(); + return FALSE; +} + + +/********************************************************** + * IUnknown parts follows + **********************************************************/ + +static HRESULT WINAPI IWineD3DImpl_QueryInterface(IWineD3D *iface,REFIID riid,LPVOID *ppobj) +{ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DDevice)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DImpl_AddRef(IWineD3D *iface) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1); + return refCount; +} + +static ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->ref); + ref = InterlockedDecrement(&This->ref); + if (ref == 0) { + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +/* Set the shader type for this device, depending on the given capabilities, + * the device type, and the user preferences in wined3d_settings */ + +static void select_shader_mode( + WineD3D_GL_Info *gl_info, + WINED3DDEVTYPE DeviceType, + int* ps_selected, + int* vs_selected) { + + if (wined3d_settings.vs_mode == VS_NONE) { + *vs_selected = SHADER_NONE; + } else if (gl_info->supported[ARB_VERTEX_SHADER] && wined3d_settings.glslRequested) { + *vs_selected = SHADER_GLSL; + } else if (gl_info->supported[ARB_VERTEX_PROGRAM]) { + *vs_selected = SHADER_ARB; + } else { + *vs_selected = SHADER_NONE; + } + + if (wined3d_settings.ps_mode == PS_NONE) { + *ps_selected = SHADER_NONE; + } else if (gl_info->supported[ARB_FRAGMENT_SHADER] && wined3d_settings.glslRequested) { + *ps_selected = SHADER_GLSL; + } else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) { + *ps_selected = SHADER_ARB; + } else { + *ps_selected = SHADER_NONE; + } +} + +/** Select the number of report maximum shader constants based on the selected shader modes */ +static void select_shader_max_constants( + int ps_selected_mode, + int vs_selected_mode, + WineD3D_GL_Info *gl_info) { + + switch (vs_selected_mode) { + case SHADER_GLSL: + /* Subtract the other potential uniforms from the max available (bools, ints, and 1 row of projection matrix) */ + gl_info->max_vshader_constantsF = gl_info->vs_glsl_constantsF - (MAX_CONST_B / 4) - MAX_CONST_I - 1; + break; + case SHADER_ARB: + /* We have to subtract any other PARAMs that we might use in our shader programs. + * ATI seems to count 2 implicit PARAMs when we use fog and NVIDIA counts 1, + * and we reference one row of the PROJECTION matrix which counts as 1 PARAM. */ + gl_info->max_vshader_constantsF = gl_info->vs_arb_constantsF - 3; + break; + default: + gl_info->max_vshader_constantsF = 0; + break; + } + + switch (ps_selected_mode) { + case SHADER_GLSL: + /* Subtract the other potential uniforms from the max available (bools & ints), and 2 states for fog. + * In theory the texbem instruction may need one more shader constant too. But lets assume + * that a sm <= 1.3 shader does not need all the uniforms provided by a glsl-capable card, + * and lets not take away a uniform needlessly from all other shaders. + */ + gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF - (MAX_CONST_B / 4) - MAX_CONST_I - 2; + break; + case SHADER_ARB: + /* The arb shader only loads the bump mapping environment matrix into the shader if it finds + * a free constant to do that, so only reduce the number of available constants by 2 for the fog states. + */ + gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF - 2; + break; + default: + gl_info->max_pshader_constantsF = 0; + break; + } +} + +/********************************************************** + * IWineD3D parts follows + **********************************************************/ + +#define GLINFO_LOCATION (*gl_info) +BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { + const char *GL_Extensions = NULL; + const char *WGL_Extensions = NULL; + const char *gl_string = NULL; + const char *gl_string_cursor = NULL; + GLint gl_max; + GLfloat gl_floatv[2]; + int major = 1, minor = 0; + BOOL return_value = TRUE; + int i; + HDC hdc; + HMODULE mod_gl; + +#ifdef USE_WIN32_OPENGL +#define USE_GL_FUNC(pfn) pfn = (void*)GetProcAddress(mod_gl, #pfn); + mod_gl = LoadLibraryA("opengl32.dll"); + if(!mod_gl) { + ERR("Can't load opengl32.dll!\n"); + return FALSE; + } +#else +#define USE_GL_FUNC(pfn) pfn = (void*)pwglGetProcAddress(#pfn); + /* To bypass the opengl32 thunks load wglGetProcAddress from gdi32 (glXGetProcAddress wrapper) instead of opengl32's */ + mod_gl = GetModuleHandleA("gdi32.dll"); +#endif + +/* Load WGL core functions from opengl32.dll */ +#define USE_WGL_FUNC(pfn) p##pfn = (void*)GetProcAddress(mod_gl, #pfn); + WGL_FUNCS_GEN; +#undef USE_WGL_FUNC + + if(!pwglGetProcAddress) { + ERR("Unable to load wglGetProcAddress!\n"); + return FALSE; + } + +/* Dynamicly load all GL core functions */ + GL_FUNCS_GEN; +#undef USE_GL_FUNC + + /* Make sure that we've got a context */ + /* TODO: CreateFakeGLContext should really take a display as a parameter */ + /* Only save the values obtained when a display is provided */ + if (!WineD3D_CreateFakeGLContext() || wined3d_fake_gl_context_foreign) + return_value = FALSE; + + TRACE_(d3d_caps)("(%p)\n", gl_info); + + gl_string = (const char *) glGetString(GL_RENDERER); + if (NULL == gl_string) + gl_string = "None"; + strcpy(gl_info->gl_renderer, gl_string); + + gl_string = (const char *) glGetString(GL_VENDOR); + TRACE_(d3d_caps)("Filling vendor string %s\n", gl_string); + if (gl_string != NULL) { + /* Fill in the GL vendor */ + if (strstr(gl_string, "NVIDIA")) { + gl_info->gl_vendor = VENDOR_NVIDIA; + } else if (strstr(gl_string, "ATI")) { + gl_info->gl_vendor = VENDOR_ATI; + } else if (strstr(gl_string, "Intel(R)") || + strstr(gl_info->gl_renderer, "Intel(R)")) { + gl_info->gl_vendor = VENDOR_INTEL; + } else if (strstr(gl_string, "Mesa")) { + gl_info->gl_vendor = VENDOR_MESA; + } else { + gl_info->gl_vendor = VENDOR_WINE; + } + } else { + gl_info->gl_vendor = VENDOR_WINE; + } + + + TRACE_(d3d_caps)("found GL_VENDOR (%s)->(0x%04x)\n", debugstr_a(gl_string), gl_info->gl_vendor); + + /* Parse the GL_VERSION field into major and minor information */ + gl_string = (const char *) glGetString(GL_VERSION); + if (gl_string != NULL) { + + switch (gl_info->gl_vendor) { + case VENDOR_NVIDIA: + gl_string_cursor = strstr(gl_string, "NVIDIA"); + if (!gl_string_cursor) { + ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string)); + break; + } + + gl_string_cursor = strstr(gl_string_cursor, " "); + if (!gl_string_cursor) { + ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string)); + break; + } + + while (*gl_string_cursor == ' ') { + ++gl_string_cursor; + } + + if (!*gl_string_cursor) { + ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string)); + break; + } + + major = atoi(gl_string_cursor); + while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') { + ++gl_string_cursor; + } + + if (*gl_string_cursor++ != '.') { + ERR_(d3d_caps)("Invalid nVidia version string: %s\n", debugstr_a(gl_string)); + break; + } + + minor = atoi(gl_string_cursor); + minor = major*100+minor; + major = 10; + + break; + + case VENDOR_ATI: + major = minor = 0; + gl_string_cursor = strchr(gl_string, '-'); + if (gl_string_cursor) { + int error = 0; + gl_string_cursor++; + + /* Check if version number is of the form x.y.z */ + if (*gl_string_cursor > '9' && *gl_string_cursor < '0') + error = 1; + if (!error && *(gl_string_cursor+2) > '9' && *(gl_string_cursor+2) < '0') + error = 1; + if (!error && *(gl_string_cursor+4) > '9' && *(gl_string_cursor+4) < '0') + error = 1; + if (!error && *(gl_string_cursor+1) != '.' && *(gl_string_cursor+3) != '.') + error = 1; + + /* Mark version number as malformed */ + if (error) + gl_string_cursor = 0; + } + + if (!gl_string_cursor) + WARN_(d3d_caps)("malformed GL_VERSION (%s)\n", debugstr_a(gl_string)); + else { + major = *gl_string_cursor - '0'; + minor = (*(gl_string_cursor+2) - '0') * 256 + (*(gl_string_cursor+4) - '0'); + } + break; + + case VENDOR_INTEL: + case VENDOR_MESA: + gl_string_cursor = strstr(gl_string, "Mesa"); + gl_string_cursor = strstr(gl_string_cursor, " "); + while (*gl_string_cursor && ' ' == *gl_string_cursor) ++gl_string_cursor; + if (*gl_string_cursor) { + char tmp[16]; + int cursor = 0; + + while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') { + tmp[cursor++] = *gl_string_cursor; + ++gl_string_cursor; + } + tmp[cursor] = 0; + major = atoi(tmp); + + if (*gl_string_cursor != '.') WARN_(d3d_caps)("malformed GL_VERSION (%s)\n", debugstr_a(gl_string)); + ++gl_string_cursor; + + cursor = 0; + while (*gl_string_cursor <= '9' && *gl_string_cursor >= '0') { + tmp[cursor++] = *gl_string_cursor; + ++gl_string_cursor; + } + tmp[cursor] = 0; + minor = atoi(tmp); + } + break; + + default: + major = 0; + minor = 9; + } + gl_info->gl_driver_version = MAKEDWORD_VERSION(major, minor); + TRACE_(d3d_caps)("found GL_VERSION (%s)->%i.%i->(0x%08x)\n", debugstr_a(gl_string), major, minor, gl_info->gl_driver_version); + } + + TRACE_(d3d_caps)("found GL_RENDERER (%s)->(0x%04x)\n", debugstr_a(gl_info->gl_renderer), gl_info->gl_card); + + /* + * Initialize openGL extension related variables + * with Default values + */ + memset(&gl_info->supported, 0, sizeof(gl_info->supported)); + gl_info->max_buffers = 1; + gl_info->max_textures = 1; + gl_info->max_texture_stages = 1; + gl_info->max_fragment_samplers = 1; + gl_info->max_vertex_samplers = 0; + gl_info->max_combined_samplers = 0; + gl_info->max_sampler_stages = 1; + gl_info->ps_arb_version = PS_VERSION_NOT_SUPPORTED; + gl_info->ps_arb_max_temps = 0; + gl_info->ps_arb_max_instructions = 0; + gl_info->vs_arb_version = VS_VERSION_NOT_SUPPORTED; + gl_info->vs_arb_max_temps = 0; + gl_info->vs_arb_max_instructions = 0; + gl_info->vs_nv_version = VS_VERSION_NOT_SUPPORTED; + gl_info->vs_ati_version = VS_VERSION_NOT_SUPPORTED; + gl_info->vs_glsl_constantsF = 0; + gl_info->ps_glsl_constantsF = 0; + gl_info->vs_arb_constantsF = 0; + gl_info->ps_arb_constantsF = 0; + +/* Now work out what GL support this card really has */ +#define USE_GL_FUNC(type, pfn) gl_info->pfn = (type) pwglGetProcAddress(#pfn); + GL_EXT_FUNCS_GEN; + WGL_EXT_FUNCS_GEN; +#undef USE_GL_FUNC + + /* Retrieve opengl defaults */ + glGetIntegerv(GL_MAX_CLIP_PLANES, &gl_max); + gl_info->max_clipplanes = min(WINED3DMAXUSERCLIPPLANES, gl_max); + TRACE_(d3d_caps)("ClipPlanes support - num Planes=%d\n", gl_max); + + glGetIntegerv(GL_MAX_LIGHTS, &gl_max); + gl_info->max_lights = gl_max; + TRACE_(d3d_caps)("Lights support - max lights=%d\n", gl_max); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_max); + gl_info->max_texture_size = gl_max; + TRACE_(d3d_caps)("Maximum texture size support - max texture size=%d\n", gl_max); + + glGetFloatv(GL_POINT_SIZE_RANGE, gl_floatv); + gl_info->max_pointsize = gl_floatv[1]; + TRACE_(d3d_caps)("Maximum point size support - max point size=%f\n", gl_floatv[1]); + + glGetIntegerv(GL_AUX_BUFFERS, &gl_max); + gl_info->max_aux_buffers = gl_max; + TRACE_(d3d_caps)("Offscreen rendering support - number of aux buffers=%d\n", gl_max); + + /* Parse the gl supported features, in theory enabling parts of our code appropriately */ + GL_Extensions = (const char *) glGetString(GL_EXTENSIONS); + TRACE_(d3d_caps)("GL_Extensions reported:\n"); + + if (NULL == GL_Extensions) { + ERR(" GL_Extensions returns NULL\n"); + } else { + while (*GL_Extensions != 0x00) { + const char *Start; + char ThisExtn[256]; + size_t len; + + while (isspace(*GL_Extensions)) GL_Extensions++; + Start = GL_Extensions; + while (!isspace(*GL_Extensions) && *GL_Extensions != 0x00) { + GL_Extensions++; + } + + len = GL_Extensions - Start; + if (len == 0 || len >= sizeof(ThisExtn)) + continue; + + memcpy(ThisExtn, Start, len); + ThisExtn[len] = '\0'; + TRACE_(d3d_caps)("- %s\n", ThisExtn); + + for (i = 0; i < (sizeof(EXTENSION_MAP) / sizeof(*EXTENSION_MAP)); ++i) { + if (!strcmp(ThisExtn, EXTENSION_MAP[i].extension_string)) { + TRACE_(d3d_caps)(" FOUND: %s support\n", EXTENSION_MAP[i].extension_string); + gl_info->supported[EXTENSION_MAP[i].extension] = TRUE; + break; + } + } + } + + if (gl_info->supported[APPLE_FENCE]) { + /* GL_NV_fence and GL_APPLE_fence provide the same functionality basically. + * The apple extension interacts with some other apple exts. Disable the NV + * extension if the apple one is support to prevent confusion in other parts + * of the code + */ + gl_info->supported[NV_FENCE] = FALSE; + } + if (gl_info->supported[ARB_TEXTURE_CUBE_MAP]) { + TRACE_(d3d_caps)(" IMPLIED: NVIDIA (NV) Texture Gen Reflection support\n"); + gl_info->supported[NV_TEXGEN_REFLECTION] = TRUE; + } + if (gl_info->supported[NV_TEXTURE_SHADER2]) { + /* GL_ATI_envmap_bumpmap won't play nice with texture shaders, so disable it + * Won't occur in any real world situation though + */ + gl_info->supported[ATI_ENVMAP_BUMPMAP] = FALSE; + } + if (gl_info->supported[ARB_DRAW_BUFFERS]) { + glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &gl_max); + gl_info->max_buffers = gl_max; + TRACE_(d3d_caps)("Max draw buffers: %u\n", gl_max); + } + if (gl_info->supported[ARB_MULTITEXTURE]) { + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &gl_max); + gl_info->max_textures = min(MAX_TEXTURES, gl_max); + TRACE_(d3d_caps)("Max textures: %d\n", gl_info->max_textures); + + if (gl_info->supported[NV_REGISTER_COMBINERS]) { + GLint tmp; + glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &tmp); + gl_info->max_texture_stages = min(MAX_TEXTURES, tmp); + } else { + gl_info->max_texture_stages = min(MAX_TEXTURES, gl_max); + } + TRACE_(d3d_caps)("Max texture stages: %d\n", gl_info->max_texture_stages); + + if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) { + GLint tmp; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &tmp); + gl_info->max_fragment_samplers = min(MAX_FRAGMENT_SAMPLERS, tmp); + } else { + gl_info->max_fragment_samplers = max(gl_info->max_fragment_samplers, gl_max); + } + TRACE_(d3d_caps)("Max fragment samplers: %d\n", gl_info->max_fragment_samplers); + + if (gl_info->supported[ARB_VERTEX_SHADER]) { + GLint tmp; + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, &tmp); + gl_info->max_vertex_samplers = tmp; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, &tmp); + gl_info->max_combined_samplers = tmp; + } else { + gl_info->max_combined_samplers = gl_info->max_fragment_samplers; + } + TRACE_(d3d_caps)("Max vertex samplers: %u\n", gl_info->max_vertex_samplers); + TRACE_(d3d_caps)("Max combined samplers: %u\n", gl_info->max_combined_samplers); + } + if (gl_info->supported[ARB_VERTEX_BLEND]) { + glGetIntegerv(GL_MAX_VERTEX_UNITS_ARB, &gl_max); + gl_info->max_blends = gl_max; + TRACE_(d3d_caps)("Max blends: %u\n", gl_info->max_blends); + } + if (gl_info->supported[EXT_TEXTURE3D]) { + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_EXT, &gl_max); + gl_info->max_texture3d_size = gl_max; + TRACE_(d3d_caps)("Max texture3D size: %d\n", gl_info->max_texture3d_size); + } + if (gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC]) { + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_max); + gl_info->max_anisotropy = gl_max; + TRACE_(d3d_caps)("Max anisotropy: %d\n", gl_info->max_anisotropy); + } + if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) { + gl_info->ps_arb_version = PS_VERSION_11; + GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max)); + gl_info->ps_arb_constantsF = gl_max; + TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM float constants: %d\n", gl_info->ps_arb_constantsF); + GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &gl_max)); + gl_info->ps_arb_max_temps = gl_max; + TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM temporaries: %d\n", gl_info->ps_arb_max_temps); + GL_EXTCALL(glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &gl_max)); + gl_info->ps_arb_max_instructions = gl_max; + TRACE_(d3d_caps)("Max ARB_FRAGMENT_PROGRAM instructions: %d\n", gl_info->ps_arb_max_instructions); + } + if (gl_info->supported[ARB_VERTEX_PROGRAM]) { + gl_info->vs_arb_version = VS_VERSION_11; + GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max)); + gl_info->vs_arb_constantsF = gl_max; + TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM float constants: %d\n", gl_info->vs_arb_constantsF); + GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_TEMPORARIES_ARB, &gl_max)); + gl_info->vs_arb_max_temps = gl_max; + TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM temporaries: %d\n", gl_info->vs_arb_max_temps); + GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_INSTRUCTIONS_ARB, &gl_max)); + gl_info->vs_arb_max_instructions = gl_max; + TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM instructions: %d\n", gl_info->vs_arb_max_instructions); + } + if (gl_info->supported[ARB_VERTEX_SHADER]) { + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max); + gl_info->vs_glsl_constantsF = gl_max / 4; + TRACE_(d3d_caps)("Max ARB_VERTEX_SHADER float constants: %u\n", gl_info->vs_glsl_constantsF); + } + if (gl_info->supported[ARB_FRAGMENT_SHADER]) { + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &gl_max); + gl_info->ps_glsl_constantsF = gl_max / 4; + TRACE_(d3d_caps)("Max ARB_FRAGMENT_SHADER float constants: %u\n", gl_info->ps_glsl_constantsF); + } + if (gl_info->supported[EXT_VERTEX_SHADER]) { + gl_info->vs_ati_version = VS_VERSION_11; + } + if (gl_info->supported[NV_VERTEX_PROGRAM3]) { + gl_info->vs_nv_version = VS_VERSION_30; + } else if (gl_info->supported[NV_VERTEX_PROGRAM2]) { + gl_info->vs_nv_version = VS_VERSION_20; + } else if (gl_info->supported[NV_VERTEX_PROGRAM1_1]) { + gl_info->vs_nv_version = VS_VERSION_11; + } else if (gl_info->supported[NV_VERTEX_PROGRAM]) { + gl_info->vs_nv_version = VS_VERSION_10; + } + if (gl_info->supported[NV_FRAGMENT_PROGRAM2]) { + gl_info->ps_nv_version = PS_VERSION_30; + } else if (gl_info->supported[NV_FRAGMENT_PROGRAM]) { + gl_info->ps_nv_version = PS_VERSION_20; + } + + } + checkGLcall("extension detection\n"); + + /* In some cases the number of texture stages can be larger than the number + * of samplers. The GF4 for example can use only 2 samplers (no fragment + * shaders), but 8 texture stages (register combiners). */ + gl_info->max_sampler_stages = max(gl_info->max_fragment_samplers, gl_info->max_texture_stages); + + /* We can only use ORM_FBO when the hardware supports it. */ + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && !gl_info->supported[EXT_FRAMEBUFFER_OBJECT]) { + WARN_(d3d_caps)("GL_EXT_framebuffer_object not supported, falling back to PBuffer offscreen rendering mode.\n"); + wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER; + } + + /* MRTs are currently only supported when FBOs are used. */ + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) { + gl_info->max_buffers = 1; + } + + /* Below is a list of Nvidia and ATI GPUs. Both vendors have dozens of different GPUs with roughly the same + * features. In most cases GPUs from a certain family differ in clockspeeds, the amount of video memory and + * in case of the latest videocards in the number of pixel/vertex pipelines. + * + * A Direct3D device object contains the PCI id (vendor + device) of the videocard which is used for + * rendering. Various games use this information to get a rough estimation of the features of the card + * and some might use it for enabling 3d effects only on certain types of videocards. In some cases + * games might even use it to work around bugs which happen on certain videocards/driver combinations. + * The problem is that OpenGL only exposes a rendering string containing the name of the videocard and + * not the PCI id. + * + * Various games depend on the PCI id, so somehow we need to provide one. A simple option is to parse + * the renderer string and translate this to the right PCI id. This is a lot of work because there are more + * than 200 GPUs just for Nvidia. Various cards share the same renderer string, so the amount of code might + * be 'small' but there are quite a number of exceptions which would make this a pain to maintain. + * Another way would be to query the PCI id from the operating system (assuming this is the videocard which + * is used for rendering which is not always the case). This would work but it is not very portable. Second + * it would not work well in, let's say, a remote X situation in which the amount of 3d features which can be used + * is limited. + * + * As said most games only use the PCI id to get an indication of the capabilities of the card. + * It doesn't really matter if the given id is the correct one if we return the id of a card with + * similar 3d features. + * + * The code below checks the OpenGL capabilities of a videocard and matches that to a certain level of + * Direct3D functionality. Once a card passes the Direct3D9 check, we know that the card (in case of Nvidia) + * is at least a GeforceFX. To give a better estimate we do a basic check on the renderer string but if that + * won't pass we return a default card. This way is better than maintaining a full card database as even + * without a full database we can return a card with similar features. Second the size of the database + * can be made quite small because when you know what type of 3d functionality a card has, you know to which + * GPU family the GPU must belong. Because of this you only have to check a small part of the renderer string + * to distinguishes between different models from that family. + */ + switch (gl_info->gl_vendor) { + case VENDOR_NVIDIA: + /* Both the GeforceFX, 6xxx and 7xxx series support D3D9. The last two types have more + * shader capabilities, so we use the shader capabilities to distinguish between FX and 6xxx/7xxx. + */ + if(WINE_D3D9_CAPABLE(gl_info) && (gl_info->vs_nv_version == VS_VERSION_30)) { + if (strstr(gl_info->gl_renderer, "7800") || + strstr(gl_info->gl_renderer, "7900") || + strstr(gl_info->gl_renderer, "7950") || + strstr(gl_info->gl_renderer, "Quadro FX 4") || + strstr(gl_info->gl_renderer, "Quadro FX 5")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE_7800GT; + else if(strstr(gl_info->gl_renderer, "6800") || + strstr(gl_info->gl_renderer, "7600")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE_6800; + else if(strstr(gl_info->gl_renderer, "6600") || + strstr(gl_info->gl_renderer, "6610") || + strstr(gl_info->gl_renderer, "6700")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE_6600GT; + else + gl_info->gl_card = CARD_NVIDIA_GEFORCE_6200; /* Geforce 6100/6150/6200/7300/7400 */ + } else if(WINE_D3D9_CAPABLE(gl_info)) { + if (strstr(gl_info->gl_renderer, "5800") || + strstr(gl_info->gl_renderer, "5900") || + strstr(gl_info->gl_renderer, "5950") || + strstr(gl_info->gl_renderer, "Quadro FX")) + gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5800; + else if(strstr(gl_info->gl_renderer, "5600") || + strstr(gl_info->gl_renderer, "5650") || + strstr(gl_info->gl_renderer, "5700") || + strstr(gl_info->gl_renderer, "5750")) + gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600; + else + gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5200; /* GeforceFX 5100/5200/5250/5300/5500 */ + } else if(WINE_D3D8_CAPABLE(gl_info)) { + if (strstr(gl_info->gl_renderer, "GeForce4 Ti") || strstr(gl_info->gl_renderer, "Quadro4")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE4_TI4200; /* Geforce4 Ti4200/Ti4400/Ti4600/Ti4800, Quadro4 */ + else + gl_info->gl_card = CARD_NVIDIA_GEFORCE3; /* Geforce3 standard/Ti200/Ti500, Quadro DCC */ + } else if(WINE_D3D7_CAPABLE(gl_info)) { + if (strstr(gl_info->gl_renderer, "GeForce4 MX")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE4_MX; /* MX420/MX440/MX460/MX4000 */ + else if(strstr(gl_info->gl_renderer, "GeForce2 MX") || strstr(gl_info->gl_renderer, "Quadro2 MXR")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE2_MX; /* Geforce2 standard/MX100/MX200/MX400, Quadro2 MXR */ + else if(strstr(gl_info->gl_renderer, "GeForce2") || strstr(gl_info->gl_renderer, "Quadro2")) + gl_info->gl_card = CARD_NVIDIA_GEFORCE2; /* Geforce2 GTS/Pro/Ti/Ultra, Quadro2 */ + else + gl_info->gl_card = CARD_NVIDIA_GEFORCE; /* Geforce 256/DDR, Quadro */ + } else { + if (strstr(gl_info->gl_renderer, "TNT2")) + gl_info->gl_card = CARD_NVIDIA_RIVA_TNT2; /* Riva TNT2 standard/M64/Pro/Ultra */ + else + gl_info->gl_card = CARD_NVIDIA_RIVA_TNT; /* Riva TNT, Vanta */ + } + break; + case VENDOR_ATI: + if(WINE_D3D9_CAPABLE(gl_info)) { + /* Radeon R5xx */ + if (strstr(gl_info->gl_renderer, "X1600") || + strstr(gl_info->gl_renderer, "X1800") || + strstr(gl_info->gl_renderer, "X1900") || + strstr(gl_info->gl_renderer, "X1950")) + gl_info->gl_card = CARD_ATI_RADEON_X1600; + /* Radeon R4xx + X1300/X1400 (lowend R5xx) */ + else if(strstr(gl_info->gl_renderer, "X700") || + strstr(gl_info->gl_renderer, "X800") || + strstr(gl_info->gl_renderer, "X850") || + strstr(gl_info->gl_renderer, "X1300") || + strstr(gl_info->gl_renderer, "X1400")) + gl_info->gl_card = CARD_ATI_RADEON_X700; + /* Radeon R3xx */ + else + gl_info->gl_card = CARD_ATI_RADEON_9500; /* Radeon 9500/9550/9600/9700/9800/X300/X550/X600 */ + } else if(WINE_D3D8_CAPABLE(gl_info)) { + gl_info->gl_card = CARD_ATI_RADEON_8500; /* Radeon 8500/9000/9100/9200/9300 */ + } else if(WINE_D3D7_CAPABLE(gl_info)) { + gl_info->gl_card = CARD_ATI_RADEON_7200; /* Radeon 7000/7100/7200/7500 */ + } else + gl_info->gl_card = CARD_ATI_RAGE_128PRO; + break; + case VENDOR_INTEL: + if (strstr(gl_info->gl_renderer, "915GM")) { + gl_info->gl_card = CARD_INTEL_I915GM; + } else if (strstr(gl_info->gl_renderer, "915G")) { + gl_info->gl_card = CARD_INTEL_I915G; + } else if (strstr(gl_info->gl_renderer, "865G")) { + gl_info->gl_card = CARD_INTEL_I865G; + } else if (strstr(gl_info->gl_renderer, "855G")) { + gl_info->gl_card = CARD_INTEL_I855G; + } else if (strstr(gl_info->gl_renderer, "830G")) { + gl_info->gl_card = CARD_INTEL_I830G; + } else { + gl_info->gl_card = CARD_INTEL_I915G; + } + break; + case VENDOR_MESA: + case VENDOR_WINE: + default: + /* Default to generic Nvidia hardware based on the supported OpenGL extensions. The choice + * for Nvidia was because the hardware and drivers they make are of good quality. This makes + * them a good generic choice. + */ + gl_info->gl_vendor = VENDOR_NVIDIA; + if(WINE_D3D9_CAPABLE(gl_info)) + gl_info->gl_card = CARD_NVIDIA_GEFORCEFX_5600; + else if(WINE_D3D8_CAPABLE(gl_info)) + gl_info->gl_card = CARD_NVIDIA_GEFORCE3; + else if(WINE_D3D7_CAPABLE(gl_info)) + gl_info->gl_card = CARD_NVIDIA_GEFORCE; + else if(WINE_D3D6_CAPABLE(gl_info)) + gl_info->gl_card = CARD_NVIDIA_RIVA_TNT; + else + gl_info->gl_card = CARD_NVIDIA_RIVA_128; + } + TRACE("FOUND (fake) card: 0x%x (vendor id), 0x%x (device id)\n", gl_info->gl_vendor, gl_info->gl_card); + + /* Load all the lookup tables + TODO: It may be a good idea to make minLookup and maxLookup const and populate them in wined3d_private.h where they are declared */ + minLookup[WINELOOKUP_WARPPARAM] = WINED3DTADDRESS_WRAP; + maxLookup[WINELOOKUP_WARPPARAM] = WINED3DTADDRESS_MIRRORONCE; + + minLookup[WINELOOKUP_MAGFILTER] = WINED3DTEXF_NONE; + maxLookup[WINELOOKUP_MAGFILTER] = WINED3DTEXF_ANISOTROPIC; + + + for (i = 0; i < MAX_LOOKUPS; i++) { + stateLookup[i] = HeapAlloc(GetProcessHeap(), 0, sizeof(*stateLookup[i]) * (1 + maxLookup[i] - minLookup[i]) ); + } + + stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_WRAP - minLookup[WINELOOKUP_WARPPARAM]] = GL_REPEAT; + stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_CLAMP - minLookup[WINELOOKUP_WARPPARAM]] = GL_CLAMP_TO_EDGE; + stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_BORDER - minLookup[WINELOOKUP_WARPPARAM]] = + gl_info->supported[ARB_TEXTURE_BORDER_CLAMP] ? GL_CLAMP_TO_BORDER_ARB : GL_REPEAT; + stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_BORDER - minLookup[WINELOOKUP_WARPPARAM]] = + gl_info->supported[ARB_TEXTURE_BORDER_CLAMP] ? GL_CLAMP_TO_BORDER_ARB : GL_REPEAT; + stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_MIRROR - minLookup[WINELOOKUP_WARPPARAM]] = + gl_info->supported[ARB_TEXTURE_MIRRORED_REPEAT] ? GL_MIRRORED_REPEAT_ARB : GL_REPEAT; + stateLookup[WINELOOKUP_WARPPARAM][WINED3DTADDRESS_MIRRORONCE - minLookup[WINELOOKUP_WARPPARAM]] = + gl_info->supported[ATI_TEXTURE_MIRROR_ONCE] ? GL_MIRROR_CLAMP_TO_EDGE_ATI : GL_REPEAT; + + stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_NONE - minLookup[WINELOOKUP_MAGFILTER]] = GL_NEAREST; + stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_POINT - minLookup[WINELOOKUP_MAGFILTER]] = GL_NEAREST; + stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_LINEAR - minLookup[WINELOOKUP_MAGFILTER]] = GL_LINEAR; + stateLookup[WINELOOKUP_MAGFILTER][WINED3DTEXF_ANISOTROPIC - minLookup[WINELOOKUP_MAGFILTER]] = + gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? GL_LINEAR : GL_NEAREST; + + + minMipLookup[WINED3DTEXF_NONE][WINED3DTEXF_NONE] = GL_LINEAR; + minMipLookup[WINED3DTEXF_NONE][WINED3DTEXF_POINT] = GL_LINEAR; + minMipLookup[WINED3DTEXF_NONE][WINED3DTEXF_LINEAR] = GL_LINEAR; + minMipLookup[WINED3DTEXF_POINT][WINED3DTEXF_NONE] = GL_NEAREST; + minMipLookup[WINED3DTEXF_POINT][WINED3DTEXF_POINT] = GL_NEAREST_MIPMAP_NEAREST; + minMipLookup[WINED3DTEXF_POINT][WINED3DTEXF_LINEAR] = GL_NEAREST_MIPMAP_LINEAR; + minMipLookup[WINED3DTEXF_LINEAR][WINED3DTEXF_NONE] = GL_LINEAR; + minMipLookup[WINED3DTEXF_LINEAR][WINED3DTEXF_POINT] = GL_LINEAR_MIPMAP_NEAREST; + minMipLookup[WINED3DTEXF_LINEAR][WINED3DTEXF_LINEAR] = GL_LINEAR_MIPMAP_LINEAR; + minMipLookup[WINED3DTEXF_ANISOTROPIC][WINED3DTEXF_NONE] = gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? + GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + minMipLookup[WINED3DTEXF_ANISOTROPIC][WINED3DTEXF_POINT] = gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR; + minMipLookup[WINED3DTEXF_ANISOTROPIC][WINED3DTEXF_LINEAR] = gl_info->supported[EXT_TEXTURE_FILTER_ANISOTROPIC] ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + +/* TODO: config lookups */ + + /* Make sure there's an active HDC else the WGL extensions will fail */ + hdc = pwglGetCurrentDC(); + if (hdc) { + WGL_Extensions = GL_EXTCALL(wglGetExtensionsStringARB(hdc)); + TRACE_(d3d_caps)("WGL_Extensions reported:\n"); + + if (NULL == WGL_Extensions) { + ERR(" WGL_Extensions returns NULL\n"); + } else { + while (*WGL_Extensions != 0x00) { + const char *Start; + char ThisExtn[256]; + size_t len; + + while (isspace(*WGL_Extensions)) WGL_Extensions++; + Start = WGL_Extensions; + while (!isspace(*WGL_Extensions) && *WGL_Extensions != 0x00) { + WGL_Extensions++; + } + + len = WGL_Extensions - Start; + if (len == 0 || len >= sizeof(ThisExtn)) + continue; + + memcpy(ThisExtn, Start, len); + ThisExtn[len] = '\0'; + TRACE_(d3d_caps)("- %s\n", ThisExtn); + + if (!strcmp(ThisExtn, "WGL_ARB_pbuffer")) { + gl_info->supported[WGL_ARB_PBUFFER] = TRUE; + TRACE_(d3d_caps)("FOUND: WGL_ARB_pbuffer support\n"); + } + } + } + } + + + WineD3D_ReleaseFakeGLContext(); + return return_value; +} +#undef GLINFO_LOCATION + +/********************************************************** + * IWineD3D implementation follows + **********************************************************/ + +static UINT WINAPI IWineD3DImpl_GetAdapterCount (IWineD3D *iface) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + + TRACE_(d3d_caps)("(%p): Reporting %d adapters\n", This, numAdapters); + return numAdapters; +} + +static HRESULT WINAPI IWineD3DImpl_RegisterSoftwareDevice(IWineD3D *iface, void* pInitializeFunction) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + FIXME("(%p)->(%p): stub\n", This, pInitializeFunction); + return WINED3D_OK; +} + +static HMONITOR WINAPI IWineD3DImpl_GetAdapterMonitor(IWineD3D *iface, UINT Adapter) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + + if (Adapter >= IWineD3DImpl_GetAdapterCount(iface)) { + return NULL; + } + + TRACE_(d3d_caps)("(%p)->(%d)\n", This, Adapter); + return MonitorFromPoint(Adapters[Adapter].monitorPoint, MONITOR_DEFAULTTOPRIMARY); +} + +/* FIXME: GetAdapterModeCount and EnumAdapterModes currently only returns modes + of the same bpp but different resolutions */ + +/* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ +static UINT WINAPI IWineD3DImpl_GetAdapterModeCount(IWineD3D *iface, UINT Adapter, WINED3DFORMAT Format) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + TRACE_(d3d_caps)("(%p}->(Adapter: %d, Format: %s)\n", This, Adapter, debug_d3dformat(Format)); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + return 0; + } + + /* TODO: Store modes per adapter and read it from the adapter structure */ + if (Adapter == 0) { /* Display */ + int i = 0; + int j = 0; + + if (!DEBUG_SINGLE_MODE) { + DEVMODEW DevModeW; + + ZeroMemory(&DevModeW, sizeof(DevModeW)); + DevModeW.dmSize = sizeof(DevModeW); + while (EnumDisplaySettingsExW(NULL, j, &DevModeW, 0)) { + j++; + switch (Format) + { + case WINED3DFMT_UNKNOWN: + /* This is for D3D8, do not enumerate P8 here */ + if (DevModeW.dmBitsPerPel == 32 || + DevModeW.dmBitsPerPel == 16) i++; + break; + case WINED3DFMT_X8R8G8B8: + if (DevModeW.dmBitsPerPel == 32) i++; + break; + case WINED3DFMT_R5G6B5: + if (DevModeW.dmBitsPerPel == 16) i++; + break; + case WINED3DFMT_P8: + if (DevModeW.dmBitsPerPel == 8) i++; + break; + default: + /* Skip other modes as they do not match the requested format */ + break; + } + } + } else { + i = 1; + j = 1; + } + + TRACE_(d3d_caps)("(%p}->(Adapter: %d) => %d (out of %d)\n", This, Adapter, i, j); + return i; + } else { + FIXME_(d3d_caps)("Adapter not primary display\n"); + } + return 0; +} + +/* Note: dx9 supplies a format. Calls from d3d8 supply WINED3DFMT_UNKNOWN */ +static HRESULT WINAPI IWineD3DImpl_EnumAdapterModes(IWineD3D *iface, UINT Adapter, WINED3DFORMAT Format, UINT Mode, WINED3DDISPLAYMODE* pMode) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + TRACE_(d3d_caps)("(%p}->(Adapter:%d, mode:%d, pMode:%p, format:%s)\n", This, Adapter, Mode, pMode, debug_d3dformat(Format)); + + /* Validate the parameters as much as possible */ + if (NULL == pMode || + Adapter >= IWineD3DImpl_GetAdapterCount(iface) || + Mode >= IWineD3DImpl_GetAdapterModeCount(iface, Adapter, Format)) { + return WINED3DERR_INVALIDCALL; + } + + /* TODO: Store modes per adapter and read it from the adapter structure */ + if (Adapter == 0 && !DEBUG_SINGLE_MODE) { /* Display */ + DEVMODEW DevModeW; + int ModeIdx = 0; + int i = 0; + int j = 0; + + ZeroMemory(&DevModeW, sizeof(DevModeW)); + DevModeW.dmSize = sizeof(DevModeW); + + /* If we are filtering to a specific format (D3D9), then need to skip + all unrelated modes, but if mode is irrelevant (D3D8), then we can + just count through the ones with valid bit depths */ + while ((i<=Mode) && EnumDisplaySettingsExW(NULL, j++, &DevModeW, 0)) { + switch (Format) + { + case WINED3DFMT_UNKNOWN: + /* This is D3D8. Do not enumerate P8 here */ + if (DevModeW.dmBitsPerPel == 32 || + DevModeW.dmBitsPerPel == 16) i++; + break; + case WINED3DFMT_X8R8G8B8: + if (DevModeW.dmBitsPerPel == 32) i++; + break; + case WINED3DFMT_R5G6B5: + if (DevModeW.dmBitsPerPel == 16) i++; + break; + case WINED3DFMT_P8: + if (DevModeW.dmBitsPerPel == 8) i++; + break; + default: + /* Modes that don't match what we support can get an early-out */ + TRACE_(d3d_caps)("Searching for %s, returning D3DERR_INVALIDCALL\n", debug_d3dformat(Format)); + return WINED3DERR_INVALIDCALL; + } + } + + if (i == 0) { + TRACE_(d3d_caps)("No modes found for format (%x - %s)\n", Format, debug_d3dformat(Format)); + return WINED3DERR_INVALIDCALL; + } + ModeIdx = j - 1; + + /* Now get the display mode via the calculated index */ + if (EnumDisplaySettingsExW(NULL, ModeIdx, &DevModeW, 0)) { + pMode->Width = DevModeW.dmPelsWidth; + pMode->Height = DevModeW.dmPelsHeight; + pMode->RefreshRate = WINED3DADAPTER_DEFAULT; + if (DevModeW.dmFields & DM_DISPLAYFREQUENCY) + pMode->RefreshRate = DevModeW.dmDisplayFrequency; + + if (Format == WINED3DFMT_UNKNOWN) + { + switch (DevModeW.dmBitsPerPel) + { + case 8: + pMode->Format = WINED3DFMT_P8; + break; + case 16: + pMode->Format = WINED3DFMT_R5G6B5; + break; + case 32: + pMode->Format = WINED3DFMT_X8R8G8B8; + break; + default: + pMode->Format = WINED3DFMT_UNKNOWN; + ERR("Unhandled bit depth (%u) in mode list!\n", DevModeW.dmBitsPerPel); + } + } else { + pMode->Format = Format; + } + } else { + TRACE_(d3d_caps)("Requested mode out of range %d\n", Mode); + return WINED3DERR_INVALIDCALL; + } + + TRACE_(d3d_caps)("W %d H %d rr %d fmt (%x - %s) bpp %u\n", pMode->Width, pMode->Height, + pMode->RefreshRate, pMode->Format, debug_d3dformat(pMode->Format), + DevModeW.dmBitsPerPel); + + } else if (DEBUG_SINGLE_MODE) { + /* Return one setting of the format requested */ + if (Mode > 0) return WINED3DERR_INVALIDCALL; + pMode->Width = 800; + pMode->Height = 600; + pMode->RefreshRate = 60; + pMode->Format = (Format == WINED3DFMT_UNKNOWN) ? WINED3DFMT_X8R8G8B8 : Format; + } else { + FIXME_(d3d_caps)("Adapter not primary display\n"); + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DImpl_GetAdapterDisplayMode(IWineD3D *iface, UINT Adapter, WINED3DDISPLAYMODE* pMode) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + TRACE_(d3d_caps)("(%p}->(Adapter: %d, pMode: %p)\n", This, Adapter, pMode); + + if (NULL == pMode || + Adapter >= IWineD3D_GetAdapterCount(iface)) { + return WINED3DERR_INVALIDCALL; + } + + if (Adapter == 0) { /* Display */ + int bpp = 0; + DEVMODEW DevModeW; + + ZeroMemory(&DevModeW, sizeof(DevModeW)); + DevModeW.dmSize = sizeof(DevModeW); + + EnumDisplaySettingsExW(NULL, ENUM_CURRENT_SETTINGS, &DevModeW, 0); + pMode->Width = DevModeW.dmPelsWidth; + pMode->Height = DevModeW.dmPelsHeight; + bpp = DevModeW.dmBitsPerPel; + pMode->RefreshRate = WINED3DADAPTER_DEFAULT; + if (DevModeW.dmFields&DM_DISPLAYFREQUENCY) + { + pMode->RefreshRate = DevModeW.dmDisplayFrequency; + } + + switch (bpp) { + case 8: pMode->Format = WINED3DFMT_R3G3B2; break; + case 16: pMode->Format = WINED3DFMT_R5G6B5; break; + case 24: pMode->Format = WINED3DFMT_X8R8G8B8; break; /* Robots needs 24bit to be X8R8G8B8 */ + case 32: pMode->Format = WINED3DFMT_X8R8G8B8; break; /* EVE online and the Fur demo need 32bit AdapterDisplatMode to return X8R8G8B8 */ + default: pMode->Format = WINED3DFMT_UNKNOWN; + } + + } else { + FIXME_(d3d_caps)("Adapter not primary display\n"); + } + + TRACE_(d3d_caps)("returning w:%d, h:%d, ref:%d, fmt:%s\n", pMode->Width, + pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format)); + return WINED3D_OK; +} + +/* NOTE: due to structure differences between dx8 and dx9 D3DADAPTER_IDENTIFIER, + and fields being inserted in the middle, a new structure is used in place */ +static HRESULT WINAPI IWineD3DImpl_GetAdapterIdentifier(IWineD3D *iface, UINT Adapter, DWORD Flags, + WINED3DADAPTER_IDENTIFIER* pIdentifier) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + + TRACE_(d3d_caps)("(%p}->(Adapter: %d, Flags: %x, pId=%p)\n", This, Adapter, Flags, pIdentifier); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + return WINED3DERR_INVALIDCALL; + } + + /* Return the information requested */ + TRACE_(d3d_caps)("device/Vendor Name and Version detection using FillGLCaps\n"); + strcpy(pIdentifier->Driver, Adapters[Adapter].driver); + strcpy(pIdentifier->Description, Adapters[Adapter].description); + + /* Note dx8 doesn't supply a DeviceName */ + if (NULL != pIdentifier->DeviceName) strcpy(pIdentifier->DeviceName, "\\\\.\\DISPLAY"); /* FIXME: May depend on desktop? */ + /* Current Windows drivers have versions like 6.14.... (some older have an earlier version) */ + pIdentifier->DriverVersion->u.HighPart = MAKEDWORD_VERSION(6, 14); + pIdentifier->DriverVersion->u.LowPart = Adapters[Adapter].gl_info.gl_driver_version; + *(pIdentifier->VendorId) = Adapters[Adapter].gl_info.gl_vendor; + *(pIdentifier->DeviceId) = Adapters[Adapter].gl_info.gl_card; + *(pIdentifier->SubSysId) = 0; + *(pIdentifier->Revision) = 0; + + /*FIXME: memcpy(&pIdentifier->DeviceIdentifier, ??, sizeof(??GUID)); */ + if (Flags & WINED3DENUM_NO_WHQL_LEVEL) { + *(pIdentifier->WHQLLevel) = 0; + } else { + *(pIdentifier->WHQLLevel) = 1; + } + + return WINED3D_OK; +} + +static BOOL IWineD3DImpl_IsPixelFormatCompatibleWithRenderFmt(const WineD3D_PixelFormat *cfg, WINED3DFORMAT Format) { + short redSize, greenSize, blueSize, alphaSize, colorBits; + + if(!cfg) + return FALSE; + + if(!getColorBits(Format, &redSize, &greenSize, &blueSize, &alphaSize, &colorBits)) { + ERR("Unable to check compatibility for Format=%s\n", debug_d3dformat(Format)); + return FALSE; + } + + if(cfg->redSize < redSize) + return FALSE; + + if(cfg->greenSize < greenSize) + return FALSE; + + if(cfg->blueSize < blueSize) + return FALSE; + + if(cfg->alphaSize < alphaSize) + return FALSE; + + return TRUE; +} + +static BOOL IWineD3DImpl_IsPixelFormatCompatibleWithDepthFmt(const WineD3D_PixelFormat *cfg, WINED3DFORMAT Format) { + short depthSize, stencilSize; + + if(!cfg) + return FALSE; + + if(!getDepthStencilBits(Format, &depthSize, &stencilSize)) { + ERR("Unable to check compatibility for Format=%s\n", debug_d3dformat(Format)); + return FALSE; + } + + if(cfg->depthSize < depthSize) + return FALSE; + + if(cfg->stencilSize < stencilSize) + return FALSE; + + return TRUE; +} + +static HRESULT WINAPI IWineD3DImpl_CheckDepthStencilMatch(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, + WINED3DFORMAT AdapterFormat, + WINED3DFORMAT RenderTargetFormat, + WINED3DFORMAT DepthStencilFormat) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + int nCfgs; + WineD3D_PixelFormat *cfgs; + int it; + + WARN_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%x,%s), AdptFmt:(%x,%s), RendrTgtFmt:(%x,%s), DepthStencilFmt:(%x,%s))\n", + This, Adapter, + DeviceType, debug_d3ddevicetype(DeviceType), + AdapterFormat, debug_d3dformat(AdapterFormat), + RenderTargetFormat, debug_d3dformat(RenderTargetFormat), + DepthStencilFormat, debug_d3dformat(DepthStencilFormat)); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + TRACE("(%p) Failed: Atapter (%u) higher than supported adapters (%u) returning WINED3DERR_INVALIDCALL\n", This, Adapter, IWineD3D_GetAdapterCount(iface)); + return WINED3DERR_INVALIDCALL; + } + + cfgs = Adapters[Adapter].cfgs; + nCfgs = Adapters[Adapter].nCfgs; + for (it = 0; it < nCfgs; ++it) { + if (IWineD3DImpl_IsPixelFormatCompatibleWithRenderFmt(&cfgs[it], RenderTargetFormat)) { + if (IWineD3DImpl_IsPixelFormatCompatibleWithDepthFmt(&cfgs[it], DepthStencilFormat)) { + TRACE_(d3d_caps)("(%p) : Formats matched\n", This); + return WINED3D_OK; + } + } + } + WARN_(d3d_caps)("unsupported format pair: %s and %s\n", debug_d3dformat(RenderTargetFormat), debug_d3dformat(DepthStencilFormat)); + + return WINED3DERR_NOTAVAILABLE; +} + +static HRESULT WINAPI IWineD3DImpl_CheckDeviceMultiSampleType(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, + WINED3DFORMAT SurfaceFormat, + BOOL Windowed, WINED3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels) { + + IWineD3DImpl *This = (IWineD3DImpl *)iface; + TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%x,%s), SurfFmt:(%x,%s), Win?%d, MultiSamp:%x, pQual:%p)\n", + This, + Adapter, + DeviceType, debug_d3ddevicetype(DeviceType), + SurfaceFormat, debug_d3dformat(SurfaceFormat), + Windowed, + MultiSampleType, + pQualityLevels); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + return WINED3DERR_INVALIDCALL; + } + + /* TODO: Store in Adapter structure */ + if (pQualityLevels != NULL) { + static int s_single_shot = 0; + if (!s_single_shot) { + FIXME("Quality levels unsupported at present\n"); + s_single_shot = 1; + } + *pQualityLevels = 1; /* Guess at a value! */ + } + + if (WINED3DMULTISAMPLE_NONE == MultiSampleType) return WINED3D_OK; + return WINED3DERR_NOTAVAILABLE; +} + +static HRESULT WINAPI IWineD3DImpl_CheckDeviceType(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE CheckType, + WINED3DFORMAT DisplayFormat, WINED3DFORMAT BackBufferFormat, BOOL Windowed) { + + IWineD3DImpl *This = (IWineD3DImpl *)iface; + int nCfgs = 0; + WineD3D_PixelFormat *cfgs; + int it; + HRESULT hr = WINED3DERR_NOTAVAILABLE; + + TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, CheckType:(%x,%s), DispFmt:(%x,%s), BackBuf:(%x,%s), Win?%d): stub\n", + This, + Adapter, + CheckType, debug_d3ddevicetype(CheckType), + DisplayFormat, debug_d3dformat(DisplayFormat), + BackBufferFormat, debug_d3dformat(BackBufferFormat), + Windowed); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + WARN_(d3d_caps)("Adapter >= IWineD3D_GetAdapterCount(iface), returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + + cfgs = Adapters[Adapter].cfgs; + nCfgs = Adapters[Adapter].nCfgs; + for (it = 0; it < nCfgs; ++it) { + if (IWineD3DImpl_IsPixelFormatCompatibleWithRenderFmt(&cfgs[it], DisplayFormat)) { + hr = WINED3D_OK; + TRACE_(d3d_caps)("OK\n"); + break ; + } + } + + if(hr != WINED3D_OK) + ERR("unsupported format %s\n", debug_d3dformat(DisplayFormat)); + + if(hr != WINED3D_OK) + TRACE_(d3d_caps)("returning something different from WINED3D_OK\n"); + + return hr; +} + +#define GLINFO_LOCATION Adapters[Adapter].gl_info +static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormat(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, + WINED3DFORMAT AdapterFormat, DWORD Usage, WINED3DRESOURCETYPE RType, WINED3DFORMAT CheckFormat) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + TRACE_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), AdptFmt:(%u,%s), Use:(%u,%s,%s), ResTyp:(%x,%s), CheckFmt:(%u,%s))\n", + This, + Adapter, + DeviceType, debug_d3ddevicetype(DeviceType), + AdapterFormat, debug_d3dformat(AdapterFormat), + Usage, debug_d3dusage(Usage), debug_d3dusagequery(Usage), + RType, debug_d3dresourcetype(RType), + CheckFormat, debug_d3dformat(CheckFormat)); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + return WINED3DERR_INVALIDCALL; + } + + if (Usage & WINED3DUSAGE_QUERY_FILTER) { + switch (CheckFormat) { + /* Filtering not supported */ + case WINED3DFMT_A32B32G32R32F: + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + default: + break; + } + } + + /* TODO: Check support against more of the WINED3DUSAGE_QUERY_* constants + * See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/IDirect3D9__CheckDeviceFormat.asp + * and http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/D3DUSAGE_QUERY.asp */ + if (Usage & WINED3DUSAGE_QUERY_VERTEXTEXTURE) { + if (!GL_LIMITS(vertex_samplers)) { + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + + switch (CheckFormat) { + case WINED3DFMT_A32B32G32R32F: + if (!GL_SUPPORT(ARB_TEXTURE_FLOAT)) { + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + + default: + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + } + + if(Usage & WINED3DUSAGE_DEPTHSTENCIL) { + switch (CheckFormat) { + /* In theory we could do all formats, just fetch them accordingly should the buffer be locked. + * Windows supports only those 3, and enumerating the other formats confuses applications + */ + case WINED3DFMT_D24S8: + case WINED3DFMT_D24X8: + case WINED3DFMT_D16: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + case WINED3DFMT_D16_LOCKABLE: + case WINED3DFMT_D24FS8: + case WINED3DFMT_D32F_LOCKABLE: + case WINED3DFMT_D24X4S4: + case WINED3DFMT_D15S1: + case WINED3DFMT_D32: + TRACE_(d3d_caps)("[FAILED]. Disabled because not enumerated on windows\n"); + return WINED3DERR_NOTAVAILABLE; + default: + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + } else if(Usage & WINED3DUSAGE_RENDERTARGET) { + switch (CheckFormat) { + case WINED3DFMT_R8G8B8: + case WINED3DFMT_A8R8G8B8: + case WINED3DFMT_X8R8G8B8: + case WINED3DFMT_R5G6B5: + case WINED3DFMT_X1R5G5B5: + case WINED3DFMT_A1R5G5B5: + case WINED3DFMT_A4R4G4B4: + case WINED3DFMT_R3G3B2: + case WINED3DFMT_X4R4G4B4: + case WINED3DFMT_A8B8G8R8: + case WINED3DFMT_X8B8G8R8: + case WINED3DFMT_P8: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + case WINED3DFMT_R16F: + case WINED3DFMT_A16B16G16R16F: + if (!GL_SUPPORT(ARB_HALF_FLOAT_PIXEL) || !GL_SUPPORT(ARB_TEXTURE_FLOAT)) { + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + case WINED3DFMT_A32B32G32R32F: + if (!GL_SUPPORT(ARB_TEXTURE_FLOAT)) { + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + default: + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + } else if(Usage & WINED3DUSAGE_QUERY_LEGACYBUMPMAP) { + if(GL_SUPPORT(NV_REGISTER_COMBINERS) && GL_SUPPORT(NV_TEXTURE_SHADER2)) { + switch (CheckFormat) { + case WINED3DFMT_V8U8: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + /* TODO: Other bump map formats */ + default: + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + } + if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + switch (CheckFormat) { + case WINED3DFMT_V8U8: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + default: + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + } + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + + if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { + switch (CheckFormat) { + case WINED3DFMT_DXT1: + case WINED3DFMT_DXT2: + case WINED3DFMT_DXT3: + case WINED3DFMT_DXT4: + case WINED3DFMT_DXT5: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + default: + break; /* Avoid compiler warnings */ + } + } + + /* Check for supported sRGB formats (Texture loading and framebuffer) */ + if (GL_SUPPORT(EXT_TEXTURE_SRGB) && (Usage & WINED3DUSAGE_QUERY_SRGBREAD)) { + switch (CheckFormat) { + case WINED3DFMT_A8R8G8B8: + case WINED3DFMT_X8R8G8B8: + case WINED3DFMT_A4R4G4B4: + case WINED3DFMT_L8: + case WINED3DFMT_A8L8: + case WINED3DFMT_DXT1: + case WINED3DFMT_DXT2: + case WINED3DFMT_DXT3: + case WINED3DFMT_DXT4: + case WINED3DFMT_DXT5: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + + default: + TRACE_(d3d_caps)("[FAILED] Gamma texture format %s not supported.\n", debug_d3dformat(CheckFormat)); + return WINED3DERR_NOTAVAILABLE; + } + } + + if (GL_SUPPORT(ARB_TEXTURE_FLOAT)) { + + BOOL half_pixel_support = GL_SUPPORT(ARB_HALF_FLOAT_PIXEL); + + switch (CheckFormat) { + case WINED3DFMT_R16F: + case WINED3DFMT_A16B16G16R16F: + if (!half_pixel_support) break; + case WINED3DFMT_R32F: + case WINED3DFMT_A32B32G32R32F: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + default: + break; /* Avoid compiler warnings */ + } + } + + /* This format is nothing special and it is supported perfectly. + * However, ati and nvidia driver on windows do not mark this format as + * supported (tested with the dxCapsViewer) and pretending to + * support this format uncovers a bug in Battlefield 1942 (fonts are missing) + * So do the same as Windows drivers and pretend not to support it on dx8 and 9 + * Enable it on dx7. It will need additional checking on dx10 when we support it. + */ + if(This->dxVersion > 7 && CheckFormat == WINED3DFMT_R8G8B8) { + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + + switch (CheckFormat) { + + /***** + * supported: RGB(A) formats + */ + case WINED3DFMT_R8G8B8: /* Enable for dx7, blacklisted for 8 and 9 above */ + case WINED3DFMT_A8R8G8B8: + case WINED3DFMT_X8R8G8B8: + case WINED3DFMT_R5G6B5: + case WINED3DFMT_X1R5G5B5: + case WINED3DFMT_A1R5G5B5: + case WINED3DFMT_A4R4G4B4: + case WINED3DFMT_R3G3B2: + case WINED3DFMT_A8: + case WINED3DFMT_X4R4G4B4: + case WINED3DFMT_A8B8G8R8: + case WINED3DFMT_X8B8G8R8: + case WINED3DFMT_A2R10G10B10: + case WINED3DFMT_A2B10G10R10: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + + /***** + * supported: Palettized + */ + case WINED3DFMT_P8: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + + /***** + * Supported: (Alpha)-Luminance + */ + case WINED3DFMT_L8: + case WINED3DFMT_A8L8: + case WINED3DFMT_A4L4: + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + + /***** + * Not supported for now: Bump mapping formats + * Enable some because games often fail when they are not available + * and are still playable even without bump mapping + */ + case WINED3DFMT_V8U8: + case WINED3DFMT_V16U16: + case WINED3DFMT_L6V5U5: + case WINED3DFMT_X8L8V8U8: + case WINED3DFMT_Q8W8V8U8: + case WINED3DFMT_W11V11U10: + case WINED3DFMT_A2W10V10U10: + WARN_(d3d_caps)("[Not supported, but pretended to do]\n"); + return WINED3D_OK; + + /***** + * DXTN Formats: Handled above + * WINED3DFMT_DXT1 + * WINED3DFMT_DXT2 + * WINED3DFMT_DXT3 + * WINED3DFMT_DXT4 + * WINED3DFMT_DXT5 + */ + + /***** + * Odd formats - not supported + */ + case WINED3DFMT_VERTEXDATA: + case WINED3DFMT_INDEX16: + case WINED3DFMT_INDEX32: + case WINED3DFMT_Q16W16V16U16: + TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */ + return WINED3DERR_NOTAVAILABLE; + + /***** + * Float formats: Not supported right now + */ + case WINED3DFMT_G16R16F: + case WINED3DFMT_G32R32F: + case WINED3DFMT_CxV8U8: + TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */ + return WINED3DERR_NOTAVAILABLE; + + /* Not supported */ + case WINED3DFMT_G16R16: + case WINED3DFMT_A16B16G16R16: + case WINED3DFMT_A8R3G3B2: + TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */ + return WINED3DERR_NOTAVAILABLE; + + /* ATI instancing hack: Although ATI cards do not support Shader Model 3.0, they support + * instancing. To query if the card supports instancing CheckDeviceFormat with the special format + * MAKEFOURCC('I','N','S','T') is used. Should a (broken) app check for this provide a proper return value. + * We can do instancing with all shader versions, but we need vertex shaders. + * + * Additionally applications have to set the D3DRS_POINTSIZE render state to MAKEFOURCC('I','N','S','T') once + * to enable instancing. WineD3D doesn't need that and just ignores it. + * + * With Shader Model 3.0 capable cards Instancing 'just works' in Windows. + */ + case WINEMAKEFOURCC('I','N','S','T'): + TRACE("ATI Instancing check hack\n"); + if(GL_SUPPORT(ARB_VERTEX_PROGRAM) || GL_SUPPORT(ARB_VERTEX_SHADER)) { + TRACE_(d3d_caps)("[OK]\n"); + return WINED3D_OK; + } else { + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; + } + + default: + break; + } + + TRACE_(d3d_caps)("[FAILED]\n"); + return WINED3DERR_NOTAVAILABLE; +} + +static HRESULT WINAPI IWineD3DImpl_CheckDeviceFormatConversion(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, + WINED3DFORMAT SourceFormat, WINED3DFORMAT TargetFormat) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + + FIXME_(d3d_caps)("(%p)-> (STUB) (Adptr:%d, DevType:(%u,%s), SrcFmt:(%u,%s), TgtFmt:(%u,%s))\n", + This, + Adapter, + DeviceType, debug_d3ddevicetype(DeviceType), + SourceFormat, debug_d3dformat(SourceFormat), + TargetFormat, debug_d3dformat(TargetFormat)); + return WINED3D_OK; +} + +/* Note: d3d8 passes in a pointer to a D3DCAPS8 structure, which is a true + subset of a D3DCAPS9 structure. However, it has to come via a void * + as the d3d8 interface cannot import the d3d9 header */ +static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, WINED3DCAPS* pCaps) { + + IWineD3DImpl *This = (IWineD3DImpl *)iface; + int vs_selected_mode; + int ps_selected_mode; + + TRACE_(d3d_caps)("(%p)->(Adptr:%d, DevType: %x, pCaps: %p)\n", This, Adapter, DeviceType, pCaps); + + if (Adapter >= IWineD3D_GetAdapterCount(iface)) { + return WINED3DERR_INVALIDCALL; + } + + select_shader_mode(&Adapters[Adapter].gl_info, DeviceType, &ps_selected_mode, &vs_selected_mode); + + /* This function should *not* be modifying GL caps + * TODO: move the functionality where it belongs */ + select_shader_max_constants(ps_selected_mode, vs_selected_mode, &Adapters[Adapter].gl_info); + + /* ------------------------------------------------ + The following fields apply to both d3d8 and d3d9 + ------------------------------------------------ */ + *pCaps->DeviceType = (DeviceType == WINED3DDEVTYPE_HAL) ? WINED3DDEVTYPE_HAL : WINED3DDEVTYPE_REF; /* Not quite true, but use h/w supported by opengl I suppose */ + *pCaps->AdapterOrdinal = Adapter; + + *pCaps->Caps = 0; + *pCaps->Caps2 = WINED3DCAPS2_CANRENDERWINDOWED | + WINED3DCAPS2_FULLSCREENGAMMA | + WINED3DCAPS2_DYNAMICTEXTURES; + *pCaps->Caps3 = WINED3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD; + *pCaps->PresentationIntervals = WINED3DPRESENT_INTERVAL_IMMEDIATE; + + *pCaps->CursorCaps = WINED3DCURSORCAPS_COLOR | + WINED3DCURSORCAPS_LOWRES; + + *pCaps->DevCaps = WINED3DDEVCAPS_FLOATTLVERTEX | + WINED3DDEVCAPS_EXECUTESYSTEMMEMORY | + WINED3DDEVCAPS_TLVERTEXSYSTEMMEMORY| + WINED3DDEVCAPS_TLVERTEXVIDEOMEMORY | + WINED3DDEVCAPS_DRAWPRIMTLVERTEX | + WINED3DDEVCAPS_HWTRANSFORMANDLIGHT | + WINED3DDEVCAPS_EXECUTEVIDEOMEMORY | + WINED3DDEVCAPS_PUREDEVICE | + WINED3DDEVCAPS_HWRASTERIZATION | + WINED3DDEVCAPS_TEXTUREVIDEOMEMORY | + WINED3DDEVCAPS_TEXTURESYSTEMMEMORY | + WINED3DDEVCAPS_CANRENDERAFTERFLIP | + WINED3DDEVCAPS_DRAWPRIMITIVES2 | + WINED3DDEVCAPS_DRAWPRIMITIVES2EX | + WINED3DDEVCAPS_RTPATCHES; + + *pCaps->PrimitiveMiscCaps = WINED3DPMISCCAPS_CULLNONE | + WINED3DPMISCCAPS_CULLCCW | + WINED3DPMISCCAPS_CULLCW | + WINED3DPMISCCAPS_COLORWRITEENABLE | + WINED3DPMISCCAPS_CLIPTLVERTS | + WINED3DPMISCCAPS_CLIPPLANESCALEDPOINTS | + WINED3DPMISCCAPS_MASKZ | + WINED3DPMISCCAPS_BLENDOP; + /* TODO: + WINED3DPMISCCAPS_NULLREFERENCE + WINED3DPMISCCAPS_INDEPENDENTWRITEMASKS + WINED3DPMISCCAPS_FOGANDSPECULARALPHA + WINED3DPMISCCAPS_SEPARATEALPHABLEND + WINED3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS + WINED3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING + WINED3DPMISCCAPS_FOGVERTEXCLAMPED */ + +/* The caps below can be supported but aren't handled yet in utils.c 'd3dta_to_combiner_input', disable them until support is fixed */ +#if 0 + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) + *pCaps->PrimitiveMiscCaps |= WINED3DPMISCCAPS_TSSARGTEMP; + if (GL_SUPPORT(NV_REGISTER_COMBINERS2)) + *pCaps->PrimitiveMiscCaps |= WINED3DPMISCCAPS_PERSTAGECONSTANT; +#endif + + *pCaps->RasterCaps = WINED3DPRASTERCAPS_DITHER | + WINED3DPRASTERCAPS_PAT | + WINED3DPRASTERCAPS_WFOG | + WINED3DPRASTERCAPS_ZFOG | + WINED3DPRASTERCAPS_FOGVERTEX | + WINED3DPRASTERCAPS_FOGTABLE | + WINED3DPRASTERCAPS_FOGRANGE | + WINED3DPRASTERCAPS_STIPPLE | + WINED3DPRASTERCAPS_SUBPIXEL | + WINED3DPRASTERCAPS_ZTEST | + WINED3DPRASTERCAPS_SCISSORTEST | + WINED3DPRASTERCAPS_SLOPESCALEDEPTHBIAS | + WINED3DPRASTERCAPS_DEPTHBIAS; + + if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { + *pCaps->RasterCaps |= WINED3DPRASTERCAPS_ANISOTROPY | + WINED3DPRASTERCAPS_ZBIAS | + WINED3DPRASTERCAPS_MIPMAPLODBIAS; + } + /* FIXME Add: + WINED3DPRASTERCAPS_COLORPERSPECTIVE + WINED3DPRASTERCAPS_STRETCHBLTMULTISAMPLE + WINED3DPRASTERCAPS_ANTIALIASEDGES + WINED3DPRASTERCAPS_ZBUFFERLESSHSR + WINED3DPRASTERCAPS_WBUFFER */ + + *pCaps->ZCmpCaps = WINED3DPCMPCAPS_ALWAYS | + WINED3DPCMPCAPS_EQUAL | + WINED3DPCMPCAPS_GREATER | + WINED3DPCMPCAPS_GREATEREQUAL | + WINED3DPCMPCAPS_LESS | + WINED3DPCMPCAPS_LESSEQUAL | + WINED3DPCMPCAPS_NEVER | + WINED3DPCMPCAPS_NOTEQUAL; + + *pCaps->SrcBlendCaps = WINED3DPBLENDCAPS_BLENDFACTOR | + WINED3DPBLENDCAPS_BOTHINVSRCALPHA | + WINED3DPBLENDCAPS_BOTHSRCALPHA | + WINED3DPBLENDCAPS_DESTALPHA | + WINED3DPBLENDCAPS_DESTCOLOR | + WINED3DPBLENDCAPS_INVDESTALPHA | + WINED3DPBLENDCAPS_INVDESTCOLOR | + WINED3DPBLENDCAPS_INVSRCALPHA | + WINED3DPBLENDCAPS_INVSRCCOLOR | + WINED3DPBLENDCAPS_ONE | + WINED3DPBLENDCAPS_SRCALPHA | + WINED3DPBLENDCAPS_SRCALPHASAT | + WINED3DPBLENDCAPS_SRCCOLOR | + WINED3DPBLENDCAPS_ZERO; + + *pCaps->DestBlendCaps = WINED3DPBLENDCAPS_BLENDFACTOR | + WINED3DPBLENDCAPS_BOTHINVSRCALPHA | + WINED3DPBLENDCAPS_BOTHSRCALPHA | + WINED3DPBLENDCAPS_DESTALPHA | + WINED3DPBLENDCAPS_DESTCOLOR | + WINED3DPBLENDCAPS_INVDESTALPHA | + WINED3DPBLENDCAPS_INVDESTCOLOR | + WINED3DPBLENDCAPS_INVSRCALPHA | + WINED3DPBLENDCAPS_INVSRCCOLOR | + WINED3DPBLENDCAPS_ONE | + WINED3DPBLENDCAPS_SRCALPHA | + WINED3DPBLENDCAPS_SRCCOLOR | + WINED3DPBLENDCAPS_ZERO; + /* NOTE: WINED3DPBLENDCAPS_SRCALPHASAT is not supported as dest blend factor, + * according to the glBlendFunc manpage + */ + + *pCaps->AlphaCmpCaps = WINED3DPCMPCAPS_ALWAYS | + WINED3DPCMPCAPS_EQUAL | + WINED3DPCMPCAPS_GREATER | + WINED3DPCMPCAPS_GREATEREQUAL | + WINED3DPCMPCAPS_LESS | + WINED3DPCMPCAPS_LESSEQUAL | + WINED3DPCMPCAPS_NEVER | + WINED3DPCMPCAPS_NOTEQUAL; + + *pCaps->ShadeCaps = WINED3DPSHADECAPS_SPECULARGOURAUDRGB | + WINED3DPSHADECAPS_COLORGOURAUDRGB | + WINED3DPSHADECAPS_ALPHAFLATBLEND | + WINED3DPSHADECAPS_ALPHAGOURAUDBLEND | + WINED3DPSHADECAPS_COLORFLATRGB | + WINED3DPSHADECAPS_FOGFLAT | + WINED3DPSHADECAPS_FOGGOURAUD | + WINED3DPSHADECAPS_SPECULARFLATRGB; + + *pCaps->TextureCaps = WINED3DPTEXTURECAPS_ALPHA | + WINED3DPTEXTURECAPS_ALPHAPALETTE | + WINED3DPTEXTURECAPS_BORDER | + WINED3DPTEXTURECAPS_MIPMAP | + WINED3DPTEXTURECAPS_PROJECTED | + WINED3DPTEXTURECAPS_PERSPECTIVE | + WINED3DPTEXTURECAPS_NONPOW2CONDITIONAL; + + if( GL_SUPPORT(EXT_TEXTURE3D)) { + *pCaps->TextureCaps |= WINED3DPTEXTURECAPS_VOLUMEMAP | + WINED3DPTEXTURECAPS_MIPVOLUMEMAP | + WINED3DPTEXTURECAPS_VOLUMEMAP_POW2; + } + + if (GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + *pCaps->TextureCaps |= WINED3DPTEXTURECAPS_CUBEMAP | + WINED3DPTEXTURECAPS_MIPCUBEMAP | + WINED3DPTEXTURECAPS_CUBEMAP_POW2; + + } + + *pCaps->TextureFilterCaps = WINED3DPTFILTERCAPS_MAGFLINEAR | + WINED3DPTFILTERCAPS_MAGFPOINT | + WINED3DPTFILTERCAPS_MINFLINEAR | + WINED3DPTFILTERCAPS_MINFPOINT | + WINED3DPTFILTERCAPS_MIPFLINEAR | + WINED3DPTFILTERCAPS_MIPFPOINT | + WINED3DPTFILTERCAPS_LINEAR | + WINED3DPTFILTERCAPS_LINEARMIPLINEAR | + WINED3DPTFILTERCAPS_LINEARMIPNEAREST | + WINED3DPTFILTERCAPS_MIPLINEAR | + WINED3DPTFILTERCAPS_MIPNEAREST | + WINED3DPTFILTERCAPS_NEAREST; + + if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { + *pCaps->TextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFANISOTROPIC | + WINED3DPTFILTERCAPS_MINFANISOTROPIC; + } + + if (GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + *pCaps->CubeTextureFilterCaps = WINED3DPTFILTERCAPS_MAGFLINEAR | + WINED3DPTFILTERCAPS_MAGFPOINT | + WINED3DPTFILTERCAPS_MINFLINEAR | + WINED3DPTFILTERCAPS_MINFPOINT | + WINED3DPTFILTERCAPS_MIPFLINEAR | + WINED3DPTFILTERCAPS_MIPFPOINT | + WINED3DPTFILTERCAPS_LINEAR | + WINED3DPTFILTERCAPS_LINEARMIPLINEAR | + WINED3DPTFILTERCAPS_LINEARMIPNEAREST | + WINED3DPTFILTERCAPS_MIPLINEAR | + WINED3DPTFILTERCAPS_MIPNEAREST | + WINED3DPTFILTERCAPS_NEAREST; + + if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { + *pCaps->CubeTextureFilterCaps |= WINED3DPTFILTERCAPS_MAGFANISOTROPIC | + WINED3DPTFILTERCAPS_MINFANISOTROPIC; + } + } else + *pCaps->CubeTextureFilterCaps = 0; + + if (GL_SUPPORT(EXT_TEXTURE3D)) { + *pCaps->VolumeTextureFilterCaps = WINED3DPTFILTERCAPS_MAGFLINEAR | + WINED3DPTFILTERCAPS_MAGFPOINT | + WINED3DPTFILTERCAPS_MINFLINEAR | + WINED3DPTFILTERCAPS_MINFPOINT | + WINED3DPTFILTERCAPS_MIPFLINEAR | + WINED3DPTFILTERCAPS_MIPFPOINT | + WINED3DPTFILTERCAPS_LINEAR | + WINED3DPTFILTERCAPS_LINEARMIPLINEAR | + WINED3DPTFILTERCAPS_LINEARMIPNEAREST | + WINED3DPTFILTERCAPS_MIPLINEAR | + WINED3DPTFILTERCAPS_MIPNEAREST | + WINED3DPTFILTERCAPS_NEAREST; + } else + *pCaps->VolumeTextureFilterCaps = 0; + + *pCaps->TextureAddressCaps = WINED3DPTADDRESSCAPS_INDEPENDENTUV | + WINED3DPTADDRESSCAPS_CLAMP | + WINED3DPTADDRESSCAPS_WRAP; + + if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) { + *pCaps->TextureAddressCaps |= WINED3DPTADDRESSCAPS_BORDER; + } + if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) { + *pCaps->TextureAddressCaps |= WINED3DPTADDRESSCAPS_MIRROR; + } + if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) { + *pCaps->TextureAddressCaps |= WINED3DPTADDRESSCAPS_MIRRORONCE; + } + + if (GL_SUPPORT(EXT_TEXTURE3D)) { + *pCaps->VolumeTextureAddressCaps = WINED3DPTADDRESSCAPS_INDEPENDENTUV | + WINED3DPTADDRESSCAPS_CLAMP | + WINED3DPTADDRESSCAPS_WRAP; + if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) { + *pCaps->VolumeTextureAddressCaps |= WINED3DPTADDRESSCAPS_BORDER; + } + if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) { + *pCaps->VolumeTextureAddressCaps |= WINED3DPTADDRESSCAPS_MIRROR; + } + if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) { + *pCaps->VolumeTextureAddressCaps |= WINED3DPTADDRESSCAPS_MIRRORONCE; + } + } else + *pCaps->VolumeTextureAddressCaps = 0; + + *pCaps->LineCaps = WINED3DLINECAPS_TEXTURE | + WINED3DLINECAPS_ZTEST; + /* FIXME: Add + WINED3DLINECAPS_BLEND + WINED3DLINECAPS_ALPHACMP + WINED3DLINECAPS_FOG */ + + *pCaps->MaxTextureWidth = GL_LIMITS(texture_size); + *pCaps->MaxTextureHeight = GL_LIMITS(texture_size); + + if(GL_SUPPORT(EXT_TEXTURE3D)) + *pCaps->MaxVolumeExtent = GL_LIMITS(texture3d_size); + else + *pCaps->MaxVolumeExtent = 0; + + *pCaps->MaxTextureRepeat = 32768; + *pCaps->MaxTextureAspectRatio = GL_LIMITS(texture_size); + *pCaps->MaxVertexW = 1.0; + + *pCaps->GuardBandLeft = 0; + *pCaps->GuardBandTop = 0; + *pCaps->GuardBandRight = 0; + *pCaps->GuardBandBottom = 0; + + *pCaps->ExtentsAdjust = 0; + + *pCaps->StencilCaps = WINED3DSTENCILCAPS_DECRSAT | + WINED3DSTENCILCAPS_INCRSAT | + WINED3DSTENCILCAPS_INVERT | + WINED3DSTENCILCAPS_KEEP | + WINED3DSTENCILCAPS_REPLACE | + WINED3DSTENCILCAPS_ZERO; + if (GL_SUPPORT(EXT_STENCIL_WRAP)) { + *pCaps->StencilCaps |= WINED3DSTENCILCAPS_DECR | + WINED3DSTENCILCAPS_INCR; + } + if ( This->dxVersion > 8 && + ( GL_SUPPORT(EXT_STENCIL_TWO_SIDE) || + GL_SUPPORT(ATI_SEPARATE_STENCIL) ) ) { + *pCaps->StencilCaps |= WINED3DSTENCILCAPS_TWOSIDED; + } + + *pCaps->FVFCaps = WINED3DFVFCAPS_PSIZE | 0x0008; /* 8 texture coords */ + + *pCaps->TextureOpCaps = WINED3DTEXOPCAPS_ADD | + WINED3DTEXOPCAPS_ADDSIGNED | + WINED3DTEXOPCAPS_ADDSIGNED2X | + WINED3DTEXOPCAPS_MODULATE | + WINED3DTEXOPCAPS_MODULATE2X | + WINED3DTEXOPCAPS_MODULATE4X | + WINED3DTEXOPCAPS_SELECTARG1 | + WINED3DTEXOPCAPS_SELECTARG2 | + WINED3DTEXOPCAPS_DISABLE; + + if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE) || + GL_SUPPORT(EXT_TEXTURE_ENV_COMBINE) || + GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA | + WINED3DTEXOPCAPS_BLENDTEXTUREALPHA | + WINED3DTEXOPCAPS_BLENDFACTORALPHA | + WINED3DTEXOPCAPS_BLENDCURRENTALPHA | + WINED3DTEXOPCAPS_LERP | + WINED3DTEXOPCAPS_SUBTRACT; + } + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3) || + GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_ADDSMOOTH | + WINED3DTEXOPCAPS_MULTIPLYADD | + WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | + WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA | + WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM; + } + if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3)) + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_DOTPRODUCT3; + + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | + WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA; + } + + if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP; + } else if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + /* Bump mapping is supported already in NV_TEXTURE_SHADER, but that extension does + * not support 3D textures. This asks for trouble if an app uses both bump mapping + * and 3D textures. It also allows us to keep the code simpler by having texture + * shaders constantly enabled. + */ + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP; + /* TODO: Luminance bump map? */ + } +#if 0 + /* FIXME: Add + *pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE + WINED3DTEXOPCAPS_PREMODULATE */ +#endif + + *pCaps->MaxTextureBlendStages = GL_LIMITS(texture_stages); + *pCaps->MaxSimultaneousTextures = GL_LIMITS(textures); + *pCaps->MaxUserClipPlanes = GL_LIMITS(clipplanes); + *pCaps->MaxActiveLights = GL_LIMITS(lights); + + *pCaps->MaxVertexBlendMatrices = GL_LIMITS(blends); + *pCaps->MaxVertexBlendMatrixIndex = 0; + + *pCaps->MaxAnisotropy = GL_LIMITS(anisotropy); + *pCaps->MaxPointSize = GL_LIMITS(pointsize); + + + *pCaps->VertexProcessingCaps = WINED3DVTXPCAPS_DIRECTIONALLIGHTS | + WINED3DVTXPCAPS_MATERIALSOURCE7 | + WINED3DVTXPCAPS_POSITIONALLIGHTS | + WINED3DVTXPCAPS_LOCALVIEWER | + WINED3DVTXPCAPS_VERTEXFOG | + WINED3DVTXPCAPS_TEXGEN; + /* FIXME: Add + D3DVTXPCAPS_TWEENING, D3DVTXPCAPS_TEXGEN_SPHEREMAP */ + + *pCaps->MaxPrimitiveCount = 0xFFFFF; /* For now set 2^20-1 which is used by most >=Geforce3/Radeon8500 cards */ + *pCaps->MaxVertexIndex = 0xFFFFF; + *pCaps->MaxStreams = MAX_STREAMS; + *pCaps->MaxStreamStride = 1024; + + if (vs_selected_mode == SHADER_GLSL) { + /* Nvidia Geforce6/7 or Ati R4xx/R5xx cards with GLSL support, support VS 3.0 but older Nvidia/Ati + models with GLSL support only support 2.0. In case of nvidia we can detect VS 2.0 support using + vs_nv_version which is based on NV_vertex_program. For Ati cards there's no easy way, so for + now only support 2.0/3.0 detection on Nvidia GeforceFX cards and default to 3.0 for everything else */ + if(GLINFO_LOCATION.vs_nv_version == VS_VERSION_20) + *pCaps->VertexShaderVersion = WINED3DVS_VERSION(2,0); + else + *pCaps->VertexShaderVersion = WINED3DVS_VERSION(3,0); + TRACE_(d3d_caps)("Hardware vertex shader version 3.0 enabled (GLSL)\n"); + } else if (vs_selected_mode == SHADER_ARB) { + *pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1); + TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); + } else { + *pCaps->VertexShaderVersion = 0; + TRACE_(d3d_caps)("Vertex shader functionality not available\n"); + } + + *pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF); + + if (ps_selected_mode == SHADER_GLSL) { + /* See the comment about VS2.0/VS3.0 detection as we do the same here but then based on NV_fragment_program + in case of GeforceFX cards. */ + if(GLINFO_LOCATION.ps_nv_version == PS_VERSION_20) + *pCaps->PixelShaderVersion = WINED3DPS_VERSION(2,0); + else + *pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0); + /* FIXME: The following line is card dependent. -1.0 to 1.0 is a safe default clamp range for now */ + *pCaps->PixelShader1xMaxValue = 1.0; + TRACE_(d3d_caps)("Hardware pixel shader version 3.0 enabled (GLSL)\n"); + } else if (ps_selected_mode == SHADER_ARB) { + *pCaps->PixelShaderVersion = WINED3DPS_VERSION(1,4); + *pCaps->PixelShader1xMaxValue = 1.0; + TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); + } else { + *pCaps->PixelShaderVersion = 0; + *pCaps->PixelShader1xMaxValue = 0.0; + TRACE_(d3d_caps)("Pixel shader functionality not available\n"); + } + + /* ------------------------------------------------ + The following fields apply to d3d9 only + ------------------------------------------------ */ + if (This->dxVersion > 8) { + /* d3d9.dll sets D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES here because StretchRects is implemented in d3d9 */ + *pCaps->DevCaps2 = WINED3DDEVCAPS2_STREAMOFFSET; + /* TODO: VS3.0 needs at least D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET */ + *pCaps->MaxNpatchTessellationLevel = 0; + *pCaps->MasterAdapterOrdinal = 0; + *pCaps->AdapterOrdinalInGroup = 0; + *pCaps->NumberOfAdaptersInGroup = 1; + + if(*pCaps->VertexShaderVersion >= WINED3DVS_VERSION(2,0)) { + /* OpenGL supports all the formats below, perhaps not always + * without conversion, but it supports them. + * Further GLSL doesn't seem to have an official unsigned type so + * don't advertise it yet as I'm not sure how we handle it. + * We might need to add some clamping in the shader engine to + * support it. + * TODO: WINED3DDTCAPS_USHORT2N, WINED3DDTCAPS_USHORT4N, WINED3DDTCAPS_UDEC3, WINED3DDTCAPS_DEC3N */ + *pCaps->DeclTypes = WINED3DDTCAPS_UBYTE4 | + WINED3DDTCAPS_UBYTE4N | + WINED3DDTCAPS_SHORT2N | + WINED3DDTCAPS_SHORT4N; + if (GL_SUPPORT(NV_HALF_FLOAT)) { + *pCaps->DeclTypes |= + WINED3DDTCAPS_FLOAT16_2 | + WINED3DDTCAPS_FLOAT16_4; + } + } else + *pCaps->DeclTypes = 0; + + *pCaps->NumSimultaneousRTs = GL_LIMITS(buffers); + + + *pCaps->StretchRectFilterCaps = WINED3DPTFILTERCAPS_MINFPOINT | + WINED3DPTFILTERCAPS_MAGFPOINT | + WINED3DPTFILTERCAPS_MINFLINEAR | + WINED3DPTFILTERCAPS_MAGFLINEAR; + *pCaps->VertexTextureFilterCaps = 0; + + if(*pCaps->VertexShaderVersion == WINED3DVS_VERSION(3,0)) { + /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering) + use the VS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum VS3.0 value. */ + *pCaps->VS20Caps.Caps = WINED3DVS20CAPS_PREDICATION; + *pCaps->VS20Caps.DynamicFlowControlDepth = WINED3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* VS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */ + *pCaps->VS20Caps.NumTemps = max(32, GLINFO_LOCATION.vs_arb_max_temps); + *pCaps->VS20Caps.StaticFlowControlDepth = WINED3DVS20_MAX_STATICFLOWCONTROLDEPTH ; /* level of nesting in loops / if-statements; VS 3.0 requires MAX (4) */ + + *pCaps->MaxVShaderInstructionsExecuted = 65535; /* VS 3.0 needs at least 65535, some cards even use 2^32-1 */ + *pCaps->MaxVertexShader30InstructionSlots = max(512, GLINFO_LOCATION.vs_arb_max_instructions); + } else if(*pCaps->VertexShaderVersion == WINED3DVS_VERSION(2,0)) { + *pCaps->VS20Caps.Caps = 0; + *pCaps->VS20Caps.DynamicFlowControlDepth = WINED3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH; + *pCaps->VS20Caps.NumTemps = max(12, GLINFO_LOCATION.vs_arb_max_temps); + *pCaps->VS20Caps.StaticFlowControlDepth = 1; + + *pCaps->MaxVShaderInstructionsExecuted = 65535; + *pCaps->MaxVertexShader30InstructionSlots = 0; + } else { /* VS 1.x */ + *pCaps->VS20Caps.Caps = 0; + *pCaps->VS20Caps.DynamicFlowControlDepth = 0; + *pCaps->VS20Caps.NumTemps = 0; + *pCaps->VS20Caps.StaticFlowControlDepth = 0; + + *pCaps->MaxVShaderInstructionsExecuted = 0; + *pCaps->MaxVertexShader30InstructionSlots = 0; + } + + if(*pCaps->PixelShaderVersion == WINED3DPS_VERSION(3,0)) { + /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering) + use the PS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum PS 3.0 value. */ + + /* Caps is more or less undocumented on MSDN but it appears to be used for PS20Caps based on results from R9600/FX5900/Geforce6800 cards from Windows */ + *pCaps->PS20Caps.Caps = WINED3DPS20CAPS_ARBITRARYSWIZZLE | + WINED3DPS20CAPS_GRADIENTINSTRUCTIONS | + WINED3DPS20CAPS_PREDICATION | + WINED3DPS20CAPS_NODEPENDENTREADLIMIT | + WINED3DPS20CAPS_NOTEXINSTRUCTIONLIMIT; + *pCaps->PS20Caps.DynamicFlowControlDepth = WINED3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */ + *pCaps->PS20Caps.NumTemps = max(32, GLINFO_LOCATION.ps_arb_max_temps); + *pCaps->PS20Caps.StaticFlowControlDepth = WINED3DPS20_MAX_STATICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_STATICFLOWCONTROLDEPTH (4) */ + *pCaps->PS20Caps.NumInstructionSlots = WINED3DPS20_MAX_NUMINSTRUCTIONSLOTS; /* PS 3.0 requires MAX_NUMINSTRUCTIONSLOTS (512) */ + + *pCaps->MaxPShaderInstructionsExecuted = 65535; + *pCaps->MaxPixelShader30InstructionSlots = max(WINED3DMIN30SHADERINSTRUCTIONS, GLINFO_LOCATION.ps_arb_max_instructions); + } else if(*pCaps->PixelShaderVersion == WINED3DPS_VERSION(2,0)) { + /* Below we assume PS2.0 specs, not extended 2.0a(GeforceFX)/2.0b(Radeon R3xx) ones */ + *pCaps->PS20Caps.Caps = 0; + *pCaps->PS20Caps.DynamicFlowControlDepth = 0; /* WINED3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH = 0 */ + *pCaps->PS20Caps.NumTemps = max(12, GLINFO_LOCATION.ps_arb_max_temps); + *pCaps->PS20Caps.StaticFlowControlDepth = WINED3DPS20_MIN_STATICFLOWCONTROLDEPTH; /* Minumum: 1 */ + *pCaps->PS20Caps.NumInstructionSlots = WINED3DPS20_MIN_NUMINSTRUCTIONSLOTS; /* Minimum number (64 ALU + 32 Texture), a GeforceFX uses 512 */ + + *pCaps->MaxPShaderInstructionsExecuted = 512; /* Minimum value, a GeforceFX uses 1024 */ + *pCaps->MaxPixelShader30InstructionSlots = 0; + } else { /* PS 1.x */ + *pCaps->PS20Caps.Caps = 0; + *pCaps->PS20Caps.DynamicFlowControlDepth = 0; + *pCaps->PS20Caps.NumTemps = 0; + *pCaps->PS20Caps.StaticFlowControlDepth = 0; + *pCaps->PS20Caps.NumInstructionSlots = 0; + + *pCaps->MaxPShaderInstructionsExecuted = 0; + *pCaps->MaxPixelShader30InstructionSlots = 0; + } + } + + return WINED3D_OK; +} + +static unsigned int glsl_program_key_hash(void *key) { + glsl_program_key_t *k = (glsl_program_key_t *)key; + + unsigned int hash = k->vshader | k->pshader << 16; + hash += ~(hash << 15); + hash ^= (hash >> 10); + hash += (hash << 3); + hash ^= (hash >> 6); + hash += ~(hash << 11); + hash ^= (hash >> 16); + + return hash; +} + +static BOOL glsl_program_key_compare(void *keya, void *keyb) { + glsl_program_key_t *ka = (glsl_program_key_t *)keya; + glsl_program_key_t *kb = (glsl_program_key_t *)keyb; + + return ka->vshader == kb->vshader && ka->pshader == kb->pshader; +} + +/* Note due to structure differences between dx8 and dx9 D3DPRESENT_PARAMETERS, + and fields being inserted in the middle, a new structure is used in place */ +static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, WINED3DDEVTYPE DeviceType, HWND hFocusWindow, + DWORD BehaviourFlags, IWineD3DDevice** ppReturnedDeviceInterface, + IUnknown *parent) { + + IWineD3DDeviceImpl *object = NULL; + IWineD3DImpl *This = (IWineD3DImpl *)iface; + HDC hDC; + int i; + + /* Validate the adapter number. If no adapters are available(no GL), ignore the adapter + * number and create a device without a 3D adapter for 2D only operation. + */ + if (IWineD3D_GetAdapterCount(iface) && Adapter >= IWineD3D_GetAdapterCount(iface)) { + return WINED3DERR_INVALIDCALL; + } + + /* Create a WineD3DDevice object */ + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DDeviceImpl)); + *ppReturnedDeviceInterface = (IWineD3DDevice *)object; + TRACE("Created WineD3DDevice object @ %p\n", object); + if (NULL == object) { + return WINED3DERR_OUTOFVIDEOMEMORY; + } + + /* Set up initial COM information */ + object->lpVtbl = &IWineD3DDevice_Vtbl; + object->ref = 1; + object->wineD3D = iface; + object->adapter = numAdapters ? &Adapters[Adapter] : NULL; + IWineD3D_AddRef(object->wineD3D); + object->parent = parent; + + if(This->dxVersion == 7) { + object->surface_alignment = 8; + } else { + object->surface_alignment = 4; + } + + /* Set the state up as invalid until the device is fully created */ + object->state = WINED3DERR_DRIVERINTERNALERROR; + + TRACE("(%p)->(Adptr:%d, DevType: %x, FocusHwnd: %p, BehFlags: %x, RetDevInt: %p)\n", This, Adapter, DeviceType, + hFocusWindow, BehaviourFlags, ppReturnedDeviceInterface); + + /* Save the creation parameters */ + object->createParms.AdapterOrdinal = Adapter; + object->createParms.DeviceType = DeviceType; + object->createParms.hFocusWindow = hFocusWindow; + object->createParms.BehaviorFlags = BehaviourFlags; + + /* Initialize other useful values */ + object->adapterNo = Adapter; + object->devType = DeviceType; + + select_shader_mode(&GLINFO_LOCATION, DeviceType, &object->ps_selected_mode, &object->vs_selected_mode); + if (object->ps_selected_mode == SHADER_GLSL || object->vs_selected_mode == SHADER_GLSL) { + object->shader_backend = &glsl_shader_backend; + object->glsl_program_lookup = hash_table_create(&glsl_program_key_hash, &glsl_program_key_compare); + } else if (object->ps_selected_mode == SHADER_ARB || object->vs_selected_mode == SHADER_ARB) { + object->shader_backend = &arb_program_shader_backend; + } else { + object->shader_backend = &none_shader_backend; + } + + /* set the state of the device to valid */ + object->state = WINED3D_OK; + + /* Get the initial screen setup for ddraw */ + object->ddraw_width = GetSystemMetrics(SM_CXSCREEN); + object->ddraw_height = GetSystemMetrics(SM_CYSCREEN); + hDC = GetDC(0); + object->ddraw_format = pixelformat_for_depth(GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)); + ReleaseDC(0, hDC); + + for(i = 0; i < PATCHMAP_SIZE; i++) { + list_init(&object->patches[i]); + } + return WINED3D_OK; +} +#undef GLINFO_LOCATION + +static HRESULT WINAPI IWineD3DImpl_GetParent(IWineD3D *iface, IUnknown **pParent) { + IWineD3DImpl *This = (IWineD3DImpl *)iface; + IUnknown_AddRef(This->parent); + *pParent = This->parent; + return WINED3D_OK; +} + +ULONG WINAPI D3DCB_DefaultDestroySurface(IWineD3DSurface *pSurface) { + IUnknown* surfaceParent; + TRACE("(%p) call back\n", pSurface); + + /* Now, release the parent, which will take care of cleaning up the surface for us */ + IWineD3DSurface_GetParent(pSurface, &surfaceParent); + IUnknown_Release(surfaceParent); + return IUnknown_Release(surfaceParent); +} + +ULONG WINAPI D3DCB_DefaultDestroyVolume(IWineD3DVolume *pVolume) { + IUnknown* volumeParent; + TRACE("(%p) call back\n", pVolume); + + /* Now, release the parent, which will take care of cleaning up the volume for us */ + IWineD3DVolume_GetParent(pVolume, &volumeParent); + IUnknown_Release(volumeParent); + return IUnknown_Release(volumeParent); +} + +#define PUSH1(att) attribs[nAttribs++] = (att); +#define GLINFO_LOCATION (Adapters[0].gl_info) +BOOL InitAdapters(void) { + BOOL ret; + int ps_selected_mode, vs_selected_mode; + + /* No need to hold any lock. The calling library makes sure only one thread calls + * wined3d simultaneously + */ + if(numAdapters > 0) return TRUE; + + TRACE("Initializing adapters\n"); + /* For now only one default adapter */ + { + int attribute; + DISPLAY_DEVICEW DisplayDevice; + + TRACE("Initializing default adapter\n"); + Adapters[0].monitorPoint.x = -1; + Adapters[0].monitorPoint.y = -1; + + ret = IWineD3DImpl_FillGLCaps(&Adapters[0].gl_info); + if(!ret) { + ERR("Failed to initialize gl caps for default adapter\n"); + HeapFree(GetProcessHeap(), 0, Adapters); + return FALSE; + } + ret = initPixelFormats(&Adapters[0].gl_info); + if(!ret) { + ERR("Failed to init gl formats\n"); + HeapFree(GetProcessHeap(), 0, Adapters); + return FALSE; + } + + Adapters[0].driver = "Display"; + Adapters[0].description = "Direct3D HAL"; + + /* Initialize the Adapter's DeviceName which is required for ChangeDisplaySettings and friends */ + DisplayDevice.cb = sizeof(DisplayDevice); + EnumDisplayDevicesW(NULL, 0 /* Adapter 0 = iDevNum 0 */, &DisplayDevice, 0); + TRACE("DeviceName: %s\n", debugstr_w(DisplayDevice.DeviceName)); + strcpyW(Adapters[0].DeviceName, DisplayDevice.DeviceName); + + if (WineD3D_CreateFakeGLContext()) { + int iPixelFormat; + int attribs[8]; + int values[8]; + int nAttribs = 0; + int res; + WineD3D_PixelFormat *cfgs; + + attribute = WGL_NUMBER_PIXEL_FORMATS_ARB; + GL_EXTCALL(wglGetPixelFormatAttribivARB(wined3d_fake_gl_context_hdc, 0, 0, 1, &attribute, &Adapters[0].nCfgs)); + + Adapters[0].cfgs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Adapters[0].nCfgs *sizeof(WineD3D_PixelFormat)); + cfgs = Adapters[0].cfgs; + PUSH1(WGL_RED_BITS_ARB) + PUSH1(WGL_GREEN_BITS_ARB) + PUSH1(WGL_BLUE_BITS_ARB) + PUSH1(WGL_ALPHA_BITS_ARB) + PUSH1(WGL_DEPTH_BITS_ARB) + PUSH1(WGL_STENCIL_BITS_ARB) + + for(iPixelFormat=1; iPixelFormat<=Adapters[0].nCfgs; iPixelFormat++) { + res = GL_EXTCALL(wglGetPixelFormatAttribivARB(wined3d_fake_gl_context_hdc, iPixelFormat, 0, nAttribs, attribs, values)); + + if(!res) + continue; + + /* Cache the pixel format */ + cfgs->iPixelFormat = iPixelFormat; + cfgs->redSize = values[0]; + cfgs->greenSize = values[1]; + cfgs->blueSize = values[2]; + cfgs->alphaSize = values[3]; + cfgs->depthSize = values[4]; + cfgs->stencilSize = values[5]; + + TRACE("iPixelFormat=%d, RGBA=%d/%d/%d/%d, depth=%d, stencil=%d\n", cfgs->iPixelFormat, cfgs->redSize, cfgs->greenSize, cfgs->blueSize, cfgs->alphaSize, cfgs->depthSize, cfgs->stencilSize); + cfgs++; + } + WineD3D_ReleaseFakeGLContext(); + } + + select_shader_mode(&Adapters[0].gl_info, WINED3DDEVTYPE_HAL, &ps_selected_mode, &vs_selected_mode); + select_shader_max_constants(ps_selected_mode, vs_selected_mode, &Adapters[0].gl_info); + + } + numAdapters = 1; + TRACE("%d adapters successfully initialized\n", numAdapters); + + return TRUE; +} +#undef PUSH1 +#undef GLINFO_LOCATION + +/********************************************************** + * IWineD3D VTbl follows + **********************************************************/ + +const IWineD3DVtbl IWineD3D_Vtbl = +{ + /* IUnknown */ + IWineD3DImpl_QueryInterface, + IWineD3DImpl_AddRef, + IWineD3DImpl_Release, + /* IWineD3D */ + IWineD3DImpl_GetParent, + IWineD3DImpl_GetAdapterCount, + IWineD3DImpl_RegisterSoftwareDevice, + IWineD3DImpl_GetAdapterMonitor, + IWineD3DImpl_GetAdapterModeCount, + IWineD3DImpl_EnumAdapterModes, + IWineD3DImpl_GetAdapterDisplayMode, + IWineD3DImpl_GetAdapterIdentifier, + IWineD3DImpl_CheckDeviceMultiSampleType, + IWineD3DImpl_CheckDepthStencilMatch, + IWineD3DImpl_CheckDeviceType, + IWineD3DImpl_CheckDeviceFormat, + IWineD3DImpl_CheckDeviceFormatConversion, + IWineD3DImpl_GetDeviceCaps, + IWineD3DImpl_CreateDevice +}; diff --git a/reactos/dll/directx/wine/wined3d/drawprim.c b/reactos/dll/directx/wine/wined3d/drawprim.c new file mode 100644 index 00000000000..e6766a24b4b --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/drawprim.c @@ -0,0 +1,1535 @@ +/* + * WINED3D draw functions + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2002-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Henri Verbeet + * Copyright 2007 Stefan Dösinger for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw); +#define GLINFO_LOCATION This->adapter->gl_info + +#include + +#if 0 /* TODO */ +extern IWineD3DVertexShaderImpl* VertexShaders[64]; +extern IWineD3DVertexDeclarationImpl* VertexShaderDeclarations[64]; +extern IWineD3DPixelShaderImpl* PixelShaders[64]; + +#undef GL_VERSION_1_4 /* To be fixed, caused by mesa headers */ +#endif + +/* Issues the glBegin call for gl given the primitive type and count */ +static DWORD primitiveToGl(WINED3DPRIMITIVETYPE PrimitiveType, + DWORD NumPrimitives, + GLenum *primType) +{ + DWORD NumVertexes = NumPrimitives; + + switch (PrimitiveType) { + case WINED3DPT_POINTLIST: + TRACE("POINTS\n"); + *primType = GL_POINTS; + NumVertexes = NumPrimitives; + break; + + case WINED3DPT_LINELIST: + TRACE("LINES\n"); + *primType = GL_LINES; + NumVertexes = NumPrimitives * 2; + break; + + case WINED3DPT_LINESTRIP: + TRACE("LINE_STRIP\n"); + *primType = GL_LINE_STRIP; + NumVertexes = NumPrimitives + 1; + break; + + case WINED3DPT_TRIANGLELIST: + TRACE("TRIANGLES\n"); + *primType = GL_TRIANGLES; + NumVertexes = NumPrimitives * 3; + break; + + case WINED3DPT_TRIANGLESTRIP: + TRACE("TRIANGLE_STRIP\n"); + *primType = GL_TRIANGLE_STRIP; + NumVertexes = NumPrimitives + 2; + break; + + case WINED3DPT_TRIANGLEFAN: + TRACE("TRIANGLE_FAN\n"); + *primType = GL_TRIANGLE_FAN; + NumVertexes = NumPrimitives + 2; + break; + + default: + FIXME("Unhandled primitive\n"); + *primType = GL_POINTS; + break; + } + return NumVertexes; +} + +static BOOL fixed_get_input( + BYTE usage, BYTE usage_idx, + unsigned int* regnum) { + + *regnum = -1; + + /* Those positions must have the order in the + * named part of the strided data */ + + if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0) + *regnum = 0; + else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0) + *regnum = 1; + else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0) + *regnum = 2; + else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0) + *regnum = 3; + else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0) + *regnum = 4; + else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0) + *regnum = 5; + else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1) + *regnum = 6; + else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD) + *regnum = 7 + usage_idx; + else if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 1) + *regnum = 7 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 1) + *regnum = 8 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_TANGENT && usage_idx == 0) + *regnum = 9 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_BINORMAL && usage_idx == 0) + *regnum = 10 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_TESSFACTOR && usage_idx == 0) + *regnum = 11 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_FOG && usage_idx == 0) + *regnum = 12 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_DEPTH && usage_idx == 0) + *regnum = 13 + WINED3DDP_MAXTEXCOORD; + else if (usage == WINED3DDECLUSAGE_SAMPLE && usage_idx == 0) + *regnum = 14 + WINED3DDP_MAXTEXCOORD; + + if (*regnum < 0) { + FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", + debug_d3ddeclusage(usage), usage_idx); + return FALSE; + } + return TRUE; +} + +void primitiveDeclarationConvertToStridedData( + IWineD3DDevice *iface, + BOOL useVertexShaderFunction, + WineDirect3DVertexStridedData *strided, + BOOL *fixup) { + + /* We need to deal with frequency data!*/ + + BYTE *data = NULL; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DVertexDeclarationImpl* vertexDeclaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl; + int i; + WINED3DVERTEXELEMENT *element; + DWORD stride; + int reg; + DWORD numPreloadStreams = This->stateBlock->streamIsUP ? 0 : vertexDeclaration->num_streams; + DWORD *streams = vertexDeclaration->streams; + + /* Check for transformed vertices, disable vertex shader if present */ + strided->u.s.position_transformed = vertexDeclaration->position_transformed; + if(vertexDeclaration->position_transformed) { + useVertexShaderFunction = FALSE; + } + + /* Translate the declaration into strided data */ + for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) { + GLint streamVBO = 0; + BOOL stride_used; + unsigned int idx; + + element = vertexDeclaration->pDeclarationWine + i; + TRACE("%p Element %p (%d of %d)\n", vertexDeclaration->pDeclarationWine, + element, i + 1, vertexDeclaration->declarationWNumElements - 1); + + if (This->stateBlock->streamSource[element->Stream] == NULL) + continue; + + if (This->stateBlock->streamIsUP) { + TRACE("Stream is up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]); + streamVBO = 0; + data = (BYTE *)This->stateBlock->streamSource[element->Stream]; + } else { + TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]); + data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO); + if(fixup) { + if( streamVBO != 0) *fixup = TRUE; + else if(*fixup && !useVertexShaderFunction && + (element->Usage == WINED3DDECLUSAGE_COLOR || + element->Usage == WINED3DDECLUSAGE_POSITIONT)) { + /* This may be bad with the fixed function pipeline */ + FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n"); + } + } + } + stride = This->stateBlock->streamStride[element->Stream]; + data += element->Offset; + reg = element->Reg; + + TRACE("Offset %d Stream %d UsageIndex %d\n", element->Offset, element->Stream, element->UsageIndex); + + if (useVertexShaderFunction) + stride_used = vshader_get_input(This->stateBlock->vertexShader, + element->Usage, element->UsageIndex, &idx); + else + stride_used = fixed_get_input(element->Usage, element->UsageIndex, &idx); + + if (stride_used) { + TRACE("Loaded %s array %u [usage=%s, usage_idx=%u, " + "stream=%u, offset=%u, stride=%u, type=%s, VBO=%u]\n", + useVertexShaderFunction? "shader": "fixed function", idx, + debug_d3ddeclusage(element->Usage), element->UsageIndex, + element->Stream, element->Offset, stride, debug_d3ddecltype(element->Type), streamVBO); + + strided->u.input[idx].lpData = data; + strided->u.input[idx].dwType = element->Type; + strided->u.input[idx].dwStride = stride; + strided->u.input[idx].VBO = streamVBO; + strided->u.input[idx].streamNo = element->Stream; + } + } + /* Now call PreLoad on all the vertex buffers. In the very rare case + * that the buffers stopps converting PreLoad will dirtify the VDECL again. + * The vertex buffer can now use the strided structure in the device instead of finding its + * own again. + * + * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only + * once in there. + */ + for(i=0; i < numPreloadStreams; i++) { + IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[streams[i]]); + } +} + +static void drawStridedFast(IWineD3DDevice *iface,UINT numberOfVertices, GLenum glPrimitiveType, + const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + if (idxSize != 0 /* This crashes sometimes!*/) { + TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex); + idxData = idxData == (void *)-1 ? NULL : idxData; +#if 1 + glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, + (const char *)idxData+(idxSize * startIdx)); + checkGLcall("glDrawElements"); +#else /* using drawRangeElements may be faster */ + + glDrawRangeElements(glPrimitiveType, minIndex, minIndex + numberOfVertices - 1, numberOfVertices, + idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, + (const char *)idxData+(idxSize * startIdx)); + checkGLcall("glDrawRangeElements"); +#endif + + } else { + + /* Note first is now zero as we shuffled along earlier */ + TRACE("(%p) : glDrawArrays(%x, 0, %d)\n", This, glPrimitiveType, numberOfVertices); + glDrawArrays(glPrimitiveType, startVertex, numberOfVertices); + checkGLcall("glDrawArrays"); + + } + + return; +} + +/* + * Actually draw using the supplied information. + * Slower GL version which extracts info about each vertex in turn + */ + +static void drawStridedSlow(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd, + UINT NumVertexes, GLenum glPrimType, + const void *idxData, short idxSize, ULONG minIndex, ULONG startIdx, ULONG startVertex) { + + unsigned int textureNo = 0; + const WORD *pIdxBufS = NULL; + const DWORD *pIdxBufL = NULL; + LONG vx_index; + float x = 0.0f, y = 0.0f, z = 0.0f; /* x,y,z coordinates */ + float rhw = 0.0f; /* rhw */ + DWORD diffuseColor = 0xFFFFFFFF; /* Diffuse Color */ + DWORD specularColor = 0; /* Specular Color */ + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + UINT *streamOffset = This->stateBlock->streamOffset; + DWORD SkipnStrides = startVertex + This->stateBlock->loadBaseVertexIndex; + + BYTE *texCoords[WINED3DDP_MAXTEXCOORD]; + BYTE *diffuse = NULL, *specular = NULL, *normal = NULL, *position = NULL; + + TRACE("Using slow vertex array code\n"); + + /* Variable Initialization */ + if (idxSize != 0) { + /* Immediate mode drawing can't make use of indices in a vbo - get the data from the index buffer. + * If the index buffer has no vbo(not supported or other reason), or with user pointer drawing + * idxData will be != NULL + */ + if(idxData == NULL) { + idxData = ((IWineD3DIndexBufferImpl *) This->stateBlock->pIndexData)->resource.allocatedMemory; + } + + if (idxSize == 2) pIdxBufS = (const WORD *) idxData; + else pIdxBufL = (const DWORD *) idxData; + } + + /* Adding the stream offset once is cheaper than doing it every iteration. Do not modify the strided data, it is a pointer + * to the strided Data in the device and might be needed intact on the next draw + */ + for (textureNo = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) { + if(sd->u.s.texCoords[textureNo].lpData) { + texCoords[textureNo] = sd->u.s.texCoords[textureNo].lpData + streamOffset[sd->u.s.texCoords[textureNo].streamNo]; + } else { + texCoords[textureNo] = NULL; + } + } + if(sd->u.s.diffuse.lpData) { + diffuse = sd->u.s.diffuse.lpData + streamOffset[sd->u.s.diffuse.streamNo]; + } + if(sd->u.s.specular.lpData) { + specular = sd->u.s.specular.lpData + streamOffset[sd->u.s.specular.streamNo]; + } + if(sd->u.s.normal.lpData) { + normal = sd->u.s.normal.lpData + streamOffset[sd->u.s.normal.streamNo]; + } + if(sd->u.s.position.lpData) { + position = sd->u.s.position.lpData + streamOffset[sd->u.s.position.streamNo]; + } + + /* Start drawing in GL */ + VTRACE(("glBegin(%x)\n", glPrimType)); + glBegin(glPrimType); + + /* Default settings for data that is not passed */ + if (sd->u.s.normal.lpData == NULL) { + glNormal3f(0, 0, 1); + } + if(sd->u.s.diffuse.lpData == NULL) { + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + if(sd->u.s.specular.lpData == NULL) { + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0); + } + } + + /* We shouldn't start this function if any VBO is involved. Should I put a safety check here? + * Guess it's not necessary(we crash then anyway) and would only eat CPU time + */ + + /* For each primitive */ + for (vx_index = 0; vx_index < NumVertexes; ++vx_index) { + + /* Initialize diffuse color */ + diffuseColor = 0xFFFFFFFF; + + /* Blending data and Point sizes are not supported by this function. They are not supported by the fixed + * function pipeline at all. A Fixme for them is printed after decoding the vertex declaration + */ + + /* For indexed data, we need to go a few more strides in */ + if (idxData != NULL) { + + /* Indexed so work out the number of strides to skip */ + if (idxSize == 2) { + VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufS[startIdx+vx_index])); + SkipnStrides = pIdxBufS[startIdx + vx_index] + This->stateBlock->loadBaseVertexIndex; + } else { + VTRACE(("Idx for vertex %d = %d\n", vx_index, pIdxBufL[startIdx+vx_index])); + SkipnStrides = pIdxBufL[startIdx + vx_index] + This->stateBlock->loadBaseVertexIndex; + } + } + + /* Texture coords --------------------------- */ + for (textureNo = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) { + + if (!GL_SUPPORT(ARB_MULTITEXTURE) && textureNo > 0) { + FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + continue ; + } + + /* Query tex coords */ + if (This->stateBlock->textures[textureNo] != NULL) { + + int coordIdx = This->stateBlock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX]; + float *ptrToCoords = NULL; + float s = 0.0, t = 0.0, r = 0.0, q = 0.0; + + if (coordIdx > 7) { + VTRACE(("tex: %d - Skip tex coords, as being system generated\n", textureNo)); + continue; + } else if (coordIdx < 0) { + FIXME("tex: %d - Coord index %d is less than zero, expect a crash.\n", textureNo, coordIdx); + continue; + } + + ptrToCoords = (float *)(texCoords[coordIdx] + (SkipnStrides * sd->u.s.texCoords[coordIdx].dwStride)); + if (texCoords[coordIdx] == NULL) { + TRACE("tex: %d - Skipping tex coords, as no data supplied\n", textureNo); + continue; + } else { + int texture_idx = This->texUnitMap[textureNo]; + int coordsToUse = sd->u.s.texCoords[coordIdx].dwType + 1; /* 0 == WINED3DDECLTYPE_FLOAT1 etc */ + + if (texture_idx == -1) continue; + + /* The coords to supply depend completely on the fvf / vertex shader */ + switch (coordsToUse) { + case 4: q = ptrToCoords[3]; /* drop through */ + case 3: r = ptrToCoords[2]; /* drop through */ + case 2: t = ptrToCoords[1]; /* drop through */ + case 1: s = ptrToCoords[0]; + } + + /* Projected is more 'fun' - Move the last coord to the 'q' + parameter (see comments under WINED3DTSS_TEXTURETRANSFORMFLAGS */ + if ((This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] != WINED3DTTFF_DISABLE) && + (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) { + + if (This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED) { + switch (coordsToUse) { + case 0: /* Drop Through */ + case 1: + FIXME("WINED3DTTFF_PROJECTED but only zero or one coordinate?\n"); + break; + case 2: + q = t; + t = 0.0; + coordsToUse = 4; + break; + case 3: + q = r; + r = 0.0; + coordsToUse = 4; + break; + case 4: /* Nop here */ + break; + default: + FIXME("Unexpected WINED3DTSS_TEXTURETRANSFORMFLAGS value of %d\n", + This->stateBlock->textureState[textureNo][WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED); + } + } + } + + switch (coordsToUse) { /* Supply the provided texture coords */ + case WINED3DTTFF_COUNT1: + VTRACE(("tex:%d, s=%f\n", textureNo, s)); + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glMultiTexCoord1fARB(GL_TEXTURE0_ARB + texture_idx, s)); + } else { + glTexCoord1f(s); + } + break; + case WINED3DTTFF_COUNT2: + VTRACE(("tex:%d, s=%f, t=%f\n", textureNo, s, t)); + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glMultiTexCoord2fARB(GL_TEXTURE0_ARB + texture_idx, s, t)); + } else { + glTexCoord2f(s, t); + } + break; + case WINED3DTTFF_COUNT3: + VTRACE(("tex:%d, s=%f, t=%f, r=%f\n", textureNo, s, t, r)); + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glMultiTexCoord3fARB(GL_TEXTURE0_ARB + texture_idx, s, t, r)); + } else { + glTexCoord3f(s, t, r); + } + break; + case WINED3DTTFF_COUNT4: + VTRACE(("tex:%d, s=%f, t=%f, r=%f, q=%f\n", textureNo, s, t, r, q)); + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_idx, s, t, r, q)); + } else { + glTexCoord4f(s, t, r, q); + } + break; + default: + FIXME("Should not get here as coordsToUse is two bits only (%x)!\n", coordsToUse); + } + } + } + } /* End of textures */ + + /* Diffuse -------------------------------- */ + if (diffuse) { + DWORD *ptrToCoords = (DWORD *)(diffuse + (SkipnStrides * sd->u.s.diffuse.dwStride)); + diffuseColor = ptrToCoords[0]; + VTRACE(("diffuseColor=%lx\n", diffuseColor)); + + glColor4ub(D3DCOLOR_B_R(diffuseColor), + D3DCOLOR_B_G(diffuseColor), + D3DCOLOR_B_B(diffuseColor), + D3DCOLOR_B_A(diffuseColor)); + VTRACE(("glColor4ub: r,g,b,a=%lu,%lu,%lu,%lu\n", + D3DCOLOR_B_R(diffuseColor), + D3DCOLOR_B_G(diffuseColor), + D3DCOLOR_B_B(diffuseColor), + D3DCOLOR_B_A(diffuseColor))); + + if(This->activeContext->num_untracked_materials) { + unsigned char i; + float color[4]; + color[0] = D3DCOLOR_B_R(diffuseColor) / 255.0; + color[1] = D3DCOLOR_B_G(diffuseColor) / 255.0; + color[2] = D3DCOLOR_B_B(diffuseColor) / 255.0; + color[3] = D3DCOLOR_B_A(diffuseColor) / 255.0; + + for(i = 0; i < This->activeContext->num_untracked_materials; i++) { + glMaterialfv(GL_FRONT_AND_BACK, This->activeContext->untracked_materials[i], color); + } + } + } + + /* Specular ------------------------------- */ + if (specular) { + DWORD *ptrToCoords = (DWORD *)(specular + (SkipnStrides * sd->u.s.specular.dwStride)); + specularColor = ptrToCoords[0]; + VTRACE(("specularColor=%lx\n", specularColor)); + + /* special case where the fog density is stored in the specular alpha channel */ + if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && + (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == WINED3DFOG_NONE || sd->u.s.position.dwType == WINED3DDECLTYPE_FLOAT4 )&& + This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) { + if(GL_SUPPORT(EXT_FOG_COORD)) { + GL_EXTCALL(glFogCoordfEXT(specularColor >> 24)); + } else { + static BOOL warned = FALSE; + if(!warned) { + /* TODO: Use the fog table code from old ddraw */ + FIXME("Implement fog for transformed vertices in software\n"); + warned = TRUE; + } + } + } + + VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n", + D3DCOLOR_B_R(specularColor), + D3DCOLOR_B_G(specularColor), + D3DCOLOR_B_B(specularColor))); + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + GL_EXTCALL(glSecondaryColor3ubEXT)( + D3DCOLOR_B_R(specularColor), + D3DCOLOR_B_G(specularColor), + D3DCOLOR_B_B(specularColor)); + } else { + /* Do not worry if specular colour missing and disable request */ + VTRACE(("Specular color extensions not supplied\n")); + } + } + + /* Normal -------------------------------- */ + if (normal != NULL) { + float *ptrToCoords = (float *)(normal + (SkipnStrides * sd->u.s.normal.dwStride)); + + VTRACE(("glNormal:nx,ny,nz=%f,%f,%f\n", ptrToCoords[0], ptrToCoords[1], ptrToCoords[2])); + glNormal3f(ptrToCoords[0], ptrToCoords[1], ptrToCoords[2]); + } + + /* Position -------------------------------- */ + if (position) { + float *ptrToCoords = (float *)(position + (SkipnStrides * sd->u.s.position.dwStride)); + x = ptrToCoords[0]; + y = ptrToCoords[1]; + z = ptrToCoords[2]; + rhw = 1.0; + VTRACE(("x,y,z=%f,%f,%f\n", x,y,z)); + + /* RHW follows, only if transformed, ie 4 floats were provided */ + if (sd->u.s.position_transformed) { + rhw = ptrToCoords[3]; + VTRACE(("rhw=%f\n", rhw)); + } + + if (1.0f == rhw || ((rhw < eps) && (rhw > -eps))) { + VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f\n", x,y,z)); + glVertex3f(x, y, z); + } else { + GLfloat w = 1.0 / rhw; + VTRACE(("Vertex: glVertex:x,y,z=%f,%f,%f / rhw=%f\n", x,y,z,rhw)); + glVertex4f(x*w, y*w, z*w, w); + } + } + + /* For non indexed mode, step onto next parts */ + if (idxData == NULL) { + ++SkipnStrides; + } + } + + glEnd(); + checkGLcall("glEnd and previous calls"); +} + +static void depth_blt(IWineD3DDevice *iface, GLuint texture) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + GLint old_binding = 0; + + glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glDisable(GL_CULL_FACE); + glEnable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); + glBlendFunc(GL_ZERO, GL_ONE); + + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding); + glBindTexture(GL_TEXTURE_2D, texture); + glEnable(GL_TEXTURE_2D); + + This->shader_backend->shader_select_depth_blt(iface); + + glBegin(GL_TRIANGLE_STRIP); + glVertex2f(-1.0f, -1.0f); + glVertex2f(1.0f, -1.0f); + glVertex2f(-1.0f, 1.0f); + glVertex2f(1.0f, 1.0f); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, old_binding); + + glPopAttrib(); + + /* Reselect the old shaders. There doesn't seem to be any glPushAttrib bit for arb shaders, + * and this seems easier and more efficient than providing the shader backend with a private + * storage to read and restore the old shader settings + */ + This->shader_backend->shader_select(iface, use_ps(This), use_vs(This)); +} + +static void depth_copy(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *)This->depthStencilBuffer; + + /* Only copy the depth buffer if there is one. */ + if (!depth_stencil) return; + + /* TODO: Make this work for modes other than FBO */ + if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return; + + if (depth_stencil->current_renderbuffer) { + FIXME("Not supported with fixed up depth stencil\n"); + return; + } + + if (This->render_offscreen) { + static GLuint tmp_texture = 0; + GLint old_binding = 0; + + TRACE("Copying onscreen depth buffer to offscreen surface\n"); + + if (!tmp_texture) { + glGenTextures(1, &tmp_texture); + } + + /* Note that we use depth_blt here as well, rather than glCopyTexImage2D + * directly on the FBO texture. That's because we need to flip. */ + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding); + glBindTexture(GL_TEXTURE_2D, tmp_texture); + glCopyTexImage2D(depth_stencil->glDescription.target, + depth_stencil->glDescription.level, + depth_stencil->glDescription.glFormatInternal, + 0, + 0, + depth_stencil->currentDesc.Width, + depth_stencil->currentDesc.Height, + 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); + glBindTexture(GL_TEXTURE_2D, old_binding); + + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo)); + checkGLcall("glBindFramebuffer()"); + depth_blt(iface, tmp_texture); + checkGLcall("depth_blt"); + } else { + TRACE("Copying offscreen surface to onscreen depth buffer\n"); + + GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); + checkGLcall("glBindFramebuffer()"); + depth_blt(iface, depth_stencil->glDescription.textureName); + checkGLcall("depth_blt"); + } +} + +static inline void drawStridedInstanced(IWineD3DDevice *iface, WineDirect3DVertexStridedData *sd, UINT numberOfVertices, + GLenum glPrimitiveType, const void *idxData, short idxSize, ULONG minIndex, + ULONG startIdx, ULONG startVertex) { + UINT numInstances = 0; + int numInstancedAttribs = 0, i, j; + UINT instancedData[sizeof(sd->u.input) / sizeof(sd->u.input[0]) /* 16 */]; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DStateBlockImpl *stateblock = This->stateBlock; + + if (idxSize == 0) { + /* This is a nasty thing. MSDN says no hardware supports that and apps have to use software vertex processing. + * We don't support this for now + * + * Shouldn't be too hard to support with opengl, in theory just call glDrawArrays instead of drawElements. + * But the StreamSourceFreq value has a different meaning in that situation. + */ + FIXME("Non-indexed instanced drawing is not supported\n"); + return; + } + + TRACE("(%p) : glElements(%x, %d, %d, ...)\n", This, glPrimitiveType, numberOfVertices, minIndex); + idxData = idxData == (void *)-1 ? NULL : idxData; + + /* First, figure out how many instances we have to draw */ + for(i = 0; i < MAX_STREAMS; i++) { + /* Look at all non-instanced streams */ + if(!(stateblock->streamFlags[i] & WINED3DSTREAMSOURCE_INSTANCEDATA) && + stateblock->streamSource[i]) { + int inst = stateblock->streamFreq[i]; + + if(numInstances && inst != numInstances) { + ERR("Two streams specify a different number of instances. Got %d, new is %d\n", numInstances, inst); + } + numInstances = inst; + } + } + + for(i = 0; i < sizeof(sd->u.input) / sizeof(sd->u.input[0]); i++) { + if(stateblock->streamFlags[sd->u.input[i].streamNo] & WINED3DSTREAMSOURCE_INSTANCEDATA) { + instancedData[numInstancedAttribs] = i; + numInstancedAttribs++; + } + } + + /* now draw numInstances instances :-) */ + for(i = 0; i < numInstances; i++) { + /* Specify the instanced attributes using immediate mode calls */ + for(j = 0; j < numInstancedAttribs; j++) { + BYTE *ptr = sd->u.input[instancedData[j]].lpData + + sd->u.input[instancedData[j]].dwStride * i + + stateblock->streamOffset[sd->u.input[instancedData[j]].streamNo]; + if(sd->u.input[instancedData[j]].VBO) { + IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) stateblock->streamSource[sd->u.input[instancedData[j]].streamNo]; + ptr += (long) vb->resource.allocatedMemory; + } + + switch(sd->u.input[instancedData[j]].dwType) { + case WINED3DDECLTYPE_FLOAT1: + GL_EXTCALL(glVertexAttrib1fvARB(instancedData[j], (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT2: + GL_EXTCALL(glVertexAttrib2fvARB(instancedData[j], (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT3: + GL_EXTCALL(glVertexAttrib3fvARB(instancedData[j], (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT4: + GL_EXTCALL(glVertexAttrib4fvARB(instancedData[j], (float *) ptr)); + break; + + case WINED3DDECLTYPE_UBYTE4: + GL_EXTCALL(glVertexAttrib4NubvARB(instancedData[j], ptr)); + break; + case WINED3DDECLTYPE_UBYTE4N: + case WINED3DDECLTYPE_D3DCOLOR: + GL_EXTCALL(glVertexAttrib4NubvARB(instancedData[j], ptr)); + break; + + case WINED3DDECLTYPE_SHORT2: + GL_EXTCALL(glVertexAttrib4svARB(instancedData[j], (GLshort *) ptr)); + break; + case WINED3DDECLTYPE_SHORT4: + GL_EXTCALL(glVertexAttrib4svARB(instancedData[j], (GLshort *) ptr)); + break; + + case WINED3DDECLTYPE_SHORT2N: + { + GLshort s[4] = {((short *) ptr)[0], ((short *) ptr)[1], 0, 1}; + GL_EXTCALL(glVertexAttrib4NsvARB(instancedData[j], s)); + break; + } + case WINED3DDECLTYPE_USHORT2N: + { + GLushort s[4] = {((unsigned short *) ptr)[0], ((unsigned short *) ptr)[1], 0, 1}; + GL_EXTCALL(glVertexAttrib4NusvARB(instancedData[j], s)); + break; + } + case WINED3DDECLTYPE_SHORT4N: + GL_EXTCALL(glVertexAttrib4NsvARB(instancedData[j], (GLshort *) ptr)); + break; + case WINED3DDECLTYPE_USHORT4N: + GL_EXTCALL(glVertexAttrib4NusvARB(instancedData[j], (GLushort *) ptr)); + break; + + case WINED3DDECLTYPE_UDEC3: + FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n"); + /*glVertexAttrib3usvARB(instancedData[j], (GLushort *) ptr); Does not exist */ + break; + case WINED3DDECLTYPE_DEC3N: + FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n"); + /*glVertexAttrib3NusvARB(instancedData[j], (GLushort *) ptr); Does not exist */ + break; + + case WINED3DDECLTYPE_FLOAT16_2: + /* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4 + * byte float according to the IEEE standard + */ + if (GL_SUPPORT(NV_HALF_FLOAT)) { + GL_EXTCALL(glVertexAttrib2hvNV(instancedData[j], (GLhalfNV *)ptr)); + } else { + FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_2\n"); + } + break; + case WINED3DDECLTYPE_FLOAT16_4: + if (GL_SUPPORT(NV_HALF_FLOAT)) { + GL_EXTCALL(glVertexAttrib4hvNV(instancedData[j], (GLhalfNV *)ptr)); + } else { + FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_4\n"); + } + break; + + case WINED3DDECLTYPE_UNUSED: + default: + ERR("Unexpected declaration in instanced attributes\n"); + break; + } + } + + glDrawElements(glPrimitiveType, numberOfVertices, idxSize == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, + (const char *)idxData+(idxSize * startIdx)); + checkGLcall("glDrawElements"); + } +} + +struct coords { + int x, y, z; +}; + +void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface) { + struct coords coords[4]; + int low_coord; + + /* TODO: This could be supported for lazy unlocking */ + if(!(surface->Flags & SFLAG_INTEXTURE)) { + /* It is ok at init to be nowhere */ + if(!(surface->Flags & SFLAG_INSYSMEM)) { + ERR("Blitting surfaces from sysmem not supported yet\n"); + } + return; + } + + ActivateContext(This, This->render_targets[0], CTXUSAGE_BLIT); + ENTER_GL(); + + if(surface->glDescription.target == GL_TEXTURE_2D) { + glBindTexture(GL_TEXTURE_2D, surface->glDescription.textureName); + checkGLcall("GL_TEXTURE_2D, This->glDescription.textureName)"); + + coords[0].x = 0; coords[0].y = 0; coords[0].z = 0; + coords[1].x = 0; coords[1].y = 1; coords[1].z = 0; + coords[2].x = 1; coords[2].y = 1; coords[2].z = 0; + coords[3].x = 1; coords[3].y = 0; coords[3].z = 0; + + low_coord = 0; + } else { + /* Must be a cube map */ + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + glEnable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glEnable(surface->glDescription.target)"); + glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, surface->glDescription.textureName); + checkGLcall("GL_TEXTURE_CUBE_MAP_ARB, This->glDescription.textureName)"); + + switch(surface->glDescription.target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + coords[0].x = 1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = 1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = 1; coords[2].z = -1; + coords[3].x = 1; coords[3].y = -1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = -1; coords[1].y = 1; coords[1].z = 1; + coords[2].x = -1; coords[2].y = 1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + coords[0].x = -1; coords[0].y = 1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = 1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = 1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = 1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = -1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = -1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; + break; + + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + coords[0].x = -1; coords[0].y = -1; coords[0].z = 1; + coords[1].x = 1; coords[1].y = -1; coords[1].z = 1; + coords[2].x = 1; coords[2].y = -1; coords[2].z = 1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = 1; + break; + + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + coords[0].x = -1; coords[0].y = -1; coords[0].z = -1; + coords[1].x = 1; coords[1].y = -1; coords[1].z = -1; + coords[2].x = 1; coords[2].y = -1; coords[2].z = -1; + coords[3].x = -1; coords[3].y = -1; coords[3].z = -1; + + default: + ERR("Unexpected texture target\n"); + LEAVE_GL(); + return; + } + + low_coord = -1; + } + + if(This->render_offscreen) { + coords[0].y = coords[0].y == 1 ? low_coord : 1; + coords[1].y = coords[1].y == 1 ? low_coord : 1; + coords[2].y = coords[2].y == 1 ? low_coord : 1; + coords[3].y = coords[3].y == 1 ? low_coord : 1; + } + + glBegin(GL_QUADS); + glTexCoord3iv((GLint *) &coords[0]); + glVertex2i(0, 0); + + glTexCoord3iv((GLint *) &coords[1]); + glVertex2i(0, surface->pow2Height); + + glTexCoord3iv((GLint *) &coords[2]); + glVertex2i(surface->pow2Width, surface->pow2Height); + + glTexCoord3iv((GLint *) &coords[3]); + glVertex2i(surface->pow2Width, 0); + glEnd(); + checkGLcall("glEnd"); + + if(surface->glDescription.target != GL_TEXTURE_2D) { + glEnable(GL_TEXTURE_2D); + checkGLcall("glEnable(GL_TEXTURE_2D)"); + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + LEAVE_GL(); +} + +/* Routine common to the draw primitive and draw indexed primitive routines */ +void drawPrimitive(IWineD3DDevice *iface, + int PrimitiveType, + long NumPrimitives, + /* for Indexed: */ + long StartVertexIndex, + UINT numberOfVertices, + long StartIdx, + short idxSize, + const void *idxData, + int minIndex) { + + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + IWineD3DSwapChain *swapchain; + IWineD3DBaseTexture *texture = NULL; + IWineD3DSurfaceImpl *target; + int i; + + /* Signals other modules that a drawing is in progress and the stateblock finalized */ + This->isInDraw = TRUE; + + /* Invalidate the back buffer memory so LockRect will read it the next time */ + for(i = 0; i < GL_LIMITS(buffers); i++) { + target = (IWineD3DSurfaceImpl *) This->render_targets[i]; + + /* TODO: Only do all that if we're going to change anything + * Texture container dirtification does not work quite right yet + */ + if(target /*&& target->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)*/) { + swapchain = NULL; + texture = NULL; + + if(i == 0) { + IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain); + + /* Need the surface in the drawable! */ + if(!(target->Flags & SFLAG_INDRAWABLE) && (swapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO)) { + blt_to_drawable(This, target); + } + + if(swapchain) { + /* Onscreen target. Invalidate system memory copy and texture copy */ + target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE); + target->Flags |= SFLAG_INDRAWABLE; + IWineD3DSwapChain_Release(swapchain); + } else if(wined3d_settings.offscreen_rendering_mode != ORM_FBO) { + /* Non-FBO target: Invalidate system copy, texture copy and dirtify the container */ + IWineD3DSurface_GetContainer((IWineD3DSurface *) target, &IID_IWineD3DBaseTexture, (void **)&texture); + + if(texture) { + IWineD3DBaseTexture_SetDirty(texture, TRUE); + IWineD3DTexture_Release(texture); + } + + target->Flags &= ~(SFLAG_INSYSMEM | SFLAG_INTEXTURE); + target->Flags |= SFLAG_INDRAWABLE; + } else { + /* FBO offscreen target. Invalidate system memory copy */ + target->Flags &= ~SFLAG_INSYSMEM; + } + } else { + /* Must be an fbo render target */ + target->Flags &= ~SFLAG_INSYSMEM; + target->Flags |= SFLAG_INTEXTURE; + } + } + } + + /* Ok, we will be updating the screen from here onwards so grab the lock */ + + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { + ENTER_GL(); + apply_fbo_state(iface); + LEAVE_GL(); + } + + ActivateContext(This, This->render_targets[0], CTXUSAGE_DRAWPRIM); + ENTER_GL(); + + if (This->depth_copy_state == WINED3D_DCS_COPY) { + depth_copy(iface); + } + This->depth_copy_state = WINED3D_DCS_INITIAL; + + { + GLenum glPrimType; + BOOL emulation = FALSE; + WineDirect3DVertexStridedData *strided = &This->strided_streams; + WineDirect3DVertexStridedData stridedlcl; + /* Ok, Work out which primitive is requested and how many vertexes that + will be */ + UINT calculatedNumberOfindices = primitiveToGl(PrimitiveType, NumPrimitives, &glPrimType); + if (numberOfVertices == 0 ) + numberOfVertices = calculatedNumberOfindices; + + if(!This->strided_streams.u.s.position_transformed && !use_vs(This)) { + if(This->activeContext->num_untracked_materials && + This->stateBlock->renderState[WINED3DRS_LIGHTING]) { + IWineD3DVertexBufferImpl *vb; + + FIXME("Using software emulation because not all material properties could be tracked\n"); + emulation = TRUE; + + strided = &stridedlcl; + memcpy(&stridedlcl, &This->strided_streams, sizeof(stridedlcl)); + +#define FIXVBO(type) \ +if(stridedlcl.u.s.type.VBO) { \ + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[stridedlcl.u.s.type.streamNo]; \ + stridedlcl.u.s.type.VBO = 0; \ + stridedlcl.u.s.type.lpData = (BYTE *) ((unsigned long) stridedlcl.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \ +} + FIXVBO(position); + FIXVBO(blendWeights); + FIXVBO(blendMatrixIndices); + FIXVBO(normal); + FIXVBO(pSize); + FIXVBO(diffuse); + FIXVBO(specular); + for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) FIXVBO(texCoords[i]); + FIXVBO(position2); + FIXVBO(normal2); + FIXVBO(tangent); + FIXVBO(binormal); + FIXVBO(tessFactor); + FIXVBO(fog); + FIXVBO(depth); + FIXVBO(sample); +#undef FIXVBO + } + } + + if (This->useDrawStridedSlow || emulation) { + /* Immediate mode drawing */ + drawStridedSlow(iface, strided, calculatedNumberOfindices, + glPrimType, idxData, idxSize, minIndex, StartIdx, StartVertexIndex); + } else if(This->instancedDraw) { + /* Instancing emulation with mixing immediate mode and arrays */ + drawStridedInstanced(iface, &This->strided_streams, calculatedNumberOfindices, glPrimType, + idxData, idxSize, minIndex, StartIdx, StartVertexIndex); + } else { + /* Simple array draw call */ + drawStridedFast(iface, calculatedNumberOfindices, glPrimType, + idxData, idxSize, minIndex, StartIdx, StartVertexIndex); + } + } + + /* Finshed updating the screen, restore lock */ + LEAVE_GL(); + TRACE("Done all gl drawing\n"); + + /* Diagnostics */ +#ifdef SHOW_FRAME_MAKEUP + { + static long int primCounter = 0; + /* NOTE: set primCounter to the value reported by drawprim + before you want to to write frame makeup to /tmp */ + if (primCounter >= 0) { + WINED3DLOCKED_RECT r; + char buffer[80]; + IWineD3DSurface_LockRect(This->renderTarget, &r, NULL, WINED3DLOCK_READONLY); + sprintf(buffer, "/tmp/backbuffer_%d.tga", primCounter); + TRACE("Saving screenshot %s\n", buffer); + IWineD3DSurface_SaveSnapshot(This->renderTarget, buffer); + IWineD3DSurface_UnlockRect(This->renderTarget); + +#ifdef SHOW_TEXTURE_MAKEUP + { + IWineD3DSurface *pSur; + int textureNo; + for (textureNo = 0; textureNo < MAX_COMBINED_SAMPLERS; ++textureNo) { + if (This->stateBlock->textures[textureNo] != NULL) { + sprintf(buffer, "/tmp/texture_%p_%d_%d.tga", This->stateBlock->textures[textureNo], primCounter, textureNo); + TRACE("Saving texture %s\n", buffer); + if (IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo]) == WINED3DRTYPE_TEXTURE) { + IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)This->stateBlock->textures[textureNo], 0, &pSur); + IWineD3DSurface_SaveSnapshot(pSur, buffer); + IWineD3DSurface_Release(pSur); + } else { + FIXME("base Texture isn't of type texture %d\n", IWineD3DBaseTexture_GetType(This->stateBlock->textures[textureNo])); + } + } + } + } +#endif + } + TRACE("drawprim #%d\n", primCounter); + ++primCounter; + } +#endif + + /* Control goes back to the device, stateblock values may change again */ + This->isInDraw = FALSE; +} + +static void normalize_normal(float *n) { + float length = n[0] * n[0] + n[1] * n[1] + n[2] * n[2]; + if(length == 0.0) return; + length = sqrt(length); + n[0] = n[0] / length; + n[1] = n[1] / length; + n[2] = n[2] / length; +} + +/* Tesselates a high order rectangular patch into single triangles using gl evaluators + * + * The problem is that OpenGL does not offer a direct way to return the tesselated primitives, + * and they can't be sent off for rendering directly either. Tesselating is slow, so we want + * to chache the patches in a vertex buffer. But more importantly, gl can't bind generated + * attributes to numbered shader attributes, so we have to store them and rebind them as needed + * in drawprim. + * + * To read back, the opengl feedback mode is used. This creates a proplem because we want + * untransformed, unlit vertices, but feedback runs everything through transform and lighting. + * Thus disable lighting and set identity matrices to get unmodified colors and positions. + * To overcome clipping find the biggest x, y and z values of the vertices in the patch and scale + * them to [-1.0;+1.0] and set the viewport up to scale them back. + * + * Normals are more tricky: Draw white vertices with 3 directional lights, and calculate the + * resulting colors back to the normals. + * + * NOTE: This function activates a context for blitting, modifies matrices & viewport, but + * does not restore it because normally a draw follows immediately afterwards. The caller is + * responsible of taking care that either the gl states are restored, or the context activated + * for drawing to reset the lastWasBlit flag. + */ +HRESULT tesselate_rectpatch(IWineD3DDeviceImpl *This, + struct WineD3DRectPatch *patch) { + unsigned int i, j, num_quads, out_vertex_size, buffer_size, d3d_out_vertex_size; + float max_x = 0.0, max_y = 0.0, max_z = 0.0, neg_z = 0.0; + WineDirect3DVertexStridedData strided; + BYTE *data; + WINED3DRECTPATCH_INFO *info = &patch->RectPatchInfo; + DWORD vtxStride; + GLenum feedback_type; + GLfloat *feedbuffer; + + /* First, locate the position data. This is provided in a vertex buffer in the stateblock. + * Beware of vbos + */ + memset(&strided, 0, sizeof(strided)); + primitiveDeclarationConvertToStridedData((IWineD3DDevice *) This, FALSE, &strided, NULL); + if(strided.u.s.position.VBO) { + IWineD3DVertexBufferImpl *vb; + vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.position.streamNo]; + strided.u.s.position.lpData = (BYTE *) ((unsigned long) strided.u.s.position.lpData + + (unsigned long) vb->resource.allocatedMemory); + } + vtxStride = strided.u.s.position.dwStride; + data = strided.u.s.position.lpData + + vtxStride * info->Stride * info->StartVertexOffsetHeight + + vtxStride * info->StartVertexOffsetWidth; + + /* Not entirely sure about what happens with transformed vertices */ + if(strided.u.s.position_transformed) { + FIXME("Transformed position in rectpatch generation\n"); + } + if(vtxStride % sizeof(GLfloat)) { + /* glMap2f reads vertex sizes in GLfloats, the d3d stride is in bytes. + * I don't see how the stride could not be a multiple of 4, but make sure + * to check it + */ + ERR("Vertex stride is not a multiple of sizeof(GLfloat)\n"); + } + if(info->Basis != WINED3DBASIS_BEZIER) { + FIXME("Basis is %s, how to handle this?\n", debug_d3dbasis(info->Basis)); + } + if(info->Degree != WINED3DDEGREE_CUBIC) { + FIXME("Degree is %s, how to handle this?\n", debug_d3ddegree(info->Degree)); + } + + /* First, get the boundary cube of the input data */ + for(j = 0; j < info->Height; j++) { + for(i = 0; i < info->Width; i++) { + float *v = (float *) (data + vtxStride * i + vtxStride * info->Stride * j); + if(fabs(v[0]) > max_x) max_x = fabs(v[0]); + if(fabs(v[1]) > max_y) max_y = fabs(v[1]); + if(fabs(v[2]) > max_z) max_z = fabs(v[2]); + if(v[2] < neg_z) neg_z = v[2]; + } + } + + /* This needs some improvements in the vertex decl code */ + FIXME("Cannot find data to generate. Only generating position and normals\n"); + patch->has_normals = TRUE; + patch->has_texcoords = FALSE; + + /* Simply activate the context for blitting. This disables all the things we don't want and + * takes care of dirtifying. Dirtifying is preferred over pushing / popping, since drawing the + * patch (as opposed to normal draws) will most likely need different changes anyway + */ + ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_BLIT); + ENTER_GL(); + + glMatrixMode(GL_PROJECTION); + checkGLcall("glMatrixMode(GL_PROJECTION)"); + glLoadIdentity(); + checkGLcall("glLoadIndentity()"); + glScalef(1 / (max_x) , 1 / (max_y), max_z == 0 ? 1 : 1 / ( 2 * max_z)); + glTranslatef(0, 0, 0.5); + checkGLcall("glScalef"); + glViewport(-max_x, -max_y, 2 * (max_x), 2 * (max_y)); + checkGLcall("glViewport"); + + /* Some states to take care of. If we're in wireframe opengl will produce lines, and confuse + * our feedback buffer parser + */ + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + checkGLcall("glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)"); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_FILLMODE)); + if(patch->has_normals) { + float black[4] = {0, 0, 0, 0}; + float red[4] = {1, 0, 0, 0}; + float green[4] = {0, 1, 0, 0}; + float blue[4] = {0, 0, 1, 0}; + float white[4] = {1, 1, 1, 1}; + glEnable(GL_LIGHTING); + checkGLcall("glEnable(GL_LIGHTING)"); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, black); + checkGLcall("glLightModel for MODEL_AMBIENT"); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_AMBIENT)); + + for(i = 3; i < GL_LIMITS(lights); i++) { + glDisable(GL_LIGHT0 + i); + checkGLcall("glDisable(GL_LIGHT0 + i)"); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i)); + } + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(0)); + glLightfv(GL_LIGHT0, GL_DIFFUSE, red); + glLightfv(GL_LIGHT0, GL_SPECULAR, black); + glLightfv(GL_LIGHT0, GL_AMBIENT, black); + glLightfv(GL_LIGHT0, GL_POSITION, red); + glEnable(GL_LIGHT0); + checkGLcall("Setting up light 1\n"); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(1)); + glLightfv(GL_LIGHT1, GL_DIFFUSE, green); + glLightfv(GL_LIGHT1, GL_SPECULAR, black); + glLightfv(GL_LIGHT1, GL_AMBIENT, black); + glLightfv(GL_LIGHT1, GL_POSITION, green); + glEnable(GL_LIGHT1); + checkGLcall("Setting up light 2\n"); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(2)); + glLightfv(GL_LIGHT2, GL_DIFFUSE, blue); + glLightfv(GL_LIGHT2, GL_SPECULAR, black); + glLightfv(GL_LIGHT2, GL_AMBIENT, black); + glLightfv(GL_LIGHT2, GL_POSITION, blue); + glEnable(GL_LIGHT2); + checkGLcall("Setting up light 3\n"); + + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL); + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORVERTEX)); + glDisable(GL_COLOR_MATERIAL); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white); + checkGLcall("Setting up materials\n"); + } + + /* Enable the needed maps. + * GL_MAP2_VERTEX_3 is needed for positional data. + * GL_AUTO_NORMAL to generate normals from the position. Do not use GL_MAP2_NORMAL. + * GL_MAP2_TEXTURE_COORD_4 for texture coords + */ + num_quads = ceilf(patch->numSegs[0]) * ceilf(patch->numSegs[1]); + out_vertex_size = 3 /* position */; + d3d_out_vertex_size = 3; + glEnable(GL_MAP2_VERTEX_3); + if(patch->has_normals && patch->has_texcoords) { + FIXME("Texcoords not handled yet\n"); + feedback_type = GL_3D_COLOR_TEXTURE; + out_vertex_size += 8; + d3d_out_vertex_size += 7; + glEnable(GL_AUTO_NORMAL); + glEnable(GL_MAP2_TEXTURE_COORD_4); + } else if(patch->has_texcoords) { + FIXME("Texcoords not handled yet\n"); + feedback_type = GL_3D_COLOR_TEXTURE; + out_vertex_size += 7; + d3d_out_vertex_size += 4; + glEnable(GL_MAP2_TEXTURE_COORD_4); + } else if(patch->has_normals) { + feedback_type = GL_3D_COLOR; + out_vertex_size += 4; + d3d_out_vertex_size += 3; + glEnable(GL_AUTO_NORMAL); + } else { + feedback_type = GL_3D; + } + checkGLcall("glEnable vertex attrib generation"); + + buffer_size = num_quads * out_vertex_size * 2 /* triangle list */ * 3 /* verts per tri */ + + 4 * num_quads /* 2 triangle markers per quad + num verts in tri */; + feedbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size * sizeof(float) * 8); + + glMap2f(GL_MAP2_VERTEX_3, + 0, 1, vtxStride / sizeof(float), info->Width, + 0, 1, info->Stride * vtxStride / sizeof(float), info->Height, + (float *) data); + checkGLcall("glMap2f"); + if(patch->has_texcoords) { + glMap2f(GL_MAP2_TEXTURE_COORD_4, + 0, 1, vtxStride / sizeof(float), info->Width, + 0, 1, info->Stride * vtxStride / sizeof(float), info->Height, + (float *) data); + checkGLcall("glMap2f"); + } + glMapGrid2f(ceilf(patch->numSegs[0]), 0.0, 1.0, ceilf(patch->numSegs[1]), 0.0, 1.0); + checkGLcall("glMapGrid2f"); + + glFeedbackBuffer(buffer_size * 2, feedback_type, feedbuffer); + checkGLcall("glFeedbackBuffer"); + glRenderMode(GL_FEEDBACK); + + glEvalMesh2(GL_FILL, 0, ceilf(patch->numSegs[0]), 0, ceilf(patch->numSegs[1])); + checkGLcall("glEvalMesh2\n"); + + i = glRenderMode(GL_RENDER); + if(i == -1) { + ERR("Feedback failed. Expected %d elements back\n", buffer_size); + Sleep(10000); + HeapFree(GetProcessHeap(), 0, feedbuffer); + return WINED3DERR_DRIVERINTERNALERROR; + } else if(i != buffer_size) { + ERR("Unexpected amount of elements returned. Expected %d, got %d\n", buffer_size, i); + Sleep(10000); + HeapFree(GetProcessHeap(), 0, feedbuffer); + return WINED3DERR_DRIVERINTERNALERROR; + } else { + TRACE("Got %d elements as expected\n", i); + } + + HeapFree(GetProcessHeap(), 0, patch->mem); + patch->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, num_quads * 6 * d3d_out_vertex_size * sizeof(float) * 8); + i = 0; + for(j = 0; j < buffer_size; j += (3 /* num verts */ * out_vertex_size + 2 /* tri marker */)) { + if(feedbuffer[j] != GL_POLYGON_TOKEN) { + ERR("Unexpected token: %f\n", feedbuffer[j]); + continue; + } + if(feedbuffer[j + 1] != 3) { + ERR("Unexpected polygon: %f corners\n", feedbuffer[j + 1]); + continue; + } + /* Somehow there are different ideas about back / front facing, so fix up the + * vertex order + */ + patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 2 + 2]; /* x, triangle 2 */ + patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 2 + 3]; /* y, triangle 2 */ + patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 2 + 4] - 0.5) * 4 * max_z; /* z, triangle 3 */ + if(patch->has_normals) { + patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 2 + 5]; + patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 2 + 6]; + patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 2 + 7]; + } + i += d3d_out_vertex_size; + + patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 1 + 2]; /* x, triangle 2 */ + patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 1 + 3]; /* y, triangle 2 */ + patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 1 + 4] - 0.5) * 4 * max_z; /* z, triangle 2 */ + if(patch->has_normals) { + patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 1 + 5]; + patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 1 + 6]; + patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 1 + 7]; + } + i += d3d_out_vertex_size; + + patch->mem[i + 0] = feedbuffer[j + out_vertex_size * 0 + 2]; /* x, triangle 1 */ + patch->mem[i + 1] = feedbuffer[j + out_vertex_size * 0 + 3]; /* y, triangle 1 */ + patch->mem[i + 2] = (feedbuffer[j + out_vertex_size * 0 + 4] - 0.5) * 4 * max_z; /* z, triangle 1 */ + if(patch->has_normals) { + patch->mem[i + 3] = feedbuffer[j + out_vertex_size * 0 + 5]; + patch->mem[i + 4] = feedbuffer[j + out_vertex_size * 0 + 6]; + patch->mem[i + 5] = feedbuffer[j + out_vertex_size * 0 + 7]; + } + i += d3d_out_vertex_size; + } + + if(patch->has_normals) { + /* Now do the same with reverse light directions */ + float x[4] = {-1, 0, 0, 0}; + float y[4] = { 0, -1, 0, 0}; + float z[4] = { 0, 0, -1, 0}; + glLightfv(GL_LIGHT0, GL_POSITION, x); + glLightfv(GL_LIGHT1, GL_POSITION, y); + glLightfv(GL_LIGHT2, GL_POSITION, z); + checkGLcall("Setting up reverse light directions\n"); + + glRenderMode(GL_FEEDBACK); + checkGLcall("glRenderMode(GL_FEEDBACK)"); + glEvalMesh2(GL_FILL, 0, ceilf(patch->numSegs[0]), 0, ceilf(patch->numSegs[1])); + checkGLcall("glEvalMesh2\n"); + i = glRenderMode(GL_RENDER); + checkGLcall("glRenderMode(GL_RENDER)"); + + i = 0; + for(j = 0; j < buffer_size; j += (3 /* num verts */ * out_vertex_size + 2 /* tri marker */)) { + if(feedbuffer[j] != GL_POLYGON_TOKEN) { + ERR("Unexpected token: %f\n", feedbuffer[j]); + continue; + } + if(feedbuffer[j + 1] != 3) { + ERR("Unexpected polygon: %f corners\n", feedbuffer[j + 1]); + continue; + } + if(patch->mem[i + 3] == 0.0) + patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 2 + 5]; + if(patch->mem[i + 4] == 0.0) + patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 2 + 6]; + if(patch->mem[i + 5] == 0.0) + patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 2 + 7]; + normalize_normal(patch->mem + i + 3); + i += d3d_out_vertex_size; + + if(patch->mem[i + 3] == 0.0) + patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 1 + 5]; + if(patch->mem[i + 4] == 0.0) + patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 1 + 6]; + if(patch->mem[i + 5] == 0.0) + patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 1 + 7]; + normalize_normal(patch->mem + i + 3); + i += d3d_out_vertex_size; + + if(patch->mem[i + 3] == 0.0) + patch->mem[i + 3] = -feedbuffer[j + out_vertex_size * 0 + 5]; + if(patch->mem[i + 4] == 0.0) + patch->mem[i + 4] = -feedbuffer[j + out_vertex_size * 0 + 6]; + if(patch->mem[i + 5] == 0.0) + patch->mem[i + 5] = -feedbuffer[j + out_vertex_size * 0 + 7]; + normalize_normal(patch->mem + i + 3); + i += d3d_out_vertex_size; + } + } + + glDisable(GL_MAP2_VERTEX_3); + glDisable(GL_AUTO_NORMAL); + glDisable(GL_MAP2_NORMAL); + glDisable(GL_MAP2_TEXTURE_COORD_4); + checkGLcall("glDisable vertex attrib generation"); + LEAVE_GL(); + + HeapFree(GetProcessHeap(), 0, feedbuffer); + + vtxStride = 3 * sizeof(float); + if(patch->has_normals) { + vtxStride += 3 * sizeof(float); + } + if(patch->has_texcoords) { + vtxStride += 4 * sizeof(float); + } + memset(&patch->strided, 0, sizeof(&patch->strided)); + patch->strided.u.s.position.lpData = (BYTE *) patch->mem; + patch->strided.u.s.position.dwStride = vtxStride; + patch->strided.u.s.position.dwType = WINED3DDECLTYPE_FLOAT3; + patch->strided.u.s.position.streamNo = 255; + + if(patch->has_normals) { + patch->strided.u.s.normal.lpData = (BYTE *) patch->mem + 3 * sizeof(float) /* pos */; + patch->strided.u.s.normal.dwStride = vtxStride; + patch->strided.u.s.normal.dwType = WINED3DDECLTYPE_FLOAT3; + patch->strided.u.s.normal.streamNo = 255; + } + if(patch->has_texcoords) { + patch->strided.u.s.texCoords[0].lpData = (BYTE *) patch->mem + 3 * sizeof(float) /* pos */; + if(patch->has_normals) { + patch->strided.u.s.texCoords[0].lpData += 3 * sizeof(float); + } + patch->strided.u.s.texCoords[0].dwStride = vtxStride; + patch->strided.u.s.texCoords[0].dwType = WINED3DDECLTYPE_FLOAT4; + /* MAX_STREAMS index points to an unused element in stateblock->streamOffsets which + * always remains set to 0. Windows uses stream 255 here, but this is not visible to the + * application. + */ + patch->strided.u.s.texCoords[0].streamNo = MAX_STREAMS; + } + + return WINED3D_OK; +} diff --git a/reactos/dll/directx/wine/wined3d/glsl_shader.c b/reactos/dll/directx/wine/wined3d/glsl_shader.c new file mode 100644 index 00000000000..a39caf42fdf --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/glsl_shader.c @@ -0,0 +1,2369 @@ +/* + * GLSL pixel and vertex shader implementation + * + * Copyright 2006 Jason Green + * Copyright 2006-2007 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * D3D shader asm has swizzles on source parameters, and write masks for + * destination parameters. GLSL uses swizzles for both. The result of this is + * that for example "mov dst.xw, src.zyxw" becomes "dst.xw = src.zw" in GLSL. + * Ie, to generate a proper GLSL source swizzle, we need to take the D3D write + * mask for the destination parameter into account. + */ + +#include "config.h" +#include +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); +WINE_DECLARE_DEBUG_CHANNEL(d3d_constants); + +#define GLINFO_LOCATION (*gl_info) + +typedef struct { + char reg_name[50]; + char mask_str[6]; +} glsl_dst_param_t; + +typedef struct { + char reg_name[50]; + char param_str[100]; +} glsl_src_param_t; + +typedef struct { + const char *name; + DWORD coord_mask; +} glsl_sample_function_t; + +/** Prints the GLSL info log which will contain error messages if they exist */ +void print_glsl_info_log(WineD3D_GL_Info *gl_info, GLhandleARB obj) { + + int infologLength = 0; + char *infoLog; + + GL_EXTCALL(glGetObjectParameterivARB(obj, + GL_OBJECT_INFO_LOG_LENGTH_ARB, + &infologLength)); + + /* A size of 1 is just a null-terminated string, so the log should be bigger than + * that if there are errors. */ + if (infologLength > 1) + { + infoLog = HeapAlloc(GetProcessHeap(), 0, infologLength); + GL_EXTCALL(glGetInfoLogARB(obj, infologLength, NULL, infoLog)); + FIXME("Error received from GLSL shader #%u: %s\n", obj, debugstr_a(infoLog)); + HeapFree(GetProcessHeap(), 0, infoLog); + } +} + +/** + * Loads (pixel shader) samplers + */ +static void shader_glsl_load_psamplers( + WineD3D_GL_Info *gl_info, + IWineD3DStateBlock* iface) { + + IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface; + GLhandleARB programId = stateBlock->glsl_program->programId; + GLhandleARB name_loc; + int i; + char sampler_name[20]; + + for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) { + _snprintf(sampler_name, sizeof(sampler_name), "Psampler%d", i); + name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name)); + if (name_loc != -1) { + int mapped_unit = stateBlock->wineD3DDevice->texUnitMap[i]; + if (mapped_unit != -1 && mapped_unit < GL_LIMITS(fragment_samplers)) { + TRACE("Loading %s for texture %d\n", sampler_name, mapped_unit); + GL_EXTCALL(glUniform1iARB(name_loc, mapped_unit)); + checkGLcall("glUniform1iARB"); + } else { + ERR("Trying to load sampler %s on unsupported unit %d\n", sampler_name, mapped_unit); + } + } + } +} + +static void shader_glsl_load_vsamplers(WineD3D_GL_Info *gl_info, IWineD3DStateBlock* iface) { + IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface; + GLhandleARB programId = stateBlock->glsl_program->programId; + GLhandleARB name_loc; + char sampler_name[20]; + int i; + + for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) { + _snprintf(sampler_name, sizeof(sampler_name), "Vsampler%d", i); + name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name)); + if (name_loc != -1) { + int mapped_unit = stateBlock->wineD3DDevice->texUnitMap[MAX_FRAGMENT_SAMPLERS + i]; + if (mapped_unit != -1 && mapped_unit < GL_LIMITS(combined_samplers)) { + TRACE("Loading %s for texture %d\n", sampler_name, mapped_unit); + GL_EXTCALL(glUniform1iARB(name_loc, mapped_unit)); + checkGLcall("glUniform1iARB"); + } else { + ERR("Trying to load sampler %s on unsupported unit %d\n", sampler_name, mapped_unit); + } + } + } +} + +/** + * Loads floating point constants (aka uniforms) into the currently set GLSL program. + * When constant_list == NULL, it will load all the constants. + */ +static void shader_glsl_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, + unsigned int max_constants, float* constants, GLhandleARB *constant_locations, + struct list *constant_list) { + constants_entry *constant; + local_constant* lconst; + GLhandleARB tmp_loc; + DWORD i, j; + DWORD *idx; + + if (TRACE_ON(d3d_shader)) { + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + tmp_loc = constant_locations[i]; + if (tmp_loc != -1) { + TRACE_(d3d_constants)("Loading constants %i: %f, %f, %f, %f\n", i, + constants[i * 4 + 0], constants[i * 4 + 1], + constants[i * 4 + 2], constants[i * 4 + 3]); + } + } + } + } + LIST_FOR_EACH_ENTRY(constant, constant_list, constants_entry, entry) { + idx = constant->idx; + j = constant->count; + while (j--) { + i = *idx++; + tmp_loc = constant_locations[i]; + if (tmp_loc != -1) { + /* We found this uniform name in the program - go ahead and send the data */ + GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, constants + (i * 4))); + } + } + } + checkGLcall("glUniform4fvARB()"); + + /* Load immediate constants */ + if (TRACE_ON(d3d_shader)) { + LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { + tmp_loc = constant_locations[lconst->idx]; + if (tmp_loc != -1) { + GLfloat* values = (GLfloat*)lconst->value; + TRACE_(d3d_constants)("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx, + values[0], values[1], values[2], values[3]); + } + } + } + LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) { + tmp_loc = constant_locations[lconst->idx]; + if (tmp_loc != -1) { + /* We found this uniform name in the program - go ahead and send the data */ + GL_EXTCALL(glUniform4fvARB(tmp_loc, 1, (GLfloat*)lconst->value)); + } + } + checkGLcall("glUniform4fvARB()"); +} + +/** + * Loads integer constants (aka uniforms) into the currently set GLSL program. + * When @constants_set == NULL, it will load all the constants. + */ +static void shader_glsl_load_constantsI( + IWineD3DBaseShaderImpl* This, + WineD3D_GL_Info *gl_info, + GLhandleARB programId, + unsigned max_constants, + int* constants, + BOOL* constants_set) { + + GLhandleARB tmp_loc; + int i; + char tmp_name[8]; + char is_pshader = shader_is_pshader_version(This->baseShader.hex_version); + const char* prefix = is_pshader? "PI":"VI"; + struct list* ptr; + + for (i=0; ibaseShader.constantsI); + while (ptr) { + local_constant* lconst = LIST_ENTRY(ptr, struct local_constant, entry); + unsigned int idx = lconst->idx; + GLint* values = (GLint*) lconst->value; + + TRACE_(d3d_constants)("Loading local constants %i: %i, %i, %i, %i\n", idx, + values[0], values[1], values[2], values[3]); + + _snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx); + tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name)); + if (tmp_loc != -1) { + /* We found this uniform name in the program - go ahead and send the data */ + GL_EXTCALL(glUniform4ivARB(tmp_loc, 1, values)); + checkGLcall("glUniform4ivARB"); + } + ptr = list_next(&This->baseShader.constantsI, ptr); + } +} + +/** + * Loads boolean constants (aka uniforms) into the currently set GLSL program. + * When @constants_set == NULL, it will load all the constants. + */ +static void shader_glsl_load_constantsB( + IWineD3DBaseShaderImpl* This, + WineD3D_GL_Info *gl_info, + GLhandleARB programId, + unsigned max_constants, + BOOL* constants, + BOOL* constants_set) { + + GLhandleARB tmp_loc; + int i; + char tmp_name[8]; + char is_pshader = shader_is_pshader_version(This->baseShader.hex_version); + const char* prefix = is_pshader? "PB":"VB"; + struct list* ptr; + + for (i=0; ibaseShader.constantsB); + while (ptr) { + local_constant* lconst = LIST_ENTRY(ptr, struct local_constant, entry); + unsigned int idx = lconst->idx; + GLint* values = (GLint*) lconst->value; + + TRACE_(d3d_constants)("Loading local constants %i: %i\n", idx, values[0]); + + _snprintf(tmp_name, sizeof(tmp_name), "%s[%i]", prefix, idx); + tmp_loc = GL_EXTCALL(glGetUniformLocationARB(programId, tmp_name)); + if (tmp_loc != -1) { + /* We found this uniform name in the program - go ahead and send the data */ + GL_EXTCALL(glUniform1ivARB(tmp_loc, 1, values)); + checkGLcall("glUniform1ivARB"); + } + ptr = list_next(&This->baseShader.constantsB, ptr); + } +} + + + +/** + * Loads the app-supplied constants into the currently set GLSL program. + */ +void shader_glsl_load_constants( + IWineD3DDevice* device, + char usePixelShader, + char useVertexShader) { + + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) device; + IWineD3DStateBlockImpl* stateBlock = deviceImpl->stateBlock; + WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info; + + GLhandleARB *constant_locations; + struct list *constant_list; + GLhandleARB programId; + GLint pos; + + if (!stateBlock->glsl_program) { + /* No GLSL program set - nothing to do. */ + return; + } + programId = stateBlock->glsl_program->programId; + + if (useVertexShader) { + IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader; + GLint pos; + + constant_locations = stateBlock->glsl_program->vuniformF_locations; + constant_list = &stateBlock->set_vconstantsF; + + /* Load vertex shader samplers */ + shader_glsl_load_vsamplers(gl_info, (IWineD3DStateBlock*)stateBlock); + + /* Load DirectX 9 float constants/uniforms for vertex shader */ + shader_glsl_load_constantsF(vshader, gl_info, GL_LIMITS(vshader_constantsF), + stateBlock->vertexShaderConstantF, constant_locations, constant_list); + + /* Load DirectX 9 integer constants/uniforms for vertex shader */ + shader_glsl_load_constantsI(vshader, gl_info, programId, MAX_CONST_I, + stateBlock->vertexShaderConstantI, + stateBlock->changed.vertexShaderConstantsI); + + /* Load DirectX 9 boolean constants/uniforms for vertex shader */ + shader_glsl_load_constantsB(vshader, gl_info, programId, MAX_CONST_B, + stateBlock->vertexShaderConstantB, + stateBlock->changed.vertexShaderConstantsB); + + /* Upload the position fixup params */ + pos = GL_EXTCALL(glGetUniformLocationARB(programId, "posFixup")); + checkGLcall("glGetUniformLocationARB"); + GL_EXTCALL(glUniform4fvARB(pos, 1, &deviceImpl->posFixup[0])); + checkGLcall("glUniform4fvARB"); + } + + if (usePixelShader) { + + IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader; + + constant_locations = stateBlock->glsl_program->puniformF_locations; + constant_list = &stateBlock->set_pconstantsF; + + /* Load pixel shader samplers */ + shader_glsl_load_psamplers(gl_info, (IWineD3DStateBlock*) stateBlock); + + /* Load DirectX 9 float constants/uniforms for pixel shader */ + shader_glsl_load_constantsF(pshader, gl_info, GL_LIMITS(pshader_constantsF), + stateBlock->pixelShaderConstantF, constant_locations, constant_list); + + /* Load DirectX 9 integer constants/uniforms for pixel shader */ + shader_glsl_load_constantsI(pshader, gl_info, programId, MAX_CONST_I, + stateBlock->pixelShaderConstantI, + stateBlock->changed.pixelShaderConstantsI); + + /* Load DirectX 9 boolean constants/uniforms for pixel shader */ + shader_glsl_load_constantsB(pshader, gl_info, programId, MAX_CONST_B, + stateBlock->pixelShaderConstantB, + stateBlock->changed.pixelShaderConstantsB); + + /* Upload the environment bump map matrix if needed. The needsbumpmat member specifies the texture stage to load the matrix from. + * It can't be 0 for a valid texbem instruction. + */ + if(((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat != -1) { + float *data = (float *) &stateBlock->textureState[(int) ((IWineD3DPixelShaderImpl *) pshader)->needsbumpmat][WINED3DTSS_BUMPENVMAT00]; + pos = GL_EXTCALL(glGetUniformLocationARB(programId, "bumpenvmat")); + checkGLcall("glGetUniformLocationARB"); + GL_EXTCALL(glUniformMatrix2fvARB(pos, 1, 0, data)); + checkGLcall("glUniform4fvARB"); + } + } +} + +/** Generate the variable & register declarations for the GLSL output target */ +void shader_generate_glsl_declarations( + IWineD3DBaseShader *iface, + shader_reg_maps* reg_maps, + SHADER_BUFFER* buffer, + WineD3D_GL_Info* gl_info) { + + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; + int i; + + /* There are some minor differences between pixel and vertex shaders */ + char pshader = shader_is_pshader_version(This->baseShader.hex_version); + char prefix = pshader ? 'P' : 'V'; + + /* Prototype the subroutines */ + for (i = 0; i < This->baseShader.limits.label; i++) { + if (reg_maps->labels[i]) + shader_addline(buffer, "void subroutine%lu();\n", i); + } + + /* Declare the constants (aka uniforms) */ + if (This->baseShader.limits.constant_float > 0) { + unsigned max_constantsF = min(This->baseShader.limits.constant_float, + (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF))); + shader_addline(buffer, "uniform vec4 %cC[%u];\n", prefix, max_constantsF); + } + + if (This->baseShader.limits.constant_int > 0) + shader_addline(buffer, "uniform ivec4 %cI[%u];\n", prefix, This->baseShader.limits.constant_int); + + if (This->baseShader.limits.constant_bool > 0) + shader_addline(buffer, "uniform bool %cB[%u];\n", prefix, This->baseShader.limits.constant_bool); + + if(!pshader) + shader_addline(buffer, "uniform vec4 posFixup;\n"); + else if(reg_maps->bumpmat != -1) + shader_addline(buffer, "uniform mat2 bumpenvmat;\n"); + + /* Declare texture samplers */ + for (i = 0; i < This->baseShader.limits.sampler; i++) { + if (reg_maps->samplers[i]) { + + DWORD stype = reg_maps->samplers[i] & WINED3DSP_TEXTURETYPE_MASK; + switch (stype) { + + case WINED3DSTT_1D: + shader_addline(buffer, "uniform sampler1D %csampler%lu;\n", prefix, i); + break; + case WINED3DSTT_2D: + shader_addline(buffer, "uniform sampler2D %csampler%lu;\n", prefix, i); + break; + case WINED3DSTT_CUBE: + shader_addline(buffer, "uniform samplerCube %csampler%lu;\n", prefix, i); + break; + case WINED3DSTT_VOLUME: + shader_addline(buffer, "uniform sampler3D %csampler%lu;\n", prefix, i); + break; + default: + shader_addline(buffer, "uniform unsupported_sampler %csampler%lu;\n", prefix, i); + FIXME("Unrecognized sampler type: %#x\n", stype); + break; + } + } + } + + /* Declare address variables */ + for (i = 0; i < This->baseShader.limits.address; i++) { + if (reg_maps->address[i]) + shader_addline(buffer, "ivec4 A%d;\n", i); + } + + /* Declare texture coordinate temporaries and initialize them */ + for (i = 0; i < This->baseShader.limits.texcoord; i++) { + if (reg_maps->texcoord[i]) + shader_addline(buffer, "vec4 T%lu = gl_TexCoord[%lu];\n", i, i); + } + + /* Declare input register temporaries */ + for (i=0; i < This->baseShader.limits.packed_input; i++) { + if (reg_maps->packed_input[i]) + shader_addline(buffer, "vec4 IN%lu;\n", i); + } + + /* Declare output register temporaries */ + for (i = 0; i < This->baseShader.limits.packed_output; i++) { + if (reg_maps->packed_output[i]) + shader_addline(buffer, "vec4 OUT%lu;\n", i); + } + + /* Declare temporary variables */ + for(i = 0; i < This->baseShader.limits.temporary; i++) { + if (reg_maps->temporary[i]) + shader_addline(buffer, "vec4 R%lu;\n", i); + } + + /* Declare attributes */ + for (i = 0; i < This->baseShader.limits.attributes; i++) { + if (reg_maps->attributes[i]) + shader_addline(buffer, "attribute vec4 attrib%i;\n", i); + } + + /* Declare loop register aL */ + if (reg_maps->loop) { + shader_addline(buffer, "int aL;\n"); + shader_addline(buffer, "int tmpInt;\n"); + } + + /* Temporary variables for matrix operations */ + shader_addline(buffer, "vec4 tmp0;\n"); + shader_addline(buffer, "vec4 tmp1;\n"); + + /* Start the main program */ + shader_addline(buffer, "void main() {\n"); +} + +/***************************************************************************** + * Functions to generate GLSL strings from DirectX Shader bytecode begin here. + * + * For more information, see http://wiki.winehq.org/DirectX-Shaders + ****************************************************************************/ + +/* Prototypes */ +static void shader_glsl_add_src_param(SHADER_OPCODE_ARG* arg, const DWORD param, + const DWORD addr_token, DWORD mask, glsl_src_param_t *src_param); + +/** Used for opcode modifiers - They multiply the result by the specified amount */ +static const char * const shift_glsl_tab[] = { + "", /* 0 (none) */ + "2.0 * ", /* 1 (x2) */ + "4.0 * ", /* 2 (x4) */ + "8.0 * ", /* 3 (x8) */ + "16.0 * ", /* 4 (x16) */ + "32.0 * ", /* 5 (x32) */ + "", /* 6 (x64) */ + "", /* 7 (x128) */ + "", /* 8 (d256) */ + "", /* 9 (d128) */ + "", /* 10 (d64) */ + "", /* 11 (d32) */ + "0.0625 * ", /* 12 (d16) */ + "0.125 * ", /* 13 (d8) */ + "0.25 * ", /* 14 (d4) */ + "0.5 * " /* 15 (d2) */ +}; + +/* Generate a GLSL parameter that does the input modifier computation and return the input register/mask to use */ +static void shader_glsl_gen_modifier ( + const DWORD instr, + const char *in_reg, + const char *in_regswizzle, + char *out_str) { + + out_str[0] = 0; + + if (instr == WINED3DSIO_TEXKILL) + return; + + switch (instr & WINED3DSP_SRCMOD_MASK) { + case WINED3DSPSM_DZ: /* Need to handle this in the instructions itself (texld & texcrd). */ + case WINED3DSPSM_DW: + case WINED3DSPSM_NONE: + sprintf(out_str, "%s%s", in_reg, in_regswizzle); + break; + case WINED3DSPSM_NEG: + sprintf(out_str, "-%s%s", in_reg, in_regswizzle); + break; + case WINED3DSPSM_NOT: + sprintf(out_str, "!%s%s", in_reg, in_regswizzle); + break; + case WINED3DSPSM_BIAS: + sprintf(out_str, "(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle); + break; + case WINED3DSPSM_BIASNEG: + sprintf(out_str, "-(%s%s - vec4(0.5)%s)", in_reg, in_regswizzle, in_regswizzle); + break; + case WINED3DSPSM_SIGN: + sprintf(out_str, "(2.0 * (%s%s - 0.5))", in_reg, in_regswizzle); + break; + case WINED3DSPSM_SIGNNEG: + sprintf(out_str, "-(2.0 * (%s%s - 0.5))", in_reg, in_regswizzle); + break; + case WINED3DSPSM_COMP: + sprintf(out_str, "(1.0 - %s%s)", in_reg, in_regswizzle); + break; + case WINED3DSPSM_X2: + sprintf(out_str, "(2.0 * %s%s)", in_reg, in_regswizzle); + break; + case WINED3DSPSM_X2NEG: + sprintf(out_str, "-(2.0 * %s%s)", in_reg, in_regswizzle); + break; + case WINED3DSPSM_ABS: + sprintf(out_str, "abs(%s%s)", in_reg, in_regswizzle); + break; + case WINED3DSPSM_ABSNEG: + sprintf(out_str, "-abs(%s%s)", in_reg, in_regswizzle); + break; + default: + FIXME("Unhandled modifier %u\n", (instr & WINED3DSP_SRCMOD_MASK)); + sprintf(out_str, "%s%s", in_reg, in_regswizzle); + } +} + +/** Writes the GLSL variable name that corresponds to the register that the + * DX opcode parameter is trying to access */ +static void shader_glsl_get_register_name( + const DWORD param, + const DWORD addr_token, + char* regstr, + BOOL* is_color, + SHADER_OPCODE_ARG* arg) { + + /* oPos, oFog and oPts in D3D */ + static const char * const hwrastout_reg_names[] = { "gl_Position", "gl_FogFragCoord", "gl_PointSize" }; + + DWORD reg = param & WINED3DSP_REGNUM_MASK; + DWORD regtype = shader_get_regtype(param); + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + WineD3D_GL_Info* gl_info = &deviceImpl->adapter->gl_info; + + char pshader = shader_is_pshader_version(This->baseShader.hex_version); + char tmpStr[50]; + + *is_color = FALSE; + + switch (regtype) { + case WINED3DSPR_TEMP: + sprintf(tmpStr, "R%u", reg); + break; + case WINED3DSPR_INPUT: + if (pshader) { + /* Pixel shaders >= 3.0 */ + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) + sprintf(tmpStr, "IN%u", reg); + else { + if (reg==0) + strcpy(tmpStr, "gl_Color"); + else + strcpy(tmpStr, "gl_SecondaryColor"); + } + } else { + if (vshader_input_is_color((IWineD3DVertexShader*) This, reg)) + *is_color = TRUE; + sprintf(tmpStr, "attrib%u", reg); + } + break; + case WINED3DSPR_CONST: + { + const char* prefix = pshader? "PC":"VC"; + + /* Relative addressing */ + if (param & WINED3DSHADER_ADDRMODE_RELATIVE) { + + /* Relative addressing on shaders 2.0+ have a relative address token, + * prior to that, it was hard-coded as "A0.x" because there's only 1 register */ + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2) { + glsl_src_param_t rel_param; + shader_glsl_add_src_param(arg, addr_token, 0, WINED3DSP_WRITEMASK_0, &rel_param); + sprintf(tmpStr, "%s[%s + %u]", prefix, rel_param.param_str, reg); + } else + sprintf(tmpStr, "%s[A0.x + %u]", prefix, reg); + + } else + sprintf(tmpStr, "%s[%u]", prefix, reg); + + break; + } + case WINED3DSPR_CONSTINT: + if (pshader) + sprintf(tmpStr, "PI[%u]", reg); + else + sprintf(tmpStr, "VI[%u]", reg); + break; + case WINED3DSPR_CONSTBOOL: + if (pshader) + sprintf(tmpStr, "PB[%u]", reg); + else + sprintf(tmpStr, "VB[%u]", reg); + break; + case WINED3DSPR_TEXTURE: /* case WINED3DSPR_ADDR: */ + if (pshader) { + sprintf(tmpStr, "T%u", reg); + } else { + sprintf(tmpStr, "A%u", reg); + } + break; + case WINED3DSPR_LOOP: + sprintf(tmpStr, "aL"); + break; + case WINED3DSPR_SAMPLER: + if (pshader) + sprintf(tmpStr, "Psampler%u", reg); + else + sprintf(tmpStr, "Vsampler%u", reg); + break; + case WINED3DSPR_COLOROUT: + if (reg >= GL_LIMITS(buffers)) { + WARN("Write to render target %u, only %d supported\n", reg, 4); + } + if (GL_SUPPORT(ARB_DRAW_BUFFERS)) { + sprintf(tmpStr, "gl_FragData[%u]", reg); + } else { /* On older cards with GLSL support like the GeforceFX there's only one buffer. */ + sprintf(tmpStr, "gl_FragColor"); + } + break; + case WINED3DSPR_RASTOUT: + sprintf(tmpStr, "%s", hwrastout_reg_names[reg]); + break; + case WINED3DSPR_DEPTHOUT: + sprintf(tmpStr, "gl_FragDepth"); + break; + case WINED3DSPR_ATTROUT: + if (reg == 0) { + sprintf(tmpStr, "gl_FrontColor"); + } else { + sprintf(tmpStr, "gl_FrontSecondaryColor"); + } + break; + case WINED3DSPR_TEXCRDOUT: + /* Vertex shaders >= 3.0: WINED3DSPR_OUTPUT */ + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) + sprintf(tmpStr, "OUT%u", reg); + else + sprintf(tmpStr, "gl_TexCoord[%u]", reg); + break; + case WINED3DSPR_MISCTYPE: + if (reg == 0) { + /* vPos */ + sprintf(tmpStr, "gl_FragCoord"); + } else { + /* gl_FrontFacing could be used for vFace, but note that + * gl_FrontFacing is a bool, while vFace is a float for + * which the sign determines front/back */ + FIXME("Unhandled misctype register %d\n", reg); + sprintf(tmpStr, "unrecognized_register"); + } + break; + default: + FIXME("Unhandled register name Type(%d)\n", regtype); + sprintf(tmpStr, "unrecognized_register"); + break; + } + + strcat(regstr, tmpStr); +} + +/* Get the GLSL write mask for the destination register */ +static DWORD shader_glsl_get_write_mask(const DWORD param, char *write_mask) { + char *ptr = write_mask; + DWORD mask = param & WINED3DSP_WRITEMASK_ALL; + + if (shader_is_scalar(param)) { + mask = WINED3DSP_WRITEMASK_0; + } else { + *ptr++ = '.'; + if (param & WINED3DSP_WRITEMASK_0) *ptr++ = 'x'; + if (param & WINED3DSP_WRITEMASK_1) *ptr++ = 'y'; + if (param & WINED3DSP_WRITEMASK_2) *ptr++ = 'z'; + if (param & WINED3DSP_WRITEMASK_3) *ptr++ = 'w'; + } + + *ptr = '\0'; + + return mask; +} + +static size_t shader_glsl_get_write_mask_size(DWORD write_mask) { + size_t size = 0; + + if (write_mask & WINED3DSP_WRITEMASK_0) ++size; + if (write_mask & WINED3DSP_WRITEMASK_1) ++size; + if (write_mask & WINED3DSP_WRITEMASK_2) ++size; + if (write_mask & WINED3DSP_WRITEMASK_3) ++size; + + return size; +} + +static void shader_glsl_get_swizzle(const DWORD param, BOOL fixup, DWORD mask, char *swizzle_str) { + /* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra", + * but addressed as "rgba". To fix this we need to swap the register's x + * and z components. */ + DWORD swizzle = (param & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT; + const char *swizzle_chars = fixup ? "zyxw" : "xyzw"; + char *ptr = swizzle_str; + + if (!shader_is_scalar(param)) { + *ptr++ = '.'; + /* swizzle bits fields: wwzzyyxx */ + if (mask & WINED3DSP_WRITEMASK_0) *ptr++ = swizzle_chars[swizzle & 0x03]; + if (mask & WINED3DSP_WRITEMASK_1) *ptr++ = swizzle_chars[(swizzle >> 2) & 0x03]; + if (mask & WINED3DSP_WRITEMASK_2) *ptr++ = swizzle_chars[(swizzle >> 4) & 0x03]; + if (mask & WINED3DSP_WRITEMASK_3) *ptr++ = swizzle_chars[(swizzle >> 6) & 0x03]; + } + + *ptr = '\0'; +} + +/* From a given parameter token, generate the corresponding GLSL string. + * Also, return the actual register name and swizzle in case the + * caller needs this information as well. */ +static void shader_glsl_add_src_param(SHADER_OPCODE_ARG* arg, const DWORD param, + const DWORD addr_token, DWORD mask, glsl_src_param_t *src_param) { + BOOL is_color = FALSE; + char swizzle_str[6]; + + src_param->reg_name[0] = '\0'; + src_param->param_str[0] = '\0'; + swizzle_str[0] = '\0'; + + shader_glsl_get_register_name(param, addr_token, src_param->reg_name, &is_color, arg); + + shader_glsl_get_swizzle(param, is_color, mask, swizzle_str); + shader_glsl_gen_modifier(param, src_param->reg_name, swizzle_str, src_param->param_str); +} + +/* From a given parameter token, generate the corresponding GLSL string. + * Also, return the actual register name and swizzle in case the + * caller needs this information as well. */ +static DWORD shader_glsl_add_dst_param(SHADER_OPCODE_ARG* arg, const DWORD param, + const DWORD addr_token, glsl_dst_param_t *dst_param) { + BOOL is_color = FALSE; + + dst_param->mask_str[0] = '\0'; + dst_param->reg_name[0] = '\0'; + + shader_glsl_get_register_name(param, addr_token, dst_param->reg_name, &is_color, arg); + return shader_glsl_get_write_mask(param, dst_param->mask_str); +} + +/* Append the destination part of the instruction to the buffer, return the effective write mask */ +static DWORD shader_glsl_append_dst_ext(SHADER_BUFFER *buffer, SHADER_OPCODE_ARG *arg, const DWORD param) { + glsl_dst_param_t dst_param; + DWORD mask; + int shift; + + mask = shader_glsl_add_dst_param(arg, param, arg->dst_addr, &dst_param); + + if(mask) { + shift = (param & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT; + shader_addline(buffer, "%s%s = %s(", dst_param.reg_name, dst_param.mask_str, shift_glsl_tab[shift]); + } + + return mask; +} + +/* Append the destination part of the instruction to the buffer, return the effective write mask */ +static DWORD shader_glsl_append_dst(SHADER_BUFFER *buffer, SHADER_OPCODE_ARG *arg) { + return shader_glsl_append_dst_ext(buffer, arg, arg->dst); +} + +/** Process GLSL instruction modifiers */ +void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG* arg) { + + DWORD mask = arg->dst & WINED3DSP_DSTMOD_MASK; + + if (arg->opcode->dst_token && mask != 0) { + glsl_dst_param_t dst_param; + + shader_glsl_add_dst_param(arg, arg->dst, 0, &dst_param); + + if (mask & WINED3DSPDM_SATURATE) { + /* _SAT means to clamp the value of the register to between 0 and 1 */ + shader_addline(arg->buffer, "%s%s = clamp(%s%s, 0.0, 1.0);\n", dst_param.reg_name, + dst_param.mask_str, dst_param.reg_name, dst_param.mask_str); + } + if (mask & WINED3DSPDM_MSAMPCENTROID) { + FIXME("_centroid modifier not handled\n"); + } + if (mask & WINED3DSPDM_PARTIALPRECISION) { + /* MSDN says this modifier can be safely ignored, so that's what we'll do. */ + } + } +} + +static inline const char* shader_get_comp_op( + const DWORD opcode) { + + DWORD op = (opcode & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT; + switch (op) { + case COMPARISON_GT: return ">"; + case COMPARISON_EQ: return "=="; + case COMPARISON_GE: return ">="; + case COMPARISON_LT: return "<"; + case COMPARISON_NE: return "!="; + case COMPARISON_LE: return "<="; + default: + FIXME("Unrecognized comparison value: %u\n", op); + return "(\?\?)"; + } +} + +static void shader_glsl_get_sample_function(DWORD sampler_type, BOOL projected, glsl_sample_function_t *sample_function) { + /* Note that there's no such thing as a projected cube texture. */ + switch(sampler_type) { + case WINED3DSTT_1D: + sample_function->name = projected ? "texture1DProj" : "texture1D"; + sample_function->coord_mask = WINED3DSP_WRITEMASK_0; + break; + case WINED3DSTT_2D: + sample_function->name = projected ? "texture2DProj" : "texture2D"; + sample_function->coord_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1; + break; + case WINED3DSTT_CUBE: + sample_function->name = "textureCube"; + sample_function->coord_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + break; + case WINED3DSTT_VOLUME: + sample_function->name = projected ? "texture3DProj" : "texture3D"; + sample_function->coord_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + break; + default: + sample_function->name = ""; + FIXME("Unrecognized sampler type: %#x;\n", sampler_type); + break; + } +} + + +/***************************************************************************** + * + * Begin processing individual instruction opcodes + * + ****************************************************************************/ + +/* Generate GLSL arithmetic functions (dst = src1 + src2) */ +void shader_glsl_arith(SHADER_OPCODE_ARG* arg) { + CONST SHADER_OPCODE* curOpcode = arg->opcode; + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + DWORD write_mask; + char op; + + /* Determine the GLSL operator to use based on the opcode */ + switch (curOpcode->opcode) { + case WINED3DSIO_MUL: op = '*'; break; + case WINED3DSIO_ADD: op = '+'; break; + case WINED3DSIO_SUB: op = '-'; break; + default: + op = ' '; + FIXME("Opcode %s not yet handled in GLSL\n", curOpcode->name); + break; + } + + write_mask = shader_glsl_append_dst(buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + shader_addline(buffer, "%s %c %s);\n", src0_param.param_str, op, src1_param.param_str); +} + +/* Process the WINED3DSIO_MOV opcode using GLSL (dst = src) */ +void shader_glsl_mov(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src0_param; + DWORD write_mask; + + write_mask = shader_glsl_append_dst(buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param); + + /* In vs_1_1 WINED3DSIO_MOV can write to the address register. In later + * shader versions WINED3DSIO_MOVA is used for this. */ + if ((WINED3DSHADER_VERSION_MAJOR(shader->baseShader.hex_version) == 1 && + !shader_is_pshader_version(shader->baseShader.hex_version) && + shader_get_regtype(arg->dst) == WINED3DSPR_ADDR) || + arg->opcode->opcode == WINED3DSIO_MOVA) { + /* We need to *round* to the nearest int here. */ + size_t mask_size = shader_glsl_get_write_mask_size(write_mask); + if (mask_size > 1) { + shader_addline(buffer, "ivec%d(floor(abs(%s) + vec%d(0.5)) * sign(%s)));\n", mask_size, src0_param.param_str, mask_size, src0_param.param_str); + } else { + shader_addline(buffer, "int(floor(abs(%s) + 0.5) * sign(%s)));\n", src0_param.param_str, src0_param.param_str); + } + } else { + shader_addline(buffer, "%s);\n", src0_param.param_str); + } +} + +/* Process the dot product operators DP3 and DP4 in GLSL (dst = dot(src0, src1)) */ +void shader_glsl_dot(SHADER_OPCODE_ARG* arg) { + CONST SHADER_OPCODE* curOpcode = arg->opcode; + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + DWORD dst_write_mask, src_write_mask; + size_t dst_size = 0; + + dst_write_mask = shader_glsl_append_dst(buffer, arg); + dst_size = shader_glsl_get_write_mask_size(dst_write_mask); + + /* dp3 works on vec3, dp4 on vec4 */ + if (curOpcode->opcode == WINED3DSIO_DP4) { + src_write_mask = WINED3DSP_WRITEMASK_ALL; + } else { + src_write_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + } + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_write_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], src_write_mask, &src1_param); + + if (dst_size > 1) { + shader_addline(buffer, "vec%d(dot(%s, %s)));\n", dst_size, src0_param.param_str, src1_param.param_str); + } else { + shader_addline(buffer, "dot(%s, %s));\n", src0_param.param_str, src1_param.param_str); + } +} + +/* Note that this instruction has some restrictions. The destination write mask + * can't contain the w component, and the source swizzles have to be .xyzw */ +void shader_glsl_cross(SHADER_OPCODE_ARG *arg) { + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + char dst_mask[6]; + + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], src_mask, &src1_param); + shader_addline(arg->buffer, "cross(%s, %s).%s);\n", src0_param.param_str, src1_param.param_str, dst_mask); +} + +/* Process the WINED3DSIO_POW instruction in GLSL (dst = |src0|^src1) + * Src0 and src1 are scalars. Note that D3D uses the absolute of src0, while + * GLSL uses the value as-is. */ +void shader_glsl_pow(SHADER_OPCODE_ARG *arg) { + SHADER_BUFFER *buffer = arg->buffer; + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + DWORD dst_write_mask; + size_t dst_size; + + dst_write_mask = shader_glsl_append_dst(buffer, arg); + dst_size = shader_glsl_get_write_mask_size(dst_write_mask); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0, &src1_param); + + if (dst_size > 1) { + shader_addline(buffer, "vec%d(pow(abs(%s), %s)));\n", dst_size, src0_param.param_str, src1_param.param_str); + } else { + shader_addline(buffer, "pow(abs(%s), %s));\n", src0_param.param_str, src1_param.param_str); + } +} + +/* Map the opcode 1-to-1 to the GL code (arg->dst = instruction(src0, src1, ...) */ +void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg) { + CONST SHADER_OPCODE* curOpcode = arg->opcode; + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src_param; + const char *instruction; + char arguments[256]; + DWORD write_mask; + unsigned i; + + /* Determine the GLSL function to use based on the opcode */ + /* TODO: Possibly make this a table for faster lookups */ + switch (curOpcode->opcode) { + case WINED3DSIO_MIN: instruction = "min"; break; + case WINED3DSIO_MAX: instruction = "max"; break; + case WINED3DSIO_ABS: instruction = "abs"; break; + case WINED3DSIO_FRC: instruction = "fract"; break; + case WINED3DSIO_NRM: instruction = "normalize"; break; + case WINED3DSIO_LOGP: + case WINED3DSIO_LOG: instruction = "log2"; break; + case WINED3DSIO_EXP: instruction = "exp2"; break; + case WINED3DSIO_SGN: instruction = "sign"; break; + case WINED3DSIO_DSX: instruction = "dFdx"; break; + case WINED3DSIO_DSY: instruction = "dFdy"; break; + default: instruction = ""; + FIXME("Opcode %s not yet handled in GLSL\n", curOpcode->name); + break; + } + + write_mask = shader_glsl_append_dst(buffer, arg); + + arguments[0] = '\0'; + if (curOpcode->num_params > 0) { + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src_param); + strcat(arguments, src_param.param_str); + for (i = 2; i < curOpcode->num_params; ++i) { + strcat(arguments, ", "); + shader_glsl_add_src_param(arg, arg->src[i-1], arg->src_addr[i-1], write_mask, &src_param); + strcat(arguments, src_param.param_str); + } + } + + shader_addline(buffer, "%s(%s));\n", instruction, arguments); +} + +/** Process the WINED3DSIO_EXPP instruction in GLSL: + * For shader model 1.x, do the following (and honor the writemask, so use a temporary variable): + * dst.x = 2^(floor(src)) + * dst.y = src - floor(src) + * dst.z = 2^src (partial precision is allowed, but optional) + * dst.w = 1.0; + * For 2.0 shaders, just do this (honoring writemask and swizzle): + * dst = 2^src; (partial precision is allowed, but optional) + */ +void shader_glsl_expp(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl *shader = (IWineD3DBaseShaderImpl *)arg->shader; + glsl_src_param_t src_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src_param); + + if (shader->baseShader.hex_version < WINED3DPS_VERSION(2,0)) { + char dst_mask[6]; + + shader_addline(arg->buffer, "tmp0.x = exp2(floor(%s));\n", src_param.param_str); + shader_addline(arg->buffer, "tmp0.y = %s - floor(%s);\n", src_param.param_str, src_param.param_str); + shader_addline(arg->buffer, "tmp0.z = exp2(%s);\n", src_param.param_str); + shader_addline(arg->buffer, "tmp0.w = 1.0;\n"); + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_addline(arg->buffer, "tmp0%s);\n", dst_mask); + } else { + DWORD write_mask; + size_t mask_size; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + mask_size = shader_glsl_get_write_mask_size(write_mask); + + if (mask_size > 1) { + shader_addline(arg->buffer, "vec%d(exp2(%s)));\n", mask_size, src_param.param_str); + } else { + shader_addline(arg->buffer, "exp2(%s));\n", src_param.param_str); + } + } +} + +/** Process the RCP (reciprocal or inverse) opcode in GLSL (dst = 1 / src) */ +void shader_glsl_rcp(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src_param; + DWORD write_mask; + size_t mask_size; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + mask_size = shader_glsl_get_write_mask_size(write_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &src_param); + + if (mask_size > 1) { + shader_addline(arg->buffer, "vec%d(1.0 / %s));\n", mask_size, src_param.param_str); + } else { + shader_addline(arg->buffer, "1.0 / %s);\n", src_param.param_str); + } +} + +void shader_glsl_rsq(SHADER_OPCODE_ARG* arg) { + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src_param; + DWORD write_mask; + size_t mask_size; + + write_mask = shader_glsl_append_dst(buffer, arg); + mask_size = shader_glsl_get_write_mask_size(write_mask); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &src_param); + + if (mask_size > 1) { + shader_addline(buffer, "vec%d(inversesqrt(%s)));\n", mask_size, src_param.param_str); + } else { + shader_addline(buffer, "inversesqrt(%s));\n", src_param.param_str); + } +} + +/** Process signed comparison opcodes in GLSL. */ +void shader_glsl_compare(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + DWORD write_mask; + size_t mask_size; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + mask_size = shader_glsl_get_write_mask_size(write_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + + if (mask_size > 1) { + const char *compare; + + switch(arg->opcode->opcode) { + case WINED3DSIO_SLT: compare = "lessThan"; break; + case WINED3DSIO_SGE: compare = "greaterThanEqual"; break; + default: compare = ""; + FIXME("Can't handle opcode %s\n", arg->opcode->name); + } + + shader_addline(arg->buffer, "vec%d(%s(%s, %s)));\n", mask_size, compare, + src0_param.param_str, src1_param.param_str); + } else { + const char *compare; + + switch(arg->opcode->opcode) { + case WINED3DSIO_SLT: compare = "<"; break; + case WINED3DSIO_SGE: compare = ">="; break; + default: compare = ""; + FIXME("Can't handle opcode %s\n", arg->opcode->name); + } + + shader_addline(arg->buffer, "(%s %s %s) ? 1.0 : 0.0);\n", + src0_param.param_str, compare, src1_param.param_str); + } +} + +/** Process CMP instruction in GLSL (dst = src0 >= 0.0 ? src1 : src2), per channel */ +void shader_glsl_cmp(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + glsl_src_param_t src2_param; + DWORD write_mask, cmp_channel = 0; + unsigned int i, j; + + /* Cycle through all source0 channels */ + for (i=0; i<4; i++) { + write_mask = 0; + /* Find the destination channels which use the current source0 channel */ + for (j=0; j<4; j++) { + if ( ((arg->src[0] >> (WINED3DSP_SWIZZLE_SHIFT + 2*j)) & 0x3) == i ) { + write_mask |= WINED3DSP_WRITEMASK_0 << j; + cmp_channel = WINED3DSP_WRITEMASK_0 << j; + } + } + write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask)); + if (!write_mask) continue; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], cmp_channel, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); + + shader_addline(arg->buffer, "%s >= 0.0 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); + } +} + +/** Process the CND opcode in GLSL (dst = (src0 > 0.5) ? src1 : src2) */ +/* For ps 1.1-1.3, only a single component of src0 is used. For ps 1.4 + * the compare is done per component of src0. */ +void shader_glsl_cnd(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader; + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + glsl_src_param_t src2_param; + DWORD write_mask, cmp_channel = 0; + unsigned int i, j; + + if (shader->baseShader.hex_version < WINED3DPS_VERSION(1, 4)) { + write_mask = shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); + shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); + return; + } + /* Cycle through all source0 channels */ + for (i=0; i<4; i++) { + write_mask = 0; + /* Find the destination channels which use the current source0 channel */ + for (j=0; j<4; j++) { + if ( ((arg->src[0] >> (WINED3DSP_SWIZZLE_SHIFT + 2*j)) & 0x3) == i ) { + write_mask |= WINED3DSP_WRITEMASK_0 << j; + cmp_channel = WINED3DSP_WRITEMASK_0 << j; + } + } + write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask)); + if (!write_mask) continue; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], cmp_channel, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); + + shader_addline(arg->buffer, "%s > 0.5 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); + } +} + +/** GLSL code generation for WINED3DSIO_MAD: Multiply the first 2 opcodes, then add the last */ +void shader_glsl_mad(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + glsl_src_param_t src2_param; + DWORD write_mask; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); + shader_addline(arg->buffer, "(%s * %s) + %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); +} + +/** Handles transforming all WINED3DSIO_M?x? opcodes for + Vertex shaders to GLSL codes */ +void shader_glsl_mnxn(SHADER_OPCODE_ARG* arg) { + int i; + int nComponents = 0; + SHADER_OPCODE_ARG tmpArg; + + memset(&tmpArg, 0, sizeof(SHADER_OPCODE_ARG)); + + /* Set constants for the temporary argument */ + tmpArg.shader = arg->shader; + tmpArg.buffer = arg->buffer; + tmpArg.src[0] = arg->src[0]; + tmpArg.src_addr[0] = arg->src_addr[0]; + tmpArg.src_addr[1] = arg->src_addr[1]; + tmpArg.reg_maps = arg->reg_maps; + + switch(arg->opcode->opcode) { + case WINED3DSIO_M4x4: + nComponents = 4; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP4); + break; + case WINED3DSIO_M4x3: + nComponents = 3; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP4); + break; + case WINED3DSIO_M3x4: + nComponents = 4; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3); + break; + case WINED3DSIO_M3x3: + nComponents = 3; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3); + break; + case WINED3DSIO_M3x2: + nComponents = 2; + tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3); + break; + default: + break; + } + + for (i = 0; i < nComponents; i++) { + tmpArg.dst = ((arg->dst) & ~WINED3DSP_WRITEMASK_ALL)|(WINED3DSP_WRITEMASK_0<src[1]+i; + shader_glsl_dot(&tmpArg); + } +} + +/** + The LRP instruction performs a component-wise linear interpolation + between the second and third operands using the first operand as the + blend factor. Equation: (dst = src2 + src0 * (src1 - src2)) + This is equivalent to mix(src2, src1, src0); +*/ +void shader_glsl_lrp(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + glsl_src_param_t src2_param; + DWORD write_mask; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], write_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); + shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); + + shader_addline(arg->buffer, "mix(%s, %s, %s));\n", + src2_param.param_str, src1_param.param_str, src0_param.param_str); +} + +/** Process the WINED3DSIO_LIT instruction in GLSL: + * dst.x = dst.w = 1.0 + * dst.y = (src0.x > 0) ? src0.x + * dst.z = (src0.x > 0) ? ((src0.y > 0) ? pow(src0.y, src.w) : 0) : 0 + * where src.w is clamped at +- 128 + */ +void shader_glsl_lit(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + glsl_src_param_t src3_param; + char dst_mask[6]; + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_1, &src1_param); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &src3_param); + + shader_addline(arg->buffer, "vec4(1.0, (%s > 0.0 ? %s : 0.0), (%s > 0.0 ? ((%s > 0.0) ? pow(%s, clamp(%s, -128.0, 128.0)) : 0.0) : 0.0), 1.0)%s);\n", + src0_param.param_str, src0_param.param_str, src0_param.param_str, src1_param.param_str, src1_param.param_str, src3_param.param_str, dst_mask); +} + +/** Process the WINED3DSIO_DST instruction in GLSL: + * dst.x = 1.0 + * dst.y = src0.x * src0.y + * dst.z = src0.z + * dst.w = src1.w + */ +void shader_glsl_dst(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0y_param; + glsl_src_param_t src0z_param; + glsl_src_param_t src1y_param; + glsl_src_param_t src1w_param; + char dst_mask[6]; + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_1, &src0y_param); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_2, &src0z_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_1, &src1y_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_3, &src1w_param); + + shader_addline(arg->buffer, "vec4(1.0, %s * %s, %s, %s))%s;\n", + src0y_param.param_str, src1y_param.param_str, src0z_param.param_str, src1w_param.param_str, dst_mask); +} + +/** Process the WINED3DSIO_SINCOS instruction in GLSL: + * VS 2.0 requires that specific cosine and sine constants be passed to this instruction so the hardware + * can handle it. But, these functions are built-in for GLSL, so we can just ignore the last 2 params. + * + * dst.x = cos(src0.?) + * dst.y = sin(src0.?) + * dst.z = dst.z + * dst.w = dst.w + */ +void shader_glsl_sincos(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + DWORD write_mask; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + + switch (write_mask) { + case WINED3DSP_WRITEMASK_0: + shader_addline(arg->buffer, "cos(%s));\n", src0_param.param_str); + break; + + case WINED3DSP_WRITEMASK_1: + shader_addline(arg->buffer, "sin(%s));\n", src0_param.param_str); + break; + + case (WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1): + shader_addline(arg->buffer, "vec2(cos(%s), sin(%s)));\n", src0_param.param_str, src0_param.param_str); + break; + + default: + ERR("Write mask should be .x, .y or .xy\n"); + break; + } +} + +/** Process the WINED3DSIO_LOOP instruction in GLSL: + * Start a for() loop where src1.y is the initial value of aL, + * increment aL by src1.z for a total of src1.x iterations. + * Need to use a temporary variable for this operation. + */ +/* FIXME: I don't think nested loops will work correctly this way. */ +void shader_glsl_loop(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src1_param; + + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_ALL, &src1_param); + + shader_addline(arg->buffer, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n", + src1_param.reg_name, src1_param.reg_name, src1_param.reg_name); +} + +void shader_glsl_end(SHADER_OPCODE_ARG* arg) { + shader_addline(arg->buffer, "}\n"); +} + +void shader_glsl_rep(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_addline(arg->buffer, "for (tmpInt = 0; tmpInt < %s; tmpInt++) {\n", src0_param.param_str); +} + +void shader_glsl_if(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_addline(arg->buffer, "if (%s) {\n", src0_param.param_str); +} + +void shader_glsl_ifc(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0, &src1_param); + + shader_addline(arg->buffer, "if (%s %s %s) {\n", + src0_param.param_str, shader_get_comp_op(arg->opcode_token), src1_param.param_str); +} + +void shader_glsl_else(SHADER_OPCODE_ARG* arg) { + shader_addline(arg->buffer, "} else {\n"); +} + +void shader_glsl_break(SHADER_OPCODE_ARG* arg) { + shader_addline(arg->buffer, "break;\n"); +} + +/* FIXME: According to MSDN the compare is done per component. */ +void shader_glsl_breakc(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0, &src1_param); + + shader_addline(arg->buffer, "if (%s %s %s) break;\n", + src0_param.param_str, shader_get_comp_op(arg->opcode_token), src1_param.param_str); +} + +void shader_glsl_label(SHADER_OPCODE_ARG* arg) { + + DWORD snum = (arg->src[0]) & WINED3DSP_REGNUM_MASK; + shader_addline(arg->buffer, "}\n"); + shader_addline(arg->buffer, "void subroutine%lu () {\n", snum); +} + +void shader_glsl_call(SHADER_OPCODE_ARG* arg) { + DWORD snum = (arg->src[0]) & WINED3DSP_REGNUM_MASK; + shader_addline(arg->buffer, "subroutine%lu();\n", snum); +} + +void shader_glsl_callnz(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src1_param; + + DWORD snum = (arg->src[0]) & WINED3DSP_REGNUM_MASK; + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0, &src1_param); + shader_addline(arg->buffer, "if (%s) subroutine%lu();\n", src1_param.param_str, snum); +} + +/********************************************* + * Pixel Shader Specific Code begins here + ********************************************/ +void pshader_glsl_tex(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD hex_version = This->baseShader.hex_version; + char dst_swizzle[6]; + glsl_sample_function_t sample_function; + DWORD sampler_type; + DWORD sampler_idx; + BOOL projected; + DWORD mask = 0; + + /* All versions have a destination register */ + shader_glsl_append_dst(arg->buffer, arg); + + /* 1.0-1.4: Use destination register as sampler source. + * 2.0+: Use provided sampler source. */ + if (hex_version < WINED3DPS_VERSION(1,4)) { + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + DWORD flags; + + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + flags = deviceImpl->stateBlock->textureState[sampler_idx][WINED3DTSS_TEXTURETRANSFORMFLAGS]; + + if (flags & WINED3DTTFF_PROJECTED) { + projected = TRUE; + switch (flags & ~WINED3DTTFF_PROJECTED) { + case WINED3DTTFF_COUNT1: FIXME("WINED3DTTFF_PROJECTED with WINED3DTTFF_COUNT1?\n"); break; + case WINED3DTTFF_COUNT2: mask = WINED3DSP_WRITEMASK_1; break; + case WINED3DTTFF_COUNT3: mask = WINED3DSP_WRITEMASK_2; break; + case WINED3DTTFF_COUNT4: + case WINED3DTTFF_DISABLE: mask = WINED3DSP_WRITEMASK_3; break; + } + } else { + projected = FALSE; + } + } else if (hex_version < WINED3DPS_VERSION(2,0)) { + DWORD src_mod = arg->src[0] & WINED3DSP_SRCMOD_MASK; + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + + if (src_mod == WINED3DSPSM_DZ) { + projected = TRUE; + mask = WINED3DSP_WRITEMASK_2; + } else if (src_mod == WINED3DSPSM_DW) { + projected = TRUE; + mask = WINED3DSP_WRITEMASK_3; + } else { + projected = FALSE; + } + } else { + sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK; + if(arg->opcode_token & WINED3DSI_TEXLD_PROJECT) { + /* ps 2.0 texldp instruction always divides by the fourth component. */ + projected = TRUE; + mask = WINED3DSP_WRITEMASK_3; + } else { + projected = FALSE; + } + } + + sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; + shader_glsl_get_sample_function(sampler_type, projected, &sample_function); + mask |= sample_function.coord_mask; + + if (hex_version < WINED3DPS_VERSION(2,0)) { + shader_glsl_get_write_mask(arg->dst, dst_swizzle); + } else { + shader_glsl_get_swizzle(arg->src[1], FALSE, arg->dst, dst_swizzle); + } + + /* 1.0-1.3: Use destination register as coordinate source. + 1.4+: Use provided coordinate source register. */ + if (hex_version < WINED3DPS_VERSION(1,4)) { + char coord_mask[6]; + shader_glsl_get_write_mask(mask, coord_mask); + shader_addline(arg->buffer, "%s(Psampler%u, T%u%s)%s);\n", + sample_function.name, sampler_idx, sampler_idx, coord_mask, dst_swizzle); + } else { + glsl_src_param_t coord_param; + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], mask, &coord_param); + shader_addline(arg->buffer, "%s(Psampler%u, %s)%s);\n", + sample_function.name, sampler_idx, coord_param.param_str, dst_swizzle); + } +} + +void shader_glsl_texldl(SHADER_OPCODE_ARG* arg) { + IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*)arg->shader; + glsl_sample_function_t sample_function; + glsl_src_param_t coord_param, lod_param; + char dst_swizzle[6]; + DWORD sampler_type; + DWORD sampler_idx; + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_swizzle(arg->src[1], FALSE, arg->dst, dst_swizzle); + + sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK; + sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; + shader_glsl_get_sample_function(sampler_type, FALSE, &sample_function); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], sample_function.coord_mask, &coord_param); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &lod_param); + + if (shader_is_pshader_version(This->baseShader.hex_version)) { + /* The GLSL spec claims the Lod sampling functions are only supported in vertex shaders. + * However, they seem to work just fine in fragment shaders as well. */ + WARN("Using %sLod in fragment shader.\n", sample_function.name); + shader_addline(arg->buffer, "%sLod(Psampler%u, %s, %s)%s);\n", + sample_function.name, sampler_idx, coord_param.param_str, lod_param.param_str, dst_swizzle); + } else { + shader_addline(arg->buffer, "%sLod(Vsampler%u, %s, %s)%s);\n", + sample_function.name, sampler_idx, coord_param.param_str, lod_param.param_str, dst_swizzle); + } +} + +void pshader_glsl_texcoord(SHADER_OPCODE_ARG* arg) { + + /* FIXME: Make this work for more than just 2D textures */ + + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + SHADER_BUFFER* buffer = arg->buffer; + DWORD hex_version = This->baseShader.hex_version; + DWORD write_mask; + char dst_mask[6]; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(write_mask, dst_mask); + + if (hex_version != WINED3DPS_VERSION(1,4)) { + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + shader_addline(buffer, "clamp(gl_TexCoord[%u], 0.0, 1.0)%s);\n", reg, dst_mask); + } else { + DWORD reg = arg->src[0] & WINED3DSP_REGNUM_MASK; + DWORD src_mod = arg->src[0] & WINED3DSP_SRCMOD_MASK; + char dst_swizzle[6]; + + shader_glsl_get_swizzle(arg->src[0], FALSE, write_mask, dst_swizzle); + + if (src_mod == WINED3DSPSM_DZ) { + glsl_src_param_t div_param; + size_t mask_size = shader_glsl_get_write_mask_size(write_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_2, &div_param); + + if (mask_size > 1) { + shader_addline(buffer, "gl_TexCoord[%u]%s / vec%d(%s));\n", reg, dst_swizzle, mask_size, div_param.param_str); + } else { + shader_addline(buffer, "gl_TexCoord[%u]%s / %s);\n", reg, dst_swizzle, div_param.param_str); + } + } else if (src_mod == WINED3DSPSM_DW) { + glsl_src_param_t div_param; + size_t mask_size = shader_glsl_get_write_mask_size(write_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_3, &div_param); + + if (mask_size > 1) { + shader_addline(buffer, "gl_TexCoord[%u]%s / vec%d(%s));\n", reg, dst_swizzle, mask_size, div_param.param_str); + } else { + shader_addline(buffer, "gl_TexCoord[%u]%s / %s);\n", reg, dst_swizzle, div_param.param_str); + } + } else { + shader_addline(buffer, "gl_TexCoord[%u]%s);\n", reg, dst_swizzle); + } + } +} + +/** Process the WINED3DSIO_TEXDP3TEX instruction in GLSL: + * Take a 3-component dot product of the TexCoord[dstreg] and src, + * then perform a 1D texture lookup from stage dstregnum, place into dst. */ +void pshader_glsl_texdp3tex(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + char dst_mask[6]; + DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_addline(arg->buffer, "texture2D(Psampler%u, vec2(dot(gl_TexCoord[%u].xyz, %s), 0.5))%s);\n", + sampler_idx, sampler_idx, src0_param.param_str, dst_mask); +} + +/** Process the WINED3DSIO_TEXDP3 instruction in GLSL: + * Take a 3-component dot product of the TexCoord[dstreg] and src. */ +void pshader_glsl_texdp3(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + DWORD dstreg = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD dst_mask; + size_t mask_size; + + dst_mask = shader_glsl_append_dst(arg->buffer, arg); + mask_size = shader_glsl_get_write_mask_size(dst_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + + if (mask_size > 1) { + shader_addline(arg->buffer, "vec%d(dot(T%u.xyz, %s)));\n", mask_size, dstreg, src0_param.param_str); + } else { + shader_addline(arg->buffer, "dot(T%u.xyz, %s));\n", dstreg, src0_param.param_str); + } +} + +/** Process the WINED3DSIO_TEXDEPTH instruction in GLSL: + * Calculate the depth as dst.x / dst.y */ +void pshader_glsl_texdepth(SHADER_OPCODE_ARG* arg) { + glsl_dst_param_t dst_param; + + shader_glsl_add_dst_param(arg, arg->dst, 0, &dst_param); + + shader_addline(arg->buffer, "gl_FragDepth = %s.x / %s.y;\n", dst_param.reg_name, dst_param.reg_name); +} + +/** Process the WINED3DSIO_TEXM3X2DEPTH instruction in GLSL: + * Last row of a 3x2 matrix multiply, use the result to calculate the depth: + * Calculate tmp0.y = TexCoord[dstreg] . src.xyz; (tmp0.x has already been calculated) + * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y + */ +void pshader_glsl_texm3x2depth(SHADER_OPCODE_ARG* arg) { + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD dstreg = arg->dst & WINED3DSP_REGNUM_MASK; + glsl_src_param_t src0_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + + shader_addline(arg->buffer, "tmp0.y = dot(T%u.xyz, %s);\n", dstreg, src0_param.param_str); + shader_addline(arg->buffer, "gl_FragDepth = (tmp0.y == 0.0) ? 1.0 : clamp(tmp0.x / tmp0.y, 0.0, 1.0);\n"); +} + +/** Process the WINED3DSIO_TEXM3X2PAD instruction in GLSL + * Calculate the 1st of a 2-row matrix multiplication. */ +void pshader_glsl_texm3x2pad(SHADER_OPCODE_ARG* arg) { + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src0_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + shader_addline(buffer, "tmp0.x = dot(T%u.xyz, %s);\n", reg, src0_param.param_str); +} + +/** Process the WINED3DSIO_TEXM3X3PAD instruction in GLSL + * Calculate the 1st or 2nd row of a 3-row matrix multiplication. */ +void pshader_glsl_texm3x3pad(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* shader = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + SHADER_PARSE_STATE* current_state = &shader->baseShader.parse_state; + glsl_src_param_t src0_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + shader_addline(buffer, "tmp0.%c = dot(T%u.xyz, %s);\n", 'x' + current_state->current_row, reg, src0_param.param_str); + current_state->texcoord_w[current_state->current_row++] = reg; +} + +void pshader_glsl_texm3x2tex(SHADER_OPCODE_ARG* arg) { + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + glsl_src_param_t src0_param; + char dst_mask[6]; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + shader_addline(buffer, "tmp0.y = dot(T%u.xyz, %s);\n", reg, src0_param.param_str); + + shader_glsl_append_dst(buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + + /* Sample the texture using the calculated coordinates */ + shader_addline(buffer, "texture2D(Psampler%u, tmp0.xy)%s);\n", reg, dst_mask); +} + +/** Process the WINED3DSIO_TEXM3X3TEX instruction in GLSL + * Perform the 3rd row of a 3x3 matrix multiply, then sample the texture using the calculated coordinates */ +void pshader_glsl_texm3x3tex(SHADER_OPCODE_ARG* arg) { + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + glsl_src_param_t src0_param; + char dst_mask[6]; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; + DWORD sampler_type = arg->reg_maps->samplers[reg] & WINED3DSP_TEXTURETYPE_MASK; + glsl_sample_function_t sample_function; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + shader_addline(arg->buffer, "tmp0.z = dot(T%u.xyz, %s);\n", reg, src0_param.param_str); + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_get_sample_function(sampler_type, FALSE, &sample_function); + + /* Sample the texture using the calculated coordinates */ + shader_addline(arg->buffer, "%s(Psampler%u, tmp0.xyz)%s);\n", sample_function.name, reg, dst_mask); + + current_state->current_row = 0; +} + +/** Process the WINED3DSIO_TEXM3X3 instruction in GLSL + * Perform the 3rd row of a 3x3 matrix multiply */ +void pshader_glsl_texm3x3(SHADER_OPCODE_ARG* arg) { + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + glsl_src_param_t src0_param; + char dst_mask[6]; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_addline(arg->buffer, "vec4(tmp.xy, dot(T%u.xyz, %s), 1.0)%s);\n", reg, src0_param.param_str, dst_mask); + + current_state->current_row = 0; +} + +/** Process the WINED3DSIO_TEXM3X3SPEC instruction in GLSL + * Peform the final texture lookup based on the previous 2 3x3 matrix multiplies */ +void pshader_glsl_texm3x3spec(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* shader = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + char dst_mask[6]; + SHADER_BUFFER* buffer = arg->buffer; + SHADER_PARSE_STATE* current_state = &shader->baseShader.parse_state; + DWORD stype = arg->reg_maps->samplers[reg] & WINED3DSP_TEXTURETYPE_MASK; + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + glsl_sample_function_t sample_function; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], src_mask, &src1_param); + + /* Perform the last matrix multiply operation */ + shader_addline(buffer, "tmp0.z = dot(T%u.xyz, %s);\n", reg, src0_param.param_str); + + /* Calculate reflection vector, 2*(tmp0.src1)*tmp0-src1 + * This is equivalent to reflect(-src1, tmp0); */ + shader_addline(buffer, "tmp0.xyz = reflect(-(%s), tmp0.xyz);\n", src1_param.param_str); + + shader_glsl_append_dst(buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_get_sample_function(stype, FALSE, &sample_function); + + /* Sample the texture */ + shader_addline(buffer, "%s(Psampler%u, tmp0.xyz)%s);\n", sample_function.name, reg, dst_mask); + + current_state->current_row = 0; +} + +/** Process the WINED3DSIO_TEXM3X3VSPEC instruction in GLSL + * Peform the final texture lookup based on the previous 2 3x3 matrix multiplies */ +void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG* arg) { + + IWineD3DPixelShaderImpl* shader = (IWineD3DPixelShaderImpl*) arg->shader; + DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK; + SHADER_BUFFER* buffer = arg->buffer; + SHADER_PARSE_STATE* current_state = &shader->baseShader.parse_state; + glsl_src_param_t src0_param; + char dst_mask[6]; + DWORD src_mask = WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 | WINED3DSP_WRITEMASK_2; + DWORD sampler_type = arg->reg_maps->samplers[reg] & WINED3DSP_TEXTURETYPE_MASK; + glsl_sample_function_t sample_function; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], src_mask, &src0_param); + + /* Perform the last matrix multiply operation */ + shader_addline(buffer, "tmp0.z = dot(vec3(T%u), vec3(%s));\n", reg, src0_param.param_str); + + /* Construct the eye-ray vector from w coordinates */ + shader_addline(buffer, "tmp1.xyz = normalize(vec3(gl_TexCoord[%u].w, gl_TexCoord[%u].w, gl_TexCoord[%u].w));\n", + current_state->texcoord_w[0], current_state->texcoord_w[1], reg); + + /* Calculate reflection vector (Assume normal is normalized): RF = 2*(tmp0.tmp1)*tmp0-tmp1 + * This is equivalent to reflect(-tmp1, tmp0); */ + shader_addline(buffer, "tmp0.xyz = reflect(-tmp1.xyz, tmp0.xyz);\n"); + + shader_glsl_append_dst(buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_get_sample_function(sampler_type, FALSE, &sample_function); + + /* Sample the texture using the calculated coordinates */ + shader_addline(buffer, "%s(Psampler%u, tmp0.xyz)%s);\n", sample_function.name, reg, dst_mask); + + current_state->current_row = 0; +} + +/** Process the WINED3DSIO_TEXBEM instruction in GLSL. + * Apply a fake bump map transform. + * texbem is pshader <= 1.3 only, this saves a few version checks + */ +void pshader_glsl_texbem(SHADER_OPCODE_ARG* arg) { + IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + char dst_swizzle[6]; + glsl_sample_function_t sample_function; + glsl_src_param_t coord_param; + DWORD sampler_type; + DWORD sampler_idx; + DWORD mask; + DWORD flags; + char coord_mask[6]; + + sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + flags = deviceImpl->stateBlock->textureState[sampler_idx][WINED3DTSS_TEXTURETRANSFORMFLAGS]; + + sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; + shader_glsl_get_sample_function(sampler_type, FALSE, &sample_function); + mask = sample_function.coord_mask; + + shader_glsl_get_write_mask(arg->dst, dst_swizzle); + + shader_glsl_get_write_mask(mask, coord_mask); + + /* with projective textures, texbem only divides the static texture coord, not the displacement, + * so we can't let the GL handle this. + */ + if (flags & WINED3DTTFF_PROJECTED) { + DWORD div_mask=0; + char coord_div_mask[3]; + switch (flags & ~WINED3DTTFF_PROJECTED) { + case WINED3DTTFF_COUNT1: FIXME("WINED3DTTFF_PROJECTED with WINED3DTTFF_COUNT1?\n"); break; + case WINED3DTTFF_COUNT2: div_mask = WINED3DSP_WRITEMASK_1; break; + case WINED3DTTFF_COUNT3: div_mask = WINED3DSP_WRITEMASK_2; break; + case WINED3DTTFF_COUNT4: + case WINED3DTTFF_DISABLE: div_mask = WINED3DSP_WRITEMASK_3; break; + } + shader_glsl_get_write_mask(div_mask, coord_div_mask); + shader_addline(arg->buffer, "T%u%s /= T%u%s;\n", sampler_idx, coord_mask, sampler_idx, coord_div_mask); + } + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0|WINED3DSP_WRITEMASK_1, &coord_param); + shader_addline(arg->buffer, "%s(Psampler%u, T%u%s + vec4(bumpenvmat * %s, 0.0, 0.0)%s )%s);\n", + sample_function.name, sampler_idx, sampler_idx, coord_mask, coord_param.param_str, coord_mask, dst_swizzle); +} + +void pshader_glsl_bem(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param, src1_param; + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0|WINED3DSP_WRITEMASK_1, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0|WINED3DSP_WRITEMASK_1, &src1_param); + + shader_glsl_append_dst(arg->buffer, arg); + shader_addline(arg->buffer, "%s + bumpenvmat * %s);\n", + src0_param.param_str, src1_param.param_str); +} + +/** Process the WINED3DSIO_TEXREG2AR instruction in GLSL + * Sample 2D texture at dst using the alpha & red (wx) components of src as texture coordinates */ +void pshader_glsl_texreg2ar(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + char dst_mask[6]; + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_ALL, &src0_param); + + shader_addline(arg->buffer, "texture2D(Psampler%u, %s.wx)%s);\n", sampler_idx, src0_param.reg_name, dst_mask); +} + +/** Process the WINED3DSIO_TEXREG2GB instruction in GLSL + * Sample 2D texture at dst using the green & blue (yz) components of src as texture coordinates */ +void pshader_glsl_texreg2gb(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + char dst_mask[6]; + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_ALL, &src0_param); + + shader_addline(arg->buffer, "texture2D(Psampler%u, %s.yz)%s);\n", sampler_idx, src0_param.reg_name, dst_mask); +} + +/** Process the WINED3DSIO_TEXREG2RGB instruction in GLSL + * Sample texture at dst using the rgb (xyz) components of src as texture coordinates */ +void pshader_glsl_texreg2rgb(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + char dst_mask[6]; + DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK; + glsl_sample_function_t sample_function; + + shader_glsl_append_dst(arg->buffer, arg); + shader_glsl_get_write_mask(arg->dst, dst_mask); + shader_glsl_get_sample_function(sampler_type, FALSE, &sample_function); + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], sample_function.coord_mask, &src0_param); + + shader_addline(arg->buffer, "%s(Psampler%u, %s)%s);\n", sample_function.name, sampler_idx, src0_param.param_str, dst_mask); +} + +/** Process the WINED3DSIO_TEXKILL instruction in GLSL. + * If any of the first 3 components are < 0, discard this pixel */ +void pshader_glsl_texkill(SHADER_OPCODE_ARG* arg) { + glsl_dst_param_t dst_param; + + shader_glsl_add_dst_param(arg, arg->dst, 0, &dst_param); + shader_addline(arg->buffer, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;\n", dst_param.reg_name); +} + +/** Process the WINED3DSIO_DP2ADD instruction in GLSL. + * dst = dot2(src0, src1) + src2 */ +void pshader_glsl_dp2add(SHADER_OPCODE_ARG* arg) { + glsl_src_param_t src0_param; + glsl_src_param_t src1_param; + glsl_src_param_t src2_param; + DWORD write_mask; + size_t mask_size; + + write_mask = shader_glsl_append_dst(arg->buffer, arg); + mask_size = shader_glsl_get_write_mask_size(write_mask); + + shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &src0_param); + shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &src1_param); + shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], WINED3DSP_WRITEMASK_0, &src2_param); + + shader_addline(arg->buffer, "dot(%s, %s) + %s);\n", src0_param.param_str, src1_param.param_str, src2_param.param_str); +} + +void pshader_glsl_input_pack( + SHADER_BUFFER* buffer, + semantic* semantics_in) { + + unsigned int i; + + for (i = 0; i < MAX_REG_INPUT; i++) { + + DWORD usage_token = semantics_in[i].usage; + DWORD register_token = semantics_in[i].reg; + DWORD usage, usage_idx; + char reg_mask[6]; + + /* Uninitialized */ + if (!usage_token) continue; + usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + shader_glsl_get_write_mask(register_token, reg_mask); + + switch(usage) { + + case WINED3DDECLUSAGE_COLOR: + if (usage_idx == 0) + shader_addline(buffer, "IN%u%s = vec4(gl_Color)%s;\n", + i, reg_mask, reg_mask); + else if (usage_idx == 1) + shader_addline(buffer, "IN%u%s = vec4(gl_SecondaryColor)%s;\n", + i, reg_mask, reg_mask); + else + shader_addline(buffer, "IN%u%s = vec4(unsupported_color_input)%s;\n", + i, reg_mask, reg_mask); + break; + + case WINED3DDECLUSAGE_TEXCOORD: + shader_addline(buffer, "IN%u%s = vec4(gl_TexCoord[%u])%s;\n", + i, reg_mask, usage_idx, reg_mask ); + break; + + case WINED3DDECLUSAGE_FOG: + shader_addline(buffer, "IN%u%s = vec4(gl_FogFragCoord)%s;\n", + i, reg_mask, reg_mask); + break; + + default: + shader_addline(buffer, "IN%u%s = vec4(unsupported_input)%s;\n", + i, reg_mask, reg_mask); + } + } +} + +/********************************************* + * Vertex Shader Specific Code begins here + ********************************************/ + +void vshader_glsl_output_unpack( + SHADER_BUFFER* buffer, + semantic* semantics_out) { + + unsigned int i; + + for (i = 0; i < MAX_REG_OUTPUT; i++) { + + DWORD usage_token = semantics_out[i].usage; + DWORD register_token = semantics_out[i].reg; + DWORD usage, usage_idx; + char reg_mask[6]; + + /* Uninitialized */ + if (!usage_token) continue; + + usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + shader_glsl_get_write_mask(register_token, reg_mask); + + switch(usage) { + + case WINED3DDECLUSAGE_COLOR: + if (usage_idx == 0) + shader_addline(buffer, "gl_FrontColor%s = OUT%u%s;\n", reg_mask, i, reg_mask); + else if (usage_idx == 1) + shader_addline(buffer, "gl_FrontSecondaryColor%s = OUT%u%s;\n", reg_mask, i, reg_mask); + else + shader_addline(buffer, "unsupported_color_output%s = OUT%u%s;\n", reg_mask, i, reg_mask); + break; + + case WINED3DDECLUSAGE_POSITION: + shader_addline(buffer, "gl_Position%s = OUT%u%s;\n", reg_mask, i, reg_mask); + break; + + case WINED3DDECLUSAGE_TEXCOORD: + shader_addline(buffer, "gl_TexCoord[%u]%s = OUT%u%s;\n", + usage_idx, reg_mask, i, reg_mask); + break; + + case WINED3DDECLUSAGE_PSIZE: + shader_addline(buffer, "gl_PointSize = OUT%u.x;\n", i); + break; + + case WINED3DDECLUSAGE_FOG: + shader_addline(buffer, "gl_FogFragCoord = OUT%u%s;\n", i, reg_mask); + break; + + default: + shader_addline(buffer, "unsupported_output%s = OUT%u%s;\n", reg_mask, i, reg_mask); + } + } +} + +static void add_glsl_program_entry(IWineD3DDeviceImpl *device, struct glsl_shader_prog_link *entry) { + glsl_program_key_t *key; + + key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t)); + key->vshader = entry->vshader; + key->pshader = entry->pshader; + + hash_table_put(device->glsl_program_lookup, key, entry); +} + +static struct glsl_shader_prog_link *get_glsl_program_entry(IWineD3DDeviceImpl *device, + GLhandleARB vshader, GLhandleARB pshader) { + glsl_program_key_t key; + + key.vshader = vshader; + key.pshader = pshader; + + return (struct glsl_shader_prog_link *)hash_table_get(device->glsl_program_lookup, &key); +} + +void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_link *entry) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + glsl_program_key_t *key; + + key = HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t)); + key->vshader = entry->vshader; + key->pshader = entry->pshader; + hash_table_remove(This->glsl_program_lookup, key); + + GL_EXTCALL(glDeleteObjectARB(entry->programId)); + if (entry->vshader) list_remove(&entry->vshader_entry); + if (entry->pshader) list_remove(&entry->pshader_entry); + HeapFree(GetProcessHeap(), 0, entry->vuniformF_locations); + HeapFree(GetProcessHeap(), 0, entry->puniformF_locations); + HeapFree(GetProcessHeap(), 0, entry); +} + +/** Sets the GLSL program ID for the given pixel and vertex shader combination. + * It sets the programId on the current StateBlock (because it should be called + * inside of the DrawPrimitive() part of the render loop). + * + * If a program for the given combination does not exist, create one, and store + * the program in the hash table. If it creates a program, it will link the + * given objects, too. + */ +static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use_vs) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + IWineD3DPixelShader *pshader = This->stateBlock->pixelShader; + IWineD3DVertexShader *vshader = This->stateBlock->vertexShader; + struct glsl_shader_prog_link *entry = NULL; + GLhandleARB programId = 0; + int i; + char glsl_name[8]; + + GLhandleARB vshader_id = use_vs ? ((IWineD3DBaseShaderImpl*)vshader)->baseShader.prgId : 0; + GLhandleARB pshader_id = use_ps ? ((IWineD3DBaseShaderImpl*)pshader)->baseShader.prgId : 0; + entry = get_glsl_program_entry(This, vshader_id, pshader_id); + if (entry) { + This->stateBlock->glsl_program = entry; + return; + } + + /* If we get to this point, then no matching program exists, so we create one */ + programId = GL_EXTCALL(glCreateProgramObjectARB()); + TRACE("Created new GLSL shader program %u\n", programId); + + /* Create the entry */ + entry = HeapAlloc(GetProcessHeap(), 0, sizeof(struct glsl_shader_prog_link)); + entry->programId = programId; + entry->vshader = vshader_id; + entry->pshader = pshader_id; + /* Add the hash table entry */ + add_glsl_program_entry(This, entry); + + /* Set the current program */ + This->stateBlock->glsl_program = entry; + + /* Attach GLSL vshader */ + if (vshader_id) { + int max_attribs = 16; /* TODO: Will this always be the case? It is at the moment... */ + char tmp_name[10]; + + TRACE("Attaching GLSL shader object %u to program %u\n", vshader_id, programId); + GL_EXTCALL(glAttachObjectARB(programId, vshader_id)); + checkGLcall("glAttachObjectARB"); + + /* Bind vertex attributes to a corresponding index number to match + * the same index numbers as ARB_vertex_programs (makes loading + * vertex attributes simpler). With this method, we can use the + * exact same code to load the attributes later for both ARB and + * GLSL shaders. + * + * We have to do this here because we need to know the Program ID + * in order to make the bindings work, and it has to be done prior + * to linking the GLSL program. */ + for (i = 0; i < max_attribs; ++i) { + _snprintf(tmp_name, sizeof(tmp_name), "attrib%i", i); + GL_EXTCALL(glBindAttribLocationARB(programId, i, tmp_name)); + } + checkGLcall("glBindAttribLocationARB"); + + list_add_head(&((IWineD3DBaseShaderImpl *)vshader)->baseShader.linked_programs, &entry->vshader_entry); + } + + /* Attach GLSL pshader */ + if (pshader_id) { + TRACE("Attaching GLSL shader object %u to program %u\n", pshader_id, programId); + GL_EXTCALL(glAttachObjectARB(programId, pshader_id)); + checkGLcall("glAttachObjectARB"); + + list_add_head(&((IWineD3DBaseShaderImpl *)pshader)->baseShader.linked_programs, &entry->pshader_entry); + } + + /* Link the program */ + TRACE("Linking GLSL shader program %u\n", programId); + GL_EXTCALL(glLinkProgramARB(programId)); + print_glsl_info_log(&GLINFO_LOCATION, programId); + + entry->vuniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(vshader_constantsF)); + for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) { + _snprintf(glsl_name, sizeof(glsl_name), "VC[%i]", i); + entry->vuniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name)); + } + entry->puniformF_locations = HeapAlloc(GetProcessHeap(), 0, sizeof(GLhandleARB) * GL_LIMITS(pshader_constantsF)); + for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) { + _snprintf(glsl_name, sizeof(glsl_name), "PC[%i]", i); + entry->puniformF_locations[i] = GL_EXTCALL(glGetUniformLocationARB(programId, glsl_name)); + } +} + +static GLhandleARB create_glsl_blt_shader(WineD3D_GL_Info *gl_info) { + GLhandleARB program_id; + GLhandleARB vshader_id, pshader_id; + const char *blt_vshader[] = { + "void main(void)\n" + "{\n" + " gl_Position = gl_Vertex;\n" + " gl_FrontColor = vec4(1.0);\n" + " gl_TexCoord[0].x = (gl_Vertex.x * 0.5) + 0.5;\n" + " gl_TexCoord[0].y = (-gl_Vertex.y * 0.5) + 0.5;\n" + "}\n" + }; + + const char *blt_pshader[] = { + "uniform sampler2D sampler;\n" + "void main(void)\n" + "{\n" + " gl_FragDepth = texture2D(sampler, gl_TexCoord[0].xy).x;\n" + "}\n" + }; + + vshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB)); + GL_EXTCALL(glShaderSourceARB(vshader_id, 1, blt_vshader, NULL)); + GL_EXTCALL(glCompileShaderARB(vshader_id)); + + pshader_id = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB)); + GL_EXTCALL(glShaderSourceARB(pshader_id, 1, blt_pshader, NULL)); + GL_EXTCALL(glCompileShaderARB(pshader_id)); + + program_id = GL_EXTCALL(glCreateProgramObjectARB()); + GL_EXTCALL(glAttachObjectARB(program_id, vshader_id)); + GL_EXTCALL(glAttachObjectARB(program_id, pshader_id)); + GL_EXTCALL(glLinkProgramARB(program_id)); + + print_glsl_info_log(&GLINFO_LOCATION, program_id); + + return program_id; +} + +static void shader_glsl_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + GLhandleARB program_id = 0; + + if (useVS || usePS) set_glsl_shader_program(iface, usePS, useVS); + else This->stateBlock->glsl_program = NULL; + + program_id = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0; + if (program_id) TRACE("Using GLSL program %u\n", program_id); + GL_EXTCALL(glUseProgramObjectARB(program_id)); + checkGLcall("glUseProgramObjectARB"); +} + +static void shader_glsl_select_depth_blt(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + static GLhandleARB program_id = 0; + static GLhandleARB loc = -1; + + if (!program_id) { + program_id = create_glsl_blt_shader(gl_info); + loc = GL_EXTCALL(glGetUniformLocationARB(program_id, "sampler")); + } + + GL_EXTCALL(glUseProgramObjectARB(program_id)); + GL_EXTCALL(glUniform1iARB(loc, 0)); +} + +static void shader_glsl_cleanup(IWineD3DDevice *iface) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + WineD3D_GL_Info *gl_info = &This->adapter->gl_info; + GL_EXTCALL(glUseProgramObjectARB(0)); +} + +const shader_backend_t glsl_shader_backend = { + &shader_glsl_select, + &shader_glsl_select_depth_blt, + &shader_glsl_load_constants, + &shader_glsl_cleanup +}; diff --git a/reactos/dll/directx/wine/wined3d/indexbuffer.c b/reactos/dll/directx/wine/wined3d/indexbuffer.c new file mode 100644 index 00000000000..62d90d19d1c --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/indexbuffer.c @@ -0,0 +1,211 @@ +/* + * IWineD3DIndexBuffer Implementation + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +/* ******************************************* + IWineD3DIndexBuffer IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DIndexBufferImpl_QueryInterface(IWineD3DIndexBuffer *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DIndexBufferImpl *This = (IWineD3DIndexBufferImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DIndexBuffer)){ + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DIndexBufferImpl_AddRef(IWineD3DIndexBuffer *iface) { + IWineD3DIndexBufferImpl *This = (IWineD3DIndexBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&This->resource.ref); + TRACE("(%p) : AddRef increasing from %d\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IWineD3DIndexBufferImpl_Release(IWineD3DIndexBuffer *iface) { + IWineD3DIndexBufferImpl *This = (IWineD3DIndexBufferImpl *)iface; + ULONG ref = InterlockedDecrement(&This->resource.ref); + TRACE("(%p) : Releasing from %d\n", This, ref + 1); + if (ref == 0) { + if(This->vbo) { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + /* No need to manually unset the buffer. glDeleteBuffers unsets it for the current context, + * but not for other contexts. However, because the d3d buffer is destroyed the app has to + * unset it before doing the next draw, thus dirtifying the index buffer state and forcing + * binding a new buffer + */ + GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo)); + checkGLcall("glDeleteBuffersARB"); + LEAVE_GL(); + } + + IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* **************************************************** + IWineD3DIndexBuffer IWineD3DResource parts follow + **************************************************** */ +static HRESULT WINAPI IWineD3DIndexBufferImpl_GetDevice(IWineD3DIndexBuffer *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +static HRESULT WINAPI IWineD3DIndexBufferImpl_SetPrivateData(IWineD3DIndexBuffer *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IWineD3DIndexBufferImpl_GetPrivateData(IWineD3DIndexBuffer *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IWineD3DIndexBufferImpl_FreePrivateData(IWineD3DIndexBuffer *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +static DWORD WINAPI IWineD3DIndexBufferImpl_SetPriority(IWineD3DIndexBuffer *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +static DWORD WINAPI IWineD3DIndexBufferImpl_GetPriority(IWineD3DIndexBuffer *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +static void WINAPI IWineD3DIndexBufferImpl_PreLoad(IWineD3DIndexBuffer *iface) { + IWineD3DResourceImpl_PreLoad((IWineD3DResource *)iface); +} + +static WINED3DRESOURCETYPE WINAPI IWineD3DIndexBufferImpl_GetType(IWineD3DIndexBuffer *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +static HRESULT WINAPI IWineD3DIndexBufferImpl_GetParent(IWineD3DIndexBuffer *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DIndexBuffer IWineD3DIndexBuffer parts follow + ****************************************************** */ +static HRESULT WINAPI IWineD3DIndexBufferImpl_Lock(IWineD3DIndexBuffer *iface, UINT OffsetToLock, UINT SizeToLock, BYTE** ppbData, DWORD Flags) { + IWineD3DIndexBufferImpl *This = (IWineD3DIndexBufferImpl *)iface; + TRACE("(%p) : offset %d, size %d, Flags=%x\n", This, OffsetToLock, SizeToLock, Flags); + + InterlockedIncrement(&This->lockcount); + *ppbData = (BYTE *)This->resource.allocatedMemory + OffsetToLock; + + if(Flags & (WINED3DLOCK_READONLY | WINED3DLOCK_NO_DIRTY_UPDATE) || This->vbo == 0) { + return WINED3D_OK; + } + + if(This->dirtystart != This->dirtyend) { + if(This->dirtystart > OffsetToLock) This->dirtystart = OffsetToLock; + if(SizeToLock) { + if(This->dirtyend < OffsetToLock + SizeToLock) This->dirtyend = OffsetToLock + SizeToLock; + } else { + This->dirtyend = This->resource.size; + } + } else { + This->dirtystart = OffsetToLock; + if(SizeToLock) + This->dirtyend = OffsetToLock + SizeToLock; + else + This->dirtyend = This->resource.size; + } + + return WINED3D_OK; +} +static HRESULT WINAPI IWineD3DIndexBufferImpl_Unlock(IWineD3DIndexBuffer *iface) { + IWineD3DIndexBufferImpl *This = (IWineD3DIndexBufferImpl *)iface; + unsigned long locks = InterlockedDecrement(&This->lockcount); + TRACE("(%p)\n", This); + + /* For now load in unlock */ + if(locks == 0 && This->vbo && (This->dirtyend - This->dirtystart) > 0) { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + if(device->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + ENTER_GL(); + GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, This->vbo)); + checkGLcall("glBindBufferARB"); + GL_EXTCALL(glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, + This->dirtystart, This->dirtyend - This->dirtystart, This->resource.allocatedMemory + This->dirtystart)); + checkGLcall("glBufferSubDataARB"); + LEAVE_GL(); + This->dirtystart = 0; + This->dirtyend = 0; + /* TODO: Move loading into preload when the buffer is used, that avoids dirtifying the state */ + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_INDEXBUFFER); + } + return WINED3D_OK; +} +static HRESULT WINAPI IWineD3DIndexBufferImpl_GetDesc(IWineD3DIndexBuffer *iface, WINED3DINDEXBUFFER_DESC *pDesc) { + IWineD3DIndexBufferImpl *This = (IWineD3DIndexBufferImpl *)iface; + + TRACE("(%p)\n", This); + pDesc->Format = This->resource.format; + pDesc->Type = This->resource.resourceType; + pDesc->Usage = This->resource.usage; + pDesc->Pool = This->resource.pool; + pDesc->Size = This->resource.size; + return WINED3D_OK; +} + +const IWineD3DIndexBufferVtbl IWineD3DIndexBuffer_Vtbl = +{ + /* IUnknown */ + IWineD3DIndexBufferImpl_QueryInterface, + IWineD3DIndexBufferImpl_AddRef, + IWineD3DIndexBufferImpl_Release, + /* IWineD3DResource */ + IWineD3DIndexBufferImpl_GetParent, + IWineD3DIndexBufferImpl_GetDevice, + IWineD3DIndexBufferImpl_SetPrivateData, + IWineD3DIndexBufferImpl_GetPrivateData, + IWineD3DIndexBufferImpl_FreePrivateData, + IWineD3DIndexBufferImpl_SetPriority, + IWineD3DIndexBufferImpl_GetPriority, + IWineD3DIndexBufferImpl_PreLoad, + IWineD3DIndexBufferImpl_GetType, + /* IWineD3DIndexBuffer */ + IWineD3DIndexBufferImpl_Lock, + IWineD3DIndexBufferImpl_Unlock, + IWineD3DIndexBufferImpl_GetDesc +}; diff --git a/reactos/dll/directx/wine/wined3d/palette.c b/reactos/dll/directx/wine/wined3d/palette.c new file mode 100644 index 00000000000..a1dcc9f95f7 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/palette.c @@ -0,0 +1,187 @@ +/* DirectDraw - IDirectPalette base interface + * + * Copyright 1997-2000 Marcus Meissner + * Copyright 2000-2001 TransGaming Technologies Inc. + * Copyright 2006 Stefan Dösinger for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#include "config.h" +#include "winerror.h" +#include "wine/debug.h" + +#include +#include + +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); + +#define SIZE_BITS (WINEDDPCAPS_1BIT | WINEDDPCAPS_2BIT | WINEDDPCAPS_4BIT | WINEDDPCAPS_8BIT) + +static HRESULT WINAPI IWineD3DPaletteImpl_QueryInterface(IWineD3DPalette *iface, REFIID refiid, void **obj) { + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); + + if (IsEqualGUID(refiid, &IID_IUnknown) + || IsEqualGUID(refiid, &IID_IWineD3DPalette)) { + *obj = iface; + IWineD3DPalette_AddRef(iface); + return S_OK; + } + else { + *obj = NULL; + return E_NOINTERFACE; + } +} + +static ULONG WINAPI IWineD3DPaletteImpl_AddRef(IWineD3DPalette *iface) { + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->() incrementing from %u.\n", This, ref - 1); + + return ref; +} + +static ULONG WINAPI IWineD3DPaletteImpl_Release(IWineD3DPalette *iface) { + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->() decrementing from %u.\n", This, ref + 1); + + if (!ref) { + HeapFree(GetProcessHeap(), 0, This); + return 0; + } + + return ref; +} + +/* Not called from the vtable */ +DWORD IWineD3DPaletteImpl_Size(DWORD dwFlags) { + switch (dwFlags & SIZE_BITS) { + case WINEDDPCAPS_1BIT: return 2; + case WINEDDPCAPS_2BIT: return 4; + case WINEDDPCAPS_4BIT: return 16; + case WINEDDPCAPS_8BIT: return 256; + default: assert(0); return 256; + } +} + +static HRESULT WINAPI IWineD3DPaletteImpl_GetEntries(IWineD3DPalette *iface, DWORD Flags, DWORD Start, DWORD Count, PALETTEENTRY *PalEnt) { + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + + TRACE("(%p)->(%08x,%d,%d,%p)\n",This,Flags,Start,Count,PalEnt); + + if (Flags != 0) return WINED3DERR_INVALIDCALL; /* unchecked */ + if (Start + Count > IWineD3DPaletteImpl_Size(This->Flags)) + return WINED3DERR_INVALIDCALL; + + if (This->Flags & WINEDDPCAPS_8BITENTRIES) + { + unsigned int i; + LPBYTE entry = (LPBYTE)PalEnt; + + for (i=Start; i < Count+Start; i++) + *entry++ = This->palents[i].peRed; + } + else + memcpy(PalEnt, This->palents+Start, Count * sizeof(PALETTEENTRY)); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DPaletteImpl_SetEntries(IWineD3DPalette *iface, DWORD Flags, DWORD Start, DWORD Count, PALETTEENTRY *PalEnt) +{ + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + ResourceList *res; + + TRACE("(%p)->(%08x,%d,%d,%p)\n",This,Flags,Start,Count,PalEnt); + + if (This->Flags & WINEDDPCAPS_8BITENTRIES) { + unsigned int i; + const BYTE* entry = (const BYTE*)PalEnt; + + for (i=Start; i < Count+Start; i++) + This->palents[i].peRed = *entry++; + } + else { + memcpy(This->palents+Start, PalEnt, Count * sizeof(PALETTEENTRY)); + + if (This->hpal) + SetPaletteEntries(This->hpal, Start, Count, This->palents+Start); + } + +#if 0 + /* Now, if we are in 'depth conversion mode', update the screen palette */ + /* FIXME: we need to update the image or we won't get palette fading. */ + if (This->ddraw->d->palette_convert != NULL) + This->ddraw->d->palette_convert(palent,This->screen_palents,start,count); +#endif + + /* If the palette is attached to the render target, update all render targets */ + + for(res = This->wineD3DDevice->resources; res != NULL; res=res->next) { + if(IWineD3DResource_GetType(res->resource) == WINED3DRTYPE_SURFACE) { + IWineD3DSurfaceImpl *impl = (IWineD3DSurfaceImpl *) res->resource; + if(impl->palette == This) + IWineD3DSurface_RealizePalette( (IWineD3DSurface *) res->resource); + } + } + + /* If the palette is the primary palette, set the entries to the device */ + if(This->Flags & WINEDDPCAPS_PRIMARYSURFACE) { + unsigned int i; + IWineD3DDeviceImpl *device = This->wineD3DDevice; + PALETTEENTRY *entry = PalEnt; + + for(i = Start; i < Start+Count; i++) { + device->palettes[device->currentPalette][i] = *entry++; + } + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DPaletteImpl_GetCaps(IWineD3DPalette *iface, DWORD *Caps) { + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + TRACE("(%p)->(%p)\n", This, Caps); + + *Caps = This->Flags; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DPaletteImpl_GetParent(IWineD3DPalette *iface, IUnknown **Parent) { + IWineD3DPaletteImpl *This = (IWineD3DPaletteImpl *)iface; + TRACE("(%p)->(%p)\n", This, Parent); + + *Parent = (IUnknown *) This->parent; + IUnknown_AddRef( (IUnknown *) This->parent); + return WINED3D_OK; +} + +const IWineD3DPaletteVtbl IWineD3DPalette_Vtbl = +{ + /*** IUnknown ***/ + IWineD3DPaletteImpl_QueryInterface, + IWineD3DPaletteImpl_AddRef, + IWineD3DPaletteImpl_Release, + /*** IWineD3DPalette ***/ + IWineD3DPaletteImpl_GetParent, + IWineD3DPaletteImpl_GetEntries, + IWineD3DPaletteImpl_GetCaps, + IWineD3DPaletteImpl_SetEntries +}; diff --git a/reactos/dll/directx/wine/wined3d/pixelshader.c b/reactos/dll/directx/wine/wined3d/pixelshader.c new file mode 100644 index 00000000000..163453bcc14 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/pixelshader.c @@ -0,0 +1,585 @@ +/* + * shaders implementation + * + * Copyright 2002-2003 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Ivan Gyurdiev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include +#include + +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); + +#define GLINFO_LOCATION ((IWineD3DDeviceImpl *) This->baseShader.device)->adapter->gl_info + +#if 0 /* Must not be 1 in cvs version */ +# define PSTRACE(A) TRACE A +# define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w) +#else +# define PSTRACE(A) +# define TRACE_VSVECTOR(name) +#endif + +#define GLNAME_REQUIRE_GLSL ((const char *)1) +/* ******************************************* + IWineD3DPixelShader IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DPixelShaderImpl_QueryInterface(IWineD3DPixelShader *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DBaseShader) + || IsEqualGUID(riid, &IID_IWineD3DPixelShader)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DPixelShaderImpl_AddRef(IWineD3DPixelShader *iface) { + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->ref); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface) { + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->ref); + ref = InterlockedDecrement(&This->ref); + if (ref == 0) { + /* SetPixelShader does not AddRef. If the bound pixel shader is destroyed, the pointer in the stateblock remains + * unchanged. Drawing again will most likely crash, even on windows. A problem can occur if the application creates + * a new pixel shader which resides at the same address. Then SetPixelShader will think it is a NOP change, and won't + * dirtify the state. + * + * Do NOT call GetPixelShader here. This will addRef and cause a recursion. And do NOT set the pixel shader to NULL, + * Windows does not do that(Although no test exists since they'd crash randomly) + */ + if(iface == ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->pixelShader) { + IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_PIXELSHADER); + } + + if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { + struct list *linked_programs = &This->baseShader.linked_programs; + + TRACE("Deleting linked programs\n"); + if (linked_programs->next) { + struct glsl_shader_prog_link *entry, *entry2; + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, pshader_entry) { + delete_glsl_program_entry(This->baseShader.device, entry); + } + } + + TRACE("Deleting shader object %u\n", This->baseShader.prgId); + GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId)); + checkGLcall("glDeleteObjectARB"); + } + shader_delete_constant_list(&This->baseShader.constantsF); + shader_delete_constant_list(&This->baseShader.constantsB); + shader_delete_constant_list(&This->baseShader.constantsI); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* ******************************************* + IWineD3DPixelShader IWineD3DPixelShader parts follow + ******************************************* */ + +static HRESULT WINAPI IWineD3DPixelShaderImpl_GetParent(IWineD3DPixelShader *iface, IUnknown** parent){ + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; + + *parent = This->parent; + IUnknown_AddRef(*parent); + TRACE("(%p) : returning %p\n", This, *parent); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DPixelShaderImpl_GetDevice(IWineD3DPixelShader* iface, IWineD3DDevice **pDevice){ + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; + IWineD3DDevice_AddRef(This->baseShader.device); + *pDevice = This->baseShader.device; + TRACE("(%p) returning %p\n", This, *pDevice); + return WINED3D_OK; +} + + +static HRESULT WINAPI IWineD3DPixelShaderImpl_GetFunction(IWineD3DPixelShader* impl, VOID* pData, UINT* pSizeOfData) { + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)impl; + TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData); + + if (NULL == pData) { + *pSizeOfData = This->baseShader.functionLength; + return WINED3D_OK; + } + if (*pSizeOfData < This->baseShader.functionLength) { + /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller + * than the required size we should write the required size and + * return D3DERR_MOREDATA. That's not actually true. */ + return WINED3DERR_INVALIDCALL; + } + if (NULL == This->baseShader.function) { /* no function defined */ + TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This, pData); + (*(DWORD **) pData) = NULL; + } else { + if (This->baseShader.functionLength == 0) { + + } + TRACE("(%p) : GetFunction copying to %p\n", This, pData); + memcpy(pData, This->baseShader.function, This->baseShader.functionLength); + } + return WINED3D_OK; +} + +CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { + /* Arithmethic */ + {WINED3DSIO_NOP, "nop", "NOP", 0, 0, pshader_hw_map2gl, NULL, 0, 0}, + {WINED3DSIO_MOV, "mov", "MOV", 1, 2, pshader_hw_map2gl, shader_glsl_mov, 0, 0}, + {WINED3DSIO_ADD, "add", "ADD", 1, 3, pshader_hw_map2gl, shader_glsl_arith, 0, 0}, + {WINED3DSIO_SUB, "sub", "SUB", 1, 3, pshader_hw_map2gl, shader_glsl_arith, 0, 0}, + {WINED3DSIO_MAD, "mad", "MAD", 1, 4, pshader_hw_map2gl, shader_glsl_mad, 0, 0}, + {WINED3DSIO_MUL, "mul", "MUL", 1, 3, pshader_hw_map2gl, shader_glsl_arith, 0, 0}, + {WINED3DSIO_RCP, "rcp", "RCP", 1, 2, pshader_hw_map2gl, shader_glsl_rcp, 0, 0}, + {WINED3DSIO_RSQ, "rsq", "RSQ", 1, 2, pshader_hw_map2gl, shader_glsl_rsq, 0, 0}, + {WINED3DSIO_DP3, "dp3", "DP3", 1, 3, pshader_hw_map2gl, shader_glsl_dot, 0, 0}, + {WINED3DSIO_DP4, "dp4", "DP4", 1, 3, pshader_hw_map2gl, shader_glsl_dot, 0, 0}, + {WINED3DSIO_MIN, "min", "MIN", 1, 3, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_MAX, "max", "MAX", 1, 3, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_SLT, "slt", "SLT", 1, 3, pshader_hw_map2gl, shader_glsl_compare, 0, 0}, + {WINED3DSIO_SGE, "sge", "SGE", 1, 3, pshader_hw_map2gl, shader_glsl_compare, 0, 0}, + {WINED3DSIO_ABS, "abs", "ABS", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_EXP, "exp", "EX2", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_LOG, "log", "LG2", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_EXPP, "expp", "EXP", 1, 2, pshader_hw_map2gl, shader_glsl_expp, 0, 0}, + {WINED3DSIO_LOGP, "logp", "LOG", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_DST, "dst", "DST", 1, 3, pshader_hw_map2gl, shader_glsl_dst, 0, 0}, + {WINED3DSIO_LRP, "lrp", "LRP", 1, 4, pshader_hw_map2gl, shader_glsl_lrp, 0, 0}, + {WINED3DSIO_FRC, "frc", "FRC", 1, 2, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_CND, "cnd", NULL, 1, 4, pshader_hw_cnd, shader_glsl_cnd, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_CMP, "cmp", NULL, 1, 4, pshader_hw_cmp, shader_glsl_cmp, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(3,0)}, + {WINED3DSIO_POW, "pow", "POW", 1, 3, NULL, shader_glsl_pow, 0, 0}, + {WINED3DSIO_CRS, "crs", "XPS", 1, 3, NULL, shader_glsl_cross, 0, 0}, + /* TODO: xyz normalise can be performed as VS_ARB using one temporary register, + DP3 tmp , vec, vec; + RSQ tmp, tmp.x; + MUL vec.xyz, vec, tmp; + but I think this is better because it accounts for w properly. + DP3 tmp , vec, vec; + RSQ tmp, tmp.x; + MUL vec, vec, tmp; + */ + {WINED3DSIO_NRM, "nrm", NULL, 1, 2, NULL, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, NULL, shader_glsl_sincos, WINED3DPS_VERSION(2,0), WINED3DPS_VERSION(2,1)}, + {WINED3DSIO_SINCOS, "sincos", NULL, 1, 2, NULL, shader_glsl_sincos, WINED3DPS_VERSION(3,0), -1}, + /* TODO: dp2add can be made out of multiple instuctions */ + {WINED3DSIO_DP2ADD, "dp2add", GLNAME_REQUIRE_GLSL, 1, 4, NULL, pshader_glsl_dp2add, WINED3DPS_VERSION(2,0), -1}, + /* Matrix */ + {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, NULL, shader_glsl_mnxn, 0, 0}, + /* Register declarations */ + {WINED3DSIO_DCL, "dcl", NULL, 0, 2, NULL, NULL, 0, 0}, + /* Flow control - requires GLSL or software shaders */ + {WINED3DSIO_REP , "rep", NULL, 0, 1, NULL, shader_glsl_rep, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_ENDREP, "endrep", NULL, 0, 0, NULL, shader_glsl_end, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_IF, "if", NULL, 0, 1, NULL, shader_glsl_if, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_IFC, "ifc", NULL, 0, 2, NULL, shader_glsl_ifc, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_ELSE, "else", NULL, 0, 0, NULL, shader_glsl_else, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_ENDIF, "endif", NULL, 0, 0, NULL, shader_glsl_end, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_BREAK, "break", NULL, 0, 0, NULL, shader_glsl_break, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_BREAKC, "breakc", NULL, 0, 2, NULL, shader_glsl_breakc, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, NULL, NULL, 0, 0}, + {WINED3DSIO_CALL, "call", NULL, 0, 1, NULL, shader_glsl_call, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_CALLNZ, "callnz", NULL, 0, 2, NULL, shader_glsl_callnz, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_LOOP, "loop", NULL, 0, 2, NULL, shader_glsl_loop, WINED3DPS_VERSION(3,0), -1}, + {WINED3DSIO_RET, "ret", NULL, 0, 0, NULL, NULL, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_ENDLOOP, "endloop", NULL, 0, 0, NULL, shader_glsl_end, WINED3DPS_VERSION(3,0), -1}, + {WINED3DSIO_LABEL, "label", NULL, 0, 1, NULL, shader_glsl_label, WINED3DPS_VERSION(2,1), -1}, + /* Constant definitions */ + {WINED3DSIO_DEF, "def", "undefined", 1, 5, NULL, NULL, 0, 0}, + {WINED3DSIO_DEFB, "defb", GLNAME_REQUIRE_GLSL, 1, 2, NULL, NULL, 0, 0}, + {WINED3DSIO_DEFI, "defi", GLNAME_REQUIRE_GLSL, 1, 5, NULL, NULL, 0, 0}, + /* Texture */ + {WINED3DSIO_TEXCOORD, "texcoord", "undefined", 1, 1, pshader_hw_texcoord, pshader_glsl_texcoord, 0, WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXCOORD, "texcrd", "undefined", 1, 2, pshader_hw_texcoord, pshader_glsl_texcoord, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_TEXKILL, "texkill", "KIL", 1, 1, pshader_hw_map2gl, pshader_glsl_texkill, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(3,0)}, + {WINED3DSIO_TEX, "tex", "undefined", 1, 1, pshader_hw_tex, pshader_glsl_tex, 0, WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEX, "texld", "undefined", 1, 2, pshader_hw_tex, pshader_glsl_tex, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_TEX, "texld", "undefined", 1, 3, pshader_hw_tex, pshader_glsl_tex, WINED3DPS_VERSION(2,0), -1}, + {WINED3DSIO_TEXBEM, "texbem", "undefined", 1, 2, pshader_hw_texbem, pshader_glsl_texbem, 0, WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXBEML, "texbeml", GLNAME_REQUIRE_GLSL, 1, 2, NULL, NULL, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXREG2AR,"texreg2ar","undefined", 1, 2, pshader_hw_texreg2ar, pshader_glsl_texreg2ar, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXREG2GB,"texreg2gb","undefined", 1, 2, pshader_hw_texreg2gb, pshader_glsl_texreg2gb, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXREG2RGB, "texreg2rgb", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texreg2rgb, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x2PAD, "texm3x2pad", "undefined", 1, 2, pshader_hw_texm3x2pad, pshader_glsl_texm3x2pad, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x2TEX, "texm3x2tex", "undefined", 1, 2, pshader_hw_texm3x2tex, pshader_glsl_texm3x2tex, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x3PAD, "texm3x3pad", "undefined", 1, 2, pshader_hw_texm3x3pad, pshader_glsl_texm3x3pad, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x3DIFF, "texm3x3diff", GLNAME_REQUIRE_GLSL, 1, 2, NULL, NULL, WINED3DPS_VERSION(0,0), WINED3DPS_VERSION(0,0)}, + {WINED3DSIO_TEXM3x3SPEC, "texm3x3spec", "undefined", 1, 3, pshader_hw_texm3x3spec, pshader_glsl_texm3x3spec, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x3VSPEC, "texm3x3vspec", "undefined", 1, 2, pshader_hw_texm3x3vspec, pshader_glsl_texm3x3vspec, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x3TEX, "texm3x3tex", "undefined", 1, 2, pshader_hw_texm3x3tex, pshader_glsl_texm3x3tex, WINED3DPS_VERSION(1,0), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXDP3TEX, "texdp3tex", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texdp3tex, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x2DEPTH, "texm3x2depth", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texm3x2depth, WINED3DPS_VERSION(1,3), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXDP3, "texdp3", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texdp3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXM3x3, "texm3x3", GLNAME_REQUIRE_GLSL, 1, 2, NULL, pshader_glsl_texm3x3, WINED3DPS_VERSION(1,2), WINED3DPS_VERSION(1,3)}, + {WINED3DSIO_TEXDEPTH, "texdepth", GLNAME_REQUIRE_GLSL, 1, 1, NULL, pshader_glsl_texdepth, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_BEM, "bem", "undefined", 1, 3, pshader_hw_bem, pshader_glsl_bem, WINED3DPS_VERSION(1,4), WINED3DPS_VERSION(1,4)}, + {WINED3DSIO_DSX, "dsx", NULL, 1, 2, NULL, shader_glsl_map2gl, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_DSY, "dsy", NULL, 1, 2, NULL, shader_glsl_map2gl, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_TEXLDD, "texldd", GLNAME_REQUIRE_GLSL, 1, 5, NULL, NULL, WINED3DPS_VERSION(2,1), -1}, + {WINED3DSIO_SETP, "setp", GLNAME_REQUIRE_GLSL, 1, 3, NULL, NULL, 0, 0}, + {WINED3DSIO_TEXLDL, "texldl", NULL, 1, 3, NULL, shader_glsl_texldl, WINED3DPS_VERSION(3,0), -1}, + {WINED3DSIO_PHASE, "phase", GLNAME_REQUIRE_GLSL, 0, 0, NULL, NULL, 0, 0}, + {0, NULL, NULL, 0, 0, NULL, NULL, 0, 0} +}; + +static void pshader_set_limits( + IWineD3DPixelShaderImpl *This) { + + This->baseShader.limits.attributes = 0; + This->baseShader.limits.address = 0; + This->baseShader.limits.packed_output = 0; + + switch (This->baseShader.hex_version) { + case WINED3DPS_VERSION(1,0): + case WINED3DPS_VERSION(1,1): + case WINED3DPS_VERSION(1,2): + case WINED3DPS_VERSION(1,3): + This->baseShader.limits.temporary = 2; + This->baseShader.limits.constant_float = 8; + This->baseShader.limits.constant_int = 0; + This->baseShader.limits.constant_bool = 0; + This->baseShader.limits.texcoord = 4; + This->baseShader.limits.sampler = 4; + This->baseShader.limits.packed_input = 0; + This->baseShader.limits.label = 0; + break; + + case WINED3DPS_VERSION(1,4): + This->baseShader.limits.temporary = 6; + This->baseShader.limits.constant_float = 8; + This->baseShader.limits.constant_int = 0; + This->baseShader.limits.constant_bool = 0; + This->baseShader.limits.texcoord = 6; + This->baseShader.limits.sampler = 6; + This->baseShader.limits.packed_input = 0; + This->baseShader.limits.label = 0; + break; + + /* FIXME: temporaries must match D3DPSHADERCAPS2_0.NumTemps */ + case WINED3DPS_VERSION(2,0): + This->baseShader.limits.temporary = 32; + This->baseShader.limits.constant_float = 32; + This->baseShader.limits.constant_int = 16; + This->baseShader.limits.constant_bool = 16; + This->baseShader.limits.texcoord = 8; + This->baseShader.limits.sampler = 16; + This->baseShader.limits.packed_input = 0; + break; + + case WINED3DPS_VERSION(2,1): + This->baseShader.limits.temporary = 32; + This->baseShader.limits.constant_float = 32; + This->baseShader.limits.constant_int = 16; + This->baseShader.limits.constant_bool = 16; + This->baseShader.limits.texcoord = 8; + This->baseShader.limits.sampler = 16; + This->baseShader.limits.packed_input = 0; + This->baseShader.limits.label = 16; + break; + + case WINED3DPS_VERSION(3,0): + This->baseShader.limits.temporary = 32; + This->baseShader.limits.constant_float = 224; + This->baseShader.limits.constant_int = 16; + This->baseShader.limits.constant_bool = 16; + This->baseShader.limits.texcoord = 0; + This->baseShader.limits.sampler = 16; + This->baseShader.limits.packed_input = 12; + This->baseShader.limits.label = 16; /* FIXME: 2048 */ + break; + + default: This->baseShader.limits.temporary = 32; + This->baseShader.limits.constant_float = 32; + This->baseShader.limits.constant_int = 16; + This->baseShader.limits.constant_bool = 16; + This->baseShader.limits.texcoord = 8; + This->baseShader.limits.sampler = 16; + This->baseShader.limits.packed_input = 0; + This->baseShader.limits.label = 0; + FIXME("Unrecognized pixel shader version %#x\n", + This->baseShader.hex_version); + } +} + +/** Generate a pixel shader string using either GL_FRAGMENT_PROGRAM_ARB + or GLSL and send it to the card */ +static inline VOID IWineD3DPixelShaderImpl_GenerateShader( + IWineD3DPixelShader *iface, + shader_reg_maps* reg_maps, + CONST DWORD *pFunction) { + + IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; + SHADER_BUFFER buffer; + +#if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders + it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */ + if (This->device->fixupVertexBufferSize < SHADER_PGMSIZE) { + HeapFree(GetProcessHeap(), 0, This->fixupVertexBuffer); + This->fixupVertexBuffer = HeapAlloc(GetProcessHeap() , 0, SHADER_PGMSIZE); + This->fixupVertexBufferSize = PGMSIZE; + This->fixupVertexBuffer[0] = 0; + } + buffer.buffer = This->device->fixupVertexBuffer; +#else + buffer.buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SHADER_PGMSIZE); +#endif + buffer.bsize = 0; + buffer.lineNo = 0; + buffer.newline = TRUE; + + if (This->baseShader.shader_mode == SHADER_GLSL) { + + /* Create the hw GLSL shader object and assign it as the baseShader.prgId */ + GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB)); + + if (GL_SUPPORT(ARB_DRAW_BUFFERS)) { + shader_addline(&buffer, "#extension GL_ARB_draw_buffers : enable\n"); + } + + /* Base Declarations */ + shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION); + + /* Pack 3.0 inputs */ + if (This->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) + pshader_glsl_input_pack(&buffer, This->semantics_in); + + /* Base Shader Body */ + shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction); + + /* Pixel shaders < 2.0 place the resulting color in R0 implicitly */ + if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) { + /* Some older cards like GeforceFX ones don't support multiple buffers, so also not gl_FragData */ + if(GL_SUPPORT(ARB_DRAW_BUFFERS)) + shader_addline(&buffer, "gl_FragData[0] = R0;\n"); + else + shader_addline(&buffer, "gl_FragColor = R0;\n"); + } + + /* Pixel shader < 3.0 do not replace the fog stage. + * This implements linear fog computation and blending. + * TODO: non linear fog + * NOTE: gl_Fog.start and gl_Fog.end don't hold fog start s and end e but + * -1/(e-s) and e/(e-s) respectively. + */ + if(This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) { + shader_addline(&buffer, "float Fog = clamp(gl_FogFragCoord * gl_Fog.start + gl_Fog.end, 0.0, 1.0);\n"); + if(GL_SUPPORT(ARB_DRAW_BUFFERS)) + shader_addline(&buffer, "gl_FragData[0].xyz = mix(gl_Fog.color.xyz, gl_FragData[0].xyz, Fog);\n"); + else + shader_addline(&buffer, "gl_FragColor.xyz = mix(gl_Fog.color.xyz, gl_FragColor.xyz, Fog);\n"); + } + + shader_addline(&buffer, "}\n"); + + TRACE("Compiling shader object %u\n", shader_obj); + GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL)); + GL_EXTCALL(glCompileShaderARB(shader_obj)); + print_glsl_info_log(&GLINFO_LOCATION, shader_obj); + + /* Store the shader object */ + This->baseShader.prgId = shader_obj; + + } else if (This->baseShader.shader_mode == SHADER_ARB) { + /* Create the hw ARB shader */ + shader_addline(&buffer, "!!ARBfp1.0\n"); + + shader_addline(&buffer, "TEMP TMP;\n"); /* Used in matrix ops */ + shader_addline(&buffer, "TEMP TMP2;\n"); /* Used in matrix ops */ + shader_addline(&buffer, "TEMP TA;\n"); /* Used for modifiers */ + shader_addline(&buffer, "TEMP TB;\n"); /* Used for modifiers */ + shader_addline(&buffer, "TEMP TC;\n"); /* Used for modifiers */ + shader_addline(&buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n"); + shader_addline(&buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n"); + shader_addline(&buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n"); + + /* Base Declarations */ + shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION); + + /* We need two variables for fog blending */ + shader_addline(&buffer, "TEMP TMP_FOG;\n"); + if (This->baseShader.hex_version >= WINED3DPS_VERSION(2,0)) { + shader_addline(&buffer, "TEMP TMP_COLOR;\n"); + } + + /* Base Shader Body */ + shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction); + + /* calculate fog and blend it + * NOTE: state.fog.params.y and state.fog.params.z don't hold fog start s and end e but + * -1/(e-s) and e/(e-s) respectively. + */ + shader_addline(&buffer, "MAD_SAT TMP_FOG, fragment.fogcoord, state.fog.params.y, state.fog.params.z;\n"); + if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) { + shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, R0, state.fog.color;\n"); + shader_addline(&buffer, "MOV result.color.a, R0.a;\n"); + } else { + shader_addline(&buffer, "LRP result.color.rgb, TMP_FOG.x, TMP_COLOR, state.fog.color;\n"); + shader_addline(&buffer, "MOV result.color.a, TMP_COLOR.a;\n"); + } + + shader_addline(&buffer, "END\n"); + + /* TODO: change to resource.glObjectHandle or something like that */ + GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId)); + + TRACE("Creating a hw pixel shader, prg=%d\n", This->baseShader.prgId); + GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, This->baseShader.prgId)); + + TRACE("Created hw pixel shader, prg=%d\n", This->baseShader.prgId); + /* Create the program and check for errors */ + GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + buffer.bsize, buffer.buffer)); + + if (glGetError() == GL_INVALID_OPERATION) { + GLint errPos; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); + FIXME("HW PixelShader Error at position %d: %s\n", + errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); + This->baseShader.prgId = -1; + } + } + + This->needsbumpmat = reg_maps->bumpmat; + +#if 1 /* if were using the data buffer of device then we don't need to free it */ + HeapFree(GetProcessHeap(), 0, buffer.buffer); +#endif +} + +static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *iface, CONST DWORD *pFunction) { + + IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface; + IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device; + + TRACE("(%p) : pFunction %p\n", iface, pFunction); + + /* First pass: trace shader */ + shader_trace_init((IWineD3DBaseShader*) This, pFunction); + pshader_set_limits(This); + + /* Initialize immediate constant lists */ + list_init(&This->baseShader.constantsF); + list_init(&This->baseShader.constantsB); + list_init(&This->baseShader.constantsI); + + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) > 1) { + shader_reg_maps *reg_maps = &This->baseShader.reg_maps; + HRESULT hr; + + /* Second pass: figure out which registers are used, what the semantics are, etc.. */ + memset(reg_maps, 0, sizeof(shader_reg_maps)); + hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps, + This->semantics_in, NULL, pFunction, NULL); + if (FAILED(hr)) return hr; + /* FIXME: validate reg_maps against OpenGL */ + } + + This->baseShader.shader_mode = deviceImpl->ps_selected_mode; + + TRACE("(%p) : Copying the function\n", This); + if (NULL != pFunction) { + void *function; + + function = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->baseShader.functionLength); + if (!function) return E_OUTOFMEMORY; + memcpy(function, pFunction, This->baseShader.functionLength); + This->baseShader.function = function; + } else { + This->baseShader.function = NULL; + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader *iface) { + + IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface; + IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + CONST DWORD *function = This->baseShader.function; + + TRACE("(%p) : function %p\n", iface, function); + + /* We're already compiled. */ + if (This->baseShader.is_compiled) return WINED3D_OK; + + /* We don't need to compile */ + if (!function) { + This->baseShader.is_compiled = TRUE; + return WINED3D_OK; + } + + if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1) { + shader_reg_maps *reg_maps = &This->baseShader.reg_maps; + HRESULT hr; + + /* Second pass: figure out which registers are used, what the semantics are, etc.. */ + memset(reg_maps, 0, sizeof(shader_reg_maps)); + hr = shader_get_registers_used((IWineD3DBaseShader*)This, reg_maps, + This->semantics_in, NULL, This->baseShader.function, deviceImpl->stateBlock); + if (FAILED(hr)) return hr; + /* FIXME: validate reg_maps against OpenGL */ + } + + /* Generate the HW shader */ + TRACE("(%p) : Generating hardware program\n", This); + IWineD3DPixelShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function); + + This->baseShader.is_compiled = TRUE; + + return WINED3D_OK; +} + +const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl = +{ + /*** IUnknown methods ***/ + IWineD3DPixelShaderImpl_QueryInterface, + IWineD3DPixelShaderImpl_AddRef, + IWineD3DPixelShaderImpl_Release, + /*** IWineD3DBase methods ***/ + IWineD3DPixelShaderImpl_GetParent, + /*** IWineD3DBaseShader methods ***/ + IWineD3DPixelShaderImpl_SetFunction, + IWineD3DPixelShaderImpl_CompileShader, + /*** IWineD3DPixelShader methods ***/ + IWineD3DPixelShaderImpl_GetDevice, + IWineD3DPixelShaderImpl_GetFunction +}; diff --git a/reactos/dll/directx/wine/wined3d/query.c b/reactos/dll/directx/wine/wined3d/query.c new file mode 100644 index 00000000000..99390f867ea --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/query.c @@ -0,0 +1,433 @@ +/* + * IWineD3DQuery implementation + * + * Copyright 2005 Oliver Stieber + * + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include "config.h" +#include "wined3d_private.h" + +/* + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/Queries.asp + * + * Occlusion Queries: + * http://www.gris.uni-tuebingen.de/~bartz/Publications/paper/hww98.pdf + * http://oss.sgi.com/projects/ogl-sample/registry/ARB/occlusion_query.txt + */ + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info + +/* ******************************************* + IWineD3DQuery IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DQuery)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DQueryImpl_AddRef(IWineD3DQuery *iface) { + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->ref); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) { + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->ref); + ref = InterlockedDecrement(&This->ref); + if (ref == 0) { + if(This->type == WINED3DQUERYTYPE_EVENT) { + if(GL_SUPPORT(APPLE_FENCE)) { + GL_EXTCALL(glDeleteFencesAPPLE(1, &((WineQueryEventData *)(This->extendedData))->fenceId)); + checkGLcall("glDeleteFencesAPPLE"); + } else if(GL_SUPPORT(NV_FENCE)) { + GL_EXTCALL(glDeleteFencesNV(1, &((WineQueryEventData *)(This->extendedData))->fenceId)); + checkGLcall("glDeleteFencesNV"); + } + } else if(This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY)) { + GL_EXTCALL(glDeleteQueriesARB(1, &((WineQueryOcclusionData *)(This->extendedData))->queryId)); + checkGLcall("glDeleteQueriesARB"); + } + + HeapFree(GetProcessHeap(), 0, This->extendedData); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* ******************************************* + IWineD3DQuery IWineD3DQuery parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + + *parent= (IUnknown*) parent; + IUnknown_AddRef(*parent); + TRACE("(%p) : returning %p\n", This, *parent); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DQueryImpl_GetDevice(IWineD3DQuery* iface, IWineD3DDevice **pDevice){ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice); + *pDevice = (IWineD3DDevice *)This->wineD3DDevice; + TRACE("(%p) returning %p\n", This, *pDevice); + return WINED3D_OK; +} + + +static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + HRESULT res = S_OK; + + TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags); + + if(dwSize == 0){ + /*you can use this method to poll the resource for the query status*/ + /*We return success(S_OK) if we support a feature, and faikure(S_FALSE) if we don't, just return success and fluff it for now*/ + return S_OK; + }else{ + } + + switch (This->type){ + + case WINED3DQUERYTYPE_VCACHE: + { + + WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This); + data->Pattern = WINEMAKEFOURCC('C','A','C','H'); + data->OptMethod = 0; /*0 get longest strips, 1 optimize vertex cache*/ + data->CacheSize = 0; /*cache size, only required if OptMethod == 1*/ + data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/ + + } + break; + case WINED3DQUERYTYPE_RESOURCEMANAGER: + { + WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData; + int i; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This); + for(i = 0; i < WINED3DRTYPECOUNT; i++){ + /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/ + /* isTextureResident could be used to get some of this infomration */ + data->stats[i].bThrashing = FALSE; + data->stats[i].ApproxBytesDownloaded = 1; + data->stats[i].NumEvicts = 1; + data->stats[i].NumVidCreates = 1; + data->stats[i].LastPri = 1; + data->stats[i].NumUsed = 1; + data->stats[i].NumUsedInVidMem = 1; + data->stats[i].WorkingSet = 1; + data->stats[i].WorkingSetBytes = 1; + data->stats[i].TotalManaged = 1; + data->stats[i].TotalBytes = 1; + } + + } + break; + case WINED3DQUERYTYPE_VERTEXSTATS: + { + WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This); + data->NumRenderedTriangles = 1; + data->NumExtraClippingTriangles = 1; + + } + break; + case WINED3DQUERYTYPE_EVENT: + { + BOOL* data = pData; + if(GL_SUPPORT(APPLE_FENCE)) { + *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId)); + checkGLcall("glTestFenceAPPLE"); + } else if(GL_SUPPORT(NV_FENCE)) { + *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId)); + checkGLcall("glTestFenceNV"); + } else { + WARN("(%p): reporting GPU idle\n", This); + *data = TRUE; + } + } + break; + case WINED3DQUERYTYPE_OCCLUSION: + { + DWORD* data = pData; + if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) { + GLuint available; + GLuint samples; + GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId; + + GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available)); + checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n"); + TRACE("(%p) : available %d.\n", This, available); + + if (available) { + GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples)); + checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n"); + TRACE("(%p) : Returning %d samples.\n", This, samples); + *data = samples; + res = S_OK; + } else { + res = S_FALSE; + } + } else { + FIXME("(%p) : Occlusion queries not supported. Returning 1.\n", This); + *data = 1; + res = S_OK; + } + } + break; + case WINED3DQUERYTYPE_TIMESTAMP: + { + UINT64* data = pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This); + *data = 1; /*Don't know what this is supposed to be*/ + } + break; + case WINED3DQUERYTYPE_TIMESTAMPDISJOINT: + { + BOOL* data = pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This); + *data = FALSE; /*Don't know what this is supposed to be*/ + } + break; + case WINED3DQUERYTYPE_TIMESTAMPFREQ: + { + UINT64* data = pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This); + *data = 1; /*Don't know what this is supposed to be*/ + } + break; + case WINED3DQUERYTYPE_PIPELINETIMINGS: + { + WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This); + + data->VertexProcessingTimePercent = 1.0f; + data->PixelProcessingTimePercent = 1.0f; + data->OtherGPUProcessingTimePercent = 97.0f; + data->GPUIdleTimePercent = 1.0f; + } + break; + case WINED3DQUERYTYPE_INTERFACETIMINGS: + { + WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This); + + data->WaitingForGPUToUseApplicationResourceTimePercent = 1.0f; + data->WaitingForGPUToAcceptMoreCommandsTimePercent = 1.0f; + data->WaitingForGPUToStayWithinLatencyTimePercent = 1.0f; + data->WaitingForGPUExclusiveResourceTimePercent = 1.0f; + data->WaitingForGPUOtherTimePercent = 96.0f; + } + + break; + case WINED3DQUERYTYPE_VERTEXTIMINGS: + { + WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This); + + data->MemoryProcessingPercent = 50.0f; + data->ComputationProcessingPercent = 50.0f; + + } + break; + case WINED3DQUERYTYPE_PIXELTIMINGS: + { + WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This); + + data->MemoryProcessingPercent = 50.0f; + data->ComputationProcessingPercent = 50.0f; + } + break; + case WINED3DQUERYTYPE_BANDWIDTHTIMINGS: + { + WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This); + + data->MaxBandwidthUtilized = 1.0f; + data->FrontEndUploadMemoryUtilizedPercent = 1.0f; + data->VertexRateUtilizedPercent = 1.0f; + data->TriangleSetupRateUtilizedPercent = 1.0f; + data->FillRateUtilizedPercent = 97.0f; + } + break; + case WINED3DQUERYTYPE_CACHEUTILIZATION: + { + WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData; + FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This); + + data->TextureCacheHitRate = 1.0f; + data->PostTransformVertexCacheHitRate = 1.0f; + } + + + break; + default: + FIXME("(%p) Unhandled query type %d\n",This , This->type); + + }; + + /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH + D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost + */ + return res; /* S_OK if the query data is available*/ +} + + +static DWORD WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + int dataSize = 0; + TRACE("(%p) : type %#x\n", This, This->type); + switch(This->type){ + case WINED3DQUERYTYPE_VCACHE: + dataSize = sizeof(WINED3DDEVINFO_VCACHE); + break; + case WINED3DQUERYTYPE_RESOURCEMANAGER: + dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER); + break; + case WINED3DQUERYTYPE_VERTEXSTATS: + dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS); + break; + case WINED3DQUERYTYPE_EVENT: + dataSize = sizeof(BOOL); + break; + case WINED3DQUERYTYPE_OCCLUSION: + dataSize = sizeof(DWORD); + break; + case WINED3DQUERYTYPE_TIMESTAMP: + dataSize = sizeof(UINT64); + break; + case WINED3DQUERYTYPE_TIMESTAMPDISJOINT: + dataSize = sizeof(BOOL); + break; + case WINED3DQUERYTYPE_TIMESTAMPFREQ: + dataSize = sizeof(UINT64); + break; + case WINED3DQUERYTYPE_PIPELINETIMINGS: + dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS); + break; + case WINED3DQUERYTYPE_INTERFACETIMINGS: + dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS); + break; + case WINED3DQUERYTYPE_VERTEXTIMINGS: + dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS); + break; + case WINED3DQUERYTYPE_PIXELTIMINGS: + dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS); + break; + case WINED3DQUERYTYPE_BANDWIDTHTIMINGS: + dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS); + break; + case WINED3DQUERYTYPE_CACHEUTILIZATION: + dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION); + break; + default: + FIXME("(%p) Unhandled query type %d\n",This , This->type); + dataSize = 0; + } + return dataSize; +} + + +static WINED3DQUERYTYPE WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + return This->type; +} + + +static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIssueFlags){ + IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface; + + TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type); + + switch (This->type) { + case WINED3DQUERYTYPE_OCCLUSION: + if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) { + if (dwIssueFlags & WINED3DISSUE_BEGIN) { + GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId)); + checkGLcall("glBeginQuery()"); + } + if (dwIssueFlags & WINED3DISSUE_END) { + GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB)); + checkGLcall("glEndQuery()"); + } + } else { + FIXME("(%p) : Occlusion queries not supported\n", This); + } + break; + + case WINED3DQUERYTYPE_EVENT: { + if (dwIssueFlags & WINED3DISSUE_END) { + if(GL_SUPPORT(APPLE_FENCE)) { + GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId)); + checkGLcall("glSetFenceAPPLE"); + } else if (GL_SUPPORT(NV_FENCE)) { + GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV)); + checkGLcall("glSetFenceNV"); + } + } else if(dwIssueFlags & WINED3DISSUE_BEGIN) { + /* Started implicitly at device creation */ + ERR("Event query issued with START flag - what to do?\n"); + } + } + + default: + /* The fixme is printed when the app asks for the resulting data */ + WARN("(%p) : Unhandled query type %#x\n", This, This->type); + break; + } + + return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */ +} + + +/********************************************************** + * IWineD3DQuery VTbl follows + **********************************************************/ + +const IWineD3DQueryVtbl IWineD3DQuery_Vtbl = +{ + /*** IUnknown methods ***/ + IWineD3DQueryImpl_QueryInterface, + IWineD3DQueryImpl_AddRef, + IWineD3DQueryImpl_Release, + /*** IWineD3Dquery methods ***/ + IWineD3DQueryImpl_GetParent, + IWineD3DQueryImpl_GetDevice, + IWineD3DQueryImpl_GetData, + IWineD3DQueryImpl_GetDataSize, + IWineD3DQueryImpl_GetType, + IWineD3DQueryImpl_Issue +}; diff --git a/reactos/dll/directx/wine/wined3d/resource.c b/reactos/dll/directx/wine/wined3d/resource.c new file mode 100644 index 00000000000..6999f060c05 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/resource.c @@ -0,0 +1,274 @@ +/* + * IWineD3DResource Implementation + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info + +/* IWineD3DResource IUnknown parts follow: */ +HRESULT WINAPI IWineD3DResourceImpl_QueryInterface(IWineD3DResource *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI IWineD3DResourceImpl_AddRef(IWineD3DResource *iface) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + ULONG ref = InterlockedIncrement(&This->resource.ref); + TRACE("(%p) : AddRef increasing from %d\n", This, ref - 1); + return ref; +} + +ULONG WINAPI IWineD3DResourceImpl_Release(IWineD3DResource *iface) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + ULONG ref = InterlockedDecrement(&This->resource.ref); + TRACE("(%p) : Releasing from %d\n", This, ref + 1); + if (ref == 0) { + IWineD3DResourceImpl_CleanUp(iface); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* class static (not in vtable) */ +void IWineD3DResourceImpl_CleanUp(IWineD3DResource *iface){ + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + struct list *e1, *e2; + PrivateData *data; + HRESULT hr; + + TRACE("(%p) Cleaning up resource\n", This); + if (This->resource.pool == WINED3DPOOL_DEFAULT) { + TRACE("Decrementing device memory pool by %u\n", This->resource.size); + globalChangeGlRam(-This->resource.size); + } + + LIST_FOR_EACH_SAFE(e1, e2, &This->resource.privateData) { + data = LIST_ENTRY(e1, PrivateData, entry); + hr = IWineD3DResourceImpl_FreePrivateData(iface, &data->tag); + if(hr != WINED3D_OK) { + ERR("Failed to free private data when destroying resource %p, hr = %08x\n", This, hr); + } + } + + HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + This->resource.allocatedMemory = 0; + + if (This->resource.wineD3DDevice != NULL) { + IWineD3DDevice_ResourceReleased((IWineD3DDevice *)This->resource.wineD3DDevice, iface); + }/* NOTE: this is not really an error for systemmem resoruces */ + return; +} + +/* IWineD3DResource Interface follow: */ +HRESULT WINAPI IWineD3DResourceImpl_GetDevice(IWineD3DResource *iface, IWineD3DDevice** ppDevice) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + TRACE("(%p) : returning %p\n", This, This->resource.wineD3DDevice); + *ppDevice = (IWineD3DDevice *) This->resource.wineD3DDevice; + IWineD3DDevice_AddRef(*ppDevice); + return WINED3D_OK; +} + +static PrivateData* IWineD3DResourceImpl_FindPrivateData(IWineD3DResourceImpl *This, + REFGUID tag) +{ + PrivateData *data; + struct list *entry; + + TRACE("Searching for private data %s\n", debugstr_guid(tag)); + LIST_FOR_EACH(entry, &This->resource.privateData) + { + data = LIST_ENTRY(entry, PrivateData, entry); + if (IsEqualGUID(&data->tag, tag)) { + TRACE("Found %p\n", data); + return data; + } + } + TRACE("Not found\n"); + return NULL; +} + +HRESULT WINAPI IWineD3DResourceImpl_SetPrivateData(IWineD3DResource *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + PrivateData *data; + + TRACE("(%p) : %s %p %d %d\n", This, debugstr_guid(refguid), pData, SizeOfData, Flags); + IWineD3DResourceImpl_FreePrivateData(iface, refguid); + + data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); + if (NULL == data) return E_OUTOFMEMORY; + + data->tag = *refguid; + data->flags = Flags; +#if 0 + (*data)->uniquenessValue = This->uniquenessValue; +#endif + if (Flags & WINED3DSPD_IUNKNOWN) { + if(SizeOfData != sizeof(IUnknown *)) { + WARN("IUnknown data with size %d, returning WINED3DERR_INVALIDCALL\n", SizeOfData); + return WINED3DERR_INVALIDCALL; + } + data->ptr.object = (LPUNKNOWN)pData; + data->size = sizeof(LPUNKNOWN); + IUnknown_AddRef(data->ptr.object); + } + else + { + data->ptr.data = HeapAlloc(GetProcessHeap(), 0, SizeOfData); + if (NULL == data->ptr.data) { + HeapFree(GetProcessHeap(), 0, data); + return E_OUTOFMEMORY; + } + data->size = SizeOfData; + memcpy(data->ptr.data, pData, SizeOfData); + } + list_add_tail(&This->resource.privateData, &data->entry); + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DResourceImpl_GetPrivateData(IWineD3DResource *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + PrivateData *data; + + TRACE("(%p) : %p %p %p\n", This, refguid, pData, pSizeOfData); + data = IWineD3DResourceImpl_FindPrivateData(This, refguid); + if (data == NULL) return WINED3DERR_NOTFOUND; + + +#if 0 /* This may not be right. */ + if (((*data)->flags & WINED3DSPD_VOLATILE) + && (*data)->uniquenessValue != This->uniquenessValue) + return DDERR_EXPIRED; +#endif + if (*pSizeOfData < data->size) { + *pSizeOfData = data->size; + return WINED3DERR_MOREDATA; + } + + if (data->flags & WINED3DSPD_IUNKNOWN) { + *(LPUNKNOWN *)pData = data->ptr.object; + if(((IWineD3DImpl *) This->resource.wineD3DDevice->wineD3D)->dxVersion != 7) { + /* D3D8 and D3D9 addref the private data, DDraw does not. This can't be handled in + * ddraw because it doesn't know if the pointer returned is an IUnknown * or just a + * Blob + */ + IUnknown_AddRef(data->ptr.object); + } + } + else { + memcpy(pData, data->ptr.data, data->size); + } + + return WINED3D_OK; +} +HRESULT WINAPI IWineD3DResourceImpl_FreePrivateData(IWineD3DResource *iface, REFGUID refguid) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + PrivateData *data; + + TRACE("(%p) : %s\n", This, debugstr_guid(refguid)); + data = IWineD3DResourceImpl_FindPrivateData(This, refguid); + if (data == NULL) return WINED3DERR_NOTFOUND; + + if (data->flags & WINED3DSPD_IUNKNOWN) + { + if (data->ptr.object != NULL) + IUnknown_Release(data->ptr.object); + } else { + HeapFree(GetProcessHeap(), 0, data->ptr.data); + } + list_remove(&data->entry); + + HeapFree(GetProcessHeap(), 0, data); + + return WINED3D_OK; +} + +/* Priority support is not implemented yet */ +DWORD WINAPI IWineD3DResourceImpl_SetPriority(IWineD3DResource *iface, DWORD PriorityNew) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + FIXME("(%p) : stub\n", This); + return 0; +} +DWORD WINAPI IWineD3DResourceImpl_GetPriority(IWineD3DResource *iface) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + FIXME("(%p) : stub\n", This); + return 0; +} + +/* Preloading of resources is not supported yet */ +void WINAPI IWineD3DResourceImpl_PreLoad(IWineD3DResource *iface) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + FIXME("(%p) : stub\n", This); +} + +WINED3DRESOURCETYPE WINAPI IWineD3DResourceImpl_GetType(IWineD3DResource *iface) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + TRACE("(%p) : returning %d\n", This, This->resource.resourceType); + return This->resource.resourceType; +} + +HRESULT WINAPI IWineD3DResourceImpl_GetParent(IWineD3DResource *iface, IUnknown **pParent) { + IWineD3DResourceImpl *This = (IWineD3DResourceImpl *)iface; + IUnknown_AddRef(This->resource.parent); + *pParent = This->resource.parent; + return WINED3D_OK; +} + +void dumpResources(ResourceList *resources) { + ResourceList *iterator = resources; + + while(iterator) { + FIXME("Leftover resource %p with type %d,%s\n", iterator->resource, IWineD3DResource_GetType(iterator->resource), debug_d3dresourcetype(IWineD3DResource_GetType(iterator->resource))); + iterator = iterator->next; + } +} + +static const IWineD3DResourceVtbl IWineD3DResource_Vtbl = +{ + /* IUnknown */ + IWineD3DResourceImpl_QueryInterface, + IWineD3DResourceImpl_AddRef, + IWineD3DResourceImpl_Release, + /* IWineD3DResource */ + IWineD3DResourceImpl_GetParent, + IWineD3DResourceImpl_GetDevice, + IWineD3DResourceImpl_SetPrivateData, + IWineD3DResourceImpl_GetPrivateData, + IWineD3DResourceImpl_FreePrivateData, + IWineD3DResourceImpl_SetPriority, + IWineD3DResourceImpl_GetPriority, + IWineD3DResourceImpl_PreLoad, + IWineD3DResourceImpl_GetType +}; diff --git a/reactos/dll/directx/wine/wined3d/state.c b/reactos/dll/directx/wine/wined3d/state.c new file mode 100644 index 00000000000..9a768d13230 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/state.c @@ -0,0 +1,4528 @@ +/* + * Direct3D state management + * + * Copyright 2002 Lionel Ulmer + * Copyright 2002-2005 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Henri Verbeet + * Copyright 2006-2007 Stefan Dösinger for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include +#ifdef HAVE_FLOAT_H +# include +#endif +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +WINE_DECLARE_DEBUG_CHANNEL(d3d_shader); + +#define GLINFO_LOCATION stateblock->wineD3DDevice->adapter->gl_info + +static void state_nogl(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* Used for states which are not mapped to a gl state as-is, but used somehow different, + * e.g as a parameter for drawing, or which are unimplemented in windows d3d + */ + if(STATE_IS_RENDER(state)) { + WINED3DRENDERSTATETYPE RenderState = state - STATE_RENDER(0); + TRACE("(%s,%d) no direct mapping to gl\n", debug_d3drenderstate(RenderState), stateblock->renderState[RenderState]); + } else { + /* Shouldn't have an unknown type here */ + FIXME("%d no direct mapping to gl of state with unknown type\n", state); + } +} + +static void state_undefined(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* Print a WARN, this allows the stateblock code to loop over all states to generate a display + * list without causing confusing terminal output. Deliberately no special debug name here + * because its undefined. + */ + WARN("undefined state %d\n", state); +} + +static void state_fillmode(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + WINED3DFILLMODE Value = stateblock->renderState[WINED3DRS_FILLMODE]; + + switch(Value) { + case WINED3DFILL_POINT: + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + checkGLcall("glPolygonMode(GL_FRONT_AND_BACK, GL_POINT)"); + break; + case WINED3DFILL_WIREFRAME: + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + checkGLcall("glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)"); + break; + case WINED3DFILL_SOLID: + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + checkGLcall("glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)"); + break; + default: + FIXME("Unrecognized WINED3DRS_FILLMODE value %d\n", Value); + } +} + +static void state_lighting(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + BOOL transformed; + + /* Lighting is not enabled if transformed vertices are drawn + * but lighting does not affect the stream sources, so it is not grouped for performance reasons. + * This state reads the decoded vertex decl, so if it is dirty don't do anything. The + * vertex declaration appplying function calls this function for updating + */ + + if(isStateDirty(context, STATE_VDECL)) { + return; + } + + transformed = ((stateblock->wineD3DDevice->strided_streams.u.s.position.lpData != NULL || + stateblock->wineD3DDevice->strided_streams.u.s.position.VBO != 0) && + stateblock->wineD3DDevice->strided_streams.u.s.position_transformed) ? TRUE : FALSE; + + if (stateblock->renderState[WINED3DRS_LIGHTING] && !transformed) { + glEnable(GL_LIGHTING); + checkGLcall("glEnable GL_LIGHTING"); + } else { + glDisable(GL_LIGHTING); + checkGLcall("glDisable GL_LIGHTING"); + } +} + +static void state_zenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* No z test without depth stencil buffers */ + if(stateblock->wineD3DDevice->stencilBufferTarget == NULL) { + glDisable(GL_DEPTH_TEST); /* This also disables z writing in gl */ + checkGLcall("glDisable GL_DEPTH_TEST"); + return; + } + + switch ((WINED3DZBUFFERTYPE) stateblock->renderState[WINED3DRS_ZENABLE]) { + case WINED3DZB_FALSE: + glDisable(GL_DEPTH_TEST); + checkGLcall("glDisable GL_DEPTH_TEST"); + break; + case WINED3DZB_TRUE: + glEnable(GL_DEPTH_TEST); + checkGLcall("glEnable GL_DEPTH_TEST"); + break; + case WINED3DZB_USEW: + glEnable(GL_DEPTH_TEST); + checkGLcall("glEnable GL_DEPTH_TEST"); + FIXME("W buffer is not well handled\n"); + break; + default: + FIXME("Unrecognized D3DZBUFFERTYPE value %d\n", stateblock->renderState[WINED3DRS_ZENABLE]); + } +} + +static void state_cullmode(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* TODO: Put this into the offscreen / onscreen rendering block due to device->render_offscreen */ + + /* If we are culling "back faces with clockwise vertices" then + set front faces to be counter clockwise and enable culling + of back faces */ + switch ((WINED3DCULL) stateblock->renderState[WINED3DRS_CULLMODE]) { + case WINED3DCULL_NONE: + glDisable(GL_CULL_FACE); + checkGLcall("glDisable GL_CULL_FACE"); + break; + case WINED3DCULL_CW: + glEnable(GL_CULL_FACE); + checkGLcall("glEnable GL_CULL_FACE"); + if (stateblock->wineD3DDevice->render_offscreen) { + glFrontFace(GL_CW); + checkGLcall("glFrontFace GL_CW"); + } else { + glFrontFace(GL_CCW); + checkGLcall("glFrontFace GL_CCW"); + } + glCullFace(GL_BACK); + break; + case WINED3DCULL_CCW: + glEnable(GL_CULL_FACE); + checkGLcall("glEnable GL_CULL_FACE"); + if (stateblock->wineD3DDevice->render_offscreen) { + glFrontFace(GL_CCW); + checkGLcall("glFrontFace GL_CCW"); + } else { + glFrontFace(GL_CW); + checkGLcall("glFrontFace GL_CW"); + } + glCullFace(GL_BACK); + break; + default: + FIXME("Unrecognized/Unhandled WINED3DCULL value %d\n", stateblock->renderState[WINED3DRS_CULLMODE]); + } +} + +static void state_shademode(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + switch ((WINED3DSHADEMODE) stateblock->renderState[WINED3DRS_SHADEMODE]) { + case WINED3DSHADE_FLAT: + glShadeModel(GL_FLAT); + checkGLcall("glShadeModel(GL_FLAT)"); + break; + case WINED3DSHADE_GOURAUD: + glShadeModel(GL_SMOOTH); + checkGLcall("glShadeModel(GL_SMOOTH)"); + break; + case WINED3DSHADE_PHONG: + FIXME("WINED3DSHADE_PHONG isn't supported\n"); + break; + default: + FIXME("Unrecognized/Unhandled WINED3DSHADEMODE value %d\n", stateblock->renderState[WINED3DRS_SHADEMODE]); + } +} + +static void state_ditherenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if (stateblock->renderState[WINED3DRS_DITHERENABLE]) { + glEnable(GL_DITHER); + checkGLcall("glEnable GL_DITHER"); + } else { + glDisable(GL_DITHER); + checkGLcall("glDisable GL_DITHER"); + } +} + +static void state_zwritenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* TODO: Test if in d3d z writing is enabled even if ZENABLE is off. If yes, + * this has to be merged with ZENABLE and ZFUNC + */ + if (stateblock->renderState[WINED3DRS_ZWRITEENABLE]) { + glDepthMask(1); + checkGLcall("glDepthMask(1)"); + } else { + glDepthMask(0); + checkGLcall("glDepthMask(0)"); + } +} + +static void state_zfunc(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + int glParm = CompareFunc(stateblock->renderState[WINED3DRS_ZFUNC]); + + if(glParm) { + glDepthFunc(glParm); + checkGLcall("glDepthFunc"); + } +} + +static void state_ambient(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + float col[4]; + D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_AMBIENT], col); + + TRACE("Setting ambient to (%f,%f,%f,%f)\n", col[0], col[1], col[2], col[3]); + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col); + checkGLcall("glLightModel for MODEL_AMBIENT"); +} + +static void state_blend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + int srcBlend = GL_ZERO; + int dstBlend = GL_ZERO; + + /* GL_LINE_SMOOTH needs GL_BLEND to work, according to the red book, and special blending params */ + if (stateblock->renderState[WINED3DRS_ALPHABLENDENABLE] || + stateblock->renderState[WINED3DRS_EDGEANTIALIAS] || + stateblock->renderState[WINED3DRS_ANTIALIASEDLINEENABLE]) { + glEnable(GL_BLEND); + checkGLcall("glEnable GL_BLEND"); + } else { + glDisable(GL_BLEND); + checkGLcall("glDisable GL_BLEND"); + /* Nothing more to do - get out */ + return; + }; + + switch (stateblock->renderState[WINED3DRS_SRCBLEND]) { + case WINED3DBLEND_ZERO : srcBlend = GL_ZERO; break; + case WINED3DBLEND_ONE : srcBlend = GL_ONE; break; + case WINED3DBLEND_SRCCOLOR : srcBlend = GL_SRC_COLOR; break; + case WINED3DBLEND_INVSRCCOLOR : srcBlend = GL_ONE_MINUS_SRC_COLOR; break; + case WINED3DBLEND_SRCALPHA : srcBlend = GL_SRC_ALPHA; break; + case WINED3DBLEND_INVSRCALPHA : srcBlend = GL_ONE_MINUS_SRC_ALPHA; break; + case WINED3DBLEND_DESTALPHA : srcBlend = GL_DST_ALPHA; break; + case WINED3DBLEND_INVDESTALPHA : srcBlend = GL_ONE_MINUS_DST_ALPHA; break; + case WINED3DBLEND_DESTCOLOR : srcBlend = GL_DST_COLOR; break; + case WINED3DBLEND_INVDESTCOLOR : srcBlend = GL_ONE_MINUS_DST_COLOR; break; + case WINED3DBLEND_SRCALPHASAT : srcBlend = GL_SRC_ALPHA_SATURATE; break; + + case WINED3DBLEND_BOTHSRCALPHA : srcBlend = GL_SRC_ALPHA; + dstBlend = GL_SRC_ALPHA; + break; + + case WINED3DBLEND_BOTHINVSRCALPHA : srcBlend = GL_ONE_MINUS_SRC_ALPHA; + dstBlend = GL_ONE_MINUS_SRC_ALPHA; + break; + + case WINED3DBLEND_BLENDFACTOR : srcBlend = GL_CONSTANT_COLOR; break; + case WINED3DBLEND_INVBLENDFACTOR : srcBlend = GL_ONE_MINUS_CONSTANT_COLOR; break; + default: + FIXME("Unrecognized src blend value %d\n", stateblock->renderState[WINED3DRS_SRCBLEND]); + } + + switch (stateblock->renderState[WINED3DRS_DESTBLEND]) { + case WINED3DBLEND_ZERO : dstBlend = GL_ZERO; break; + case WINED3DBLEND_ONE : dstBlend = GL_ONE; break; + case WINED3DBLEND_SRCCOLOR : dstBlend = GL_SRC_COLOR; break; + case WINED3DBLEND_INVSRCCOLOR : dstBlend = GL_ONE_MINUS_SRC_COLOR; break; + case WINED3DBLEND_SRCALPHA : dstBlend = GL_SRC_ALPHA; break; + case WINED3DBLEND_INVSRCALPHA : dstBlend = GL_ONE_MINUS_SRC_ALPHA; break; + case WINED3DBLEND_DESTALPHA : dstBlend = GL_DST_ALPHA; break; + case WINED3DBLEND_INVDESTALPHA : dstBlend = GL_ONE_MINUS_DST_ALPHA; break; + case WINED3DBLEND_DESTCOLOR : dstBlend = GL_DST_COLOR; break; + case WINED3DBLEND_INVDESTCOLOR : dstBlend = GL_ONE_MINUS_DST_COLOR; break; + + case WINED3DBLEND_SRCALPHASAT : + dstBlend = GL_SRC_ALPHA_SATURATE; + WARN("Application uses SRCALPHASAT as dest blend factor, expect problems\n"); + break; + + case WINED3DBLEND_BOTHSRCALPHA : dstBlend = GL_SRC_ALPHA; + srcBlend = GL_SRC_ALPHA; + break; + + case WINED3DBLEND_BOTHINVSRCALPHA : dstBlend = GL_ONE_MINUS_SRC_ALPHA; + srcBlend = GL_ONE_MINUS_SRC_ALPHA; + break; + + case WINED3DBLEND_BLENDFACTOR : dstBlend = GL_CONSTANT_COLOR; break; + case WINED3DBLEND_INVBLENDFACTOR : dstBlend = GL_ONE_MINUS_CONSTANT_COLOR; break; + default: + FIXME("Unrecognized dst blend value %d\n", stateblock->renderState[WINED3DRS_DESTBLEND]); + } + + if(stateblock->renderState[WINED3DRS_EDGEANTIALIAS] || + stateblock->renderState[WINED3DRS_ANTIALIASEDLINEENABLE]) { + glEnable(GL_LINE_SMOOTH); + checkGLcall("glEnable(GL_LINE_SMOOTH)"); + if(srcBlend != GL_SRC_ALPHA) { + WARN("WINED3DRS_EDGEANTIALIAS enabled, but unexpected src blending param\n"); + } + if(dstBlend != GL_ONE_MINUS_SRC_ALPHA && dstBlend != GL_ONE) { + WARN("WINED3DRS_EDGEANTIALIAS enabled, but unexpected dst blending param\n"); + } + } else { + glDisable(GL_LINE_SMOOTH); + checkGLcall("glDisable(GL_LINE_SMOOTH)"); + } + + TRACE("glBlendFunc src=%x, dst=%x\n", srcBlend, dstBlend); + glBlendFunc(srcBlend, dstBlend); + checkGLcall("glBlendFunc"); +} + +static void state_blendfactor(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + float col[4]; + + TRACE("Setting BlendFactor to %d\n", stateblock->renderState[WINED3DRS_BLENDFACTOR]); + D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_BLENDFACTOR], col); + GL_EXTCALL(glBlendColor (col[0],col[1],col[2],col[3])); + checkGLcall("glBlendColor"); +} + +static void state_alpha(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + int glParm = 0; + float ref; + BOOL enable_ckey = FALSE; + + IWineD3DSurfaceImpl *surf; + + /* Find out if the texture on the first stage has a ckey set + * The alpha state func reads the texture settings, even though alpha and texture are not grouped + * together. This is to avoid making a huge alpha+texture+texture stage+ckey block due to the hardly + * used WINED3DRS_COLORKEYENABLE state(which is d3d <= 3 only). The texture function will call alpha + * in case it finds some texture+colorkeyenable combination which needs extra care. + */ + if(stateblock->textures[0] && stateblock->textureDimensions[0] == GL_TEXTURE_2D) { + surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *)stateblock->textures[0])->surfaces[0]; + + if(surf->CKeyFlags & WINEDDSD_CKSRCBLT) { + const StaticPixelFormatDesc *fmt = getFormatDescEntry(surf->resource.format, NULL, NULL); + /* The surface conversion does not do color keying conversion for surfaces that have an alpha + * channel on their own. Likewise, the alpha test shouldn't be set up for color keying if the + * surface has alpha bits + */ + if(fmt->alphaMask == 0x00000000) { + enable_ckey = TRUE; + } + } + } + + if(enable_ckey || context->last_was_ckey) { + StateTable[STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP)].apply(STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), stateblock, context); + } + context->last_was_ckey = enable_ckey; + + if (stateblock->renderState[WINED3DRS_ALPHATESTENABLE] || + (stateblock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey)) { + glEnable(GL_ALPHA_TEST); + checkGLcall("glEnable GL_ALPHA_TEST"); + } else { + glDisable(GL_ALPHA_TEST); + checkGLcall("glDisable GL_ALPHA_TEST"); + /* Alpha test is disabled, don't bother setting the params - it will happen on the next + * enable call + */ + return; + } + + if(stateblock->renderState[WINED3DRS_COLORKEYENABLE] && enable_ckey) { + glParm = GL_NOTEQUAL; + ref = 0.0; + } else { + ref = ((float) stateblock->renderState[WINED3DRS_ALPHAREF]) / 255.0f; + glParm = CompareFunc(stateblock->renderState[WINED3DRS_ALPHAFUNC]); + } + if(glParm) { + glAlphaFunc(glParm, ref); + checkGLcall("glAlphaFunc"); + } +} + +static void state_clipping(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD enable = 0xFFFFFFFF; + DWORD disable = 0x00000000; + + if (use_vs(stateblock->wineD3DDevice)) { + /* The spec says that opengl clipping planes are disabled when using shaders. Direct3D planes aren't, + * so that is an issue. The MacOS ATI driver keeps clipping planes activated with shaders in some + * contitions I got sick of tracking down. The shader state handler disables all clip planes because + * of that - don't do anything here and keep them disabled + */ + if(stateblock->renderState[WINED3DRS_CLIPPLANEENABLE]) { + static BOOL warned = FALSE; + if(!warned) { + FIXME("Clipping not supported with vertex shaders\n"); + warned = TRUE; + } + } + return; + } + + /* TODO: Keep track of previously enabled clipplanes to avoid unnecessary resetting + * of already set values + */ + + /* If enabling / disabling all + * TODO: Is this correct? Doesn't D3DRS_CLIPPING disable clipping on the viewport frustrum? + */ + if (stateblock->renderState[WINED3DRS_CLIPPING]) { + enable = stateblock->renderState[WINED3DRS_CLIPPLANEENABLE]; + disable = ~stateblock->renderState[WINED3DRS_CLIPPLANEENABLE]; + } else { + disable = 0xffffffff; + enable = 0x00; + } + + if (enable & WINED3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); } + if (enable & WINED3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); } + if (enable & WINED3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); } + if (enable & WINED3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); } + if (enable & WINED3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); } + if (enable & WINED3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); } + + if (disable & WINED3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); } + if (disable & WINED3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); } + if (disable & WINED3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); } + if (disable & WINED3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); } + if (disable & WINED3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); } + if (disable & WINED3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); } + + /** update clipping status */ + if (enable) { + stateblock->clip_status.ClipUnion = 0; + stateblock->clip_status.ClipIntersection = 0xFFFFFFFF; + } else { + stateblock->clip_status.ClipUnion = 0; + stateblock->clip_status.ClipIntersection = 0; + } +} + +static void state_blendop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + int glParm = GL_FUNC_ADD; + + if(!GL_SUPPORT(EXT_BLEND_MINMAX)) { + WARN("Unsupported in local OpenGL implementation: glBlendEquation\n"); + return; + } + + switch ((WINED3DBLENDOP) stateblock->renderState[WINED3DRS_BLENDOP]) { + case WINED3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break; + case WINED3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break; + case WINED3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break; + case WINED3DBLENDOP_MIN : glParm = GL_MIN; break; + case WINED3DBLENDOP_MAX : glParm = GL_MAX; break; + default: + FIXME("Unrecognized/Unhandled D3DBLENDOP value %d\n", stateblock->renderState[WINED3DRS_BLENDOP]); + } + + TRACE("glBlendEquation(%x)\n", glParm); + GL_EXTCALL(glBlendEquation(glParm)); + checkGLcall("glBlendEquation"); +} + +static void +state_specularenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* Originally this used glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR) + * and (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SINGLE_COLOR) to swap between enabled/disabled + * specular color. This is wrong: + * Separate specular color means the specular colour is maintained separately, whereas + * single color means it is merged in. However in both cases they are being used to + * some extent. + * To disable specular color, set it explicitly to black and turn off GL_COLOR_SUM_EXT + * NOTE: If not supported don't give FIXMEs the impact is really minimal and very few people are + * running 1.4 yet! + * + * + * If register combiners are enabled, enabling / disabling GL_COLOR_SUM has no effect. + * Instead, we need to setup the FinalCombiner properly. + * + * The default setup for the FinalCombiner is: + * + * + * GL_VARIABLE_A_NV GL_FOG, GL_UNSIGNED_IDENTITY_NV GL_ALPHA + * GL_VARIABLE_B_NV GL_SPARE0_PLUS_SECONDARY_COLOR_NV GL_UNSIGNED_IDENTITY_NV GL_RGB + * GL_VARIABLE_C_NV GL_FOG GL_UNSIGNED_IDENTITY_NV GL_RGB + * GL_VARIABLE_D_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB + * GL_VARIABLE_E_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB + * GL_VARIABLE_F_NV GL_ZERO GL_UNSIGNED_IDENTITY_NV GL_RGB + * GL_VARIABLE_G_NV GL_SPARE0_NV GL_UNSIGNED_IDENTITY_NV GL_ALPHA + * + * That's pretty much fine as it is, except for variable B, which needs to take + * either GL_SPARE0_PLUS_SECONDARY_COLOR_NV or GL_SPARE0_NV, depending on + * whether WINED3DRS_SPECULARENABLE is enabled or not. + */ + + TRACE("Setting specular enable state and materials\n"); + if (stateblock->renderState[WINED3DRS_SPECULARENABLE]) { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &stateblock->material.Specular); + checkGLcall("glMaterialfv"); + + if(stateblock->material.Power > 128.0) { + /* glMaterialf man page says that the material says that GL_SHININESS must be between 0.0 + * and 128.0, although in d3d neither -1 nor 129 produce an error. For values > 128 clamp + * them, since 128 results in a hardly visible specular highlight, so it should be safe to + * to clamp to 128 + */ + WARN("Material power > 128\n"); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128.0); + } else { + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, stateblock->material.Power); + } + checkGLcall("glMaterialf(GL_SHININESS"); + + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + glEnable(GL_COLOR_SUM_EXT); + } else { + TRACE("Specular colors cannot be enabled in this version of opengl\n"); + } + checkGLcall("glEnable(GL_COLOR_SUM)"); + + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_PLUS_SECONDARY_COLOR_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB)); + checkGLcall("glFinalCombinerInputNV()"); + } + } else { + float black[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* for the case of enabled lighting: */ + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]); + checkGLcall("glMaterialfv"); + + /* for the case of disabled lighting: */ + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + glDisable(GL_COLOR_SUM_EXT); + } else { + TRACE("Specular colors cannot be disabled in this version of opengl\n"); + } + checkGLcall("glDisable(GL_COLOR_SUM)"); + + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + GL_EXTCALL(glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_RGB)); + checkGLcall("glFinalCombinerInputNV()"); + } + } + + TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", stateblock->wineD3DDevice, stateblock->material.Diffuse.r, stateblock->material.Diffuse.g, + stateblock->material.Diffuse.b, stateblock->material.Diffuse.a); + TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", stateblock->wineD3DDevice, stateblock->material.Ambient.r, stateblock->material.Ambient.g, + stateblock->material.Ambient.b, stateblock->material.Ambient.a); + TRACE("(%p) : Specular (%f,%f,%f,%f)\n", stateblock->wineD3DDevice, stateblock->material.Specular.r, stateblock->material.Specular.g, + stateblock->material.Specular.b, stateblock->material.Specular.a); + TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", stateblock->wineD3DDevice, stateblock->material.Emissive.r, stateblock->material.Emissive.g, + stateblock->material.Emissive.b, stateblock->material.Emissive.a); + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &stateblock->material.Ambient); + checkGLcall("glMaterialfv(GL_AMBIENT)"); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &stateblock->material.Diffuse); + checkGLcall("glMaterialfv(GL_DIFFUSE)"); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &stateblock->material.Emissive); + checkGLcall("glMaterialfv(GL_EMISSION)"); +} + +static void state_texfactor(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + unsigned int i; + + /* Note the texture color applies to all textures whereas + * GL_TEXTURE_ENV_COLOR applies to active only + */ + float col[4]; + D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_TEXTUREFACTOR], col); + + if (!GL_SUPPORT(NV_REGISTER_COMBINERS)) { + /* And now the default texture color as well */ + for (i = 0; i < GL_LIMITS(texture_stages); i++) { + /* Note the WINED3DRS value applies to all textures, but GL has one + * per texture, so apply it now ready to be used! + */ + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i)); + checkGLcall("glActiveTextureARB"); + } else if (i>0) { + FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + } + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]); + checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);"); + } + } else { + GL_EXTCALL(glCombinerParameterfvNV(GL_CONSTANT_COLOR0_NV, &col[0])); + } +} + +static void +renderstate_stencil_twosided(IWineD3DStateBlockImpl *stateblock, GLint face, GLint func, GLint ref, GLuint mask, GLint stencilFail, GLint depthFail, GLint stencilPass ) { +#if 0 /* Don't use OpenGL 2.0 calls for now */ + if(GL_EXTCALL(glStencilFuncSeparate) && GL_EXTCALL(glStencilOpSeparate)) { + GL_EXTCALL(glStencilFuncSeparate(face, func, ref, mask)); + checkGLcall("glStencilFuncSeparate(...)"); + GL_EXTCALL(glStencilOpSeparate(face, stencilFail, depthFail, stencilPass)); + checkGLcall("glStencilOpSeparate(...)"); + } + else +#endif + if(GL_SUPPORT(EXT_STENCIL_TWO_SIDE)) { + glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); + checkGLcall("glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)"); + GL_EXTCALL(glActiveStencilFaceEXT(face)); + checkGLcall("glActiveStencilFaceEXT(...)"); + glStencilFunc(func, ref, mask); + checkGLcall("glStencilFunc(...)"); + glStencilOp(stencilFail, depthFail, stencilPass); + checkGLcall("glStencilOp(...)"); + } else if(GL_SUPPORT(ATI_SEPARATE_STENCIL)) { + GL_EXTCALL(glStencilFuncSeparateATI(face, func, ref, mask)); + checkGLcall("glStencilFuncSeparateATI(...)"); + GL_EXTCALL(glStencilOpSeparateATI(face, stencilFail, depthFail, stencilPass)); + checkGLcall("glStencilOpSeparateATI(...)"); + } else { + ERR("Separate (two sided) stencil not supported on this version of opengl. Caps weren't honored?\n"); + } +} + +static void +state_stencil(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD onesided_enable = FALSE; + DWORD twosided_enable = FALSE; + GLint func = GL_ALWAYS; + GLint func_ccw = GL_ALWAYS; + GLint ref = 0; + GLuint mask = 0; + GLint stencilFail = GL_KEEP; + GLint depthFail = GL_KEEP; + GLint stencilPass = GL_KEEP; + GLint stencilFail_ccw = GL_KEEP; + GLint depthFail_ccw = GL_KEEP; + GLint stencilPass_ccw = GL_KEEP; + + /* No stencil test without a stencil buffer */ + if(stateblock->wineD3DDevice->stencilBufferTarget == NULL) { + glDisable(GL_STENCIL_TEST); + checkGLcall("glDisable GL_STENCIL_TEST"); + return; + } + + onesided_enable = stateblock->renderState[WINED3DRS_STENCILENABLE]; + twosided_enable = stateblock->renderState[WINED3DRS_TWOSIDEDSTENCILMODE]; + if( !( func = CompareFunc(stateblock->renderState[WINED3DRS_STENCILFUNC]) ) ) + func = GL_ALWAYS; + if( !( func_ccw = CompareFunc(stateblock->renderState[WINED3DRS_CCW_STENCILFUNC]) ) ) + func = GL_ALWAYS; + ref = stateblock->renderState[WINED3DRS_STENCILREF]; + mask = stateblock->renderState[WINED3DRS_STENCILMASK]; + stencilFail = StencilOp(stateblock->renderState[WINED3DRS_STENCILFAIL]); + depthFail = StencilOp(stateblock->renderState[WINED3DRS_STENCILZFAIL]); + stencilPass = StencilOp(stateblock->renderState[WINED3DRS_STENCILPASS]); + stencilFail_ccw = StencilOp(stateblock->renderState[WINED3DRS_CCW_STENCILFAIL]); + depthFail_ccw = StencilOp(stateblock->renderState[WINED3DRS_CCW_STENCILZFAIL]); + stencilPass_ccw = StencilOp(stateblock->renderState[WINED3DRS_CCW_STENCILPASS]); + + TRACE("(onesided %d, twosided %d, ref %x, mask %x, " + "GL_FRONT: func: %x, fail %x, zfail %x, zpass %x " + "GL_BACK: func: %x, fail %x, zfail %x, zpass %x )\n", + onesided_enable, twosided_enable, ref, mask, + func, stencilFail, depthFail, stencilPass, + func_ccw, stencilFail_ccw, depthFail_ccw, stencilPass_ccw); + + if (twosided_enable) { + renderstate_stencil_twosided(stateblock, GL_FRONT, func, ref, mask, stencilFail, depthFail, stencilPass); + renderstate_stencil_twosided(stateblock, GL_BACK, func_ccw, ref, mask, stencilFail_ccw, depthFail_ccw, stencilPass_ccw); + } else { + if (onesided_enable) { + glEnable(GL_STENCIL_TEST); + checkGLcall("glEnable GL_STENCIL_TEST"); + glStencilFunc(func, ref, mask); + checkGLcall("glStencilFunc(...)"); + glStencilOp(stencilFail, depthFail, stencilPass); + checkGLcall("glStencilOp(...)"); + } else { + glDisable(GL_STENCIL_TEST); + checkGLcall("glDisable GL_STENCIL_TEST"); + } + } +} + +static void state_stencilwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->wineD3DDevice->stencilBufferTarget) { + glStencilMask(stateblock->renderState[WINED3DRS_STENCILWRITEMASK]); + } else { + glStencilMask(0); + } + checkGLcall("glStencilMask"); +} + +static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* TODO: Put this into the vertex type block once that is in the state table */ + BOOL fogenable = stateblock->renderState[WINED3DRS_FOGENABLE]; + BOOL is_ps3 = use_ps(stateblock->wineD3DDevice) + && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.hex_version >= WINED3DPS_VERSION(3,0); + float fogstart, fogend; + + union { + DWORD d; + float f; + } tmpvalue; + + if (!fogenable) { + /* No fog? Disable it, and we're done :-) */ + glDisable(GL_FOG); + checkGLcall("glDisable GL_FOG"); + if( use_ps(stateblock->wineD3DDevice) + && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.hex_version < WINED3DPS_VERSION(3,0) ) { + /* disable fog in the pixel shader + * NOTE: For pixel shader, GL_FOG_START and GL_FOG_END don't hold fog start s and end e but + * -1/(e-s) and e/(e-s) respectively. + */ + glFogf(GL_FOG_START, 0.0f); + checkGLcall("glFogf(GL_FOG_START, fogstart"); + glFogf(GL_FOG_END, 1.0f); + checkGLcall("glFogf(GL_FOG_END, fogend"); + } + return; + } + + tmpvalue.d = stateblock->renderState[WINED3DRS_FOGSTART]; + fogstart = tmpvalue.f; + tmpvalue.d = stateblock->renderState[WINED3DRS_FOGEND]; + fogend = tmpvalue.f; + + /* Fog Rules: + * + * With fixed function vertex processing, Direct3D knows 2 different fog input sources. + * It can use the Z value of the vertex, or the alpha component of the specular color. + * This depends on the fog vertex, fog table and the vertex declaration. If the Z value + * is used, fogstart, fogend and the equation type are used, otherwise linear fog with + * start = 255, end = 0 is used. Obviously the msdn is not very clear on that. + * + * FOGTABLEMODE != NONE: + * The Z value is used, with the equation specified, no matter what vertex type. + * + * FOGTABLEMODE == NONE, FOGVERTEXMODE != NONE, untransformed: + * Per vertex fog is calculated using the specified fog equation and the parameters + * + * FOGTABLEMODE == NONE, FOGVERTEXMODE != NONE, transformed, OR + * FOGTABLEMODE == NONE, FOGVERTEXMODE == NONE, untransformed: + * Linear fog with start = 255.0, end = 0.0, input comes from the specular color + * + * + * Rules for vertex fog with shaders: + * + * When mixing fixed function functionality with the programmable pipeline, D3D expects + * the fog computation to happen during transformation while openGL expects it to happen + * during rasterization. Also, prior to pixel shader 3.0 D3D handles fog blending after + * the pixel shader while openGL always expects the pixel shader to handle the blending. + * To solve this problem, WineD3D does: + * 1) implement a linear fog equation and fog blending at the end of every pre 3.0 pixel + * shader, + * and 2) disables the fog computation (in either the fixed function or programmable + * rasterizer) if using a vertex program. + * + * + * If a fogtablemode and a fogvertexmode are specified, table fog is applied (with or + * without shaders). + */ + + if( is_ps3 ) { + if( !use_vs(stateblock->wineD3DDevice) + && stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE ) { + FIXME("Implement vertex fog for pixel shader >= 3.0 and fixed function pipeline\n"); + } + } + + if (use_vs(stateblock->wineD3DDevice) + && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.fog) { + if( stateblock->renderState[WINED3DRS_FOGTABLEMODE] != WINED3DFOG_NONE ) { + if(!is_ps3) FIXME("Implement table fog for foggy vertex shader\n"); + /* Disable fog */ + fogenable = FALSE; + } else { + /* Set fog computation in the rasterizer to pass through the value (just blend it) */ + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)"); + fogstart = 1.0; + fogend = 0.0; + } + context->last_was_foggy_shader = TRUE; + } + else if( use_ps(stateblock->wineD3DDevice) ) { + /* NOTE: For pixel shader, GL_FOG_START and GL_FOG_END don't hold fog start s and end e but + * -1/(e-s) and e/(e-s) respectively to simplify fog computation in the shader. + */ + WINED3DFOGMODE mode; + context->last_was_foggy_shader = FALSE; + + /* If both fogmodes are set use the table fog mode */ + if(stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) + mode = stateblock->renderState[WINED3DRS_FOGVERTEXMODE]; + else + mode = stateblock->renderState[WINED3DRS_FOGTABLEMODE]; + + switch (mode) { + case WINED3DFOG_EXP: + case WINED3DFOG_EXP2: + if(!is_ps3) FIXME("Implement non linear fog for pixel shader < 3.0\n"); + /* Disable fog */ + fogenable = FALSE; + break; + + case WINED3DFOG_LINEAR: + fogstart = -1.0f/(fogend-fogstart); + fogend *= -fogstart; + break; + + case WINED3DFOG_NONE: + if(!is_ps3) FIXME("Implement software vertex fog for pixel shader < 3.0\n"); + /* Disable fog */ + fogenable = FALSE; + break; + default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", stateblock->renderState[WINED3DRS_FOGVERTEXMODE]); + } + } + /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, + * the system will apply only pixel(=table) fog effects." + */ + else if(stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) { + glHint(GL_FOG_HINT, GL_FASTEST); + checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)"); + context->last_was_foggy_shader = FALSE; + + switch (stateblock->renderState[WINED3DRS_FOGVERTEXMODE]) { + /* If processed vertices are used, fall through to the NONE case */ + case WINED3DFOG_EXP: { + if(!context->last_was_rhw) { + glFogi(GL_FOG_MODE, GL_EXP); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + } + break; + } + } + case WINED3DFOG_EXP2: { + if(!context->last_was_rhw) { + glFogi(GL_FOG_MODE, GL_EXP2); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + } + break; + } + } + case WINED3DFOG_LINEAR: { + if(!context->last_was_rhw) { + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + } + break; + } + } + case WINED3DFOG_NONE: { + /* Both are none? According to msdn the alpha channel of the specular + * color contains a fog factor. Set it in drawStridedSlow. + * Same happens with Vertexfog on transformed vertices + */ + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT)\n"); + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)"); + fogstart = 0xff; + fogend = 0x0; + } else { + /* Disable GL fog, handle this in software in drawStridedSlow */ + fogenable = FALSE; + } + break; + } + default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %d\n", stateblock->renderState[WINED3DRS_FOGVERTEXMODE]); + } + } else { + glHint(GL_FOG_HINT, GL_NICEST); + checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)"); + context->last_was_foggy_shader = FALSE; + + switch (stateblock->renderState[WINED3DRS_FOGTABLEMODE]) { + case WINED3DFOG_EXP: + glFogi(GL_FOG_MODE, GL_EXP); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + } + break; + + case WINED3DFOG_EXP2: + glFogi(GL_FOG_MODE, GL_EXP2); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + } + break; + + case WINED3DFOG_LINEAR: + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT); + checkGLcall("glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FRAGMENT_DEPTH_EXT"); + } + break; + + case WINED3DFOG_NONE: /* Won't happen */ + default: + FIXME("Unexpected WINED3DRS_FOGTABLEMODE %d\n", stateblock->renderState[WINED3DRS_FOGTABLEMODE]); + } + } + + if(fogenable) { + glEnable(GL_FOG); + checkGLcall("glEnable GL_FOG"); + + glFogfv(GL_FOG_START, &fogstart); + checkGLcall("glFogf(GL_FOG_START, fogstart"); + TRACE("Fog Start == %f\n", fogstart); + + glFogfv(GL_FOG_END, &fogend); + checkGLcall("glFogf(GL_FOG_END, fogend"); + TRACE("Fog End == %f\n", fogend); + } else { + glDisable(GL_FOG); + checkGLcall("glDisable GL_FOG"); + if( use_ps(stateblock->wineD3DDevice) ) { + /* disable fog in the pixel shader + * NOTE: For pixel shader, GL_FOG_START and GL_FOG_END don't hold fog start s and end e but + * -1/(e-s) and e/(e-s) respectively. + */ + glFogf(GL_FOG_START, 0.0f); + checkGLcall("glFogf(GL_FOG_START, fogstart"); + glFogf(GL_FOG_END, 1.0f); + checkGLcall("glFogf(GL_FOG_END, fogend"); + } + } + + if (GL_SUPPORT(NV_FOG_DISTANCE)) { + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); + } +} + +static void state_fogcolor(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + float col[4]; + D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_FOGCOLOR], col); + glFogfv(GL_FOG_COLOR, &col[0]); + checkGLcall("glFog GL_FOG_COLOR"); +} + +static void state_fogdensity(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + tmpvalue.d = stateblock->renderState[WINED3DRS_FOGDENSITY]; + glFogfv(GL_FOG_DENSITY, &tmpvalue.f); + checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)"); +} + +/* TODO: Merge with primitive type + init_materials()!! */ +static void state_colormat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)stateblock->wineD3DDevice; + GLenum Parm = 0; + WineDirect3DStridedData *diffuse = &device->strided_streams.u.s.diffuse; + BOOL isDiffuseSupplied; + + /* Depends on the decoded vertex declaration to read the existence of diffuse data. + * The vertex declaration will call this function if the fixed function pipeline is used. + */ + + if(isStateDirty(context, STATE_VDECL)) { + return; + } + + isDiffuseSupplied = diffuse->lpData || diffuse->VBO; + + context->num_untracked_materials = 0; + if (isDiffuseSupplied && stateblock->renderState[WINED3DRS_COLORVERTEX]) { + TRACE("diff %d, amb %d, emis %d, spec %d\n", + stateblock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE], + stateblock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE], + stateblock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE], + stateblock->renderState[WINED3DRS_SPECULARMATERIALSOURCE]); + + if (stateblock->renderState[WINED3DRS_DIFFUSEMATERIALSOURCE] == WINED3DMCS_COLOR1) { + if (stateblock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) { + Parm = GL_AMBIENT_AND_DIFFUSE; + } else { + Parm = GL_DIFFUSE; + } + if(stateblock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == WINED3DMCS_COLOR1) { + context->untracked_materials[context->num_untracked_materials] = GL_EMISSION; + context->num_untracked_materials++; + } + if(stateblock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) { + context->untracked_materials[context->num_untracked_materials] = GL_SPECULAR; + context->num_untracked_materials++; + } + } else if (stateblock->renderState[WINED3DRS_AMBIENTMATERIALSOURCE] == WINED3DMCS_COLOR1) { + Parm = GL_AMBIENT; + if(stateblock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == WINED3DMCS_COLOR1) { + context->untracked_materials[context->num_untracked_materials] = GL_EMISSION; + context->num_untracked_materials++; + } + if(stateblock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) { + context->untracked_materials[context->num_untracked_materials] = GL_SPECULAR; + context->num_untracked_materials++; + } + } else if (stateblock->renderState[WINED3DRS_EMISSIVEMATERIALSOURCE] == WINED3DMCS_COLOR1) { + Parm = GL_EMISSION; + if(stateblock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) { + context->untracked_materials[context->num_untracked_materials] = GL_SPECULAR; + context->num_untracked_materials++; + } + } else if (stateblock->renderState[WINED3DRS_SPECULARMATERIALSOURCE] == WINED3DMCS_COLOR1) { + Parm = GL_SPECULAR; + } + } + + /* Nothing changed, return. */ + if (Parm == context->tracking_parm) return; + + if(!Parm) { + glDisable(GL_COLOR_MATERIAL); + checkGLcall("glDisable GL_COLOR_MATERIAL"); + } else { + glColorMaterial(GL_FRONT_AND_BACK, Parm); + checkGLcall("glColorMaterial(GL_FRONT_AND_BACK, Parm)"); + glEnable(GL_COLOR_MATERIAL); + checkGLcall("glEnable(GL_COLOR_MATERIAL)"); + } + + /* Apparently calls to glMaterialfv are ignored for properties we're + * tracking with glColorMaterial, so apply those here. */ + switch (context->tracking_parm) { + case GL_AMBIENT_AND_DIFFUSE: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*)&device->updateStateBlock->material.Ambient); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*)&device->updateStateBlock->material.Diffuse); + checkGLcall("glMaterialfv"); + break; + + case GL_DIFFUSE: + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*)&device->updateStateBlock->material.Diffuse); + checkGLcall("glMaterialfv"); + break; + + case GL_AMBIENT: + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*)&device->updateStateBlock->material.Ambient); + checkGLcall("glMaterialfv"); + break; + + case GL_EMISSION: + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*)&device->updateStateBlock->material.Emissive); + checkGLcall("glMaterialfv"); + break; + + case GL_SPECULAR: + /* Only change material color if specular is enabled, otherwise it is set to black */ + if (device->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*)&device->updateStateBlock->material.Specular); + checkGLcall("glMaterialfv"); + } else { + float black[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]); + checkGLcall("glMaterialfv"); + } + break; + } + + context->tracking_parm = Parm; +} + +static void state_linepattern(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + WINED3DLINEPATTERN lp; + } tmppattern; + tmppattern.d = stateblock->renderState[WINED3DRS_LINEPATTERN]; + + TRACE("Line pattern: repeat %d bits %x\n", tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern); + + if (tmppattern.lp.wRepeatFactor) { + glLineStipple(tmppattern.lp.wRepeatFactor, tmppattern.lp.wLinePattern); + checkGLcall("glLineStipple(repeat, linepattern)"); + glEnable(GL_LINE_STIPPLE); + checkGLcall("glEnable(GL_LINE_STIPPLE);"); + } else { + glDisable(GL_LINE_STIPPLE); + checkGLcall("glDisable(GL_LINE_STIPPLE);"); + } +} + +static void state_zbias(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + + if (stateblock->renderState[WINED3DRS_ZBIAS]) { + tmpvalue.d = stateblock->renderState[WINED3DRS_ZBIAS]; + TRACE("ZBias value %f\n", tmpvalue.f); + glPolygonOffset(0, -tmpvalue.f); + checkGLcall("glPolygonOffset(0, -Value)"); + glEnable(GL_POLYGON_OFFSET_FILL); + checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL);"); + glEnable(GL_POLYGON_OFFSET_LINE); + checkGLcall("glEnable(GL_POLYGON_OFFSET_LINE);"); + glEnable(GL_POLYGON_OFFSET_POINT); + checkGLcall("glEnable(GL_POLYGON_OFFSET_POINT);"); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL);"); + glDisable(GL_POLYGON_OFFSET_LINE); + checkGLcall("glDisable(GL_POLYGON_OFFSET_LINE);"); + glDisable(GL_POLYGON_OFFSET_POINT); + checkGLcall("glDisable(GL_POLYGON_OFFSET_POINT);"); + } +} + + +static void state_normalize(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if (stateblock->renderState[WINED3DRS_NORMALIZENORMALS]) { + glEnable(GL_NORMALIZE); + checkGLcall("glEnable(GL_NORMALIZE);"); + } else { + glDisable(GL_NORMALIZE); + checkGLcall("glDisable(GL_NORMALIZE);"); + } +} + +static void state_psize(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + + /* FIXME: check that pointSize isn't outside glGetFloatv( GL_POINT_SIZE_MAX_ARB, &maxSize ); or -ve */ + tmpvalue.d = stateblock->renderState[WINED3DRS_POINTSIZE]; + TRACE("Set point size to %f\n", tmpvalue.f); + glPointSize(tmpvalue.f); + checkGLcall("glPointSize(...);"); +} + +static void state_psizemin(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + + tmpvalue.d = stateblock->renderState[WINED3DRS_POINTSIZE_MIN]; + if(GL_SUPPORT(ARB_POINT_PARAMETERS)) { + GL_EXTCALL(glPointParameterfARB)(GL_POINT_SIZE_MIN_ARB, tmpvalue.f); + checkGLcall("glPointParameterfARB(..."); + } + else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) { + GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f); + checkGLcall("glPointParameterfEXT(...);"); + } else if(tmpvalue.f != 1.0) { + FIXME("WINED3DRS_POINTSIZE_MIN not supported on this opengl, value is %f\n", tmpvalue.f); + } +} + +static void state_psizemax(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + + tmpvalue.d = stateblock->renderState[WINED3DRS_POINTSIZE_MAX]; + if(GL_SUPPORT(ARB_POINT_PARAMETERS)) { + GL_EXTCALL(glPointParameterfARB)(GL_POINT_SIZE_MAX_ARB, tmpvalue.f); + checkGLcall("glPointParameterfARB(..."); + } + else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) { + GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f); + checkGLcall("glPointParameterfEXT(...);"); + } else if(tmpvalue.f != 64.0) { + FIXME("WINED3DRS_POINTSIZE_MAX not supported on this opengl, value is %f\n", tmpvalue.f); + } +} + +static void state_pscale(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* TODO: Group this with the viewport */ + /* + * POINTSCALEENABLE controls how point size value is treated. If set to + * true, the point size is scaled with respect to height of viewport. + * When set to false point size is in pixels. + * + * http://msdn.microsoft.com/library/en-us/directx9_c/point_sprites.asp + */ + + /* Default values */ + GLfloat att[3] = {1.0f, 0.0f, 0.0f}; + + /* + * Minimum valid point size for OpenGL is 1.0f. For Direct3D it is 0.0f. + * This means that OpenGL will clamp really small point sizes to 1.0f. + * To correct for this we need to multiply by the scale factor when sizes + * are less than 1.0f. scale_factor = 1.0f / point_size. + */ + GLfloat pointSize = *((float*)&stateblock->renderState[WINED3DRS_POINTSIZE]); + if(pointSize > 0.0f) { + GLfloat scaleFactor; + + if(pointSize < 1.0f) { + scaleFactor = pointSize * pointSize; + } else { + scaleFactor = 1.0f; + } + + if(stateblock->renderState[WINED3DRS_POINTSCALEENABLE]) { + att[0] = *((float*)&stateblock->renderState[WINED3DRS_POINTSCALE_A]) / + (stateblock->viewport.Height * stateblock->viewport.Height * scaleFactor); + att[1] = *((float*)&stateblock->renderState[WINED3DRS_POINTSCALE_B]) / + (stateblock->viewport.Height * stateblock->viewport.Height * scaleFactor); + att[2] = *((float*)&stateblock->renderState[WINED3DRS_POINTSCALE_C]) / + (stateblock->viewport.Height * stateblock->viewport.Height * scaleFactor); + } + } + + if(GL_SUPPORT(ARB_POINT_PARAMETERS)) { + GL_EXTCALL(glPointParameterfvARB)(GL_POINT_DISTANCE_ATTENUATION_ARB, att); + checkGLcall("glPointParameterfvARB(GL_DISTANCE_ATTENUATION_ARB, ..."); + } + else if(GL_SUPPORT(EXT_POINT_PARAMETERS)) { + GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att); + checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ..."); + } else { + TRACE("POINT_PARAMETERS not supported in this version of opengl\n"); + } +} + +static void state_colorwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD Value = stateblock->renderState[WINED3DRS_COLORWRITEENABLE]; + + TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n", + Value & WINED3DCOLORWRITEENABLE_RED ? 1 : 0, + Value & WINED3DCOLORWRITEENABLE_GREEN ? 1 : 0, + Value & WINED3DCOLORWRITEENABLE_BLUE ? 1 : 0, + Value & WINED3DCOLORWRITEENABLE_ALPHA ? 1 : 0); + glColorMask(Value & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE, + Value & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE, + Value & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE, + Value & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE); + checkGLcall("glColorMask(...)"); + + /* depends on WINED3DRS_COLORWRITEENABLE. */ + if(stateblock->renderState[WINED3DRS_COLORWRITEENABLE1] != 0x0000000F || + stateblock->renderState[WINED3DRS_COLORWRITEENABLE2] != 0x0000000F || + stateblock->renderState[WINED3DRS_COLORWRITEENABLE3] != 0x0000000F ) { + ERR("(WINED3DRS_COLORWRITEENABLE1/2/3,%d,%d,%d) not yet implemented. Missing of cap D3DPMISCCAPS_INDEPENDENTWRITEMASKS wasn't honored?\n", + stateblock->renderState[WINED3DRS_COLORWRITEENABLE1], + stateblock->renderState[WINED3DRS_COLORWRITEENABLE2], + stateblock->renderState[WINED3DRS_COLORWRITEENABLE3]); + } +} + +static void state_localviewer(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_LOCALVIEWER]) { + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); + checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1)"); + } else { + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0); + checkGLcall("glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0)"); + } +} + +static void state_lastpixel(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_LASTPIXEL]) { + TRACE("Last Pixel Drawing Enabled\n"); + } else { + static BOOL first = TRUE; + if(first) { + FIXME("Last Pixel Drawing Disabled, not handled yet\n"); + first = FALSE; + } else { + TRACE("Last Pixel Drawing Disabled, not handled yet\n"); + } + } +} + +static void state_pointsprite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* TODO: NV_POINT_SPRITE */ + if (!GL_SUPPORT(ARB_POINT_SPRITE)) { + TRACE("Point sprites not supported\n"); + return; + } + + if (stateblock->renderState[WINED3DRS_POINTSPRITEENABLE]) { + glEnable(GL_POINT_SPRITE_ARB); + checkGLcall("glEnable(GL_POINT_SPRITE_ARB)\n"); + } else { + glDisable(GL_POINT_SPRITE_ARB); + checkGLcall("glDisable(GL_POINT_SPRITE_ARB)\n"); + } +} + +static void state_wrap(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /** + http://www.cosc.brocku.ca/Offerings/3P98/course/lectures/texture/ + http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/FixedFunction/Textures/texturewrapping.asp + http://www.gamedev.net/reference/programming/features/rendererdll3/page2.asp + Descussion that ways to turn on WRAPing to solve an opengl conversion problem. + http://www.flipcode.org/cgi-bin/fcmsg.cgi?thread_show=10248 + + so far as I can tell, wrapping and texture-coordinate generate go hand in hand, + */ + TRACE("Stub\n"); + if(stateblock->renderState[WINED3DRS_WRAP0] || + stateblock->renderState[WINED3DRS_WRAP1] || + stateblock->renderState[WINED3DRS_WRAP2] || + stateblock->renderState[WINED3DRS_WRAP3] || + stateblock->renderState[WINED3DRS_WRAP4] || + stateblock->renderState[WINED3DRS_WRAP5] || + stateblock->renderState[WINED3DRS_WRAP6] || + stateblock->renderState[WINED3DRS_WRAP7] || + stateblock->renderState[WINED3DRS_WRAP8] || + stateblock->renderState[WINED3DRS_WRAP9] || + stateblock->renderState[WINED3DRS_WRAP10] || + stateblock->renderState[WINED3DRS_WRAP11] || + stateblock->renderState[WINED3DRS_WRAP12] || + stateblock->renderState[WINED3DRS_WRAP13] || + stateblock->renderState[WINED3DRS_WRAP14] || + stateblock->renderState[WINED3DRS_WRAP15] ) { + FIXME("(WINED3DRS_WRAP0) Texture wraping not yet supported\n"); + } +} + +static void state_multisampleaa(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if( GL_SUPPORT(ARB_MULTISAMPLE) ) { + if(stateblock->renderState[WINED3DRS_MULTISAMPLEANTIALIAS]) { + glEnable(GL_MULTISAMPLE_ARB); + checkGLcall("glEnable(GL_MULTISAMPLE_ARB)"); + } else { + glDisable(GL_MULTISAMPLE_ARB); + checkGLcall("glDisable(GL_MULTISAMPLE_ARB)"); + } + } else { + if(stateblock->renderState[WINED3DRS_MULTISAMPLEANTIALIAS]) { + WARN("Multisample antialiasing not supported by gl\n"); + } + } +} + +static void state_scissor(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_SCISSORTESTENABLE]) { + glEnable(GL_SCISSOR_TEST); + checkGLcall("glEnable(GL_SCISSOR_TEST)"); + } else { + glDisable(GL_SCISSOR_TEST); + checkGLcall("glDisable(GL_SCISSOR_TEST)"); + } +} + +static void state_depthbias(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + + if(stateblock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS] || + stateblock->renderState[WINED3DRS_DEPTHBIAS]) { + tmpvalue.d = stateblock->renderState[WINED3DRS_SLOPESCALEDEPTHBIAS]; + glEnable(GL_POLYGON_OFFSET_FILL); + checkGLcall("glEnable(GL_POLYGON_OFFSET_FILL)"); + glPolygonOffset(tmpvalue.f, *((float*)&stateblock->renderState[WINED3DRS_DEPTHBIAS])); + checkGLcall("glPolygonOffset(...)"); + } else { + glDisable(GL_POLYGON_OFFSET_FILL); + checkGLcall("glDisable(GL_POLYGON_OFFSET_FILL)"); + } +} + +static void state_perspective(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if (stateblock->renderState[WINED3DRS_TEXTUREPERSPECTIVE]) { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + checkGLcall("glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)"); + } else { + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + checkGLcall("glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)"); + } +} + +static void state_stippledalpha(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_STIPPLEDALPHA]) + FIXME(" Stippled Alpha not supported yet.\n"); +} + +static void state_antialias(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_ANTIALIAS]) + FIXME(" Antialias not supported yet.\n"); +} + +static void state_multisampmask(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_MULTISAMPLEMASK] != 0xFFFFFFFF) + FIXME("(WINED3DRS_MULTISAMPLEMASK,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_MULTISAMPLEMASK]); +} + +static void state_patchedgestyle(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_PATCHEDGESTYLE] != WINED3DPATCHEDGE_DISCRETE) + FIXME("(WINED3DRS_PATCHEDGESTYLE,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_PATCHEDGESTYLE]); +} + +static void state_patchsegments(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + union { + DWORD d; + float f; + } tmpvalue; + tmpvalue.f = 1.0f; + + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_PATCHSEGMENTS] != tmpvalue.d) + { + static BOOL displayed = FALSE; + + tmpvalue.d = stateblock->renderState[WINED3DRS_PATCHSEGMENTS]; + if(!displayed) + FIXME("(WINED3DRS_PATCHSEGMENTS,%f) not yet implemented\n", tmpvalue.f); + + displayed = TRUE; + } +} + +static void state_positiondegree(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_POSITIONDEGREE] != WINED3DDEGREE_CUBIC) + FIXME("(WINED3DRS_POSITIONDEGREE,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_POSITIONDEGREE]); +} + +static void state_normaldegree(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if (stateblock->renderState[WINED3DRS_NORMALDEGREE] != WINED3DDEGREE_LINEAR) + FIXME("(WINED3DRS_NORMALDEGREE,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_NORMALDEGREE]); +} + +static void state_tessellation(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if(stateblock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION]) + FIXME("(WINED3DRS_ENABLEADAPTIVETESSELLATION,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_ENABLEADAPTIVETESSELLATION]); +} + + +static void state_srgbwrite(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_SRGBWRITEENABLE]) + FIXME("Render state WINED3DRS_SRGBWRITEENABLE not yet implemented\n"); +} + +static void state_separateblend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + TRACE("Stub\n"); + if(stateblock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE]) + FIXME("(WINED3DRS_SEPARATEALPHABLENDENABLE,%d) not yet implemented\n", stateblock->renderState[WINED3DRS_SEPARATEALPHABLENDENABLE]); +} + +static void state_wrapu(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_WRAPU]) { + FIXME("Render state WINED3DRS_WRAPU not implemented yet\n"); + } +} + +static void state_wrapv(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_WRAPV]) { + FIXME("Render state WINED3DRS_WRAPV not implemented yet\n"); + } +} + +static void state_monoenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_MONOENABLE]) { + FIXME("Render state WINED3DRS_MONOENABLE not implemented yet\n"); + } +} + +static void state_rop2(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_ROP2]) { + FIXME("Render state WINED3DRS_ROP2 not implemented yet\n"); + } +} + +static void state_planemask(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_PLANEMASK]) { + FIXME("Render state WINED3DRS_PLANEMASK not implemented yet\n"); + } +} + +static void state_subpixel(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_SUBPIXEL]) { + FIXME("Render state WINED3DRS_SUBPIXEL not implemented yet\n"); + } +} + +static void state_subpixelx(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_SUBPIXELX]) { + FIXME("Render state WINED3DRS_SUBPIXELX not implemented yet\n"); + } +} + +static void state_stippleenable(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_STIPPLEENABLE]) { + FIXME("Render state WINED3DRS_STIPPLEENABLE not implemented yet\n"); + } +} + +static void state_bordercolor(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_BORDERCOLOR]) { + FIXME("Render state WINED3DRS_BORDERCOLOR not implemented yet\n"); + } +} + +static void state_mipmaplodbias(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_MIPMAPLODBIAS]) { + FIXME("Render state WINED3DRS_MIPMAPLODBIAS not implemented yet\n"); + } +} + +static void state_anisotropy(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_ANISOTROPY]) { + FIXME("Render state WINED3DRS_ANISOTROPY not implemented yet\n"); + } +} + +static void state_flushbatch(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_FLUSHBATCH]) { + FIXME("Render state WINED3DRS_FLUSHBATCH not implemented yet\n"); + } +} + +static void state_translucentsi(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_TRANSLUCENTSORTINDEPENDENT]) { + FIXME("Render state WINED3DRS_TRANSLUCENTSORTINDEPENDENT not implemented yet\n"); + } +} + +static void state_extents(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_EXTENTS]) { + FIXME("Render state WINED3DRS_EXTENTS not implemented yet\n"); + } +} + +static void state_ckeyblend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(stateblock->renderState[WINED3DRS_COLORKEYBLENDENABLE]) { + FIXME("Render state WINED3DRS_COLORKEYBLENDENABLE not implemented yet\n"); + } +} + +/* Activates the texture dimension according to the bound D3D texture. + * Does not care for the colorop or correct gl texture unit(when using nvrc) + * Requires the caller to activate the correct unit before + */ +static void activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + BOOL bumpmap = FALSE; + + if(stage > 0 && (stateblock->textureState[stage - 1][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAPLUMINANCE || + stateblock->textureState[stage - 1][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAP)) { + bumpmap = TRUE; + context->texShaderBumpMap |= (1 << stage); + } else { + context->texShaderBumpMap &= ~(1 << stage); + } + + if(stateblock->textures[stage]) { + switch(stateblock->textureDimensions[stage]) { + case GL_TEXTURE_2D: + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, bumpmap ? GL_OFFSET_TEXTURE_2D_NV : GL_TEXTURE_2D); + } else { + glDisable(GL_TEXTURE_3D); + checkGLcall("glDisable(GL_TEXTURE_3D)"); + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + glEnable(GL_TEXTURE_2D); + checkGLcall("glEnable(GL_TEXTURE_2D)"); + } + break; + case GL_TEXTURE_3D: + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_3D); + } else { + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + glEnable(GL_TEXTURE_3D); + checkGLcall("glEnable(GL_TEXTURE_3D)"); + } + break; + case GL_TEXTURE_CUBE_MAP_ARB: + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_CUBE_MAP_ARB); + } else { + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + glDisable(GL_TEXTURE_3D); + checkGLcall("glDisable(GL_TEXTURE_3D)"); + glEnable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glEnable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + break; + } + } else { + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_NONE); + } else { + glEnable(GL_TEXTURE_2D); + checkGLcall("glEnable(GL_TEXTURE_2D)"); + glDisable(GL_TEXTURE_3D); + checkGLcall("glDisable(GL_TEXTURE_3D)"); + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + /* Binding textures is done by samplers. A dummy texture will be bound */ + } + } +} + +static void tex_colorop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[stage]; + BOOL tex_used = stateblock->wineD3DDevice->fixed_function_usage_map[stage]; + + TRACE("Setting color op for stage %d\n", stage); + + if (stateblock->pixelShader && stateblock->wineD3DDevice->ps_selected_mode != SHADER_NONE && + ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function) { + /* Using a pixel shader? Don't care for anything here, the shader applying does it */ + return; + } + + if (stage != mapped_stage) WARN("Using non 1:1 mapping: %d -> %d!\n", stage, mapped_stage); + + if (mapped_stage != -1) { + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + if (tex_used && mapped_stage >= GL_LIMITS(textures)) { + FIXME("Attempt to enable unsupported stage!\n"); + return; + } + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glActiveTextureARB"); + } else if (stage > 0) { + WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + return; + } + } + + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + if(stateblock->lowest_disabled_stage > 0) { + glEnable(GL_REGISTER_COMBINERS_NV); + GL_EXTCALL(glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, stateblock->lowest_disabled_stage)); + } else { + glDisable(GL_REGISTER_COMBINERS_NV); + } + } + if(stage >= stateblock->lowest_disabled_stage) { + TRACE("Stage disabled\n"); + if (mapped_stage != -1) { + /* Disable everything here */ + glDisable(GL_TEXTURE_2D); + checkGLcall("glDisable(GL_TEXTURE_2D)"); + glDisable(GL_TEXTURE_3D); + checkGLcall("glDisable(GL_TEXTURE_3D)"); + if(GL_SUPPORT(ARB_TEXTURE_CUBE_MAP)) { + glDisable(GL_TEXTURE_CUBE_MAP_ARB); + checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)"); + } + if(GL_SUPPORT(NV_TEXTURE_SHADER2) && mapped_stage < GL_LIMITS(textures)) { + glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_NONE); + } + } + /* All done */ + return; + } + + /* The sampler will also activate the correct texture dimensions, so no need to do it here + * if the sampler for this stage is dirty + */ + if(!isStateDirty(context, STATE_SAMPLER(stage))) { + if (tex_used) activate_dimensions(stage, stateblock, context); + } + + /* Set the texture combiners */ + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + set_tex_op_nvrc((IWineD3DDevice *)stateblock->wineD3DDevice, FALSE, stage, + stateblock->textureState[stage][WINED3DTSS_COLOROP], + stateblock->textureState[stage][WINED3DTSS_COLORARG1], + stateblock->textureState[stage][WINED3DTSS_COLORARG2], + stateblock->textureState[stage][WINED3DTSS_COLORARG0], + mapped_stage); + + /* In register combiners bump mapping is done in the stage AFTER the one that has the bump map operation set, + * thus the texture shader may have to be updated + */ + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + BOOL usesBump = (stateblock->textureState[stage][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAPLUMINANCE || + stateblock->textureState[stage][WINED3DTSS_COLOROP] == WINED3DTOP_BUMPENVMAP) ? TRUE : FALSE; + BOOL usedBump = (context->texShaderBumpMap & 1 << (stage + 1)) ? TRUE : FALSE; + if(usesBump != usedBump) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage + 1)); + checkGLcall("glActiveTextureARB"); + activate_dimensions(stage + 1, stateblock, context); + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glActiveTextureARB"); + } + } + } else { + set_tex_op((IWineD3DDevice *)stateblock->wineD3DDevice, FALSE, stage, + stateblock->textureState[stage][WINED3DTSS_COLOROP], + stateblock->textureState[stage][WINED3DTSS_COLORARG1], + stateblock->textureState[stage][WINED3DTSS_COLORARG2], + stateblock->textureState[stage][WINED3DTSS_COLORARG0]); + } +} + +static void tex_alphaop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[stage]; + BOOL tex_used = stateblock->wineD3DDevice->fixed_function_usage_map[stage]; + DWORD op, arg1, arg2, arg0; + + TRACE("Setting alpha op for stage %d\n", stage); + /* Do not care for enabled / disabled stages, just assign the settigns. colorop disables / enables required stuff */ + if (mapped_stage != -1) { + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + if (tex_used && mapped_stage >= GL_LIMITS(textures)) { + FIXME("Attempt to enable unsupported stage!\n"); + return; + } + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glActiveTextureARB"); + } else if (stage > 0) { + /* We can't do anything here */ + WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + return; + } + } + + op = stateblock->textureState[stage][WINED3DTSS_ALPHAOP]; + arg1 = stateblock->textureState[stage][WINED3DTSS_ALPHAARG1]; + arg2 = stateblock->textureState[stage][WINED3DTSS_ALPHAARG2]; + arg0 = stateblock->textureState[stage][WINED3DTSS_ALPHAARG0]; + + if(stateblock->renderState[WINED3DRS_COLORKEYENABLE] && stage == 0 && + stateblock->textures[0] && stateblock->textureDimensions[0] == GL_TEXTURE_2D) { + IWineD3DSurfaceImpl *surf = (IWineD3DSurfaceImpl *) ((IWineD3DTextureImpl *) stateblock->textures[0])->surfaces[0]; + + if(surf->CKeyFlags & WINEDDSD_CKSRCBLT && + getFormatDescEntry(surf->resource.format, NULL, NULL)->alphaMask == 0x00000000) { + + /* Color keying needs to pass alpha values from the texture through to have the alpha test work properly. + * On the other hand applications can still use texture combiners apparently. This code takes care that apps + * cannot remove the texture's alpha channel entirely. + * + * The fixup is required for Prince of Persia 3D(prison bars), while Moto racer 2 requires D3DTOP_MODULATE to work + * on color keyed surfaces. + * + * What to do with multitexturing? So far no app has been found that uses color keying with multitexturing + */ + if(op == WINED3DTOP_DISABLE) op = WINED3DTOP_SELECTARG1; + if(op == WINED3DTOP_SELECTARG1) arg1 = WINED3DTA_TEXTURE; + else if(op == WINED3DTOP_SELECTARG2) arg2 = WINED3DTA_TEXTURE; + } + } + + TRACE("Setting alpha op for stage %d\n", stage); + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + set_tex_op_nvrc((IWineD3DDevice *)stateblock->wineD3DDevice, TRUE, stage, + op, arg1, arg2, arg0, + mapped_stage); + } else { + set_tex_op((IWineD3DDevice *)stateblock->wineD3DDevice, TRUE, stage, + op, arg1, arg2, arg0); + } +} + +static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD texUnit = state - STATE_TRANSFORM(WINED3DTS_TEXTURE0); + DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[texUnit]; + + if (mapped_stage < 0) return; + + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + if(mapped_stage >= GL_LIMITS(textures)) { + return; + } + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glActiveTextureARB"); + } else if (mapped_stage > 0) { + /* We can't do anything here */ + WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + return; + } + + set_texture_matrix((float *)&stateblock->transforms[WINED3DTS_TEXTURE0 + texUnit].u.m[0][0], + stateblock->textureState[texUnit][WINED3DTSS_TEXTURETRANSFORMFLAGS], + (stateblock->textureState[texUnit][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) != WINED3DTSS_TCI_PASSTHRU); + +} + +static void unloadTexCoords(IWineD3DStateBlockImpl *stateblock) { + int texture_idx; + + for (texture_idx = 0; texture_idx < GL_LIMITS(texture_stages); ++texture_idx) { + GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + texture_idx)); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } +} + +static void loadTexCoords(IWineD3DStateBlockImpl *stateblock, WineDirect3DVertexStridedData *sd, GLint *curVBO) { + UINT *offset = stateblock->streamOffset; + unsigned int mapped_stage = 0; + unsigned int textureNo = 0; + + /* The code below uses glClientActiveTexture and glMultiTexCoord* which are all part of the GL_ARB_multitexture extension. */ + /* Abort if we don't support the extension. */ + if (!GL_SUPPORT(ARB_MULTITEXTURE)) { + FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + return; + } + + for (textureNo = 0; textureNo < GL_LIMITS(texture_stages); ++textureNo) { + int coordIdx = stateblock->textureState[textureNo][WINED3DTSS_TEXCOORDINDEX]; + + mapped_stage = stateblock->wineD3DDevice->texUnitMap[textureNo]; + if (mapped_stage == -1) continue; + + if (coordIdx < MAX_TEXTURES && (sd->u.s.texCoords[coordIdx].lpData || sd->u.s.texCoords[coordIdx].VBO)) { + TRACE("Setting up texture %u, idx %d, cordindx %u, data %p\n", + textureNo, mapped_stage, coordIdx, sd->u.s.texCoords[coordIdx].lpData); + + if (*curVBO != sd->u.s.texCoords[coordIdx].VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.texCoords[coordIdx].VBO)); + checkGLcall("glBindBufferARB"); + *curVBO = sd->u.s.texCoords[coordIdx].VBO; + } + + GL_EXTCALL(glClientActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glClientActiveTextureARB"); + + /* The coords to supply depend completely on the fvf / vertex shader */ + glTexCoordPointer( + WINED3D_ATR_SIZE(sd->u.s.texCoords[coordIdx].dwType), + WINED3D_ATR_GLTYPE(sd->u.s.texCoords[coordIdx].dwType), + sd->u.s.texCoords[coordIdx].dwStride, + sd->u.s.texCoords[coordIdx].lpData + stateblock->loadBaseVertexIndex * sd->u.s.texCoords[coordIdx].dwStride + offset[sd->u.s.texCoords[coordIdx].streamNo]); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } else { + GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + mapped_stage, 0, 0, 0, 1)); + } + } + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + /* The number of the mapped stages increases monotonically, so it's fine to use the last used one */ + for (textureNo = mapped_stage + 1; textureNo < GL_LIMITS(textures); ++textureNo) { + GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + textureNo, 0, 0, 0, 1)); + } + } +} + +static void tex_coordindex(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[stage]; + + if (mapped_stage == -1) { + TRACE("No texture unit mapped to stage %d. Skipping texture coordinates.\n", stage); + return; + } + + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + if(mapped_stage >= GL_LIMITS(fragment_samplers)) { + return; + } + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glActiveTextureARB"); + } else if (stage > 0) { + /* We can't do anything here */ + WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + return; + } + + /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive + * + * FIXME: From MSDN: The WINED3DTSS_TCI_* flags are mutually exclusive. If you include + * one flag, you can still specify an index value, which the system uses to + * determine the texture wrapping mode. + * eg. SetTextureStageState( 0, WINED3DTSS_TEXCOORDINDEX, WINED3DTSS_TCI_CAMERASPACEPOSITION | 1 ); + * means use the vertex position (camera-space) as the input texture coordinates + * for this texture stage, and the wrap mode set in the WINED3DRS_WRAP1 render + * state. We do not (yet) support the WINED3DRENDERSTATE_WRAPx values, nor tie them up + * to the TEXCOORDINDEX value + */ + + /* + * Be careful the value of the mask 0xF0000 come from d3d8types.h infos + */ + switch (stateblock->textureState[stage][WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) { + case WINED3DTSS_TCI_PASSTHRU: + /*Use the specified texture coordinates contained within the vertex format. This value resolves to zero.*/ + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_Q); + checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R,Q)"); + break; + + case WINED3DTSS_TCI_CAMERASPACEPOSITION: + /* CameraSpacePosition means use the vertex position, transformed to camera space, + * as the input texture coordinates for this stage's texture transformation. This + * equates roughly to EYE_LINEAR + */ + { + float s_plane[] = { 1.0, 0.0, 0.0, 0.0 }; + float t_plane[] = { 0.0, 1.0, 0.0, 0.0 }; + float r_plane[] = { 0.0, 0.0, 1.0, 0.0 }; + float q_plane[] = { 0.0, 0.0, 0.0, 1.0 }; + TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set eye plane\n"); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTexGenfv(GL_S, GL_EYE_PLANE, s_plane); + glTexGenfv(GL_T, GL_EYE_PLANE, t_plane); + glTexGenfv(GL_R, GL_EYE_PLANE, r_plane); + glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane); + glPopMatrix(); + + TRACE("WINED3DTSS_TCI_CAMERASPACEPOSITION - Set GL_TEXTURE_GEN_x and GL_x, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR\n"); + glEnable(GL_TEXTURE_GEN_S); + checkGLcall("glEnable(GL_TEXTURE_GEN_S);"); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)"); + glEnable(GL_TEXTURE_GEN_T); + checkGLcall("glEnable(GL_TEXTURE_GEN_T);"); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)"); + glEnable(GL_TEXTURE_GEN_R); + checkGLcall("glEnable(GL_TEXTURE_GEN_R);"); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); + checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR)"); + } + break; + + case WINED3DTSS_TCI_CAMERASPACENORMAL: + { + if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) { + float s_plane[] = { 1.0, 0.0, 0.0, 0.0 }; + float t_plane[] = { 0.0, 1.0, 0.0, 0.0 }; + float r_plane[] = { 0.0, 0.0, 1.0, 0.0 }; + float q_plane[] = { 0.0, 0.0, 0.0, 1.0 }; + TRACE("WINED3DTSS_TCI_CAMERASPACENORMAL - Set eye plane\n"); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTexGenfv(GL_S, GL_EYE_PLANE, s_plane); + glTexGenfv(GL_T, GL_EYE_PLANE, t_plane); + glTexGenfv(GL_R, GL_EYE_PLANE, r_plane); + glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane); + glPopMatrix(); + + glEnable(GL_TEXTURE_GEN_S); + checkGLcall("glEnable(GL_TEXTURE_GEN_S);"); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV); + checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)"); + glEnable(GL_TEXTURE_GEN_T); + checkGLcall("glEnable(GL_TEXTURE_GEN_T);"); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV); + checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)"); + glEnable(GL_TEXTURE_GEN_R); + checkGLcall("glEnable(GL_TEXTURE_GEN_R);"); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV); + checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_NV)"); + } + } + break; + + case WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR: + { + if (GL_SUPPORT(NV_TEXGEN_REFLECTION)) { + float s_plane[] = { 1.0, 0.0, 0.0, 0.0 }; + float t_plane[] = { 0.0, 1.0, 0.0, 0.0 }; + float r_plane[] = { 0.0, 0.0, 1.0, 0.0 }; + float q_plane[] = { 0.0, 0.0, 0.0, 1.0 }; + TRACE("WINED3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR - Set eye plane\n"); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glTexGenfv(GL_S, GL_EYE_PLANE, s_plane); + glTexGenfv(GL_T, GL_EYE_PLANE, t_plane); + glTexGenfv(GL_R, GL_EYE_PLANE, r_plane); + glTexGenfv(GL_Q, GL_EYE_PLANE, q_plane); + glPopMatrix(); + + glEnable(GL_TEXTURE_GEN_S); + checkGLcall("glEnable(GL_TEXTURE_GEN_S);"); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV); + checkGLcall("glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)"); + glEnable(GL_TEXTURE_GEN_T); + checkGLcall("glEnable(GL_TEXTURE_GEN_T);"); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV); + checkGLcall("glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)"); + glEnable(GL_TEXTURE_GEN_R); + checkGLcall("glEnable(GL_TEXTURE_GEN_R);"); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV); + checkGLcall("glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV)"); + } + } + break; + + /* Unhandled types: */ + default: + /* Todo: */ + /* ? disable GL_TEXTURE_GEN_n ? */ + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_Q); + FIXME("Unhandled WINED3DTSS_TEXCOORDINDEX %x\n", stateblock->textureState[stage][WINED3DTSS_TEXCOORDINDEX]); + break; + } + + /* Update the texture matrix */ + if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stage))) { + transform_texture(STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stage), stateblock, context); + } + + if(!isStateDirty(context, STATE_VDECL) && context->namedArraysLoaded) { + /* Reload the arrays if we are using fixed function arrays to reflect the selected coord input + * source. Call loadTexCoords directly because there is no need to reparse the vertex declaration + * and do all the things linked to it + * TODO: Tidy that up to reload only the arrays of the changed unit + */ + GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0; + + unloadTexCoords(stateblock); + loadTexCoords(stateblock, &stateblock->wineD3DDevice->strided_streams, &curVBO); + } +} + +static void tex_bumpenvlscale(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + union { + DWORD d; + float f; + } tmpvalue; + + tmpvalue.d = stateblock->textureState[stage][WINED3DTSS_BUMPENVLSCALE]; + if(tmpvalue.f != 0.0) { + FIXME("WINED3DTSS_BUMPENVLSCALE not supported yet\n"); + } +} + +static void tex_bumpenvloffset(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + union { + DWORD d; + float f; + } tmpvalue; + + tmpvalue.d = stateblock->textureState[stage][WINED3DTSS_BUMPENVLOFFSET]; + if(tmpvalue.f != 0.0) { + FIXME("WINED3DTSS_BUMPENVLOFFSET not supported yet\n"); + } +} + +static void tex_resultarg(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + + if(stage >= GL_LIMITS(texture_stages)) { + return; + } + + if(stateblock->textureState[stage][WINED3DTSS_RESULTARG] != WINED3DTA_CURRENT) { + FIXME("WINED3DTSS_RESULTARG not supported yet\n"); + } +} + +static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD sampler = state - STATE_SAMPLER(0); + DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[sampler]; + union { + float f; + DWORD d; + } tmpvalue; + + TRACE("Sampler: %d\n", sampler); + /* Enabling and disabling texture dimensions is done by texture stage state / pixel shader setup, this function + * only has to bind textures and set the per texture states + */ + + if (mapped_stage == -1) { + TRACE("No sampler mapped to stage %d. Returning.\n", sampler); + return; + } + + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + if (mapped_stage >= GL_LIMITS(combined_samplers)) { + return; + } + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("glActiveTextureARB"); + } else if (sampler > 0) { + /* We can't do anything here */ + WARN("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + return; + } + + if(stateblock->textures[sampler]) { + BOOL texIsPow2 = FALSE; + + /* The fixed function np2 texture emulation uses the texture matrix to fix up the coordinates + * IWineD3DBaseTexture::ApplyStateChanges multiplies the set matrix with a fixup matrix. Before the + * scaling is reapplied or removed, the texture matrix has to be reapplied + */ + if(!GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) && sampler < MAX_TEXTURES) { + if(stateblock->textureDimensions[sampler] == GL_TEXTURE_2D) { + if(((IWineD3DTextureImpl *) stateblock->textures[sampler])->pow2scalingFactorX != 1.0 || + ((IWineD3DTextureImpl *) stateblock->textures[sampler])->pow2scalingFactorY != 1.0 ) { + texIsPow2 = TRUE; + } + } else if(stateblock->textureDimensions[sampler] == GL_TEXTURE_CUBE_MAP_ARB) { + if(((IWineD3DCubeTextureImpl *) stateblock->textures[sampler])->pow2scalingFactor != 1.0) { + texIsPow2 = TRUE; + } + } + + if(texIsPow2 || context->lastWasPow2Texture[sampler]) { + transform_texture(STATE_TRANSFORM(WINED3DTS_TEXTURE0 + stateblock->wineD3DDevice->texUnitMap[sampler]), stateblock, context); + context->lastWasPow2Texture[sampler] = texIsPow2; + } + } + + IWineD3DBaseTexture_PreLoad((IWineD3DBaseTexture *) stateblock->textures[sampler]); + IWineD3DBaseTexture_ApplyStateChanges(stateblock->textures[sampler], stateblock->textureState[sampler], stateblock->samplerState[sampler]); + + if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) { + tmpvalue.d = stateblock->samplerState[sampler][WINED3DSAMP_MIPMAPLODBIAS]; + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, + GL_TEXTURE_LOD_BIAS_EXT, + tmpvalue.f); + checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ..."); + } + + if (stateblock->wineD3DDevice->ps_selected_mode != SHADER_NONE && stateblock->pixelShader && + ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function) { + /* Using a pixel shader? Verify the sampler types */ + + /* Make sure that the texture dimensions are enabled. I don't have to disable the other + * dimensions because the shader knows from which texture type to sample from. For the sake of + * debugging all dimensions could be enabled and a texture with some ugly pink bound to the unused + * dimensions. This should make wrong sampling sources visible :-) + */ + glEnable(stateblock->textureDimensions[sampler]); + checkGLcall("glEnable(stateblock->textureDimensions[sampler])"); + } else if(sampler < stateblock->lowest_disabled_stage) { + if(!isStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) { + activate_dimensions(sampler, stateblock, context); + } + + if(stateblock->renderState[WINED3DRS_COLORKEYENABLE] && sampler == 0) { + /* If color keying is enabled update the alpha test, it depends on the existence + * of a color key in stage 0 + */ + state_alpha(WINED3DRS_COLORKEYENABLE, stateblock, context); + } + } + } else if(sampler < GL_LIMITS(texture_stages)) { + if(sampler < stateblock->lowest_disabled_stage) { + /* TODO: What should I do with pixel shaders here ??? */ + if(!isStateDirty(context, STATE_TEXTURESTAGE(sampler, WINED3DTSS_COLOROP))) { + activate_dimensions(sampler, stateblock, context); + } + } /* Otherwise tex_colorop disables the stage */ + glBindTexture(GL_TEXTURE_2D, stateblock->wineD3DDevice->dummyTextureName[sampler]); + checkGLcall("glBindTexture(GL_TEXTURE_2D, stateblock->wineD3DDevice->dummyTextureName[sampler])"); + } +} + +static void shaderconstant(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; + + /* Vertex and pixel shader states will call a shader upload, don't do anything as long one of them + * has an update pending + */ + if(isStateDirty(context, STATE_VDECL) || + isStateDirty(context, STATE_PIXELSHADER)) { + return; + } + + device->shader_backend->shader_load_constants((IWineD3DDevice *) device, use_ps(device), use_vs(device)); +} + +static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; + BOOL use_pshader = use_ps(device); + BOOL use_vshader = use_vs(device); + BOOL update_fog = FALSE; + int i; + + if (use_pshader) { + if(!context->last_was_pshader) { + /* Former draw without a pixel shader, some samplers + * may be disabled because of WINED3DTSS_COLOROP = WINED3DTOP_DISABLE + * make sure to enable them + */ + for(i=0; i < MAX_FRAGMENT_SAMPLERS; i++) { + if(!isStateDirty(context, STATE_SAMPLER(i))) { + sampler(STATE_SAMPLER(i), stateblock, context); + } + } + update_fog = TRUE; + } else { + /* Otherwise all samplers were activated by the code above in earlier draws, or by sampler() + * if a different texture was bound. I don't have to do anything. + */ + } + + /* Compile and bind the shader */ + IWineD3DPixelShader_CompileShader(stateblock->pixelShader); + } else { + /* Disabled the pixel shader - color ops weren't applied + * while it was enabled, so re-apply them. + */ + for(i=0; i < MAX_TEXTURES; i++) { + if(!isStateDirty(context, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP))) { + tex_colorop(STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP), stateblock, context); + } + } + if(context->last_was_pshader) + update_fog = TRUE; + } + + if(!isStateDirty(context, StateTable[STATE_VSHADER].representative)) { + device->shader_backend->shader_select((IWineD3DDevice *)stateblock->wineD3DDevice, use_pshader, use_vshader); + + if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vshader || use_pshader)) { + shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context); + } + } + + if(update_fog) + state_fog(state, stateblock, context); + + context->last_was_pshader = use_pshader; +} + +static void tex_bumpenvmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE; + + if(stateblock->pixelShader && stage != 0 && + ((IWineD3DPixelShaderImpl *) stateblock->pixelShader)->needsbumpmat == stage) { + /* The pixel shader has to know the bump env matrix. Do a constants update if it isn't scheduled + * anyway + */ + if(!isStateDirty(context, STATE_PIXELSHADERCONSTANT) && + !isStateDirty(context, STATE_PIXELSHADER)) { + shaderconstant(STATE_PIXELSHADERCONSTANT, stateblock, context); + } + } + + if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + if(stage >= GL_LIMITS(texture_stages)) { + WARN("Bump env matrix of unsupported stage set\n"); + } else if(GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stage)); + checkGLcall("GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + stage))"); + } + GL_EXTCALL(glTexBumpParameterfvATI(GL_BUMP_ROT_MATRIX_ATI, + (float *) &(stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT00]))); + checkGLcall("glTexBumpParameterfvATI"); + } + if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + /* Direct3D sets the matrix in the stage reading the perturbation map. The result is used to + * offset the destination stage(always stage + 1 in d3d). In GL_NV_texture_shader, the bump + * map offseting is done in the stage reading the bump mapped texture, and the perturbation + * map is read from a specified source stage(always stage - 1 for d3d). Thus set the matrix + * for stage + 1. Keep the nvrc tex unit mapping in mind too + */ + DWORD mapped_stage = stateblock->wineD3DDevice->texUnitMap[stage + 1]; + + if(mapped_stage < GL_LIMITS(textures)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage)); + checkGLcall("GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage))"); + + glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, + (float *) &(stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT00])); + checkGLcall("glTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, mat)\n"); + } + } +} + +static void transform_world(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + /* This function is called by transform_view below if the view matrix was changed too + * + * Deliberately no check if the vertex declaration is dirty because the vdecl state + * does not always update the world matrix, only on a switch between transformed + * and untrannsformed draws. It *may* happen that the world matrix is set 2 times during one + * draw, but that should be rather rare and cheaper in total. + */ + glMatrixMode(GL_MODELVIEW); + checkGLcall("glMatrixMode"); + + if(context->last_was_rhw) { + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + } else { + /* In the general case, the view matrix is the identity matrix */ + if (stateblock->wineD3DDevice->view_ident) { + glLoadMatrixf((float *) &stateblock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]); + checkGLcall("glLoadMatrixf"); + } else { + glLoadMatrixf((float *) &stateblock->transforms[WINED3DTS_VIEW].u.m[0][0]); + checkGLcall("glLoadMatrixf"); + glMultMatrixf((float *) &stateblock->transforms[WINED3DTS_WORLDMATRIX(0)].u.m[0][0]); + checkGLcall("glMultMatrixf"); + } + } +} + +static void clipplane(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + UINT index = state - STATE_CLIPPLANE(0); + + if(isStateDirty(context, STATE_TRANSFORM(WINED3DTS_VIEW)) || index >= GL_LIMITS(clipplanes)) { + return; + } + + /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf((float *) &stateblock->transforms[WINED3DTS_VIEW].u.m[0][0]); + + TRACE("Clipplane [%f,%f,%f,%f]\n", + stateblock->clipplane[index][0], + stateblock->clipplane[index][1], + stateblock->clipplane[index][2], + stateblock->clipplane[index][3]); + glClipPlane(GL_CLIP_PLANE0 + index, stateblock->clipplane[index]); + checkGLcall("glClipPlane"); + + glPopMatrix(); +} + +static void transform_worldex(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + UINT matrix = state - STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)); + GLenum glMat; + TRACE("Setting world matrix %d\n", matrix); + + if(matrix >= GL_LIMITS(blends)) { + WARN("Unsupported blend matrix set\n"); + return; + } else if(isStateDirty(context, STATE_TRANSFORM(WINED3DTS_VIEW))) { + return; + } + + /* GL_MODELVIEW0_ARB: 0x1700 + * GL_MODELVIEW1_ARB: 0x0x850a + * GL_MODELVIEW2_ARB: 0x8722 + * GL_MODELVIEW3_ARB: 0x8723 + * etc + * GL_MODELVIEW31_ARB: 0x873F + */ + if(matrix == 1) glMat = GL_MODELVIEW1_ARB; + else glMat = GL_MODELVIEW2_ARB - 2 + matrix; + + glMatrixMode(glMat); + checkGLcall("glMatrixMode(glMat)"); + + /* World matrix 0 is multiplied with the view matrix because d3d uses 3 matrices while gl uses only 2. To avoid + * weighting the view matrix incorrectly it has to be multiplied into every gl modelview matrix + */ + if(stateblock->wineD3DDevice->view_ident) { + glLoadMatrixf(&stateblock->transforms[WINED3DTS_WORLDMATRIX(matrix)].u.m[0][0]); + checkGLcall("glLoadMatrixf") + } else { + glLoadMatrixf(&stateblock->transforms[WINED3DTS_VIEW].u.m[0][0]); + checkGLcall("glLoadMatrixf") + glMultMatrixf(&stateblock->transforms[WINED3DTS_WORLDMATRIX(matrix)].u.m[0][0]); + checkGLcall("glMultMatrixf") + } +} + +static void state_vertexblend(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + WINED3DVERTEXBLENDFLAGS val = stateblock->renderState[WINED3DRS_VERTEXBLEND]; + + switch(val) { + case WINED3DVBF_1WEIGHTS: + case WINED3DVBF_2WEIGHTS: + case WINED3DVBF_3WEIGHTS: + if(GL_SUPPORT(ARB_VERTEX_BLEND)) { + glEnable(GL_VERTEX_BLEND_ARB); + checkGLcall("glEnable(GL_VERTEX_BLEND_ARB)"); + + /* D3D adds one more matrix which has weight (1 - sum(weights)). This is enabled at context + * creation with enabling GL_WEIGHT_SUM_UNITY_ARB. + */ + GL_EXTCALL(glVertexBlendARB(stateblock->renderState[WINED3DRS_VERTEXBLEND] + 1)); + + if(!stateblock->wineD3DDevice->vertexBlendUsed) { + int i; + for(i = 1; i < GL_LIMITS(blends); i++) { + if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(i)))) { + transform_worldex(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(i)), stateblock, context); + } + } + stateblock->wineD3DDevice->vertexBlendUsed = TRUE; + } + } else { + /* TODO: Implement vertex blending in drawStridedSlow */ + FIXME("Vertex blending enabled, but not supported by hardware\n"); + } + break; + + case WINED3DVBF_DISABLE: + case WINED3DVBF_0WEIGHTS: /* for Indexed vertex blending - not supported */ + if(GL_SUPPORT(ARB_VERTEX_BLEND)) { + glDisable(GL_VERTEX_BLEND_ARB); + checkGLcall("glDisable(GL_VERTEX_BLEND_ARB)"); + } else { + TRACE("Vertex blending disabled\n"); + } + break; + + case WINED3DVBF_TWEENING: + /* Just set the vertex weight for weight 0, enable vertex blending and hope the app doesn't have + * vertex weights in the vertices? + * For now we don't report that as supported, so a warn should suffice + */ + WARN("Tweening not supported yet\n"); + break; + } +} + +static void transform_view(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + unsigned int k; + + /* If we are changing the View matrix, reset the light and clipping planes to the new view + * NOTE: We have to reset the positions even if the light/plane is not currently + * enabled, since the call to enable it will not reset the position. + * NOTE2: Apparently texture transforms do NOT need reapplying + */ + + PLIGHTINFOEL *light = NULL; + + glMatrixMode(GL_MODELVIEW); + checkGLcall("glMatrixMode(GL_MODELVIEW)"); + glLoadMatrixf((float *)(float *) &stateblock->transforms[WINED3DTS_VIEW].u.m[0][0]); + checkGLcall("glLoadMatrixf(...)"); + + /* Reset lights. TODO: Call light apply func */ + for(k = 0; k < stateblock->wineD3DDevice->maxConcurrentLights; k++) { + light = stateblock->activeLights[k]; + if(!light) continue; + glLightfv(GL_LIGHT0 + light->glIndex, GL_POSITION, light->lightPosn); + checkGLcall("glLightfv posn"); + glLightfv(GL_LIGHT0 + light->glIndex, GL_SPOT_DIRECTION, light->lightDirn); + checkGLcall("glLightfv dirn"); + } + + /* Reset Clipping Planes */ + for (k = 0; k < GL_LIMITS(clipplanes); k++) { + if(!isStateDirty(context, STATE_CLIPPLANE(k))) { + clipplane(STATE_CLIPPLANE(k), stateblock, context); + } + } + + if(context->last_was_rhw) { + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + /* No need to update the world matrix, the identity is fine */ + return; + } + + /* Call the world matrix state, this will apply the combined WORLD + VIEW matrix + * No need to do it here if the state is scheduled for update. + */ + if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)))) { + transform_world(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), stateblock, context); + } + + /* Avoid looping over a number of matrices if the app never used the functionality */ + if(stateblock->wineD3DDevice->vertexBlendUsed) { + for(k = 1; k < GL_LIMITS(blends); k++) { + if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(k)))) { + transform_worldex(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(k)), stateblock, context); + } + } + } +} + +static const GLfloat invymat[16] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + +static void transform_projection(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + glMatrixMode(GL_PROJECTION); + checkGLcall("glMatrixMode(GL_PROJECTION)"); + glLoadIdentity(); + checkGLcall("glLoadIdentity"); + + if(context->last_was_rhw) { + double X, Y, height, width, minZ, maxZ; + + X = stateblock->viewport.X; + Y = stateblock->viewport.Y; + height = stateblock->viewport.Height; + width = stateblock->viewport.Width; + minZ = stateblock->viewport.MinZ; + maxZ = stateblock->viewport.MaxZ; + + if(!stateblock->wineD3DDevice->untransformed) { + /* Transformed vertices are supposed to bypass the whole transform pipeline including + * frustum clipping. This can't be done in opengl, so this code adjusts the Z range to + * suppress depth clipping. This can be done because it is an orthogonal projection and + * the Z coordinate does not affect the size of the primitives + */ + TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, -minZ, -maxZ); + if(stateblock->wineD3DDevice->render_offscreen) { + glOrtho(X, X + width, -Y, -Y - height, -minZ, -maxZ); + } else { + glOrtho(X, X + width, Y + height, Y, -minZ, -maxZ); + } + } else { + /* If the app mixes transformed and untransformed primitives we can't use the coordinate system + * trick above because this would mess up transformed and untransformed Z order. Pass the z position + * unmodified to opengl. + * + * If the app depends on mixed types and disabled clipping we're out of luck without a pipeline + * replacement shader. + */ + TRACE("Calling glOrtho with %f, %f, %f, %f\n", width, height, 1.0, -1.0); + if(stateblock->wineD3DDevice->render_offscreen) { + glOrtho(X, X + width, -Y, -Y - height, 1.0, -1.0); + } else { + glOrtho(X, X + width, Y + height, Y, 1.0, -1.0); + } + } + checkGLcall("glOrtho"); + + /* Window Coord 0 is the middle of the first pixel, so translate by 3/8 pixels */ + glTranslatef(0.375, 0.375, 0); + checkGLcall("glTranslatef(0.375, 0.375, 0)"); + /* D3D texture coordinates are flipped compared to OpenGL ones, so + * render everything upside down when rendering offscreen. */ + if (stateblock->wineD3DDevice->render_offscreen) { + glMultMatrixf(invymat); + checkGLcall("glMultMatrixf(invymat)"); + } + } else { + /* The rule is that the window coordinate 0 does not correspond to the + beginning of the first pixel, but the center of the first pixel. + As a consequence if you want to correctly draw one line exactly from + the left to the right end of the viewport (with all matrices set to + be identity), the x coords of both ends of the line would be not + -1 and 1 respectively but (-1-1/viewport_widh) and (1-1/viewport_width) + instead. */ + glTranslatef(0.9 / stateblock->viewport.Width, -0.9 / stateblock->viewport.Height, 0); + checkGLcall("glTranslatef (0.9 / width, -0.9 / height, 0)"); + + /* D3D texture coordinates are flipped compared to OpenGL ones, so + * render everything upside down when rendering offscreen. */ + if (stateblock->wineD3DDevice->render_offscreen) { + glMultMatrixf(invymat); + checkGLcall("glMultMatrixf(invymat)"); + } + glMultMatrixf((float *) &stateblock->transforms[WINED3DTS_PROJECTION].u.m[0][0]); + checkGLcall("glLoadMatrixf"); + } +} + +/* This should match any arrays loaded in loadVertexData. + * stateblock impl is required for GL_SUPPORT + * TODO: Only load / unload arrays if we have to. + */ +static inline void unloadVertexData(IWineD3DStateBlockImpl *stateblock) { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + glDisableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); + } + if (GL_SUPPORT(ARB_VERTEX_BLEND)) { + glDisableClientState(GL_WEIGHT_ARRAY_ARB); + } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) { + glDisableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT); + } + unloadTexCoords(stateblock); +} + +/* This should match any arrays loaded in loadNumberedArrays + * TODO: Only load / unload arrays if we have to. + */ +static inline void unloadNumberedArrays(IWineD3DStateBlockImpl *stateblock) { + /* disable any attribs (this is the same for both GLSL and ARB modes) */ + GLint maxAttribs; + int i; + + /* Leave all the attribs disabled */ + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &maxAttribs); + /* MESA does not support it right not */ + if (glGetError() != GL_NO_ERROR) + maxAttribs = 16; + for (i = 0; i < maxAttribs; ++i) { + GL_EXTCALL(glDisableVertexAttribArrayARB(i)); + checkGLcall("glDisableVertexAttribArrayARB(reg);"); + } +} + +static inline void loadNumberedArrays(IWineD3DStateBlockImpl *stateblock, WineDirect3DVertexStridedData *strided) { + GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0; + int i; + UINT *offset = stateblock->streamOffset; + + /* Default to no instancing */ + stateblock->wineD3DDevice->instancedDraw = FALSE; + + for (i = 0; i < MAX_ATTRIBS; i++) { + + if (!strided->u.input[i].lpData && !strided->u.input[i].VBO) + continue; + + /* Do not load instance data. It will be specified using glTexCoord by drawprim */ + if(stateblock->streamFlags[strided->u.input[i].streamNo] & WINED3DSTREAMSOURCE_INSTANCEDATA) { + GL_EXTCALL(glDisableVertexAttribArrayARB(i)); + stateblock->wineD3DDevice->instancedDraw = TRUE; + continue; + } + + TRACE_(d3d_shader)("Loading array %u [VBO=%u]\n", i, strided->u.input[i].VBO); + + if(strided->u.input[i].dwStride) { + if(curVBO != strided->u.input[i].VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, strided->u.input[i].VBO)); + checkGLcall("glBindBufferARB"); + curVBO = strided->u.input[i].VBO; + } + GL_EXTCALL(glVertexAttribPointerARB(i, + WINED3D_ATR_SIZE(strided->u.input[i].dwType), + WINED3D_ATR_GLTYPE(strided->u.input[i].dwType), + WINED3D_ATR_NORMALIZED(strided->u.input[i].dwType), + strided->u.input[i].dwStride, + strided->u.input[i].lpData + stateblock->loadBaseVertexIndex * strided->u.input[i].dwStride + offset[strided->u.input[i].streamNo]) ); + GL_EXTCALL(glEnableVertexAttribArrayARB(i)); + } else { + /* Stride = 0 means always the same values. glVertexAttribPointerARB doesn't do that. Instead disable the pointer and + * set up the attribute statically. But we have to figure out the system memory address. + */ + BYTE *ptr = strided->u.input[i].lpData + offset[strided->u.input[i].streamNo]; + if(strided->u.input[i].VBO) { + IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) stateblock->streamSource[strided->u.input[i].streamNo]; + ptr += (long) vb->resource.allocatedMemory; + } + GL_EXTCALL(glDisableVertexAttribArrayARB(i)); + + switch(strided->u.input[i].dwType) { + case WINED3DDECLTYPE_FLOAT1: + GL_EXTCALL(glVertexAttrib1fvARB(i, (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT2: + GL_EXTCALL(glVertexAttrib2fvARB(i, (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT3: + GL_EXTCALL(glVertexAttrib3fvARB(i, (float *) ptr)); + break; + case WINED3DDECLTYPE_FLOAT4: + GL_EXTCALL(glVertexAttrib4fvARB(i, (float *) ptr)); + break; + + case WINED3DDECLTYPE_UBYTE4: + GL_EXTCALL(glVertexAttrib4NubvARB(i, ptr)); + break; + case WINED3DDECLTYPE_UBYTE4N: + case WINED3DDECLTYPE_D3DCOLOR: + GL_EXTCALL(glVertexAttrib4NubvARB(i, ptr)); + break; + + case WINED3DDECLTYPE_SHORT2: + GL_EXTCALL(glVertexAttrib4svARB(i, (GLshort *) ptr)); + break; + case WINED3DDECLTYPE_SHORT4: + GL_EXTCALL(glVertexAttrib4svARB(i, (GLshort *) ptr)); + break; + + case WINED3DDECLTYPE_SHORT2N: + { + GLshort s[4] = {((short *) ptr)[0], ((short *) ptr)[1], 0, 1}; + GL_EXTCALL(glVertexAttrib4NsvARB(i, s)); + break; + } + case WINED3DDECLTYPE_USHORT2N: + { + GLushort s[4] = {((unsigned short *) ptr)[0], ((unsigned short *) ptr)[1], 0, 1}; + GL_EXTCALL(glVertexAttrib4NusvARB(i, s)); + break; + } + case WINED3DDECLTYPE_SHORT4N: + GL_EXTCALL(glVertexAttrib4NsvARB(i, (GLshort *) ptr)); + break; + case WINED3DDECLTYPE_USHORT4N: + GL_EXTCALL(glVertexAttrib4NusvARB(i, (GLushort *) ptr)); + break; + + case WINED3DDECLTYPE_UDEC3: + FIXME("Unsure about WINED3DDECLTYPE_UDEC3\n"); + /*glVertexAttrib3usvARB(i, (GLushort *) ptr); Does not exist */ + break; + case WINED3DDECLTYPE_DEC3N: + FIXME("Unsure about WINED3DDECLTYPE_DEC3N\n"); + /*glVertexAttrib3NusvARB(i, (GLushort *) ptr); Does not exist */ + break; + + case WINED3DDECLTYPE_FLOAT16_2: + /* Are those 16 bit floats. C doesn't have a 16 bit float type. I could read the single bits and calculate a 4 + * byte float according to the IEEE standard + */ + FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_2\n"); + break; + case WINED3DDECLTYPE_FLOAT16_4: + FIXME("Unsupported WINED3DDECLTYPE_FLOAT16_4\n"); + break; + + case WINED3DDECLTYPE_UNUSED: + default: + ERR("Unexpected declaration in stride 0 attributes\n"); + break; + + } + } + } +} + +/* Used from 2 different functions, and too big to justify making it inlined */ +static void loadVertexData(IWineD3DStateBlockImpl *stateblock, WineDirect3DVertexStridedData *sd) { + UINT *offset = stateblock->streamOffset; + GLint curVBO = GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) ? -1 : 0; + + TRACE("Using fast vertex array code\n"); + + /* This is fixed function pipeline only, and the fixed function pipeline doesn't do instancing */ + stateblock->wineD3DDevice->instancedDraw = FALSE; + + /* Blend Data ---------------------------------------------- */ + if( (sd->u.s.blendWeights.lpData) || (sd->u.s.blendWeights.VBO) || + (sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO) ) { + + if (GL_SUPPORT(ARB_VERTEX_BLEND)) { + TRACE("Blend %d %p %d\n", WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType), + sd->u.s.blendWeights.lpData + stateblock->loadBaseVertexIndex * sd->u.s.blendWeights.dwStride, sd->u.s.blendWeights.dwStride + offset[sd->u.s.blendWeights.streamNo]); + + glEnableClientState(GL_WEIGHT_ARRAY_ARB); + checkGLcall("glEnableClientState(GL_WEIGHT_ARRAY_ARB)"); + + GL_EXTCALL(glVertexBlendARB(WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) + 1)); + + VTRACE(("glWeightPointerARB(%d, GL_FLOAT, %d, %p)\n", + WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType) , + sd->u.s.blendWeights.dwStride, + sd->u.s.blendWeights.lpData + stateblock->loadBaseVertexIndex * sd->u.s.blendWeights.dwStride + offset[sd->u.s.blendWeights.streamNo])); + + if(curVBO != sd->u.s.blendWeights.VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.blendWeights.VBO)); + checkGLcall("glBindBufferARB"); + curVBO = sd->u.s.blendWeights.VBO; + } + + GL_EXTCALL(glWeightPointerARB)( + WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType), + WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType), + sd->u.s.blendWeights.dwStride, + sd->u.s.blendWeights.lpData + stateblock->loadBaseVertexIndex * sd->u.s.blendWeights.dwStride + offset[sd->u.s.blendWeights.streamNo]); + + checkGLcall("glWeightPointerARB"); + + if((sd->u.s.blendMatrixIndices.lpData) || (sd->u.s.blendMatrixIndices.VBO)){ + static BOOL showfixme = TRUE; + if(showfixme){ + FIXME("blendMatrixIndices support\n"); + showfixme = FALSE; + } + } + } else if (GL_SUPPORT(EXT_VERTEX_WEIGHTING)) { + /* FIXME("TODO\n");*/ +#if 0 + + GL_EXTCALL(glVertexWeightPointerEXT)( + WINED3D_ATR_SIZE(sd->u.s.blendWeights.dwType), + WINED3D_ATR_GLTYPE(sd->u.s.blendWeights.dwType), + sd->u.s.blendWeights.dwStride, + sd->u.s.blendWeights.lpData + stateblock->loadBaseVertexIndex * sd->u.s.blendWeights.dwStride); + checkGLcall("glVertexWeightPointerEXT(numBlends, ...)"); + glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT); + checkGLcall("glEnableClientState(GL_VERTEX_WEIGHT_ARRAY_EXT)"); +#endif + + } else { + /* TODO: support blends in drawStridedSlow + * No need to write a FIXME here, this is done after the general vertex decl decoding + */ + WARN("unsupported blending in openGl\n"); + } + } else { + if (GL_SUPPORT(ARB_VERTEX_BLEND)) { + static const GLbyte one = 1; + GL_EXTCALL(glWeightbvARB(1, &one)); + checkGLcall("glWeightivARB(GL_LIMITS(blends), weights)"); + } + } + +#if 0 /* FOG ----------------------------------------------*/ + if (sd->u.s.fog.lpData || sd->u.s.fog.VBO) { + /* TODO: fog*/ + if (GL_SUPPORT(EXT_FOG_COORD) { + glEnableClientState(GL_FOG_COORDINATE_EXT); + (GL_EXTCALL)(FogCoordPointerEXT)( + WINED3D_ATR_GLTYPE(sd->u.s.fog.dwType), + sd->u.s.fog.dwStride, + sd->u.s.fog.lpData + stateblock->loadBaseVertexIndex * sd->u.s.fog.dwStride); + } else { + /* don't bother falling back to 'slow' as we don't support software FOG yet. */ + /* FIXME: fixme once */ + TRACE("Hardware support for FOG is not avaiable, FOG disabled.\n"); + } + } else { + if (GL_SUPPRT(EXT_FOR_COORD) { + /* make sure fog is disabled */ + glDisableClientState(GL_FOG_COORDINATE_EXT); + } + } +#endif + +#if 0 /* tangents ----------------------------------------------*/ + if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO || + sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) { + /* TODO: tangents*/ + if (GL_SUPPORT(EXT_COORDINATE_FRAME) { + if (sd->u.s.tangent.lpData || sd->u.s.tangent.VBO) { + glEnable(GL_TANGENT_ARRAY_EXT); + (GL_EXTCALL)(TangentPointerEXT)( + WINED3D_ATR_GLTYPE(sd->u.s.tangent.dwType), + sd->u.s.tangent.dwStride, + sd->u.s.tangent.lpData + stateblock->loadBaseVertexIndex * sd->u.s.tangent.dwStride); + } else { + glDisable(GL_TANGENT_ARRAY_EXT); + } + if (sd->u.s.binormal.lpData || sd->u.s.binormal.VBO) { + glEnable(GL_BINORMAL_ARRAY_EXT); + (GL_EXTCALL)(BinormalPointerEXT)( + WINED3D_ATR_GLTYPE(sd->u.s.binormal.dwType), + sd->u.s.binormal.dwStride, + sd->u.s.binormal.lpData + stateblock->loadBaseVertexIndex * sd->u.s.binormal.dwStride); + } else{ + glDisable(GL_BINORMAL_ARRAY_EXT); + } + + } else { + /* don't bother falling back to 'slow' as we don't support software tangents and binormals yet . */ + /* FIXME: fixme once */ + TRACE("Hardware support for tangents and binormals is not avaiable, tangents and binormals disabled.\n"); + } + } else { + if (GL_SUPPORT(EXT_COORDINATE_FRAME) { + /* make sure fog is disabled */ + glDisable(GL_TANGENT_ARRAY_EXT); + glDisable(GL_BINORMAL_ARRAY_EXT); + } + } +#endif + + /* Point Size ----------------------------------------------*/ + if (sd->u.s.pSize.lpData || sd->u.s.pSize.VBO) { + + /* no such functionality in the fixed function GL pipeline */ + TRACE("Cannot change ptSize here in openGl\n"); + /* TODO: Implement this function in using shaders if they are available */ + + } + + /* Vertex Pointers -----------------------------------------*/ + if (sd->u.s.position.lpData != NULL || sd->u.s.position.VBO != 0) { + /* Note dwType == float3 or float4 == 2 or 3 */ + VTRACE(("glVertexPointer(%d, GL_FLOAT, %d, %p)\n", + sd->u.s.position.dwStride, + sd->u.s.position.dwType + 1, + sd->u.s.position.lpData)); + + if(curVBO != sd->u.s.position.VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.position.VBO)); + checkGLcall("glBindBufferARB"); + curVBO = sd->u.s.position.VBO; + } + + /* min(WINED3D_ATR_SIZE(position),3) to Disable RHW mode as 'w' coord + handling for rhw mode should not impact screen position whereas in GL it does. + This may result in very slightly distored textures in rhw mode, but + a very minimal different. There's always the other option of + fixing the view matrix to prevent w from having any effect + + This only applies to user pointer sources, in VBOs the vertices are fixed up + */ + if(sd->u.s.position.VBO == 0) { + glVertexPointer(3 /* min(WINED3D_ATR_SIZE(sd->u.s.position.dwType),3) */, + WINED3D_ATR_GLTYPE(sd->u.s.position.dwType), + sd->u.s.position.dwStride, sd->u.s.position.lpData + stateblock->loadBaseVertexIndex * sd->u.s.position.dwStride + offset[sd->u.s.position.streamNo]); + } else { + glVertexPointer( + WINED3D_ATR_SIZE(sd->u.s.position.dwType), + WINED3D_ATR_GLTYPE(sd->u.s.position.dwType), + sd->u.s.position.dwStride, sd->u.s.position.lpData + stateblock->loadBaseVertexIndex * sd->u.s.position.dwStride + offset[sd->u.s.position.streamNo]); + } + checkGLcall("glVertexPointer(...)"); + glEnableClientState(GL_VERTEX_ARRAY); + checkGLcall("glEnableClientState(GL_VERTEX_ARRAY)"); + } + + /* Normals -------------------------------------------------*/ + if (sd->u.s.normal.lpData || sd->u.s.normal.VBO) { + /* Note dwType == float3 or float4 == 2 or 3 */ + VTRACE(("glNormalPointer(GL_FLOAT, %d, %p)\n", + sd->u.s.normal.dwStride, + sd->u.s.normal.lpData)); + if(curVBO != sd->u.s.normal.VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.normal.VBO)); + checkGLcall("glBindBufferARB"); + curVBO = sd->u.s.normal.VBO; + } + glNormalPointer( + WINED3D_ATR_GLTYPE(sd->u.s.normal.dwType), + sd->u.s.normal.dwStride, + sd->u.s.normal.lpData + stateblock->loadBaseVertexIndex * sd->u.s.normal.dwStride + offset[sd->u.s.normal.streamNo]); + checkGLcall("glNormalPointer(...)"); + glEnableClientState(GL_NORMAL_ARRAY); + checkGLcall("glEnableClientState(GL_NORMAL_ARRAY)"); + + } else { + glNormal3f(0, 0, 1); + checkGLcall("glNormal3f(0, 0, 1)"); + } + + /* Diffuse Colour --------------------------------------------*/ + /* WARNING: Data here MUST be in RGBA format, so cannot */ + /* go directly into fast mode from app pgm, because */ + /* directx requires data in BGRA format. */ + /* currently fixupVertices swizels the format, but this isn't */ + /* very practical when using VBOS */ + /* NOTE: Unless we write a vertex shader to swizel the colour */ + /* , or the user doesn't care and wants the speed advantage */ + + if (sd->u.s.diffuse.lpData || sd->u.s.diffuse.VBO) { + /* Note dwType == float3 or float4 == 2 or 3 */ + VTRACE(("glColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n", + sd->u.s.diffuse.dwStride, + sd->u.s.diffuse.lpData)); + + if(curVBO != sd->u.s.diffuse.VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.diffuse.VBO)); + checkGLcall("glBindBufferARB"); + curVBO = sd->u.s.diffuse.VBO; + } + glColorPointer(4, GL_UNSIGNED_BYTE, + sd->u.s.diffuse.dwStride, + sd->u.s.diffuse.lpData + stateblock->loadBaseVertexIndex * sd->u.s.diffuse.dwStride + offset[sd->u.s.diffuse.streamNo]); + checkGLcall("glColorPointer(4, GL_UNSIGNED_BYTE, ...)"); + glEnableClientState(GL_COLOR_ARRAY); + checkGLcall("glEnableClientState(GL_COLOR_ARRAY)"); + + } else { + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + checkGLcall("glColor4f(1, 1, 1, 1)"); + } + + /* Specular Colour ------------------------------------------*/ + if (sd->u.s.specular.lpData || sd->u.s.specular.VBO) { + TRACE("setting specular colour\n"); + /* Note dwType == float3 or float4 == 2 or 3 */ + VTRACE(("glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, %d, %p)\n", + sd->u.s.specular.dwStride, + sd->u.s.specular.lpData)); + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + if(curVBO != sd->u.s.specular.VBO) { + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, sd->u.s.specular.VBO)); + checkGLcall("glBindBufferARB"); + curVBO = sd->u.s.specular.VBO; + } + GL_EXTCALL(glSecondaryColorPointerEXT)(4, GL_UNSIGNED_BYTE, + sd->u.s.specular.dwStride, + sd->u.s.specular.lpData + stateblock->loadBaseVertexIndex * sd->u.s.specular.dwStride + offset[sd->u.s.specular.streamNo]); + vcheckGLcall("glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, ...)"); + glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT); + vcheckGLcall("glEnableClientState(GL_SECONDARY_COLOR_ARRAY_EXT)"); + } else { + + /* Missing specular color is not critical, no warnings */ + VTRACE(("Specular colour is not supported in this GL implementation\n")); + } + + } else { + if (GL_SUPPORT(EXT_SECONDARY_COLOR)) { + GL_EXTCALL(glSecondaryColor3fEXT)(0, 0, 0); + checkGLcall("glSecondaryColor3fEXT(0, 0, 0)"); + } else { + + /* Missing specular color is not critical, no warnings */ + VTRACE(("Specular colour is not supported in this GL implementation\n")); + } + } + + /* Texture coords -------------------------------------------*/ + loadTexCoords(stateblock, sd, &curVBO); +} + +static inline void drawPrimitiveTraceDataLocations( + WineDirect3DVertexStridedData *dataLocations) { + + /* Dump out what parts we have supplied */ + TRACE("Strided Data:\n"); + TRACE_STRIDED((dataLocations), position); + TRACE_STRIDED((dataLocations), blendWeights); + TRACE_STRIDED((dataLocations), blendMatrixIndices); + TRACE_STRIDED((dataLocations), normal); + TRACE_STRIDED((dataLocations), pSize); + TRACE_STRIDED((dataLocations), diffuse); + TRACE_STRIDED((dataLocations), specular); + TRACE_STRIDED((dataLocations), texCoords[0]); + TRACE_STRIDED((dataLocations), texCoords[1]); + TRACE_STRIDED((dataLocations), texCoords[2]); + TRACE_STRIDED((dataLocations), texCoords[3]); + TRACE_STRIDED((dataLocations), texCoords[4]); + TRACE_STRIDED((dataLocations), texCoords[5]); + TRACE_STRIDED((dataLocations), texCoords[6]); + TRACE_STRIDED((dataLocations), texCoords[7]); + TRACE_STRIDED((dataLocations), position2); + TRACE_STRIDED((dataLocations), normal2); + TRACE_STRIDED((dataLocations), tangent); + TRACE_STRIDED((dataLocations), binormal); + TRACE_STRIDED((dataLocations), tessFactor); + TRACE_STRIDED((dataLocations), fog); + TRACE_STRIDED((dataLocations), depth); + TRACE_STRIDED((dataLocations), sample); + + return; +} + +/* Helper for vertexdeclaration() */ +static inline void handleStreams(IWineD3DStateBlockImpl *stateblock, BOOL useVertexShaderFunction, WineD3DContext *context) { + IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; + BOOL fixup = FALSE; + WineDirect3DVertexStridedData *dataLocations = &device->strided_streams; + + if(device->up_strided) { + /* Note: this is a ddraw fixed-function code path */ + TRACE("================ Strided Input ===================\n"); + memcpy(dataLocations, device->up_strided, sizeof(*dataLocations)); + + if(TRACE_ON(d3d)) { + drawPrimitiveTraceDataLocations(dataLocations); + } + } else { + /* Note: This is a fixed function or shader codepath. + * This means it must handle both types of strided data. + * Shaders must go through here to zero the strided data, even if they + * don't set any declaration at all + */ + TRACE("================ Vertex Declaration ===================\n"); + memset(dataLocations, 0, sizeof(*dataLocations)); + primitiveDeclarationConvertToStridedData((IWineD3DDevice *) device, + useVertexShaderFunction, dataLocations, &fixup); + } + + if (dataLocations->u.s.position_transformed) { + useVertexShaderFunction = FALSE; + } + + /* Unload the old arrays before loading the new ones to get old junk out */ + if(context->numberedArraysLoaded) { + unloadNumberedArrays(stateblock); + context->numberedArraysLoaded = FALSE; + } + if(context->namedArraysLoaded) { + unloadVertexData(stateblock); + context->namedArraysLoaded = FALSE; + } + + if(useVertexShaderFunction) { + TRACE("Loading numbered arrays\n"); + loadNumberedArrays(stateblock, dataLocations); + device->useDrawStridedSlow = FALSE; + context->numberedArraysLoaded = TRUE; + } else if (fixup || + (dataLocations->u.s.pSize.lpData == NULL && + dataLocations->u.s.diffuse.lpData == NULL && + dataLocations->u.s.specular.lpData == NULL)) { + /* Load the vertex data using named arrays */ + TRACE("Loading vertex data\n"); + loadVertexData(stateblock, dataLocations); + device->useDrawStridedSlow = FALSE; + context->namedArraysLoaded = TRUE; + } else { + TRACE("Not loading vertex data\n"); + device->useDrawStridedSlow = TRUE; + } + +/* Generate some fixme's if unsupported functionality is being used */ +#define BUFFER_OR_DATA(_attribute) dataLocations->u.s._attribute.lpData + /* TODO: Either support missing functionality in fixupVertices or by creating a shader to replace the pipeline. */ + if (!useVertexShaderFunction && (BUFFER_OR_DATA(position2) || BUFFER_OR_DATA(normal2))) { + FIXME("Tweening is only valid with vertex shaders\n"); + } + if (!useVertexShaderFunction && (BUFFER_OR_DATA(tangent) || BUFFER_OR_DATA(binormal))) { + FIXME("Tangent and binormal bump mapping is only valid with vertex shaders\n"); + } + if (!useVertexShaderFunction && (BUFFER_OR_DATA(tessFactor) || BUFFER_OR_DATA(fog) || BUFFER_OR_DATA(depth) || BUFFER_OR_DATA(sample))) { + FIXME("Extended attributes are only valid with vertex shaders\n"); + } +#undef BUFFER_OR_DATA +} + +static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + BOOL useVertexShaderFunction = FALSE, updateFog = FALSE; + BOOL usePixelShaderFunction = stateblock->wineD3DDevice->ps_selected_mode != SHADER_NONE && stateblock->pixelShader + && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function; + BOOL transformed; + /* Some stuff is in the device until we have per context tracking */ + IWineD3DDeviceImpl *device = stateblock->wineD3DDevice; + BOOL wasrhw = context->last_was_rhw; + + /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software - + * here simply check whether a shader was set, or the user disabled shaders + */ + if (device->vs_selected_mode != SHADER_NONE && stateblock->vertexShader && + ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function != NULL) { + useVertexShaderFunction = TRUE; + + if(((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.fog != context->last_was_foggy_shader) { + updateFog = TRUE; + } + } else if(context->last_was_foggy_shader) { + updateFog = TRUE; + } + + handleStreams(stateblock, useVertexShaderFunction, context); + + transformed = device->strided_streams.u.s.position_transformed; + if (transformed) useVertexShaderFunction = FALSE; + + if(transformed != context->last_was_rhw && !useVertexShaderFunction) { + updateFog = TRUE; + } + + /* Reapply lighting if it is not scheduled for reapplication already */ + if(!isStateDirty(context, STATE_RENDER(WINED3DRS_LIGHTING))) { + state_lighting(STATE_RENDER(WINED3DRS_LIGHTING), stateblock, context); + } + + if (transformed) { + context->last_was_rhw = TRUE; + } else { + + /* Untransformed, so relies on the view and projection matrices */ + context->last_was_rhw = FALSE; + /* This turns off the Z scale trick to 'disable' viewport frustum clipping in rhw mode*/ + device->untransformed = TRUE; + + /* Todo for sw shaders: Vertex Shader output is already transformed, so set up identity matrices + * Not needed as long as only hw shaders are supported + */ + + /* This sets the shader output position correction constants. + * TODO: Move to the viewport state + */ + if (useVertexShaderFunction) { + device->posFixup[1] = device->render_offscreen ? -1.0 : 1.0; + } + } + + /* Don't have to apply the matrices when vertex shaders are used. When vshaders are turned + * off this function will be called again anyway to make sure they're properly set + */ + if(!useVertexShaderFunction) { + /* TODO: Move this mainly to the viewport state and only apply when the vp has changed + * or transformed / untransformed was switched + */ + if(wasrhw != context->last_was_rhw && + !isStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION)) && + !isStateDirty(context, STATE_VIEWPORT)) { + transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock, context); + } + /* World matrix needs reapplication here only if we're switching between rhw and non-rhw + * mode. + * + * If a vertex shader is used, the world matrix changed and then vertex shader unbound + * this check will fail and the matrix not applied again. This is OK because a simple + * world matrix change reapplies the matrix - These checks here are only to satisfy the + * needs of the vertex declaration. + * + * World and view matrix go into the same gl matrix, so only apply them when neither is + * dirty + */ + if(transformed != wasrhw && + !isStateDirty(context, STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))) && + !isStateDirty(context, STATE_TRANSFORM(WINED3DTS_VIEW))) { + transform_world(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), stateblock, context); + } + + if(!isStateDirty(context, STATE_RENDER(WINED3DRS_COLORVERTEX))) { + state_colormat(STATE_RENDER(WINED3DRS_COLORVERTEX), stateblock, context); + } + + if(context->last_was_vshader && !isStateDirty(context, STATE_RENDER(WINED3DRS_CLIPPLANEENABLE))) { + state_clipping(STATE_RENDER(WINED3DRS_CLIPPLANEENABLE), stateblock, context); + } + } else { + /* We compile the shader here because we need the vertex declaration + * in order to determine if we need to do any swizzling for D3DCOLOR + * registers. If the shader is already compiled this call will do nothing. */ + IWineD3DVertexShader_CompileShader(stateblock->vertexShader); + + if(!context->last_was_vshader) { + int i; + static BOOL warned = FALSE; + /* Disable all clip planes to get defined results on all drivers. See comment in the + * state_clipping state handler + */ + for(i = 0; i < GL_LIMITS(clipplanes); i++) { + glDisable(GL_CLIP_PLANE0 + i); + checkGLcall("glDisable(GL_CLIP_PLANE0 + i)"); + } + + if(!warned && stateblock->renderState[WINED3DRS_CLIPPLANEENABLE]) { + FIXME("Clipping not supported with vertex shaders\n"); + warned = TRUE; + } + } + } + + /* Vertex and pixel shaders are applied together for now, so let the last dirty state do the + * application + */ + if (!isStateDirty(context, STATE_PIXELSHADER)) { + device->shader_backend->shader_select((IWineD3DDevice *)device, usePixelShaderFunction, useVertexShaderFunction); + + if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (useVertexShaderFunction || usePixelShaderFunction)) { + shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context); + } + } + + context->last_was_vshader = useVertexShaderFunction; + + if(updateFog) { + state_fog(STATE_RENDER(WINED3DRS_FOGENABLE), stateblock, context); + } +} + +static void viewport(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + glDepthRange(stateblock->viewport.MinZ, stateblock->viewport.MaxZ); + checkGLcall("glDepthRange"); + /* Note: GL requires lower left, DirectX supplies upper left. This is reversed when using offscreen rendering + */ + if(stateblock->wineD3DDevice->render_offscreen) { + glViewport(stateblock->viewport.X, + stateblock->viewport.Y, + stateblock->viewport.Width, stateblock->viewport.Height); + } else { + glViewport(stateblock->viewport.X, + (((IWineD3DSurfaceImpl *)stateblock->wineD3DDevice->render_targets[0])->currentDesc.Height - (stateblock->viewport.Y + stateblock->viewport.Height)), + stateblock->viewport.Width, stateblock->viewport.Height); + } + + checkGLcall("glViewport"); + + stateblock->wineD3DDevice->posFixup[2] = 0.9 / stateblock->viewport.Width; + stateblock->wineD3DDevice->posFixup[3] = -0.9 / stateblock->viewport.Height; + if(!isStateDirty(context, STATE_TRANSFORM(WINED3DTS_PROJECTION))) { + transform_projection(STATE_TRANSFORM(WINED3DTS_PROJECTION), stateblock, context); + } + +} + +static void light(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + UINT Index = state - STATE_ACTIVELIGHT(0); + PLIGHTINFOEL *lightInfo = stateblock->activeLights[Index]; + + if(!lightInfo) { + glDisable(GL_LIGHT0 + Index); + checkGLcall("glDisable(GL_LIGHT0 + Index)"); + } else { + float quad_att; + float colRGBA[] = {0.0, 0.0, 0.0, 0.0}; + + /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/ + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadMatrixf((float *)&stateblock->transforms[WINED3DTS_VIEW].u.m[0][0]); + + /* Diffuse: */ + colRGBA[0] = lightInfo->OriginalParms.Diffuse.r; + colRGBA[1] = lightInfo->OriginalParms.Diffuse.g; + colRGBA[2] = lightInfo->OriginalParms.Diffuse.b; + colRGBA[3] = lightInfo->OriginalParms.Diffuse.a; + glLightfv(GL_LIGHT0 + Index, GL_DIFFUSE, colRGBA); + checkGLcall("glLightfv"); + + /* Specular */ + colRGBA[0] = lightInfo->OriginalParms.Specular.r; + colRGBA[1] = lightInfo->OriginalParms.Specular.g; + colRGBA[2] = lightInfo->OriginalParms.Specular.b; + colRGBA[3] = lightInfo->OriginalParms.Specular.a; + glLightfv(GL_LIGHT0 + Index, GL_SPECULAR, colRGBA); + checkGLcall("glLightfv"); + + /* Ambient */ + colRGBA[0] = lightInfo->OriginalParms.Ambient.r; + colRGBA[1] = lightInfo->OriginalParms.Ambient.g; + colRGBA[2] = lightInfo->OriginalParms.Ambient.b; + colRGBA[3] = lightInfo->OriginalParms.Ambient.a; + glLightfv(GL_LIGHT0 + Index, GL_AMBIENT, colRGBA); + checkGLcall("glLightfv"); + + if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) { + quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range); + } else { + quad_att = 0; /* 0 or MAX? (0 seems to be ok) */ + } + + /* Do not assign attenuation values for lights that do not use them. D3D apps are free to pass any junk, + * but gl drivers use them and may crash due to bad Attenuation values. Need for Speed most wanted sets + * Attenuation0 to NaN and crashes in the gl lib + */ + + switch (lightInfo->OriginalParms.Type) { + case WINED3DLIGHT_POINT: + /* Position */ + glLightfv(GL_LIGHT0 + Index, GL_POSITION, &lightInfo->lightPosn[0]); + checkGLcall("glLightfv"); + glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff); + checkGLcall("glLightf"); + /* Attenuation - Are these right? guessing... */ + glLightf(GL_LIGHT0 + Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0); + checkGLcall("glLightf"); + glLightf(GL_LIGHT0 + Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1); + checkGLcall("glLightf"); + if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2; + glLightf(GL_LIGHT0 + Index, GL_QUADRATIC_ATTENUATION, quad_att); + checkGLcall("glLightf"); + /* FIXME: Range */ + break; + + case WINED3DLIGHT_SPOT: + /* Position */ + glLightfv(GL_LIGHT0 + Index, GL_POSITION, &lightInfo->lightPosn[0]); + checkGLcall("glLightfv"); + /* Direction */ + glLightfv(GL_LIGHT0 + Index, GL_SPOT_DIRECTION, &lightInfo->lightDirn[0]); + checkGLcall("glLightfv"); + glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, lightInfo->exponent); + checkGLcall("glLightf"); + glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff); + checkGLcall("glLightf"); + /* Attenuation - Are these right? guessing... */ + glLightf(GL_LIGHT0 + Index, GL_CONSTANT_ATTENUATION, lightInfo->OriginalParms.Attenuation0); + checkGLcall("glLightf"); + glLightf(GL_LIGHT0 + Index, GL_LINEAR_ATTENUATION, lightInfo->OriginalParms.Attenuation1); + checkGLcall("glLightf"); + if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2; + glLightf(GL_LIGHT0 + Index, GL_QUADRATIC_ATTENUATION, quad_att); + checkGLcall("glLightf"); + /* FIXME: Range */ + break; + + case WINED3DLIGHT_DIRECTIONAL: + /* Direction */ + glLightfv(GL_LIGHT0 + Index, GL_POSITION, &lightInfo->lightPosn[0]); /* Note gl uses w position of 0 for direction! */ + checkGLcall("glLightfv"); + glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff); + checkGLcall("glLightf"); + glLightf(GL_LIGHT0 + Index, GL_SPOT_EXPONENT, 0.0f); + checkGLcall("glLightf"); + break; + + default: + FIXME("Unrecognized light type %d\n", lightInfo->OriginalParms.Type); + } + + /* Restore the modelview matrix */ + glPopMatrix(); + + glEnable(GL_LIGHT0 + Index); + checkGLcall("glEnable(GL_LIGHT0 + Index)"); + } + + return; +} + +static void scissorrect(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) stateblock->wineD3DDevice->swapchains[0]; + RECT *pRect = &stateblock->scissorRect; + RECT windowRect; + UINT winHeight; + + GetClientRect(swapchain->win_handle, &windowRect); + /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply + * Warning2: Even in windowed mode the coords are relative to the window, not the screen + */ + winHeight = windowRect.bottom - windowRect.top; + TRACE("(%p) Setting new Scissor Rect to %d:%d-%d:%d\n", stateblock->wineD3DDevice, pRect->left, pRect->bottom - winHeight, + pRect->right - pRect->left, pRect->bottom - pRect->top); + + if (stateblock->wineD3DDevice->render_offscreen) { + glScissor(pRect->left, pRect->top, pRect->right - pRect->left, pRect->bottom - pRect->top); + } else { + glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top); + } + checkGLcall("glScissor"); +} + +static void indexbuffer(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) { + if(stateblock->streamIsUP || stateblock->pIndexData == NULL ) { + GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0)); + } else { + IWineD3DIndexBufferImpl *ib = (IWineD3DIndexBufferImpl *) stateblock->pIndexData; + GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ib->vbo)); + } + } +} + +const struct StateEntry StateTable[] = +{ + /* State name representative, apply function */ + { /* 0, Undefined */ 0, state_undefined }, + { /* 1, WINED3DRS_TEXTUREHANDLE */ 0 /* Handled in ddraw */, state_undefined }, + { /* 2, WINED3DRS_ANTIALIAS */ STATE_RENDER(WINED3DRS_ANTIALIAS), state_antialias }, + { /* 3, WINED3DRS_TEXTUREADDRESS */ 0 /* Handled in ddraw */, state_undefined }, + { /* 4, WINED3DRS_TEXTUREPERSPECTIVE */ STATE_RENDER(WINED3DRS_TEXTUREPERSPECTIVE), state_perspective }, + { /* 5, WINED3DRS_WRAPU */ STATE_RENDER(WINED3DRS_WRAPU), state_wrapu }, + { /* 6, WINED3DRS_WRAPV */ STATE_RENDER(WINED3DRS_WRAPV), state_wrapv }, + { /* 7, WINED3DRS_ZENABLE */ STATE_RENDER(WINED3DRS_ZENABLE), state_zenable }, + { /* 8, WINED3DRS_FILLMODE */ STATE_RENDER(WINED3DRS_FILLMODE), state_fillmode }, + { /* 9, WINED3DRS_SHADEMODE */ STATE_RENDER(WINED3DRS_SHADEMODE), state_shademode }, + { /* 10, WINED3DRS_LINEPATTERN */ STATE_RENDER(WINED3DRS_LINEPATTERN), state_linepattern }, + { /* 11, WINED3DRS_MONOENABLE */ STATE_RENDER(WINED3DRS_MONOENABLE), state_monoenable }, + { /* 12, WINED3DRS_ROP2 */ STATE_RENDER(WINED3DRS_ROP2), state_rop2 }, + { /* 13, WINED3DRS_PLANEMASK */ STATE_RENDER(WINED3DRS_PLANEMASK), state_planemask }, + { /* 14, WINED3DRS_ZWRITEENABLE */ STATE_RENDER(WINED3DRS_ZWRITEENABLE), state_zwritenable }, + { /* 15, WINED3DRS_ALPHATESTENABLE */ STATE_RENDER(WINED3DRS_ALPHATESTENABLE), state_alpha }, + { /* 16, WINED3DRS_LASTPIXEL */ STATE_RENDER(WINED3DRS_LASTPIXEL), state_lastpixel }, + { /* 17, WINED3DRS_TEXTUREMAG */ 0 /* Handled in ddraw */, state_undefined }, + { /* 18, WINED3DRS_TEXTUREMIN */ 0 /* Handled in ddraw */, state_undefined }, + { /* 19, WINED3DRS_SRCBLEND */ STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_blend }, + { /* 20, WINED3DRS_DESTBLEND */ STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_blend }, + { /* 21, WINED3DRS_TEXTUREMAPBLEND */ 0 /* Handled in ddraw */, state_undefined }, + { /* 22, WINED3DRS_CULLMODE */ STATE_RENDER(WINED3DRS_CULLMODE), state_cullmode }, + { /* 23, WINED3DRS_ZFUNC */ STATE_RENDER(WINED3DRS_ZFUNC), state_zfunc }, + { /* 24, WINED3DRS_ALPHAREF */ STATE_RENDER(WINED3DRS_ALPHATESTENABLE), state_alpha }, + { /* 25, WINED3DRS_ALPHAFUNC */ STATE_RENDER(WINED3DRS_ALPHATESTENABLE), state_alpha }, + { /* 26, WINED3DRS_DITHERENABLE */ STATE_RENDER(WINED3DRS_DITHERENABLE), state_ditherenable }, + { /* 27, WINED3DRS_ALPHABLENDENABLE */ STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_blend }, + { /* 28, WINED3DRS_FOGENABLE */ STATE_RENDER(WINED3DRS_FOGENABLE), state_fog }, + { /* 29, WINED3DRS_SPECULARENABLE */ STATE_RENDER(WINED3DRS_SPECULARENABLE), state_specularenable}, + { /* 30, WINED3DRS_ZVISIBLE */ 0 /* Not supported according to the msdn */, state_nogl }, + { /* 31, WINED3DRS_SUBPIXEL */ STATE_RENDER(WINED3DRS_SUBPIXEL), state_subpixel }, + { /* 32, WINED3DRS_SUBPIXELX */ STATE_RENDER(WINED3DRS_SUBPIXELX), state_subpixelx }, + { /* 33, WINED3DRS_STIPPLEDALPHA */ STATE_RENDER(WINED3DRS_STIPPLEDALPHA), state_stippledalpha }, + { /* 34, WINED3DRS_FOGCOLOR */ STATE_RENDER(WINED3DRS_FOGCOLOR), state_fogcolor }, + { /* 35, WINED3DRS_FOGTABLEMODE */ STATE_RENDER(WINED3DRS_FOGENABLE), state_fog }, + { /* 36, WINED3DRS_FOGSTART */ STATE_RENDER(WINED3DRS_FOGENABLE), state_fog }, + { /* 37, WINED3DRS_FOGEND */ STATE_RENDER(WINED3DRS_FOGENABLE), state_fog }, + { /* 38, WINED3DRS_FOGDENSITY */ STATE_RENDER(WINED3DRS_FOGDENSITY), state_fogdensity }, + { /* 39, WINED3DRS_STIPPLEENABLE */ STATE_RENDER(WINED3DRS_STIPPLEENABLE), state_stippleenable }, + { /* 40, WINED3DRS_EDGEANTIALIAS */ STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_blend }, + { /* 41, WINED3DRS_COLORKEYENABLE */ STATE_RENDER(WINED3DRS_ALPHATESTENABLE), state_alpha }, + { /* 42, undefined */ 0, state_undefined }, + { /* 43, WINED3DRS_BORDERCOLOR */ STATE_RENDER(WINED3DRS_BORDERCOLOR), state_bordercolor }, + { /* 44, WINED3DRS_TEXTUREADDRESSU */ 0, /* Handled in ddraw */ state_undefined }, + { /* 45, WINED3DRS_TEXTUREADDRESSV */ 0, /* Handled in ddraw */ state_undefined }, + { /* 46, WINED3DRS_MIPMAPLODBIAS */ STATE_RENDER(WINED3DRS_MIPMAPLODBIAS), state_mipmaplodbias }, + { /* 47, WINED3DRS_ZBIAS */ STATE_RENDER(WINED3DRS_ZBIAS), state_zbias }, + { /* 48, WINED3DRS_RANGEFOGENABLE */ 0, state_nogl }, + { /* 49, WINED3DRS_ANISOTROPY */ STATE_RENDER(WINED3DRS_ANISOTROPY), state_anisotropy }, + { /* 50, WINED3DRS_FLUSHBATCH */ STATE_RENDER(WINED3DRS_FLUSHBATCH), state_flushbatch }, + { /* 51, WINED3DRS_TRANSLUCENTSORTINDEPENDENT */ STATE_RENDER(WINED3DRS_TRANSLUCENTSORTINDEPENDENT), state_translucentsi }, + { /* 52, WINED3DRS_STENCILENABLE */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 53, WINED3DRS_STENCILFAIL */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 54, WINED3DRS_STENCILZFAIL */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 55, WINED3DRS_STENCILPASS */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 56, WINED3DRS_STENCILFUNC */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 57, WINED3DRS_STENCILREF */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 58, WINED3DRS_STENCILMASK */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /* 59, WINED3DRS_STENCILWRITEMASK */ STATE_RENDER(WINED3DRS_STENCILWRITEMASK), state_stencilwrite }, + { /* 60, WINED3DRS_TEXTUREFACTOR */ STATE_RENDER(WINED3DRS_TEXTUREFACTOR), state_texfactor }, + { /* 61, Undefined */ 0, state_undefined }, + { /* 62, Undefined */ 0, state_undefined }, + { /* 63, Undefined */ 0, state_undefined }, + { /* 64, WINED3DRS_STIPPLEPATTERN00 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 65, WINED3DRS_STIPPLEPATTERN01 */ 0 /* Obsolete, should he handled by ddraw */, state_undefined }, + { /* 66, WINED3DRS_STIPPLEPATTERN02 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 67, WINED3DRS_STIPPLEPATTERN03 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 68, WINED3DRS_STIPPLEPATTERN04 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 69, WINED3DRS_STIPPLEPATTERN05 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 70, WINED3DRS_STIPPLEPATTERN06 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 71, WINED3DRS_STIPPLEPATTERN07 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 72, WINED3DRS_STIPPLEPATTERN08 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 73, WINED3DRS_STIPPLEPATTERN09 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 74, WINED3DRS_STIPPLEPATTERN10 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 75, WINED3DRS_STIPPLEPATTERN11 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 76, WINED3DRS_STIPPLEPATTERN12 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 77, WINED3DRS_STIPPLEPATTERN13 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 78, WINED3DRS_STIPPLEPATTERN14 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 79, WINED3DRS_STIPPLEPATTERN15 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 80, WINED3DRS_STIPPLEPATTERN16 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 81, WINED3DRS_STIPPLEPATTERN17 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 82, WINED3DRS_STIPPLEPATTERN18 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 83, WINED3DRS_STIPPLEPATTERN19 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 84, WINED3DRS_STIPPLEPATTERN20 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 85, WINED3DRS_STIPPLEPATTERN21 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 86, WINED3DRS_STIPPLEPATTERN22 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 87, WINED3DRS_STIPPLEPATTERN23 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 88, WINED3DRS_STIPPLEPATTERN24 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 89, WINED3DRS_STIPPLEPATTERN25 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 90, WINED3DRS_STIPPLEPATTERN26 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 91, WINED3DRS_STIPPLEPATTERN27 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 92, WINED3DRS_STIPPLEPATTERN28 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 93, WINED3DRS_STIPPLEPATTERN29 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 94, WINED3DRS_STIPPLEPATTERN30 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 95, WINED3DRS_STIPPLEPATTERN31 */ 0 /* Obsolete, should be handled by ddraw */, state_undefined }, + { /* 96, Undefined */ 0, state_undefined }, + { /* 97, Undefined */ 0, state_undefined }, + { /* 98, Undefined */ 0, state_undefined }, + { /* 99, Undefined */ 0, state_undefined }, + { /*100, Undefined */ 0, state_undefined }, + { /*101, Undefined */ 0, state_undefined }, + { /*102, Undefined */ 0, state_undefined }, + { /*103, Undefined */ 0, state_undefined }, + { /*104, Undefined */ 0, state_undefined }, + { /*105, Undefined */ 0, state_undefined }, + { /*106, Undefined */ 0, state_undefined }, + { /*107, Undefined */ 0, state_undefined }, + { /*108, Undefined */ 0, state_undefined }, + { /*109, Undefined */ 0, state_undefined }, + { /*110, Undefined */ 0, state_undefined }, + { /*111, Undefined */ 0, state_undefined }, + { /*112, Undefined */ 0, state_undefined }, + { /*113, Undefined */ 0, state_undefined }, + { /*114, Undefined */ 0, state_undefined }, + { /*115, Undefined */ 0, state_undefined }, + { /*116, Undefined */ 0, state_undefined }, + { /*117, Undefined */ 0, state_undefined }, + { /*118, Undefined */ 0, state_undefined }, + { /*119, Undefined */ 0, state_undefined }, + { /*120, Undefined */ 0, state_undefined }, + { /*121, Undefined */ 0, state_undefined }, + { /*122, Undefined */ 0, state_undefined }, + { /*123, Undefined */ 0, state_undefined }, + { /*124, Undefined */ 0, state_undefined }, + { /*125, Undefined */ 0, state_undefined }, + { /*126, Undefined */ 0, state_undefined }, + { /*127, Undefined */ 0, state_undefined }, + /* Big hole ends */ + { /*128, WINED3DRS_WRAP0 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*129, WINED3DRS_WRAP1 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*130, WINED3DRS_WRAP2 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*131, WINED3DRS_WRAP3 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*132, WINED3DRS_WRAP4 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*133, WINED3DRS_WRAP5 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*134, WINED3DRS_WRAP6 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*135, WINED3DRS_WRAP7 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*136, WINED3DRS_CLIPPING */ STATE_RENDER(WINED3DRS_CLIPPING), state_clipping }, + { /*137, WINED3DRS_LIGHTING */ STATE_RENDER(WINED3DRS_LIGHTING), state_lighting }, + { /*138, WINED3DRS_EXTENTS */ STATE_RENDER(WINED3DRS_EXTENTS), state_extents }, + { /*139, WINED3DRS_AMBIENT */ STATE_RENDER(WINED3DRS_AMBIENT), state_ambient }, + { /*140, WINED3DRS_FOGVERTEXMODE */ STATE_RENDER(WINED3DRS_FOGENABLE), state_fog }, + { /*141, WINED3DRS_COLORVERTEX */ STATE_RENDER(WINED3DRS_COLORVERTEX), state_colormat }, + { /*142, WINED3DRS_LOCALVIEWER */ STATE_RENDER(WINED3DRS_LOCALVIEWER), state_localviewer }, + { /*143, WINED3DRS_NORMALIZENORMALS */ STATE_RENDER(WINED3DRS_NORMALIZENORMALS), state_normalize }, + { /*144, WINED3DRS_COLORKEYBLENDENABLE */ STATE_RENDER(WINED3DRS_COLORKEYBLENDENABLE), state_ckeyblend }, + { /*145, WINED3DRS_DIFFUSEMATERIALSOURCE */ STATE_RENDER(WINED3DRS_COLORVERTEX), state_colormat }, + { /*146, WINED3DRS_SPECULARMATERIALSOURCE */ STATE_RENDER(WINED3DRS_COLORVERTEX), state_colormat }, + { /*147, WINED3DRS_AMBIENTMATERIALSOURCE */ STATE_RENDER(WINED3DRS_COLORVERTEX), state_colormat }, + { /*148, WINED3DRS_EMISSIVEMATERIALSOURCE */ STATE_RENDER(WINED3DRS_COLORVERTEX), state_colormat }, + { /*149, Undefined */ 0, state_undefined }, + { /*150, Undefined */ 0, state_undefined }, + { /*151, WINED3DRS_VERTEXBLEND */ STATE_RENDER(WINED3DRS_VERTEXBLEND), state_vertexblend }, + { /*152, WINED3DRS_CLIPPLANEENABLE */ STATE_RENDER(WINED3DRS_CLIPPING), state_clipping }, + { /*153, WINED3DRS_SOFTWAREVERTEXPROCESSING */ 0, state_nogl }, + { /*154, WINED3DRS_POINTSIZE */ STATE_RENDER(WINED3DRS_POINTSIZE), state_psize }, + { /*155, WINED3DRS_POINTSIZE_MIN */ STATE_RENDER(WINED3DRS_POINTSIZE_MIN), state_psizemin }, + { /*156, WINED3DRS_POINTSPRITEENABLE */ STATE_RENDER(WINED3DRS_POINTSPRITEENABLE), state_pointsprite }, + { /*157, WINED3DRS_POINTSCALEENABLE */ STATE_RENDER(WINED3DRS_POINTSCALEENABLE), state_pscale }, + { /*158, WINED3DRS_POINTSCALE_A */ STATE_RENDER(WINED3DRS_POINTSCALEENABLE), state_pscale }, + { /*159, WINED3DRS_POINTSCALE_B */ STATE_RENDER(WINED3DRS_POINTSCALEENABLE), state_pscale }, + { /*160, WINED3DRS_POINTSCALE_C */ STATE_RENDER(WINED3DRS_POINTSCALEENABLE), state_pscale }, + { /*161, WINED3DRS_MULTISAMPLEANTIALIAS */ STATE_RENDER(WINED3DRS_MULTISAMPLEANTIALIAS), state_multisampleaa }, + { /*162, WINED3DRS_MULTISAMPLEMASK */ STATE_RENDER(WINED3DRS_MULTISAMPLEMASK), state_multisampmask }, + { /*163, WINED3DRS_PATCHEDGESTYLE */ STATE_RENDER(WINED3DRS_PATCHEDGESTYLE), state_patchedgestyle}, + { /*164, WINED3DRS_PATCHSEGMENTS */ STATE_RENDER(WINED3DRS_PATCHSEGMENTS), state_patchsegments }, + { /*165, WINED3DRS_DEBUGMONITORTOKEN */ STATE_RENDER(WINED3DRS_DEBUGMONITORTOKEN), state_nogl }, + { /*166, WINED3DRS_POINTSIZE_MAX */ STATE_RENDER(WINED3DRS_POINTSIZE_MAX), state_psizemax }, + { /*167, WINED3DRS_INDEXEDVERTEXBLENDENABLE */ 0, state_nogl }, + { /*168, WINED3DRS_COLORWRITEENABLE */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite }, + { /*169, Undefined */ 0, state_undefined }, + { /*170, WINED3DRS_TWEENFACTOR */ 0, state_nogl }, + { /*171, WINED3DRS_BLENDOP */ STATE_RENDER(WINED3DRS_BLENDOP), state_blendop }, + { /*172, WINED3DRS_POSITIONDEGREE */ STATE_RENDER(WINED3DRS_POSITIONDEGREE), state_positiondegree}, + { /*173, WINED3DRS_NORMALDEGREE */ STATE_RENDER(WINED3DRS_NORMALDEGREE), state_normaldegree }, + /*172, WINED3DRS_POSITIONORDER */ /* Value assigned to 2 state names */ + /*173, WINED3DRS_NORMALORDER */ /* Value assigned to 2 state names */ + { /*174, WINED3DRS_SCISSORTESTENABLE */ STATE_RENDER(WINED3DRS_SCISSORTESTENABLE), state_scissor }, + { /*175, WINED3DRS_SLOPESCALEDEPTHBIAS */ STATE_RENDER(WINED3DRS_DEPTHBIAS), state_depthbias }, + { /*176, WINED3DRS_ANTIALIASEDLINEENABLE */ STATE_RENDER(WINED3DRS_ALPHABLENDENABLE), state_blend }, + { /*177, undefined */ 0, state_undefined }, + { /*178, WINED3DRS_MINTESSELLATIONLEVEL */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*179, WINED3DRS_MAXTESSELLATIONLEVEL */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*180, WINED3DRS_ADAPTIVETESS_X */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*181, WINED3DRS_ADAPTIVETESS_Y */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*182, WINED3DRS_ADAPTIVETESS_Z */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*183, WINED3DRS_ADAPTIVETESS_W */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*184, WINED3DRS_ENABLEADAPTIVETESSELLATION */ STATE_RENDER(WINED3DRS_ENABLEADAPTIVETESSELLATION), state_tessellation }, + { /*185, WINED3DRS_TWOSIDEDSTENCILMODE */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /*186, WINED3DRS_CCW_STENCILFAIL */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /*187, WINED3DRS_CCW_STENCILZFAIL */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /*188, WINED3DRS_CCW_STENCILPASS */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /*189, WINED3DRS_CCW_STENCILFUNC */ STATE_RENDER(WINED3DRS_STENCILENABLE), state_stencil }, + { /*190, WINED3DRS_COLORWRITEENABLE1 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite }, + { /*191, WINED3DRS_COLORWRITEENABLE2 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite }, + { /*192, WINED3DRS_COLORWRITEENABLE3 */ STATE_RENDER(WINED3DRS_COLORWRITEENABLE), state_colorwrite }, + { /*193, WINED3DRS_BLENDFACTOR */ STATE_RENDER(WINED3DRS_BLENDFACTOR), state_blendfactor }, + { /*194, WINED3DRS_SRGBWRITEENABLE */ STATE_RENDER(WINED3DRS_SRGBWRITEENABLE), state_srgbwrite }, + { /*195, WINED3DRS_DEPTHBIAS */ STATE_RENDER(WINED3DRS_DEPTHBIAS), state_depthbias }, + { /*196, undefined */ 0, state_undefined }, + { /*197, undefined */ 0, state_undefined }, + { /*198, WINED3DRS_WRAP8 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*199, WINED3DRS_WRAP9 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*200, WINED3DRS_WRAP10 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*201, WINED3DRS_WRAP11 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*202, WINED3DRS_WRAP12 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*203, WINED3DRS_WRAP13 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*204, WINED3DRS_WRAP14 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*205, WINED3DRS_WRAP15 */ STATE_RENDER(WINED3DRS_WRAP0), state_wrap }, + { /*206, WINED3DRS_SEPARATEALPHABLENDENABLE */ STATE_RENDER(WINED3DRS_SEPARATEALPHABLENDENABLE), state_separateblend }, + { /*207, WINED3DRS_SRCBLENDALPHA */ STATE_RENDER(WINED3DRS_SEPARATEALPHABLENDENABLE), state_separateblend }, + { /*208, WINED3DRS_DESTBLENDALPHA */ STATE_RENDER(WINED3DRS_SEPARATEALPHABLENDENABLE), state_separateblend }, + { /*209, WINED3DRS_BLENDOPALPHA */ STATE_RENDER(WINED3DRS_SEPARATEALPHABLENDENABLE), state_separateblend }, + /* Texture stage states */ + { /*0, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), tex_colorop }, + { /*0, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), tex_colorop }, + { /*0, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), tex_colorop }, + { /*0, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*0, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*0, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*0, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*0, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*0, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*0, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*0, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(0, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*0, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*0, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*0, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE0), transform_texture }, + { /*0, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP), tex_colorop }, + { /*0, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*0, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(0, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*0, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*0, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*1, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP), tex_colorop }, + { /*1, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP), tex_colorop }, + { /*1, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP), tex_colorop }, + { /*1, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*1, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*1, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*1, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*1, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*1, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*1, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*1, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(1, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*1, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*1, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*1, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE1), transform_texture }, + { /*1, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP), tex_colorop }, + { /*1, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*1, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(1, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*1, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*1, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*2, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP), tex_colorop }, + { /*2, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP), tex_colorop }, + { /*2, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP), tex_colorop }, + { /*2, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*2, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*2, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*2, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*2, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*2, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*2, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*2, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(2, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*2, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*2, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*2, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE2), transform_texture }, + { /*2, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP), tex_colorop }, + { /*2, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*2, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(2, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*2, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*2, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*3, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP), tex_colorop }, + { /*3, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP), tex_colorop }, + { /*3, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP), tex_colorop }, + { /*3, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*3, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*3, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*3, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*3, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*3, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*3, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*3, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(3, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*3, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*3, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*3, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE3), transform_texture }, + { /*3, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP), tex_colorop }, + { /*3, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*3, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(3, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*3, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*3, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*4, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP), tex_colorop }, + { /*4, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP), tex_colorop }, + { /*4, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP), tex_colorop }, + { /*4, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*4, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*4, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*4, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*4, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*4, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*4, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*4, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(4, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*4, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*4, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*4, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE4), transform_texture }, + { /*4, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP), tex_colorop }, + { /*4, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*4, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(4, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*4, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*4, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*5, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP), tex_colorop }, + { /*5, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP), tex_colorop }, + { /*5, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP), tex_colorop }, + { /*5, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*5, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*5, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*5, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*5, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*5, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*5, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*5, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(5, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*5, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*5, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*5, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE5), transform_texture }, + { /*5, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP), tex_colorop }, + { /*5, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*5, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(5, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*5, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*5, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*6, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP), tex_colorop }, + { /*6, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP), tex_colorop }, + { /*6, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP), tex_colorop }, + { /*6, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*6, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*6, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*6, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*6, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*6, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*6, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*6, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(6, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*6, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*6, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*6, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE6), transform_texture }, + { /*6, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP), tex_colorop }, + { /*6, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*6, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(6, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*6, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*6, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + + { /*7, 01, WINED3DTSS_COLOROP */ STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP), tex_colorop }, + { /*7, 02, WINED3DTSS_COLORARG1 */ STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP), tex_colorop }, + { /*7, 03, WINED3DTSS_COLORARG2 */ STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP), tex_colorop }, + { /*7, 04, WINED3DTSS_ALPHAOP */ STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*7, 05, WINED3DTSS_ALPHAARG1 */ STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*7, 06, WINED3DTSS_ALPHAARG2 */ STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*7, 07, WINED3DTSS_BUMPENVMAT00 */ STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*7, 08, WINED3DTSS_BUMPENVMAT01 */ STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*7, 09, WINED3DTSS_BUMPENVMAT10 */ STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*7, 10, WINED3DTSS_BUMPENVMAT11 */ STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00), tex_bumpenvmat }, + { /*7, 11, WINED3DTSS_TEXCOORDINDEX */ STATE_TEXTURESTAGE(7, WINED3DTSS_TEXCOORDINDEX), tex_coordindex }, + { /*7, 12, WINED3DTSS_ADDRESS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 13, WINED3DTSS_ADDRESSU */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 14, WINED3DTSS_ADDRESSV */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 15, WINED3DTSS_BORDERCOLOR */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 16, WINED3DTSS_MAGFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 17, WINED3DTSS_MINFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 18, WINED3DTSS_MIPFILTER */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 19, WINED3DTSS_MIPMAPLODBIAS */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 20, WINED3DTSS_MAXMIPLEVEL */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 21, WINED3DTSS_MAXANISOTROPY */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 22, WINED3DTSS_BUMPENVLSCALE */ STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVLSCALE), tex_bumpenvlscale }, + { /*7, 23, WINED3DTSS_BUMPENVLOFFSET */ STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVLOFFSET), tex_bumpenvloffset }, + { /*7, 24, WINED3DTSS_TEXTURETRANSFORMFLAGS */ STATE_TRANSFORM(WINED3DTS_TEXTURE7), transform_texture }, + { /*7, 25, WINED3DTSS_ADDRESSW */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 26, WINED3DTSS_COLORARG0 */ STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP), tex_colorop }, + { /*7, 27, WINED3DTSS_ALPHAARG0 */ STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP), tex_alphaop }, + { /*7, 28, WINED3DTSS_RESULTARG */ STATE_TEXTURESTAGE(7, WINED3DTSS_RESULTARG), tex_resultarg }, + { /*7, 29, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 30, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 31, undefined */ 0 /* -> sampler state in ddraw / d3d8 */, state_undefined }, + { /*7, 32, WINED3DTSS_CONSTANT */ 0 /* As long as we don't support D3DTA_CONSTANT */, state_nogl }, + /* Sampler states */ + { /* 0, Sampler 0 */ STATE_SAMPLER(0), sampler }, + { /* 1, Sampler 1 */ STATE_SAMPLER(1), sampler }, + { /* 2, Sampler 2 */ STATE_SAMPLER(2), sampler }, + { /* 3, Sampler 3 */ STATE_SAMPLER(3), sampler }, + { /* 4, Sampler 3 */ STATE_SAMPLER(4), sampler }, + { /* 5, Sampler 5 */ STATE_SAMPLER(5), sampler }, + { /* 6, Sampler 6 */ STATE_SAMPLER(6), sampler }, + { /* 7, Sampler 7 */ STATE_SAMPLER(7), sampler }, + { /* 8, Sampler 8 */ STATE_SAMPLER(8), sampler }, + { /* 9, Sampler 9 */ STATE_SAMPLER(9), sampler }, + { /*10, Sampler 10 */ STATE_SAMPLER(10), sampler }, + { /*11, Sampler 11 */ STATE_SAMPLER(11), sampler }, + { /*12, Sampler 12 */ STATE_SAMPLER(12), sampler }, + { /*13, Sampler 13 */ STATE_SAMPLER(13), sampler }, + { /*14, Sampler 14 */ STATE_SAMPLER(14), sampler }, + { /*15, Sampler 15 */ STATE_SAMPLER(15), sampler }, + { /*16, Vertex sampler 0 */ STATE_SAMPLER(16), sampler }, + { /*17, Vertex sampler 1 */ STATE_SAMPLER(17), sampler }, + { /*18, Vertex sampler 2 */ STATE_SAMPLER(18), sampler }, + { /*19, Vertex sampler 3 */ STATE_SAMPLER(19), sampler }, + /* Pixel shader */ + { /* , Pixel Shader */ STATE_PIXELSHADER, pixelshader }, + /* Transform states follow */ + { /* 1, undefined */ 0, state_undefined }, + { /* 2, WINED3DTS_VIEW */ STATE_TRANSFORM(WINED3DTS_VIEW), transform_view }, + { /* 3, WINED3DTS_PROJECTION */ STATE_TRANSFORM(WINED3DTS_PROJECTION), transform_projection}, + { /* 4, undefined */ 0, state_undefined }, + { /* 5, undefined */ 0, state_undefined }, + { /* 6, undefined */ 0, state_undefined }, + { /* 7, undefined */ 0, state_undefined }, + { /* 8, undefined */ 0, state_undefined }, + { /* 9, undefined */ 0, state_undefined }, + { /* 10, undefined */ 0, state_undefined }, + { /* 11, undefined */ 0, state_undefined }, + { /* 12, undefined */ 0, state_undefined }, + { /* 13, undefined */ 0, state_undefined }, + { /* 14, undefined */ 0, state_undefined }, + { /* 15, undefined */ 0, state_undefined }, + { /* 16, WINED3DTS_TEXTURE0 */ STATE_TRANSFORM(WINED3DTS_TEXTURE0), transform_texture }, + { /* 17, WINED3DTS_TEXTURE1 */ STATE_TRANSFORM(WINED3DTS_TEXTURE1), transform_texture }, + { /* 18, WINED3DTS_TEXTURE2 */ STATE_TRANSFORM(WINED3DTS_TEXTURE2), transform_texture }, + { /* 19, WINED3DTS_TEXTURE3 */ STATE_TRANSFORM(WINED3DTS_TEXTURE3), transform_texture }, + { /* 20, WINED3DTS_TEXTURE4 */ STATE_TRANSFORM(WINED3DTS_TEXTURE4), transform_texture }, + { /* 21, WINED3DTS_TEXTURE5 */ STATE_TRANSFORM(WINED3DTS_TEXTURE5), transform_texture }, + { /* 22, WINED3DTS_TEXTURE6 */ STATE_TRANSFORM(WINED3DTS_TEXTURE6), transform_texture }, + { /* 23, WINED3DTS_TEXTURE7 */ STATE_TRANSFORM(WINED3DTS_TEXTURE7), transform_texture }, + /* A huge gap between TEXTURE7 and WORLDMATRIX(0) :-( But entries are needed to catch then if a broken app sets them */ + { /* 24, undefined */ 0, state_undefined }, + { /* 25, undefined */ 0, state_undefined }, + { /* 26, undefined */ 0, state_undefined }, + { /* 27, undefined */ 0, state_undefined }, + { /* 28, undefined */ 0, state_undefined }, + { /* 29, undefined */ 0, state_undefined }, + { /* 30, undefined */ 0, state_undefined }, + { /* 31, undefined */ 0, state_undefined }, + { /* 32, undefined */ 0, state_undefined }, + { /* 33, undefined */ 0, state_undefined }, + { /* 34, undefined */ 0, state_undefined }, + { /* 35, undefined */ 0, state_undefined }, + { /* 36, undefined */ 0, state_undefined }, + { /* 37, undefined */ 0, state_undefined }, + { /* 38, undefined */ 0, state_undefined }, + { /* 39, undefined */ 0, state_undefined }, + { /* 40, undefined */ 0, state_undefined }, + { /* 41, undefined */ 0, state_undefined }, + { /* 42, undefined */ 0, state_undefined }, + { /* 43, undefined */ 0, state_undefined }, + { /* 44, undefined */ 0, state_undefined }, + { /* 45, undefined */ 0, state_undefined }, + { /* 46, undefined */ 0, state_undefined }, + { /* 47, undefined */ 0, state_undefined }, + { /* 48, undefined */ 0, state_undefined }, + { /* 49, undefined */ 0, state_undefined }, + { /* 50, undefined */ 0, state_undefined }, + { /* 51, undefined */ 0, state_undefined }, + { /* 52, undefined */ 0, state_undefined }, + { /* 53, undefined */ 0, state_undefined }, + { /* 54, undefined */ 0, state_undefined }, + { /* 55, undefined */ 0, state_undefined }, + { /* 56, undefined */ 0, state_undefined }, + { /* 57, undefined */ 0, state_undefined }, + { /* 58, undefined */ 0, state_undefined }, + { /* 59, undefined */ 0, state_undefined }, + { /* 60, undefined */ 0, state_undefined }, + { /* 61, undefined */ 0, state_undefined }, + { /* 62, undefined */ 0, state_undefined }, + { /* 63, undefined */ 0, state_undefined }, + { /* 64, undefined */ 0, state_undefined }, + { /* 65, undefined */ 0, state_undefined }, + { /* 66, undefined */ 0, state_undefined }, + { /* 67, undefined */ 0, state_undefined }, + { /* 68, undefined */ 0, state_undefined }, + { /* 69, undefined */ 0, state_undefined }, + { /* 70, undefined */ 0, state_undefined }, + { /* 71, undefined */ 0, state_undefined }, + { /* 72, undefined */ 0, state_undefined }, + { /* 73, undefined */ 0, state_undefined }, + { /* 74, undefined */ 0, state_undefined }, + { /* 75, undefined */ 0, state_undefined }, + { /* 76, undefined */ 0, state_undefined }, + { /* 77, undefined */ 0, state_undefined }, + { /* 78, undefined */ 0, state_undefined }, + { /* 79, undefined */ 0, state_undefined }, + { /* 80, undefined */ 0, state_undefined }, + { /* 81, undefined */ 0, state_undefined }, + { /* 82, undefined */ 0, state_undefined }, + { /* 83, undefined */ 0, state_undefined }, + { /* 84, undefined */ 0, state_undefined }, + { /* 85, undefined */ 0, state_undefined }, + { /* 86, undefined */ 0, state_undefined }, + { /* 87, undefined */ 0, state_undefined }, + { /* 88, undefined */ 0, state_undefined }, + { /* 89, undefined */ 0, state_undefined }, + { /* 90, undefined */ 0, state_undefined }, + { /* 91, undefined */ 0, state_undefined }, + { /* 92, undefined */ 0, state_undefined }, + { /* 93, undefined */ 0, state_undefined }, + { /* 94, undefined */ 0, state_undefined }, + { /* 95, undefined */ 0, state_undefined }, + { /* 96, undefined */ 0, state_undefined }, + { /* 97, undefined */ 0, state_undefined }, + { /* 98, undefined */ 0, state_undefined }, + { /* 99, undefined */ 0, state_undefined }, + { /*100, undefined */ 0, state_undefined }, + { /*101, undefined */ 0, state_undefined }, + { /*102, undefined */ 0, state_undefined }, + { /*103, undefined */ 0, state_undefined }, + { /*104, undefined */ 0, state_undefined }, + { /*105, undefined */ 0, state_undefined }, + { /*106, undefined */ 0, state_undefined }, + { /*107, undefined */ 0, state_undefined }, + { /*108, undefined */ 0, state_undefined }, + { /*109, undefined */ 0, state_undefined }, + { /*110, undefined */ 0, state_undefined }, + { /*111, undefined */ 0, state_undefined }, + { /*112, undefined */ 0, state_undefined }, + { /*113, undefined */ 0, state_undefined }, + { /*114, undefined */ 0, state_undefined }, + { /*115, undefined */ 0, state_undefined }, + { /*116, undefined */ 0, state_undefined }, + { /*117, undefined */ 0, state_undefined }, + { /*118, undefined */ 0, state_undefined }, + { /*119, undefined */ 0, state_undefined }, + { /*120, undefined */ 0, state_undefined }, + { /*121, undefined */ 0, state_undefined }, + { /*122, undefined */ 0, state_undefined }, + { /*123, undefined */ 0, state_undefined }, + { /*124, undefined */ 0, state_undefined }, + { /*125, undefined */ 0, state_undefined }, + { /*126, undefined */ 0, state_undefined }, + { /*127, undefined */ 0, state_undefined }, + { /*128, undefined */ 0, state_undefined }, + { /*129, undefined */ 0, state_undefined }, + { /*130, undefined */ 0, state_undefined }, + { /*131, undefined */ 0, state_undefined }, + { /*132, undefined */ 0, state_undefined }, + { /*133, undefined */ 0, state_undefined }, + { /*134, undefined */ 0, state_undefined }, + { /*135, undefined */ 0, state_undefined }, + { /*136, undefined */ 0, state_undefined }, + { /*137, undefined */ 0, state_undefined }, + { /*138, undefined */ 0, state_undefined }, + { /*139, undefined */ 0, state_undefined }, + { /*140, undefined */ 0, state_undefined }, + { /*141, undefined */ 0, state_undefined }, + { /*142, undefined */ 0, state_undefined }, + { /*143, undefined */ 0, state_undefined }, + { /*144, undefined */ 0, state_undefined }, + { /*145, undefined */ 0, state_undefined }, + { /*146, undefined */ 0, state_undefined }, + { /*147, undefined */ 0, state_undefined }, + { /*148, undefined */ 0, state_undefined }, + { /*149, undefined */ 0, state_undefined }, + { /*150, undefined */ 0, state_undefined }, + { /*151, undefined */ 0, state_undefined }, + { /*152, undefined */ 0, state_undefined }, + { /*153, undefined */ 0, state_undefined }, + { /*154, undefined */ 0, state_undefined }, + { /*155, undefined */ 0, state_undefined }, + { /*156, undefined */ 0, state_undefined }, + { /*157, undefined */ 0, state_undefined }, + { /*158, undefined */ 0, state_undefined }, + { /*159, undefined */ 0, state_undefined }, + { /*160, undefined */ 0, state_undefined }, + { /*161, undefined */ 0, state_undefined }, + { /*162, undefined */ 0, state_undefined }, + { /*163, undefined */ 0, state_undefined }, + { /*164, undefined */ 0, state_undefined }, + { /*165, undefined */ 0, state_undefined }, + { /*166, undefined */ 0, state_undefined }, + { /*167, undefined */ 0, state_undefined }, + { /*168, undefined */ 0, state_undefined }, + { /*169, undefined */ 0, state_undefined }, + { /*170, undefined */ 0, state_undefined }, + { /*171, undefined */ 0, state_undefined }, + { /*172, undefined */ 0, state_undefined }, + { /*173, undefined */ 0, state_undefined }, + { /*174, undefined */ 0, state_undefined }, + { /*175, undefined */ 0, state_undefined }, + { /*176, undefined */ 0, state_undefined }, + { /*177, undefined */ 0, state_undefined }, + { /*178, undefined */ 0, state_undefined }, + { /*179, undefined */ 0, state_undefined }, + { /*180, undefined */ 0, state_undefined }, + { /*181, undefined */ 0, state_undefined }, + { /*182, undefined */ 0, state_undefined }, + { /*183, undefined */ 0, state_undefined }, + { /*184, undefined */ 0, state_undefined }, + { /*185, undefined */ 0, state_undefined }, + { /*186, undefined */ 0, state_undefined }, + { /*187, undefined */ 0, state_undefined }, + { /*188, undefined */ 0, state_undefined }, + { /*189, undefined */ 0, state_undefined }, + { /*190, undefined */ 0, state_undefined }, + { /*191, undefined */ 0, state_undefined }, + { /*192, undefined */ 0, state_undefined }, + { /*193, undefined */ 0, state_undefined }, + { /*194, undefined */ 0, state_undefined }, + { /*195, undefined */ 0, state_undefined }, + { /*196, undefined */ 0, state_undefined }, + { /*197, undefined */ 0, state_undefined }, + { /*198, undefined */ 0, state_undefined }, + { /*199, undefined */ 0, state_undefined }, + { /*200, undefined */ 0, state_undefined }, + { /*201, undefined */ 0, state_undefined }, + { /*202, undefined */ 0, state_undefined }, + { /*203, undefined */ 0, state_undefined }, + { /*204, undefined */ 0, state_undefined }, + { /*205, undefined */ 0, state_undefined }, + { /*206, undefined */ 0, state_undefined }, + { /*207, undefined */ 0, state_undefined }, + { /*208, undefined */ 0, state_undefined }, + { /*209, undefined */ 0, state_undefined }, + { /*210, undefined */ 0, state_undefined }, + { /*211, undefined */ 0, state_undefined }, + { /*212, undefined */ 0, state_undefined }, + { /*213, undefined */ 0, state_undefined }, + { /*214, undefined */ 0, state_undefined }, + { /*215, undefined */ 0, state_undefined }, + { /*216, undefined */ 0, state_undefined }, + { /*217, undefined */ 0, state_undefined }, + { /*218, undefined */ 0, state_undefined }, + { /*219, undefined */ 0, state_undefined }, + { /*220, undefined */ 0, state_undefined }, + { /*221, undefined */ 0, state_undefined }, + { /*222, undefined */ 0, state_undefined }, + { /*223, undefined */ 0, state_undefined }, + { /*224, undefined */ 0, state_undefined }, + { /*225, undefined */ 0, state_undefined }, + { /*226, undefined */ 0, state_undefined }, + { /*227, undefined */ 0, state_undefined }, + { /*228, undefined */ 0, state_undefined }, + { /*229, undefined */ 0, state_undefined }, + { /*230, undefined */ 0, state_undefined }, + { /*231, undefined */ 0, state_undefined }, + { /*232, undefined */ 0, state_undefined }, + { /*233, undefined */ 0, state_undefined }, + { /*234, undefined */ 0, state_undefined }, + { /*235, undefined */ 0, state_undefined }, + { /*236, undefined */ 0, state_undefined }, + { /*237, undefined */ 0, state_undefined }, + { /*238, undefined */ 0, state_undefined }, + { /*239, undefined */ 0, state_undefined }, + { /*240, undefined */ 0, state_undefined }, + { /*241, undefined */ 0, state_undefined }, + { /*242, undefined */ 0, state_undefined }, + { /*243, undefined */ 0, state_undefined }, + { /*244, undefined */ 0, state_undefined }, + { /*245, undefined */ 0, state_undefined }, + { /*246, undefined */ 0, state_undefined }, + { /*247, undefined */ 0, state_undefined }, + { /*248, undefined */ 0, state_undefined }, + { /*249, undefined */ 0, state_undefined }, + { /*250, undefined */ 0, state_undefined }, + { /*251, undefined */ 0, state_undefined }, + { /*252, undefined */ 0, state_undefined }, + { /*253, undefined */ 0, state_undefined }, + { /*254, undefined */ 0, state_undefined }, + { /*255, undefined */ 0, state_undefined }, + /* End huge gap */ + { /*256, WINED3DTS_WORLDMATRIX(0) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), transform_world }, + { /*257, WINED3DTS_WORLDMATRIX(1) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(1)), transform_worldex }, + { /*258, WINED3DTS_WORLDMATRIX(2) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(2)), transform_worldex }, + { /*259, WINED3DTS_WORLDMATRIX(3) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(3)), transform_worldex }, + { /*260, WINED3DTS_WORLDMATRIX(4) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(4)), transform_worldex }, + { /*261, WINED3DTS_WORLDMATRIX(5) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(5)), transform_worldex }, + { /*262, WINED3DTS_WORLDMATRIX(6) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(6)), transform_worldex }, + { /*263, WINED3DTS_WORLDMATRIX(7) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(7)), transform_worldex }, + { /*264, WINED3DTS_WORLDMATRIX(8) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(8)), transform_worldex }, + { /*265, WINED3DTS_WORLDMATRIX(9) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(9)), transform_worldex }, + { /*266, WINED3DTS_WORLDMATRIX(10) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(10)), transform_worldex }, + { /*267, WINED3DTS_WORLDMATRIX(11) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(11)), transform_worldex }, + { /*268, WINED3DTS_WORLDMATRIX(12) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(12)), transform_worldex }, + { /*269, WINED3DTS_WORLDMATRIX(13) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(13)), transform_worldex }, + { /*270, WINED3DTS_WORLDMATRIX(14) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(14)), transform_worldex }, + { /*271, WINED3DTS_WORLDMATRIX(15) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(15)), transform_worldex }, + { /*272, WINED3DTS_WORLDMATRIX(16) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(16)), transform_worldex }, + { /*273, WINED3DTS_WORLDMATRIX(17) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(17)), transform_worldex }, + { /*274, WINED3DTS_WORLDMATRIX(18) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(18)), transform_worldex }, + { /*275, WINED3DTS_WORLDMATRIX(19) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(19)), transform_worldex }, + { /*276, WINED3DTS_WORLDMATRIX(20) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(20)), transform_worldex }, + { /*277, WINED3DTS_WORLDMATRIX(21) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(21)), transform_worldex }, + { /*278, WINED3DTS_WORLDMATRIX(22) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(22)), transform_worldex }, + { /*279, WINED3DTS_WORLDMATRIX(23) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(23)), transform_worldex }, + { /*280, WINED3DTS_WORLDMATRIX(24) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(24)), transform_worldex }, + { /*281, WINED3DTS_WORLDMATRIX(25) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(25)), transform_worldex }, + { /*282, WINED3DTS_WORLDMATRIX(26) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(26)), transform_worldex }, + { /*283, WINED3DTS_WORLDMATRIX(27) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(27)), transform_worldex }, + { /*284, WINED3DTS_WORLDMATRIX(28) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(28)), transform_worldex }, + { /*285, WINED3DTS_WORLDMATRIX(29) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(29)), transform_worldex }, + { /*286, WINED3DTS_WORLDMATRIX(30) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(30)), transform_worldex }, + { /*287, WINED3DTS_WORLDMATRIX(31) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(31)), transform_worldex }, + { /*288, WINED3DTS_WORLDMATRIX(32) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(32)), transform_worldex }, + { /*289, WINED3DTS_WORLDMATRIX(33) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(33)), transform_worldex }, + { /*290, WINED3DTS_WORLDMATRIX(34) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(34)), transform_worldex }, + { /*291, WINED3DTS_WORLDMATRIX(35) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(35)), transform_worldex }, + { /*292, WINED3DTS_WORLDMATRIX(36) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(36)), transform_worldex }, + { /*293, WINED3DTS_WORLDMATRIX(37) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(37)), transform_worldex }, + { /*294, WINED3DTS_WORLDMATRIX(38) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(38)), transform_worldex }, + { /*295, WINED3DTS_WORLDMATRIX(39) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(39)), transform_worldex }, + { /*296, WINED3DTS_WORLDMATRIX(40) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(40)), transform_worldex }, + { /*297, WINED3DTS_WORLDMATRIX(41) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(41)), transform_worldex }, + { /*298, WINED3DTS_WORLDMATRIX(42) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(42)), transform_worldex }, + { /*299, WINED3DTS_WORLDMATRIX(43) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(43)), transform_worldex }, + { /*300, WINED3DTS_WORLDMATRIX(44) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(44)), transform_worldex }, + { /*301, WINED3DTS_WORLDMATRIX(45) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(45)), transform_worldex }, + { /*302, WINED3DTS_WORLDMATRIX(46) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(46)), transform_worldex }, + { /*303, WINED3DTS_WORLDMATRIX(47) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(47)), transform_worldex }, + { /*304, WINED3DTS_WORLDMATRIX(48) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(48)), transform_worldex }, + { /*305, WINED3DTS_WORLDMATRIX(49) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(49)), transform_worldex }, + { /*306, WINED3DTS_WORLDMATRIX(50) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(50)), transform_worldex }, + { /*307, WINED3DTS_WORLDMATRIX(51) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(51)), transform_worldex }, + { /*308, WINED3DTS_WORLDMATRIX(52) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(52)), transform_worldex }, + { /*309, WINED3DTS_WORLDMATRIX(53) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(53)), transform_worldex }, + { /*310, WINED3DTS_WORLDMATRIX(54) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(54)), transform_worldex }, + { /*311, WINED3DTS_WORLDMATRIX(55) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(55)), transform_worldex }, + { /*312, WINED3DTS_WORLDMATRIX(56) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(56)), transform_worldex }, + { /*313, WINED3DTS_WORLDMATRIX(57) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(57)), transform_worldex }, + { /*314, WINED3DTS_WORLDMATRIX(58) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(58)), transform_worldex }, + { /*315, WINED3DTS_WORLDMATRIX(59) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(59)), transform_worldex }, + { /*316, WINED3DTS_WORLDMATRIX(60) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(60)), transform_worldex }, + { /*317, WINED3DTS_WORLDMATRIX(61) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(61)), transform_worldex }, + { /*318, WINED3DTS_WORLDMATRIX(62) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(62)), transform_worldex }, + { /*319, WINED3DTS_WORLDMATRIX(63) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(63)), transform_worldex }, + { /*320, WINED3DTS_WORLDMATRIX(64) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(64)), transform_worldex }, + { /*321, WINED3DTS_WORLDMATRIX(65) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(65)), transform_worldex }, + { /*322, WINED3DTS_WORLDMATRIX(66) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(66)), transform_worldex }, + { /*323, WINED3DTS_WORLDMATRIX(67) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(67)), transform_worldex }, + { /*324, WINED3DTS_WORLDMATRIX(68) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(68)), transform_worldex }, + { /*325, WINED3DTS_WORLDMATRIX(68) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(69)), transform_worldex }, + { /*326, WINED3DTS_WORLDMATRIX(70) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(70)), transform_worldex }, + { /*327, WINED3DTS_WORLDMATRIX(71) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(71)), transform_worldex }, + { /*328, WINED3DTS_WORLDMATRIX(72) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(72)), transform_worldex }, + { /*329, WINED3DTS_WORLDMATRIX(73) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(73)), transform_worldex }, + { /*330, WINED3DTS_WORLDMATRIX(74) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(74)), transform_worldex }, + { /*331, WINED3DTS_WORLDMATRIX(75) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(75)), transform_worldex }, + { /*332, WINED3DTS_WORLDMATRIX(76) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(76)), transform_worldex }, + { /*333, WINED3DTS_WORLDMATRIX(77) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(77)), transform_worldex }, + { /*334, WINED3DTS_WORLDMATRIX(78) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(78)), transform_worldex }, + { /*335, WINED3DTS_WORLDMATRIX(79) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(79)), transform_worldex }, + { /*336, WINED3DTS_WORLDMATRIX(80) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(80)), transform_worldex }, + { /*337, WINED3DTS_WORLDMATRIX(81) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(81)), transform_worldex }, + { /*338, WINED3DTS_WORLDMATRIX(82) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(82)), transform_worldex }, + { /*339, WINED3DTS_WORLDMATRIX(83) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(83)), transform_worldex }, + { /*340, WINED3DTS_WORLDMATRIX(84) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(84)), transform_worldex }, + { /*341, WINED3DTS_WORLDMATRIX(85) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(85)), transform_worldex }, + { /*341, WINED3DTS_WORLDMATRIX(86) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(86)), transform_worldex }, + { /*343, WINED3DTS_WORLDMATRIX(87) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(87)), transform_worldex }, + { /*344, WINED3DTS_WORLDMATRIX(88) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(88)), transform_worldex }, + { /*345, WINED3DTS_WORLDMATRIX(89) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(89)), transform_worldex }, + { /*346, WINED3DTS_WORLDMATRIX(90) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(90)), transform_worldex }, + { /*347, WINED3DTS_WORLDMATRIX(91) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(91)), transform_worldex }, + { /*348, WINED3DTS_WORLDMATRIX(92) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(92)), transform_worldex }, + { /*349, WINED3DTS_WORLDMATRIX(93) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(93)), transform_worldex }, + { /*350, WINED3DTS_WORLDMATRIX(94) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(94)), transform_worldex }, + { /*351, WINED3DTS_WORLDMATRIX(95) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(95)), transform_worldex }, + { /*352, WINED3DTS_WORLDMATRIX(96) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(96)), transform_worldex }, + { /*353, WINED3DTS_WORLDMATRIX(97) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(97)), transform_worldex }, + { /*354, WINED3DTS_WORLDMATRIX(98) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(98)), transform_worldex }, + { /*355, WINED3DTS_WORLDMATRIX(99) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(99)), transform_worldex }, + { /*356, WINED3DTS_WORLDMATRIX(100) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(100)), transform_worldex }, + { /*357, WINED3DTS_WORLDMATRIX(101) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(101)), transform_worldex }, + { /*358, WINED3DTS_WORLDMATRIX(102) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(102)), transform_worldex }, + { /*359, WINED3DTS_WORLDMATRIX(103) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(103)), transform_worldex }, + { /*360, WINED3DTS_WORLDMATRIX(104) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(104)), transform_worldex }, + { /*361, WINED3DTS_WORLDMATRIX(105) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(105)), transform_worldex }, + { /*362, WINED3DTS_WORLDMATRIX(106) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(106)), transform_worldex }, + { /*363, WINED3DTS_WORLDMATRIX(107) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(107)), transform_worldex }, + { /*364, WINED3DTS_WORLDMATRIX(108) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(108)), transform_worldex }, + { /*365, WINED3DTS_WORLDMATRIX(109) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(109)), transform_worldex }, + { /*366, WINED3DTS_WORLDMATRIX(110) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(110)), transform_worldex }, + { /*367, WINED3DTS_WORLDMATRIX(111) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(111)), transform_worldex }, + { /*368, WINED3DTS_WORLDMATRIX(112) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(112)), transform_worldex }, + { /*369, WINED3DTS_WORLDMATRIX(113) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(113)), transform_worldex }, + { /*370, WINED3DTS_WORLDMATRIX(114) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(114)), transform_worldex }, + { /*371, WINED3DTS_WORLDMATRIX(115) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(115)), transform_worldex }, + { /*372, WINED3DTS_WORLDMATRIX(116) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(116)), transform_worldex }, + { /*373, WINED3DTS_WORLDMATRIX(117) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(117)), transform_worldex }, + { /*374, WINED3DTS_WORLDMATRIX(118) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(118)), transform_worldex }, + { /*375, WINED3DTS_WORLDMATRIX(119) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(119)), transform_worldex }, + { /*376, WINED3DTS_WORLDMATRIX(120) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(120)), transform_worldex }, + { /*377, WINED3DTS_WORLDMATRIX(121) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(121)), transform_worldex }, + { /*378, WINED3DTS_WORLDMATRIX(122) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(122)), transform_worldex }, + { /*379, WINED3DTS_WORLDMATRIX(123) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(123)), transform_worldex }, + { /*380, WINED3DTS_WORLDMATRIX(124) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(124)), transform_worldex }, + { /*381, WINED3DTS_WORLDMATRIX(125) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(125)), transform_worldex }, + { /*382, WINED3DTS_WORLDMATRIX(126) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(126)), transform_worldex }, + { /*383, WINED3DTS_WORLDMATRIX(127) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(127)), transform_worldex }, + { /*384, WINED3DTS_WORLDMATRIX(128) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(128)), transform_worldex }, + { /*385, WINED3DTS_WORLDMATRIX(129) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(129)), transform_worldex }, + { /*386, WINED3DTS_WORLDMATRIX(130) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(130)), transform_worldex }, + { /*387, WINED3DTS_WORLDMATRIX(131) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(131)), transform_worldex }, + { /*388, WINED3DTS_WORLDMATRIX(132) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(132)), transform_worldex }, + { /*389, WINED3DTS_WORLDMATRIX(133) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(133)), transform_worldex }, + { /*390, WINED3DTS_WORLDMATRIX(134) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(134)), transform_worldex }, + { /*391, WINED3DTS_WORLDMATRIX(135) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(135)), transform_worldex }, + { /*392, WINED3DTS_WORLDMATRIX(136) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(136)), transform_worldex }, + { /*393, WINED3DTS_WORLDMATRIX(137) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(137)), transform_worldex }, + { /*394, WINED3DTS_WORLDMATRIX(138) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(138)), transform_worldex }, + { /*395, WINED3DTS_WORLDMATRIX(139) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(139)), transform_worldex }, + { /*396, WINED3DTS_WORLDMATRIX(140) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(140)), transform_worldex }, + { /*397, WINED3DTS_WORLDMATRIX(141) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(141)), transform_worldex }, + { /*398, WINED3DTS_WORLDMATRIX(142) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(142)), transform_worldex }, + { /*399, WINED3DTS_WORLDMATRIX(143) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(143)), transform_worldex }, + { /*400, WINED3DTS_WORLDMATRIX(144) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(144)), transform_worldex }, + { /*401, WINED3DTS_WORLDMATRIX(145) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(145)), transform_worldex }, + { /*402, WINED3DTS_WORLDMATRIX(146) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(146)), transform_worldex }, + { /*403, WINED3DTS_WORLDMATRIX(147) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(147)), transform_worldex }, + { /*404, WINED3DTS_WORLDMATRIX(148) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(148)), transform_worldex }, + { /*405, WINED3DTS_WORLDMATRIX(149) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(149)), transform_worldex }, + { /*406, WINED3DTS_WORLDMATRIX(150) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(150)), transform_worldex }, + { /*407, WINED3DTS_WORLDMATRIX(151) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(151)), transform_worldex }, + { /*408, WINED3DTS_WORLDMATRIX(152) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(152)), transform_worldex }, + { /*409, WINED3DTS_WORLDMATRIX(153) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(153)), transform_worldex }, + { /*410, WINED3DTS_WORLDMATRIX(154) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(154)), transform_worldex }, + { /*411, WINED3DTS_WORLDMATRIX(155) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(155)), transform_worldex }, + { /*412, WINED3DTS_WORLDMATRIX(156) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(156)), transform_worldex }, + { /*413, WINED3DTS_WORLDMATRIX(157) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(157)), transform_worldex }, + { /*414, WINED3DTS_WORLDMATRIX(158) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(158)), transform_worldex }, + { /*415, WINED3DTS_WORLDMATRIX(159) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(159)), transform_worldex }, + { /*416, WINED3DTS_WORLDMATRIX(160) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(160)), transform_worldex }, + { /*417, WINED3DTS_WORLDMATRIX(161) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(161)), transform_worldex }, + { /*418, WINED3DTS_WORLDMATRIX(162) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(162)), transform_worldex }, + { /*419, WINED3DTS_WORLDMATRIX(163) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(163)), transform_worldex }, + { /*420, WINED3DTS_WORLDMATRIX(164) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(164)), transform_worldex }, + { /*421, WINED3DTS_WORLDMATRIX(165) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(165)), transform_worldex }, + { /*422, WINED3DTS_WORLDMATRIX(166) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(166)), transform_worldex }, + { /*423, WINED3DTS_WORLDMATRIX(167) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(167)), transform_worldex }, + { /*424, WINED3DTS_WORLDMATRIX(168) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(168)), transform_worldex }, + { /*425, WINED3DTS_WORLDMATRIX(168) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(169)), transform_worldex }, + { /*426, WINED3DTS_WORLDMATRIX(170) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(170)), transform_worldex }, + { /*427, WINED3DTS_WORLDMATRIX(171) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(171)), transform_worldex }, + { /*428, WINED3DTS_WORLDMATRIX(172) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(172)), transform_worldex }, + { /*429, WINED3DTS_WORLDMATRIX(173) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(173)), transform_worldex }, + { /*430, WINED3DTS_WORLDMATRIX(174) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(174)), transform_worldex }, + { /*431, WINED3DTS_WORLDMATRIX(175) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(175)), transform_worldex }, + { /*432, WINED3DTS_WORLDMATRIX(176) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(176)), transform_worldex }, + { /*433, WINED3DTS_WORLDMATRIX(177) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(177)), transform_worldex }, + { /*434, WINED3DTS_WORLDMATRIX(178) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(178)), transform_worldex }, + { /*435, WINED3DTS_WORLDMATRIX(179) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(179)), transform_worldex }, + { /*436, WINED3DTS_WORLDMATRIX(180) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(180)), transform_worldex }, + { /*437, WINED3DTS_WORLDMATRIX(181) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(181)), transform_worldex }, + { /*438, WINED3DTS_WORLDMATRIX(182) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(182)), transform_worldex }, + { /*439, WINED3DTS_WORLDMATRIX(183) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(183)), transform_worldex }, + { /*440, WINED3DTS_WORLDMATRIX(184) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(184)), transform_worldex }, + { /*441, WINED3DTS_WORLDMATRIX(185) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(185)), transform_worldex }, + { /*441, WINED3DTS_WORLDMATRIX(186) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(186)), transform_worldex }, + { /*443, WINED3DTS_WORLDMATRIX(187) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(187)), transform_worldex }, + { /*444, WINED3DTS_WORLDMATRIX(188) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(188)), transform_worldex }, + { /*445, WINED3DTS_WORLDMATRIX(189) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(189)), transform_worldex }, + { /*446, WINED3DTS_WORLDMATRIX(190) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(190)), transform_worldex }, + { /*447, WINED3DTS_WORLDMATRIX(191) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(191)), transform_worldex }, + { /*448, WINED3DTS_WORLDMATRIX(192) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(192)), transform_worldex }, + { /*449, WINED3DTS_WORLDMATRIX(193) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(193)), transform_worldex }, + { /*450, WINED3DTS_WORLDMATRIX(194) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(194)), transform_worldex }, + { /*451, WINED3DTS_WORLDMATRIX(195) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(195)), transform_worldex }, + { /*452, WINED3DTS_WORLDMATRIX(196) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(196)), transform_worldex }, + { /*453, WINED3DTS_WORLDMATRIX(197) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(197)), transform_worldex }, + { /*454, WINED3DTS_WORLDMATRIX(198) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(198)), transform_worldex }, + { /*455, WINED3DTS_WORLDMATRIX(199) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(199)), transform_worldex }, + { /*356, WINED3DTS_WORLDMATRIX(200) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(200)), transform_worldex }, + { /*457, WINED3DTS_WORLDMATRIX(201) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(201)), transform_worldex }, + { /*458, WINED3DTS_WORLDMATRIX(202) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(202)), transform_worldex }, + { /*459, WINED3DTS_WORLDMATRIX(203) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(203)), transform_worldex }, + { /*460, WINED3DTS_WORLDMATRIX(204) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(204)), transform_worldex }, + { /*461, WINED3DTS_WORLDMATRIX(205) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(205)), transform_worldex }, + { /*462, WINED3DTS_WORLDMATRIX(206) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(206)), transform_worldex }, + { /*463, WINED3DTS_WORLDMATRIX(207) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(207)), transform_worldex }, + { /*464, WINED3DTS_WORLDMATRIX(208) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(208)), transform_worldex }, + { /*465, WINED3DTS_WORLDMATRIX(209) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(209)), transform_worldex }, + { /*466, WINED3DTS_WORLDMATRIX(210) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(210)), transform_worldex }, + { /*467, WINED3DTS_WORLDMATRIX(211) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(211)), transform_worldex }, + { /*468, WINED3DTS_WORLDMATRIX(212) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(212)), transform_worldex }, + { /*469, WINED3DTS_WORLDMATRIX(213) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(213)), transform_worldex }, + { /*470, WINED3DTS_WORLDMATRIX(214) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(214)), transform_worldex }, + { /*471, WINED3DTS_WORLDMATRIX(215) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(215)), transform_worldex }, + { /*472, WINED3DTS_WORLDMATRIX(216) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(216)), transform_worldex }, + { /*473, WINED3DTS_WORLDMATRIX(217) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(217)), transform_worldex }, + { /*474, WINED3DTS_WORLDMATRIX(218) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(218)), transform_worldex }, + { /*475, WINED3DTS_WORLDMATRIX(219) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(219)), transform_worldex }, + { /*476, WINED3DTS_WORLDMATRIX(220) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(220)), transform_worldex }, + { /*477, WINED3DTS_WORLDMATRIX(221) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(221)), transform_worldex }, + { /*478, WINED3DTS_WORLDMATRIX(222) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(222)), transform_worldex }, + { /*479, WINED3DTS_WORLDMATRIX(223) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(223)), transform_worldex }, + { /*480, WINED3DTS_WORLDMATRIX(224) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(224)), transform_worldex }, + { /*481, WINED3DTS_WORLDMATRIX(225) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(225)), transform_worldex }, + { /*482, WINED3DTS_WORLDMATRIX(226) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(226)), transform_worldex }, + { /*483, WINED3DTS_WORLDMATRIX(227) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(227)), transform_worldex }, + { /*484, WINED3DTS_WORLDMATRIX(228) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(228)), transform_worldex }, + { /*485, WINED3DTS_WORLDMATRIX(229) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(229)), transform_worldex }, + { /*486, WINED3DTS_WORLDMATRIX(230) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(230)), transform_worldex }, + { /*487, WINED3DTS_WORLDMATRIX(231) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(231)), transform_worldex }, + { /*488, WINED3DTS_WORLDMATRIX(232) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(232)), transform_worldex }, + { /*489, WINED3DTS_WORLDMATRIX(233) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(233)), transform_worldex }, + { /*490, WINED3DTS_WORLDMATRIX(234) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(234)), transform_worldex }, + { /*491, WINED3DTS_WORLDMATRIX(235) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(235)), transform_worldex }, + { /*492, WINED3DTS_WORLDMATRIX(236) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(236)), transform_worldex }, + { /*493, WINED3DTS_WORLDMATRIX(237) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(237)), transform_worldex }, + { /*494, WINED3DTS_WORLDMATRIX(238) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(238)), transform_worldex }, + { /*495, WINED3DTS_WORLDMATRIX(239) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(239)), transform_worldex }, + { /*496, WINED3DTS_WORLDMATRIX(240) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(240)), transform_worldex }, + { /*497, WINED3DTS_WORLDMATRIX(241) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(241)), transform_worldex }, + { /*498, WINED3DTS_WORLDMATRIX(242) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(242)), transform_worldex }, + { /*499, WINED3DTS_WORLDMATRIX(243) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(243)), transform_worldex }, + { /*500, WINED3DTS_WORLDMATRIX(244) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(244)), transform_worldex }, + { /*501, WINED3DTS_WORLDMATRIX(245) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(245)), transform_worldex }, + { /*502, WINED3DTS_WORLDMATRIX(246) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(246)), transform_worldex }, + { /*503, WINED3DTS_WORLDMATRIX(247) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(247)), transform_worldex }, + { /*504, WINED3DTS_WORLDMATRIX(248) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(248)), transform_worldex }, + { /*505, WINED3DTS_WORLDMATRIX(249) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(249)), transform_worldex }, + { /*506, WINED3DTS_WORLDMATRIX(250) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(250)), transform_worldex }, + { /*507, WINED3DTS_WORLDMATRIX(251) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(251)), transform_worldex }, + { /*508, WINED3DTS_WORLDMATRIX(252) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(252)), transform_worldex }, + { /*509, WINED3DTS_WORLDMATRIX(253) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(253)), transform_worldex }, + { /*510, WINED3DTS_WORLDMATRIX(254) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(254)), transform_worldex }, + { /*511, WINED3DTS_WORLDMATRIX(255) */ STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(255)), transform_worldex }, + /* Various Vertex states follow */ + { /* , STATE_STREAMSRC */ STATE_VDECL, vertexdeclaration }, + { /* , STATE_INDEXBUFFER */ STATE_INDEXBUFFER, indexbuffer }, + { /* , STATE_VDECL */ STATE_VDECL, vertexdeclaration }, + { /* , STATE_VSHADER */ STATE_VDECL, vertexdeclaration }, + { /* , STATE_VIEWPORT */ STATE_VIEWPORT, viewport }, + { /* , STATE_VERTEXSHADERCONSTANT */ STATE_VERTEXSHADERCONSTANT, shaderconstant }, + { /* , STATE_PIXELSHADERCONSTANT */ STATE_VERTEXSHADERCONSTANT, shaderconstant }, + /* Lights */ + { /* , STATE_ACTIVELIGHT(0) */ STATE_ACTIVELIGHT(0), light }, + { /* , STATE_ACTIVELIGHT(1) */ STATE_ACTIVELIGHT(1), light }, + { /* , STATE_ACTIVELIGHT(2) */ STATE_ACTIVELIGHT(2), light }, + { /* , STATE_ACTIVELIGHT(3) */ STATE_ACTIVELIGHT(3), light }, + { /* , STATE_ACTIVELIGHT(4) */ STATE_ACTIVELIGHT(4), light }, + { /* , STATE_ACTIVELIGHT(5) */ STATE_ACTIVELIGHT(5), light }, + { /* , STATE_ACTIVELIGHT(6) */ STATE_ACTIVELIGHT(6), light }, + { /* , STATE_ACTIVELIGHT(7) */ STATE_ACTIVELIGHT(7), light }, + + { /* Scissor rect */ STATE_SCISSORRECT, scissorrect }, + /* Clip planes */ + { /* STATE_CLIPPLANE(0) */ STATE_CLIPPLANE(0), clipplane }, + { /* STATE_CLIPPLANE(1) */ STATE_CLIPPLANE(1), clipplane }, + { /* STATE_CLIPPLANE(2) */ STATE_CLIPPLANE(2), clipplane }, + { /* STATE_CLIPPLANE(3) */ STATE_CLIPPLANE(3), clipplane }, + { /* STATE_CLIPPLANE(4) */ STATE_CLIPPLANE(4), clipplane }, + { /* STATE_CLIPPLANE(5) */ STATE_CLIPPLANE(5), clipplane }, + { /* STATE_CLIPPLANE(6) */ STATE_CLIPPLANE(6), clipplane }, + { /* STATE_CLIPPLANE(7) */ STATE_CLIPPLANE(7), clipplane }, + { /* STATE_CLIPPLANE(8) */ STATE_CLIPPLANE(8), clipplane }, + { /* STATE_CLIPPLANE(9) */ STATE_CLIPPLANE(9), clipplane }, + { /* STATE_CLIPPLANE(10) */ STATE_CLIPPLANE(10), clipplane }, + { /* STATE_CLIPPLANE(11) */ STATE_CLIPPLANE(11), clipplane }, + { /* STATE_CLIPPLANE(12) */ STATE_CLIPPLANE(12), clipplane }, + { /* STATE_CLIPPLANE(13) */ STATE_CLIPPLANE(13), clipplane }, + { /* STATE_CLIPPLANE(14) */ STATE_CLIPPLANE(14), clipplane }, + { /* STATE_CLIPPLANE(15) */ STATE_CLIPPLANE(15), clipplane }, + { /* STATE_CLIPPLANE(16) */ STATE_CLIPPLANE(16), clipplane }, + { /* STATE_CLIPPLANE(17) */ STATE_CLIPPLANE(17), clipplane }, + { /* STATE_CLIPPLANE(18) */ STATE_CLIPPLANE(18), clipplane }, + { /* STATE_CLIPPLANE(19) */ STATE_CLIPPLANE(19), clipplane }, + { /* STATE_CLIPPLANE(20) */ STATE_CLIPPLANE(20), clipplane }, + { /* STATE_CLIPPLANE(21) */ STATE_CLIPPLANE(21), clipplane }, + { /* STATE_CLIPPLANE(22) */ STATE_CLIPPLANE(22), clipplane }, + { /* STATE_CLIPPLANE(23) */ STATE_CLIPPLANE(23), clipplane }, + { /* STATE_CLIPPLANE(24) */ STATE_CLIPPLANE(24), clipplane }, + { /* STATE_CLIPPLANE(25) */ STATE_CLIPPLANE(25), clipplane }, + { /* STATE_CLIPPLANE(26) */ STATE_CLIPPLANE(26), clipplane }, + { /* STATE_CLIPPLANE(27) */ STATE_CLIPPLANE(27), clipplane }, + { /* STATE_CLIPPLANE(28) */ STATE_CLIPPLANE(28), clipplane }, + { /* STATE_CLIPPLANE(29) */ STATE_CLIPPLANE(29), clipplane }, + { /* STATE_CLIPPLANE(30) */ STATE_CLIPPLANE(30), clipplane }, + { /* STATE_CLIPPLANE(31) */ STATE_CLIPPLANE(31), clipplane }, + + { /* STATE_MATERIAL */ STATE_RENDER(WINED3DRS_SPECULARENABLE), state_specularenable}, +}; diff --git a/reactos/dll/directx/wine/wined3d/stateblock.c b/reactos/dll/directx/wine/wined3d/stateblock.c new file mode 100644 index 00000000000..772bd788719 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/stateblock.c @@ -0,0 +1,1276 @@ +/* + * state block implementation + * + * Copyright 2002 Raphael Junqueira + * Copyright 2004 Jason Edmeades + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info + +/*************************************** + * Stateblock helper functions follow + **************************************/ + +/** Allocates the correct amount of space for pixel and vertex shader constants, + * along with their set/changed flags on the given stateblock object + */ +HRESULT allocate_shader_constants(IWineD3DStateBlockImpl* object) { + + IWineD3DStateBlockImpl *This = object; + +#define WINED3D_MEMCHECK(_object) if (NULL == _object) { FIXME("Out of memory!\n"); return E_OUTOFMEMORY; } + + /* Allocate space for floating point constants */ + object->pixelShaderConstantF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4); + WINED3D_MEMCHECK(object->pixelShaderConstantF); + object->changed.pixelShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(pshader_constantsF)); + WINED3D_MEMCHECK(object->changed.pixelShaderConstantsF); + object->vertexShaderConstantF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4); + WINED3D_MEMCHECK(object->vertexShaderConstantF); + object->changed.vertexShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(vshader_constantsF)); + WINED3D_MEMCHECK(object->changed.vertexShaderConstantsF); + object->contained_vs_consts_f = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * GL_LIMITS(vshader_constantsF)); + WINED3D_MEMCHECK(object->contained_vs_consts_f); + object->contained_ps_consts_f = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * GL_LIMITS(pshader_constantsF)); + WINED3D_MEMCHECK(object->contained_ps_consts_f); + + list_init(&object->set_vconstantsF); + list_init(&object->set_pconstantsF); + +#undef WINED3D_MEMCHECK + + return WINED3D_OK; +} + +/** Copy all members of one stateblock to another */ +void stateblock_savedstates_copy( + IWineD3DStateBlock* iface, + SAVEDSTATES* dest, + SAVEDSTATES* source) { + + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + unsigned bsize = sizeof(BOOL); + + /* Single values */ + dest->indices = source->indices; + dest->material = source->material; + dest->fvf = source->fvf; + dest->viewport = source->viewport; + dest->vertexDecl = source->vertexDecl; + dest->pixelShader = source->pixelShader; + dest->vertexShader = source->vertexShader; + dest->scissorRect = dest->scissorRect; + + /* Fixed size arrays */ + memcpy(dest->streamSource, source->streamSource, bsize * MAX_STREAMS); + memcpy(dest->streamFreq, source->streamFreq, bsize * MAX_STREAMS); + memcpy(dest->textures, source->textures, bsize * MAX_COMBINED_SAMPLERS); + memcpy(dest->transform, source->transform, bsize * (HIGHEST_TRANSFORMSTATE + 1)); + memcpy(dest->renderState, source->renderState, bsize * (WINEHIGHEST_RENDER_STATE + 1)); + memcpy(dest->textureState, source->textureState, bsize * MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE + 1)); + memcpy(dest->samplerState, source->samplerState, bsize * MAX_COMBINED_SAMPLERS * (WINED3D_HIGHEST_SAMPLER_STATE + 1)); + memcpy(dest->clipplane, source->clipplane, bsize * MAX_CLIPPLANES); + memcpy(dest->pixelShaderConstantsB, source->pixelShaderConstantsB, bsize * MAX_CONST_B); + memcpy(dest->pixelShaderConstantsI, source->pixelShaderConstantsI, bsize * MAX_CONST_I); + memcpy(dest->vertexShaderConstantsB, source->vertexShaderConstantsB, bsize * MAX_CONST_B); + memcpy(dest->vertexShaderConstantsI, source->vertexShaderConstantsI, bsize * MAX_CONST_I); + + /* Dynamically sized arrays */ + memcpy(dest->pixelShaderConstantsF, source->pixelShaderConstantsF, bsize * GL_LIMITS(pshader_constantsF)); + memcpy(dest->vertexShaderConstantsF, source->vertexShaderConstantsF, bsize * GL_LIMITS(vshader_constantsF)); +} + +/** Set all members of a stateblock savedstate to the given value */ +void stateblock_savedstates_set( + IWineD3DStateBlock* iface, + SAVEDSTATES* states, + BOOL value) { + + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + unsigned bsize = sizeof(BOOL); + + /* Single values */ + states->indices = value; + states->material = value; + states->fvf = value; + states->viewport = value; + states->vertexDecl = value; + states->pixelShader = value; + states->vertexShader = value; + states->scissorRect = value; + + /* Fixed size arrays */ + memset(states->streamSource, value, bsize * MAX_STREAMS); + memset(states->streamFreq, value, bsize * MAX_STREAMS); + memset(states->textures, value, bsize * MAX_COMBINED_SAMPLERS); + memset(states->transform, value, bsize * (HIGHEST_TRANSFORMSTATE + 1)); + memset(states->renderState, value, bsize * (WINEHIGHEST_RENDER_STATE + 1)); + memset(states->textureState, value, bsize * MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE + 1)); + memset(states->samplerState, value, bsize * MAX_COMBINED_SAMPLERS * (WINED3D_HIGHEST_SAMPLER_STATE + 1)); + memset(states->clipplane, value, bsize * MAX_CLIPPLANES); + memset(states->pixelShaderConstantsB, value, bsize * MAX_CONST_B); + memset(states->pixelShaderConstantsI, value, bsize * MAX_CONST_I); + memset(states->vertexShaderConstantsB, value, bsize * MAX_CONST_B); + memset(states->vertexShaderConstantsI, value, bsize * MAX_CONST_I); + + /* Dynamically sized arrays */ + memset(states->pixelShaderConstantsF, value, bsize * GL_LIMITS(pshader_constantsF)); + memset(states->vertexShaderConstantsF, value, bsize * GL_LIMITS(vshader_constantsF)); +} + +void stateblock_copy( + IWineD3DStateBlock* destination, + IWineD3DStateBlock* source) { + int l; + + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)source; + IWineD3DStateBlockImpl *Dest = (IWineD3DStateBlockImpl *)destination; + + /* IUnknown fields */ + Dest->lpVtbl = This->lpVtbl; + Dest->ref = This->ref; + + /* IWineD3DStateBlock information */ + Dest->parent = This->parent; + Dest->wineD3DDevice = This->wineD3DDevice; + Dest->blockType = This->blockType; + + /* Saved states */ + stateblock_savedstates_copy(source, &Dest->changed, &This->changed); + + /* Single items */ + Dest->fvf = This->fvf; + Dest->vertexDecl = This->vertexDecl; + Dest->vertexShader = This->vertexShader; + Dest->streamIsUP = This->streamIsUP; + Dest->pIndexData = This->pIndexData; + Dest->baseVertexIndex = This->baseVertexIndex; + /* Dest->lights = This->lights; */ + Dest->clip_status = This->clip_status; + Dest->viewport = This->viewport; + Dest->material = This->material; + Dest->pixelShader = This->pixelShader; + Dest->glsl_program = This->glsl_program; + memcpy(&Dest->scissorRect, &This->scissorRect, sizeof(Dest->scissorRect)); + + /* Lights */ + memset(This->activeLights, 0, sizeof(This->activeLights)); + for(l = 0; l < LIGHTMAP_SIZE; l++) { + struct list *e1, *e2; + LIST_FOR_EACH_SAFE(e1, e2, &Dest->lightMap[l]) { + PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry); + list_remove(&light->entry); + HeapFree(GetProcessHeap(), 0, light); + } + + LIST_FOR_EACH(e1, &This->lightMap[l]) { + PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry), *light2; + light2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*light)); + memcpy(light2, light, sizeof(*light)); + list_add_tail(&This->lightMap[l], &light2->entry); + if(light2->glIndex != -1) This->activeLights[light2->glIndex] = light2; + } + } + + /* Fixed size arrays */ + memcpy(Dest->vertexShaderConstantB, This->vertexShaderConstantB, sizeof(BOOL) * MAX_CONST_B); + memcpy(Dest->vertexShaderConstantI, This->vertexShaderConstantI, sizeof(INT) * MAX_CONST_I * 4); + memcpy(Dest->pixelShaderConstantB, This->pixelShaderConstantB, sizeof(BOOL) * MAX_CONST_B); + memcpy(Dest->pixelShaderConstantI, This->pixelShaderConstantI, sizeof(INT) * MAX_CONST_I * 4); + + memcpy(Dest->streamStride, This->streamStride, sizeof(UINT) * MAX_STREAMS); + memcpy(Dest->streamOffset, This->streamOffset, sizeof(UINT) * MAX_STREAMS); + memcpy(Dest->streamSource, This->streamSource, sizeof(IWineD3DVertexBuffer*) * MAX_STREAMS); + memcpy(Dest->streamFreq, This->streamFreq, sizeof(UINT) * MAX_STREAMS); + memcpy(Dest->streamFlags, This->streamFlags, sizeof(UINT) * MAX_STREAMS); + memcpy(Dest->transforms, This->transforms, sizeof(WINED3DMATRIX) * (HIGHEST_TRANSFORMSTATE + 1)); + memcpy(Dest->clipplane, This->clipplane, sizeof(double) * MAX_CLIPPLANES * 4); + memcpy(Dest->renderState, This->renderState, sizeof(DWORD) * (WINEHIGHEST_RENDER_STATE + 1)); + memcpy(Dest->textures, This->textures, sizeof(IWineD3DBaseTexture*) * MAX_COMBINED_SAMPLERS); + memcpy(Dest->textureDimensions, This->textureDimensions, sizeof(int) * MAX_COMBINED_SAMPLERS); + memcpy(Dest->textureState, This->textureState, sizeof(DWORD) * MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE + 1)); + memcpy(Dest->samplerState, This->samplerState, sizeof(DWORD) * MAX_COMBINED_SAMPLERS * (WINED3D_HIGHEST_SAMPLER_STATE + 1)); + + /* Dynamically sized arrays */ + memcpy(Dest->vertexShaderConstantF, This->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4); + memcpy(Dest->pixelShaderConstantF, This->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4); +} + +/********************************************************** + * IWineD3DStateBlockImpl IUnknown parts follows + **********************************************************/ +static HRESULT WINAPI IWineD3DStateBlockImpl_QueryInterface(IWineD3DStateBlock *iface,REFIID riid,LPVOID *ppobj) +{ + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DStateBlock)){ + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DStateBlockImpl_AddRef(IWineD3DStateBlock *iface) { + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1); + return refCount; +} + +static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) { + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p) : Releasing from %d\n", This, refCount + 1); + + if (!refCount) { + constants_entry *constant, *constant2; + int counter; + + /* type 0 represents the primary stateblock, so free all the resources */ + if (This->blockType == WINED3DSBT_INIT) { + /* NOTE: according to MSDN: The application is responsible for making sure the texture references are cleared down */ + for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) { + if (This->textures[counter]) { + /* release our 'internal' hold on the texture */ + if(0 != IWineD3DBaseTexture_Release(This->textures[counter])) { + TRACE("Texture still referenced by stateblock, applications has leaked Stage = %u Texture = %p\n", counter, This->textures[counter]); + } + } + } + if(This->pIndexData) IWineD3DIndexBuffer_Release(This->pIndexData); + + } + + for(counter = 0; counter < LIGHTMAP_SIZE; counter++) { + struct list *e1, *e2; + LIST_FOR_EACH_SAFE(e1, e2, &This->lightMap[counter]) { + PLIGHTINFOEL *light = LIST_ENTRY(e1, PLIGHTINFOEL, entry); + list_remove(&light->entry); + HeapFree(GetProcessHeap(), 0, light); + } + } + + HeapFree(GetProcessHeap(), 0, This->vertexShaderConstantF); + HeapFree(GetProcessHeap(), 0, This->changed.vertexShaderConstantsF); + HeapFree(GetProcessHeap(), 0, This->pixelShaderConstantF); + HeapFree(GetProcessHeap(), 0, This->changed.pixelShaderConstantsF); + HeapFree(GetProcessHeap(), 0, This->contained_vs_consts_f); + HeapFree(GetProcessHeap(), 0, This->contained_ps_consts_f); + + LIST_FOR_EACH_ENTRY_SAFE(constant, constant2, &This->set_vconstantsF, constants_entry, entry) { + HeapFree(GetProcessHeap(), 0, constant); + } + + LIST_FOR_EACH_ENTRY_SAFE(constant, constant2, &This->set_pconstantsF, constants_entry, entry) { + HeapFree(GetProcessHeap(), 0, constant); + } + + HeapFree(GetProcessHeap(), 0, This); + } + return refCount; +} + +/********************************************************** + * IWineD3DStateBlockImpl parts follows + **********************************************************/ +static HRESULT WINAPI IWineD3DStateBlockImpl_GetParent(IWineD3DStateBlock *iface, IUnknown **pParent) { + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + IUnknown_AddRef(This->parent); + *pParent = This->parent; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DStateBlockImpl_GetDevice(IWineD3DStateBlock *iface, IWineD3DDevice** ppDevice){ + + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + + *ppDevice = (IWineD3DDevice*)This->wineD3DDevice; + IWineD3DDevice_AddRef(*ppDevice); + return WINED3D_OK; + +} + +static inline void record_lights(IWineD3DStateBlockImpl *This, IWineD3DStateBlockImpl *targetStateBlock) { + UINT i; + + /* Lights... For a recorded state block, we just had a chain of actions to perform, + * so we need to walk that chain and update any actions which differ + */ + for(i = 0; i < LIGHTMAP_SIZE; i++) { + struct list *e, *f; + LIST_FOR_EACH(e, &This->lightMap[i]) { + BOOL updated = FALSE; + PLIGHTINFOEL *src = LIST_ENTRY(e, PLIGHTINFOEL, entry), *realLight; + if(!src->changed || !src->enabledChanged) continue; + + /* Look up the light in the destination */ + LIST_FOR_EACH(f, &targetStateBlock->lightMap[i]) { + realLight = LIST_ENTRY(f, PLIGHTINFOEL, entry); + if(realLight->OriginalIndex == src->OriginalIndex) { + if(src->changed) { + memcpy(&src->OriginalParms, &realLight->OriginalParms, sizeof(src->OriginalParms)); + } + if(src->enabledChanged) { + /* Need to double check because enabledChanged does not catch enabled -> disabled -> enabled + * or disabled -> enabled -> disabled changes + */ + if(realLight->glIndex == -1 && src->glIndex != -1) { + /* Light disabled */ + This->activeLights[src->glIndex] = NULL; + } else if(realLight->glIndex != -1 && src->glIndex == -1){ + /* Light enabled */ + This->activeLights[realLight->glIndex] = src; + } + src->glIndex = realLight->glIndex; + } + updated = TRUE; + break; + } + } + + if(updated) { + /* Found a light, all done, proceed with next hash entry */ + continue; + } else if(src->changed) { + /* Otherwise assign defaul params */ + memcpy(&src->OriginalParms, &WINED3D_default_light, sizeof(src->OriginalParms)); + } else { + /* Not enabled by default */ + src->glIndex = -1; + } + } + } +} + +static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface){ + + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + IWineD3DStateBlockImpl *targetStateBlock = This->wineD3DDevice->stateBlock; + unsigned int i, j; + + TRACE("(%p) : Updating state block %p ------------------v\n", targetStateBlock, This); + + /* If not recorded, then update can just recapture */ + if (This->blockType == WINED3DSBT_RECORDED) { + + /* Recorded => Only update 'changed' values */ + if (This->vertexShader != targetStateBlock->vertexShader) { + TRACE("Updating vertex shader from %p to %p\n", This->vertexShader, targetStateBlock->vertexShader); + + This->vertexShader = targetStateBlock->vertexShader; + } + + /* Vertex Shader Float Constants */ + for (j = 0; j < This->num_contained_vs_consts_f; ++j) { + i = This->contained_vs_consts_f[j]; + TRACE("Setting %p from %p %d to { %f, %f, %f, %f }\n", This, targetStateBlock, i, + targetStateBlock->vertexShaderConstantF[i * 4], + targetStateBlock->vertexShaderConstantF[i * 4 + 1], + targetStateBlock->vertexShaderConstantF[i * 4 + 2], + targetStateBlock->vertexShaderConstantF[i * 4 + 3]); + + This->vertexShaderConstantF[i * 4] = targetStateBlock->vertexShaderConstantF[i * 4]; + This->vertexShaderConstantF[i * 4 + 1] = targetStateBlock->vertexShaderConstantF[i * 4 + 1]; + This->vertexShaderConstantF[i * 4 + 2] = targetStateBlock->vertexShaderConstantF[i * 4 + 2]; + This->vertexShaderConstantF[i * 4 + 3] = targetStateBlock->vertexShaderConstantF[i * 4 + 3]; + } + + /* Vertex Shader Integer Constants */ + for (j = 0; j < This->num_contained_vs_consts_i; ++j) { + i = This->contained_vs_consts_i[j]; + TRACE("Setting %p from %p %d to { %d, %d, %d, %d }\n", This, targetStateBlock, i, + targetStateBlock->vertexShaderConstantI[i * 4], + targetStateBlock->vertexShaderConstantI[i * 4 + 1], + targetStateBlock->vertexShaderConstantI[i * 4 + 2], + targetStateBlock->vertexShaderConstantI[i * 4 + 3]); + + This->vertexShaderConstantI[i * 4] = targetStateBlock->vertexShaderConstantI[i * 4]; + This->vertexShaderConstantI[i * 4 + 1] = targetStateBlock->vertexShaderConstantI[i * 4 + 1]; + This->vertexShaderConstantI[i * 4 + 2] = targetStateBlock->vertexShaderConstantI[i * 4 + 2]; + This->vertexShaderConstantI[i * 4 + 3] = targetStateBlock->vertexShaderConstantI[i * 4 + 3]; + } + + /* Vertex Shader Boolean Constants */ + for (j = 0; j < This->num_contained_vs_consts_b; ++j) { + i = This->contained_vs_consts_b[j]; + TRACE("Setting %p from %p %d to %s\n", This, targetStateBlock, i, + targetStateBlock->vertexShaderConstantB[i]? "TRUE":"FALSE"); + + This->vertexShaderConstantB[i] = targetStateBlock->vertexShaderConstantB[i]; + } + + /* Recorded => Only update 'changed' values */ + if (This->pixelShader != targetStateBlock->pixelShader) { + TRACE("Updating pixel shader from %p to %p\n", This->pixelShader, targetStateBlock->pixelShader); + + This->pixelShader = targetStateBlock->pixelShader; + } + + /* Pixel Shader Float Constants */ + for (j = 0; j < This->num_contained_ps_consts_f; ++j) { + i = This->contained_ps_consts_f[j]; + TRACE("Setting %p from %p %d to { %f, %f, %f, %f }\n", This, targetStateBlock, i, + targetStateBlock->pixelShaderConstantF[i * 4], + targetStateBlock->pixelShaderConstantF[i * 4 + 1], + targetStateBlock->pixelShaderConstantF[i * 4 + 2], + targetStateBlock->pixelShaderConstantF[i * 4 + 3]); + + This->pixelShaderConstantF[i * 4] = targetStateBlock->pixelShaderConstantF[i * 4]; + This->pixelShaderConstantF[i * 4 + 1] = targetStateBlock->pixelShaderConstantF[i * 4 + 1]; + This->pixelShaderConstantF[i * 4 + 2] = targetStateBlock->pixelShaderConstantF[i * 4 + 2]; + This->pixelShaderConstantF[i * 4 + 3] = targetStateBlock->pixelShaderConstantF[i * 4 + 3]; + } + + /* Pixel Shader Integer Constants */ + for (j = 0; j < This->num_contained_ps_consts_i; ++j) { + i = This->contained_ps_consts_i[j]; + TRACE("Setting %p from %p %d to { %d, %d, %d, %d }\n", This, targetStateBlock, i, + targetStateBlock->pixelShaderConstantI[i * 4], + targetStateBlock->pixelShaderConstantI[i * 4 + 1], + targetStateBlock->pixelShaderConstantI[i * 4 + 2], + targetStateBlock->pixelShaderConstantI[i * 4 + 3]); + + This->pixelShaderConstantI[i * 4] = targetStateBlock->pixelShaderConstantI[i * 4]; + This->pixelShaderConstantI[i * 4 + 1] = targetStateBlock->pixelShaderConstantI[i * 4 + 1]; + This->pixelShaderConstantI[i * 4 + 2] = targetStateBlock->pixelShaderConstantI[i * 4 + 2]; + This->pixelShaderConstantI[i * 4 + 3] = targetStateBlock->pixelShaderConstantI[i * 4 + 3]; + } + + /* Pixel Shader Boolean Constants */ + for (j = 0; j < This->num_contained_ps_consts_b; ++j) { + i = This->contained_ps_consts_b[j]; + TRACE("Setting %p from %p %d to %s\n", This, targetStateBlock, i, + targetStateBlock->pixelShaderConstantB[i]? "TRUE":"FALSE"); + + This->pixelShaderConstantB[i] = targetStateBlock->pixelShaderConstantB[i]; + } + + /* Others + Render & Texture */ + for (i = 0; i < This->num_contained_transform_states; i++) { + TRACE("Updating transform %d\n", i); + memcpy(&This->transforms[This->contained_transform_states[i]], + &targetStateBlock->transforms[This->contained_transform_states[i]], + sizeof(WINED3DMATRIX)); + } + + if (This->changed.indices && ((This->pIndexData != targetStateBlock->pIndexData) + || (This->baseVertexIndex != targetStateBlock->baseVertexIndex))) { + TRACE("Updating pindexData to %p, baseVertexIndex to %d\n", + targetStateBlock->pIndexData, targetStateBlock->baseVertexIndex); + This->pIndexData = targetStateBlock->pIndexData; + This->baseVertexIndex = targetStateBlock->baseVertexIndex; + } + + if(This->changed.vertexDecl && This->vertexDecl != targetStateBlock->vertexDecl){ + TRACE("Updating vertex declaration from %p to %p\n", This->vertexDecl, targetStateBlock->vertexDecl); + + This->vertexDecl = targetStateBlock->vertexDecl; + } + + if(This->changed.fvf && This->fvf != targetStateBlock->fvf){ + This->fvf = targetStateBlock->fvf; + } + + if (This->changed.material && memcmp(&targetStateBlock->material, + &This->material, + sizeof(WINED3DMATERIAL)) != 0) { + TRACE("Updating material\n"); + memcpy(&This->material, &targetStateBlock->material, sizeof(WINED3DMATERIAL)); + } + + if (This->changed.viewport && memcmp(&targetStateBlock->viewport, + &This->viewport, + sizeof(WINED3DVIEWPORT)) != 0) { + TRACE("Updating viewport\n"); + memcpy(&This->viewport, &targetStateBlock->viewport, sizeof(WINED3DVIEWPORT)); + } + + if(This->changed.scissorRect && memcmp(&targetStateBlock->scissorRect, + &This->scissorRect, + sizeof(targetStateBlock->scissorRect))) + { + TRACE("Updating scissor rect\n"); + memcpy(&targetStateBlock->scissorRect, &This->scissorRect, sizeof(targetStateBlock->scissorRect)); + } + + for (i = 0; i < MAX_STREAMS; i++) { + if (This->changed.streamSource[i] && + ((This->streamStride[i] != targetStateBlock->streamStride[i]) || + (This->streamSource[i] != targetStateBlock->streamSource[i]))) { + TRACE("Updating stream source %d to %p, stride to %d\n", i, targetStateBlock->streamSource[i], + targetStateBlock->streamStride[i]); + This->streamStride[i] = targetStateBlock->streamStride[i]; + This->streamSource[i] = targetStateBlock->streamSource[i]; + } + + if (This->changed.streamFreq[i] && + (This->streamFreq[i] != targetStateBlock->streamFreq[i] + || This->streamFlags[i] != targetStateBlock->streamFlags[i])){ + TRACE("Updating stream frequency %d to %d flags to %d\n", i , targetStateBlock->streamFreq[i] , + targetStateBlock->streamFlags[i]); + This->streamFreq[i] = targetStateBlock->streamFreq[i]; + This->streamFlags[i] = targetStateBlock->streamFlags[i]; + } + } + + for (i = 0; i < GL_LIMITS(clipplanes); i++) { + if (This->changed.clipplane[i] && memcmp(&targetStateBlock->clipplane[i], + &This->clipplane[i], + sizeof(This->clipplane)) != 0) { + + TRACE("Updating clipplane %d\n", i); + memcpy(&This->clipplane[i], &targetStateBlock->clipplane[i], + sizeof(This->clipplane)); + } + } + + /* Render */ + for (i = 0; i < This->num_contained_render_states; i++) { + TRACE("Updating renderState %d to %d\n", + This->contained_render_states[i], targetStateBlock->renderState[This->contained_render_states[i]]); + This->renderState[This->contained_render_states[i]] = targetStateBlock->renderState[This->contained_render_states[i]]; + } + + /* Texture states */ + for (j = 0; j < This->num_contained_tss_states; j++) { + DWORD stage = This->contained_tss_states[j].stage; + DWORD state = This->contained_tss_states[j].state; + + TRACE("Updating texturestagestate %d,%d to %d (was %d)\n", stage,state, + targetStateBlock->textureState[stage][state], This->textureState[stage][state]); + This->textureState[stage][state] = targetStateBlock->textureState[stage][state]; + } + + /* Samplers */ + /* TODO: move over to using memcpy */ + for (j = 0; j < MAX_COMBINED_SAMPLERS; j++) { + if (This->changed.textures[j]) { + TRACE("Updating texture %d to %p (was %p)\n", j, targetStateBlock->textures[j], This->textures[j]); + This->textures[j] = targetStateBlock->textures[j]; + } + } + + for (j = 0; j < This->num_contained_sampler_states; j++) { + DWORD stage = This->contained_sampler_states[j].stage; + DWORD state = This->contained_sampler_states[j].state; + TRACE("Updating sampler state %d,%d to %d (was %d)\n", + stage, state, targetStateBlock->samplerState[stage][state], + This->samplerState[stage][state]); + This->samplerState[stage][state] = targetStateBlock->samplerState[stage][state]; + } + + record_lights(This, targetStateBlock); + } else if(This->blockType == WINED3DSBT_ALL) { + This->vertexDecl = targetStateBlock->vertexDecl; + This->vertexShader = targetStateBlock->vertexShader; + memcpy(This->vertexShaderConstantB, targetStateBlock->vertexShaderConstantB, sizeof(This->vertexShaderConstantI)); + memcpy(This->vertexShaderConstantI, targetStateBlock->vertexShaderConstantI, sizeof(This->vertexShaderConstantF)); + memcpy(This->vertexShaderConstantF, targetStateBlock->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4); + memcpy(This->streamStride, targetStateBlock->streamStride, sizeof(This->streamStride)); + memcpy(This->streamOffset, targetStateBlock->streamOffset, sizeof(This->streamOffset)); + memcpy(This->streamSource, targetStateBlock->streamSource, sizeof(This->streamSource)); + memcpy(This->streamFreq, targetStateBlock->streamFreq, sizeof(This->streamFreq)); + memcpy(This->streamFlags, targetStateBlock->streamFlags, sizeof(This->streamFlags)); + This->pIndexData = targetStateBlock->pIndexData; + This->baseVertexIndex = targetStateBlock->baseVertexIndex; + memcpy(This->transforms, targetStateBlock->transforms, sizeof(This->transforms)); + record_lights(This, targetStateBlock); + memcpy(This->clipplane, targetStateBlock->clipplane, sizeof(This->clipplane)); + This->clip_status = targetStateBlock->clip_status; + This->viewport = targetStateBlock->viewport; + This->material = targetStateBlock->material; + This->pixelShader = targetStateBlock->pixelShader; + memcpy(This->pixelShaderConstantB, targetStateBlock->pixelShaderConstantB, sizeof(This->pixelShaderConstantI)); + memcpy(This->pixelShaderConstantI, targetStateBlock->pixelShaderConstantI, sizeof(This->pixelShaderConstantF)); + memcpy(This->pixelShaderConstantF, targetStateBlock->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4); + memcpy(This->renderState, targetStateBlock->renderState, sizeof(This->renderState)); + memcpy(This->textures, targetStateBlock->textures, sizeof(This->textures)); + memcpy(This->textureDimensions, targetStateBlock->textureDimensions, sizeof(This->textureDimensions)); + memcpy(This->textureState, targetStateBlock->textureState, sizeof(This->textureState)); + memcpy(This->samplerState, targetStateBlock->samplerState, sizeof(This->samplerState)); + This->scissorRect = targetStateBlock->scissorRect; + } else if(This->blockType == WINED3DSBT_VERTEXSTATE) { + This->vertexShader = targetStateBlock->vertexShader; + memcpy(This->vertexShaderConstantB, targetStateBlock->vertexShaderConstantB, sizeof(This->vertexShaderConstantI)); + memcpy(This->vertexShaderConstantI, targetStateBlock->vertexShaderConstantI, sizeof(This->vertexShaderConstantF)); + memcpy(This->vertexShaderConstantF, targetStateBlock->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4); + record_lights(This, targetStateBlock); + for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) { + This->renderState[SavedVertexStates_R[i]] = targetStateBlock->renderState[SavedVertexStates_R[i]]; + } + for (j = 0; j < MAX_COMBINED_SAMPLERS; j++) { + for (i = 0; i < NUM_SAVEDVERTEXSTATES_S; i++) { + This->samplerState[j][SavedVertexStates_S[i]] = targetStateBlock->samplerState[j][SavedVertexStates_S[i]]; + } + } + for (j = 0; j < MAX_TEXTURES; j++) { + for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) { + This->textureState[j][SavedVertexStates_R[i]] = targetStateBlock->textureState[j][SavedVertexStates_R[i]]; + } + } + } else if(This->blockType == WINED3DSBT_PIXELSTATE) { + This->pixelShader = targetStateBlock->pixelShader; + memcpy(This->pixelShaderConstantB, targetStateBlock->pixelShaderConstantB, sizeof(This->pixelShaderConstantI)); + memcpy(This->pixelShaderConstantI, targetStateBlock->pixelShaderConstantI, sizeof(This->pixelShaderConstantF)); + memcpy(This->pixelShaderConstantF, targetStateBlock->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4); + for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) { + This->renderState[SavedPixelStates_R[i]] = targetStateBlock->renderState[SavedPixelStates_R[i]]; + } + for (j = 0; j < MAX_COMBINED_SAMPLERS; j++) { + for (i = 0; i < NUM_SAVEDPIXELSTATES_S; i++) { + This->samplerState[j][SavedPixelStates_S[i]] = targetStateBlock->samplerState[j][SavedPixelStates_S[i]]; + } + } + for (j = 0; j < MAX_TEXTURES; j++) { + for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) { + This->textureState[j][SavedPixelStates_R[i]] = targetStateBlock->textureState[j][SavedPixelStates_R[i]]; + } + } + } + + TRACE("(%p) : Updated state block %p ------------------^\n", targetStateBlock, This); + + return WINED3D_OK; +} + +static inline void apply_lights(IWineD3DDevice *pDevice, IWineD3DStateBlockImpl *This) { + UINT i; + for(i = 0; i < LIGHTMAP_SIZE; i++) { + struct list *e; + + LIST_FOR_EACH(e, &This->lightMap[i]) { + PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry); + + if(light->changed) { + IWineD3DDevice_SetLight(pDevice, light->OriginalIndex, &light->OriginalParms); + } + if(light->enabledChanged) { + IWineD3DDevice_SetLightEnable(pDevice, light->OriginalIndex, light->glIndex != -1); + } + } + } +} + +static HRESULT WINAPI IWineD3DStateBlockImpl_Apply(IWineD3DStateBlock *iface){ + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + IWineD3DDevice* pDevice = (IWineD3DDevice*)This->wineD3DDevice; + +/*Copy thing over to updateBlock is isRecording otherwise StateBlock, +should really perform a delta so that only the changes get updated*/ + + UINT i; + UINT j; + + TRACE("(%p) : Applying state block %p ------------------v\n", This, pDevice); + + TRACE("Blocktype: %d\n", This->blockType); + + if(This->blockType == WINED3DSBT_RECORDED) { + if (This->changed.vertexShader) { + IWineD3DDevice_SetVertexShader(pDevice, This->vertexShader); + } + /* Vertex Shader Constants */ + for (i = 0; i < This->num_contained_vs_consts_f; i++) { + IWineD3DDevice_SetVertexShaderConstantF(pDevice, This->contained_vs_consts_f[i], + This->vertexShaderConstantF + This->contained_vs_consts_f[i] * 4, 1); + } + for (i = 0; i < This->num_contained_vs_consts_i; i++) { + IWineD3DDevice_SetVertexShaderConstantI(pDevice, This->contained_vs_consts_i[i], + This->vertexShaderConstantI + This->contained_vs_consts_i[i] * 4, 1); + } + for (i = 0; i < This->num_contained_vs_consts_b; i++) { + IWineD3DDevice_SetVertexShaderConstantB(pDevice, This->contained_vs_consts_b[i], + This->vertexShaderConstantB + This->contained_vs_consts_b[i], 1); + } + + apply_lights(pDevice, This); + + if (This->changed.pixelShader) { + IWineD3DDevice_SetPixelShader(pDevice, This->pixelShader); + } + /* Pixel Shader Constants */ + for (i = 0; i < This->num_contained_ps_consts_f; i++) { + IWineD3DDevice_SetPixelShaderConstantF(pDevice, This->contained_ps_consts_f[i], + This->pixelShaderConstantF + This->contained_ps_consts_f[i] * 4, 1); + } + for (i = 0; i < This->num_contained_ps_consts_i; i++) { + IWineD3DDevice_SetPixelShaderConstantI(pDevice, This->contained_ps_consts_i[i], + This->pixelShaderConstantI + This->contained_ps_consts_i[i] * 4, 1); + } + for (i = 0; i < This->num_contained_ps_consts_b; i++) { + IWineD3DDevice_SetPixelShaderConstantB(pDevice, This->contained_ps_consts_b[i], + This->pixelShaderConstantB + This->contained_ps_consts_b[i], 1); + } + + /* Render */ + for (i = 0; i <= This->num_contained_render_states; i++) { + IWineD3DDevice_SetRenderState(pDevice, This->contained_render_states[i], + This->renderState[This->contained_render_states[i]]); + } + /* Texture states */ + for (i = 0; i < This->num_contained_tss_states; i++) { + DWORD stage = This->contained_tss_states[i].stage; + DWORD state = This->contained_tss_states[i].state; + ((IWineD3DDeviceImpl *)pDevice)->stateBlock->textureState[stage][state] = This->textureState[stage][state]; + ((IWineD3DDeviceImpl *)pDevice)->stateBlock->changed.textureState[stage][state] = TRUE; + /* TODO: Record a display list to apply all gl states. For now apply by brute force */ + IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)pDevice, STATE_TEXTURESTAGE(stage, state)); + } + /* Sampler states */ + for (i = 0; i < This->num_contained_sampler_states; i++) { + DWORD stage = This->contained_sampler_states[i].stage; + DWORD state = This->contained_sampler_states[i].state; + ((IWineD3DDeviceImpl *)pDevice)->stateBlock->samplerState[stage][state] = This->samplerState[stage][state]; + ((IWineD3DDeviceImpl *)pDevice)->stateBlock->changed.samplerState[stage][state] = TRUE; + IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)pDevice, STATE_SAMPLER(stage)); + } + + for (i = 0; i < This->num_contained_transform_states; i++) { + IWineD3DDevice_SetTransform(pDevice, This->contained_transform_states[i], + &This->transforms[This->contained_transform_states[i]]); + } + + if (This->changed.indices) { + IWineD3DDevice_SetIndices(pDevice, This->pIndexData); + IWineD3DDevice_SetBaseVertexIndex(pDevice, This->baseVertexIndex); + } + + if (This->changed.fvf) { + IWineD3DDevice_SetFVF(pDevice, This->fvf); + } + + if (This->changed.vertexDecl) { + IWineD3DDevice_SetVertexDeclaration(pDevice, This->vertexDecl); + } + + if (This->changed.material ) { + IWineD3DDevice_SetMaterial(pDevice, &This->material); + } + + if (This->changed.viewport) { + IWineD3DDevice_SetViewport(pDevice, &This->viewport); + } + + if (This->changed.scissorRect) { + IWineD3DDevice_SetScissorRect(pDevice, &This->scissorRect); + } + + /* TODO: Proper implementation using SetStreamSource offset (set to 0 for the moment)\n") */ + for (i=0; ichanged.streamSource[i]) + IWineD3DDevice_SetStreamSource(pDevice, i, This->streamSource[i], 0, This->streamStride[i]); + + if (This->changed.streamFreq[i]) + IWineD3DDevice_SetStreamSourceFreq(pDevice, i, This->streamFreq[i] | This->streamFlags[i]); + } + for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){ + if (This->changed.textures[j]) { + if (j < MAX_FRAGMENT_SAMPLERS) { + IWineD3DDevice_SetTexture(pDevice, j, This->textures[j]); + } else { + IWineD3DDevice_SetTexture(pDevice, WINED3DVERTEXTEXTURESAMPLER0 + j - MAX_FRAGMENT_SAMPLERS, This->textures[j]); + } + } + } + + for (i = 0; i < GL_LIMITS(clipplanes); i++) { + if (This->changed.clipplane[i]) { + float clip[4]; + + clip[0] = This->clipplane[i][0]; + clip[1] = This->clipplane[i][1]; + clip[2] = This->clipplane[i][2]; + clip[3] = This->clipplane[i][3]; + IWineD3DDevice_SetClipPlane(pDevice, i, clip); + } + } + + } else if(This->blockType == WINED3DSBT_VERTEXSTATE) { + IWineD3DDevice_SetVertexShader(pDevice, This->vertexShader); + for (i = 0; i < GL_LIMITS(vshader_constantsF); i++) { + IWineD3DDevice_SetVertexShaderConstantF(pDevice, i, + This->vertexShaderConstantF + i * 4, 1); + } + for (i = 0; i < MAX_CONST_I; i++) { + IWineD3DDevice_SetVertexShaderConstantI(pDevice, i, + This->vertexShaderConstantI + i * 4, 1); + } + for (i = 0; i < MAX_CONST_B; i++) { + IWineD3DDevice_SetVertexShaderConstantB(pDevice, i, + This->vertexShaderConstantB + i, 1); + } + + apply_lights(pDevice, This); + + for(i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) { + IWineD3DDevice_SetRenderState(pDevice, SavedVertexStates_R[i], This->renderState[SavedVertexStates_R[i]]); + } + for(j = 0; j < MAX_TEXTURES; j++) { + for(i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) { + IWineD3DDevice_SetTextureStageState(pDevice, j, SavedVertexStates_T[i], + This->textureState[j][SavedVertexStates_T[i]]); + } + } + + for(j = 0; j < MAX_FRAGMENT_SAMPLERS; j++) { + for(i = 0; i < NUM_SAVEDVERTEXSTATES_S; i++) { + IWineD3DDevice_SetSamplerState(pDevice, j, SavedVertexStates_S[i], + This->samplerState[j][SavedVertexStates_S[i]]); + } + } + for(j = MAX_FRAGMENT_SAMPLERS; j < MAX_COMBINED_SAMPLERS; j++) { + for(i = 0; i < NUM_SAVEDVERTEXSTATES_S; i++) { + IWineD3DDevice_SetSamplerState(pDevice, + WINED3DVERTEXTEXTURESAMPLER0 + j - MAX_FRAGMENT_SAMPLERS, + SavedVertexStates_S[i], + This->samplerState[j][SavedVertexStates_S[i]]); + } + } + } else if(This->blockType == WINED3DSBT_PIXELSTATE) { + IWineD3DDevice_SetPixelShader(pDevice, This->pixelShader); + for (i = 0; i < GL_LIMITS(pshader_constantsF); i++) { + IWineD3DDevice_SetPixelShaderConstantF(pDevice, i, + This->pixelShaderConstantF + i * 4, 1); + } + for (i = 0; i < MAX_CONST_I; i++) { + IWineD3DDevice_SetPixelShaderConstantI(pDevice, i, + This->pixelShaderConstantI + i * 4, 1); + } + for (i = 0; i < MAX_CONST_B; i++) { + IWineD3DDevice_SetPixelShaderConstantB(pDevice, i, + This->pixelShaderConstantB + i, 1); + } + + for(i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) { + IWineD3DDevice_SetRenderState(pDevice, SavedPixelStates_R[i], This->renderState[SavedPixelStates_R[i]]); + } + for(j = 0; j < MAX_TEXTURES; j++) { + for(i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) { + IWineD3DDevice_SetTextureStageState(pDevice, j, SavedPixelStates_T[i], + This->textureState[j][SavedPixelStates_T[i]]); + } + } + + for(j = 0; j < MAX_FRAGMENT_SAMPLERS; j++) { + for(i = 0; i < NUM_SAVEDPIXELSTATES_S; i++) { + IWineD3DDevice_SetSamplerState(pDevice, j, SavedPixelStates_S[i], + This->samplerState[j][SavedPixelStates_S[i]]); + } + } + for(j = MAX_FRAGMENT_SAMPLERS; j < MAX_COMBINED_SAMPLERS; j++) { + for(i = 0; i < NUM_SAVEDPIXELSTATES_S; i++) { + IWineD3DDevice_SetSamplerState(pDevice, + WINED3DVERTEXTEXTURESAMPLER0 + j - MAX_FRAGMENT_SAMPLERS, + SavedPixelStates_S[i], + This->samplerState[j][SavedPixelStates_S[i]]); + } + } + } else if(This->blockType == WINED3DSBT_ALL) { + IWineD3DDevice_SetVertexShader(pDevice, This->vertexShader); + for (i = 0; i < GL_LIMITS(vshader_constantsF); i++) { + IWineD3DDevice_SetVertexShaderConstantF(pDevice, i, + This->vertexShaderConstantF + i * 4, 1); + } + for (i = 0; i < MAX_CONST_I; i++) { + IWineD3DDevice_SetVertexShaderConstantI(pDevice, i, + This->vertexShaderConstantI + i * 4, 1); + } + for (i = 0; i < MAX_CONST_B; i++) { + IWineD3DDevice_SetVertexShaderConstantB(pDevice, i, + This->vertexShaderConstantB + i, 1); + } + + IWineD3DDevice_SetPixelShader(pDevice, This->pixelShader); + for (i = 0; i < GL_LIMITS(pshader_constantsF); i++) { + IWineD3DDevice_SetPixelShaderConstantF(pDevice, i, + This->pixelShaderConstantF + i * 4, 1); + } + for (i = 0; i < MAX_CONST_I; i++) { + IWineD3DDevice_SetPixelShaderConstantI(pDevice, i, + This->pixelShaderConstantI + i * 4, 1); + } + for (i = 0; i < MAX_CONST_B; i++) { + IWineD3DDevice_SetPixelShaderConstantB(pDevice, i, + This->pixelShaderConstantB + i, 1); + } + + apply_lights(pDevice, This); + + for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) { + IWineD3DDevice_SetRenderState(pDevice, i, This->renderState[i]); + } + for(j = 0; j < MAX_TEXTURES; j++) { + for(i = 1; i <= WINED3D_HIGHEST_TEXTURE_STATE; i++) { + IWineD3DDevice_SetTextureStageState(pDevice, j, i, This->textureState[j][i]); + } + } + + /* Skip unused values between TEXTURE8 and WORLD0 ? */ + for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) { + IWineD3DDevice_SetTransform(pDevice, i, &This->transforms[i]); + } + IWineD3DDevice_SetIndices(pDevice, This->pIndexData); + IWineD3DDevice_SetBaseVertexIndex(pDevice, This->baseVertexIndex); + IWineD3DDevice_SetFVF(pDevice, This->fvf); + IWineD3DDevice_SetVertexDeclaration(pDevice, This->vertexDecl); + IWineD3DDevice_SetMaterial(pDevice, &This->material); + IWineD3DDevice_SetViewport(pDevice, &This->viewport); + IWineD3DDevice_SetScissorRect(pDevice, &This->scissorRect); + + /* TODO: Proper implementation using SetStreamSource offset (set to 0 for the moment)\n") */ + for (i=0; istreamSource[i], 0, This->streamStride[i]); + IWineD3DDevice_SetStreamSourceFreq(pDevice, i, This->streamFreq[i] | This->streamFlags[i]); + } + for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){ + UINT sampler = j < MAX_FRAGMENT_SAMPLERS ? j : WINED3DVERTEXTEXTURESAMPLER0 + j - MAX_FRAGMENT_SAMPLERS; + + IWineD3DDevice_SetTexture(pDevice, sampler, This->textures[j]); + for(i = 1; i < WINED3D_HIGHEST_SAMPLER_STATE; i++) { + IWineD3DDevice_SetSamplerState(pDevice, sampler, i, This->samplerState[j][i]); + } + } + for (i = 0; i < GL_LIMITS(clipplanes); i++) { + float clip[4]; + + clip[0] = This->clipplane[i][0]; + clip[1] = This->clipplane[i][1]; + clip[2] = This->clipplane[i][2]; + clip[3] = This->clipplane[i][3]; + IWineD3DDevice_SetClipPlane(pDevice, i, clip); + } + } + + ((IWineD3DDeviceImpl *)pDevice)->stateBlock->lowest_disabled_stage = MAX_TEXTURES - 1; + for(j = 0; j < MAX_TEXTURES - 1; j++) { + if(((IWineD3DDeviceImpl *)pDevice)->stateBlock->textureState[j][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) { + ((IWineD3DDeviceImpl *)pDevice)->stateBlock->lowest_disabled_stage = j; + break; + } + } + TRACE("(%p) : Applied state block %p ------------------^\n", This, pDevice); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStateBlock* iface) { + IWineD3DStateBlockImpl *This = (IWineD3DStateBlockImpl *)iface; + IWineD3DDevice *device = (IWineD3DDevice *)This->wineD3DDevice; + IWineD3DDeviceImpl *ThisDevice = (IWineD3DDeviceImpl *)device; + union { + WINED3DLINEPATTERN lp; + DWORD d; + } lp; + union { + float f; + DWORD d; + } tmpfloat; + unsigned int i; + + /* Note this may have a large overhead but it should only be executed + once, in order to initialize the complete state of the device and + all opengl equivalents */ + TRACE("(%p) -----------------------> Setting up device defaults... %p\n", This, This->wineD3DDevice); + /* TODO: make a special stateblock type for the primary stateblock (it never gets applied so it doesn't need a real type) */ + This->blockType = WINED3DSBT_INIT; + + /* Set some of the defaults for lights, transforms etc */ + memcpy(&This->transforms[WINED3DTS_PROJECTION], &identity, sizeof(identity)); + memcpy(&This->transforms[WINED3DTS_VIEW], &identity, sizeof(identity)); + for (i = 0; i < 256; ++i) { + memcpy(&This->transforms[WINED3DTS_WORLDMATRIX(i)], &identity, sizeof(identity)); + } + + TRACE("Render states\n"); + /* Render states: */ + if (ThisDevice->depthStencilBuffer != NULL) { + IWineD3DDevice_SetRenderState(device, WINED3DRS_ZENABLE, WINED3DZB_TRUE); + } else { + IWineD3DDevice_SetRenderState(device, WINED3DRS_ZENABLE, WINED3DZB_FALSE); + } + IWineD3DDevice_SetRenderState(device, WINED3DRS_FILLMODE, WINED3DFILL_SOLID); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SHADEMODE, WINED3DSHADE_GOURAUD); + lp.lp.wRepeatFactor = 0; + lp.lp.wLinePattern = 0; + IWineD3DDevice_SetRenderState(device, WINED3DRS_LINEPATTERN, lp.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ZWRITEENABLE, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ALPHATESTENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_LASTPIXEL, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SRCBLEND, WINED3DBLEND_ONE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_DESTBLEND, WINED3DBLEND_ZERO); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CULLMODE, WINED3DCULL_CCW); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ZFUNC, WINED3DCMP_LESSEQUAL); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ALPHAFUNC, WINED3DCMP_ALWAYS); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ALPHAREF, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_DITHERENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ALPHABLENDENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SPECULARENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ZVISIBLE, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGCOLOR, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGTABLEMODE, WINED3DFOG_NONE); + tmpfloat.f = 0.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGSTART, tmpfloat.d); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGEND, tmpfloat.d); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGDENSITY, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_EDGEANTIALIAS, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ZBIAS, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_RANGEFOGENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILFAIL, WINED3DSTENCILOP_KEEP); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILZFAIL, WINED3DSTENCILOP_KEEP); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILPASS, WINED3DSTENCILOP_KEEP); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILREF, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILMASK, 0xFFFFFFFF); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILFUNC, WINED3DCMP_ALWAYS); + IWineD3DDevice_SetRenderState(device, WINED3DRS_STENCILWRITEMASK, 0xFFFFFFFF); + IWineD3DDevice_SetRenderState(device, WINED3DRS_TEXTUREFACTOR, 0xFFFFFFFF); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP0, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP1, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP2, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP3, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP4, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP5, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP6, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP7, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CLIPPING, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_LIGHTING, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_AMBIENT, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_FOGVERTEXMODE, WINED3DFOG_NONE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_COLORVERTEX, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_LOCALVIEWER, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_NORMALIZENORMALS, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_DIFFUSEMATERIALSOURCE, WINED3DMCS_COLOR1); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SPECULARMATERIALSOURCE, WINED3DMCS_COLOR2); + IWineD3DDevice_SetRenderState(device, WINED3DRS_AMBIENTMATERIALSOURCE, WINED3DMCS_MATERIAL); + IWineD3DDevice_SetRenderState(device, WINED3DRS_EMISSIVEMATERIALSOURCE, WINED3DMCS_MATERIAL); + IWineD3DDevice_SetRenderState(device, WINED3DRS_VERTEXBLEND, WINED3DVBF_DISABLE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CLIPPLANEENABLE, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SOFTWAREVERTEXPROCESSING, FALSE); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSIZE, tmpfloat.d); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSIZE_MIN, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSPRITEENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSCALEENABLE, FALSE); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSCALE_A, tmpfloat.d); + tmpfloat.f = 0.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSCALE_B, tmpfloat.d); + tmpfloat.f = 0.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSCALE_C, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_MULTISAMPLEANTIALIAS, TRUE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_MULTISAMPLEMASK, 0xFFFFFFFF); + IWineD3DDevice_SetRenderState(device, WINED3DRS_PATCHEDGESTYLE, WINED3DPATCHEDGE_DISCRETE); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_PATCHSEGMENTS, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_DEBUGMONITORTOKEN, 0xbaadcafe); + tmpfloat.f = 64.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_POINTSIZE_MAX, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_COLORWRITEENABLE, 0x0000000F); + tmpfloat.f = 0.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_TWEENFACTOR, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_BLENDOP, WINED3DBLENDOP_ADD); + IWineD3DDevice_SetRenderState(device, WINED3DRS_POSITIONDEGREE, WINED3DDEGREE_CUBIC); + IWineD3DDevice_SetRenderState(device, WINED3DRS_NORMALDEGREE, WINED3DDEGREE_LINEAR); + /* states new in d3d9 */ + IWineD3DDevice_SetRenderState(device, WINED3DRS_SCISSORTESTENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SLOPESCALEDEPTHBIAS, 0); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_MINTESSELLATIONLEVEL, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_MAXTESSELLATIONLEVEL, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ANTIALIASEDLINEENABLE, FALSE); + tmpfloat.f = 0.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_ADAPTIVETESS_X, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ADAPTIVETESS_Y, tmpfloat.d); + tmpfloat.f = 1.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_ADAPTIVETESS_Z, tmpfloat.d); + tmpfloat.f = 0.0f; + IWineD3DDevice_SetRenderState(device, WINED3DRS_ADAPTIVETESS_W, tmpfloat.d); + IWineD3DDevice_SetRenderState(device, WINED3DRS_ENABLEADAPTIVETESSELLATION, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_TWOSIDEDSTENCILMODE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CCW_STENCILFAIL, WINED3DSTENCILOP_KEEP); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CCW_STENCILZFAIL, WINED3DSTENCILOP_KEEP); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CCW_STENCILPASS, WINED3DSTENCILOP_KEEP); + IWineD3DDevice_SetRenderState(device, WINED3DRS_CCW_STENCILFUNC, WINED3DCMP_ALWAYS); + IWineD3DDevice_SetRenderState(device, WINED3DRS_COLORWRITEENABLE1, 0x0000000F); + IWineD3DDevice_SetRenderState(device, WINED3DRS_COLORWRITEENABLE2, 0x0000000F); + IWineD3DDevice_SetRenderState(device, WINED3DRS_COLORWRITEENABLE3, 0x0000000F); + IWineD3DDevice_SetRenderState(device, WINED3DRS_BLENDFACTOR, 0xFFFFFFFF); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SRGBWRITEENABLE, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_DEPTHBIAS, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP8, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP9, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP10, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP11, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP12, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP13, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP14, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_WRAP15, 0); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SEPARATEALPHABLENDENABLE, FALSE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_SRCBLENDALPHA, WINED3DBLEND_ONE); + IWineD3DDevice_SetRenderState(device, WINED3DRS_DESTBLENDALPHA, WINED3DBLEND_ZERO); + IWineD3DDevice_SetRenderState(device, WINED3DRS_BLENDOPALPHA, WINED3DBLENDOP_ADD); + + /* clipping status */ + This->clip_status.ClipUnion = 0; + This->clip_status.ClipIntersection = 0xFFFFFFFF; + + /* Texture Stage States - Put directly into state block, we will call function below */ + for (i = 0; i < MAX_TEXTURES; i++) { + TRACE("Setting up default texture states for texture Stage %d\n", i); + memcpy(&This->transforms[WINED3DTS_TEXTURE0 + i], &identity, sizeof(identity)); + This->textureState[i][WINED3DTSS_COLOROP ] = (i==0)? WINED3DTOP_MODULATE : WINED3DTOP_DISABLE; + This->textureState[i][WINED3DTSS_COLORARG1 ] = WINED3DTA_TEXTURE; + This->textureState[i][WINED3DTSS_COLORARG2 ] = WINED3DTA_CURRENT; + This->textureState[i][WINED3DTSS_ALPHAOP ] = (i==0)? WINED3DTOP_SELECTARG1 : WINED3DTOP_DISABLE; + This->textureState[i][WINED3DTSS_ALPHAARG1 ] = WINED3DTA_TEXTURE; + This->textureState[i][WINED3DTSS_ALPHAARG2 ] = WINED3DTA_CURRENT; + This->textureState[i][WINED3DTSS_BUMPENVMAT00 ] = (DWORD) 0.0; + This->textureState[i][WINED3DTSS_BUMPENVMAT01 ] = (DWORD) 0.0; + This->textureState[i][WINED3DTSS_BUMPENVMAT10 ] = (DWORD) 0.0; + This->textureState[i][WINED3DTSS_BUMPENVMAT11 ] = (DWORD) 0.0; + This->textureState[i][WINED3DTSS_TEXCOORDINDEX ] = i; + This->textureState[i][WINED3DTSS_BUMPENVLSCALE ] = (DWORD) 0.0; + This->textureState[i][WINED3DTSS_BUMPENVLOFFSET ] = (DWORD) 0.0; + This->textureState[i][WINED3DTSS_TEXTURETRANSFORMFLAGS ] = WINED3DTTFF_DISABLE; + This->textureState[i][WINED3DTSS_ADDRESSW ] = WINED3DTADDRESS_WRAP; + This->textureState[i][WINED3DTSS_COLORARG0 ] = WINED3DTA_CURRENT; + This->textureState[i][WINED3DTSS_ALPHAARG0 ] = WINED3DTA_CURRENT; + This->textureState[i][WINED3DTSS_RESULTARG ] = WINED3DTA_CURRENT; + } + This->lowest_disabled_stage = 1; + + /* Sampler states*/ + for (i = 0 ; i < MAX_COMBINED_SAMPLERS; i++) { + TRACE("Setting up default samplers states for sampler %d\n", i); + This->samplerState[i][WINED3DSAMP_ADDRESSU ] = WINED3DTADDRESS_WRAP; + This->samplerState[i][WINED3DSAMP_ADDRESSV ] = WINED3DTADDRESS_WRAP; + This->samplerState[i][WINED3DSAMP_ADDRESSW ] = WINED3DTADDRESS_WRAP; + This->samplerState[i][WINED3DSAMP_BORDERCOLOR ] = 0x00; + This->samplerState[i][WINED3DSAMP_MAGFILTER ] = WINED3DTEXF_POINT; + This->samplerState[i][WINED3DSAMP_MINFILTER ] = WINED3DTEXF_POINT; + This->samplerState[i][WINED3DSAMP_MIPFILTER ] = WINED3DTEXF_NONE; + This->samplerState[i][WINED3DSAMP_MIPMAPLODBIAS ] = 0; + This->samplerState[i][WINED3DSAMP_MAXMIPLEVEL ] = 0; + This->samplerState[i][WINED3DSAMP_MAXANISOTROPY ] = 1; + This->samplerState[i][WINED3DSAMP_SRGBTEXTURE ] = 0; + This->samplerState[i][WINED3DSAMP_ELEMENTINDEX ] = 0; /* TODO: Indicates which element of a multielement texture to use */ + This->samplerState[i][WINED3DSAMP_DMAPOFFSET ] = 0; /* TODO: Vertex offset in the presampled displacement map */ + } + + /* Under DirectX you can have texture stage operations even if no texture is + bound, whereas opengl will only do texture operations when a valid texture is + bound. We emulate this by creating dummy textures and binding them to each + texture stage, but disable all stages by default. Hence if a stage is enabled + then the default texture will kick in until replaced by a SetTexture call */ + ENTER_GL(); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* The dummy texture does not have client storage backing */ + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); + } + for (i = 0; i < GL_LIMITS(textures); i++) { + GLubyte white = 255; + + /* Note this avoids calling settexture, so pretend it has been called */ + This->changed.textures[i] = TRUE; + This->textures[i] = NULL; + + /* Make appropriate texture active */ + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i)); + checkGLcall("glActiveTextureARB"); + } else if (i > 0) { + FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); + } + + /* Generate an opengl texture name */ + glGenTextures(1, &ThisDevice->dummyTextureName[i]); + checkGLcall("glGenTextures"); + TRACE("Dummy Texture %d given name %d\n", i, ThisDevice->dummyTextureName[i]); + + /* Generate a dummy 2d texture (not using 1d because they cause many + * DRI drivers fall back to sw) */ + This->textureDimensions[i] = GL_TEXTURE_2D; + glBindTexture(GL_TEXTURE_2D, ThisDevice->dummyTextureName[i]); + checkGLcall("glBindTexture"); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white); + checkGLcall("glTexImage2D"); + } + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* Reenable because if supported it is enabled by default */ + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } + + LEAVE_GL(); + + + /* Defaulting palettes - Note these are device wide but reinitialized here for convenience*/ + for (i = 0; i < MAX_PALETTES; ++i) { + int j; + for (j = 0; j < 256; ++j) { + This->wineD3DDevice->palettes[i][j].peRed = 0xFF; + This->wineD3DDevice->palettes[i][j].peGreen = 0xFF; + This->wineD3DDevice->palettes[i][j].peBlue = 0xFF; + This->wineD3DDevice->palettes[i][j].peFlags = 0xFF; + } + } + This->wineD3DDevice->currentPalette = 0; + + /* Set default GLSL program to NULL. We won't actually create one + * until the app sets a vertex or pixel shader */ + This->glsl_program = NULL; + + TRACE("-----------------------> Device defaults now set up...\n"); + return WINED3D_OK; +} + +/********************************************************** + * IWineD3DStateBlock VTbl follows + **********************************************************/ + +const IWineD3DStateBlockVtbl IWineD3DStateBlock_Vtbl = +{ + /* IUnknown */ + IWineD3DStateBlockImpl_QueryInterface, + IWineD3DStateBlockImpl_AddRef, + IWineD3DStateBlockImpl_Release, + /* IWineD3DStateBlock */ + IWineD3DStateBlockImpl_GetParent, + IWineD3DStateBlockImpl_GetDevice, + IWineD3DStateBlockImpl_Capture, + IWineD3DStateBlockImpl_Apply, + IWineD3DStateBlockImpl_InitStartupStateBlock +}; diff --git a/reactos/dll/directx/wine/wined3d/surface.c b/reactos/dll/directx/wine/wined3d/surface.c new file mode 100644 index 00000000000..58b4ed61450 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/surface.c @@ -0,0 +1,3745 @@ +/* + * IWineD3DSurface Implementation + * + * Copyright 1998 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * Copyright 2002-2005 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Stefan Dösinger for CodeWeavers + * Copyright 2007 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf); + +static void surface_download_data(IWineD3DSurfaceImpl *This) { + if (!This->resource.allocatedMemory) This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, This->resource.size + 4); + if (This->resource.format == WINED3DFMT_DXT1 || + This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */ + FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This); + } else { + TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level, + This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory); + + GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory)); + checkGLcall("glGetCompressedTexImageARB()"); + } + } else { + void *mem; + int src_pitch = 0; + int dst_pitch = 0; + + if(This->Flags & SFLAG_CONVERTED) { + FIXME("Read back converted textures unsupported\n"); + return; + } + + if (This->Flags & SFLAG_NONPOW2) { + unsigned char alignment = This->resource.wineD3DDevice->surface_alignment; + src_pitch = This->bytesPerPixel * This->pow2Width; + dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); + src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1); + mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height); + } else { + mem = This->resource.allocatedMemory; + } + + TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level, + This->glDescription.glFormat, This->glDescription.glType, mem); + + glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat, + This->glDescription.glType, mem); + checkGLcall("glGetTexImage()"); + + if (This->Flags & SFLAG_NONPOW2) { + LPBYTE src_data, dst_data; + int y; + /* + * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing + * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to + * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width. + * + * We're doing this... + * + * instead of boxing the texture : + * |<-texture width ->| -->pow2width| /\ + * |111111111111111111| | | + * |222 Texture 222222| boxed empty | texture height + * |3333 Data 33333333| | | + * |444444444444444444| | \/ + * ----------------------------------- | + * | boxed empty | boxed empty | pow2height + * | | | \/ + * ----------------------------------- + * + * + * we're repacking the data to the expected texture width + * + * |<-texture width ->| -->pow2width| /\ + * |111111111111111111222222222222222| | + * |222333333333333333333444444444444| texture height + * |444444 | | + * | | \/ + * | | | + * | empty | pow2height + * | | \/ + * ----------------------------------- + * + * == is the same as + * + * |<-texture width ->| /\ + * |111111111111111111| + * |222222222222222222|texture height + * |333333333333333333| + * |444444444444444444| \/ + * -------------------- + * + * this also means that any references to allocatedMemory should work with the data as if were a + * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture. + * + * internally the texture is still stored in a boxed format so any references to textureName will + * get a boxed texture with width pow2width and not a texture of width currentDesc.Width. + * + * Performance should not be an issue, because applications normally do not lock the surfaces when + * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released, + * and doesn't have to be re-read. + */ + src_data = mem; + dst_data = This->resource.allocatedMemory; + TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch); + for (y = 1 ; y < This->currentDesc.Height; y++) { + /* skip the first row */ + src_data += src_pitch; + dst_data += dst_pitch; + memcpy(dst_data, src_data, dst_pitch); + } + + HeapFree(GetProcessHeap(), 0, mem); + } + } + /* Surface has now been downloaded */ + This->Flags |= SFLAG_INSYSMEM; +} + +static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) { + if (This->resource.format == WINED3DFMT_DXT1 || + This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { + FIXME("Using DXT1/3/5 without advertized support\n"); + } else { + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */ + This->Flags |= SFLAG_CLIENT; + } + + TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data); + ENTER_GL(); + /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver) + * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this + * function uses glCompressedTexImage2D instead of the SubImage call + */ + GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal, + width, height, 0 /* border */, This->resource.size, data)); + checkGLcall("glCompressedTexSubImage2D"); + LEAVE_GL(); + } + } else { + TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data); + ENTER_GL(); + glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data); + checkGLcall("glTexSubImage2D"); + LEAVE_GL(); + } +} + +static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) { + BOOL enable_client_storage = FALSE; + + TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This, + This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type); + + if (This->resource.format == WINED3DFMT_DXT1 || + This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */ + TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n"); + return; + } + + ENTER_GL(); + + if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) { + if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_OVERSIZE | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) { + /* In some cases we want to disable client storage. + * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches + * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues... + * SFLAG_OVERSIZE: The gl texture is smaller than the allocated memory + * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface + * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively + */ + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)"); + This->Flags &= SFLAG_CLIENT; + enable_client_storage = TRUE; + } else { + This->Flags |= SFLAG_CLIENT; + /* Below point opengl to our allocated texture memory */ + } + } + glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, + This->Flags & SFLAG_CLIENT ? This->resource.allocatedMemory : NULL); + checkGLcall("glTexImage2D"); + + if(enable_client_storage) { + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); + } + LEAVE_GL(); + + This->Flags |= SFLAG_ALLOCATED; +} + +/* In D3D the depth stencil dimensions have to be greater than or equal to the + * render target dimensions. With FBOs, the dimensions have to be an exact match. */ +/* TODO: We should synchronize the renderbuffer's content with the texture's content. */ +void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + renderbuffer_entry_t *entry; + GLuint renderbuffer = 0; + unsigned int src_width, src_height; + + src_width = This->pow2Width; + src_height = This->pow2Height; + + /* A depth stencil smaller than the render target is not valid */ + if (width > src_width || height > src_height) return; + + /* Remove any renderbuffer set if the sizes match */ + if (width == src_width && height == src_height) { + This->current_renderbuffer = NULL; + return; + } + + /* Look if we've already got a renderbuffer of the correct dimensions */ + LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) { + if (entry->width == width && entry->height == height) { + renderbuffer = entry->id; + This->current_renderbuffer = entry; + break; + } + } + + if (!renderbuffer) { + const GlPixelFormatDesc *glDesc; + getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc); + + GL_EXTCALL(glGenRenderbuffersEXT(1, &renderbuffer)); + GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer)); + GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, glDesc->glFormat, width, height)); + + entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t)); + entry->width = width; + entry->height = height; + entry->id = renderbuffer; + list_add_head(&This->renderbuffers, &entry->entry); + + This->current_renderbuffer = entry; + } + + checkGLcall("set_compatible_renderbuffer"); +} + +GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DSwapChainImpl *swapchain_impl = (IWineD3DSwapChainImpl *)swapchain; + + TRACE("(%p) : swapchain %p\n", This, swapchain); + + if (swapchain_impl->backBuffer && swapchain_impl->backBuffer[0] == iface) { + TRACE("Returning GL_BACK\n"); + return GL_BACK; + } else if (swapchain_impl->frontBuffer == iface) { + TRACE("Returning GL_FRONT\n"); + return GL_FRONT; + } + + FIXME("Higher back buffer, returning GL_BACK\n"); + return GL_BACK; +} + +/* ******************************************* + IWineD3DSurface IUnknown parts follow + ******************************************* */ +HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + /* Warn ,but be nice about things */ + TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj); + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DSurface)) { + IUnknown_AddRef((IUnknown*)iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + ULONG ref = InterlockedIncrement(&This->resource.ref); + TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1); + return ref; +} + +ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + ULONG ref = InterlockedDecrement(&This->resource.ref); + TRACE("(%p) : Releasing from %d\n", This, ref + 1); + if (ref == 0) { + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice; + renderbuffer_entry_t *entry, *entry2; + TRACE("(%p) : cleaning up\n", This); + + if(iface == device->lastActiveRenderTarget) { + IWineD3DSwapChainImpl *swapchain = device->swapchains ? (IWineD3DSwapChainImpl *) device->swapchains[0] : NULL; + + TRACE("Last active render target destroyed\n"); + /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL + * checks, so switch to a valid target as long as the currently set surface is still valid. Use the + * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed + * and the lastActiveRenderTarget member shouldn't matter + */ + if(swapchain) { + if(swapchain->backBuffer && swapchain->backBuffer[0] != iface) { + TRACE("Activating primary back buffer\n"); + ActivateContext(device, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD); + } else if(!swapchain->backBuffer && swapchain->frontBuffer != iface) { + /* Single buffering environment */ + TRACE("Activating primary front buffer\n"); + ActivateContext(device, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD); + } else { + TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n"); + /* Implicit render target destroyed, that means the device is being destroyed + * whatever we set here, it shouldn't matter + */ + device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe; + } + } else { + /* May happen during ddraw uninitialization */ + TRACE("Render target set, but swapchain does not exist!\n"); + device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe; + } + } + + if (This->glDescription.textureName != 0) { /* release the openGL texture.. */ + + /* Need a context to destroy the texture. Use the currently active render target, but only if + * the primary render target exists. Otherwise lastActiveRenderTarget is garbage, see above. + * When destroying the primary rt, Uninit3D will activate a context before doing anything + */ + if(device->render_targets[0]) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + TRACE("Deleting texture %d\n", This->glDescription.textureName); + ENTER_GL(); + glDeleteTextures(1, &This->glDescription.textureName); + LEAVE_GL(); + } + + if(This->Flags & SFLAG_DIBSECTION) { + /* Release the DC */ + SelectObject(This->hDC, This->dib.holdbitmap); + DeleteDC(This->hDC); + /* Release the DIB section */ + DeleteObject(This->dib.DIBsection); + This->dib.bitmap_data = NULL; + This->resource.allocatedMemory = NULL; + } + if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL); + + HeapFree(GetProcessHeap(), 0, This->palette9); + + IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface); + if(iface == device->ddraw_primary) + device->ddraw_primary = NULL; + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) { + GL_EXTCALL(glDeleteRenderbuffersEXT(1, &entry->id)); + HeapFree(GetProcessHeap(), 0, entry); + } + + TRACE("(%p) Released\n", This); + HeapFree(GetProcessHeap(), 0, This); + + } + return ref; +} + +/* **************************************************** + IWineD3DSurface IWineD3DResource parts follow + **************************************************** */ +HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) { + /* TODO: check for locks */ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DBaseTexture *baseTexture = NULL; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + TRACE("(%p)Checking to see if the container is a base texture\n", This); + if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) { + TRACE("Passing to container\n"); + IWineD3DBaseTexture_PreLoad(baseTexture); + IWineD3DBaseTexture_Release(baseTexture); + } else { + TRACE("(%p) : About to load surface\n", This); + + if(!device->isInDraw) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + ENTER_GL(); + glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */ + if (!This->glDescription.level) { + if (!This->glDescription.textureName) { + glGenTextures(1, &This->glDescription.textureName); + checkGLcall("glGenTextures"); + TRACE("Surface %p given name %d\n", This, This->glDescription.textureName); + } + glBindTexture(This->glDescription.target, This->glDescription.textureName); + checkGLcall("glBindTexture"); + IWineD3DSurface_LoadTexture(iface, FALSE); + /* This is where we should be reducing the amount of GLMemoryUsed */ + } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */ + /* assume this is a coding error not a real error for now */ + FIXME("Mipmap surface has a glTexture bound to it!\n"); + } + if (This->resource.pool == WINED3DPOOL_DEFAULT) { + /* Tell opengl to try and keep this texture in video ram (well mostly) */ + GLclampf tmp; + tmp = 0.9f; + glPrioritizeTextures(1, &This->glDescription.textureName, &tmp); + } + LEAVE_GL(); + } + return; +} + +WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) { + TRACE("(%p) : calling resourceimpl_GetType\n", iface); + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) { + TRACE("(%p) : calling resourceimpl_GetParent\n", iface); + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DSurface IWineD3DSurface parts follow + ****************************************************** */ + +HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DBase *container = 0; + + TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer); + + if (!ppContainer) { + ERR("Called without a valid ppContainer.\n"); + } + + /** From MSDN: + * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget, + * or CreateDepthStencilSurface, the surface is considered stand alone. In this case, + * GetContainer will return the Direct3D device used to create the surface. + */ + if (This->container) { + container = This->container; + } else { + container = (IWineD3DBase *)This->resource.wineD3DDevice; + } + + TRACE("Relaying to QueryInterface\n"); + return IUnknown_QueryInterface(container, riid, ppContainer); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + + TRACE("(%p) : copying into %p\n", This, pDesc); + if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format; + if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType; + if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage; + if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool; + if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */ + if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType; + if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality; + if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width; + if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height; + return WINED3D_OK; +} + +void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target); + if (This->glDescription.textureName == 0 && textureName != 0) { + This->Flags &= ~SFLAG_INTEXTURE; + IWineD3DSurface_AddDirtyRect(iface, NULL); + } + This->glDescription.textureName = textureName; + This->glDescription.target = target; + This->Flags &= ~SFLAG_ALLOCATED; +} + +void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + TRACE("(%p) : returning %p\n", This, &This->glDescription); + *glDescription = &This->glDescription; +} + +/* TODO: think about moving this down to resource? */ +const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the future */ + if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) { + FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface); + } + return (CONST void*)(This->resource.allocatedMemory); +} + +static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) { + BYTE *mem; + GLint fmt; + GLint type; + BYTE *row, *top, *bottom; + int i; + BOOL bpp; + + switch(This->resource.format) + { + case WINED3DFMT_P8: + { + /* GL can't return palettized data, so read ARGB pixels into a + * separate block of memory and convert them into palettized format + * in software. Slow, but if the app means to use palettized render + * targets and locks it... + * + * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons + * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out + * for the color channels when palettizing the colors. + */ + fmt = GL_RGB; + type = GL_UNSIGNED_BYTE; + pitch *= 3; + mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3); + if(!mem) { + ERR("Out of memory\n"); + return; + } + bpp = This->bytesPerPixel * 3; + } + break; + + default: + mem = dest; + fmt = This->glDescription.glFormat; + type = This->glDescription.glType; + bpp = This->bytesPerPixel; + } + + glReadPixels(rect->left, rect->top, + rect->right - rect->left, + rect->bottom - rect->top, + fmt, type, mem); + vcheckGLcall("glReadPixels"); + + /* TODO: Merge this with the palettization loop below for P8 targets */ + + if(!srcUpsideDown) { + UINT len, off; + /* glReadPixels returns the image upside down, and there is no way to prevent this. + Flip the lines in software */ + len = (rect->right - rect->left) * bpp; + off = rect->left * bpp; + + row = HeapAlloc(GetProcessHeap(), 0, len); + if(!row) { + ERR("Out of memory\n"); + if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem); + return; + } + + top = mem + pitch * rect->top; + bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1); + for(i = 0; i < (rect->bottom - rect->top) / 2; i++) { + memcpy(row, top + off, len); + memcpy(top + off, bottom + off, len); + memcpy(bottom + off, row, len); + top += pitch; + bottom -= pitch; + } + HeapFree(GetProcessHeap(), 0, row); + } + + if(This->resource.format == WINED3DFMT_P8) { + PALETTEENTRY *pal; + DWORD width = pitch / 3; + int x, y, c; + if(This->palette) { + pal = This->palette->palents; + } else { + pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette]; + } + + for(y = rect->top; y < rect->bottom; y++) { + for(x = rect->left; x < rect->right; x++) { + /* start lines pixels */ + BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3); + BYTE *green = blue + 1; + BYTE *red = green + 1; + + for(c = 0; c < 256; c++) { + if(*red == pal[c].peRed && + *green == pal[c].peGreen && + *blue == pal[c].peBlue) + { + *((BYTE *) dest + y * width + x) = c; + break; + } + } + } + } + HeapFree(GetProcessHeap(), 0, mem); + } +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + IWineD3DSwapChainImpl *swapchain = NULL; + + TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); + + if (!(This->Flags & SFLAG_LOCKABLE)) { + /* Note: UpdateTextures calls CopyRects which calls this routine to populate the + texture regions, and since the destination is an unlockable region we need + to tolerate this */ + TRACE("Warning: trying to lock unlockable surf@%p\n", This); + /*return WINED3DERR_INVALIDCALL; */ + } + + pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface); + + /* Mark the surface locked */ + This->Flags |= SFLAG_LOCKED; + + /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */ + if(!This->resource.allocatedMemory) { + This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4); + This->Flags &= ~SFLAG_INSYSMEM; /* This is the marker that surface data has to be downloaded */ + } + + /* Calculate the correct start address to report */ + if (NULL == pRect) { + pLockedRect->pBits = This->resource.allocatedMemory; + This->lockedRect.left = 0; + This->lockedRect.top = 0; + This->lockedRect.right = This->currentDesc.Width; + This->lockedRect.bottom = This->currentDesc.Height; + TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom); + } else { + TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom); + + /* DXTn textures are based on compressed blocks of 4x4 pixels, each + * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has + * slightly different meaning compared to regular textures. For DXTn + * textures Pitch is the size of a row of blocks, 4 high and "width" + * long. The x offset is calculated differently as well, since moving 4 + * pixels to the right actually moves an entire 4x4 block to right, ie + * 16 bytes (8 in case of DXT1). */ + if (This->resource.format == WINED3DFMT_DXT1) { + pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2); + } else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 + || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) { + pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4); + } else { + pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel); + } + This->lockedRect.left = pRect->left; + This->lockedRect.top = pRect->top; + This->lockedRect.right = pRect->right; + This->lockedRect.bottom = pRect->bottom; + } + + if (This->Flags & SFLAG_NONPOW2) { + TRACE("Locking non-power 2 texture\n"); + } + + /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy. + * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is + * changed + */ + if(!(This->Flags & SFLAG_DYNLOCK)) { + This->lockCount++; + /* MAXLOCKCOUNT is defined in wined3d_private.h */ + if(This->lockCount > MAXLOCKCOUNT) { + TRACE("Surface is locked regularly, not freeing the system memory copy any more\n"); + This->Flags |= SFLAG_DYNLOCK; + } + } + + if (Flags & WINED3DLOCK_DISCARD) { + /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */ + TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n"); + This->Flags |= SFLAG_INSYSMEM; + } + + if (This->Flags & SFLAG_INSYSMEM) { + TRACE("Local copy is up to date, not downloading data\n"); + goto lock_end; + } + + /* Now download the surface content from opengl + * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target + * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path + */ + IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain); + if(swapchain || iface == myDevice->render_targets[0]) { + BOOL srcIsUpsideDown; + + if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) { + static BOOL warned = FALSE; + if(!warned) { + ERR("The application tries to lock the render target, but render target locking is disabled\n"); + warned = TRUE; + } + if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); + return WINED3D_OK; + } + + /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect. + * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage + * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find + * context->last_was_blit set on the unlock. + */ + ActivateContext(myDevice, iface, CTXUSAGE_BLIT); + ENTER_GL(); + + /* Select the correct read buffer, and give some debug output. + * There is no need to keep track of the current read buffer or reset it, every part of the code + * that reads sets the read buffer as desired. + */ + if(!swapchain) { + /* Locking the primary render target which is not on a swapchain(=offscreen render target). + * Read from the back buffer + */ + TRACE("Locking offscreen render target\n"); + glReadBuffer(myDevice->offscreenBuffer); + srcIsUpsideDown = TRUE; + } else { + GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain); + TRACE("Locking %#x buffer\n", buffer); + glReadBuffer(buffer); + checkGLcall("glReadBuffer"); + + IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); + srcIsUpsideDown = FALSE; + } + + switch(wined3d_settings.rendertargetlock_mode) { + case RTL_AUTO: + case RTL_READDRAW: + case RTL_READTEX: + read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown); + break; + + case RTL_TEXDRAW: + case RTL_TEXTEX: + read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown); + FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n"); + break; + } + LEAVE_GL(); + + /* Mark the local copy up to date if a full download was done */ + if(This->lockedRect.left == 0 && + This->lockedRect.top == 0 && + This->lockedRect.right == This->currentDesc.Width && + This->lockedRect.bottom == This->currentDesc.Height) { + This->Flags |= SFLAG_INSYSMEM; + } + } else if(iface == myDevice->stencilBufferTarget) { + /** the depth stencil in openGL has a format of GL_FLOAT + * which should be good for WINED3DFMT_D16_LOCKABLE + * and WINED3DFMT_D16 + * it is unclear what format the stencil buffer is in except. + * 'Each index is converted to fixed point... + * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their + * mappings in the table GL_PIXEL_MAP_S_TO_S. + * glReadPixels(This->lockedRect.left, + * This->lockedRect.bottom - j - 1, + * This->lockedRect.right - This->lockedRect.left, + * 1, + * GL_DEPTH_COMPONENT, + * type, + * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top))); + * + * Depth Stencil surfaces which are not the current depth stencil target should have their data in a + * gl texture(next path), or in local memory(early return because of set SFLAG_INSYSMEM above). If + * none of that is the case the problem is not in this function :-) + ********************************************/ + FIXME("Depth stencil locking not supported yet\n"); + } else { + /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */ + TRACE("locking an ordinary surface\n"); + + if (0 != This->glDescription.textureName) { + /* Now I have to copy thing bits back */ + + if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) { + ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + + ENTER_GL(); + /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */ + if (GL_SUPPORT(ARB_MULTITEXTURE)) { + GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB)); + checkGLcall("glActiveTextureARB"); + } + IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0)); + IWineD3DSurface_PreLoad(iface); + + surface_download_data(This); + LEAVE_GL(); + } + } + +lock_end: + if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) { + /* Don't dirtify */ + } else { + IWineD3DBaseTexture *pBaseTexture; + /** + * Dirtify on lock + * as seen in msdn docs + */ + IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect); + + /** Dirtify Container if needed */ + if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) { + TRACE("Making container dirty\n"); + IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE); + IWineD3DBaseTexture_Release(pBaseTexture); + } else { + TRACE("Surface is standalone, no need to dirty the container\n"); + } + } + + TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, + This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1); + return WINED3D_OK; +} + +static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) { + GLint prev_store; + GLint prev_rasterpos[4]; + GLint skipBytes = 0; + BOOL storechanged = FALSE, memory_allocated = FALSE; + GLint fmt, type; + BYTE *mem; + UINT bpp; + UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */ + + glDisable(GL_TEXTURE_2D); + vcheckGLcall("glDisable(GL_TEXTURE_2D)"); + + glFlush(); + vcheckGLcall("glFlush"); + glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store); + vcheckGLcall("glIntegerv"); + glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]); + vcheckGLcall("glIntegerv"); + glPixelZoom(1.0, -1.0); + vcheckGLcall("glPixelZoom"); + + /* If not fullscreen, we need to skip a number of bytes to find the next row of data */ + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes); + glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width); + + glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1); + vcheckGLcall("glRasterPos2f"); + + /* Some drivers(radeon dri, others?) don't like exceptions during + * glDrawPixels. If the surface is a DIB section, it might be in GDIMode + * after ReleaseDC. Reading it will cause an exception, which x11drv will + * catch to put the dib section in InSync mode, which leads to a crash + * and a blocked x server on my radeon card. + * + * The following lines read the dib section so it is put in inSync mode + * before glDrawPixels is called and the crash is prevented. There won't + * be any interfering gdi accesses, because UnlockRect is called from + * ReleaseDC, and the app won't use the dc any more afterwards. + */ + if(This->Flags & SFLAG_DIBSECTION) { + volatile BYTE read; + read = This->resource.allocatedMemory[0]; + } + + switch (This->resource.format) { + /* No special care needed */ + case WINED3DFMT_A4R4G4B4: + case WINED3DFMT_R5G6B5: + case WINED3DFMT_A1R5G5B5: + case WINED3DFMT_R8G8B8: + type = This->glDescription.glType; + fmt = This->glDescription.glFormat; + mem = This->resource.allocatedMemory; + bpp = This->bytesPerPixel; + break; + + case WINED3DFMT_X4R4G4B4: + { + int size; + unsigned short *data; + data = (unsigned short *)This->resource.allocatedMemory; + size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left); + while(size > 0) { + *data |= 0xF000; + data++; + size--; + } + type = This->glDescription.glType; + fmt = This->glDescription.glFormat; + mem = This->resource.allocatedMemory; + bpp = This->bytesPerPixel; + } + break; + + case WINED3DFMT_X1R5G5B5: + { + int size; + unsigned short *data; + data = (unsigned short *)This->resource.allocatedMemory; + size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left); + while(size > 0) { + *data |= 0x8000; + data++; + size--; + } + type = This->glDescription.glType; + fmt = This->glDescription.glFormat; + mem = This->resource.allocatedMemory; + bpp = This->bytesPerPixel; + } + break; + + case WINED3DFMT_X8R8G8B8: + { + /* make sure the X byte is set to alpha on, since it + could be any random value. This fixes the intro movie in Pirates! */ + int size; + unsigned int *data; + data = (unsigned int *)This->resource.allocatedMemory; + size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left); + while(size > 0) { + *data |= 0xFF000000; + data++; + size--; + } + } + /* Fall through */ + + case WINED3DFMT_A8R8G8B8: + { + glPixelStorei(GL_PACK_SWAP_BYTES, TRUE); + vcheckGLcall("glPixelStorei"); + storechanged = TRUE; + type = This->glDescription.glType; + fmt = This->glDescription.glFormat; + mem = This->resource.allocatedMemory; + bpp = This->bytesPerPixel; + } + break; + + case WINED3DFMT_A2R10G10B10: + { + glPixelStorei(GL_PACK_SWAP_BYTES, TRUE); + vcheckGLcall("glPixelStorei"); + storechanged = TRUE; + type = This->glDescription.glType; + fmt = This->glDescription.glFormat; + mem = This->resource.allocatedMemory; + bpp = This->bytesPerPixel; + } + break; + + case WINED3DFMT_P8: + { + int height = This->glRect.bottom - This->glRect.top; + type = GL_UNSIGNED_BYTE; + fmt = GL_RGBA; + + mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD)); + if(!mem) { + ERR("Out of memory\n"); + return; + } + memory_allocated = TRUE; + d3dfmt_convert_surface(This->resource.allocatedMemory, + mem, + pitch, + pitch, + height, + pitch * 4, + CONVERT_PALETTED, + This); + bpp = This->bytesPerPixel * 4; + pitch *= 4; + } + break; + + default: + FIXME("Unsupported Format %u in locking func\n", This->resource.format); + + /* Give it a try */ + type = This->glDescription.glType; + fmt = This->glDescription.glFormat; + mem = This->resource.allocatedMemory; + bpp = This->bytesPerPixel; + } + + glDrawPixels(This->lockedRect.right - This->lockedRect.left, + (This->lockedRect.bottom - This->lockedRect.top)-1, + fmt, type, + mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top); + checkGLcall("glDrawPixels"); + glPixelZoom(1.0,1.0); + vcheckGLcall("glPixelZoom"); + + glRasterPos3iv(&prev_rasterpos[0]); + vcheckGLcall("glRasterPos3iv"); + + /* Reset to previous pack row length */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes); + vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH"); + if(storechanged) { + glPixelStorei(GL_PACK_SWAP_BYTES, prev_store); + vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES"); + } + + /* Blitting environment requires that 2D texturing is enabled. It was turned off before, + * turn it on again + */ + glEnable(GL_TEXTURE_2D); + checkGLcall("glEnable(GL_TEXTURE_2D)"); + + if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem); + return; +} + +static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) { + float glTexCoord[4]; + + glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */ + glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */ + glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */ + glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */ + + IWineD3DSurface_PreLoad((IWineD3DSurface *) This); + + ENTER_GL(); + + glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName); + checkGLcall("glEnable glBindTexture"); + + /* No filtering for blts */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + + /* Start drawing a quad */ + glBegin(GL_QUADS); + + glColor3d(1.0f, 1.0f, 1.0f); + glTexCoord2f(glTexCoord[0], glTexCoord[2]); + glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0); + + glTexCoord2f(glTexCoord[0], glTexCoord[3]); + glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0); + + glTexCoord2f(glTexCoord[1], glTexCoord[3]); + glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0); + + glTexCoord2f(glTexCoord[1], glTexCoord[2]); + glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0); + + glEnd(); + checkGLcall("glEnd"); + + /* Unbind the texture */ + glBindTexture(GL_TEXTURE_2D, 0); + checkGLcall("glEnable glBindTexture"); + + LEAVE_GL(); +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + IWineD3DSwapChainImpl *swapchain = NULL; + + if (!(This->Flags & SFLAG_LOCKED)) { + WARN("trying to Unlock an unlocked surf@%p\n", This); + return WINED3DERR_INVALIDCALL; + } + + TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1); + + if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) { + TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This); + goto unlock_end; + } + + IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain); + if(swapchain || iface == myDevice->render_targets[0]) { + if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) { + static BOOL warned = FALSE; + if(!warned) { + ERR("The application tries to write to the render target, but render target locking is disabled\n"); + warned = TRUE; + } + if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); + goto unlock_end; + } + + /* Activate the correct context for the render target */ + ActivateContext(myDevice, iface, CTXUSAGE_BLIT); + ENTER_GL(); + + if(!swapchain) { + /* Primary offscreen render target */ + TRACE("Offscreen render target\n"); + glDrawBuffer(myDevice->offscreenBuffer); + checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)"); + } else { + GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain); + TRACE("Unlocking %#x buffer\n", buffer); + glDrawBuffer(buffer); + checkGLcall("glDrawBuffer"); + + IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain); + } + + switch(wined3d_settings.rendertargetlock_mode) { + case RTL_AUTO: + case RTL_READDRAW: + case RTL_TEXDRAW: + flush_to_framebuffer_drawpixels(This); + break; + + case RTL_READTEX: + case RTL_TEXTEX: + flush_to_framebuffer_texture(This); + break; + } + if(!swapchain) { + glDrawBuffer(myDevice->offscreenBuffer); + checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)"); + } else if(swapchain->backBuffer) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer(GL_BACK)"); + } else { + glDrawBuffer(GL_FRONT); + checkGLcall("glDrawBuffer(GL_FRONT)"); + } + LEAVE_GL(); + + This->dirtyRect.left = This->currentDesc.Width; + This->dirtyRect.top = This->currentDesc.Height; + This->dirtyRect.right = 0; + This->dirtyRect.bottom = 0; + This->Flags |= SFLAG_INDRAWABLE; + } else if(iface == myDevice->stencilBufferTarget) { + FIXME("Depth Stencil buffer locking is not implemented\n"); + } else { + /* The rest should be a normal texture */ + IWineD3DBaseTextureImpl *impl; + /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture + * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler + * states need resetting + */ + if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) { + if(impl->baseTexture.bindCount) { + IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler)); + } + IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl); + } + } + + unlock_end: + This->Flags &= ~SFLAG_LOCKED; + memset(&This->lockedRect, 0, sizeof(RECT)); + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + WINED3DLOCKED_RECT lock; + UINT usage; + BITMAPINFO* b_info; + HDC ddc; + DWORD *masks; + HRESULT hr; + RGBQUAD col[256]; + const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL); + + TRACE("(%p)->(%p)\n",This,pHDC); + + if(This->Flags & SFLAG_USERPTR) { + ERR("Not supported on surfaces with an application-provided surfaces\n"); + return WINEDDERR_NODC; + } + + /* Give more detailed info for ddraw */ + if (This->Flags & SFLAG_DCINUSE) + return WINEDDERR_DCALREADYCREATED; + + /* Can't GetDC if the surface is locked */ + if (This->Flags & SFLAG_LOCKED) + return WINED3DERR_INVALIDCALL; + + memset(&lock, 0, sizeof(lock)); /* To be sure */ + + /* Create a DIB section if there isn't a hdc yet */ + if(!This->hDC) { + int extraline = 0; + SYSTEM_INFO sysInfo; + void *oldmem = This->resource.allocatedMemory; + + switch (This->bytesPerPixel) { + case 2: + case 4: + /* Allocate extra space to store the RGB bit masks. */ + b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD)); + break; + + case 3: + b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER)); + break; + + default: + /* Allocate extra space for a palette. */ + b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(BITMAPINFOHEADER) + + sizeof(RGBQUAD) + * (1 << (This->bytesPerPixel * 8))); + break; + } + + if (!b_info) + return E_OUTOFMEMORY; + + /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the + * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size, + * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise + * add an extra line to the dib section + */ + GetSystemInfo(&sysInfo); + if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) { + extraline = 1; + TRACE("Adding an extra line to the dib section\n"); + } + + b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */ + b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel; + b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline; + b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface); + b_info->bmiHeader.biPlanes = 1; + b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8; + + b_info->bmiHeader.biXPelsPerMeter = 0; + b_info->bmiHeader.biYPelsPerMeter = 0; + b_info->bmiHeader.biClrUsed = 0; + b_info->bmiHeader.biClrImportant = 0; + + /* Get the bit masks */ + masks = (DWORD *) &(b_info->bmiColors); + switch (This->resource.format) { + case WINED3DFMT_R8G8B8: + usage = DIB_RGB_COLORS; + b_info->bmiHeader.biCompression = BI_RGB; + break; + + case WINED3DFMT_X1R5G5B5: + case WINED3DFMT_A1R5G5B5: + case WINED3DFMT_A4R4G4B4: + case WINED3DFMT_X4R4G4B4: + case WINED3DFMT_R3G3B2: + case WINED3DFMT_A8R3G3B2: + case WINED3DFMT_A2B10G10R10: + case WINED3DFMT_A8B8G8R8: + case WINED3DFMT_X8B8G8R8: + case WINED3DFMT_A2R10G10B10: + case WINED3DFMT_R5G6B5: + case WINED3DFMT_A16B16G16R16: + usage = 0; + b_info->bmiHeader.biCompression = BI_BITFIELDS; + masks[0] = formatEntry->redMask; + masks[1] = formatEntry->greenMask; + masks[2] = formatEntry->blueMask; + break; + + default: + /* Don't know palette */ + b_info->bmiHeader.biCompression = BI_RGB; + usage = 0; + break; + } + + ddc = GetDC(0); + if (ddc == 0) { + HeapFree(GetProcessHeap(), 0, b_info); + return HRESULT_FROM_WIN32(GetLastError()); + } + + TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage); + This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */); + ReleaseDC(0, ddc); + + if (!This->dib.DIBsection) { + ERR("CreateDIBSection failed!\n"); + HeapFree(GetProcessHeap(), 0, b_info); + return HRESULT_FROM_WIN32(GetLastError()); + } + + TRACE("DIBSection at : %p\n", This->dib.bitmap_data); + + /* copy the existing surface to the dib section */ + if(This->resource.allocatedMemory) { + memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage); + /* We won't need that any more */ + } else { + /* This is to make LockRect read the gl Texture although memory is allocated */ + This->Flags &= ~SFLAG_INSYSMEM; + } + + HeapFree(GetProcessHeap(), 0, b_info); + + /* Use the dib section from now on */ + This->resource.allocatedMemory = This->dib.bitmap_data; + + /* Now allocate a HDC */ + This->hDC = CreateCompatibleDC(0); + This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection); + TRACE("using wined3d palette %p\n", This->palette); + SelectPalette(This->hDC, + This->palette ? This->palette->hpal : 0, + FALSE); + + This->Flags |= SFLAG_DIBSECTION; + + if(This->Flags & SFLAG_CLIENT) { + IWineD3DSurface_PreLoad(iface); + } + HeapFree(GetProcessHeap(), 0, oldmem); + } + + /* Lock the surface */ + hr = IWineD3DSurface_LockRect(iface, + &lock, + NULL, + 0); + if(FAILED(hr)) { + ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr); + /* keep the dib section */ + return hr; + } + + if(This->resource.format == WINED3DFMT_P8 || + This->resource.format == WINED3DFMT_A8P8) { + unsigned int n; + if(This->palette) { + PALETTEENTRY ent[256]; + + GetPaletteEntries(This->palette->hpal, 0, 256, ent); + for (n=0; n<256; n++) { + col[n].rgbRed = ent[n].peRed; + col[n].rgbGreen = ent[n].peGreen; + col[n].rgbBlue = ent[n].peBlue; + col[n].rgbReserved = 0; + } + } else { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + for (n=0; n<256; n++) { + col[n].rgbRed = device->palettes[device->currentPalette][n].peRed; + col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen; + col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue; + col[n].rgbReserved = 0; + } + + } + SetDIBColorTable(This->hDC, 0, 256, col); + } + + *pHDC = This->hDC; + TRACE("returning %p\n",*pHDC); + This->Flags |= SFLAG_DCINUSE; + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + + TRACE("(%p)->(%p)\n",This,hDC); + + if (!(This->Flags & SFLAG_DCINUSE)) + return WINED3DERR_INVALIDCALL; + + /* we locked first, so unlock now */ + IWineD3DSurface_UnlockRect(iface); + + This->Flags &= ~SFLAG_DCINUSE; + + return WINED3D_OK; +} + +/* ****************************************************** + IWineD3DSurface Internal (No mapping to directx api) parts follow + ****************************************************** */ + +HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp, BOOL srgb_mode) { + BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT); + const GlPixelFormatDesc *glDesc; + getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc); + + /* Default values: From the surface */ + *format = glDesc->glFormat; + *internal = srgb_mode?glDesc->glGammaInternal:glDesc->glInternal; + *type = glDesc->glType; + *convert = NO_CONVERSION; + *target_bpp = This->bytesPerPixel; + + /* Ok, now look if we have to do any conversion */ + switch(This->resource.format) { + case WINED3DFMT_P8: + /* **************** + Paletted Texture + **************** */ + /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used + * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying. + */ + if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) { + *format = GL_RGBA; + *internal = GL_RGBA; + *type = GL_UNSIGNED_BYTE; + *target_bpp = 4; + if(colorkey_active) { + *convert = CONVERT_PALETTED_CK; + } else { + *convert = CONVERT_PALETTED; + } + } + + break; + + case WINED3DFMT_R3G3B2: + /* ********************** + GL_UNSIGNED_BYTE_3_3_2 + ********************** */ + if (colorkey_active) { + /* This texture format will never be used.. So do not care about color keying + up until the point in time it will be needed :-) */ + FIXME(" ColorKeying not supported in the RGB 332 format !\n"); + } + break; + + case WINED3DFMT_R5G6B5: + if (colorkey_active) { + *convert = CONVERT_CK_565; + *format = GL_RGBA; + *internal = GL_RGBA; + *type = GL_UNSIGNED_SHORT_5_5_5_1; + } + break; + + case WINED3DFMT_X1R5G5B5: + if (colorkey_active) { + *convert = CONVERT_CK_5551; + *format = GL_BGRA; + *internal = GL_RGBA; + *type = GL_UNSIGNED_SHORT_1_5_5_5_REV; + } + break; + + case WINED3DFMT_R8G8B8: + if (colorkey_active) { + *convert = CONVERT_CK_RGB24; + *format = GL_RGBA; + *internal = GL_RGBA; + *type = GL_UNSIGNED_INT_8_8_8_8; + *target_bpp = 4; + } + break; + + case WINED3DFMT_X8R8G8B8: + if (colorkey_active) { + *convert = CONVERT_RGB32_888; + *format = GL_RGBA; + *internal = GL_RGBA; + *type = GL_UNSIGNED_INT_8_8_8_8; + } + break; + + case WINED3DFMT_V8U8: + if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break; + else if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + *format = GL_DUDV_ATI; + *internal = GL_DU8DV8_ATI; + *type = GL_BYTE; + /* No conversion - Just change the gl type */ + break; + } + *convert = CONVERT_V8U8; + *format = GL_BGR; + *internal = GL_RGB8; + *type = GL_UNSIGNED_BYTE; + *target_bpp = 3; + break; + + case WINED3DFMT_X8L8V8U8: + if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break; + *convert = CONVERT_X8L8V8U8; + *format = GL_BGRA; + *internal = GL_RGBA8; + *type = GL_UNSIGNED_BYTE; + *target_bpp = 4; + /* Not supported by GL_ATI_envmap_bumpmap */ + break; + + case WINED3DFMT_Q8W8V8U8: + if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break; + *convert = CONVERT_Q8W8V8U8; + *format = GL_BGRA; + *internal = GL_RGBA8; + *type = GL_UNSIGNED_BYTE; + *target_bpp = 4; + /* Not supported by GL_ATI_envmap_bumpmap */ + break; + + case WINED3DFMT_V16U16: + if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break; + *convert = CONVERT_V16U16; + *format = GL_BGR; + *internal = GL_RGB16; + *type = GL_SHORT; + *target_bpp = 6; + /* What should I do here about GL_ATI_envmap_bumpmap? + * Convert it or allow data loss by loading it into a 8 bit / channel texture? + */ + break; + + case WINED3DFMT_A4L4: + /* A4L4 exists as an internal gl format, but for some reason there is not + * format+type combination to load it. Thus convert it to A8L8, then load it + * with A4L4 internal, but A8L8 format+type + */ + *convert = CONVERT_A4L4; + *format = GL_LUMINANCE_ALPHA; + *internal = GL_LUMINANCE4_ALPHA4; + *type = GL_UNSIGNED_BYTE; + *target_bpp = 2; + break; + + case WINED3DFMT_R32F: + /* Can be loaded in theory with fmt=GL_RED, type=GL_FLOAT, but this fails. The reason + * is that D3D expects the undefined green, blue and alpha channels to return 1.0 + * when sampling, but OpenGL sets green and blue to 0.0 instead. Thus we have to inject + * 1.0 instead. + * + * The alpha channel defaults to 1.0 in opengl, so nothing has to be done about it. + */ + *convert = CONVERT_R32F; + *format = GL_RGB; + *internal = GL_RGB32F_ARB; + *type = GL_FLOAT; + *target_bpp = 12; + break; + + case WINED3DFMT_R16F: + /* Simmilar to R32F */ + *convert = CONVERT_R16F; + *format = GL_RGB; + *internal = GL_RGB16F_ARB; + *type = GL_HALF_FLOAT_ARB; + *target_bpp = 6; + break; + + default: + break; + } + + return WINED3D_OK; +} + +HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) { + BYTE *source, *dest; + TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf); + + switch (convert) { + case NO_CONVERSION: + { + memcpy(dst, src, pitch * height); + break; + } + case CONVERT_PALETTED: + case CONVERT_PALETTED_CK: + { + IWineD3DPaletteImpl* pal = surf->palette; + BYTE table[256][4]; + unsigned int i; + unsigned int x, y; + + if( pal == NULL) { + /* TODO: If we are a sublevel, try to get the palette from level 0 */ + } + + if (pal == NULL) { + /* Still no palette? Use the device's palette */ + /* Get the surface's palette */ + for (i = 0; i < 256; i++) { + IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice; + + table[i][0] = device->palettes[device->currentPalette][i].peRed; + table[i][1] = device->palettes[device->currentPalette][i].peGreen; + table[i][2] = device->palettes[device->currentPalette][i].peBlue; + if ((convert == CONVERT_PALETTED_CK) && + (i >= surf->SrcBltCKey.dwColorSpaceLowValue) && + (i <= surf->SrcBltCKey.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; + } + } + } else { + TRACE("Using surface palette %p\n", pal); + /* 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 ((convert == CONVERT_PALETTED_CK) && + (i >= surf->SrcBltCKey.dwColorSpaceLowValue) && + (i <= surf->SrcBltCKey.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 if(pal->Flags & WINEDDPCAPS_ALPHA) { + table[i][3] = pal->palents[i].peFlags; + } else { + table[i][3] = 0xFF; + } + } + } + + for (y = 0; y < height; y++) + { + source = src + pitch * y; + dest = dst + outpitch * y; + /* This is an 1 bpp format, using the width here is fine */ + for (x = 0; x < width; x++) { + BYTE color = *source++; + *dest++ = table[color][0]; + *dest++ = table[color][1]; + *dest++ = table[color][2]; + *dest++ = table[color][3]; + } + } + } + break; + + case CONVERT_CK_565: + { + /* 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: Nvidia documents say that their driver does not support alpha + color keying + on the same surface and disables color keying in such a case + */ + unsigned int x, y; + WORD *Source; + WORD *Dest; + + TRACE("Color keyed 565\n"); + + for (y = 0; y < height; y++) { + Source = (WORD *) (src + y * pitch); + Dest = (WORD *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + WORD color = *Source++; + *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1)); + if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) || + (color > surf->SrcBltCKey.dwColorSpaceHighValue)) { + *Dest |= 0x0001; + } + Dest++; + } + } + } + break; + + case CONVERT_CK_5551: + { + /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */ + unsigned int x, y; + WORD *Source; + WORD *Dest; + TRACE("Color keyed 5551\n"); + for (y = 0; y < height; y++) { + Source = (WORD *) (src + y * pitch); + Dest = (WORD *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + WORD color = *Source++; + *Dest = color; + if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) || + (color > surf->SrcBltCKey.dwColorSpaceHighValue)) { + *Dest |= (1 << 15); + } + else { + *Dest &= ~(1 << 15); + } + Dest++; + } + } + } + break; + + case CONVERT_V8U8: + { + unsigned int x, y; + short *Source; + unsigned char *Dest; + for(y = 0; y < height; y++) { + Source = (short *) (src + y * pitch); + Dest = (unsigned char *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + long color = (*Source++); + /* B */ Dest[0] = 0xff; + /* G */ Dest[1] = (color >> 8) + 128; /* V */ + /* R */ Dest[2] = (color) + 128; /* U */ + Dest += 3; + } + } + break; + } + + case CONVERT_Q8W8V8U8: + { + unsigned int x, y; + DWORD *Source; + unsigned char *Dest; + for(y = 0; y < height; y++) { + Source = (DWORD *) (src + y * pitch); + Dest = (unsigned char *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + long color = (*Source++); + /* B */ Dest[0] = ((color >> 16) & 0xff) + 128; /* W */ + /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */ + /* R */ Dest[2] = (color & 0xff) + 128; /* U */ + /* A */ Dest[3] = ((color >> 24) & 0xff) + 128; /* Q */ + Dest += 4; + } + } + break; + } + + case CONVERT_A4L4: + { + unsigned int x, y; + unsigned char *Source; + unsigned char *Dest; + for(y = 0; y < height; y++) { + Source = (unsigned char *) (src + y * pitch); + Dest = (unsigned char *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + unsigned char color = (*Source++); + /* A */ Dest[1] = (color & 0xf0) << 0; + /* L */ Dest[0] = (color & 0x0f) << 4; + Dest += 2; + } + } + break; + } + + case CONVERT_R32F: + { + unsigned int x, y; + float *Source; + float *Dest; + for(y = 0; y < height; y++) { + Source = (float *) (src + y * pitch); + Dest = (float *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + float color = (*Source++); + Dest[0] = color; + Dest[1] = 1.0; + Dest[2] = 1.0; + Dest += 3; + } + } + break; + } + + case CONVERT_R16F: + { + unsigned int x, y; + WORD *Source; + WORD *Dest; + WORD one = 0x3c00; + for(y = 0; y < height; y++) { + Source = (WORD *) (src + y * pitch); + Dest = (WORD *) (dst + y * outpitch); + for (x = 0; x < width; x++ ) { + WORD color = (*Source++); + Dest[0] = color; + Dest[1] = one; + Dest[2] = one; + Dest += 3; + } + } + break; + } + default: + ERR("Unsupported conversation type %d\n", convert); + } + return WINED3D_OK; +} + +/* This function is used in case of 8bit paletted textures to upload the palette. + For now it only supports GL_EXT_paletted_texture extension but support for other + extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well. +*/ +static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DPaletteImpl* pal = This->palette; + BYTE table[256][4]; + int i; + + if (pal == NULL) { + /* Still no palette? Use the device's palette */ + /* Get the surface's palette */ + for (i = 0; i < 256; i++) { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + table[i][0] = device->palettes[device->currentPalette][i].peRed; + table[i][1] = device->palettes[device->currentPalette][i].peGreen; + table[i][2] = device->palettes[device->currentPalette][i].peBlue; + if ((convert == CONVERT_PALETTED_CK) && + (i >= This->SrcBltCKey.dwColorSpaceLowValue) && + (i <= This->SrcBltCKey.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; + } + } + } else { + TRACE("Using surface palette %p\n", pal); + /* 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 ((convert == CONVERT_PALETTED_CK) && + (i >= This->SrcBltCKey.dwColorSpaceLowValue) && + (i <= This->SrcBltCKey.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 if(pal->Flags & WINEDDPCAPS_ALPHA) { + table[i][3] = pal->palents[i].peFlags; + } else { + table[i][3] = 0xFF; + } + } + } + GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table)); +} + +static BOOL palette9_changed(IWineD3DSurfaceImpl *This) { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) { + /* If a ddraw-style palette is attached assume no d3d9 palette change. + * Also the palette isn't interesting if the surface format isn't P8 or A8P8 + */ + return FALSE; + } + + if(This->palette9) { + if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) { + return FALSE; + } + } else { + This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256); + } + memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256); + return TRUE; +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + GLenum format, internal, type; + CONVERT_TYPES convert; + int bpp; + int width, pitch, outpitch; + BYTE *mem; + + if (!(This->Flags & SFLAG_INTEXTURE)) { + TRACE("Reloading because surface is dirty\n"); + } else if(/* Reload: gl texture has ck, now no ckey is set OR */ + ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) || + /* Reload: vice versa OR */ + ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) || + /* Also reload: Color key is active AND the color key has changed */ + ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && ( + (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) || + (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) { + TRACE("Reloading because of color keying\n"); + } else if(palette9_changed(This)) { + TRACE("Reloading surface because the d3d8/9 palette was changed\n"); + } else { + TRACE("surface is already in texture\n"); + return WINED3D_OK; + } + + This->Flags |= SFLAG_INTEXTURE; + + /* Resources are placed in system RAM and do not need to be recreated when a device is lost. + * These resources are not bound by device size or format restrictions. Because of this, + * these resources cannot be accessed by the Direct3D device nor set as textures or render targets. + * However, these resources can always be created, locked, and copied. + */ + if (This->resource.pool == WINED3DPOOL_SCRATCH ) + { + FIXME("(%p) Operation not supported for scratch textures\n",This); + return WINED3DERR_INVALIDCALL; + } + + d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb_mode); + + if (This->Flags & SFLAG_INDRAWABLE) { + if (This->glDescription.level != 0) + FIXME("Surface in texture is only supported for level 0\n"); + else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 || + This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 || + This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 || + This->resource.format == WINED3DFMT_DXT5) + FIXME("Format %d not supported\n", This->resource.format); + else { + GLint prevRead; + + ENTER_GL(); + glGetIntegerv(GL_READ_BUFFER, &prevRead); + vcheckGLcall("glGetIntegerv"); + glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer); + vcheckGLcall("glReadBuffer"); + + if(!(This->Flags & SFLAG_ALLOCATED)) { + surface_allocate_surface(This, internal, This->pow2Width, + This->pow2Height, format, type); + } + + glCopyTexSubImage2D(This->glDescription.target, + This->glDescription.level, + 0, 0, 0, 0, + This->currentDesc.Width, + This->currentDesc.Height); + checkGLcall("glCopyTexSubImage2D"); + + glReadBuffer(prevRead); + vcheckGLcall("glReadBuffer"); + + LEAVE_GL(); + + TRACE("Updated target %d\n", This->glDescription.target); + } + return WINED3D_OK; + } else + /* The only place where LoadTexture() might get called when isInDraw=1 + * is ActivateContext where lastActiveRenderTarget is preloaded. + */ + if(iface == device->lastActiveRenderTarget && device->isInDraw) + ERR("Reading back render target but SFLAG_INDRAWABLE not set\n"); + + /* Otherwise: System memory copy must be most up to date */ + + if(This->CKeyFlags & WINEDDSD_CKSRCBLT) { + This->Flags |= SFLAG_GLCKEY; + This->glCKey = This->SrcBltCKey; + } + else This->Flags &= ~SFLAG_GLCKEY; + + /* The width is in 'length' not in bytes */ + width = This->currentDesc.Width; + pitch = IWineD3DSurface_GetPitch(iface); + + if((convert != NO_CONVERSION) && This->resource.allocatedMemory) { + int height = This->currentDesc.Height; + + /* Stick to the alignment for the converted surface too, makes it easier to load the surface */ + outpitch = width * bpp; + outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1); + + mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height); + if(!mem) { + ERR("Out of memory %d, %d!\n", outpitch, height); + return WINED3DERR_OUTOFVIDEOMEMORY; + } + d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This); + + This->Flags |= SFLAG_CONVERTED; + } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) { + d3dfmt_p8_upload_palette(iface, convert); + This->Flags &= ~SFLAG_CONVERTED; + mem = This->resource.allocatedMemory; + } else { + This->Flags &= ~SFLAG_CONVERTED; + mem = This->resource.allocatedMemory; + } + + /* Make sure the correct pitch is used */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, width); + + if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) { + TRACE("non power of two support\n"); + if(!(This->Flags & SFLAG_ALLOCATED)) { + surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type); + } + if (mem) { + surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem); + } + } else { + /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory + * changed. So also keep track of memory changes. In this case the texture has to be reallocated + */ + if(!(This->Flags & SFLAG_ALLOCATED)) { + surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type); + } + if (mem) { + surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem); + } + } + + /* Restore the default pitch */ + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + if (mem != This->resource.allocatedMemory) + HeapFree(GetProcessHeap(), 0, mem); + +#if 0 + { + static unsigned int gen = 0; + char buffer[4096]; + ++gen; + if ((gen % 10) == 0) { + snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen); + IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer); + } + /* + * debugging crash code + if (gen == 250) { + void** test = NULL; + *test = 0; + } + */ + } +#endif + + if (!(This->Flags & SFLAG_DONOTFREE)) { + HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + This->resource.allocatedMemory = NULL; + This->Flags &= ~SFLAG_INSYSMEM; + } + + return WINED3D_OK; +} + +#include +#include +HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) { + FILE* f = NULL; + UINT i, y; + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + char *allocatedMemory; + char *textureRow; + IWineD3DSwapChain *swapChain = NULL; + int width, height; + GLuint tmpTexture = 0; + DWORD color; + /*FIXME: + Textures may not be stored in ->allocatedgMemory and a GlTexture + so we should lock the surface before saving a snapshot, or at least check that + */ + /* TODO: Compressed texture images can be obtained from the GL in uncompressed form + by calling GetTexImage and in compressed form by calling + GetCompressedTexImageARB. Queried compressed images can be saved and + later reused by calling CompressedTexImage[123]DARB. Pre-compressed + texture images do not need to be processed by the GL and should + significantly improve texture loading performance relative to uncompressed + images. */ + +/* Setup the width and height to be the internal texture width and height. */ + width = This->pow2Width; + height = This->pow2Height; +/* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/ + IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain); + + if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) { + /* if were not a real texture then read the back buffer into a real texture */ + /* we don't want to interfere with the back buffer so read the data into a temporary + * texture and then save the data out of the temporary texture + */ + GLint prevRead; + ENTER_GL(); + TRACE("(%p) Reading render target into texture\n", This); + glEnable(GL_TEXTURE_2D); + + glGenTextures(1, &tmpTexture); + glBindTexture(GL_TEXTURE_2D, tmpTexture); + + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + width, + height, + 0/*border*/, + GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8_REV, + NULL); + + glGetIntegerv(GL_READ_BUFFER, &prevRead); + vcheckGLcall("glGetIntegerv"); + glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer); + vcheckGLcall("glReadBuffer"); + glCopyTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + 0, + 0, + width, + height, + 0); + + checkGLcall("glCopyTexImage2D"); + glReadBuffer(prevRead); + LEAVE_GL(); + + } else { /* bind the real texture, and make sure it up to date */ + IWineD3DSurface_PreLoad(iface); + } + allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4); + ENTER_GL(); + FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height); + glGetTexImage(GL_TEXTURE_2D, + This->glDescription.level, + GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8_REV, + allocatedMemory); + checkGLcall("glTexImage2D"); + if (tmpTexture) { + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &tmpTexture); + } + LEAVE_GL(); + + f = fopen(filename, "w+"); + if (NULL == f) { + ERR("opening of %s failed with: %s\n", filename, strerror(errno)); + return WINED3DERR_INVALIDCALL; + } +/* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */ + TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format)); +/* TGA header */ + fputc(0,f); + fputc(0,f); + fputc(2,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); + fputc(0,f); +/* short width*/ + fwrite(&width,2,1,f); +/* short height */ + fwrite(&height,2,1,f); +/* format rgba */ + fputc(0x20,f); + fputc(0x28,f); +/* raw data */ + /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up */ + if(swapChain) + textureRow = allocatedMemory + (width * (height - 1) *4); + else + textureRow = allocatedMemory; + for (y = 0 ; y < height; y++) { + for (i = 0; i < width; i++) { + color = *((DWORD*)textureRow); + fputc((color >> 16) & 0xFF, f); /* B */ + fputc((color >> 8) & 0xFF, f); /* G */ + fputc((color >> 0) & 0xFF, f); /* R */ + fputc((color >> 24) & 0xFF, f); /* A */ + textureRow += 4; + } + /* take two rows of the pointer to the texture memory */ + if(swapChain) + (textureRow-= width << 3); + + } + TRACE("Closing file\n"); + fclose(f); + + if(swapChain) { + IWineD3DSwapChain_Release(swapChain); + } + HeapFree(GetProcessHeap(), 0, allocatedMemory); + return WINED3D_OK; +} + +/** + * Slightly inefficient way to handle multiple dirty rects but it works :) + */ +extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DBaseTexture *baseTexture = NULL; + if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE)) + surface_download_data(This); + + This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE); + if (NULL != pDirtyRect) { + This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left); + This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top); + This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right); + This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom); + } else { + This->dirtyRect.left = 0; + This->dirtyRect.top = 0; + This->dirtyRect.right = This->currentDesc.Width; + This->dirtyRect.bottom = This->currentDesc.Height; + } + TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left, + This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom); + /* if the container is a basetexture then mark it dirty. */ + if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) { + TRACE("Passing to container\n"); + IWineD3DBaseTexture_SetDirty(baseTexture, TRUE); + IWineD3DBaseTexture_Release(baseTexture); + } + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + + TRACE("This %p, container %p\n", This, container); + + /* We can't keep a reference to the container, since the container already keeps a reference to us. */ + + TRACE("Setting container to %p from %p\n", container, This->container); + This->container = container; + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + const GlPixelFormatDesc *glDesc; + const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc); + + if (This->resource.format != WINED3DFMT_UNKNOWN) { + FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This); + return WINED3DERR_INVALIDCALL; + } + + TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format)); + if (format == WINED3DFMT_UNKNOWN) { + This->resource.size = 0; + } else if (format == WINED3DFMT_DXT1) { + /* DXT1 is half byte per pixel */ + This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1; + + } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 || + format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) { + This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)); + } else { + unsigned char alignment = This->resource.wineD3DDevice->surface_alignment; + This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1); + This->resource.size *= This->pow2Height; + } + + + /* Setup some glformat defaults */ + This->glDescription.glFormat = glDesc->glFormat; + This->glDescription.glFormatInternal = glDesc->glInternal; + This->glDescription.glType = glDesc->glType; + + if (format != WINED3DFMT_UNKNOWN) { + This->bytesPerPixel = formatEntry->bpp; + } else { + This->bytesPerPixel = 0; + } + + This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0; + This->Flags &= ~SFLAG_ALLOCATED; + + This->resource.format = format; + + TRACE("(%p) : Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType); + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + + /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */ + if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) { + ERR("Not supported on render targets\n"); + return WINED3DERR_INVALIDCALL; + } + + if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) { + WARN("Surface is locked or the HDC is in use\n"); + return WINED3DERR_INVALIDCALL; + } + + if(Mem && Mem != This->resource.allocatedMemory) { + void *release = NULL; + + /* Do I have to copy the old surface content? */ + if(This->Flags & SFLAG_DIBSECTION) { + /* Release the DC. No need to hold the critical section for the update + * Thread because this thread runs only on front buffers, but this method + * fails for render targets in the check above. + */ + SelectObject(This->hDC, This->dib.holdbitmap); + DeleteDC(This->hDC); + /* Release the DIB section */ + DeleteObject(This->dib.DIBsection); + This->dib.bitmap_data = NULL; + This->resource.allocatedMemory = NULL; + This->hDC = NULL; + This->Flags &= ~SFLAG_DIBSECTION; + } else if(!(This->Flags & SFLAG_USERPTR)) { + release = This->resource.allocatedMemory; + } + This->resource.allocatedMemory = Mem; + This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM; + + /* Now the surface memory is most up do date. Invalidate drawable and texture */ + This->Flags &= ~(SFLAG_INDRAWABLE | SFLAG_INTEXTURE); + + /* For client textures opengl has to be notified */ + if(This->Flags & SFLAG_CLIENT) { + This->Flags &= ~SFLAG_ALLOCATED; + IWineD3DSurface_PreLoad(iface); + /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */ + } + + /* Now free the old memory if any */ + HeapFree(GetProcessHeap(), 0, release); + } else if(This->Flags & SFLAG_USERPTR) { + /* Lockrect and GetDC will re-create the dib section and allocated memory */ + This->resource.allocatedMemory = NULL; + This->Flags &= ~SFLAG_USERPTR; + + if(This->Flags & SFLAG_CLIENT) { + This->Flags &= ~SFLAG_ALLOCATED; + /* This respecifies an empty texture and opengl knows that the old memory is gone */ + IWineD3DSurface_PreLoad(iface); + } + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DSwapChainImpl *swapchain = NULL; + HRESULT hr; + TRACE("(%p)->(%p,%x)\n", This, override, Flags); + + /* Flipping is only supported on RenderTargets */ + if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return WINEDDERR_NOTFLIPPABLE; + + if(override) { + /* DDraw sets this for the X11 surfaces, so don't confuse the user + * FIXME("(%p) Target override is not supported by now\n", This); + * Additionally, it isn't really possible to support triple-buffering + * properly on opengl at all + */ + } + + IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain); + if(!swapchain) { + ERR("Flipped surface is not on a swapchain\n"); + return WINEDDERR_NOTFLIPPABLE; + } + + /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip, + * and only d3d8 and d3d9 apps specify the presentation interval + */ + if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) { + /* Most common case first to avoid wasting time on all the other cases */ + swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE; + } else if(Flags & WINEDDFLIP_NOVSYNC) { + swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE; + } else if(Flags & WINEDDFLIP_INTERVAL2) { + swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO; + } else if(Flags & WINEDDFLIP_INTERVAL3) { + swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE; + } else { + swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR; + } + + /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */ + hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0); + IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain); + return hr; +} + +/* Does a direct frame buffer -> texture copy. Stretching is done + * with single pixel copy calls + */ +static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) { + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + float xrel, yrel; + UINT row; + IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; + + + ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT); + ENTER_GL(); + IWineD3DSurface_PreLoad((IWineD3DSurface *) This); + + /* Bind the target texture */ + glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName); + checkGLcall("glBindTexture"); + if(!swapchain) { + glReadBuffer(myDevice->offscreenBuffer); + } else { + GLenum buffer = surface_get_gl_buffer(SrcSurface, (IWineD3DSwapChain *)swapchain); + glReadBuffer(buffer); + } + checkGLcall("glReadBuffer"); + + xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1); + yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1); + + if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) { + FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n"); + + if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) { + ERR("Texture filtering not supported in direct blit\n"); + } + } else if((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) && ((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) { + ERR("Texture filtering not supported in direct blit\n"); + } + + if(upsidedown && + !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) && + !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) { + /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */ + + glCopyTexSubImage2D(This->glDescription.target, + This->glDescription.level, + drect->x1, drect->y1, /* xoffset, yoffset */ + srect->x1, Src->currentDesc.Height - srect->y2, + drect->x2 - drect->x1, drect->y2 - drect->y1); + } else { + UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1; + /* I have to process this row by row to swap the image, + * otherwise it would be upside down, so stretching in y direction + * doesn't cost extra time + * + * However, stretching in x direction can be avoided if not necessary + */ + for(row = drect->y1; row < drect->y2; row++) { + if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) { + /* Well, that stuff works, but it's very slow. + * find a better way instead + */ + UINT col; + + for(col = drect->x1; col < drect->x2; col++) { + glCopyTexSubImage2D(This->glDescription.target, + This->glDescription.level, + drect->x1 + col, row, /* xoffset, yoffset */ + srect->x1 + col * xrel, yoffset - (int) (row * yrel), + 1, 1); + } + } else { + glCopyTexSubImage2D(This->glDescription.target, + This->glDescription.level, + drect->x1, row, /* xoffset, yoffset */ + srect->x1, yoffset - (int) (row * yrel), + drect->x2-drect->x1, 1); + } + } + } + + vcheckGLcall("glCopyTexSubImage2D"); + LEAVE_GL(); +} + +/* Uses the hardware to stretch and flip the image */ +static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) { + GLuint src, backup = 0; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; + float left, right, top, bottom; /* Texture coordinates */ + UINT fbwidth = Src->currentDesc.Width; + UINT fbheight = Src->currentDesc.Height; + GLenum drawBuffer = GL_BACK; + + TRACE("Using hwstretch blit\n"); + /* Activate the Proper context for reading from the source surface, set it up for blitting */ + ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT); + ENTER_GL(); + IWineD3DSurface_PreLoad((IWineD3DSurface *) This); + + /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring. + * This way we don't have to wait for the 2nd readback to finish to leave this function. + */ + if(GL_LIMITS(aux_buffers) >= 2) { + /* Got more than one aux buffer? Use the 2nd aux buffer */ + drawBuffer = GL_AUX1; + } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) { + /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */ + drawBuffer = GL_AUX0; + } + + if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) { + glGenTextures(1, &backup); + checkGLcall("glGenTextures\n"); + glBindTexture(GL_TEXTURE_2D, backup); + checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)"); + } else { + /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If + * we are reading from the back buffer, the backup can be used as source texture + */ + if(Src->glDescription.textureName == 0) { + /* Get it a description */ + IWineD3DSurface_PreLoad(SrcSurface); + } + glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName); + checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)"); + + /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */ + Src->Flags &= ~SFLAG_INTEXTURE; + } + + glReadBuffer(GL_BACK); + checkGLcall("glReadBuffer(GL_BACK)"); + + /* TODO: Only back up the part that will be overwritten */ + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0 /* read offsets */, + 0, 0, + fbwidth, + fbheight); + + checkGLcall("glCopyTexSubImage2D"); + + /* No issue with overriding these - the sampler is dirty due to blit usage */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + minMipLookup[Filter][WINED3DTEXF_NONE]); + checkGLcall("glTexParameteri"); + + if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) { + src = backup ? backup : Src->glDescription.textureName; + } else { + glReadBuffer(GL_FRONT); + checkGLcall("glReadBuffer(GL_FRONT)"); + + glGenTextures(1, &src); + checkGLcall("glGenTextures(1, &src)"); + glBindTexture(GL_TEXTURE_2D, src); + checkGLcall("glBindTexture(GL_TEXTURE_2D, src)"); + + /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch + * out for power of 2 sizes + */ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + checkGLcall("glTexImage2D"); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0 /* read offsets */, + 0, 0, + fbwidth, + fbheight); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + checkGLcall("glTexParameteri"); + + glReadBuffer(GL_BACK); + checkGLcall("glReadBuffer(GL_BACK)"); + } + checkGLcall("glEnd and previous"); + + left = (float) srect->x1 / (float) Src->pow2Width; + right = (float) srect->x2 / (float) Src->pow2Width; + + if(upsidedown) { + top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height; + bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height; + } else { + top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height; + bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height; + } + + /* draw the source texture stretched and upside down. The correct surface is bound already */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glDrawBuffer(drawBuffer); + glReadBuffer(drawBuffer); + + glBegin(GL_QUADS); + /* bottom left */ + glTexCoord2f(left, bottom); + glVertex2i(0, fbheight); + + /* top left */ + glTexCoord2f(left, top); + glVertex2i(0, fbheight - drect->y2 - drect->y1); + + /* top right */ + glTexCoord2f(right, top); + glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1); + + /* bottom right */ + glTexCoord2f(right, bottom); + glVertex2i(drect->x2 - drect->x1, fbheight); + glEnd(); + checkGLcall("glEnd and previous"); + + /* Now read the stretched and upside down image into the destination texture */ + glBindTexture(This->glDescription.target, This->glDescription.textureName); + checkGLcall("glBindTexture"); + glCopyTexSubImage2D(This->glDescription.target, + 0, + drect->x1, drect->y1, /* xoffset, yoffset */ + 0, 0, /* We blitted the image to the origin */ + drect->x2 - drect->x1, drect->y2 - drect->y1); + checkGLcall("glCopyTexSubImage2D"); + + /* Write the back buffer backup back */ + glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName); + checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)"); + + if(drawBuffer == GL_BACK) { + glBegin(GL_QUADS); + /* top left */ + glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height); + glVertex2i(0, 0); + + /* bottom left */ + glTexCoord2f(0.0, 0.0); + glVertex2i(0, fbheight); + + /* bottom right */ + glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0); + glVertex2i(fbwidth, Src->currentDesc.Height); + + /* top right */ + glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height); + glVertex2i(fbwidth, 0); + glEnd(); + } else { + /* Restore the old draw buffer */ + glDrawBuffer(GL_BACK); + } + + /* Cleanup */ + if(src != Src->glDescription.textureName && src != backup) { + glDeleteTextures(1, &src); + checkGLcall("glDeleteTextures(1, &src)"); + } + if(backup) { + glDeleteTextures(1, &backup); + checkGLcall("glDeleteTextures(1, &backup)"); + } + LEAVE_GL(); +} + +/* Not called from the VTable */ +static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) { + WINED3DRECT rect; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL; + IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; + + TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx); + + /* Get the swapchain. One of the surfaces has to be a primary surface */ + IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain); + if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain); + if(Src) { + IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain); + if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain); + } + + /* Early sort out of cases where no render target is used */ + if(!dstSwapchain && !srcSwapchain && + SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) { + TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This); + return WINED3DERR_INVALIDCALL; + } + + /* No destination color keying supported */ + if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) { + /* Can we support that with glBlendFunc if blitting to the frame buffer? */ + TRACE("Destination color key not supported in accelerated Blit, falling back to software\n"); + return WINED3DERR_INVALIDCALL; + } + + if (DestRect) { + rect.x1 = DestRect->left; + rect.y1 = DestRect->top; + rect.x2 = DestRect->right; + rect.y2 = DestRect->bottom; + } else { + rect.x1 = 0; + rect.y1 = 0; + rect.x2 = This->currentDesc.Width; + rect.y2 = This->currentDesc.Height; + } + + /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */ + if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer && + ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) { + /* Half-life does a Blt from the back buffer to the front buffer, + * Full surface size, no flags... Use present instead + * + * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer + */ + + /* Check rects - IWineD3DDevice_Present doesn't handle them */ + while(1) + { + RECT mySrcRect; + TRACE("Looking if a Present can be done...\n"); + /* Source Rectangle must be full surface */ + if( SrcRect ) { + if(SrcRect->left != 0 || SrcRect->top != 0 || + SrcRect->right != Src->currentDesc.Width || SrcRect->bottom != Src->currentDesc.Height) { + TRACE("No, Source rectangle doesn't match\n"); + break; + } + } + mySrcRect.left = 0; + mySrcRect.top = 0; + mySrcRect.right = Src->currentDesc.Width; + mySrcRect.bottom = Src->currentDesc.Height; + + /* No stretching may occur */ + if(mySrcRect.right != rect.x2 - rect.x1 || + mySrcRect.bottom != rect.y2 - rect.y1) { + TRACE("No, stretching is done\n"); + break; + } + + /* Destination must be full surface or match the clipping rectangle */ + if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd) + { + RECT cliprect; + POINT pos[2]; + GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect); + pos[0].x = rect.x1; + pos[0].y = rect.y1; + pos[1].x = rect.x2; + pos[1].y = rect.y2; + MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd, + pos, 2); + + if(pos[0].x != cliprect.left || pos[0].y != cliprect.top || + pos[1].x != cliprect.right || pos[1].y != cliprect.bottom) + { + TRACE("No, dest rectangle doesn't match(clipper)\n"); + TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect.left, cliprect.top, cliprect.right, cliprect.bottom); + TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect.x1, rect.y1, rect.x2, rect.y2); + break; + } + } + else + { + if(rect.x1 != 0 || rect.y1 != 0 || + rect.x2 != This->currentDesc.Width || rect.y2 != This->currentDesc.Height) { + TRACE("No, dest rectangle doesn't match(surface size)\n"); + break; + } + } + + TRACE("Yes\n"); + + /* These flags are unimportant for the flag check, remove them */ + if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) { + WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect; + + /* The idea behind this is that a glReadPixels and a glDrawPixels call + * take very long, while a flip is fast. + * This applies to Half-Life, which does such Blts every time it finished + * a frame, and to Prince of Persia 3D, which uses this to draw at least the main + * menu. This is also used by all apps when they do windowed rendering + * + * The problem is that flipping is not really the same as copying. After a + * Blt the front buffer is a copy of the back buffer, and the back buffer is + * untouched. Therefore it's necessary to override the swap effect + * and to set it back after the flip. + * + * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice + * testcases. + */ + + dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY; + dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE; + + TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n"); + IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0); + + dstSwapchain->presentParms.SwapEffect = orig_swap; + + return WINED3D_OK; + } + break; + } + + TRACE("Unsupported blit between buffers on the same swapchain\n"); + return WINED3DERR_INVALIDCALL; + } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) && + (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) { + ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n"); + return WINED3DERR_INVALIDCALL; + } + + if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) { + /* Blit from render target to texture */ + WINED3DRECT srect; + BOOL upsideDown, stretchx; + + if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) { + TRACE("Color keying not supported by frame buffer to texture blit\n"); + return WINED3DERR_INVALIDCALL; + /* Destination color key is checked above */ + } + + /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag + * glCopyTexSubImage is a bit picky about the parameters we pass to it + */ + if(SrcRect) { + if(SrcRect->top < SrcRect->bottom) { + srect.y1 = SrcRect->top; + srect.y2 = SrcRect->bottom; + upsideDown = FALSE; + } else { + srect.y1 = SrcRect->bottom; + srect.y2 = SrcRect->top; + upsideDown = TRUE; + } + srect.x1 = SrcRect->left; + srect.x2 = SrcRect->right; + } else { + srect.x1 = 0; + srect.y1 = 0; + srect.x2 = Src->currentDesc.Width; + srect.y2 = Src->currentDesc.Height; + upsideDown = FALSE; + } + if(rect.x1 > rect.x2) { + UINT tmp = rect.x2; + rect.x2 = rect.x1; + rect.x1 = tmp; + upsideDown = !upsideDown; + } + if(!srcSwapchain) { + TRACE("Reading from an offscreen target\n"); + upsideDown = !upsideDown; + } + + if(rect.x2 - rect.x1 != srect.x2 - srect.x1) { + stretchx = TRUE; + } else { + stretchx = FALSE; + } + + /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot + * flip the image nor scale it. + * + * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call + * -> If the app wants a image width an unscaled width, copy it line per line + * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller + * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the + * back buffer. This is slower than reading line per line, thus not used for flipping + * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied + * pixel by pixel + * + * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies + * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering + * backends. + */ + if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) { + stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect, + (IWineD3DSurface *)This, &rect, Filter, upsideDown); + } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width || + rect.y2 - rect.y1 > Src->currentDesc.Height) { + TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n"); + fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter); + } else { + TRACE("Using hardware stretching to flip / stretch the texture\n"); + fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter); + } + + if(!(This->Flags & SFLAG_DONOTFREE)) { + HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + This->resource.allocatedMemory = NULL; + } else { + This->Flags &= ~SFLAG_INSYSMEM; + } + /* The texture is now most up to date - If the surface is a render target and has a drawable, this + * path is never entered + */ + This->Flags |= SFLAG_INTEXTURE; + + return WINED3D_OK; + } else if(Src) { + /* Blit from offscreen surface to render target */ + float glTexCoord[4]; + DWORD oldCKeyFlags = Src->CKeyFlags; + WINEDDCOLORKEY oldBltCKey = This->SrcBltCKey; + RECT SourceRectangle; + + TRACE("Blt from surface %p to rendertarget %p\n", Src, This); + + if(SrcRect) { + SourceRectangle.left = SrcRect->left; + SourceRectangle.right = SrcRect->right; + SourceRectangle.top = SrcRect->top; + SourceRectangle.bottom = SrcRect->bottom; + } else { + SourceRectangle.left = 0; + SourceRectangle.right = Src->currentDesc.Width; + SourceRectangle.top = 0; + SourceRectangle.bottom = Src->currentDesc.Height; + } + + if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) { + /* Fall back to software */ + WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src, + SourceRectangle.left, SourceRectangle.top, + SourceRectangle.right, SourceRectangle.bottom); + return WINED3DERR_INVALIDCALL; + } + + /* Color keying: Check if we have to do a color keyed blt, + * and if not check if a color key is activated. + * + * Just modify the color keying parameters in the surface and restore them afterwards + * The surface keeps track of the color key last used to load the opengl surface. + * PreLoad will catch the change to the flags and color key and reload if necessary. + */ + if(Flags & WINEDDBLT_KEYSRC) { + /* Use color key from surface */ + } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) { + /* Use color key from DDBltFx */ + Src->CKeyFlags |= WINEDDSD_CKSRCBLT; + This->SrcBltCKey = DDBltFx->ddckSrcColorkey; + } else { + /* Do not use color key */ + Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT; + } + + /* Now load the surface */ + IWineD3DSurface_PreLoad((IWineD3DSurface *) Src); + + + /* Activate the destination context, set it up for blitting */ + ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT); + ENTER_GL(); + + if(!dstSwapchain) { + TRACE("Drawing to offscreen buffer\n"); + glDrawBuffer(myDevice->offscreenBuffer); + checkGLcall("glDrawBuffer"); + } else { + GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This, (IWineD3DSwapChain *)dstSwapchain); + TRACE("Drawing to %#x buffer\n", buffer); + glDrawBuffer(buffer); + checkGLcall("glDrawBuffer"); + } + + /* Bind the texture */ + glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName); + checkGLcall("glBindTexture"); + + /* Filtering for StretchRect */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + minMipLookup[Filter][WINED3DTEXF_NONE]); + checkGLcall("glTexParameteri"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + checkGLcall("glTexEnvi"); + + /* This is for color keying */ + if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) { + glEnable(GL_ALPHA_TEST); + checkGLcall("glEnable GL_ALPHA_TEST"); + glAlphaFunc(GL_NOTEQUAL, 0.0); + checkGLcall("glAlphaFunc\n"); + } else { + glDisable(GL_ALPHA_TEST); + checkGLcall("glDisable GL_ALPHA_TEST"); + } + + /* Draw a textured quad + */ + glBegin(GL_QUADS); + + glColor3d(1.0f, 1.0f, 1.0f); + glTexCoord2f(glTexCoord[0], glTexCoord[2]); + glVertex3f(rect.x1, + rect.y1, + 0.0); + + glTexCoord2f(glTexCoord[0], glTexCoord[3]); + glVertex3f(rect.x1, rect.y2, 0.0); + + glTexCoord2f(glTexCoord[1], glTexCoord[3]); + glVertex3f(rect.x2, + rect.y2, + 0.0); + + glTexCoord2f(glTexCoord[1], glTexCoord[2]); + glVertex3f(rect.x2, + rect.y1, + 0.0); + glEnd(); + checkGLcall("glEnd"); + + if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) { + glDisable(GL_ALPHA_TEST); + checkGLcall("glDisable(GL_ALPHA_TEST)"); + } + + /* Unbind the texture */ + glBindTexture(GL_TEXTURE_2D, 0); + checkGLcall("glEnable glBindTexture"); + + /* The draw buffer should only need to be restored if we were drawing to the front buffer, and there is a back buffer. + * otherwise the context manager should choose between GL_BACK / offscreenDrawBuffer + */ + if(dstSwapchain && This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && dstSwapchain->backBuffer) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer"); + } + /* Restore the color key parameters */ + Src->CKeyFlags = oldCKeyFlags; + This->SrcBltCKey = oldBltCKey; + + LEAVE_GL(); + + /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */ + This->Flags &= ~SFLAG_INSYSMEM; + /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture + * is outdated now + */ + if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) { + This->Flags |= SFLAG_INDRAWABLE; + This->Flags &= ~SFLAG_INTEXTURE; + } else { + This->Flags |= SFLAG_INTEXTURE; + } + + return WINED3D_OK; + } else { + /* Source-Less Blit to render target */ + if (Flags & WINEDDBLT_COLORFILL) { + /* This is easy to handle for the D3D Device... */ + DWORD color; + + TRACE("Colorfill\n"); + + /* The color as given in the Blt function is in the format of the frame-buffer... + * 'clear' expect it in ARGB format => we need to do some conversion :-) + */ + if (This->resource.format == WINED3DFMT_P8) { + if (This->palette) { + color = ((0xFF000000) | + (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) | + (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) | + (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue)); + } else { + color = 0xFF000000; + } + } + else if (This->resource.format == WINED3DFMT_R5G6B5) { + if (DDBltFx->u5.dwFillColor == 0xFFFF) { + color = 0xFFFFFFFF; + } else { + color = ((0xFF000000) | + ((DDBltFx->u5.dwFillColor & 0xF800) << 8) | + ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) | + ((DDBltFx->u5.dwFillColor & 0x001F) << 3)); + } + } + else if ((This->resource.format == WINED3DFMT_R8G8B8) || + (This->resource.format == WINED3DFMT_X8R8G8B8) ) { + color = 0xFF000000 | DDBltFx->u5.dwFillColor; + } + else if (This->resource.format == WINED3DFMT_A8R8G8B8) { + color = DDBltFx->u5.dwFillColor; + } + else { + ERR("Wrong surface type for BLT override(Format doesn't match) !\n"); + return WINED3DERR_INVALIDCALL; + } + + TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice); + if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) { + glDrawBuffer(GL_BACK); + checkGLcall("glDrawBuffer(GL_BACK)"); + } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) { + glDrawBuffer(GL_FRONT); + checkGLcall("glDrawBuffer(GL_FRONT)"); + } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) { + glDrawBuffer(myDevice->offscreenBuffer); + checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)"); + } else { + TRACE("Surface is higher back buffer, falling back to software\n"); + return WINED3DERR_INVALIDCALL; + } + + TRACE("(%p) executing Render Target override, color = %x\n", This, color); + + IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice, + 1 /* Number of rectangles */, + &rect, + WINED3DCLEAR_TARGET, + color, + 0.0 /* Z */, + 0 /* Stencil */); + + /* Restore the original draw buffer */ + if(!dstSwapchain) { + glDrawBuffer(myDevice->offscreenBuffer); + } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) { + glDrawBuffer(GL_BACK); + } + vcheckGLcall("glDrawBuffer"); + + return WINED3D_OK; + } + } + + /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */ + TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n"); + return WINED3DERR_INVALIDCALL; +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx) +{ + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + + if (Flags & WINEDDBLT_DEPTHFILL) + return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice, + DestRect == NULL ? 0 : 1, + (WINED3DRECT *) DestRect, + WINED3DCLEAR_ZBUFFER, + 0x00000000, + (float) DDBltFx->u5.dwFillDepth / (float) MAXDWORD, + 0x00000000); + + FIXME("(%p): Unsupp depthstencil blit\n", This); + return WINED3DERR_INVALIDCALL; +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx); + TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage)); + + /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair, + * except depth blits, which seem to work + */ + if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) { + if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) { + TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) { + TRACE("Z Blit override handled the blit\n"); + return WINED3D_OK; + } + } + + /* Special cases for RenderTargets */ + if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) || + ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) { + if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK; + } + + /* For the rest call the X11 surface implementation. + * For RenderTargets this should be implemented OpenGL accelerated in BltOverride, + * other Blts are rather rare + */ + return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + TRACE("(%p)->(%x)\n", This, Flags); + + switch (Flags) + { + case WINEDDGBS_CANBLT: + case WINEDDGBS_ISBLTDONE: + return WINED3D_OK; + + default: + return WINED3DERR_INVALIDCALL; + } +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) { + /* XXX: DDERR_INVALIDSURFACETYPE */ + + TRACE("(%p)->(%08x)\n",iface,Flags); + switch (Flags) { + case WINEDDGFS_CANFLIP: + case WINEDDGFS_ISFLIPDONE: + return WINED3D_OK; + + default: + return WINED3DERR_INVALIDCALL; + } +} + +HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + TRACE("(%p)\n", This); + + /* D3D8 and 9 loose full devices, ddraw only surfaces */ + return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + TRACE("(%p)\n", This); + + /* So far we don't lose anything :) */ + This->Flags &= ~SFLAG_LOST; + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; + TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans); + + if(myDevice->inScene && + (iface == myDevice->stencilBufferTarget || + (Source && Source == myDevice->stencilBufferTarget))) { + TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + + /* Special cases for RenderTargets */ + if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) || + ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) { + + RECT SrcRect, DstRect; + DWORD Flags=0; + + if(rsrc) { + SrcRect.left = rsrc->left; + SrcRect.top= rsrc->top; + SrcRect.bottom = rsrc->bottom; + SrcRect.right = rsrc->right; + } else { + SrcRect.left = 0; + SrcRect.top = 0; + SrcRect.right = srcImpl->currentDesc.Width; + SrcRect.bottom = srcImpl->currentDesc.Height; + } + + DstRect.left = dstx; + DstRect.top=dsty; + DstRect.right = dstx + SrcRect.right - SrcRect.left; + DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top; + + /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */ + if(trans & WINEDDBLTFAST_SRCCOLORKEY) + Flags |= WINEDDBLT_KEYSRC; + if(trans & WINEDDBLTFAST_DESTCOLORKEY) + Flags |= WINEDDBLT_KEYDEST; + if(trans & WINEDDBLTFAST_WAIT) + Flags |= WINEDDBLT_WAIT; + if(trans & WINEDDBLTFAST_DONOTWAIT) + Flags |= WINEDDBLT_DONOTWAIT; + + if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK; + } + + + return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + TRACE("(%p)->(%p)\n", This, Pal); + + *Pal = (IWineD3DPalette *) This->palette; + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + RGBQUAD col[256]; + IWineD3DPaletteImpl *pal = This->palette; + unsigned int n; + TRACE("(%p)\n", This); + + if(This->resource.format == WINED3DFMT_P8 || + This->resource.format == WINED3DFMT_A8P8) + { + if(!This->Flags & SFLAG_INSYSMEM) { + FIXME("Palette changed with surface that does not have an up to date system memory copy\n"); + } + TRACE("Dirtifying surface\n"); + This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE); + } + + if(This->Flags & SFLAG_DIBSECTION) { + TRACE("(%p): Updating the hdc's palette\n", This); + for (n=0; n<256; n++) { + if(pal) { + col[n].rgbRed = pal->palents[n].peRed; + col[n].rgbGreen = pal->palents[n].peGreen; + col[n].rgbBlue = pal->palents[n].peBlue; + } else { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + /* Use the default device palette */ + col[n].rgbRed = device->palettes[device->currentPalette][n].peRed; + col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen; + col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue; + } + col[n].rgbReserved = 0; + } + SetDIBColorTable(This->hDC, 0, 256, col); + } + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal; + TRACE("(%p)->(%p)\n", This, Pal); + + if(This->palette != NULL) + if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) + This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE; + + if(PalImpl != NULL) { + if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) { + /* Set the device's main palette if the palette + * wasn't a primary palette before + */ + if(!(PalImpl->Flags & WINEDDPCAPS_PRIMARYSURFACE)) { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + unsigned int i; + + for(i=0; i < 256; i++) { + device->palettes[device->currentPalette][i] = PalImpl->palents[i]; + } + } + + (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE; + } + } + This->palette = PalImpl; + + return IWineD3DSurface_RealizePalette(iface); +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey); + + if ((Flags & WINEDDCKEY_COLORSPACE) != 0) { + FIXME(" colorkey value not supported (%08x) !\n", Flags); + return WINED3DERR_INVALIDCALL; + } + + /* Dirtify the surface, but only if a key was changed */ + if(CKey) { + switch (Flags & ~WINEDDCKEY_COLORSPACE) { + case WINEDDCKEY_DESTBLT: + This->DestBltCKey = *CKey; + This->CKeyFlags |= WINEDDSD_CKDESTBLT; + break; + + case WINEDDCKEY_DESTOVERLAY: + This->DestOverlayCKey = *CKey; + This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY; + break; + + case WINEDDCKEY_SRCOVERLAY: + This->SrcOverlayCKey = *CKey; + This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY; + break; + + case WINEDDCKEY_SRCBLT: + This->SrcBltCKey = *CKey; + This->CKeyFlags |= WINEDDSD_CKSRCBLT; + break; + } + } + else { + switch (Flags & ~WINEDDCKEY_COLORSPACE) { + case WINEDDCKEY_DESTBLT: + This->CKeyFlags &= ~WINEDDSD_CKDESTBLT; + break; + + case WINEDDCKEY_DESTOVERLAY: + This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY; + break; + + case WINEDDCKEY_SRCOVERLAY: + This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY; + break; + + case WINEDDCKEY_SRCBLT: + This->CKeyFlags &= ~WINEDDSD_CKSRCBLT; + break; + } + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) { + /** Check against the maximum texture sizes supported by the video card **/ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + unsigned int pow2Width, pow2Height; + const GlPixelFormatDesc *glDesc; + + getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc); + /* Setup some glformat defaults */ + This->glDescription.glFormat = glDesc->glFormat; + This->glDescription.glFormatInternal = glDesc->glInternal; + This->glDescription.glType = glDesc->glType; + + This->glDescription.textureName = 0; + This->glDescription.target = GL_TEXTURE_2D; + + /* Non-power2 support */ + if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) { + pow2Width = This->currentDesc.Width; + pow2Height = This->currentDesc.Height; + } else { + /* Find the nearest pow2 match */ + pow2Width = pow2Height = 1; + while (pow2Width < This->currentDesc.Width) pow2Width <<= 1; + while (pow2Height < This->currentDesc.Height) pow2Height <<= 1; + } + This->pow2Width = pow2Width; + This->pow2Height = pow2Height; + + if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) { + WINED3DFORMAT Format = This->resource.format; + /** TODO: add support for non power two compressed textures **/ + if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 + || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) { + FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n", + This, This->currentDesc.Width, This->currentDesc.Height); + return WINED3DERR_NOTAVAILABLE; + } + } + + if(pow2Width != This->currentDesc.Width || + pow2Height != This->currentDesc.Height) { + This->Flags |= SFLAG_NONPOW2; + } + + TRACE("%p\n", This); + if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) { + /* one of three options + 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow) + 2: Set the texture to the maximum size (bad idea) + 3: WARN and return WINED3DERR_NOTAVAILABLE; + 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target. + */ + WARN("(%p) Creating an oversized surface\n", This); + This->Flags |= SFLAG_OVERSIZE; + + /* This will be initialized on the first blt */ + This->glRect.left = 0; + This->glRect.top = 0; + This->glRect.right = 0; + This->glRect.bottom = 0; + } else { + /* No oversize, gl rect is the full texture size */ + This->Flags &= ~SFLAG_OVERSIZE; + This->glRect.left = 0; + This->glRect.top = 0; + This->glRect.right = This->pow2Width; + This->glRect.bottom = This->pow2Height; + } + + if(This->resource.allocatedMemory == NULL) { + /* Make sure memory exists from the start, and it is initialized properly. D3D initializes surfaces, + * gl does not, so we need to upload zeroes to init the gl texture. + */ + This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + 4); + } + This->Flags |= SFLAG_INSYSMEM; + + return WINED3D_OK; +} + +DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + DWORD ret; + TRACE("(%p)\n", This); + + /* DXTn formats don't have exact pitches as they are to the new row of blocks, + where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5) + ie pitch = (width/4) * bytes per block */ + if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */ + ret = ((This->currentDesc.Width + 3) >> 2) << 3; + else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 || + This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */ + ret = ((This->currentDesc.Width + 3) >> 2) << 4; + else { + unsigned char alignment = This->resource.wineD3DDevice->surface_alignment; + ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */ + ret = (ret + alignment - 1) & ~(alignment - 1); + } + TRACE("(%p) Returning %d\n", This, ret); + return ret; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + + FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y); + + if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) + { + TRACE("(%p): Not an overlay surface\n", This); + return WINEDDERR_NOTAOVERLAYSURFACE; + } + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + + FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y); + + if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) + { + TRACE("(%p): Not an overlay surface\n", This); + return WINEDDERR_NOTAOVERLAYSURFACE; + } + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref; + + FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl); + + if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) + { + TRACE("(%p): Not an overlay surface\n", This); + return WINEDDERR_NOTAOVERLAYSURFACE; + } + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) { + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface; + FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX); + + if(!(This->resource.usage & WINED3DUSAGE_OVERLAY)) + { + TRACE("(%p): Not an overlay surface\n", This); + return WINEDDERR_NOTAOVERLAYSURFACE; + } + + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + TRACE("(%p)->(%p)\n", This, clipper); + + This->clipper = clipper; + return WINED3D_OK; +} + +HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + TRACE("(%p)->(%p)\n", This, clipper); + + *clipper = This->clipper; + if(*clipper) { + IWineD3DClipper_AddRef(*clipper); + } + return WINED3D_OK; +} + +const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl = +{ + /* IUnknown */ + IWineD3DSurfaceImpl_QueryInterface, + IWineD3DSurfaceImpl_AddRef, + IWineD3DSurfaceImpl_Release, + /* IWineD3DResource */ + IWineD3DSurfaceImpl_GetParent, + IWineD3DSurfaceImpl_GetDevice, + IWineD3DSurfaceImpl_SetPrivateData, + IWineD3DSurfaceImpl_GetPrivateData, + IWineD3DSurfaceImpl_FreePrivateData, + IWineD3DSurfaceImpl_SetPriority, + IWineD3DSurfaceImpl_GetPriority, + IWineD3DSurfaceImpl_PreLoad, + IWineD3DSurfaceImpl_GetType, + /* IWineD3DSurface */ + IWineD3DSurfaceImpl_GetContainer, + IWineD3DSurfaceImpl_GetDesc, + IWineD3DSurfaceImpl_LockRect, + IWineD3DSurfaceImpl_UnlockRect, + IWineD3DSurfaceImpl_GetDC, + IWineD3DSurfaceImpl_ReleaseDC, + IWineD3DSurfaceImpl_Flip, + IWineD3DSurfaceImpl_Blt, + IWineD3DSurfaceImpl_GetBltStatus, + IWineD3DSurfaceImpl_GetFlipStatus, + IWineD3DSurfaceImpl_IsLost, + IWineD3DSurfaceImpl_Restore, + IWineD3DSurfaceImpl_BltFast, + IWineD3DSurfaceImpl_GetPalette, + IWineD3DSurfaceImpl_SetPalette, + IWineD3DSurfaceImpl_RealizePalette, + IWineD3DSurfaceImpl_SetColorKey, + IWineD3DSurfaceImpl_GetPitch, + IWineD3DSurfaceImpl_SetMem, + IWineD3DSurfaceImpl_SetOverlayPosition, + IWineD3DSurfaceImpl_GetOverlayPosition, + IWineD3DSurfaceImpl_UpdateOverlayZOrder, + IWineD3DSurfaceImpl_UpdateOverlay, + IWineD3DSurfaceImpl_SetClipper, + IWineD3DSurfaceImpl_GetClipper, + /* Internal use: */ + IWineD3DSurfaceImpl_AddDirtyRect, + IWineD3DSurfaceImpl_LoadTexture, + IWineD3DSurfaceImpl_SaveSnapshot, + IWineD3DSurfaceImpl_SetContainer, + IWineD3DSurfaceImpl_SetGlTextureDesc, + IWineD3DSurfaceImpl_GetGlDesc, + IWineD3DSurfaceImpl_GetData, + IWineD3DSurfaceImpl_SetFormat, + IWineD3DSurfaceImpl_PrivateSetup +}; diff --git a/reactos/dll/directx/wine/wined3d/surface_gdi.c b/reactos/dll/directx/wine/wined3d/surface_gdi.c new file mode 100644 index 00000000000..9f498825cdc --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/surface_gdi.c @@ -0,0 +1,1605 @@ +/* + * 2D Surface implementation without OpenGL + * + * Copyright 1997-2000 Marcus Meissner + * Copyright 1998-2000 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * Copyright 2002-2005 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006-2008 Stefan Dösinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" +#include "wined3d_private.h" + +#include +#include + +/* Use the d3d_surface debug channel to have one channel for all surfaces */ +WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface); +WINE_DECLARE_DEBUG_CHANNEL(fps); + +/***************************************************************************** + * x11_copy_to_screen + * + * Helper function that blts the front buffer contents to the target window + * + * Params: + * This: Surface to copy from + * rc: Rectangle to copy + * + *****************************************************************************/ +static void +x11_copy_to_screen(IWineD3DSurfaceImpl *This, + LPRECT rc) +{ + if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) + { + POINT offset = {0,0}; + HWND hDisplayWnd; + HDC hDisplayDC; + HDC hSurfaceDC = 0; + RECT drawrect; + TRACE("(%p)->(%p): Copying to screen\n", This, rc); + + hSurfaceDC = This->hDC; + + hDisplayWnd = This->resource.wineD3DDevice->ddraw_window; + hDisplayDC = GetDCEx(hDisplayWnd, 0, DCX_CLIPSIBLINGS|DCX_CACHE); + if(rc) + { + TRACE(" copying rect (%d,%d)->(%d,%d), offset (%d,%d)\n", + rc->left, rc->top, rc->right, rc->bottom, offset.x, offset.y); + } + + /* Front buffer coordinates are screen coordinates. Map them to the destination + * window if not fullscreened + */ + if(!This->resource.wineD3DDevice->ddraw_fullscreen) { + ClientToScreen(hDisplayWnd, &offset); + } +#if 0 + /* FIXME: this doesn't work... if users really want to run + * X in 8bpp, then we need to call directly into display.drv + * (or Wine's equivalent), and force a private colormap + * without default entries. */ + if (This->palette) { + SelectPalette(hDisplayDC, This->palette->hpal, FALSE); + RealizePalette(hDisplayDC); /* sends messages => deadlocks */ + } +#endif + drawrect.left = 0; + drawrect.right = This->currentDesc.Width; + drawrect.top = 0; + drawrect.bottom = This->currentDesc.Height; + +#if 0 + /* TODO: Support clippers */ + if (This->clipper) + { + RECT xrc; + HWND hwnd = ((IWineD3DClipperImpl *) This->clipper)->hWnd; + if (hwnd && GetClientRect(hwnd,&xrc)) + { + OffsetRect(&xrc,offset.x,offset.y); + IntersectRect(&drawrect,&drawrect,&xrc); + } + } +#endif + if (rc) + { + IntersectRect(&drawrect,&drawrect,rc); + } + else + { + /* Only use this if the caller did not pass a rectangle, since + * due to double locking this could be the wrong one ... + */ + if (This->lockedRect.left != This->lockedRect.right) + { + IntersectRect(&drawrect,&drawrect,&This->lockedRect); + } + } + + BitBlt(hDisplayDC, + drawrect.left-offset.x, drawrect.top-offset.y, + drawrect.right-drawrect.left, drawrect.bottom-drawrect.top, + hSurfaceDC, + drawrect.left, drawrect.top, + SRCCOPY); + ReleaseDC(hDisplayWnd, hDisplayDC); + } +} + +/***************************************************************************** + * IWineD3DSurface::PreLoad, GDI version + * + * This call is unsupported on GDI surfaces, if it's called something went + * wrong in the parent library. Write an informative warning + * + *****************************************************************************/ +static void WINAPI +IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface) +{ + ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface); + ERR("(%p): Most likely the parent library did something wrong.\n", iface); + ERR("(%p): Please report to wine-devel\n", iface); +} + +/***************************************************************************** + * IWineD3DSurface::LockRect, GDI version + * + * Locks the surface and returns a pointer to the surface memory + * + * Params: + * pLockedRect: Address to return the locking info at + * pRect: Rectangle to lock + * Flags: Some flags + * + * Returns: + * WINED3D_OK on success + * WINED3DERR_INVALIDCALL on errors + * + *****************************************************************************/ +static HRESULT WINAPI +IWineGDISurfaceImpl_LockRect(IWineD3DSurface *iface, + WINED3DLOCKED_RECT* pLockedRect, + CONST RECT* pRect, + DWORD Flags) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + + /* Already locked? */ + if(This->Flags & SFLAG_LOCKED) + { + ERR("(%p) Surface already locked\n", This); + /* What should I return here? */ + return WINED3DERR_INVALIDCALL; + } + + if (!(This->Flags & SFLAG_LOCKABLE)) + { + /* This is some GL specific thing, see the OpenGL version of + * this method, but check for the flag and write a trace + */ + TRACE("Warning: trying to lock unlockable surf@%p\n", This); + } + + TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", + This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); + + if(!This->resource.allocatedMemory) { + HDC hdc; + HRESULT hr; + /* This happens on gdi surfaces if the application set a user pointer and resets it. + * Recreate the DIB section + */ + hr = IWineD3DSurface_GetDC(iface, &hdc); /* will recursively call lockrect, do not set the LOCKED flag to this line */ + if(hr != WINED3D_OK) return hr; + hr = IWineD3DSurface_ReleaseDC(iface, hdc); + if(hr != WINED3D_OK) return hr; + } + + pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface); + + if (NULL == pRect) + { + pLockedRect->pBits = This->resource.allocatedMemory; + This->lockedRect.left = 0; + This->lockedRect.top = 0; + This->lockedRect.right = This->currentDesc.Width; + This->lockedRect.bottom = This->currentDesc.Height; + + TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", + &This->lockedRect, This->lockedRect.left, This->lockedRect.top, + This->lockedRect.right, This->lockedRect.bottom); + } + else + { + TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", + pRect, pRect->left, pRect->top, pRect->right, pRect->bottom); + + if (This->resource.format == WINED3DFMT_DXT1) + { + /* DXT1 is half byte per pixel */ + pLockedRect->pBits = This->resource.allocatedMemory + + (pLockedRect->Pitch * pRect->top) + + ((pRect->left * This->bytesPerPixel / 2)); + } + else + { + pLockedRect->pBits = This->resource.allocatedMemory + + (pLockedRect->Pitch * pRect->top) + + (pRect->left * This->bytesPerPixel); + } + This->lockedRect.left = pRect->left; + This->lockedRect.top = pRect->top; + This->lockedRect.right = pRect->right; + This->lockedRect.bottom = pRect->bottom; + } + + /* No dirtifying is needed for this surface implementation */ + TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch); + + This->Flags |= SFLAG_LOCKED; + return WINED3D_OK; +} + +/***************************************************************************** + * IWineD3DSurface::UnlockRect, GDI version + * + * Unlocks a surface. This implementation doesn't do much, except updating + * the window if the front buffer is unlocked + * + * Returns: + * WINED3D_OK on success + * WINED3DERR_INVALIDCALL on failure + * + *****************************************************************************/ +static HRESULT WINAPI +IWineGDISurfaceImpl_UnlockRect(IWineD3DSurface *iface) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + IWineD3DDeviceImpl *dev = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice; + TRACE("(%p)\n", This); + + if (!(This->Flags & SFLAG_LOCKED)) + { + WARN("trying to Unlock an unlocked surf@%p\n", This); + return WINED3DERR_INVALIDCALL; + } + + /* Can be useful for debugging */ +#if 0 + { + static unsigned int gen = 0; + char buffer[4096]; + ++gen; + if ((gen % 10) == 0) { + snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen); + IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer); + } + /* + * debugging crash code + if (gen == 250) { + void** test = NULL; + *test = 0; + } + */ + } +#endif + + /* Update the screen */ + if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary) + { + x11_copy_to_screen(This, &This->lockedRect); + } + + This->Flags &= ~SFLAG_LOCKED; + memset(&This->lockedRect, 0, sizeof(RECT)); + return WINED3D_OK; +} + +/***************************************************************************** + * IWineD3DSurface::Flip, GDI version + * + * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by + * the parent library. This implementation changes the data pointers of the + * surfaces and copies the new front buffer content to the screen + * + * Params: + * override: Flipping target(e.g. back buffer) + * + * Returns: + * WINED3D_OK on success + * + *****************************************************************************/ +static HRESULT WINAPI +IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, + IWineD3DSurface *override, + DWORD Flags) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DSurfaceImpl *Target = (IWineD3DSurfaceImpl *) override; + TRACE("(%p)->(%p,%x)\n", This, override, Flags); + + TRACE("(%p) Flipping to surface %p\n", This, Target); + + if(Target == NULL) + { + ERR("(%p): Can't flip without a target\n", This); + return WINED3DERR_INVALIDCALL; + } + + /* Flip the DC */ + { + HDC tmp; + tmp = This->hDC; + This->hDC = Target->hDC; + Target->hDC = tmp; + } + + /* Flip the DIBsection */ + { + HBITMAP tmp; + tmp = This->dib.DIBsection; + This->dib.DIBsection = Target->dib.DIBsection; + Target->dib.DIBsection = tmp; + } + + /* Flip the surface data */ + { + void* tmp; + + tmp = This->dib.bitmap_data; + This->dib.bitmap_data = Target->dib.bitmap_data; + Target->dib.bitmap_data = tmp; + + tmp = This->resource.allocatedMemory; + This->resource.allocatedMemory = Target->resource.allocatedMemory; + Target->resource.allocatedMemory = tmp; + } + + /* client_memory should not be different, but just in case */ + { + BOOL tmp; + tmp = This->dib.client_memory; + This->dib.client_memory = Target->dib.client_memory; + Target->dib.client_memory = tmp; + } + + /* Useful for debugging */ +#if 0 + { + static unsigned int gen = 0; + char buffer[4096]; + ++gen; + if ((gen % 10) == 0) { + snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen); + IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer); + } + /* + * debugging crash code + if (gen == 250) { + void** test = NULL; + *test = 0; + } + */ + } +#endif + + /* Update the screen */ + x11_copy_to_screen(This, NULL); + + /* FPS support */ + if (TRACE_ON(fps)) + { + static long prev_time, frames; + + DWORD time = GetTickCount(); + frames++; + /* every 1.5 seconds */ + if (time - prev_time > 1500) { + TRACE_(fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time)); + prev_time = time; + frames = 0; + } + } + + return WINED3D_OK; +} + +/***************************************************************************** + * _Blt_ColorFill + * + * Helper function that fills a memory area with a specific color + * + * Params: + * buf: memory address to start filling at + * width, height: Dimensions of the area to fill + * bpp: Bit depth of the surface + * lPitch: pitch of the surface + * color: Color to fill with + * + *****************************************************************************/ +static HRESULT +_Blt_ColorFill(BYTE *buf, + int width, int height, + int bpp, LONG lPitch, + DWORD color) +{ + int x, y; + LPBYTE first; + + /* Do first row */ + +#define COLORFILL_ROW(type) \ +{ \ + type *d = (type *) buf; \ + for (x = 0; x < width; x++) \ + d[x] = (type) color; \ + break; \ +} + switch(bpp) + { + case 1: COLORFILL_ROW(BYTE) + case 2: COLORFILL_ROW(WORD) + case 3: + { + BYTE *d = (BYTE *) buf; + for (x = 0; x < width; x++,d+=3) + { + d[0] = (color ) & 0xFF; + d[1] = (color>> 8) & 0xFF; + d[2] = (color>>16) & 0xFF; + } + break; + } + case 4: COLORFILL_ROW(DWORD) + default: + FIXME("Color fill not implemented for bpp %d!\n", bpp*8); + return WINED3DERR_NOTAVAILABLE; + } + +#undef COLORFILL_ROW + + /* Now copy first row */ + first = buf; + for (y = 1; y < height; y++) + { + buf += lPitch; + memcpy(buf, first, width * bpp); + } + return WINED3D_OK; +} + +/***************************************************************************** + * IWineD3DSurface::Blt, GDI version + * + * Performs blits to a surface, eigher from a source of source-less blts + * This is the main functionality of DirectDraw + * + * Params: + * DestRect: Destination rectangle to write to + * SrcSurface: Source surface, can be NULL + * SrcRect: Source rectangle + *****************************************************************************/ +HRESULT WINAPI +IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface, + RECT *DestRect, + IWineD3DSurface *SrcSurface, + RECT *SrcRect, + DWORD Flags, + WINEDDBLTFX *DDBltFx, + WINED3DTEXTUREFILTERTYPE Filter) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; + RECT xdst,xsrc; + HRESULT ret = WINED3D_OK; + WINED3DLOCKED_RECT dlock, slock; + WINED3DFORMAT dfmt = WINED3DFMT_UNKNOWN, sfmt = WINED3DFMT_UNKNOWN; + int bpp, srcheight, srcwidth, dstheight, dstwidth, width; + int x, y; + const StaticPixelFormatDesc *sEntry, *dEntry; + LPBYTE dbuf, sbuf; + TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx); + + if (TRACE_ON(d3d_surface)) + { + if (DestRect) TRACE("\tdestrect :%dx%d-%dx%d\n", + DestRect->left, DestRect->top, DestRect->right, DestRect->bottom); + if (SrcRect) TRACE("\tsrcrect :%dx%d-%dx%d\n", + SrcRect->left, SrcRect->top, SrcRect->right, SrcRect->bottom); +#if 0 + TRACE("\tflags: "); + DDRAW_dump_DDBLT(Flags); + if (Flags & WINEDDBLT_DDFX) + { + TRACE("\tblitfx: "); + DDRAW_dump_DDBLTFX(DDBltFx->dwDDFX); + } +#endif + } + + if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED))) + { + WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n"); + return WINEDDERR_SURFACEBUSY; + } + + if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) { + /* Can happen when d3d9 apps do a StretchRect call which isn't handled in gl */ + FIXME("Filters not supported in software blit\n"); + } + + if (Src == This) + { + IWineD3DSurface_LockRect(iface, &dlock, NULL, 0); + dfmt = This->resource.format; + slock = dlock; + sfmt = dfmt; + sEntry = getFormatDescEntry(sfmt, NULL, NULL); + dEntry = sEntry; + } + else + { + if (Src) + { + IWineD3DSurface_LockRect(SrcSurface, &slock, NULL, WINED3DLOCK_READONLY); + sfmt = Src->resource.format; + } + sEntry = getFormatDescEntry(sfmt, NULL, NULL); + dfmt = This->resource.format; + dEntry = getFormatDescEntry(dfmt, NULL, NULL); + IWineD3DSurface_LockRect(iface, &dlock,NULL,0); + } + + if (!DDBltFx || !(DDBltFx->dwDDFX)) Flags &= ~WINEDDBLT_DDFX; + + if (sEntry->isFourcc && dEntry->isFourcc) + { + if (sfmt != dfmt) + { + FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n"); + ret = WINED3DERR_WRONGTEXTUREFORMAT; + goto release; + } + memcpy(dlock.pBits, slock.pBits, This->resource.size); + goto release; + } + + if (sEntry->isFourcc && !dEntry->isFourcc) + { + FIXME("DXTC decompression not supported right now\n"); + goto release; + } + + if (DestRect) + { + memcpy(&xdst,DestRect,sizeof(xdst)); + } + else + { + xdst.top = 0; + xdst.bottom = This->currentDesc.Height; + xdst.left = 0; + xdst.right = This->currentDesc.Width; + } + + if (SrcRect) + { + memcpy(&xsrc,SrcRect,sizeof(xsrc)); + } + else + { + if (Src) + { + xsrc.top = 0; + xsrc.bottom = Src->currentDesc.Height; + xsrc.left = 0; + xsrc.right = Src->currentDesc.Width; + } + else + { + memset(&xsrc,0,sizeof(xsrc)); + } + } + + /* First check for the validity of source / destination rectangles. This was + verified using a test application + by MSDN. + */ + if ((Src != NULL) && + ((xsrc.bottom > Src->currentDesc.Height) || (xsrc.bottom < 0) || + (xsrc.top > Src->currentDesc.Height) || (xsrc.top < 0) || + (xsrc.left > Src->currentDesc.Width) || (xsrc.left < 0) || + (xsrc.right > Src->currentDesc.Width) || (xsrc.right < 0) || + (xsrc.right < xsrc.left) || (xsrc.bottom < xsrc.top))) + { + WARN("Application gave us bad source rectangle for Blt.\n"); + ret = WINEDDERR_INVALIDRECT; + goto release; + } + /* For the Destination rect, it can be out of bounds on the condition that a clipper + is set for the given surface. + */ + if ((/*This->clipper == NULL*/ TRUE) && + ((xdst.bottom > This->currentDesc.Height) || (xdst.bottom < 0) || + (xdst.top > This->currentDesc.Height) || (xdst.top < 0) || + (xdst.left > This->currentDesc.Width) || (xdst.left < 0) || + (xdst.right > This->currentDesc.Width) || (xdst.right < 0) || + (xdst.right < xdst.left) || (xdst.bottom < xdst.top))) + { + WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n"); + ret = WINEDDERR_INVALIDRECT; + goto release; + } + + /* Now handle negative values in the rectangles. Warning: only supported for now + in the 'simple' cases (ie not in any stretching / rotation cases). + + First, the case where nothing is to be done. + */ + if (((xdst.bottom <= 0) || (xdst.right <= 0) || + (xdst.top >= (int) This->currentDesc.Height) || + (xdst.left >= (int) This->currentDesc.Width)) || + ((Src != NULL) && + ((xsrc.bottom <= 0) || (xsrc.right <= 0) || + (xsrc.top >= (int) Src->currentDesc.Height) || + (xsrc.left >= (int) Src->currentDesc.Width)) )) + { + TRACE("Nothing to be done !\n"); + goto release; + } + + /* The easy case : the source-less blits.... */ + if (Src == NULL) + { + RECT full_rect; + RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */ + + full_rect.left = 0; + full_rect.top = 0; + full_rect.right = This->currentDesc.Width; + full_rect.bottom = This->currentDesc.Height; + IntersectRect(&temp_rect, &full_rect, &xdst); + xdst = temp_rect; + } + else + { + /* Only handle clipping on the destination rectangle */ + int clip_horiz = (xdst.left < 0) || (xdst.right > (int) This->currentDesc.Width ); + int clip_vert = (xdst.top < 0) || (xdst.bottom > (int) This->currentDesc.Height); + if (clip_vert || clip_horiz) + { + /* Now check if this is a special case or not... */ + if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) || + (((xdst.right - xdst.left) != (xsrc.right - xsrc.left)) && clip_horiz) || + (Flags & WINEDDBLT_DDFX)) + { + WARN("Out of screen rectangle in special case. Not handled right now.\n"); + goto release; + } + + if (clip_horiz) + { + if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; } + if (xdst.right > This->currentDesc.Width) + { + xsrc.right -= (xdst.right - (int) This->currentDesc.Width); + xdst.right = (int) This->currentDesc.Width; + } + } + if (clip_vert) + { + if (xdst.top < 0) + { + xsrc.top -= xdst.top; + xdst.top = 0; + } + if (xdst.bottom > This->currentDesc.Height) + { + xsrc.bottom -= (xdst.bottom - (int) This->currentDesc.Height); + xdst.bottom = (int) This->currentDesc.Height; + } + } + /* And check if after clipping something is still to be done... */ + if ((xdst.bottom <= 0) || (xdst.right <= 0) || + (xdst.top >= (int) This->currentDesc.Height) || + (xdst.left >= (int) This->currentDesc.Width) || + (xsrc.bottom <= 0) || (xsrc.right <= 0) || + (xsrc.top >= (int) Src->currentDesc.Height) || + (xsrc.left >= (int) Src->currentDesc.Width)) + { + TRACE("Nothing to be done after clipping !\n"); + goto release; + } + } + } + + bpp = This->bytesPerPixel; + srcheight = xsrc.bottom - xsrc.top; + srcwidth = xsrc.right - xsrc.left; + dstheight = xdst.bottom - xdst.top; + dstwidth = xdst.right - xdst.left; + width = (xdst.right - xdst.left) * bpp; + + assert(width <= dlock.Pitch); + + dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp); + + if (Flags & WINEDDBLT_WAIT) + { + Flags &= ~WINEDDBLT_WAIT; + } + if (Flags & WINEDDBLT_ASYNC) + { + static BOOL displayed = FALSE; + if (!displayed) + FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n"); + displayed = TRUE; + Flags &= ~WINEDDBLT_ASYNC; + } + if (Flags & WINEDDBLT_DONOTWAIT) + { + /* WINEDDBLT_DONOTWAIT appeared in DX7 */ + static BOOL displayed = FALSE; + if (!displayed) + FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n"); + displayed = TRUE; + Flags &= ~WINEDDBLT_DONOTWAIT; + } + + /* First, all the 'source-less' blits */ + if (Flags & WINEDDBLT_COLORFILL) + { + ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, + dlock.Pitch, DDBltFx->u5.dwFillColor); + Flags &= ~WINEDDBLT_COLORFILL; + } + + if (Flags & WINEDDBLT_DEPTHFILL) + { + FIXME("DDBLT_DEPTHFILL needs to be implemented!\n"); + } + if (Flags & WINEDDBLT_ROP) + { + /* Catch some degenerate cases here */ + switch(DDBltFx->dwROP) + { + case BLACKNESS: + ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0); + break; + case 0xAA0029: /* No-op */ + break; + case WHITENESS: + ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0); + break; + case SRCCOPY: /* well, we do that below ? */ + break; + default: + FIXME("Unsupported raster op: %08x Pattern: %p\n", DDBltFx->dwROP, DDBltFx->u5.lpDDSPattern); + goto error; + } + Flags &= ~WINEDDBLT_ROP; + } + if (Flags & WINEDDBLT_DDROPS) + { + FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", DDBltFx->dwDDROP, DDBltFx->u5.lpDDSPattern); + } + /* Now the 'with source' blits */ + if (Src) + { + LPBYTE sbase; + int sx, xinc, sy, yinc; + + if (!dstwidth || !dstheight) /* hmm... stupid program ? */ + goto release; + sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp; + xinc = (srcwidth << 16) / dstwidth; + yinc = (srcheight << 16) / dstheight; + + if (!Flags) + { + /* No effects, we can cheat here */ + if (dstwidth == srcwidth) + { + if (dstheight == srcheight) + { + /* No stretching in either direction. This needs to be as + * fast as possible */ + sbuf = sbase; + + /* check for overlapping surfaces */ + if (SrcSurface != iface || xdst.top < xsrc.top || + xdst.right <= xsrc.left || xsrc.right <= xdst.left) + { + /* no overlap, or dst above src, so copy from top downwards */ + for (y = 0; y < dstheight; y++) + { + memcpy(dbuf, sbuf, width); + sbuf += slock.Pitch; + dbuf += dlock.Pitch; + } + } + else if (xdst.top > xsrc.top) /* copy from bottom upwards */ + { + sbuf += (slock.Pitch*dstheight); + dbuf += (dlock.Pitch*dstheight); + for (y = 0; y < dstheight; y++) + { + sbuf -= slock.Pitch; + dbuf -= dlock.Pitch; + memcpy(dbuf, sbuf, width); + } + } + else /* src and dst overlapping on the same line, use memmove */ + { + for (y = 0; y < dstheight; y++) + { + memmove(dbuf, sbuf, width); + sbuf += slock.Pitch; + dbuf += dlock.Pitch; + } + } + } else { + /* Stretching in Y direction only */ + for (y = sy = 0; y < dstheight; y++, sy += yinc) { + sbuf = sbase + (sy >> 16) * slock.Pitch; + memcpy(dbuf, sbuf, width); + dbuf += dlock.Pitch; + } + } + } + else + { + /* Stretching in X direction */ + int last_sy = -1; + for (y = sy = 0; y < dstheight; y++, sy += yinc) + { + sbuf = sbase + (sy >> 16) * slock.Pitch; + + if ((sy >> 16) == (last_sy >> 16)) + { + /* this sourcerow is the same as last sourcerow - + * copy already stretched row + */ + memcpy(dbuf, dbuf - dlock.Pitch, width); + } + else + { +#define STRETCH_ROW(type) { \ + type *s = (type *) sbuf, *d = (type *) dbuf; \ + for (x = sx = 0; x < dstwidth; x++, sx += xinc) \ + d[x] = s[sx >> 16]; \ + break; } + + switch(bpp) + { + case 1: STRETCH_ROW(BYTE) + case 2: STRETCH_ROW(WORD) + case 4: STRETCH_ROW(DWORD) + case 3: + { + LPBYTE s,d = dbuf; + for (x = sx = 0; x < dstwidth; x++, sx+= xinc) + { + DWORD pixel; + + s = sbuf+3*(sx>>16); + pixel = s[0]|(s[1]<<8)|(s[2]<<16); + d[0] = (pixel )&0xff; + d[1] = (pixel>> 8)&0xff; + d[2] = (pixel>>16)&0xff; + d+=3; + } + break; + } + default: + FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8); + ret = WINED3DERR_NOTAVAILABLE; + goto error; + } +#undef STRETCH_ROW + } + dbuf += dlock.Pitch; + last_sy = sy; + } + } + } + else + { + LONG dstyinc = dlock.Pitch, dstxinc = bpp; + DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF; + DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF; + if (Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE)) + { + /* The color keying flags are checked for correctness in ddraw */ + if (Flags & WINEDDBLT_KEYSRC) + { + keylow = Src->SrcBltCKey.dwColorSpaceLowValue; + keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue; + } + else if (Flags & WINEDDBLT_KEYSRCOVERRIDE) + { + keylow = DDBltFx->ddckSrcColorkey.dwColorSpaceLowValue; + keyhigh = DDBltFx->ddckSrcColorkey.dwColorSpaceHighValue; + } + + if (Flags & WINEDDBLT_KEYDEST) + { + /* Destination color keys are taken from the source surface ! */ + destkeylow = Src->DestBltCKey.dwColorSpaceLowValue; + destkeyhigh = Src->DestBltCKey.dwColorSpaceHighValue; + } + else if (Flags & WINEDDBLT_KEYDESTOVERRIDE) + { + destkeylow = DDBltFx->ddckDestColorkey.dwColorSpaceLowValue; + destkeyhigh = DDBltFx->ddckDestColorkey.dwColorSpaceHighValue; + } + + if(bpp == 1) + { + keymask = 0xff; + } + else + { + keymask = sEntry->redMask | + sEntry->greenMask | + sEntry->blueMask; + } + Flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE); + } + + if (Flags & WINEDDBLT_DDFX) + { + LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp; + LONG tmpxy; + dTopLeft = dbuf; + dTopRight = dbuf+((dstwidth-1)*bpp); + dBottomLeft = dTopLeft+((dstheight-1)*dlock.Pitch); + dBottomRight = dBottomLeft+((dstwidth-1)*bpp); + + if (DDBltFx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY) + { + /* I don't think we need to do anything about this flag */ + WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n"); + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT) + { + tmp = dTopRight; + dTopRight = dTopLeft; + dTopLeft = tmp; + tmp = dBottomRight; + dBottomRight = dBottomLeft; + dBottomLeft = tmp; + dstxinc = dstxinc *-1; + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN) + { + tmp = dTopLeft; + dTopLeft = dBottomLeft; + dBottomLeft = tmp; + tmp = dTopRight; + dTopRight = dBottomRight; + dBottomRight = tmp; + dstyinc = dstyinc *-1; + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_NOTEARING) + { + /* I don't think we need to do anything about this flag */ + WARN("Flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n"); + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE180) + { + tmp = dBottomRight; + dBottomRight = dTopLeft; + dTopLeft = tmp; + tmp = dBottomLeft; + dBottomLeft = dTopRight; + dTopRight = tmp; + dstxinc = dstxinc * -1; + dstyinc = dstyinc * -1; + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE270) + { + tmp = dTopLeft; + dTopLeft = dBottomLeft; + dBottomLeft = dBottomRight; + dBottomRight = dTopRight; + dTopRight = tmp; + tmpxy = dstxinc; + dstxinc = dstyinc; + dstyinc = tmpxy; + dstxinc = dstxinc * -1; + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_ROTATE90) + { + tmp = dTopLeft; + dTopLeft = dTopRight; + dTopRight = dBottomRight; + dBottomRight = dBottomLeft; + dBottomLeft = tmp; + tmpxy = dstxinc; + dstxinc = dstyinc; + dstyinc = tmpxy; + dstyinc = dstyinc * -1; + } + if (DDBltFx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST) + { + /* I don't think we need to do anything about this flag */ + WARN("Flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n"); + } + dbuf = dTopLeft; + Flags &= ~(WINEDDBLT_DDFX); + } + +#define COPY_COLORKEY_FX(type) { \ + type *s, *d = (type *) dbuf, *dx, tmp; \ + for (y = sy = 0; y < dstheight; y++, sy += yinc) { \ + s = (type*)(sbase + (sy >> 16) * slock.Pitch); \ + dx = d; \ + for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \ + tmp = s[sx >> 16]; \ + if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) && \ + ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) { \ + dx[0] = tmp; \ + } \ + dx = (type*)(((LPBYTE)dx)+dstxinc); \ + } \ + d = (type*)(((LPBYTE)d)+dstyinc); \ + } \ + break; } + + switch (bpp) { + case 1: COPY_COLORKEY_FX(BYTE) + case 2: COPY_COLORKEY_FX(WORD) + case 4: COPY_COLORKEY_FX(DWORD) + case 3: + { + LPBYTE s,d = dbuf, dx; + for (y = sy = 0; y < dstheight; y++, sy += yinc) + { + sbuf = sbase + (sy >> 16) * slock.Pitch; + dx = d; + for (x = sx = 0; x < dstwidth; x++, sx+= xinc) + { + DWORD pixel, dpixel = 0; + s = sbuf+3*(sx>>16); + pixel = s[0]|(s[1]<<8)|(s[2]<<16); + dpixel = dx[0]|(dx[1]<<8)|(dx[2]<<16); + if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh) && + ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh)) + { + dx[0] = (pixel )&0xff; + dx[1] = (pixel>> 8)&0xff; + dx[2] = (pixel>>16)&0xff; + } + dx+= dstxinc; + } + d += dstyinc; + } + break; + } + default: + FIXME("%s color-keyed blit not implemented for bpp %d!\n", + (Flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp*8); + ret = WINED3DERR_NOTAVAILABLE; + goto error; +#undef COPY_COLORKEY_FX + } + } + } + +error: + if (Flags && FIXME_ON(d3d_surface)) + { + FIXME("\tUnsupported flags: %08x\n", Flags); + } + +release: + IWineD3DSurface_UnlockRect(iface); + if (SrcSurface && SrcSurface != iface) IWineD3DSurface_UnlockRect(SrcSurface); + return ret; +} + +/***************************************************************************** + * IWineD3DSurface::BltFast, GDI version + * + * This is the software implementation of BltFast, as used by GDI surfaces + * and as a fallback for OpenGL surfaces. This code is taken from the old + * DirectDraw code, and was originally written by TransGaming. + * + * Params: + * dstx: + * dsty: + * Source: Source surface to copy from + * rsrc: Source rectangle + * trans: Some Flags + * + * Returns: + * WINED3D_OK on success + * + *****************************************************************************/ +HRESULT WINAPI +IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface, + DWORD dstx, + DWORD dsty, + IWineD3DSurface *Source, + RECT *rsrc, + DWORD trans) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) Source; + + int bpp, w, h, x, y; + WINED3DLOCKED_RECT dlock,slock; + HRESULT ret = WINED3D_OK; + RECT rsrc2; + RECT lock_src, lock_dst, lock_union; + BYTE *sbuf, *dbuf; + const StaticPixelFormatDesc *sEntry, *dEntry; + + if (TRACE_ON(d3d_surface)) + { + TRACE("(%p)->(%d,%d,%p,%p,%08x)\n", This,dstx,dsty,Src,rsrc,trans); + + if (rsrc) + { + TRACE("\tsrcrect: %dx%d-%dx%d\n",rsrc->left,rsrc->top, + rsrc->right,rsrc->bottom); + } + else + { + TRACE(" srcrect: NULL\n"); + } + } + + if ((This->Flags & SFLAG_LOCKED) || + ((Src != NULL) && (Src->Flags & SFLAG_LOCKED))) + { + WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n"); + return WINEDDERR_SURFACEBUSY; + } + + if (!rsrc) + { + WARN("rsrc is NULL!\n"); + rsrc = &rsrc2; + rsrc->left = 0; + rsrc->top = 0; + rsrc->right = Src->currentDesc.Width; + rsrc->bottom = Src->currentDesc.Height; + } + + /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate.*/ + if ((rsrc->bottom > Src->currentDesc.Height) || (rsrc->bottom < 0) || + (rsrc->top > Src->currentDesc.Height) || (rsrc->top < 0) || + (rsrc->left > Src->currentDesc.Width) || (rsrc->left < 0) || + (rsrc->right > Src->currentDesc.Width) || (rsrc->right < 0) || + (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top)) + { + WARN("Application gave us bad source rectangle for BltFast.\n"); + return WINEDDERR_INVALIDRECT; + } + + h = rsrc->bottom - rsrc->top; + if (h > This->currentDesc.Height-dsty) h = This->currentDesc.Height-dsty; + if (h > Src->currentDesc.Height-rsrc->top) h=Src->currentDesc.Height-rsrc->top; + if (h <= 0) return WINEDDERR_INVALIDRECT; + + w = rsrc->right - rsrc->left; + if (w > This->currentDesc.Width-dstx) w = This->currentDesc.Width-dstx; + if (w > Src->currentDesc.Width-rsrc->left) w = Src->currentDesc.Width-rsrc->left; + if (w <= 0) return WINEDDERR_INVALIDRECT; + + /* Now compute the locking rectangle... */ + lock_src.left = rsrc->left; + lock_src.top = rsrc->top; + lock_src.right = lock_src.left + w; + lock_src.bottom = lock_src.top + h; + + lock_dst.left = dstx; + lock_dst.top = dsty; + lock_dst.right = dstx + w; + lock_dst.bottom = dsty + h; + + bpp = This->bytesPerPixel; + + /* We need to lock the surfaces, or we won't get refreshes when done. */ + if (Src == This) + { + int pitch; + + UnionRect(&lock_union, &lock_src, &lock_dst); + + /* Lock the union of the two rectangles */ + ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_union, 0); + if(ret != WINED3D_OK) goto error; + + pitch = dlock.Pitch; + slock.Pitch = dlock.Pitch; + + /* Since slock was originally copied from this surface's description, we can just reuse it */ + assert(This->resource.allocatedMemory != NULL); + sbuf = (BYTE *)This->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp; + dbuf = (BYTE *)This->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp; + sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL); + dEntry = sEntry; + } + else + { + ret = IWineD3DSurface_LockRect(Source, &slock, &lock_src, WINED3DLOCK_READONLY); + if(ret != WINED3D_OK) goto error; + ret = IWineD3DSurface_LockRect(iface, &dlock, &lock_dst, 0); + if(ret != WINED3D_OK) goto error; + + sbuf = slock.pBits; + dbuf = dlock.pBits; + TRACE("Dst is at %p, Src is at %p\n", dbuf, sbuf); + + sEntry = getFormatDescEntry(Src->resource.format, NULL, NULL); + dEntry = getFormatDescEntry(This->resource.format, NULL, NULL); + } + + /* Handle first the FOURCC surfaces... */ + if (sEntry->isFourcc && dEntry->isFourcc) + { + TRACE("Fourcc -> Fourcc copy\n"); + if (trans) + FIXME("trans arg not supported when a FOURCC surface is involved\n"); + if (dstx || dsty) + FIXME("offset for destination surface is not supported\n"); + if (Src->resource.format != This->resource.format) + { + FIXME("FOURCC->FOURCC copy only supported for the same type of surface\n"); + ret = WINED3DERR_WRONGTEXTUREFORMAT; + goto error; + } + /* FIXME: Watch out that the size is correct for FOURCC surfaces */ + memcpy(dbuf, sbuf, This->resource.size); + goto error; + } + if (sEntry->isFourcc && !dEntry->isFourcc) + { + /* TODO: Use the libtxc_dxtn.so shared library to do + * software decompression + */ + ERR("DXTC decompression not supported by now\n"); + goto error; + } + + if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY)) + { + DWORD keylow, keyhigh; + TRACE("Color keyed copy\n"); + if (trans & WINEDDBLTFAST_SRCCOLORKEY) + { + keylow = Src->SrcBltCKey.dwColorSpaceLowValue; + keyhigh = Src->SrcBltCKey.dwColorSpaceHighValue; + } + else + { + /* I'm not sure if this is correct */ + FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n"); + keylow = This->DestBltCKey.dwColorSpaceLowValue; + keyhigh = This->DestBltCKey.dwColorSpaceHighValue; + } + +#define COPYBOX_COLORKEY(type) { \ + type *d, *s, tmp; \ + s = (type *) sbuf; \ + d = (type *) dbuf; \ + for (y = 0; y < h; y++) { \ + for (x = 0; x < w; x++) { \ + tmp = s[x]; \ + if (tmp < keylow || tmp > keyhigh) d[x] = tmp; \ + } \ + s = (type *)((BYTE *)s + slock.Pitch); \ + d = (type *)((BYTE *)d + dlock.Pitch); \ + } \ + break; \ + } + + switch (bpp) { + case 1: COPYBOX_COLORKEY(BYTE) + case 2: COPYBOX_COLORKEY(WORD) + case 4: COPYBOX_COLORKEY(DWORD) + case 3: + { + BYTE *d, *s; + DWORD tmp; + s = (BYTE *) sbuf; + d = (BYTE *) dbuf; + for (y = 0; y < h; y++) + { + for (x = 0; x < w * 3; x += 3) + { + tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16); + if (tmp < keylow || tmp > keyhigh) + { + d[x + 0] = s[x + 0]; + d[x + 1] = s[x + 1]; + d[x + 2] = s[x + 2]; + } + } + s += slock.Pitch; + d += dlock.Pitch; + } + break; + } + default: + FIXME("Source color key blitting not supported for bpp %d\n",bpp*8); + ret = WINED3DERR_NOTAVAILABLE; + goto error; + } +#undef COPYBOX_COLORKEY + TRACE("Copy Done\n"); + } + else + { + int width = w * bpp; + TRACE("NO color key copy\n"); + for (y = 0; y < h; y++) + { + /* This is pretty easy, a line for line memcpy */ + memcpy(dbuf, sbuf, width); + sbuf += slock.Pitch; + dbuf += dlock.Pitch; + } + TRACE("Copy done\n"); + } + +error: + if (Src == This) + { + IWineD3DSurface_UnlockRect(iface); + } + else + { + IWineD3DSurface_UnlockRect(iface); + IWineD3DSurface_UnlockRect(Source); + } + + return ret; +} + +/***************************************************************************** + * IWineD3DSurface::LoadTexture, GDI version + * + * This is mutually unsupported by GDI surfaces + * + * Returns: + * D3DERR_INVALIDCALL + * + *****************************************************************************/ +HRESULT WINAPI +IWineGDISurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) +{ + ERR("Unsupported on X11 surfaces\n"); + return WINED3DERR_INVALIDCALL; +} + +/***************************************************************************** + * IWineD3DSurface::SaveSnapshot, GDI version + * + * This method writes the surface's contents to the in tga format to the + * file specified in filename. + * + * Params: + * filename: File to write to + * + * Returns: + * WINED3DERR_INVALIDCALL if the file couldn't be opened + * WINED3D_OK on success + * + *****************************************************************************/ +static int get_shift(DWORD color_mask) { + int shift = 0; + while (color_mask > 0xFF) { + color_mask >>= 1; + shift += 1; + } + while ((color_mask & 0x80) == 0) { + color_mask <<= 1; + shift -= 1; + } + return shift; +} + + +HRESULT WINAPI +IWineGDISurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, +const char* filename) +{ + FILE* f = NULL; + UINT y = 0, x = 0; + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + static char *output = NULL; + static int size = 0; + const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL); + + if (This->pow2Width > size) { + output = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pow2Width * 3); + size = This->pow2Width; + } + + + f = fopen(filename, "w+"); + if (NULL == f) { + ERR("opening of %s failed with\n", filename); + return WINED3DERR_INVALIDCALL; + } + fprintf(f, "P6\n%d %d\n255\n", This->pow2Width, This->pow2Height); + + if (This->resource.format == WINED3DFMT_P8) { + unsigned char table[256][3]; + int i; + + if (This->palette == NULL) { + fclose(f); + return WINED3DERR_INVALIDCALL; + } + for (i = 0; i < 256; i++) { + table[i][0] = This->palette->palents[i].peRed; + table[i][1] = This->palette->palents[i].peGreen; + table[i][2] = This->palette->palents[i].peBlue; + } + for (y = 0; y < This->pow2Height; y++) { + unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface)); + for (x = 0; x < This->pow2Width; x++) { + unsigned char color = *src; + src += 1; + + output[3 * x + 0] = table[color][0]; + output[3 * x + 1] = table[color][1]; + output[3 * x + 2] = table[color][2]; + } + fwrite(output, 3 * This->pow2Width, 1, f); + } + } else { + int red_shift, green_shift, blue_shift, pix_width; + + pix_width = This->bytesPerPixel; + + red_shift = get_shift(formatEntry->redMask); + green_shift = get_shift(formatEntry->greenMask); + blue_shift = get_shift(formatEntry->blueMask); + + for (y = 0; y < This->pow2Height; y++) { + unsigned char *src = (unsigned char *) This->resource.allocatedMemory + (y * 1 * IWineD3DSurface_GetPitch(iface)); + for (x = 0; x < This->pow2Width; x++) { + unsigned int color; + unsigned int comp; + int i; + + color = 0; + for (i = 0; i < pix_width; i++) { + color |= src[i] << (8 * i); + } + src += 1 * pix_width; + + comp = color & formatEntry->redMask; + output[3 * x + 0] = red_shift > 0 ? comp >> red_shift : comp << -red_shift; + comp = color & formatEntry->greenMask; + output[3 * x + 1] = green_shift > 0 ? comp >> green_shift : comp << -green_shift; + comp = color & formatEntry->blueMask; + output[3 * x + 2] = blue_shift > 0 ? comp >> blue_shift : comp << -blue_shift; + } + fwrite(output, 3 * This->pow2Width, 1, f); + } + } + fclose(f); + return WINED3D_OK; +} + +/***************************************************************************** + * IWineD3DSurface::PrivateSetup, GDI version + * + * Initializes the GDI surface, aka creates the DIB section we render to + * The DIB section creation is done by calling GetDC, which will create the + * section and releasing the dc to allow the app to use it. The dib section + * will stay until the surface is released + * + * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes + * are set to the real sizes to save memory. The NONPOW2 flag is unset to + * avoid confusion in the shared surface code. + * + * Returns: + * WINED3D_OK on success + * The return values of called methods on failure + * + *****************************************************************************/ +HRESULT WINAPI +IWineGDISurfaceImpl_PrivateSetup(IWineD3DSurface *iface) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; + HRESULT hr; + HDC hdc; + + if(This->resource.usage & WINED3DUSAGE_OVERLAY) + { + ERR("(%p) Overlays not yet supported by GDI surfaces\n", This); + return WINED3DERR_INVALIDCALL; + } + /* Sysmem textures have memory already allocated - + * release it, this avoids an unnecessary memcpy + */ + HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory); + This->resource.allocatedMemory = NULL; + + /* We don't mind the nonpow2 stuff in GDI */ + This->pow2Width = This->currentDesc.Width; + This->pow2Height = This->currentDesc.Height; + + /* Call GetDC to create a DIB section. We will use that + * DIB section for rendering + * + * Release the DC afterwards to allow the app to use it + */ + hr = IWineD3DSurface_GetDC(iface, &hdc); + if(FAILED(hr)) + { + ERR("(%p) IWineD3DSurface::GetDC failed with hr %08x\n", This, hr); + return hr; + } + hr = IWineD3DSurface_ReleaseDC(iface, hdc); + if(FAILED(hr)) + { + ERR("(%p) IWineD3DSurface::ReleaseDC failed with hr %08x\n", This, hr); + return hr; + } + + return WINED3D_OK; +} + +const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl = +{ + /* IUnknown */ + IWineD3DSurfaceImpl_QueryInterface, + IWineD3DSurfaceImpl_AddRef, + IWineD3DSurfaceImpl_Release, + /* IWineD3DResource */ + IWineD3DSurfaceImpl_GetParent, + IWineD3DSurfaceImpl_GetDevice, + IWineD3DSurfaceImpl_SetPrivateData, + IWineD3DSurfaceImpl_GetPrivateData, + IWineD3DSurfaceImpl_FreePrivateData, + IWineD3DSurfaceImpl_SetPriority, + IWineD3DSurfaceImpl_GetPriority, + IWineGDISurfaceImpl_PreLoad, + IWineD3DSurfaceImpl_GetType, + /* IWineD3DSurface */ + IWineD3DSurfaceImpl_GetContainer, + IWineD3DSurfaceImpl_GetDesc, + IWineGDISurfaceImpl_LockRect, + IWineGDISurfaceImpl_UnlockRect, + IWineD3DSurfaceImpl_GetDC, + IWineD3DSurfaceImpl_ReleaseDC, + IWineGDISurfaceImpl_Flip, + IWineGDISurfaceImpl_Blt, + IWineD3DSurfaceImpl_GetBltStatus, + IWineD3DSurfaceImpl_GetFlipStatus, + IWineD3DSurfaceImpl_IsLost, + IWineD3DSurfaceImpl_Restore, + IWineGDISurfaceImpl_BltFast, + IWineD3DSurfaceImpl_GetPalette, + IWineD3DSurfaceImpl_SetPalette, + IWineD3DSurfaceImpl_RealizePalette, + IWineD3DSurfaceImpl_SetColorKey, + IWineD3DSurfaceImpl_GetPitch, + IWineD3DSurfaceImpl_SetMem, + IWineD3DSurfaceImpl_SetOverlayPosition, + IWineD3DSurfaceImpl_GetOverlayPosition, + IWineD3DSurfaceImpl_UpdateOverlayZOrder, + IWineD3DSurfaceImpl_UpdateOverlay, + IWineD3DSurfaceImpl_SetClipper, + IWineD3DSurfaceImpl_GetClipper, + /* Internal use: */ + IWineD3DSurfaceImpl_AddDirtyRect, + IWineGDISurfaceImpl_LoadTexture, + IWineGDISurfaceImpl_SaveSnapshot, + IWineD3DSurfaceImpl_SetContainer, + IWineD3DSurfaceImpl_SetGlTextureDesc, + IWineD3DSurfaceImpl_GetGlDesc, + IWineD3DSurfaceImpl_GetData, + IWineD3DSurfaceImpl_SetFormat, + IWineGDISurfaceImpl_PrivateSetup +}; diff --git a/reactos/dll/directx/wine/wined3d/swapchain.c b/reactos/dll/directx/wine/wined3d/swapchain.c new file mode 100644 index 00000000000..5d1edbe9022 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/swapchain.c @@ -0,0 +1,560 @@ +/* + *IDirect3DSwapChain9 implementation + * + *Copyright 2002-2003 Jason Edmeades + *Copyright 2002-2003 Raphael Junqueira + *Copyright 2005 Oliver Stieber + * + *This library is free software; you can redistribute it and/or + *modify it under the terms of the GNU Lesser General Public + *License as published by the Free Software Foundation; either + *version 2.1 of the License, or (at your option) any later version. + * + *This library is distributed in the hope that it will be useful, + *but WITHOUT ANY WARRANTY; without even the implied warranty of + *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + *Lesser General Public License for more details. + * + *You should have received a copy of the GNU Lesser General Public + *License along with this library; if not, write to the Free Software + *Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + + +/*TODO: some of the additional parameters may be required to + set the gamma ramp (for some weird reason microsoft have left swap gammaramp in device + but it operates on a swapchain, it may be a good idea to move it to IWineD3DSwapChain for IWineD3D)*/ + + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +WINE_DECLARE_DEBUG_CHANNEL(fps); + +#define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info + +/* IDirect3DSwapChain IUnknown parts follow: */ +static ULONG WINAPI IWineD3DSwapChainImpl_AddRef(IWineD3DSwapChain *iface) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + DWORD refCount = InterlockedIncrement(&This->ref); + TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1); + return refCount; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_QueryInterface(IWineD3DSwapChain *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DSwapChain)){ + IWineD3DSwapChainImpl_AddRef(iface); + if(ppobj == NULL){ + ERR("Query interface called but now data allocated\n"); + return E_NOINTERFACE; + } + *ppobj = This; + return WINED3D_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + + +static ULONG WINAPI IWineD3DSwapChainImpl_Release(IWineD3DSwapChain *iface) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + DWORD refCount; + refCount = InterlockedDecrement(&This->ref); + TRACE("(%p) : ReleaseRef to %d\n", This, refCount); + if (refCount == 0) { + IWineD3DSwapChain_Destroy(iface, D3DCB_DefaultDestroySurface); + } + return refCount; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetParent(IWineD3DSwapChain *iface, IUnknown ** ppParent){ + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + *ppParent = This->parent; + IUnknown_AddRef(*ppParent); + TRACE("(%p) returning %p\n", This , *ppParent); + return WINED3D_OK; +} + +/*IWineD3DSwapChain parts follow: */ +static void WINAPI IWineD3DSwapChainImpl_Destroy(IWineD3DSwapChain *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyRenderTarget) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + WINED3DDISPLAYMODE mode; + int i; + + /* release the ref to the front and back buffer parents */ + if(This->frontBuffer) { + IWineD3DSurface_SetContainer(This->frontBuffer, 0); + if(D3DCB_DestroyRenderTarget(This->frontBuffer) > 0) { + FIXME("(%p) Something's still holding the front buffer\n",This); + } + } + + if(This->backBuffer) { + int i; + for(i = 0; i < This->presentParms.BackBufferCount; i++) { + IWineD3DSurface_SetContainer(This->backBuffer[i], 0); + if(D3DCB_DestroyRenderTarget(This->backBuffer[i]) > 0) { + FIXME("(%p) Something's still holding the back buffer\n",This); + } + } + } + + /* Restore the screen resolution if we rendered in fullscreen + * This will restore the screen resolution to what it was before creating the swapchain. In case of d3d8 and d3d9 + * this will be the original desktop resolution. In case of d3d7 this will be a NOP because ddraw sets the resolution + * before starting up Direct3D, thus orig_width and orig_height will be equal to the modes in the presentation params + */ + if(This->presentParms.Windowed == FALSE) { + mode.Width = This->orig_width; + mode.Height = This->orig_height; + mode.RefreshRate = 0; + mode.Format = This->orig_fmt; + IWineD3DDevice_SetDisplayMode((IWineD3DDevice *) This->wineD3DDevice, 0, &mode); + } + for(i = 0; i < This->num_contexts; i++) { + DestroyContext(This->wineD3DDevice, This->context[i]); + } + HeapFree(GetProcessHeap(), 0, This->context); + + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CONST RECT *pSourceRect, CONST RECT *pDestRect, HWND hDestWindowOverride, CONST RGNDATA *pDirtyRegion, DWORD dwFlags) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + unsigned int sync; + int retval; + + + ActivateContext(This->wineD3DDevice, This->backBuffer[0], CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + + /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */ + if(This->wineD3DDevice->bCursorVisible && This->wineD3DDevice->cursorTexture) { + IWineD3DSurfaceImpl cursor; + RECT destRect = {This->wineD3DDevice->xScreenSpace - This->wineD3DDevice->xHotSpot, + This->wineD3DDevice->yScreenSpace - This->wineD3DDevice->yHotSpot, + This->wineD3DDevice->xScreenSpace + This->wineD3DDevice->cursorWidth - This->wineD3DDevice->xHotSpot, + This->wineD3DDevice->yScreenSpace + This->wineD3DDevice->cursorHeight - This->wineD3DDevice->yHotSpot}; + TRACE("Rendering the cursor. Creating fake surface at %p\n", &cursor); + /* Build a fake surface to call the Blitting code. It is not possible to use the interface passed by + * the application because we are only supposed to copy the information out. Using a fake surface + * allows to use the Blitting engine and avoid copying the whole texture -> render target blitting code. + */ + memset(&cursor, 0, sizeof(cursor)); + cursor.lpVtbl = &IWineD3DSurface_Vtbl; + cursor.resource.ref = 1; + cursor.resource.wineD3DDevice = This->wineD3DDevice; + cursor.resource.pool = WINED3DPOOL_SCRATCH; + cursor.resource.format = WINED3DFMT_A8R8G8B8; + cursor.resource.resourceType = WINED3DRTYPE_SURFACE; + cursor.glDescription.textureName = This->wineD3DDevice->cursorTexture; + cursor.glDescription.target = GL_TEXTURE_2D; + cursor.glDescription.level = 0; + cursor.currentDesc.Width = This->wineD3DDevice->cursorWidth; + cursor.currentDesc.Height = This->wineD3DDevice->cursorHeight; + cursor.glRect.left = 0; + cursor.glRect.top = 0; + cursor.glRect.right = cursor.currentDesc.Width; + cursor.glRect.bottom = cursor.currentDesc.Height; + /* The cursor must have pow2 sizes */ + cursor.pow2Width = cursor.currentDesc.Width; + cursor.pow2Height = cursor.currentDesc.Height; + /* The surface is in the texture */ + cursor.Flags |= SFLAG_INTEXTURE; + /* DDBLT_KEYSRC will cause BltOverride to enable the alpha test with GL_NOTEQUAL, 0.0, + * which is exactly what we want :-) + */ + if (This->presentParms.Windowed) { + MapWindowPoints(NULL, This->win_handle, (LPPOINT)&destRect, 2); + } + IWineD3DSurface_Blt(This->backBuffer[0], &destRect, (IWineD3DSurface *) &cursor, NULL, WINEDDBLT_KEYSRC, NULL, WINED3DTEXF_NONE); + } + + if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect); + /* TODO: If only source rect or dest rect are supplied then clip the window to match */ + TRACE("preseting HDC %p\n", This->context[0]->hdc); + + /* Don't call checkGLcall, as glGetError is not applicable here */ + if (hDestWindowOverride && This->win_handle != hDestWindowOverride) { + WINED3DLOCKED_RECT r; + BYTE *mem; + + TRACE("Performing dest override of swapchain %p from window %p to %p\n", This, This->win_handle, hDestWindowOverride); + if(This->context[0] == This->wineD3DDevice->contexts[0]) { + /* The primary context 'owns' all the opengl resources. Destroying and recreating that context would require downloading + * all opengl resources, deleting the gl resources, destroying all other contexts, then recreating all other contexts + * and reload the resources + */ + ERR("Cannot change the destination window of the owner of the primary context\n"); + } else { + This->win_handle = hDestWindowOverride; + + /* The old back buffer has to be copied over to the new back buffer. A lockrect - switchcontext - unlockrect + * would suffice in theory, but it is rather nasty and may cause troubles with future changes of the locking code + * So lock read only, copy the surface out, then lock with the discard flag and write back + */ + IWineD3DSurface_LockRect(This->backBuffer[0], &r, NULL, WINED3DLOCK_READONLY); + mem = HeapAlloc(GetProcessHeap(), 0, r.Pitch * ((IWineD3DSurfaceImpl *) This->backBuffer[0])->currentDesc.Height); + memcpy(mem, r.pBits, r.Pitch * ((IWineD3DSurfaceImpl *) This->backBuffer[0])->currentDesc.Height); + IWineD3DSurface_UnlockRect(This->backBuffer[0]); + + DestroyContext(This->wineD3DDevice, This->context[0]); + This->context[0] = CreateContext(This->wineD3DDevice, (IWineD3DSurfaceImpl *) This->frontBuffer, This->win_handle, FALSE /* pbuffer */, &This->presentParms); + + IWineD3DSurface_LockRect(This->backBuffer[0], &r, NULL, WINED3DLOCK_DISCARD); + memcpy(r.pBits, mem, r.Pitch * ((IWineD3DSurfaceImpl *) This->backBuffer[0])->currentDesc.Height); + HeapFree(GetProcessHeap(), 0, mem); + IWineD3DSurface_UnlockRect(This->backBuffer[0]); + } + } + + SwapBuffers(This->context[0]->hdc); /* TODO: cycle through the swapchain buffers */ + + TRACE("SwapBuffers called, Starting new frame\n"); + /* FPS support */ + if (TRACE_ON(fps)) + { + DWORD time = GetTickCount(); + This->frames++; + /* every 1.5 seconds */ + if (time - This->prev_time > 1500) { + TRACE_(fps)("%p @ approx %.2ffps\n", This, 1000.0*This->frames/(time - This->prev_time)); + This->prev_time = time; + This->frames = 0; + } + } + +#if defined(FRAME_DEBUGGING) +{ + if (GetFileAttributesA("C:\\D3DTRACE") != INVALID_FILE_ATTRIBUTES) { + if (!isOn) { + isOn = TRUE; + FIXME("Enabling D3D Trace\n"); + __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 1); +#if defined(SHOW_FRAME_MAKEUP) + FIXME("Singe Frame snapshots Starting\n"); + isDumpingFrames = TRUE; + glClear(GL_COLOR_BUFFER_BIT); +#endif + +#if defined(SINGLE_FRAME_DEBUGGING) + } else { +#if defined(SHOW_FRAME_MAKEUP) + FIXME("Singe Frame snapshots Finishing\n"); + isDumpingFrames = FALSE; +#endif + FIXME("Singe Frame trace complete\n"); + DeleteFileA("C:\\D3DTRACE"); + __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0); +#endif + } + } else { + if (isOn) { + isOn = FALSE; +#if defined(SHOW_FRAME_MAKEUP) + FIXME("Single Frame snapshots Finishing\n"); + isDumpingFrames = FALSE; +#endif + FIXME("Disabling D3D Trace\n"); + __WINE_SET_DEBUGGING(__WINE_DBCL_TRACE, __wine_dbch_d3d, 0); + } + } +} +#endif + + LEAVE_GL(); + + if (This->presentParms.SwapEffect == WINED3DSWAPEFFECT_DISCARD) { + TRACE("Clearing the color buffer with pink color\n"); + + IWineD3DDevice_Clear((IWineD3DDevice*)This->wineD3DDevice, 0, NULL, + WINED3DCLEAR_TARGET, 0xff00ffff, 1.0, 0); + } + + if(((IWineD3DSurfaceImpl *) This->frontBuffer)->Flags & SFLAG_INSYSMEM || + ((IWineD3DSurfaceImpl *) This->backBuffer[0])->Flags & SFLAG_INSYSMEM ) { + /* Both memory copies of the surfaces are ok, flip them around too instead of dirtifying */ + IWineD3DSurfaceImpl *front = (IWineD3DSurfaceImpl *) This->frontBuffer; + IWineD3DSurfaceImpl *back = (IWineD3DSurfaceImpl *) This->backBuffer[0]; + BOOL frontuptodate = front->Flags & SFLAG_INSYSMEM; + BOOL backuptodate = back->Flags & SFLAG_INSYSMEM; + + if(front->resource.size == back->resource.size) { + /* Flip the DC */ + { + HDC tmp; + tmp = front->hDC; + front->hDC = back->hDC; + back->hDC = tmp; + } + + /* Flip the DIBsection */ + { + HBITMAP tmp; + BOOL hasDib = front->Flags & SFLAG_DIBSECTION; + tmp = front->dib.DIBsection; + front->dib.DIBsection = back->dib.DIBsection; + back->dib.DIBsection = tmp; + + if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION; + else front->Flags &= ~SFLAG_DIBSECTION; + if(hasDib) back->Flags |= SFLAG_DIBSECTION; + else back->Flags &= ~SFLAG_DIBSECTION; + } + + /* Flip the surface data */ + { + void* tmp; + + tmp = front->dib.bitmap_data; + front->dib.bitmap_data = back->dib.bitmap_data; + back->dib.bitmap_data = tmp; + + tmp = front->resource.allocatedMemory; + front->resource.allocatedMemory = back->resource.allocatedMemory; + back->resource.allocatedMemory = tmp; + } + + /* client_memory should not be different, but just in case */ + { + BOOL tmp; + tmp = front->dib.client_memory; + front->dib.client_memory = back->dib.client_memory; + back->dib.client_memory = tmp; + } + if(frontuptodate) back->Flags |= SFLAG_INSYSMEM; + else back->Flags &= ~SFLAG_INSYSMEM; + if(backuptodate) front->Flags |= SFLAG_INSYSMEM; + else front->Flags &= ~SFLAG_INSYSMEM; + } else { + back->Flags &= ~SFLAG_INSYSMEM; + front->Flags &= ~SFLAG_INSYSMEM; + } + } + + if(This->presentParms.PresentationInterval != WINED3DPRESENT_INTERVAL_IMMEDIATE && GL_SUPPORT(SGI_VIDEO_SYNC)) { + retval = GL_EXTCALL(glXGetVideoSyncSGI(&sync)); + if(retval != 0) { + ERR("glXGetVideoSyncSGI failed(retval = %d\n", retval); + } + + switch(This->presentParms.PresentationInterval) { + case WINED3DPRESENT_INTERVAL_DEFAULT: + case WINED3DPRESENT_INTERVAL_ONE: + if(sync <= This->vSyncCounter) { + retval = GL_EXTCALL(glXWaitVideoSyncSGI(1, 0, &This->vSyncCounter)); + } else { + This->vSyncCounter = sync; + } + break; + case WINED3DPRESENT_INTERVAL_TWO: + if(sync <= This->vSyncCounter + 1) { + retval = GL_EXTCALL(glXWaitVideoSyncSGI(2, This->vSyncCounter & 0x1, &This->vSyncCounter)); + } else { + This->vSyncCounter = sync; + } + break; + case WINED3DPRESENT_INTERVAL_THREE: + if(sync <= This->vSyncCounter + 2) { + retval = GL_EXTCALL(glXWaitVideoSyncSGI(3, This->vSyncCounter % 0x3, &This->vSyncCounter)); + } else { + This->vSyncCounter = sync; + } + break; + case WINED3DPRESENT_INTERVAL_FOUR: + if(sync <= This->vSyncCounter + 3) { + retval = GL_EXTCALL(glXWaitVideoSyncSGI(4, This->vSyncCounter & 0x3, &This->vSyncCounter)); + } else { + This->vSyncCounter = sync; + } + break; + default: + FIXME("Unknown presentation interval %08x\n", This->presentParms.PresentationInterval); + } + } + + TRACE("returning\n"); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetFrontBufferData(IWineD3DSwapChain *iface, IWineD3DSurface *pDestSurface) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + POINT start; + + TRACE("(%p) : iface(%p) pDestSurface(%p)\n", This, iface, pDestSurface); + + start.x = 0; + start.y = 0; + + if (This->presentParms.Windowed) { + MapWindowPoints(This->win_handle, NULL, &start, 1); + } + + IWineD3DSurface_BltFast(pDestSurface, start.x, start.y, This->frontBuffer, NULL, 0); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetBackBuffer(IWineD3DSwapChain *iface, UINT iBackBuffer, WINED3DBACKBUFFER_TYPE Type, IWineD3DSurface **ppBackBuffer) { + + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + + if (iBackBuffer > This->presentParms.BackBufferCount - 1) { + TRACE("Back buffer count out of range\n"); + /* Native d3d9 doesn't set NULL here, just as wine's d3d9. But set it here + * in wined3d to avoid problems in other libs + */ + *ppBackBuffer = NULL; + return WINED3DERR_INVALIDCALL; + } + + *ppBackBuffer = This->backBuffer[iBackBuffer]; + TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, iBackBuffer, Type, *ppBackBuffer); + + /* Note inc ref on returned surface */ + if(*ppBackBuffer) IWineD3DSurface_AddRef(*ppBackBuffer); + return WINED3D_OK; + +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetRasterStatus(IWineD3DSwapChain *iface, WINED3DRASTER_STATUS *pRasterStatus) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + static BOOL showFixmes = TRUE; + pRasterStatus->InVBlank = TRUE; + pRasterStatus->ScanLine = 0; + /* No openGL equivalent */ + if(showFixmes) { + FIXME("(%p) : stub (once)\n", This); + showFixmes = FALSE; + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetDisplayMode(IWineD3DSwapChain *iface, WINED3DDISPLAYMODE*pMode) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + HDC hdc; + int bpp = 0; + + pMode->Width = GetSystemMetrics(SM_CXSCREEN); + pMode->Height = GetSystemMetrics(SM_CYSCREEN); + pMode->RefreshRate = 85; /* FIXME: How to identify? */ + + hdc = GetDC(0); + bpp = GetDeviceCaps(hdc, BITSPIXEL); + ReleaseDC(0, hdc); + + switch (bpp) { + case 8: pMode->Format = WINED3DFMT_R8G8B8; break; + case 16: pMode->Format = WINED3DFMT_R5G6B5; break; + case 24: /*pMode->Format = WINED3DFMT_R8G8B8; break; */ /* 32bpp and 24bpp can be aliased for X */ + case 32: pMode->Format = WINED3DFMT_A8R8G8B8; break; + default: + FIXME("Unrecognized display mode format\n"); + pMode->Format = WINED3DFMT_UNKNOWN; + } + + TRACE("(%p) : returning w(%d) h(%d) rr(%d) fmt(%u,%s)\n", This, pMode->Width, pMode->Height, pMode->RefreshRate, + pMode->Format, debug_d3dformat(pMode->Format)); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetDevice(IWineD3DSwapChain *iface, IWineD3DDevice**ppDevice) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + + *ppDevice = (IWineD3DDevice *) This->wineD3DDevice; + + /* Note Calling this method will increase the internal reference count + on the IDirect3DDevice9 interface. */ + IWineD3DDevice_AddRef(*ppDevice); + TRACE("(%p) : returning %p\n", This, *ppDevice); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetPresentParameters(IWineD3DSwapChain *iface, WINED3DPRESENT_PARAMETERS *pPresentationParameters) { + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + TRACE("(%p)\n", This); + + *pPresentationParameters = This->presentParms; + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_SetGammaRamp(IWineD3DSwapChain *iface, DWORD Flags, CONST WINED3DGAMMARAMP *pRamp){ + + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + HDC hDC; + TRACE("(%p) : pRamp@%p flags(%d)\n", This, pRamp, Flags); + hDC = GetDC(This->win_handle); + SetDeviceGammaRamp(hDC, (LPVOID)pRamp); + ReleaseDC(This->win_handle, hDC); + return WINED3D_OK; + +} + +static HRESULT WINAPI IWineD3DSwapChainImpl_GetGammaRamp(IWineD3DSwapChain *iface, WINED3DGAMMARAMP *pRamp){ + + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *)iface; + HDC hDC; + TRACE("(%p) : pRamp@%p\n", This, pRamp); + hDC = GetDC(This->win_handle); + GetDeviceGammaRamp(hDC, pRamp); + ReleaseDC(This->win_handle, hDC); + return WINED3D_OK; + +} + + +const IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl = +{ + /* IUnknown */ + IWineD3DSwapChainImpl_QueryInterface, + IWineD3DSwapChainImpl_AddRef, + IWineD3DSwapChainImpl_Release, + /* IWineD3DSwapChain */ + IWineD3DSwapChainImpl_GetParent, + IWineD3DSwapChainImpl_Destroy, + IWineD3DSwapChainImpl_GetDevice, + IWineD3DSwapChainImpl_Present, + IWineD3DSwapChainImpl_GetFrontBufferData, + IWineD3DSwapChainImpl_GetBackBuffer, + IWineD3DSwapChainImpl_GetRasterStatus, + IWineD3DSwapChainImpl_GetDisplayMode, + IWineD3DSwapChainImpl_GetPresentParameters, + IWineD3DSwapChainImpl_SetGammaRamp, + IWineD3DSwapChainImpl_GetGammaRamp +}; + +WineD3DContext *IWineD3DSwapChainImpl_CreateContextForThread(IWineD3DSwapChain *iface) { + WineD3DContext *ctx; + IWineD3DSwapChainImpl *This = (IWineD3DSwapChainImpl *) iface; + WineD3DContext **newArray; + + TRACE("Creating a new context for swapchain %p, thread %d\n", This, GetCurrentThreadId()); + + ctx = CreateContext(This->wineD3DDevice, (IWineD3DSurfaceImpl *) This->frontBuffer, + This->context[0]->win_handle, FALSE /* pbuffer */, &This->presentParms); + if(!ctx) { + ERR("Failed to create a new context for the swapchain\n"); + return NULL; + } + + newArray = HeapAlloc(GetProcessHeap(), 0, sizeof(*newArray) * This->num_contexts + 1); + if(!newArray) { + ERR("Out of memory when trying to allocate a new context array\n"); + DestroyContext(This->wineD3DDevice, ctx); + return NULL; + } + memcpy(newArray, This->context, sizeof(*newArray) * This->num_contexts); + HeapFree(GetProcessHeap(), 0, This->context); + newArray[This->num_contexts] = ctx; + This->context = newArray; + This->num_contexts++; + + TRACE("Returning context %p\n", ctx); + return ctx; +} diff --git a/reactos/dll/directx/wine/wined3d/texture.c b/reactos/dll/directx/wine/wined3d/texture.c new file mode 100644 index 00000000000..48f8c8cb15d --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/texture.c @@ -0,0 +1,376 @@ +/* + * IWineD3DTexture implementation + * + * Copyright 2002-2005 Jason Edmeades + * Copyright 2002-2005 Raphael Junqueira + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +/* ******************************************* + IWineD3DTexture IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DTextureImpl_QueryInterface(IWineD3DTexture *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DBaseTexture) + || IsEqualGUID(riid, &IID_IWineD3DTexture)){ + IUnknown_AddRef(iface); + *ppobj = This; + return WINED3D_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DTextureImpl_AddRef(IWineD3DTexture *iface) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref); + return InterlockedIncrement(&This->resource.ref); +} + +static ULONG WINAPI IWineD3DTextureImpl_Release(IWineD3DTexture *iface) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->resource.ref); + ref = InterlockedDecrement(&This->resource.ref); + if (ref == 0) { + IWineD3DTexture_Destroy(iface, D3DCB_DefaultDestroySurface); + } + return ref; +} + + +/* **************************************************** + IWineD3DTexture IWineD3DResource parts follow + **************************************************** */ +static HRESULT WINAPI IWineD3DTextureImpl_GetDevice(IWineD3DTexture *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +static HRESULT WINAPI IWineD3DTextureImpl_SetPrivateData(IWineD3DTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IWineD3DTextureImpl_GetPrivateData(IWineD3DTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IWineD3DTextureImpl_FreePrivateData(IWineD3DTexture *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +static DWORD WINAPI IWineD3DTextureImpl_SetPriority(IWineD3DTexture *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +static DWORD WINAPI IWineD3DTextureImpl_GetPriority(IWineD3DTexture *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) { + + /* Override the IWineD3DResource PreLoad method */ + unsigned int i; + BOOL setGlTextureDesc = FALSE; + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + BOOL srgb_mode = This->baseTexture.is_srgb; + BOOL srgb_was_toggled = FALSE; + + TRACE("(%p) : About to load texture\n", This); + + if (This->baseTexture.textureName == 0) setGlTextureDesc = TRUE; + + if(!device->isInDraw) { + /* ActivateContext sets isInDraw to TRUE when loading a pbuffer into a texture, thus no danger of + * recursive calls + */ + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } else if (GL_SUPPORT(EXT_TEXTURE_SRGB) && This->baseTexture.bindCount > 0) { + srgb_mode = device->stateBlock->samplerState[This->baseTexture.sampler][WINED3DSAMP_SRGBTEXTURE]; + srgb_was_toggled = This->baseTexture.is_srgb != srgb_mode; + This->baseTexture.is_srgb = srgb_mode; + } + + IWineD3DTexture_BindTexture(iface); + ENTER_GL(); + /* If the texture is marked dirty or the srgb sampler setting has changed since the last load then reload the surfaces */ + if (This->baseTexture.dirty) { + for (i = 0; i < This->baseTexture.levels; i++) { + if(setGlTextureDesc) + IWineD3DSurface_SetGlTextureDesc(This->surfaces[i], This->baseTexture.textureName, IWineD3DTexture_GetTextureDimensions(iface)); + IWineD3DSurface_LoadTexture(This->surfaces[i], srgb_mode); + } + } else if (srgb_was_toggled) { + if (This->baseTexture.srgb_mode_change_count < 20) + ++This->baseTexture.srgb_mode_change_count; + else + FIXME("Texture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); + + for (i = 0; i < This->baseTexture.levels; i++) { + IWineD3DSurfaceImpl_AddDirtyRect(This->surfaces[i], NULL); + IWineD3DSurface_SetGlTextureDesc(This->surfaces[i], This->baseTexture.textureName, IWineD3DTexture_GetTextureDimensions(iface)); + IWineD3DSurface_LoadTexture(This->surfaces[i], srgb_mode); + } + } else { + TRACE("(%p) Texture not dirty, nothing to do\n" , iface); + } + LEAVE_GL(); + + /* No longer dirty */ + This->baseTexture.dirty = FALSE; + + return ; +} + +static WINED3DRESOURCETYPE WINAPI IWineD3DTextureImpl_GetType(IWineD3DTexture *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +static HRESULT WINAPI IWineD3DTextureImpl_GetParent(IWineD3DTexture *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DTexture IWineD3DBaseTexture parts follow + ****************************************************** */ +static DWORD WINAPI IWineD3DTextureImpl_SetLOD(IWineD3DTexture *iface, DWORD LODNew) { + return IWineD3DBaseTextureImpl_SetLOD((IWineD3DBaseTexture *)iface, LODNew); +} + +static DWORD WINAPI IWineD3DTextureImpl_GetLOD(IWineD3DTexture *iface) { + return IWineD3DBaseTextureImpl_GetLOD((IWineD3DBaseTexture *)iface); +} + +static DWORD WINAPI IWineD3DTextureImpl_GetLevelCount(IWineD3DTexture *iface) { + return IWineD3DBaseTextureImpl_GetLevelCount((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DTextureImpl_SetAutoGenFilterType(IWineD3DTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) { + return IWineD3DBaseTextureImpl_SetAutoGenFilterType((IWineD3DBaseTexture *)iface, FilterType); +} + +static WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DTextureImpl_GetAutoGenFilterType(IWineD3DTexture *iface) { + return IWineD3DBaseTextureImpl_GetAutoGenFilterType((IWineD3DBaseTexture *)iface); +} + +static void WINAPI IWineD3DTextureImpl_GenerateMipSubLevels(IWineD3DTexture *iface) { + IWineD3DBaseTextureImpl_GenerateMipSubLevels((IWineD3DBaseTexture *)iface); +} + +/* Internal function, No d3d mapping */ +static BOOL WINAPI IWineD3DTextureImpl_SetDirty(IWineD3DTexture *iface, BOOL dirty) { + return IWineD3DBaseTextureImpl_SetDirty((IWineD3DBaseTexture *)iface, dirty); +} + +static BOOL WINAPI IWineD3DTextureImpl_GetDirty(IWineD3DTexture *iface) { + return IWineD3DBaseTextureImpl_GetDirty((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DTextureImpl_BindTexture(IWineD3DTexture *iface) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + TRACE("(%p) : relay to BaseTexture\n", This); + return IWineD3DBaseTextureImpl_BindTexture((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DTextureImpl_UnBindTexture(IWineD3DTexture *iface) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + TRACE("(%p) : relay to BaseTexture\n", This); + return IWineD3DBaseTextureImpl_UnBindTexture((IWineD3DBaseTexture *)iface); +} + +static UINT WINAPI IWineD3DTextureImpl_GetTextureDimensions(IWineD3DTexture *iface) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + TRACE("(%p)\n", This); + + return GL_TEXTURE_2D; +} + +static void WINAPI IWineD3DTextureImpl_ApplyStateChanges(IWineD3DTexture *iface, + const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], + const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + float matrix[16]; + IWineD3DBaseTextureImpl_ApplyStateChanges((IWineD3DBaseTexture *)iface, textureStates, samplerStates); + + /** non-power2 fixups using texture matrix **/ + if(This->pow2scalingFactorX != 1.0f || This->pow2scalingFactorY != 1.0f) { + /* Apply non-power2 mappings and texture offsets so long as the texture coords aren't projected or generated */ + if(((textureStates[WINED3DTSS_TEXCOORDINDEX] & 0xFFFF0000) == WINED3DTSS_TCI_PASSTHRU) && + (~textureStates[WINED3DTSS_TEXTURETRANSFORMFLAGS] & WINED3DTTFF_PROJECTED)) { + glMatrixMode(GL_TEXTURE); + memset(matrix, 0 , sizeof(matrix)); + matrix[0] = This->pow2scalingFactorX; + matrix[5] = This->pow2scalingFactorY; +#if 0 /* this isn't needed any more, I changed the translation in drawprim.c to 0.9/width instead of 1/width and everything lines up ok. left here as a reminder */ + matrix[12] = -0.25f / (float)This->width; + matrix[13] = -0.75f / (float)This->height; +#endif + matrix[10] = 1; + matrix[15] = 1; + TRACE("(%p) Setup Matrix:\n", This); + TRACE(" %f %f %f %f\n", matrix[0], matrix[1], matrix[2], matrix[3]); + TRACE(" %f %f %f %f\n", matrix[4], matrix[5], matrix[6], matrix[7]); + TRACE(" %f %f %f %f\n", matrix[8], matrix[9], matrix[10], matrix[11]); + TRACE(" %f %f %f %f\n", matrix[12], matrix[13], matrix[14], matrix[15]); + TRACE("\n"); + + glMultMatrixf(matrix); + } else { + /* I don't expect nonpower 2 textures to be used with generated texture coordinates, but if they are present a fixme. */ + FIXME("Non-power2 texture being used with generated texture coords\n"); + } + } + +} + +/* ******************************************* + IWineD3DTexture IWineD3DTexture parts follow + ******************************************* */ +static void WINAPI IWineD3DTextureImpl_Destroy(IWineD3DTexture *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroySurface) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + int i; + + TRACE("(%p) : Cleaning up\n",This); + for (i = 0; i < This->baseTexture.levels; i++) { + if (This->surfaces[i] != NULL) { + /* Clean out the texture name we gave to the surface so that the surface doesn't try and release it */ + IWineD3DSurface_SetGlTextureDesc(This->surfaces[i], 0, 0); + IWineD3DSurface_SetContainer(This->surfaces[i], 0); + D3DCB_DestroySurface(This->surfaces[i]); + } + } + TRACE("(%p) : cleaning up base texture\n", This); + IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *)iface); + /* free the object */ + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI IWineD3DTextureImpl_GetLevelDesc(IWineD3DTexture *iface, UINT Level, WINED3DSURFACE_DESC* pDesc) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + + if (Level < This->baseTexture.levels) { + TRACE("(%p) Level (%d)\n", This, Level); + return IWineD3DSurface_GetDesc(This->surfaces[Level], pDesc); + } + FIXME("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + return WINED3DERR_INVALIDCALL; +} + +static HRESULT WINAPI IWineD3DTextureImpl_GetSurfaceLevel(IWineD3DTexture *iface, UINT Level, IWineD3DSurface** ppSurfaceLevel) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + HRESULT hr = WINED3DERR_INVALIDCALL; + + if (Level < This->baseTexture.levels) { + *ppSurfaceLevel = This->surfaces[Level]; + IWineD3DSurface_AddRef((IWineD3DSurface*) This->surfaces[Level]); + hr = WINED3D_OK; + TRACE("(%p) : returning %p for level %d\n", This, *ppSurfaceLevel, Level); + } + if (WINED3D_OK != hr) { + WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + *ppSurfaceLevel = NULL; /* Just to be on the safe side.. */ + } + return hr; +} + +static HRESULT WINAPI IWineD3DTextureImpl_LockRect(IWineD3DTexture *iface, UINT Level, WINED3DLOCKED_RECT *pLockedRect, + CONST RECT *pRect, DWORD Flags) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + HRESULT hr = WINED3DERR_INVALIDCALL; + + if (Level < This->baseTexture.levels) { + hr = IWineD3DSurface_LockRect(This->surfaces[Level], pLockedRect, pRect, Flags); + } + if (WINED3D_OK == hr) { + TRACE("(%p) Level (%d) success\n", This, Level); + } else { + WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + } + + return hr; +} + +static HRESULT WINAPI IWineD3DTextureImpl_UnlockRect(IWineD3DTexture *iface, UINT Level) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + HRESULT hr = WINED3DERR_INVALIDCALL; + + if (Level < This->baseTexture.levels) { + hr = IWineD3DSurface_UnlockRect(This->surfaces[Level]); + } + if ( WINED3D_OK == hr) { + TRACE("(%p) Level (%d) success\n", This, Level); + } else { + WARN("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + } + return hr; +} + +static HRESULT WINAPI IWineD3DTextureImpl_AddDirtyRect(IWineD3DTexture *iface, CONST RECT* pDirtyRect) { + IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; + This->baseTexture.dirty = TRUE; + TRACE("(%p) : dirtyfication of surface Level (0)\n", This); + return IWineD3DSurface_AddDirtyRect(This->surfaces[0], pDirtyRect); +} + +const IWineD3DTextureVtbl IWineD3DTexture_Vtbl = +{ + /* IUnknown */ + IWineD3DTextureImpl_QueryInterface, + IWineD3DTextureImpl_AddRef, + IWineD3DTextureImpl_Release, + /* IWineD3DResource */ + IWineD3DTextureImpl_GetParent, + IWineD3DTextureImpl_GetDevice, + IWineD3DTextureImpl_SetPrivateData, + IWineD3DTextureImpl_GetPrivateData, + IWineD3DTextureImpl_FreePrivateData, + IWineD3DTextureImpl_SetPriority, + IWineD3DTextureImpl_GetPriority, + IWineD3DTextureImpl_PreLoad, + IWineD3DTextureImpl_GetType, + /* IWineD3DBaseTexture */ + IWineD3DTextureImpl_SetLOD, + IWineD3DTextureImpl_GetLOD, + IWineD3DTextureImpl_GetLevelCount, + IWineD3DTextureImpl_SetAutoGenFilterType, + IWineD3DTextureImpl_GetAutoGenFilterType, + IWineD3DTextureImpl_GenerateMipSubLevels, + IWineD3DTextureImpl_SetDirty, + IWineD3DTextureImpl_GetDirty, + IWineD3DTextureImpl_BindTexture, + IWineD3DTextureImpl_UnBindTexture, + IWineD3DTextureImpl_GetTextureDimensions, + IWineD3DTextureImpl_ApplyStateChanges, + /* IWineD3DTexture */ + IWineD3DTextureImpl_Destroy, + IWineD3DTextureImpl_GetLevelDesc, + IWineD3DTextureImpl_GetSurfaceLevel, + IWineD3DTextureImpl_LockRect, + IWineD3DTextureImpl_UnlockRect, + IWineD3DTextureImpl_AddDirtyRect +}; diff --git a/reactos/dll/directx/wine/wined3d/utils.c b/reactos/dll/directx/wine/wined3d/utils.c new file mode 100644 index 00000000000..dfc1fc6f52c --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/utils.c @@ -0,0 +1,2971 @@ +/* + * Utility functions for the WineD3D Library + * + * Copyright 2002-2004 Jason Edmeades + * Copyright 2003-2004 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006-2007 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); + +#define GLINFO_LOCATION This->adapter->gl_info + +/***************************************************************************** + * Pixel format array + */ +static const StaticPixelFormatDesc formats[] = { + /*{WINED3DFORMAT ,alphamask ,redmask ,greenmask ,bluemask ,bpp ,depth ,stencil, isFourcc*/ + {WINED3DFMT_UNKNOWN ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,FALSE }, + /* FourCC formats, kept here to have WINED3DFMT_R8G8B8(=20) at position 20 */ + {WINED3DFMT_UYVY ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, + {WINED3DFMT_YUY2 ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, + {WINED3DFMT_DXT1 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, + {WINED3DFMT_DXT2 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, + {WINED3DFMT_DXT3 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, + {WINED3DFMT_DXT4 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, + {WINED3DFMT_DXT5 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,TRUE }, + {WINED3DFMT_MULTI2_ARGB8,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, + {WINED3DFMT_G8R8_G8B8 ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, + {WINED3DFMT_R8G8_B8G8 ,0x0 ,0x0 ,0x0 ,0x0 ,1/*?*/ ,0 ,0 ,TRUE }, + /* IEEE formats */ + {WINED3DFMT_R32F ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_G32R32F ,0x0 ,0x0 ,0x0 ,0x0 ,8 ,0 ,0 ,FALSE }, + {WINED3DFMT_A32B32G32R32F,0x0 ,0x0 ,0x0 ,0x0 ,16 ,0 ,0 ,FALSE }, + /* Hmm? */ + {WINED3DFMT_CxV8U8 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + /* Float */ + {WINED3DFMT_R16F ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_G16R16F ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_A16B16G16R16F,0x0 ,0x0 ,0x0 ,0x0 ,8 ,0 ,0 ,FALSE }, + /* Palettized formats */ + {WINED3DFMT_A8P8 ,0x0000ff00 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_P8 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,FALSE }, + /* Standard ARGB formats. Keep WINED3DFMT_R8G8B8(=20) at position 20 */ + {WINED3DFMT_R8G8B8 ,0x0 ,0x00ff0000 ,0x0000ff00 ,0x000000ff ,3 ,0 ,0 ,FALSE }, + {WINED3DFMT_A8R8G8B8 ,0xff000000 ,0x00ff0000 ,0x0000ff00 ,0x000000ff ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_X8R8G8B8 ,0x0 ,0x00ff0000 ,0x0000ff00 ,0x000000ff ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_R5G6B5 ,0x0 ,0x0000F800 ,0x000007e0 ,0x0000001f ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_X1R5G5B5 ,0x0 ,0x00007c00 ,0x000003e0 ,0x0000001f ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_A1R5G5B5 ,0x00008000 ,0x00007c00 ,0x000003e0 ,0x0000001f ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_A4R4G4B4 ,0x0000f000 ,0x00000f00 ,0x000000f0 ,0x0000000f ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_R3G3B2 ,0x0 ,0x000000e0 ,0x0000001c ,0x00000003 ,1 ,0 ,0 ,FALSE }, + {WINED3DFMT_A8 ,0x000000ff ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,FALSE }, + {WINED3DFMT_A8R3G3B2 ,0x0000ff00 ,0x000000e0 ,0x0000001c ,0x00000003 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_X4R4G4B4 ,0x0 ,0x00000f00 ,0x000000f0 ,0x0000000f ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_A2B10G10R10 ,0xb0000000 ,0x000003ff ,0x000ffc00 ,0x3ff00000 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_A8B8G8R8 ,0xff000000 ,0x000000ff ,0x0000ff00 ,0x00ff0000 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_X8B8G8R8 ,0x0 ,0x000000ff ,0x0000ff00 ,0x00ff0000 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_G16R16 ,0x0 ,0x0000ffff ,0xffff0000 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_A2R10G10B10 ,0xb0000000 ,0x3ff00000 ,0x000ffc00 ,0x000003ff ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_A16B16G16R16,0x0 ,0x0000ffff ,0xffff0000 ,0x0 ,8 ,0 ,0 ,FALSE }, + /* Luminance */ + {WINED3DFMT_L8 ,0x0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,FALSE }, + {WINED3DFMT_A8L8 ,0x0000ff00 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_A4L4 ,0x000000f0 ,0x0 ,0x0 ,0x0 ,1 ,0 ,0 ,FALSE }, + /* Bump mapping stuff */ + {WINED3DFMT_V8U8 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_L6V5U5 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_X8L8V8U8 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_Q8W8V8U8 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_V16U16 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_W11V11U10 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_A2W10V10U10 ,0xb0000000 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + /* Depth stencil formats */ + {WINED3DFMT_D16_LOCKABLE,0x0 ,0x0 ,0x0 ,0x0 ,2 ,16 ,0 ,FALSE }, + {WINED3DFMT_D32 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,32 ,0 ,FALSE }, + {WINED3DFMT_D15S1 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,15 ,1 ,FALSE }, + {WINED3DFMT_D24S8 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,24 ,8 ,FALSE }, + {WINED3DFMT_D24X8 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,24 ,0 ,FALSE }, + {WINED3DFMT_D24X4S4 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,24 ,4 ,FALSE }, + {WINED3DFMT_D16 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,16 ,0 ,FALSE }, + {WINED3DFMT_L16 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,16 ,0 ,FALSE }, + {WINED3DFMT_D32F_LOCKABLE,0x0 ,0x0 ,0x0 ,0x0 ,4 ,32 ,0 ,FALSE }, + {WINED3DFMT_D24FS8 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,24 ,8 ,FALSE }, + /* Is this a vertex buffer? */ + {WINED3DFMT_VERTEXDATA ,0x0 ,0x0 ,0x0 ,0x0 ,0 ,0 ,0 ,FALSE }, + {WINED3DFMT_INDEX16 ,0x0 ,0x0 ,0x0 ,0x0 ,2 ,0 ,0 ,FALSE }, + {WINED3DFMT_INDEX32 ,0x0 ,0x0 ,0x0 ,0x0 ,4 ,0 ,0 ,FALSE }, + {WINED3DFMT_Q16W16V16U16,0x0 ,0x0 ,0x0 ,0x0 ,8 ,0 ,0 ,FALSE }, +}; + +typedef struct { + WINED3DFORMAT fmt; + GLint glInternal, glGammaInternal, glFormat, glType; +} GlPixelFormatDescTemplate; + +/***************************************************************************** + * OpenGL format template. Contains unexciting formats which do not need + * extension checks. The order in this table is independent of the order in + * the table StaticPixelFormatDesc above. Not all formats have to be in this + * table. + */ +static const GlPixelFormatDescTemplate gl_formats_template[] = { + /*{ internal ,srgbInternal ,format ,type }*/ + {WINED3DFMT_UNKNOWN ,0 ,0 ,0 ,0 }, + /* FourCC formats */ + {WINED3DFMT_UYVY ,0 ,0 ,0 ,0 }, + {WINED3DFMT_YUY2 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_DXT1 ,GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ,GL_RGBA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_DXT2 ,GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ,GL_RGBA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_DXT3 ,GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ,GL_RGBA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_DXT4 ,GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT ,GL_RGBA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_DXT5 ,GL_COMPRESSED_RGBA_S3TC_DXT5_EXT ,GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT ,GL_RGBA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_MULTI2_ARGB8 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_G8R8_G8B8 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_R8G8_B8G8 ,0 ,0 ,0 ,0 }, + /* IEEE formats */ + {WINED3DFMT_R32F ,GL_RGB32F_ARB ,GL_RGB32F_ARB ,GL_RED ,GL_FLOAT }, + {WINED3DFMT_G32R32F ,0 ,0 ,0 ,0 }, + {WINED3DFMT_A32B32G32R32F ,GL_RGBA32F_ARB ,GL_RGBA32F_ARB ,GL_RGBA ,GL_FLOAT }, + /* Hmm? */ + {WINED3DFMT_CxV8U8 ,0 ,0 ,0 ,0 }, + /* Float */ + {WINED3DFMT_R16F ,GL_RGB16F_ARB ,GL_RGB16F_ARB ,GL_RED ,GL_HALF_FLOAT_ARB }, + {WINED3DFMT_G16R16F ,0 ,0 ,0 ,0 }, + {WINED3DFMT_A16B16G16R16F ,GL_RGBA16F_ARB ,GL_RGBA16F_ARB ,GL_RGBA ,GL_HALF_FLOAT_ARB }, + /* Palettized formats */ + {WINED3DFMT_A8P8, 0 ,0 ,0 ,0 }, + {WINED3DFMT_P8, GL_COLOR_INDEX8_EXT ,GL_COLOR_INDEX8_EXT ,GL_COLOR_INDEX ,GL_UNSIGNED_BYTE }, + /* Standard ARGB formats */ + {WINED3DFMT_R8G8B8 ,GL_RGB8 ,GL_RGB8 ,GL_BGR ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_A8R8G8B8 ,GL_RGBA8 ,GL_SRGB8_ALPHA8_EXT ,GL_BGRA ,GL_UNSIGNED_INT_8_8_8_8_REV }, + {WINED3DFMT_X8R8G8B8 ,GL_RGB8 ,GL_SRGB8_EXT ,GL_BGRA ,GL_UNSIGNED_INT_8_8_8_8_REV }, + {WINED3DFMT_R5G6B5 ,GL_RGB5 ,GL_RGB5 ,GL_RGB ,GL_UNSIGNED_SHORT_5_6_5 }, + {WINED3DFMT_X1R5G5B5 ,GL_RGB5_A1 ,GL_RGB5_A1 ,GL_BGRA ,GL_UNSIGNED_SHORT_1_5_5_5_REV }, + {WINED3DFMT_A1R5G5B5 ,GL_RGB5_A1 ,GL_RGB5_A1 ,GL_BGRA ,GL_UNSIGNED_SHORT_1_5_5_5_REV }, + {WINED3DFMT_A4R4G4B4 ,GL_RGBA4 ,GL_SRGB8_ALPHA8_EXT ,GL_BGRA ,GL_UNSIGNED_SHORT_4_4_4_4_REV }, + {WINED3DFMT_R3G3B2 ,GL_R3_G3_B2 ,GL_R3_G3_B2 ,GL_RGB ,GL_UNSIGNED_BYTE_3_3_2 }, + {WINED3DFMT_A8 ,GL_ALPHA8 ,GL_ALPHA8 ,GL_ALPHA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_A8R3G3B2 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_X4R4G4B4 ,GL_RGB4 ,GL_RGB4 ,GL_BGRA ,GL_UNSIGNED_SHORT_4_4_4_4_REV }, + {WINED3DFMT_A2B10G10R10 ,GL_RGB ,GL_RGB ,GL_RGBA ,GL_UNSIGNED_INT_2_10_10_10_REV }, + {WINED3DFMT_A8B8G8R8 ,GL_RGBA8 ,GL_RGBA8 ,GL_RGBA ,GL_UNSIGNED_INT_8_8_8_8_REV }, + {WINED3DFMT_X8B8G8R8 ,GL_RGB8 ,GL_RGB8 ,GL_RGBA ,GL_UNSIGNED_INT_8_8_8_8_REV }, + {WINED3DFMT_G16R16 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_A2R10G10B10 ,GL_RGBA ,GL_RGBA ,GL_BGRA ,GL_UNSIGNED_INT_2_10_10_10_REV }, + {WINED3DFMT_A16B16G16R16 ,GL_RGBA16_EXT ,GL_RGBA16_EXT ,GL_RGBA ,GL_UNSIGNED_SHORT }, + /* Luminance */ + {WINED3DFMT_L8 ,GL_LUMINANCE8 ,GL_SLUMINANCE8_EXT ,GL_LUMINANCE ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_A8L8 ,GL_LUMINANCE8_ALPHA8 ,GL_SLUMINANCE8_ALPHA8_EXT ,GL_LUMINANCE_ALPHA ,GL_UNSIGNED_BYTE }, + {WINED3DFMT_A4L4 ,GL_LUMINANCE4_ALPHA4 ,GL_LUMINANCE4_ALPHA4 ,GL_LUMINANCE_ALPHA ,GL_UNSIGNED_BYTE }, + /* Bump mapping stuff */ + {WINED3DFMT_V8U8 ,GL_DSDT8_NV ,GL_DSDT8_NV ,GL_DSDT_NV ,GL_BYTE }, + {WINED3DFMT_L6V5U5 ,GL_COLOR_INDEX8_EXT ,GL_COLOR_INDEX8_EXT ,GL_COLOR_INDEX ,GL_UNSIGNED_SHORT_5_5_5_1 }, + {WINED3DFMT_X8L8V8U8 ,GL_DSDT8_MAG8_INTENSITY8_NV ,GL_DSDT8_MAG8_INTENSITY8_NV ,GL_DSDT_MAG_INTENSITY_NV ,GL_BYTE }, + {WINED3DFMT_Q8W8V8U8 ,GL_SIGNED_RGBA8_NV ,GL_SIGNED_RGBA8_NV ,GL_RGBA ,GL_BYTE }, + {WINED3DFMT_V16U16 ,GL_SIGNED_HILO16_NV ,GL_SIGNED_HILO16_NV ,GL_HILO_NV ,GL_SHORT }, + {WINED3DFMT_W11V11U10 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_A2W10V10U10 ,0 ,0 ,0 ,0 }, + /* Depth stencil formats */ + {WINED3DFMT_D16_LOCKABLE ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_SHORT }, + {WINED3DFMT_D32 ,GL_DEPTH_COMPONENT32_ARB ,GL_DEPTH_COMPONENT32_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_INT }, + {WINED3DFMT_D15S1 ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_SHORT }, + {WINED3DFMT_D24S8 ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_INT }, + {WINED3DFMT_D24X8 ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_INT }, + {WINED3DFMT_D24X4S4 ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_INT }, + {WINED3DFMT_D16 ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_UNSIGNED_SHORT }, + {WINED3DFMT_L16 ,GL_LUMINANCE16_EXT ,GL_LUMINANCE16_EXT ,GL_LUMINANCE ,GL_UNSIGNED_SHORT }, + {WINED3DFMT_D32F_LOCKABLE ,GL_DEPTH_COMPONENT32_ARB ,GL_DEPTH_COMPONENT32_ARB ,GL_DEPTH_COMPONENT ,GL_FLOAT }, + {WINED3DFMT_D24FS8 ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT24_ARB ,GL_DEPTH_COMPONENT ,GL_FLOAT }, + /* Is this a vertex buffer? */ + {WINED3DFMT_VERTEXDATA ,0 ,0 ,0 ,0 }, + {WINED3DFMT_INDEX16 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_INDEX32 ,0 ,0 ,0 ,0 }, + {WINED3DFMT_Q16W16V16U16 ,GL_COLOR_INDEX ,GL_COLOR_INDEX ,GL_COLOR_INDEX ,GL_UNSIGNED_SHORT } +}; + +static inline int getFmtIdx(WINED3DFORMAT fmt) { + /* First check if the format is at the position of its value. + * This will catch the argb formats before the loop is entered + */ + if(fmt < (sizeof(formats) / sizeof(formats[0])) && formats[fmt].format == fmt) { + return fmt; + } else { + unsigned int i; + for(i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) { + if(formats[i].format == fmt) { + return i; + } + } + } + return -1; +} + +BOOL initPixelFormats(WineD3D_GL_Info *gl_info) +{ + unsigned int src; + + gl_info->gl_formats = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(formats) / sizeof(formats[0]) * sizeof(gl_info->gl_formats[0])); + if(!gl_info->gl_formats) return FALSE; + + /* If a format depends on some extensions, remove them from the table above and initialize them + * after this loop + */ + for(src = 0; src < sizeof(gl_formats_template) / sizeof(gl_formats_template[0]); src++) { + int dst = getFmtIdx(gl_formats_template[src].fmt); + gl_info->gl_formats[dst].glInternal = gl_formats_template[src].glInternal; + gl_info->gl_formats[dst].glGammaInternal = gl_formats_template[src].glGammaInternal; + gl_info->gl_formats[dst].glFormat = gl_formats_template[src].glFormat; + gl_info->gl_formats[dst].glType = gl_formats_template[src].glType; + } + + return TRUE; +} + +const StaticPixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt, WineD3D_GL_Info *gl_info, const GlPixelFormatDesc **glDesc) +{ + int idx = getFmtIdx(fmt); + + if(idx == -1) { + FIXME("Can't find format %s(%d) in the format lookup table\n", debug_d3dformat(fmt), fmt); + /* Get the caller a valid pointer */ + idx = getFmtIdx(WINED3DFMT_UNKNOWN); + } + if(glDesc) { + if(!gl_info) { + ERR("OpenGL pixel format information was requested, but no gl info structure passed\n"); + return NULL; + } + *glDesc = &gl_info->gl_formats[idx]; + } + return &formats[idx]; +} + +/***************************************************************************** + * Trace formatting of useful values + */ +const char* debug_d3dformat(WINED3DFORMAT fmt) { + switch (fmt) { +#define FMT_TO_STR(fmt) case fmt: return #fmt + FMT_TO_STR(WINED3DFMT_UNKNOWN); + FMT_TO_STR(WINED3DFMT_R8G8B8); + FMT_TO_STR(WINED3DFMT_A8R8G8B8); + FMT_TO_STR(WINED3DFMT_X8R8G8B8); + FMT_TO_STR(WINED3DFMT_R5G6B5); + FMT_TO_STR(WINED3DFMT_X1R5G5B5); + FMT_TO_STR(WINED3DFMT_A1R5G5B5); + FMT_TO_STR(WINED3DFMT_A4R4G4B4); + FMT_TO_STR(WINED3DFMT_R3G3B2); + FMT_TO_STR(WINED3DFMT_A8); + FMT_TO_STR(WINED3DFMT_A8R3G3B2); + FMT_TO_STR(WINED3DFMT_X4R4G4B4); + FMT_TO_STR(WINED3DFMT_A2B10G10R10); + FMT_TO_STR(WINED3DFMT_A8B8G8R8); + FMT_TO_STR(WINED3DFMT_X8B8G8R8); + FMT_TO_STR(WINED3DFMT_G16R16); + FMT_TO_STR(WINED3DFMT_A2R10G10B10); + FMT_TO_STR(WINED3DFMT_A16B16G16R16); + FMT_TO_STR(WINED3DFMT_A8P8); + FMT_TO_STR(WINED3DFMT_P8); + FMT_TO_STR(WINED3DFMT_L8); + FMT_TO_STR(WINED3DFMT_A8L8); + FMT_TO_STR(WINED3DFMT_A4L4); + FMT_TO_STR(WINED3DFMT_V8U8); + FMT_TO_STR(WINED3DFMT_L6V5U5); + FMT_TO_STR(WINED3DFMT_X8L8V8U8); + FMT_TO_STR(WINED3DFMT_Q8W8V8U8); + FMT_TO_STR(WINED3DFMT_V16U16); + FMT_TO_STR(WINED3DFMT_W11V11U10); + FMT_TO_STR(WINED3DFMT_A2W10V10U10); + FMT_TO_STR(WINED3DFMT_UYVY); + FMT_TO_STR(WINED3DFMT_YUY2); + FMT_TO_STR(WINED3DFMT_DXT1); + FMT_TO_STR(WINED3DFMT_DXT2); + FMT_TO_STR(WINED3DFMT_DXT3); + FMT_TO_STR(WINED3DFMT_DXT4); + FMT_TO_STR(WINED3DFMT_DXT5); + FMT_TO_STR(WINED3DFMT_MULTI2_ARGB8); + FMT_TO_STR(WINED3DFMT_G8R8_G8B8); + FMT_TO_STR(WINED3DFMT_R8G8_B8G8); + FMT_TO_STR(WINED3DFMT_D16_LOCKABLE); + FMT_TO_STR(WINED3DFMT_D32); + FMT_TO_STR(WINED3DFMT_D15S1); + FMT_TO_STR(WINED3DFMT_D24S8); + FMT_TO_STR(WINED3DFMT_D24X8); + FMT_TO_STR(WINED3DFMT_D24X4S4); + FMT_TO_STR(WINED3DFMT_D16); + FMT_TO_STR(WINED3DFMT_L16); + FMT_TO_STR(WINED3DFMT_D32F_LOCKABLE); + FMT_TO_STR(WINED3DFMT_D24FS8); + FMT_TO_STR(WINED3DFMT_VERTEXDATA); + FMT_TO_STR(WINED3DFMT_INDEX16); + FMT_TO_STR(WINED3DFMT_INDEX32); + FMT_TO_STR(WINED3DFMT_Q16W16V16U16); + FMT_TO_STR(WINED3DFMT_R16F); + FMT_TO_STR(WINED3DFMT_G16R16F); + FMT_TO_STR(WINED3DFMT_A16B16G16R16F); + FMT_TO_STR(WINED3DFMT_R32F); + FMT_TO_STR(WINED3DFMT_G32R32F); + FMT_TO_STR(WINED3DFMT_A32B32G32R32F); + FMT_TO_STR(WINED3DFMT_CxV8U8); +#undef FMT_TO_STR + default: + { + char fourcc[5]; + fourcc[0] = (char)(fmt); + fourcc[1] = (char)(fmt >> 8); + fourcc[2] = (char)(fmt >> 16); + fourcc[3] = (char)(fmt >> 24); + fourcc[4] = 0; + if( isprint(fourcc[0]) && isprint(fourcc[1]) && isprint(fourcc[2]) && isprint(fourcc[3]) ) + FIXME("Unrecognized %u (as fourcc: %s) WINED3DFORMAT!\n", fmt, fourcc); + else + FIXME("Unrecognized %u WINED3DFORMAT!\n", fmt); + } + return "unrecognized"; + } +} + +const char* debug_d3ddevicetype(WINED3DDEVTYPE devtype) { + switch (devtype) { +#define DEVTYPE_TO_STR(dev) case dev: return #dev + DEVTYPE_TO_STR(WINED3DDEVTYPE_HAL); + DEVTYPE_TO_STR(WINED3DDEVTYPE_REF); + DEVTYPE_TO_STR(WINED3DDEVTYPE_SW); +#undef DEVTYPE_TO_STR + default: + FIXME("Unrecognized %u WINED3DDEVTYPE!\n", devtype); + return "unrecognized"; + } +} + +const char* debug_d3dusage(DWORD usage) { + switch (usage & WINED3DUSAGE_MASK) { +#define WINED3DUSAGE_TO_STR(u) case u: return #u + WINED3DUSAGE_TO_STR(WINED3DUSAGE_RENDERTARGET); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_DEPTHSTENCIL); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_WRITEONLY); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_SOFTWAREPROCESSING); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_DONOTCLIP); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_POINTS); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_RTPATCHES); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_NPATCHES); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_DYNAMIC); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_AUTOGENMIPMAP); + WINED3DUSAGE_TO_STR(WINED3DUSAGE_DMAP); +#undef WINED3DUSAGE_TO_STR + case 0: return "none"; + default: + FIXME("Unrecognized %u Usage!\n", usage); + return "unrecognized"; + } +} + +const char* debug_d3dusagequery(DWORD usagequery) { + switch (usagequery & WINED3DUSAGE_QUERY_MASK) { +#define WINED3DUSAGEQUERY_TO_STR(u) case u: return #u + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_FILTER); + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_LEGACYBUMPMAP); + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING); + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_SRGBREAD); + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_SRGBWRITE); + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_VERTEXTEXTURE); + WINED3DUSAGEQUERY_TO_STR(WINED3DUSAGE_QUERY_WRAPANDMIP); +#undef WINED3DUSAGEQUERY_TO_STR + case 0: return "none"; + default: + FIXME("Unrecognized %u Usage Query!\n", usagequery); + return "unrecognized"; + } +} + +const char* debug_d3ddeclmethod(WINED3DDECLMETHOD method) { + switch (method) { +#define WINED3DDECLMETHOD_TO_STR(u) case u: return #u + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_DEFAULT); + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_PARTIALU); + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_PARTIALV); + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_CROSSUV); + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_UV); + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_LOOKUP); + WINED3DDECLMETHOD_TO_STR(WINED3DDECLMETHOD_LOOKUPPRESAMPLED); +#undef WINED3DDECLMETHOD_TO_STR + default: + FIXME("Unrecognized %u declaration method!\n", method); + return "unrecognized"; + } +} + +const char* debug_d3ddecltype(WINED3DDECLTYPE type) { + switch (type) { +#define WINED3DDECLTYPE_TO_STR(u) case u: return #u + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_FLOAT1); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_FLOAT2); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_FLOAT3); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_FLOAT4); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_D3DCOLOR); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_UBYTE4); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_SHORT2); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_SHORT4); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_UBYTE4N); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_SHORT2N); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_SHORT4N); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_USHORT2N); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_USHORT4N); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_UDEC3); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_DEC3N); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_FLOAT16_2); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_FLOAT16_4); + WINED3DDECLTYPE_TO_STR(WINED3DDECLTYPE_UNUSED); +#undef WINED3DDECLTYPE_TO_STR + default: + FIXME("Unrecognized %u declaration type!\n", type); + return "unrecognized"; + } +} + +const char* debug_d3ddeclusage(BYTE usage) { + switch (usage) { +#define WINED3DDECLUSAGE_TO_STR(u) case u: return #u + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_POSITION); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_BLENDWEIGHT); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_BLENDINDICES); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_NORMAL); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_PSIZE); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_TEXCOORD); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_TANGENT); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_BINORMAL); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_TESSFACTOR); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_POSITIONT); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_COLOR); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_FOG); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_DEPTH); + WINED3DDECLUSAGE_TO_STR(WINED3DDECLUSAGE_SAMPLE); +#undef WINED3DDECLUSAGE_TO_STR + default: + FIXME("Unrecognized %u declaration usage!\n", usage); + return "unrecognized"; + } +} + +const char* debug_d3dresourcetype(WINED3DRESOURCETYPE res) { + switch (res) { +#define RES_TO_STR(res) case res: return #res; + RES_TO_STR(WINED3DRTYPE_SURFACE); + RES_TO_STR(WINED3DRTYPE_VOLUME); + RES_TO_STR(WINED3DRTYPE_TEXTURE); + RES_TO_STR(WINED3DRTYPE_VOLUMETEXTURE); + RES_TO_STR(WINED3DRTYPE_CUBETEXTURE); + RES_TO_STR(WINED3DRTYPE_VERTEXBUFFER); + RES_TO_STR(WINED3DRTYPE_INDEXBUFFER); +#undef RES_TO_STR + default: + FIXME("Unrecognized %u WINED3DRESOURCETYPE!\n", res); + return "unrecognized"; + } +} + +const char* debug_d3dprimitivetype(WINED3DPRIMITIVETYPE PrimitiveType) { + switch (PrimitiveType) { +#define PRIM_TO_STR(prim) case prim: return #prim; + PRIM_TO_STR(WINED3DPT_POINTLIST); + PRIM_TO_STR(WINED3DPT_LINELIST); + PRIM_TO_STR(WINED3DPT_LINESTRIP); + PRIM_TO_STR(WINED3DPT_TRIANGLELIST); + PRIM_TO_STR(WINED3DPT_TRIANGLESTRIP); + PRIM_TO_STR(WINED3DPT_TRIANGLEFAN); +#undef PRIM_TO_STR + default: + FIXME("Unrecognized %u WINED3DPRIMITIVETYPE!\n", PrimitiveType); + return "unrecognized"; + } +} + +const char* debug_d3drenderstate(DWORD state) { + switch (state) { +#define D3DSTATE_TO_STR(u) case u: return #u + D3DSTATE_TO_STR(WINED3DRS_TEXTUREHANDLE ); + D3DSTATE_TO_STR(WINED3DRS_ANTIALIAS ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREADDRESS ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREPERSPECTIVE ); + D3DSTATE_TO_STR(WINED3DRS_WRAPU ); + D3DSTATE_TO_STR(WINED3DRS_WRAPV ); + D3DSTATE_TO_STR(WINED3DRS_ZENABLE ); + D3DSTATE_TO_STR(WINED3DRS_FILLMODE ); + D3DSTATE_TO_STR(WINED3DRS_SHADEMODE ); + D3DSTATE_TO_STR(WINED3DRS_LINEPATTERN ); + D3DSTATE_TO_STR(WINED3DRS_MONOENABLE ); + D3DSTATE_TO_STR(WINED3DRS_ROP2 ); + D3DSTATE_TO_STR(WINED3DRS_PLANEMASK ); + D3DSTATE_TO_STR(WINED3DRS_ZWRITEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_ALPHATESTENABLE ); + D3DSTATE_TO_STR(WINED3DRS_LASTPIXEL ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREMAG ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREMIN ); + D3DSTATE_TO_STR(WINED3DRS_SRCBLEND ); + D3DSTATE_TO_STR(WINED3DRS_DESTBLEND ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREMAPBLEND ); + D3DSTATE_TO_STR(WINED3DRS_CULLMODE ); + D3DSTATE_TO_STR(WINED3DRS_ZFUNC ); + D3DSTATE_TO_STR(WINED3DRS_ALPHAREF ); + D3DSTATE_TO_STR(WINED3DRS_ALPHAFUNC ); + D3DSTATE_TO_STR(WINED3DRS_DITHERENABLE ); + D3DSTATE_TO_STR(WINED3DRS_ALPHABLENDENABLE ); + D3DSTATE_TO_STR(WINED3DRS_FOGENABLE ); + D3DSTATE_TO_STR(WINED3DRS_SPECULARENABLE ); + D3DSTATE_TO_STR(WINED3DRS_ZVISIBLE ); + D3DSTATE_TO_STR(WINED3DRS_SUBPIXEL ); + D3DSTATE_TO_STR(WINED3DRS_SUBPIXELX ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEDALPHA ); + D3DSTATE_TO_STR(WINED3DRS_FOGCOLOR ); + D3DSTATE_TO_STR(WINED3DRS_FOGTABLEMODE ); + D3DSTATE_TO_STR(WINED3DRS_FOGSTART ); + D3DSTATE_TO_STR(WINED3DRS_FOGEND ); + D3DSTATE_TO_STR(WINED3DRS_FOGDENSITY ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_EDGEANTIALIAS ); + D3DSTATE_TO_STR(WINED3DRS_COLORKEYENABLE ); + D3DSTATE_TO_STR(WINED3DRS_BORDERCOLOR ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREADDRESSU ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREADDRESSV ); + D3DSTATE_TO_STR(WINED3DRS_MIPMAPLODBIAS ); + D3DSTATE_TO_STR(WINED3DRS_ZBIAS ); + D3DSTATE_TO_STR(WINED3DRS_RANGEFOGENABLE ); + D3DSTATE_TO_STR(WINED3DRS_ANISOTROPY ); + D3DSTATE_TO_STR(WINED3DRS_FLUSHBATCH ); + D3DSTATE_TO_STR(WINED3DRS_TRANSLUCENTSORTINDEPENDENT); + D3DSTATE_TO_STR(WINED3DRS_STENCILENABLE ); + D3DSTATE_TO_STR(WINED3DRS_STENCILFAIL ); + D3DSTATE_TO_STR(WINED3DRS_STENCILZFAIL ); + D3DSTATE_TO_STR(WINED3DRS_STENCILPASS ); + D3DSTATE_TO_STR(WINED3DRS_STENCILFUNC ); + D3DSTATE_TO_STR(WINED3DRS_STENCILREF ); + D3DSTATE_TO_STR(WINED3DRS_STENCILMASK ); + D3DSTATE_TO_STR(WINED3DRS_STENCILWRITEMASK ); + D3DSTATE_TO_STR(WINED3DRS_TEXTUREFACTOR ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN00 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN01 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN02 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN03 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN04 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN05 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN06 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN07 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN08 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN09 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN10 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN11 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN12 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN13 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN14 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN15 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN16 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN17 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN18 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN19 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN20 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN21 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN22 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN23 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN24 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN25 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN26 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN27 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN28 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN29 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN30 ); + D3DSTATE_TO_STR(WINED3DRS_STIPPLEPATTERN31 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP0 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP1 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP2 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP3 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP4 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP5 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP6 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP7 ); + D3DSTATE_TO_STR(WINED3DRS_CLIPPING ); + D3DSTATE_TO_STR(WINED3DRS_LIGHTING ); + D3DSTATE_TO_STR(WINED3DRS_EXTENTS ); + D3DSTATE_TO_STR(WINED3DRS_AMBIENT ); + D3DSTATE_TO_STR(WINED3DRS_FOGVERTEXMODE ); + D3DSTATE_TO_STR(WINED3DRS_COLORVERTEX ); + D3DSTATE_TO_STR(WINED3DRS_LOCALVIEWER ); + D3DSTATE_TO_STR(WINED3DRS_NORMALIZENORMALS ); + D3DSTATE_TO_STR(WINED3DRS_COLORKEYBLENDENABLE ); + D3DSTATE_TO_STR(WINED3DRS_DIFFUSEMATERIALSOURCE ); + D3DSTATE_TO_STR(WINED3DRS_SPECULARMATERIALSOURCE ); + D3DSTATE_TO_STR(WINED3DRS_AMBIENTMATERIALSOURCE ); + D3DSTATE_TO_STR(WINED3DRS_EMISSIVEMATERIALSOURCE ); + D3DSTATE_TO_STR(WINED3DRS_VERTEXBLEND ); + D3DSTATE_TO_STR(WINED3DRS_CLIPPLANEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_SOFTWAREVERTEXPROCESSING ); + D3DSTATE_TO_STR(WINED3DRS_POINTSIZE ); + D3DSTATE_TO_STR(WINED3DRS_POINTSIZE_MIN ); + D3DSTATE_TO_STR(WINED3DRS_POINTSPRITEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_POINTSCALEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_POINTSCALE_A ); + D3DSTATE_TO_STR(WINED3DRS_POINTSCALE_B ); + D3DSTATE_TO_STR(WINED3DRS_POINTSCALE_C ); + D3DSTATE_TO_STR(WINED3DRS_MULTISAMPLEANTIALIAS ); + D3DSTATE_TO_STR(WINED3DRS_MULTISAMPLEMASK ); + D3DSTATE_TO_STR(WINED3DRS_PATCHEDGESTYLE ); + D3DSTATE_TO_STR(WINED3DRS_PATCHSEGMENTS ); + D3DSTATE_TO_STR(WINED3DRS_DEBUGMONITORTOKEN ); + D3DSTATE_TO_STR(WINED3DRS_POINTSIZE_MAX ); + D3DSTATE_TO_STR(WINED3DRS_INDEXEDVERTEXBLENDENABLE ); + D3DSTATE_TO_STR(WINED3DRS_COLORWRITEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_TWEENFACTOR ); + D3DSTATE_TO_STR(WINED3DRS_BLENDOP ); + D3DSTATE_TO_STR(WINED3DRS_POSITIONDEGREE ); + D3DSTATE_TO_STR(WINED3DRS_NORMALDEGREE ); + D3DSTATE_TO_STR(WINED3DRS_SCISSORTESTENABLE ); + D3DSTATE_TO_STR(WINED3DRS_SLOPESCALEDEPTHBIAS ); + D3DSTATE_TO_STR(WINED3DRS_ANTIALIASEDLINEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_MINTESSELLATIONLEVEL ); + D3DSTATE_TO_STR(WINED3DRS_MAXTESSELLATIONLEVEL ); + D3DSTATE_TO_STR(WINED3DRS_ADAPTIVETESS_X ); + D3DSTATE_TO_STR(WINED3DRS_ADAPTIVETESS_Y ); + D3DSTATE_TO_STR(WINED3DRS_ADAPTIVETESS_Z ); + D3DSTATE_TO_STR(WINED3DRS_ADAPTIVETESS_W ); + D3DSTATE_TO_STR(WINED3DRS_ENABLEADAPTIVETESSELLATION); + D3DSTATE_TO_STR(WINED3DRS_TWOSIDEDSTENCILMODE ); + D3DSTATE_TO_STR(WINED3DRS_CCW_STENCILFAIL ); + D3DSTATE_TO_STR(WINED3DRS_CCW_STENCILZFAIL ); + D3DSTATE_TO_STR(WINED3DRS_CCW_STENCILPASS ); + D3DSTATE_TO_STR(WINED3DRS_CCW_STENCILFUNC ); + D3DSTATE_TO_STR(WINED3DRS_COLORWRITEENABLE1 ); + D3DSTATE_TO_STR(WINED3DRS_COLORWRITEENABLE2 ); + D3DSTATE_TO_STR(WINED3DRS_COLORWRITEENABLE3 ); + D3DSTATE_TO_STR(WINED3DRS_BLENDFACTOR ); + D3DSTATE_TO_STR(WINED3DRS_SRGBWRITEENABLE ); + D3DSTATE_TO_STR(WINED3DRS_DEPTHBIAS ); + D3DSTATE_TO_STR(WINED3DRS_WRAP8 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP9 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP10 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP11 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP12 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP13 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP14 ); + D3DSTATE_TO_STR(WINED3DRS_WRAP15 ); + D3DSTATE_TO_STR(WINED3DRS_SEPARATEALPHABLENDENABLE ); + D3DSTATE_TO_STR(WINED3DRS_SRCBLENDALPHA ); + D3DSTATE_TO_STR(WINED3DRS_DESTBLENDALPHA ); + D3DSTATE_TO_STR(WINED3DRS_BLENDOPALPHA ); +#undef D3DSTATE_TO_STR + default: + FIXME("Unrecognized %u render state!\n", state); + return "unrecognized"; + } +} + +const char* debug_d3dsamplerstate(DWORD state) { + switch (state) { +#define D3DSTATE_TO_STR(u) case u: return #u + D3DSTATE_TO_STR(WINED3DSAMP_BORDERCOLOR ); + D3DSTATE_TO_STR(WINED3DSAMP_ADDRESSU ); + D3DSTATE_TO_STR(WINED3DSAMP_ADDRESSV ); + D3DSTATE_TO_STR(WINED3DSAMP_ADDRESSW ); + D3DSTATE_TO_STR(WINED3DSAMP_MAGFILTER ); + D3DSTATE_TO_STR(WINED3DSAMP_MINFILTER ); + D3DSTATE_TO_STR(WINED3DSAMP_MIPFILTER ); + D3DSTATE_TO_STR(WINED3DSAMP_MIPMAPLODBIAS); + D3DSTATE_TO_STR(WINED3DSAMP_MAXMIPLEVEL ); + D3DSTATE_TO_STR(WINED3DSAMP_MAXANISOTROPY); + D3DSTATE_TO_STR(WINED3DSAMP_SRGBTEXTURE ); + D3DSTATE_TO_STR(WINED3DSAMP_ELEMENTINDEX ); + D3DSTATE_TO_STR(WINED3DSAMP_DMAPOFFSET ); +#undef D3DSTATE_TO_STR + default: + FIXME("Unrecognized %u sampler state!\n", state); + return "unrecognized"; + } +} + +const char *debug_d3dtexturefiltertype(WINED3DTEXTUREFILTERTYPE filter_type) { + switch (filter_type) { +#define D3DTEXTUREFILTERTYPE_TO_STR(u) case u: return #u + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_NONE); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_POINT); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_LINEAR); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_ANISOTROPIC); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_FLATCUBIC); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_GAUSSIANCUBIC); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_PYRAMIDALQUAD); + D3DTEXTUREFILTERTYPE_TO_STR(WINED3DTEXF_GAUSSIANQUAD); +#undef D3DTEXTUREFILTERTYPE_TO_STR + default: + FIXME("Unrecognied texture filter type 0x%08x\n", filter_type); + return "unrecognized"; + } +} + +const char* debug_d3dtexturestate(DWORD state) { + switch (state) { +#define D3DSTATE_TO_STR(u) case u: return #u + D3DSTATE_TO_STR(WINED3DTSS_COLOROP ); + D3DSTATE_TO_STR(WINED3DTSS_COLORARG1 ); + D3DSTATE_TO_STR(WINED3DTSS_COLORARG2 ); + D3DSTATE_TO_STR(WINED3DTSS_ALPHAOP ); + D3DSTATE_TO_STR(WINED3DTSS_ALPHAARG1 ); + D3DSTATE_TO_STR(WINED3DTSS_ALPHAARG2 ); + D3DSTATE_TO_STR(WINED3DTSS_BUMPENVMAT00 ); + D3DSTATE_TO_STR(WINED3DTSS_BUMPENVMAT01 ); + D3DSTATE_TO_STR(WINED3DTSS_BUMPENVMAT10 ); + D3DSTATE_TO_STR(WINED3DTSS_BUMPENVMAT11 ); + D3DSTATE_TO_STR(WINED3DTSS_TEXCOORDINDEX ); + D3DSTATE_TO_STR(WINED3DTSS_BUMPENVLSCALE ); + D3DSTATE_TO_STR(WINED3DTSS_BUMPENVLOFFSET ); + D3DSTATE_TO_STR(WINED3DTSS_TEXTURETRANSFORMFLAGS ); + D3DSTATE_TO_STR(WINED3DTSS_ADDRESSW ); + D3DSTATE_TO_STR(WINED3DTSS_COLORARG0 ); + D3DSTATE_TO_STR(WINED3DTSS_ALPHAARG0 ); + D3DSTATE_TO_STR(WINED3DTSS_RESULTARG ); + D3DSTATE_TO_STR(WINED3DTSS_CONSTANT ); +#undef D3DSTATE_TO_STR + case 12: + /* Note WINED3DTSS are not consecutive, so skip these */ + return "unused"; + default: + FIXME("Unrecognized %u texture state!\n", state); + return "unrecognized"; + } +} + +static const char* debug_d3dtop(WINED3DTEXTUREOP d3dtop) { + switch (d3dtop) { +#define D3DTOP_TO_STR(u) case u: return #u + D3DTOP_TO_STR(WINED3DTOP_DISABLE); + D3DTOP_TO_STR(WINED3DTOP_SELECTARG1); + D3DTOP_TO_STR(WINED3DTOP_SELECTARG2); + D3DTOP_TO_STR(WINED3DTOP_MODULATE); + D3DTOP_TO_STR(WINED3DTOP_MODULATE2X); + D3DTOP_TO_STR(WINED3DTOP_MODULATE4X); + D3DTOP_TO_STR(WINED3DTOP_ADD); + D3DTOP_TO_STR(WINED3DTOP_ADDSIGNED); + D3DTOP_TO_STR(WINED3DTOP_SUBTRACT); + D3DTOP_TO_STR(WINED3DTOP_ADDSMOOTH); + D3DTOP_TO_STR(WINED3DTOP_BLENDDIFFUSEALPHA); + D3DTOP_TO_STR(WINED3DTOP_BLENDTEXTUREALPHA); + D3DTOP_TO_STR(WINED3DTOP_BLENDFACTORALPHA); + D3DTOP_TO_STR(WINED3DTOP_BLENDTEXTUREALPHAPM); + D3DTOP_TO_STR(WINED3DTOP_BLENDCURRENTALPHA); + D3DTOP_TO_STR(WINED3DTOP_PREMODULATE); + D3DTOP_TO_STR(WINED3DTOP_MODULATEALPHA_ADDCOLOR); + D3DTOP_TO_STR(WINED3DTOP_MODULATECOLOR_ADDALPHA); + D3DTOP_TO_STR(WINED3DTOP_MODULATEINVALPHA_ADDCOLOR); + D3DTOP_TO_STR(WINED3DTOP_MODULATEINVCOLOR_ADDALPHA); + D3DTOP_TO_STR(WINED3DTOP_BUMPENVMAP); + D3DTOP_TO_STR(WINED3DTOP_BUMPENVMAPLUMINANCE); + D3DTOP_TO_STR(WINED3DTOP_DOTPRODUCT3); + D3DTOP_TO_STR(WINED3DTOP_MULTIPLYADD); + D3DTOP_TO_STR(WINED3DTOP_LERP); +#undef D3DTOP_TO_STR + default: + FIXME("Unrecognized %u WINED3DTOP\n", d3dtop); + return "unrecognized"; + } +} + +const char* debug_d3dtstype(WINED3DTRANSFORMSTATETYPE tstype) { + switch (tstype) { +#define TSTYPE_TO_STR(tstype) case tstype: return #tstype + TSTYPE_TO_STR(WINED3DTS_VIEW); + TSTYPE_TO_STR(WINED3DTS_PROJECTION); + TSTYPE_TO_STR(WINED3DTS_TEXTURE0); + TSTYPE_TO_STR(WINED3DTS_TEXTURE1); + TSTYPE_TO_STR(WINED3DTS_TEXTURE2); + TSTYPE_TO_STR(WINED3DTS_TEXTURE3); + TSTYPE_TO_STR(WINED3DTS_TEXTURE4); + TSTYPE_TO_STR(WINED3DTS_TEXTURE5); + TSTYPE_TO_STR(WINED3DTS_TEXTURE6); + TSTYPE_TO_STR(WINED3DTS_TEXTURE7); + TSTYPE_TO_STR(WINED3DTS_WORLDMATRIX(0)); +#undef TSTYPE_TO_STR + default: + if (tstype > 256 && tstype < 512) { + FIXME("WINED3DTS_WORLDMATRIX(%u). 1..255 not currently supported\n", tstype); + return ("WINED3DTS_WORLDMATRIX > 0"); + } + FIXME("Unrecognized %u WINED3DTS\n", tstype); + return "unrecognized"; + } +} + +const char* debug_d3dpool(WINED3DPOOL Pool) { + switch (Pool) { +#define POOL_TO_STR(p) case p: return #p; + POOL_TO_STR(WINED3DPOOL_DEFAULT); + POOL_TO_STR(WINED3DPOOL_MANAGED); + POOL_TO_STR(WINED3DPOOL_SYSTEMMEM); + POOL_TO_STR(WINED3DPOOL_SCRATCH); +#undef POOL_TO_STR + default: + FIXME("Unrecognized %u WINED3DPOOL!\n", Pool); + return "unrecognized"; + } +} + +const char *debug_fbostatus(GLenum status) { + switch(status) { +#define FBOSTATUS_TO_STR(u) case u: return #u + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_COMPLETE_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT); + FBOSTATUS_TO_STR(GL_FRAMEBUFFER_UNSUPPORTED_EXT); +#undef FBOSTATUS_TO_STR + default: + FIXME("Unrecognied FBO status 0x%08x\n", status); + return "unrecognized"; + } +} + +const char *debug_glerror(GLenum error) { + switch(error) { +#define GLERROR_TO_STR(u) case u: return #u + GLERROR_TO_STR(GL_NO_ERROR); + GLERROR_TO_STR(GL_INVALID_ENUM); + GLERROR_TO_STR(GL_INVALID_VALUE); + GLERROR_TO_STR(GL_INVALID_OPERATION); + GLERROR_TO_STR(GL_STACK_OVERFLOW); + GLERROR_TO_STR(GL_STACK_UNDERFLOW); + GLERROR_TO_STR(GL_OUT_OF_MEMORY); + GLERROR_TO_STR(GL_INVALID_FRAMEBUFFER_OPERATION_EXT); +#undef GLERROR_TO_STR + default: + FIXME("Unrecognied GL error 0x%08x\n", error); + return "unrecognized"; + } +} + +const char *debug_d3dbasis(WINED3DBASISTYPE basis) { + switch(basis) { + case WINED3DBASIS_BEZIER: return "WINED3DBASIS_BEZIER"; + case WINED3DBASIS_BSPLINE: return "WINED3DBASIS_BSPLINE"; + case WINED3DBASIS_INTERPOLATE: return "WINED3DBASIS_INTERPOLATE"; + default: return "unrecognized"; + } +} + +const char *debug_d3ddegree(WINED3DDEGREETYPE degree) { + switch(degree) { + case WINED3DDEGREE_LINEAR: return "WINED3DDEGREE_LINEAR"; + case WINED3DDEGREE_QUADRATIC: return "WINED3DDEGREE_QUADRATIC"; + case WINED3DDEGREE_CUBIC: return "WINED3DDEGREE_CUBIC"; + case WINED3DDEGREE_QUINTIC: return "WINED3DDEGREE_QUINTIC"; + default: return "unrecognized"; + } +} + +/***************************************************************************** + * Useful functions mapping GL <-> D3D values + */ +GLenum StencilOp(DWORD op) { + switch(op) { + case WINED3DSTENCILOP_KEEP : return GL_KEEP; + case WINED3DSTENCILOP_ZERO : return GL_ZERO; + case WINED3DSTENCILOP_REPLACE : return GL_REPLACE; + case WINED3DSTENCILOP_INCRSAT : return GL_INCR; + case WINED3DSTENCILOP_DECRSAT : return GL_DECR; + case WINED3DSTENCILOP_INVERT : return GL_INVERT; + case WINED3DSTENCILOP_INCR : return GL_INCR_WRAP_EXT; + case WINED3DSTENCILOP_DECR : return GL_DECR_WRAP_EXT; + default: + FIXME("Unrecognized stencil op %d\n", op); + return GL_KEEP; + } +} + +GLenum CompareFunc(DWORD func) { + switch ((WINED3DCMPFUNC)func) { + case WINED3DCMP_NEVER : return GL_NEVER; + case WINED3DCMP_LESS : return GL_LESS; + case WINED3DCMP_EQUAL : return GL_EQUAL; + case WINED3DCMP_LESSEQUAL : return GL_LEQUAL; + case WINED3DCMP_GREATER : return GL_GREATER; + case WINED3DCMP_NOTEQUAL : return GL_NOTEQUAL; + case WINED3DCMP_GREATEREQUAL : return GL_GEQUAL; + case WINED3DCMP_ALWAYS : return GL_ALWAYS; + default: + FIXME("Unrecognized WINED3DCMPFUNC value %d\n", func); + return 0; + } +} + +static GLenum d3dta_to_combiner_input(DWORD d3dta, DWORD stage, INT texture_idx) { + switch (d3dta) { + case WINED3DTA_DIFFUSE: + return GL_PRIMARY_COLOR_NV; + + case WINED3DTA_CURRENT: + if (stage) return GL_SPARE0_NV; + else return GL_PRIMARY_COLOR_NV; + + case WINED3DTA_TEXTURE: + if (texture_idx > -1) return GL_TEXTURE0_ARB + texture_idx; + else return GL_PRIMARY_COLOR_NV; + + case WINED3DTA_TFACTOR: + return GL_CONSTANT_COLOR0_NV; + + case WINED3DTA_SPECULAR: + return GL_SECONDARY_COLOR_NV; + + case WINED3DTA_TEMP: + /* TODO: Support WINED3DTSS_RESULTARG */ + FIXME("WINED3DTA_TEMP, not properly supported.\n"); + return GL_SPARE1_NV; + + case WINED3DTA_CONSTANT: + /* TODO: Support per stage constants (WINED3DTSS_CONSTANT, NV_register_combiners2) */ + FIXME("WINED3DTA_CONSTANT, not properly supported.\n"); + return GL_CONSTANT_COLOR1_NV; + + default: + FIXME("Unrecognized texture arg %#x\n", d3dta); + return GL_TEXTURE; + } +} + +static GLenum invert_mapping(GLenum mapping) { + if (mapping == GL_UNSIGNED_INVERT_NV) return GL_SIGNED_IDENTITY_NV; + else if (mapping == GL_SIGNED_IDENTITY_NV) return GL_UNSIGNED_INVERT_NV; + + FIXME("Unhandled mapping %#x\n", mapping); + return mapping; +} + +static void get_src_and_opr_nvrc(DWORD stage, DWORD arg, BOOL is_alpha, GLenum* input, GLenum* mapping, GLenum *component_usage, INT texture_idx) { + /* The WINED3DTA_COMPLEMENT flag specifies the complement of the input should + * be used. */ + if (arg & WINED3DTA_COMPLEMENT) *mapping = GL_UNSIGNED_INVERT_NV; + else *mapping = GL_SIGNED_IDENTITY_NV; + + /* The WINED3DTA_ALPHAREPLICATE flag specifies the alpha component of the input + * should be used for all input components. */ + if (is_alpha || arg & WINED3DTA_ALPHAREPLICATE) *component_usage = GL_ALPHA; + else *component_usage = GL_RGB; + + *input = d3dta_to_combiner_input(arg & WINED3DTA_SELECTMASK, stage, texture_idx); +} + +typedef struct { + GLenum input[3]; + GLenum mapping[3]; + GLenum component_usage[3]; +} tex_op_args; + +static BOOL is_invalid_op(IWineD3DDeviceImpl *This, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3) { + if (op == WINED3DTOP_DISABLE) return FALSE; + if (This->stateBlock->textures[stage]) return FALSE; + + if ((arg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE + && op != WINED3DTOP_SELECTARG2) return TRUE; + if ((arg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE + && op != WINED3DTOP_SELECTARG1) return TRUE; + if ((arg3 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE + && (op == WINED3DTOP_MULTIPLYADD || op == WINED3DTOP_LERP)) return TRUE; + + return FALSE; +} + +void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl*)iface; + tex_op_args tex_op_args = {{0}, {0}, {0}}; + GLenum portion = is_alpha ? GL_ALPHA : GL_RGB; + GLenum target = GL_COMBINER0_NV + stage; + + TRACE("stage %d, is_alpha %d, op %s, arg1 %#x, arg2 %#x, arg3 %#x, texture_idx %d\n", + stage, is_alpha, debug_d3dtop(op), arg1, arg2, arg3, texture_idx); + + /* If a texture stage references an invalid texture unit the stage just + * passes through the result from the previous stage */ + if (is_invalid_op(This, stage, op, arg1, arg2, arg3)) { + arg1 = WINED3DTA_CURRENT; + op = WINED3DTOP_SELECTARG1; + } + + get_src_and_opr_nvrc(stage, arg1, is_alpha, &tex_op_args.input[0], + &tex_op_args.mapping[0], &tex_op_args.component_usage[0], texture_idx); + get_src_and_opr_nvrc(stage, arg2, is_alpha, &tex_op_args.input[1], + &tex_op_args.mapping[1], &tex_op_args.component_usage[1], texture_idx); + get_src_and_opr_nvrc(stage, arg3, is_alpha, &tex_op_args.input[2], + &tex_op_args.mapping[2], &tex_op_args.component_usage[2], texture_idx); + + + /* This is called by a state handler which has the gl lock held and a context for the thread */ + switch(op) + { + case WINED3DTOP_DISABLE: + /* Only for alpha */ + if (!is_alpha) ERR("Shouldn't be called for WINED3DTSS_COLOROP (WINED3DTOP_DISABLE)\n"); + /* Input, prev_alpha*1 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + GL_SPARE0_NV, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, GL_ALPHA)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_SELECTARG1: + case WINED3DTOP_SELECTARG2: + /* Input, arg*1 */ + if (op == WINED3DTOP_SELECTARG1) { + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + } else { + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + } + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_MODULATE: + case WINED3DTOP_MODULATE2X: + case WINED3DTOP_MODULATE4X: + /* Input, arg1*arg2 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + + /* Output */ + if (op == WINED3DTOP_MODULATE) { + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + } else if (op == WINED3DTOP_MODULATE2X) { + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_SCALE_BY_TWO_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + } else if (op == WINED3DTOP_MODULATE4X) { + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + } + break; + + case WINED3DTOP_ADD: + case WINED3DTOP_ADDSIGNED: + case WINED3DTOP_ADDSIGNED2X: + /* Input, arg1*1+arg2*1 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + if (op == WINED3DTOP_ADD) { + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + } else if (op == WINED3DTOP_ADDSIGNED) { + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE)); + } else if (op == WINED3DTOP_ADDSIGNED2X) { + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_SCALE_BY_TWO_NV, GL_BIAS_BY_NEGATIVE_ONE_HALF_NV, GL_FALSE, GL_FALSE, GL_FALSE)); + } + break; + + case WINED3DTOP_SUBTRACT: + /* Input, arg1*1+-arg2*1 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[1], GL_SIGNED_NEGATE_NV, tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_ADDSMOOTH: + /* Input, arg1*1+(1-arg1)*arg2 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_BLENDDIFFUSEALPHA: + case WINED3DTOP_BLENDTEXTUREALPHA: + case WINED3DTOP_BLENDFACTORALPHA: + case WINED3DTOP_BLENDTEXTUREALPHAPM: + case WINED3DTOP_BLENDCURRENTALPHA: + { + GLenum alpha_src = GL_PRIMARY_COLOR_NV; + if (op == WINED3DTOP_BLENDDIFFUSEALPHA) alpha_src = d3dta_to_combiner_input(WINED3DTA_DIFFUSE, stage, texture_idx); + else if (op == WINED3DTOP_BLENDTEXTUREALPHA) alpha_src = d3dta_to_combiner_input(WINED3DTA_TEXTURE, stage, texture_idx); + else if (op == WINED3DTOP_BLENDFACTORALPHA) alpha_src = d3dta_to_combiner_input(WINED3DTA_TFACTOR, stage, texture_idx); + else if (op == WINED3DTOP_BLENDTEXTUREALPHAPM) alpha_src = d3dta_to_combiner_input(WINED3DTA_TEXTURE, stage, texture_idx); + else if (op == WINED3DTOP_BLENDCURRENTALPHA) alpha_src = d3dta_to_combiner_input(WINED3DTA_CURRENT, stage, texture_idx); + else FIXME("Unhandled WINED3DTOP %s, shouldn't happen\n", debug_d3dtop(op)); + + /* Input, arg1*alpha_src+arg2*(1-alpha_src) */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + if (op == WINED3DTOP_BLENDTEXTUREALPHAPM) + { + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + } else { + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + alpha_src, GL_UNSIGNED_IDENTITY_NV, GL_ALPHA)); + } + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + alpha_src, GL_UNSIGNED_INVERT_NV, GL_ALPHA)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + } + + case WINED3DTOP_MODULATEALPHA_ADDCOLOR: + /* Input, arg1_alpha*arg2_rgb+arg1_rgb*1 */ + if (is_alpha) ERR("Only supported for WINED3DTSS_COLOROP (WINED3DTOP_MODULATEALPHA_ADDCOLOR)\n"); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], GL_ALPHA)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_MODULATECOLOR_ADDALPHA: + /* Input, arg1_rgb*arg2_rgb+arg1_alpha*1 */ + if (is_alpha) ERR("Only supported for WINED3DTSS_COLOROP (WINED3DTOP_MODULATECOLOR_ADDALPHA)\n"); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[0], tex_op_args.mapping[0], GL_ALPHA)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR: + /* Input, (1-arg1_alpha)*arg2_rgb+arg1_rgb*1 */ + if (is_alpha) ERR("Only supported for WINED3DTSS_COLOROP (WINED3DTOP_MODULATEINVALPHA_ADDCOLOR)\n"); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), GL_ALPHA)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA: + /* Input, (1-arg1_rgb)*arg2_rgb+arg1_alpha*1 */ + if (is_alpha) ERR("Only supported for WINED3DTSS_COLOROP (WINED3DTOP_MODULATEINVCOLOR_ADDALPHA)\n"); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[0], tex_op_args.mapping[0], GL_ALPHA)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_DOTPRODUCT3: + /* Input, arg1 . arg2 */ + /* FIXME: DX7 uses a different calculation? */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], GL_EXPAND_NORMAL_NV, tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], GL_EXPAND_NORMAL_NV, tex_op_args.component_usage[1])); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_NONE, GL_NONE, GL_TRUE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_MULTIPLYADD: + /* Input, arg1*1+arg2*arg3 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + tex_op_args.input[2], tex_op_args.mapping[2], tex_op_args.component_usage[2])); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_LERP: + /* Input, arg1*arg2+(1-arg1)*arg3 */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[0], tex_op_args.mapping[0], tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_C_NV, + tex_op_args.input[0], invert_mapping(tex_op_args.mapping[0]), tex_op_args.component_usage[0])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_D_NV, + tex_op_args.input[2], tex_op_args.mapping[2], tex_op_args.component_usage[2])); + + /* Output */ + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_DISCARD_NV, GL_DISCARD_NV, + GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + + case WINED3DTOP_BUMPENVMAPLUMINANCE: + case WINED3DTOP_BUMPENVMAP: + if(GL_SUPPORT(NV_TEXTURE_SHADER)) { + /* The bump map stage itself isn't exciting, just read the texture. But tell the next stage to + * perform bump mapping and source from the current stage. Pretty much a SELECTARG2. + * ARG2 is passed through unmodified(apps will most likely use D3DTA_CURRENT for arg2, arg1 + * (which will most likely be D3DTA_TEXTURE) is available as a texture shader input for the next stage + */ + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_A_NV, + tex_op_args.input[1], tex_op_args.mapping[1], tex_op_args.component_usage[1])); + GL_EXTCALL(glCombinerInputNV(target, portion, GL_VARIABLE_B_NV, + GL_ZERO, GL_UNSIGNED_INVERT_NV, portion)); + GL_EXTCALL(glCombinerOutputNV(target, portion, GL_SPARE0_NV, GL_DISCARD_NV, + GL_DISCARD_NV, GL_NONE, GL_NONE, GL_FALSE, GL_FALSE, GL_FALSE)); + break; + } + + default: + FIXME("Unhandled WINED3DTOP: stage %d, is_alpha %d, op %s (%#x), arg1 %#x, arg2 %#x, arg3 %#x, texture_idx %d\n", + stage, is_alpha, debug_d3dtop(op), op, arg1, arg2, arg3, texture_idx); + } + + checkGLcall("set_tex_op_nvrc()\n"); + +} + +static void get_src_and_opr(DWORD arg, BOOL is_alpha, GLenum* source, GLenum* operand) { + /* The WINED3DTA_ALPHAREPLICATE flag specifies the alpha component of the + * input should be used for all input components. The WINED3DTA_COMPLEMENT + * flag specifies the complement of the input should be used. */ + BOOL from_alpha = is_alpha || arg & WINED3DTA_ALPHAREPLICATE; + BOOL complement = arg & WINED3DTA_COMPLEMENT; + + /* Calculate the operand */ + if (complement) { + if (from_alpha) *operand = GL_ONE_MINUS_SRC_ALPHA; + else *operand = GL_ONE_MINUS_SRC_COLOR; + } else { + if (from_alpha) *operand = GL_SRC_ALPHA; + else *operand = GL_SRC_COLOR; + } + + /* Calculate the source */ + switch (arg & WINED3DTA_SELECTMASK) { + case WINED3DTA_CURRENT: *source = GL_PREVIOUS_EXT; break; + case WINED3DTA_DIFFUSE: *source = GL_PRIMARY_COLOR_EXT; break; + case WINED3DTA_TEXTURE: *source = GL_TEXTURE; break; + case WINED3DTA_TFACTOR: *source = GL_CONSTANT_EXT; break; + case WINED3DTA_SPECULAR: + /* + * According to the GL_ARB_texture_env_combine specs, SPECULAR is + * 'Secondary color' and isn't supported until base GL supports it + * There is no concept of temp registers as far as I can tell + */ + FIXME("Unhandled texture arg WINED3DTA_SPECULAR\n"); + *source = GL_TEXTURE; + break; + default: + FIXME("Unrecognized texture arg %#x\n", arg); + *source = GL_TEXTURE; + break; + } +} + +/* Set texture operations up - The following avoids lots of ifdefs in this routine!*/ +#if defined (GL_VERSION_1_3) +# define useext(A) A +# define combine_ext 1 +#elif defined (GL_EXT_texture_env_combine) +# define useext(A) A##_EXT +# define combine_ext 1 +#elif defined (GL_ARB_texture_env_combine) +# define useext(A) A##_ARB +# define combine_ext 1 +#else +# undef combine_ext +#endif + +#if !defined(combine_ext) +void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3) +{ + FIXME("Requires opengl combine extensions to work\n"); + return; +} +#else +/* Setup the texture operations texture stage states */ +void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3) +{ + GLenum src1, src2, src3; + GLenum opr1, opr2, opr3; + GLenum comb_target; + GLenum src0_target, src1_target, src2_target; + GLenum opr0_target, opr1_target, opr2_target; + GLenum scal_target; + GLenum opr=0, invopr, src3_target, opr3_target; + BOOL Handled = FALSE; + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; + + TRACE("Alpha?(%d), Stage:%d Op(%s), a1(%d), a2(%d), a3(%d)\n", isAlpha, Stage, debug_d3dtop(op), arg1, arg2, arg3); + + /* This is called by a state handler which has the gl lock held and a context for the thread */ + + /* Note: Operations usually involve two ars, src0 and src1 and are operations of + the form (a1 a2). However, some of the more complex operations + take 3 parameters. Instead of the (sensible) addition of a3, Microsoft added + in a third parameter called a0. Therefore these are operations of the form + a0 a1 a2, ie the new parameter goes to the front. + + However, below we treat the new (a0) parameter as src2/opr2, so in the actual + functions below, expect their syntax to differ slightly to those listed in the + manuals, ie replace arg1 with arg3, arg2 with arg1 and arg3 with arg2 + This affects WINED3DTOP_MULTIPLYADD and WINED3DTOP_LERP */ + + if (isAlpha) { + comb_target = useext(GL_COMBINE_ALPHA); + src0_target = useext(GL_SOURCE0_ALPHA); + src1_target = useext(GL_SOURCE1_ALPHA); + src2_target = useext(GL_SOURCE2_ALPHA); + opr0_target = useext(GL_OPERAND0_ALPHA); + opr1_target = useext(GL_OPERAND1_ALPHA); + opr2_target = useext(GL_OPERAND2_ALPHA); + scal_target = GL_ALPHA_SCALE; + } + else { + comb_target = useext(GL_COMBINE_RGB); + src0_target = useext(GL_SOURCE0_RGB); + src1_target = useext(GL_SOURCE1_RGB); + src2_target = useext(GL_SOURCE2_RGB); + opr0_target = useext(GL_OPERAND0_RGB); + opr1_target = useext(GL_OPERAND1_RGB); + opr2_target = useext(GL_OPERAND2_RGB); + scal_target = useext(GL_RGB_SCALE); + } + + /* If a texture stage references an invalid texture unit the stage just + * passes through the result from the previous stage */ + if (is_invalid_op(This, Stage, op, arg1, arg2, arg3)) { + arg1 = WINED3DTA_CURRENT; + op = WINED3DTOP_SELECTARG1; + } + + /* From MSDN (WINED3DTSS_ALPHAARG1) : + The default argument is WINED3DTA_TEXTURE. If no texture is set for this stage, + then the default argument is WINED3DTA_DIFFUSE. + FIXME? If texture added/removed, may need to reset back as well? */ + if (isAlpha && This->stateBlock->textures[Stage] == NULL && arg1 == WINED3DTA_TEXTURE) { + get_src_and_opr(WINED3DTA_DIFFUSE, isAlpha, &src1, &opr1); + } else { + get_src_and_opr(arg1, isAlpha, &src1, &opr1); + } + get_src_and_opr(arg2, isAlpha, &src2, &opr2); + get_src_and_opr(arg3, isAlpha, &src3, &opr3); + + TRACE("ct(%x), 1:(%x,%x), 2:(%x,%x), 3:(%x,%x)\n", comb_target, src1, opr1, src2, opr2, src3, opr3); + + Handled = TRUE; /* Assume will be handled */ + + /* Other texture operations require special extensions: */ + if (GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { + if (isAlpha) { + opr = GL_SRC_ALPHA; + invopr = GL_ONE_MINUS_SRC_ALPHA; + src3_target = GL_SOURCE3_ALPHA_NV; + opr3_target = GL_OPERAND3_ALPHA_NV; + } else { + opr = GL_SRC_COLOR; + invopr = GL_ONE_MINUS_SRC_COLOR; + src3_target = GL_SOURCE3_RGB_NV; + opr3_target = GL_OPERAND3_RGB_NV; + } + switch (op) { + case WINED3DTOP_DISABLE: /* Only for alpha */ + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, GL_PREVIOUS_EXT); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, GL_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src2_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr"); + break; + case WINED3DTOP_SELECTARG1: /* = a1 * 1 + 0 * 0 */ + case WINED3DTOP_SELECTARG2: /* = a2 * 1 + 0 * 0 */ + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + if (op == WINED3DTOP_SELECTARG1) { + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + } else { + glTexEnvi(GL_TEXTURE_ENV, src0_target, src2); + checkGLcall("GL_TEXTURE_ENV, src0_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr2"); + } + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src2_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr"); + break; + + case WINED3DTOP_MODULATE: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */ + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATE2X: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */ + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 2); + checkGLcall("GL_TEXTURE_ENV, scal_target, 2"); + break; + case WINED3DTOP_MODULATE4X: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */ + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 4); + checkGLcall("GL_TEXTURE_ENV, scal_target, 4"); + break; + + case WINED3DTOP_ADD: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + + case WINED3DTOP_ADDSIGNED: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + + case WINED3DTOP_ADDSIGNED2X: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 2); + checkGLcall("GL_TEXTURE_ENV, scal_target, 2"); + break; + + case WINED3DTOP_ADDSMOOTH: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, src1); + checkGLcall("GL_TEXTURE_ENV, src3_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break; + case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + + case WINED3DTOP_BLENDDIFFUSEALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, useext(GL_PRIMARY_COLOR)); + checkGLcall("GL_TEXTURE_ENV, src1_target, useext(GL_PRIMARY_COLOR)"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, useext(GL_PRIMARY_COLOR)); + checkGLcall("GL_TEXTURE_ENV, src3_target, useext(GL_PRIMARY_COLOR)"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_BLENDTEXTUREALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_TEXTURE); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_TEXTURE"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_TEXTURE); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_TEXTURE"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_BLENDFACTORALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, useext(GL_CONSTANT)); + checkGLcall("GL_TEXTURE_ENV, src1_target, useext(GL_CONSTANT)"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, useext(GL_CONSTANT)); + checkGLcall("GL_TEXTURE_ENV, src3_target, useext(GL_CONSTANT)"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_BLENDTEXTUREALPHAPM: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_TEXTURE); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_TEXTURE"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr3_target, GL_ONE_MINUS_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATEALPHA_ADDCOLOR: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); /* Add = a0*a1 + a2*a3 */ + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); /* a0 = src1/opr1 */ + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); /* a1 = 1 (see docs) */ + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); /* a2 = arg2 */ + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); /* a3 = src1 alpha */ + glTexEnvi(GL_TEXTURE_ENV, src3_target, src1); + checkGLcall("GL_TEXTURE_ENV, src3_target, src1"); + switch (opr) { + case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATECOLOR_ADDALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src1); + checkGLcall("GL_TEXTURE_ENV, src2_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, src1); + checkGLcall("GL_TEXTURE_ENV, src3_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break; + case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src1); + checkGLcall("GL_TEXTURE_ENV, src2_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src3_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr3_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MULTIPLYADD: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src3); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr3); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, GL_ZERO); + checkGLcall("GL_TEXTURE_ENV, src1_target, GL_ZERO"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, invopr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, invopr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src1); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src3_target, src2); + checkGLcall("GL_TEXTURE_ENV, src3_target, src3"); + glTexEnvi(GL_TEXTURE_ENV, opr3_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr3_target, opr3"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + + case WINED3DTOP_BUMPENVMAP: + { + } + + case WINED3DTOP_BUMPENVMAPLUMINANCE: + FIXME("Implement bump environment mapping in GL_NV_texture_env_combine4 path\n"); + + default: + Handled = FALSE; + } + if (Handled) { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV); + checkGLcall("GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV"); + + return; + } + } /* GL_NV_texture_env_combine4 */ + + Handled = TRUE; /* Again, assume handled */ + switch (op) { + case WINED3DTOP_DISABLE: /* Only for alpha */ + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_REPLACE); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, GL_PREVIOUS_EXT); + checkGLcall("GL_TEXTURE_ENV, src0_target, GL_PREVIOUS_EXT"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, GL_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr0_target, GL_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_SELECTARG1: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_REPLACE); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_SELECTARG2: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_REPLACE); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_REPLACE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src2); + checkGLcall("GL_TEXTURE_ENV, src0_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATE: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_MODULATE2X: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 2); + checkGLcall("GL_TEXTURE_ENV, scal_target, 2"); + break; + case WINED3DTOP_MODULATE4X: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 4); + checkGLcall("GL_TEXTURE_ENV, scal_target, 4"); + break; + case WINED3DTOP_ADD: + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_ADD); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_ADD"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_ADDSIGNED: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext((GL_ADD_SIGNED)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_ADDSIGNED2X: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_ADD_SIGNED)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 2); + checkGLcall("GL_TEXTURE_ENV, scal_target, 2"); + break; + case WINED3DTOP_SUBTRACT: + if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_SUBTRACT); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_SUBTRACT)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else { + FIXME("This version of opengl does not support GL_SUBTRACT\n"); + } + break; + + case WINED3DTOP_BLENDDIFFUSEALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, useext(GL_PRIMARY_COLOR)); + checkGLcall("GL_TEXTURE_ENV, src2_target, GL_PRIMARY_COLOR"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_BLENDTEXTUREALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, GL_TEXTURE); + checkGLcall("GL_TEXTURE_ENV, src2_target, GL_TEXTURE"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_BLENDFACTORALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, useext(GL_CONSTANT)); + checkGLcall("GL_TEXTURE_ENV, src2_target, GL_CONSTANT"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_BLENDCURRENTALPHA: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, useext(GL_PREVIOUS)); + checkGLcall("GL_TEXTURE_ENV, src2_target, GL_PREVIOUS"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr2_target, GL_SRC_ALPHA"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_DOTPRODUCT3: + if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_ARB); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_ARB"); + } else if (GL_SUPPORT(EXT_TEXTURE_ENV_DOT3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_EXT); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_DOT3_RGBA_EXT"); + } else { + FIXME("This version of opengl does not support GL_DOT3\n"); + } + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_LERP: + glTexEnvi(GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)); + checkGLcall("GL_TEXTURE_ENV, comb_target, useext(GL_INTERPOLATE)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src2); + checkGLcall("GL_TEXTURE_ENV, src1_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src3); + checkGLcall("GL_TEXTURE_ENV, src2_target, src3"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr3); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr3"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + break; + case WINED3DTOP_ADDSMOOTH: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break; + case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_BLENDTEXTUREALPHAPM: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, GL_TEXTURE); + checkGLcall("GL_TEXTURE_ENV, src0_target, GL_TEXTURE"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, GL_ONE_MINUS_SRC_ALPHA); + checkGLcall("GL_TEXTURE_ENV, opr0_target, GL_ONE_MINUS_SRC_APHA"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_MODULATEALPHA_ADDCOLOR: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_MODULATECOLOR_ADDALPHA: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_ONE_MINUS_SRC_COLOR; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_SRC_COLOR; break; + case GL_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + switch (opr1) { + case GL_SRC_COLOR: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_COLOR: opr = GL_ONE_MINUS_SRC_ALPHA; break; + case GL_SRC_ALPHA: opr = GL_SRC_ALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: opr = GL_ONE_MINUS_SRC_ALPHA; break; + } + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_MULTIPLYADD: + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3)) { + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI); + checkGLcall("GL_TEXTURE_ENV, comb_target, GL_MODULATE_ADD_ATI"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src3); + checkGLcall("GL_TEXTURE_ENV, src0_target, src3"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr3); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr3"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src1_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src2_target, src2"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + glTexEnvi(GL_TEXTURE_ENV, scal_target, 1); + checkGLcall("GL_TEXTURE_ENV, scal_target, 1"); + } else + Handled = FALSE; + break; + case WINED3DTOP_BUMPENVMAPLUMINANCE: + if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + /* Some apps use BUMPENVMAPLUMINANCE instead of D3DTOP_BUMPENVMAP, although + * they check for the non-luminance cap flag. Well, give them what they asked + * for :-) + */ + WARN("Application uses WINED3DTOP_BUMPENVMAPLUMINANCE\n"); + } else { + Handled = FALSE; + break; + } + /* Fall through */ + case WINED3DTOP_BUMPENVMAP: + if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + TRACE("Using ati bumpmap on stage %d, target %d\n", Stage, Stage + 1); + glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_BUMP_ENVMAP_ATI); + checkGLcall("glTexEnvi(GL_TEXTURE_ENV, comb_target, GL_BUMP_ENVMAP_ATI)"); + glTexEnvi(GL_TEXTURE_ENV, GL_BUMP_TARGET_ATI, GL_TEXTURE0_ARB + Stage + 1); + checkGLcall("glTexEnvi(GL_TEXTURE_ENV, GL_BUMP_TARGET_ATI, GL_TEXTURE0_ARB + Stage + 1)"); + glTexEnvi(GL_TEXTURE_ENV, src0_target, src3); + checkGLcall("GL_TEXTURE_ENV, src0_target, src3"); + glTexEnvi(GL_TEXTURE_ENV, opr0_target, opr3); + checkGLcall("GL_TEXTURE_ENV, opr0_target, opr3"); + glTexEnvi(GL_TEXTURE_ENV, src1_target, src1); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr1_target, opr1); + checkGLcall("GL_TEXTURE_ENV, opr1_target, opr1"); + glTexEnvi(GL_TEXTURE_ENV, src2_target, src2); + checkGLcall("GL_TEXTURE_ENV, src0_target, src1"); + glTexEnvi(GL_TEXTURE_ENV, opr2_target, opr2); + checkGLcall("GL_TEXTURE_ENV, opr2_target, opr2"); + + Handled = TRUE; + break; + } else if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + /* Technically texture shader support without register combiners is possible, but not expected to occur + * on real world cards, so for now a fixme should be enough + */ + FIXME("Implement bump mapping with GL_NV_texture_shader in non register combiner path\n"); + } + default: + Handled = FALSE; + } + + if (Handled) { + BOOL combineOK = TRUE; + if (GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { + DWORD op2; + + if (isAlpha) { + op2 = This->stateBlock->textureState[Stage][WINED3DTSS_COLOROP]; + } else { + op2 = This->stateBlock->textureState[Stage][WINED3DTSS_ALPHAOP]; + } + + /* Note: If COMBINE4 in effect can't go back to combine! */ + switch (op2) { + case WINED3DTOP_ADDSMOOTH: + case WINED3DTOP_BLENDTEXTUREALPHAPM: + case WINED3DTOP_MODULATEALPHA_ADDCOLOR: + case WINED3DTOP_MODULATECOLOR_ADDALPHA: + case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR: + case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA: + case WINED3DTOP_MULTIPLYADD: + /* Ignore those implemented in both cases */ + switch (op) { + case WINED3DTOP_SELECTARG1: + case WINED3DTOP_SELECTARG2: + combineOK = FALSE; + Handled = FALSE; + break; + default: + FIXME("Can't use COMBINE4 and COMBINE together, thisop=%s, otherop=%s, isAlpha(%d)\n", debug_d3dtop(op), debug_d3dtop(op2), isAlpha); + return; + } + } + } + + if (combineOK) { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, useext(GL_COMBINE)); + checkGLcall("GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, useext(GL_COMBINE)"); + + return; + } + } + + /* After all the extensions, if still unhandled, report fixme */ + FIXME("Unhandled texture operation %s\n", debug_d3dtop(op)); + #undef GLINFO_LOCATION +} +#endif + +/* Setup this textures matrix according to the texture flags*/ +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords) +{ + float mat[16]; + + glMatrixMode(GL_TEXTURE); + checkGLcall("glMatrixMode(GL_TEXTURE)"); + + if (flags == WINED3DTTFF_DISABLE) { + glLoadIdentity(); + checkGLcall("glLoadIdentity()"); + return; + } + + if (flags == (WINED3DTTFF_COUNT1|WINED3DTTFF_PROJECTED)) { + ERR("Invalid texture transform flags: WINED3DTTFF_COUNT1|WINED3DTTFF_PROJECTED\n"); + return; + } + + memcpy(mat, smat, 16 * sizeof(float)); + + switch (flags & ~WINED3DTTFF_PROJECTED) { + case WINED3DTTFF_COUNT1: mat[1] = mat[5] = mat[13] = 0; + case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; + default: mat[3] = mat[7] = mat[11] = 0, mat[15] = 1; + } + + if (flags & WINED3DTTFF_PROJECTED) { + switch (flags & ~WINED3DTTFF_PROJECTED) { + case WINED3DTTFF_COUNT2: + mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13]; + mat[1] = mat[5] = mat[9] = mat[13] = 0; + break; + case WINED3DTTFF_COUNT3: + mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14]; + mat[2] = mat[6] = mat[10] = mat[14] = 0; + break; + } + } else if(!calculatedCoords) { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */ + mat[12] = mat[8]; + mat[13] = mat[9]; + } + + glLoadMatrixf(mat); + checkGLcall("glLoadMatrixf(mat)"); +} + +#define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info + +/* This small helper function is used to convert a bitmask into the number of masked bits */ +unsigned int count_bits(unsigned int mask) +{ + unsigned int count; + for (count = 0; mask; ++count) + { + mask &= mask - 1; + } + return count; +} + +/* Helper function for retrieving color info for ChoosePixelFormat and wglChoosePixelFormatARB. + * The later function requires individual color components. */ +BOOL getColorBits(WINED3DFORMAT fmt, short *redSize, short *greenSize, short *blueSize, short *alphaSize, short *totalSize) +{ + const StaticPixelFormatDesc *desc; + + TRACE("fmt: %s\n", debug_d3dformat(fmt)); + switch(fmt) + { + case WINED3DFMT_X8R8G8B8: + case WINED3DFMT_R8G8B8: + case WINED3DFMT_A8R8G8B8: + case WINED3DFMT_A2R10G10B10: + case WINED3DFMT_X1R5G5B5: + case WINED3DFMT_A1R5G5B5: + case WINED3DFMT_R5G6B5: + case WINED3DFMT_R3G3B2: + case WINED3DFMT_A8P8: + case WINED3DFMT_P8: + break; + default: + ERR("Unsupported format: %s\n", debug_d3dformat(fmt)); + return FALSE; + } + + desc = getFormatDescEntry(fmt, NULL, NULL); + if(!desc) + { + ERR("Unable to look up format: 0x%x\n", fmt); + return FALSE; + } + *redSize = count_bits(desc->redMask); + *greenSize = count_bits(desc->greenMask); + *blueSize = count_bits(desc->blueMask); + *alphaSize = count_bits(desc->alphaMask); + *totalSize = *redSize + *greenSize + *blueSize + *alphaSize; + + TRACE("Returning red: %d, green: %d, blue: %d, alpha: %d, total: %d for fmt=%s\n", *redSize, *greenSize, *blueSize, *alphaSize, *totalSize, debug_d3dformat(fmt)); + return TRUE; +} + +/* Helper function for retrieving depth/stencil info for ChoosePixelFormat and wglChoosePixelFormatARB */ +BOOL getDepthStencilBits(WINED3DFORMAT fmt, short *depthSize, short *stencilSize) +{ + const StaticPixelFormatDesc *desc; + + TRACE("fmt: %s\n", debug_d3dformat(fmt)); + switch(fmt) + { + case WINED3DFMT_D16_LOCKABLE: + case WINED3DFMT_D16: + case WINED3DFMT_D15S1: + case WINED3DFMT_D24X8: + case WINED3DFMT_D24X4S4: + case WINED3DFMT_D24S8: + case WINED3DFMT_D24FS8: + case WINED3DFMT_D32: + break; + default: + FIXME("Unsupported stencil format: %s\n", debug_d3dformat(fmt)); + return FALSE; + } + + desc = getFormatDescEntry(fmt, NULL, NULL); + if(!desc) + { + ERR("Unable to look up format: 0x%x\n", fmt); + return FALSE; + } + *depthSize = desc->depthSize; + *stencilSize = desc->stencilSize; + + TRACE("Returning depthSize: %d and stencilSize: %d for fmt=%s\n", *depthSize, *stencilSize, debug_d3dformat(fmt)); + return TRUE; +} + +#undef GLINFO_LOCATION + +/* DirectDraw stuff */ +WINED3DFORMAT pixelformat_for_depth(DWORD depth) { + switch(depth) { + case 8: return WINED3DFMT_P8; + case 15: return WINED3DFMT_X1R5G5B5; + case 16: return WINED3DFMT_R5G6B5; + case 24: return WINED3DFMT_R8G8B8; + case 32: return WINED3DFMT_X8R8G8B8; + default: return WINED3DFMT_UNKNOWN; + } +} + +void multiply_matrix(WINED3DMATRIX *dest, const WINED3DMATRIX *src1, const WINED3DMATRIX *src2) { + WINED3DMATRIX temp; + + /* Now do the multiplication 'by hand'. + I know that all this could be optimised, but this will be done later :-) */ + temp.u.s._11 = (src1->u.s._11 * src2->u.s._11) + (src1->u.s._21 * src2->u.s._12) + (src1->u.s._31 * src2->u.s._13) + (src1->u.s._41 * src2->u.s._14); + temp.u.s._21 = (src1->u.s._11 * src2->u.s._21) + (src1->u.s._21 * src2->u.s._22) + (src1->u.s._31 * src2->u.s._23) + (src1->u.s._41 * src2->u.s._24); + temp.u.s._31 = (src1->u.s._11 * src2->u.s._31) + (src1->u.s._21 * src2->u.s._32) + (src1->u.s._31 * src2->u.s._33) + (src1->u.s._41 * src2->u.s._34); + temp.u.s._41 = (src1->u.s._11 * src2->u.s._41) + (src1->u.s._21 * src2->u.s._42) + (src1->u.s._31 * src2->u.s._43) + (src1->u.s._41 * src2->u.s._44); + + temp.u.s._12 = (src1->u.s._12 * src2->u.s._11) + (src1->u.s._22 * src2->u.s._12) + (src1->u.s._32 * src2->u.s._13) + (src1->u.s._42 * src2->u.s._14); + temp.u.s._22 = (src1->u.s._12 * src2->u.s._21) + (src1->u.s._22 * src2->u.s._22) + (src1->u.s._32 * src2->u.s._23) + (src1->u.s._42 * src2->u.s._24); + temp.u.s._32 = (src1->u.s._12 * src2->u.s._31) + (src1->u.s._22 * src2->u.s._32) + (src1->u.s._32 * src2->u.s._33) + (src1->u.s._42 * src2->u.s._34); + temp.u.s._42 = (src1->u.s._12 * src2->u.s._41) + (src1->u.s._22 * src2->u.s._42) + (src1->u.s._32 * src2->u.s._43) + (src1->u.s._42 * src2->u.s._44); + + temp.u.s._13 = (src1->u.s._13 * src2->u.s._11) + (src1->u.s._23 * src2->u.s._12) + (src1->u.s._33 * src2->u.s._13) + (src1->u.s._43 * src2->u.s._14); + temp.u.s._23 = (src1->u.s._13 * src2->u.s._21) + (src1->u.s._23 * src2->u.s._22) + (src1->u.s._33 * src2->u.s._23) + (src1->u.s._43 * src2->u.s._24); + temp.u.s._33 = (src1->u.s._13 * src2->u.s._31) + (src1->u.s._23 * src2->u.s._32) + (src1->u.s._33 * src2->u.s._33) + (src1->u.s._43 * src2->u.s._34); + temp.u.s._43 = (src1->u.s._13 * src2->u.s._41) + (src1->u.s._23 * src2->u.s._42) + (src1->u.s._33 * src2->u.s._43) + (src1->u.s._43 * src2->u.s._44); + + temp.u.s._14 = (src1->u.s._14 * src2->u.s._11) + (src1->u.s._24 * src2->u.s._12) + (src1->u.s._34 * src2->u.s._13) + (src1->u.s._44 * src2->u.s._14); + temp.u.s._24 = (src1->u.s._14 * src2->u.s._21) + (src1->u.s._24 * src2->u.s._22) + (src1->u.s._34 * src2->u.s._23) + (src1->u.s._44 * src2->u.s._24); + temp.u.s._34 = (src1->u.s._14 * src2->u.s._31) + (src1->u.s._24 * src2->u.s._32) + (src1->u.s._34 * src2->u.s._33) + (src1->u.s._44 * src2->u.s._34); + temp.u.s._44 = (src1->u.s._14 * src2->u.s._41) + (src1->u.s._24 * src2->u.s._42) + (src1->u.s._34 * src2->u.s._43) + (src1->u.s._44 * src2->u.s._44); + + /* And copy the new matrix in the good storage.. */ + memcpy(dest, &temp, 16 * sizeof(float)); +} + +DWORD get_flexible_vertex_size(DWORD d3dvtVertexType) { + DWORD size = 0; + int i; + int numTextures = (d3dvtVertexType & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT; + + if (d3dvtVertexType & WINED3DFVF_NORMAL) size += 3 * sizeof(float); + if (d3dvtVertexType & WINED3DFVF_DIFFUSE) size += sizeof(DWORD); + if (d3dvtVertexType & WINED3DFVF_SPECULAR) size += sizeof(DWORD); + if (d3dvtVertexType & WINED3DFVF_PSIZE) size += sizeof(DWORD); + switch (d3dvtVertexType & WINED3DFVF_POSITION_MASK) { + case WINED3DFVF_XYZ: size += 3 * sizeof(float); break; + case WINED3DFVF_XYZRHW: size += 4 * sizeof(float); break; + case WINED3DFVF_XYZB1: size += 4 * sizeof(float); break; + case WINED3DFVF_XYZB2: size += 5 * sizeof(float); break; + case WINED3DFVF_XYZB3: size += 6 * sizeof(float); break; + case WINED3DFVF_XYZB4: size += 7 * sizeof(float); break; + case WINED3DFVF_XYZB5: size += 8 * sizeof(float); break; + default: ERR("Unexpected position mask\n"); + } + for (i = 0; i < numTextures; i++) { + size += GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, i) * sizeof(float); + } + + return size; +} + +/*********************************************************************** + * CalculateTexRect + * + * Calculates the dimensions of the opengl texture used for blits. + * Handled oversized opengl textures and updates the source rectangle + * accordingly + * + * Params: + * This: Surface to operate on + * Rect: Requested rectangle + * + * Returns: + * TRUE if the texture part can be loaded, + * FALSE otherwise + * + *********************************************************************/ +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]) { + int x1 = Rect->left, x2 = Rect->right; + int y1 = Rect->top, y2 = Rect->bottom; + GLint maxSize = GL_LIMITS(texture_size); + + TRACE("(%p)->(%d,%d)-(%d,%d)\n", This, + Rect->left, Rect->top, Rect->right, Rect->bottom); + + /* The sizes might be reversed */ + if(Rect->left > Rect->right) { + x1 = Rect->right; + x2 = Rect->left; + } + if(Rect->top > Rect->bottom) { + y1 = Rect->bottom; + y2 = Rect->top; + } + + /* No oversized texture? This is easy */ + if(!(This->Flags & SFLAG_OVERSIZE)) { + /* Which rect from the texture do I need? */ + glTexCoord[0] = (float) Rect->left / (float) This->pow2Width; + glTexCoord[2] = (float) Rect->top / (float) This->pow2Height; + glTexCoord[1] = (float) Rect->right / (float) This->pow2Width; + glTexCoord[3] = (float) Rect->bottom / (float) This->pow2Height; + + return TRUE; + } else { + /* Check if we can succeed at all */ + if( (x2 - x1) > maxSize || + (y2 - y1) > maxSize ) { + TRACE("Requested rectangle is too large for gl\n"); + return FALSE; + } + + /* A part of the texture has to be picked. First, check if + * some texture part is loaded already, if yes try to re-use it. + * If the texture is dirty, or the part can't be used, + * re-position the part to load + */ + if(This->Flags & SFLAG_INTEXTURE) { + if(This->glRect.left <= x1 && This->glRect.right >= x2 && + This->glRect.top <= y1 && This->glRect.bottom >= x2 ) { + /* Ok, the rectangle is ok, re-use it */ + TRACE("Using existing gl Texture\n"); + } else { + /* Rectangle is not ok, dirtify the texture to reload it */ + TRACE("Dirtifying texture to force reload\n"); + This->Flags &= ~SFLAG_INTEXTURE; + } + } + + /* Now if we are dirty(no else if!) */ + if(!(This->Flags & SFLAG_INTEXTURE)) { + /* Set the new rectangle. Use the following strategy: + * 1) Use as big textures as possible. + * 2) Place the texture part in the way that the requested + * part is in the middle of the texture(well, almost) + * 3) If the texture is moved over the edges of the + * surface, replace it nicely + * 4) If the coord is not limiting the texture size, + * use the whole size + */ + if((This->pow2Width) > maxSize) { + This->glRect.left = x1 - maxSize / 2; + if(This->glRect.left < 0) { + This->glRect.left = 0; + } + This->glRect.right = This->glRect.left + maxSize; + if(This->glRect.right > This->currentDesc.Width) { + This->glRect.right = This->currentDesc.Width; + This->glRect.left = This->glRect.right - maxSize; + } + } else { + This->glRect.left = 0; + This->glRect.right = This->pow2Width; + } + + if(This->pow2Height > maxSize) { + This->glRect.top = x1 - GL_LIMITS(texture_size) / 2; + if(This->glRect.top < 0) This->glRect.top = 0; + This->glRect.bottom = This->glRect.left + maxSize; + if(This->glRect.bottom > This->currentDesc.Height) { + This->glRect.bottom = This->currentDesc.Height; + This->glRect.top = This->glRect.bottom - maxSize; + } + } else { + This->glRect.top = 0; + This->glRect.bottom = This->pow2Height; + } + TRACE("(%p): Using rect (%d,%d)-(%d,%d)\n", This, + This->glRect.left, This->glRect.top, This->glRect.right, This->glRect.bottom); + } + + /* Re-calculate the rect to draw */ + Rect->left -= This->glRect.left; + Rect->right -= This->glRect.left; + Rect->top -= This->glRect.top; + Rect->bottom -= This->glRect.top; + + /* Get the gl coordinates. The gl rectangle is a power of 2, eigher the max size, + * or the pow2Width / pow2Height of the surface + */ + glTexCoord[0] = (float) Rect->left / (float) (This->glRect.right - This->glRect.left); + glTexCoord[2] = (float) Rect->top / (float) (This->glRect.bottom - This->glRect.top); + glTexCoord[1] = (float) Rect->right / (float) (This->glRect.right - This->glRect.left); + glTexCoord[3] = (float) Rect->bottom / (float) (This->glRect.bottom - This->glRect.top); + } + return TRUE; +} +#undef GLINFO_LOCATION + +/* Hash table functions */ + +hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function_t *compare_function) +{ + hash_table_t *table; + unsigned int initial_size = 8; + + table = HeapAlloc(GetProcessHeap(), 0, sizeof(hash_table_t) + (initial_size * sizeof(struct list))); + if (!table) + { + ERR("Failed to allocate table, returning NULL.\n"); + return NULL; + } + + table->hash_function = hash_function; + table->compare_function = compare_function; + + table->grow_size = initial_size - (initial_size >> 2); + table->shrink_size = 0; + + table->buckets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, initial_size * sizeof(struct list)); + if (!table->buckets) + { + ERR("Failed to allocate table buckets, returning NULL.\n"); + HeapFree(GetProcessHeap(), 0, table); + return NULL; + } + table->bucket_count = initial_size; + + table->entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, table->grow_size * sizeof(hash_table_entry_t)); + if (!table->entries) + { + ERR("Failed to allocate table entries, returning NULL.\n"); + HeapFree(GetProcessHeap(), 0, table->buckets); + HeapFree(GetProcessHeap(), 0, table); + return NULL; + } + table->entry_count = 0; + + list_init(&table->free_entries); + table->count = 0; + + return table; +} + +void hash_table_destroy(hash_table_t *table) +{ + unsigned int i = 0; + + for (i = 0; i < table->entry_count; ++i) + { + HeapFree(GetProcessHeap(), 0, table->entries[i].key); + } + + HeapFree(GetProcessHeap(), 0, table->entries); + HeapFree(GetProcessHeap(), 0, table->buckets); + HeapFree(GetProcessHeap(), 0, table); +} + +static inline hash_table_entry_t *hash_table_get_by_idx(hash_table_t *table, void *key, unsigned int idx) +{ + hash_table_entry_t *entry; + + if (table->buckets[idx].next) + LIST_FOR_EACH_ENTRY(entry, &(table->buckets[idx]), hash_table_entry_t, entry) + if (table->compare_function(entry->key, key)) return entry; + + return NULL; +} + +static BOOL hash_table_resize(hash_table_t *table, unsigned int new_bucket_count) +{ + unsigned int new_entry_count = 0; + hash_table_entry_t *new_entries; + struct list *new_buckets; + unsigned int grow_size = new_bucket_count - (new_bucket_count >> 2); + unsigned int i; + + new_buckets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, new_bucket_count * sizeof(struct list)); + if (!new_buckets) + { + ERR("Failed to allocate new buckets, returning FALSE.\n"); + return FALSE; + } + + new_entries = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, grow_size * sizeof(hash_table_entry_t)); + if (!new_entries) + { + ERR("Failed to allocate new entries, returning FALSE.\n"); + HeapFree(GetProcessHeap(), 0, new_buckets); + return FALSE; + } + + for (i = 0; i < table->bucket_count; ++i) + { + if (table->buckets[i].next) + { + hash_table_entry_t *entry, *entry2; + + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &table->buckets[i], hash_table_entry_t, entry) + { + int j; + hash_table_entry_t *new_entry = new_entries + (new_entry_count++); + *new_entry = *entry; + + j = new_entry->hash & (new_bucket_count - 1); + + if (!new_buckets[j].next) list_init(&new_buckets[j]); + list_add_head(&new_buckets[j], &new_entry->entry); + } + } + } + + HeapFree(GetProcessHeap(), 0, table->buckets); + table->buckets = new_buckets; + + HeapFree(GetProcessHeap(), 0, table->entries); + table->entries = new_entries; + + table->entry_count = new_entry_count; + list_init(&table->free_entries); + + table->bucket_count = new_bucket_count; + table->grow_size = grow_size; + table->shrink_size = new_bucket_count > 8 ? new_bucket_count >> 2 : 0; + + return TRUE; +} + +void hash_table_put(hash_table_t *table, void *key, void *value) +{ + unsigned int idx; + unsigned int hash; + hash_table_entry_t *entry; + + hash = table->hash_function(key); + idx = hash & (table->bucket_count - 1); + entry = hash_table_get_by_idx(table, key, idx); + + if (entry) + { + HeapFree(GetProcessHeap(), 0, key); + entry->value = value; + + if (!value) + { + HeapFree(GetProcessHeap(), 0, entry->key); + entry->key = NULL; + + /* Remove the entry */ + list_remove(&entry->entry); + list_add_head(&table->free_entries, &entry->entry); + + --table->count; + + /* Shrink if necessary */ + if (table->count < table->shrink_size) { + if (!hash_table_resize(table, table->bucket_count >> 1)) + { + ERR("Failed to shrink the table...\n"); + } + } + } + + return; + } + + if (!value) return; + + /* Grow if necessary */ + if (table->count >= table->grow_size) + { + if (!hash_table_resize(table, table->bucket_count << 1)) + { + ERR("Failed to grow the table, returning.\n"); + return; + } + + idx = hash & (table->bucket_count - 1); + } + + /* Find an entry to insert */ + if (!list_empty(&table->free_entries)) + { + struct list *elem = list_head(&table->free_entries); + + list_remove(elem); + entry = LIST_ENTRY(elem, hash_table_entry_t, entry); + } else { + entry = table->entries + (table->entry_count++); + } + + /* Insert the entry */ + entry->key = key; + entry->value = value; + entry->hash = hash; + if (!table->buckets[idx].next) list_init(&table->buckets[idx]); + list_add_head(&table->buckets[idx], &entry->entry); + + ++table->count; +} + +void hash_table_remove(hash_table_t *table, void *key) +{ + hash_table_put(table, key, NULL); +} + +void *hash_table_get(hash_table_t *table, void *key) +{ + unsigned int idx; + hash_table_entry_t *entry; + + idx = table->hash_function(key) & (table->bucket_count - 1); + entry = hash_table_get_by_idx(table, key, idx); + + return entry ? entry->value : NULL; +} diff --git a/reactos/dll/directx/wine/wined3d/version.rc b/reactos/dll/directx/wine/wined3d/version.rc new file mode 100644 index 00000000000..c40f3e26111 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/version.rc @@ -0,0 +1,27 @@ +/* + * Copyright 2001 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WINE_OLESELFREGISTER +#define WINE_FILEDESCRIPTION_STR "Wine WineD3D OpenGL (Licen LGPL)" +#define WINE_FILENAME_STR "wined3d.dll" +#define WINE_FILEVERSION 5,3,1,904 +#define WINE_FILEVERSION_STR "5.3.1.904" +#define WINE_PRODUCTVERSION 5,3,1,904 +#define WINE_PRODUCTVERSION_STR "5.3.1.904" + +#include "wine/wine_common_ver.rc" diff --git a/reactos/dll/directx/wine/wined3d/vertexbuffer.c b/reactos/dll/directx/wine/wined3d/vertexbuffer.c new file mode 100644 index 00000000000..bd599c4f5f2 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/vertexbuffer.c @@ -0,0 +1,504 @@ +/* + * IWineD3DVertexBuffer Implementation + * + * Copyright 2002-2005 Jason Edmeades + * Raphael Junqueira + * Copyright 2004 Christian Costa + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +#define VB_MAXDECLCHANGES 100 /* After that number we stop converting */ +#define VB_RESETDECLCHANGE 1000 /* Reset the changecount after that number of draws */ + +/* ******************************************* + IWineD3DVertexBuffer IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DVertexBufferImpl_QueryInterface(IWineD3DVertexBuffer *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DVertexBuffer)){ + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DVertexBufferImpl_AddRef(IWineD3DVertexBuffer *iface) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface; + ULONG ref = InterlockedIncrement(&This->resource.ref); + TRACE("(%p) : AddRef increasing from %d\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IWineD3DVertexBufferImpl_Release(IWineD3DVertexBuffer *iface) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface; + ULONG ref = InterlockedDecrement(&This->resource.ref); + TRACE("(%p) : Releasing from %d\n", This, ref + 1); + if (ref == 0) { + + if(This->vbo) { + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo)); + checkGLcall("glDeleteBuffersARB"); + LEAVE_GL(); + } + + IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* **************************************************** + IWineD3DVertexBuffer IWineD3DResource parts follow + **************************************************** */ +static HRESULT WINAPI IWineD3DVertexBufferImpl_GetDevice(IWineD3DVertexBuffer *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +static HRESULT WINAPI IWineD3DVertexBufferImpl_SetPrivateData(IWineD3DVertexBuffer *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IWineD3DVertexBufferImpl_GetPrivateData(IWineD3DVertexBuffer *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IWineD3DVertexBufferImpl_FreePrivateData(IWineD3DVertexBuffer *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +static DWORD WINAPI IWineD3DVertexBufferImpl_SetPriority(IWineD3DVertexBuffer *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +static DWORD WINAPI IWineD3DVertexBufferImpl_GetPriority(IWineD3DVertexBuffer *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +static void fixup_vertices( + BYTE *src, BYTE *dst, + int stride, + int num, + int pos, BOOL haspos, + int diffuse, BOOL hasdiffuse, + int specular, BOOL hasspecular +) { + int i; + float x, y, z, w; + + for(i = num - 1; i >= 0; i--) { + if(haspos) { + float *p = (float *) ((src + pos) + i * stride); + + /* rhw conversion like in drawStridedSlow */ + if(p[3] == 1.0 || ((p[3] < eps) && (p[3] > -eps))) { + x = p[0]; + y = p[1]; + z = p[2]; + w = 1.0; + } else { + w = 1.0 / p[3]; + x = p[0] * w; + y = p[1] * w; + z = p[2] * w; + } + p = (float *) (dst + i * stride + pos); + p[0] = x; + p[1] = y; + p[2] = z; + p[3] = w; + } + if(hasdiffuse) { + DWORD srcColor, *dstColor = (DWORD *) (dst + i * stride + diffuse); + srcColor = * (DWORD *) ( (src + diffuse) + i * stride); + + /* Color conversion like in drawStridedSlow. watch out for little endianity + * If we want that stuff to work on big endian machines too we have to consider more things + * + * 0xff000000: Alpha mask + * 0x00ff0000: Blue mask + * 0x0000ff00: Green mask + * 0x000000ff: Red mask + */ + + *dstColor = 0; + *dstColor |= (srcColor & 0xff00ff00) ; /* Alpha Green */ + *dstColor |= (srcColor & 0x00ff0000) >> 16; /* Red */ + *dstColor |= (srcColor & 0x000000ff) << 16; /* Blue */ + } + if(hasspecular) { + DWORD srcColor, *dstColor = (DWORD *) (dst + i * stride + specular); + srcColor = * (DWORD *) ( (src + specular) + i * stride); + + /* Similar to diffuse + * TODO: Write the alpha value out for fog coords + */ + *dstColor = 0; + *dstColor |= (srcColor & 0xff00ff00) ; /* Alpha Green */ + *dstColor |= (srcColor & 0x00ff0000) >> 16; /* Red */ + *dstColor |= (srcColor & 0x000000ff) << 16; /* Blue */ + } + } +} + +inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *This) +{ + WineDirect3DVertexStridedData strided; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + + /* In d3d7 the vertex buffer declaration NEVER changes because it is stored in the d3d7 vertex buffer. + * Once we have our declaration there is no need to look it up again. + */ + if(((IWineD3DImpl *)device->wineD3D)->dxVersion == 7 && This->Flags & VBFLAG_HASDESC) { + return FALSE; + } + + /* There are certain vertex data types that need to be fixed up. The Vertex Buffers FVF doesn't + * help finding them, only the vertex declaration or the device FVF can determine that at drawPrim + * time. Rules are as follows: + * + * -> No modification when Vertex Shaders are used + * -> Fix up position1 and position 2 if they are XYZRHW + * -> Fix up diffuse color + * -> Fix up specular color + * + * The Declaration is only known at drawing time, and it can change from draw to draw. If any converted values + * are changed, the whole buffer has to be reconverted and reloaded. (Converting is SLOW, so if this happens too + * often PreLoad stops converting entirely and falls back to drawStridedSlow). + * + * Reconvert if: + * -> New semantics that have to be converted appear + * -> The position of semantics that have to be converted changes + * -> The stride of the vertex changed AND there is stuff that needs conversion + * -> (If a vertex shader is bound and in use assume that nothing that needs conversion is there) + * + * Return values: + * TRUE: Reload is needed + * FALSE: otherwise + */ + + if (use_vs(device)) { + /* Assume no conversion */ + memset(&strided, 0, sizeof(strided)); + } else { + /* we need a copy because we modify some params */ + memcpy(&strided, &device->strided_streams, sizeof(strided)); + + /* Filter out data that does not come from this VBO */ + if(strided.u.s.position.VBO != This->vbo) memset(&strided.u.s.position, 0, sizeof(strided.u.s.position)); + if(strided.u.s.diffuse.VBO != This->vbo) memset(&strided.u.s.diffuse, 0, sizeof(strided.u.s.diffuse)); + if(strided.u.s.specular.VBO != This->vbo) memset(&strided.u.s.specular, 0, sizeof(strided.u.s.specular)); + if(strided.u.s.position2.VBO != This->vbo) memset(&strided.u.s.position2, 0, sizeof(strided.u.s.position2)); + } + + /* We have a declaration now in the buffer */ + This->Flags |= VBFLAG_HASDESC; + + /* Find out if reload is needed + * Position of the semantic in the vertex and the stride must be equal to the stored type. Don't mind if only unconverted stuff changed. + * + * If some stuff does not exist in the buffer, then lpData, dwStride and dwType are memsetted to 0. So if the semantic didn't exist before + * and does not exist now all 3 values will be equal(=0). + * + * Checking the lpData field alone is not enough, because data may appear at offset 0 in the buffer. This is the same location as nonexistent + * data uses, so we have to check the type and stride too. Colors can be at offset 0 too, because it is perfectly fine to render from 2 or more + * buffers at the same time and get the position from one and the color from the other buffer. + */ + if( /* Position transformed vs untransformed */ + ((This->strided.u.s.position_transformed || strided.u.s.position_transformed) && + (This->strided.u.s.position.lpData != strided.u.s.position.lpData || + This->strided.u.s.position.dwType != strided.u.s.position.dwType)) || + /* Diffuse position and data type */ + This->strided.u.s.diffuse.lpData != strided.u.s.diffuse.lpData || This->strided.u.s.diffuse.dwStride != strided.u.s.diffuse.dwStride || + This->strided.u.s.diffuse.dwType != strided.u.s.diffuse.dwType || + /* Specular position and data type */ + This->strided.u.s.specular.lpData != strided.u.s.specular.lpData || This->strided.u.s.specular.dwStride != strided.u.s.specular.dwStride || + This->strided.u.s.specular.dwType != strided.u.s.specular.dwType) { + + TRACE("Declaration changed, reloading buffer\n"); + /* Set the new description */ + memcpy(&This->strided, &strided, sizeof(strided)); + return TRUE; + } + + return FALSE; +} + +static void WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *iface) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *) iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + BYTE *data; + UINT start = 0, end = 0, stride = 0; + BOOL declChanged = FALSE; + TRACE("(%p)->()\n", This); + + if(This->Flags & VBFLAG_LOAD) { + return; /* Already doing that stuff */ + } + + if(!This->vbo) { + /* TODO: Make converting independent from VBOs */ + return; /* Not doing any conversion */ + } + + /* Reading the declaration makes only sense if the stateblock is finalized and the buffer bound to a stream */ + if(device->isInDraw && This->bindCount > 0) { + declChanged = IWineD3DVertexBufferImpl_FindDecl(This); + } else if(This->Flags & VBFLAG_HASDESC) { + /* Reuse the declaration stored in the buffer. It will most likely not change, and if it does + * the stream source state handler will call PreLoad again and the change will be cought + */ + } else { + /* Cannot get a declaration, and no declaration is stored in the buffer. It is pointless to preload + * now. When the buffer is used, PreLoad will be called by the stream source state handler and a valid + * declaration for the buffer can be found + */ + return; + } + + /* If applications change the declaration over and over, reconverting all the time is a huge + * performance hit. So count the declaration changes and release the VBO if there are too much + * of them(and thus stop converting) + */ + if(declChanged) { + This->declChanges++; + This->draws = 0; + + if(This->declChanges > VB_MAXDECLCHANGES) { + FIXME("Too much declaration changes, stopping converting\n"); + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + ENTER_GL(); + GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo)); + checkGLcall("glDeleteBuffersARB"); + LEAVE_GL(); + This->vbo = 0; + + /* The stream source state handler might have read the memory of the vertex buffer already + * and got the memory in the vbo which is not valid any longer. Dirtify the stream source + * to force a reload. This happens only once per changed vertexbuffer and should occur rather + * rarely + */ + IWineD3DDeviceImpl_MarkStateDirty(device, STATE_STREAMSRC); + + return; + } + } else { + /* However, it is perfectly fine to change the declaration every now and then. We don't want a game that + * changes it every minute drop the VBO after VB_MAX_DECL_CHANGES minutes. So count draws without + * decl changes and reset the decl change count after a specific number of them + */ + This->draws++; + if(This->draws > VB_RESETDECLCHANGE) This->declChanges = 0; + } + + if(declChanged) { + /* The declaration changed, reload the whole buffer */ + WARN("Reloading buffer because of decl change\n"); + start = 0; + end = This->resource.size; + } else if(This->Flags & VBFLAG_DIRTY) { + /* No decl change, but dirty data, reload the changed stuff */ + start = This->dirtystart; + end = This->dirtyend; + } else { + /* Desc not changed, buffer not dirty, nothing to do :-) */ + return; + } + + /* Mark the buffer clean */ + This->Flags &= ~VBFLAG_DIRTY; + This->dirtystart = 0; + This->dirtyend = 0; + + if (This->strided.u.s.position.dwStride) stride = This->strided.u.s.position.dwStride; + else if(This->strided.u.s.specular.dwStride) stride = This->strided.u.s.specular.dwStride; + else if(This->strided.u.s.diffuse.dwStride) stride = This->strided.u.s.diffuse.dwStride; + else { + /* That means that there is nothing to fixup. Just upload from This->resource.allocatedMemory + * directly into the vbo. Do not free the system memory copy because drawPrimitive may need it if + * the stride is 0, for instancing emulation, vertex blending emulation or shader emulation. + */ + TRACE("No conversion needed, locking directly into the VBO in future\n"); + + if(!device->isInDraw) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + ENTER_GL(); + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo)); + checkGLcall("glBindBufferARB"); + GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end-start, This->resource.allocatedMemory + start)); + checkGLcall("glBufferSubDataARB"); + LEAVE_GL(); + return; + } + + /* OK, we have the original data from the app, the description of the buffer and the dirty area. + * so convert the stuff + */ + data = HeapAlloc(GetProcessHeap(), 0, end-start); + if(!data) { + ERR("Out of memory\n"); + return; + } + memcpy(data, This->resource.allocatedMemory + start, end - start); + + fixup_vertices(data, data, stride, ( end - start) / stride, + /* Position */ + (int)This->strided.u.s.position.lpData, /* Data location */ + This->strided.u.s.position_transformed, /* Do convert? */ + /* Diffuse color */ + (int)This->strided.u.s.diffuse.lpData, /* Location */ + This->strided.u.s.diffuse.dwType == WINED3DDECLTYPE_SHORT4 || This->strided.u.s.diffuse.dwType == WINED3DDECLTYPE_D3DCOLOR, /* Convert? */ + /* specular color */ + (int)This->strided.u.s.specular.lpData, /* location */ + This->strided.u.s.specular.dwType == WINED3DDECLTYPE_SHORT4 || This->strided.u.s.specular.dwType == WINED3DDECLTYPE_D3DCOLOR); + + if(!device->isInDraw) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } + ENTER_GL(); + GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo)); + checkGLcall("glBindBufferARB"); + GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end - start, data)); + checkGLcall("glBufferSubDataARB"); + LEAVE_GL(); + + HeapFree(GetProcessHeap(), 0, data); +} + +static WINED3DRESOURCETYPE WINAPI IWineD3DVertexBufferImpl_GetType(IWineD3DVertexBuffer *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +static HRESULT WINAPI IWineD3DVertexBufferImpl_GetParent(IWineD3DVertexBuffer *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DVertexBuffer IWineD3DVertexBuffer parts follow + ****************************************************** */ +static HRESULT WINAPI IWineD3DVertexBufferImpl_Lock(IWineD3DVertexBuffer *iface, UINT OffsetToLock, UINT SizeToLock, BYTE** ppbData, DWORD Flags) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface; + BYTE *data; + TRACE("(%p)->%d, %d, %p, %08x\n", This, OffsetToLock, SizeToLock, ppbData, Flags); + + InterlockedIncrement(&This->lockcount); + + if(This->Flags & VBFLAG_DIRTY) { + if(This->dirtystart > OffsetToLock) This->dirtystart = OffsetToLock; + if(SizeToLock) { + if(This->dirtyend < OffsetToLock + SizeToLock) This->dirtyend = OffsetToLock + SizeToLock; + } else { + This->dirtyend = This->resource.size; + } + } else { + This->dirtystart = OffsetToLock; + if(SizeToLock) + This->dirtyend = OffsetToLock + SizeToLock; + else + This->dirtyend = This->resource.size; + } + + data = This->resource.allocatedMemory; + This->Flags |= VBFLAG_DIRTY; + *ppbData = data + OffsetToLock; + + TRACE("(%p) : returning memory of %p (base:%p,offset:%u)\n", This, data + OffsetToLock, data, OffsetToLock); + /* TODO: check Flags compatibility with This->currentDesc.Usage (see MSDN) */ + return WINED3D_OK; +} +HRESULT WINAPI IWineD3DVertexBufferImpl_Unlock(IWineD3DVertexBuffer *iface) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *) iface; + LONG lockcount; + TRACE("(%p)\n", This); + + lockcount = InterlockedDecrement(&This->lockcount); + if(lockcount > 0) { + /* Delay loading the buffer until everything is unlocked */ + TRACE("Ignoring the unlock\n"); + return WINED3D_OK; + } + + if(This->Flags & VBFLAG_HASDESC) { + IWineD3DVertexBufferImpl_PreLoad(iface); + } + return WINED3D_OK; +} +static HRESULT WINAPI IWineD3DVertexBufferImpl_GetDesc(IWineD3DVertexBuffer *iface, WINED3DVERTEXBUFFER_DESC *pDesc) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface; + + TRACE("(%p)\n", This); + pDesc->Format = This->resource.format; + pDesc->Type = This->resource.resourceType; + pDesc->Usage = This->resource.usage; + pDesc->Pool = This->resource.pool; + pDesc->Size = This->resource.size; + pDesc->FVF = This->fvf; + return WINED3D_OK; +} + +const IWineD3DVertexBufferVtbl IWineD3DVertexBuffer_Vtbl = +{ + /* IUnknown */ + IWineD3DVertexBufferImpl_QueryInterface, + IWineD3DVertexBufferImpl_AddRef, + IWineD3DVertexBufferImpl_Release, + /* IWineD3DResource */ + IWineD3DVertexBufferImpl_GetParent, + IWineD3DVertexBufferImpl_GetDevice, + IWineD3DVertexBufferImpl_SetPrivateData, + IWineD3DVertexBufferImpl_GetPrivateData, + IWineD3DVertexBufferImpl_FreePrivateData, + IWineD3DVertexBufferImpl_SetPriority, + IWineD3DVertexBufferImpl_GetPriority, + IWineD3DVertexBufferImpl_PreLoad, + IWineD3DVertexBufferImpl_GetType, + /* IWineD3DVertexBuffer */ + IWineD3DVertexBufferImpl_Lock, + IWineD3DVertexBufferImpl_Unlock, + IWineD3DVertexBufferImpl_GetDesc +}; + +BYTE* WINAPI IWineD3DVertexBufferImpl_GetMemory(IWineD3DVertexBuffer* iface, DWORD iOffset, GLint *vbo) { + IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface; + + *vbo = This->vbo; + if(This->vbo == 0) { + return This->resource.allocatedMemory + iOffset; + } else { + return (BYTE *) iOffset; + } +} + +HRESULT WINAPI IWineD3DVertexBufferImpl_ReleaseMemory(IWineD3DVertexBuffer* iface) { + return WINED3D_OK; +} diff --git a/reactos/dll/directx/wine/wined3d/vertexdeclaration.c b/reactos/dll/directx/wine/wined3d/vertexdeclaration.c new file mode 100644 index 00000000000..292f1f0ae3b --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/vertexdeclaration.c @@ -0,0 +1,182 @@ +/* + * vertex declaration implementation + * + * Copyright 2002-2005 Raphael Junqueira + * Copyright 2004 Jason Edmeades + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_decl); + +static void dump_wined3dvertexelement(const WINED3DVERTEXELEMENT *element) { + TRACE(" Stream: %d\n", element->Stream); + TRACE(" Offset: %d\n", element->Offset); + TRACE(" Type: %s (%#x)\n", debug_d3ddecltype(element->Type), element->Type); + TRACE(" Method: %s (%#x)\n", debug_d3ddeclmethod(element->Method), element->Method); + TRACE(" Usage: %s (%#x)\n", debug_d3ddeclusage(element->Usage), element->Usage); + TRACE("Usage index: %d\n", element->UsageIndex); + TRACE(" Register: %d\n", element->Reg); +} + +/* ******************************************* + IWineD3DVertexDeclaration IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DVertexDeclarationImpl_QueryInterface(IWineD3DVertexDeclaration *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DVertexDeclaration)){ + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DVertexDeclarationImpl_AddRef(IWineD3DVertexDeclaration *iface) { + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->ref); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IWineD3DVertexDeclarationImpl_Release(IWineD3DVertexDeclaration *iface) { + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->ref); + ref = InterlockedDecrement(&This->ref); + if (ref == 0) { + if(iface == This->wineD3DDevice->stateBlock->vertexDecl) { + /* See comment in PixelShader::Release */ + IWineD3DDeviceImpl_MarkStateDirty(This->wineD3DDevice, STATE_VDECL); + } + + HeapFree(GetProcessHeap(), 0, This->pDeclarationWine); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* ******************************************* + IWineD3DVertexDeclaration parts follow + ******************************************* */ + +static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetParent(IWineD3DVertexDeclaration *iface, IUnknown** parent){ + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + + *parent= This->parent; + IUnknown_AddRef(*parent); + TRACE("(%p) : returning %p\n", This, *parent); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetDevice(IWineD3DVertexDeclaration *iface, IWineD3DDevice** ppDevice) { + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + TRACE("(%p) : returning %p\n", This, This->wineD3DDevice); + + *ppDevice = (IWineD3DDevice *) This->wineD3DDevice; + IWineD3DDevice_AddRef(*ppDevice); + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetDeclaration(IWineD3DVertexDeclaration *iface, + WINED3DVERTEXELEMENT *elements, size_t *element_count) { + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + HRESULT hr = WINED3D_OK; + + TRACE("(%p) : d3d version %d, elements %p, element_count %p\n", + This, ((IWineD3DImpl *)This->wineD3DDevice->wineD3D)->dxVersion, elements, element_count); + + *element_count = This->declarationWNumElements; + if (elements) { + CopyMemory(elements, This->pDeclarationWine, This->declarationWNumElements * sizeof(WINED3DVERTEXELEMENT)); + } + + return hr; +} + +static HRESULT WINAPI IWineD3DVertexDeclarationImpl_SetDeclaration(IWineD3DVertexDeclaration *iface, + const WINED3DVERTEXELEMENT *elements, size_t element_count) { + IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface; + HRESULT hr = WINED3D_OK; + int i; + char isPreLoaded[MAX_STREAMS]; + + TRACE("(%p) : d3d version %d\n", This, ((IWineD3DImpl *)This->wineD3DDevice->wineD3D)->dxVersion); + memset(isPreLoaded, 0, sizeof(isPreLoaded)); + + if (TRACE_ON(d3d_decl)) { + for (i = 0; i < element_count; ++i) { + dump_wined3dvertexelement(elements+i); + } + } + + This->declarationWNumElements = element_count; + This->pDeclarationWine = HeapAlloc(GetProcessHeap(), 0, sizeof(WINED3DVERTEXELEMENT) * element_count); + if (!This->pDeclarationWine) { + ERR("Memory allocation failed\n"); + hr = WINED3DERR_OUTOFVIDEOMEMORY; + } else { + CopyMemory(This->pDeclarationWine, elements, sizeof(WINED3DVERTEXELEMENT) * element_count); + } + + /* Do some static analysis on the elements to make reading the declaration more comfortable + * for the drawing code + */ + This->num_streams = 0; + This->position_transformed = FALSE; + for (i = 0; i < element_count; ++i) { + + if(This->pDeclarationWine[i].Usage == WINED3DDECLUSAGE_POSITIONT) { + This->position_transformed = TRUE; + } + + /* Find the Streams used in the declaration. The vertex buffers have to be loaded + * when drawing, but filter tesselation pseudo streams + */ + if(This->pDeclarationWine[i].Stream >= MAX_STREAMS) continue; + + if(!isPreLoaded[This->pDeclarationWine[i].Stream]) { + This->streams[This->num_streams] = This->pDeclarationWine[i].Stream; + This->num_streams++; + isPreLoaded[This->pDeclarationWine[i].Stream] = 1; + } + } + + TRACE("Returning\n"); + return hr; +} + +const IWineD3DVertexDeclarationVtbl IWineD3DVertexDeclaration_Vtbl = +{ + /* IUnknown */ + IWineD3DVertexDeclarationImpl_QueryInterface, + IWineD3DVertexDeclarationImpl_AddRef, + IWineD3DVertexDeclarationImpl_Release, + /* IWineD3DVertexDeclaration */ + IWineD3DVertexDeclarationImpl_GetParent, + IWineD3DVertexDeclarationImpl_GetDevice, + IWineD3DVertexDeclarationImpl_GetDeclaration, + IWineD3DVertexDeclarationImpl_SetDeclaration +}; diff --git a/reactos/dll/directx/wine/wined3d/vertexshader.c b/reactos/dll/directx/wine/wined3d/vertexshader.c new file mode 100644 index 00000000000..1c95d65c155 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/vertexshader.c @@ -0,0 +1,663 @@ +/* + * shaders implementation + * + * Copyright 2002-2003 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Christian Costa + * Copyright 2005 Oliver Stieber + * Copyright 2006 Ivan Gyurdiev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include +#include + +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); + +#define GLINFO_LOCATION ((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info + +/* Shader debugging - Change the following line to enable debugging of software + vertex shaders */ +#if 0 /* Musxt not be 1 in cvs version */ +# define VSTRACE(A) TRACE A +# define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w) +#else +# define VSTRACE(A) +# define TRACE_VSVECTOR(name) +#endif + +/** + * DirectX9 SDK download + * http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp + * + * Exploring D3DX + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx07162002.asp + * + * Using Vertex Shaders + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx02192001.asp + * + * Dx9 New + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/whatsnew.asp + * + * Dx9 Shaders + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/VertexShader2_0.asp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/Instructions/Instructions.asp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexDeclaration/VertexDeclaration.asp + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader3_0/VertexShader3_0.asp + * + * Dx9 D3DX + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/VertexPipe/matrixstack/matrixstack.asp + * + * FVF + * http://msdn.microsoft.com/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexFormats/vformats.asp + * + * NVIDIA: DX8 Vertex Shader to NV Vertex Program + * http://developer.nvidia.com/view.asp?IO=vstovp + * + * NVIDIA: Memory Management with VAR + * http://developer.nvidia.com/view.asp?IO=var_memory_management + */ + +/* TODO: Vertex and Pixel shaders are almost identicle, the only exception being the way that some of the data is looked up or the availablity of some of the data i.e. some instructions are only valid for pshaders and some for vshaders +because of this the bulk of the software pipeline can be shared between pixel and vertex shaders... and it wouldn't supprise me if the programes can be cross compiled using a large body body shared code */ + +#define GLNAME_REQUIRE_GLSL ((const char *)1) + +CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = { + /* This table is not order or position dependent. */ + + /* Arithmetic */ + {WINED3DSIO_NOP, "nop", "NOP", 0, 0, vshader_hw_map2gl, NULL, 0, 0}, + {WINED3DSIO_MOV, "mov", "MOV", 1, 2, vshader_hw_map2gl, shader_glsl_mov, 0, 0}, + {WINED3DSIO_MOVA, "mova", NULL, 1, 2, vshader_hw_map2gl, shader_glsl_mov, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_ADD, "add", "ADD", 1, 3, vshader_hw_map2gl, shader_glsl_arith, 0, 0}, + {WINED3DSIO_SUB, "sub", "SUB", 1, 3, vshader_hw_map2gl, shader_glsl_arith, 0, 0}, + {WINED3DSIO_MAD, "mad", "MAD", 1, 4, vshader_hw_map2gl, shader_glsl_mad, 0, 0}, + {WINED3DSIO_MUL, "mul", "MUL", 1, 3, vshader_hw_map2gl, shader_glsl_arith, 0, 0}, + {WINED3DSIO_RCP, "rcp", "RCP", 1, 2, vshader_hw_rsq_rcp, shader_glsl_rcp, 0, 0}, + {WINED3DSIO_RSQ, "rsq", "RSQ", 1, 2, vshader_hw_rsq_rcp, shader_glsl_rsq, 0, 0}, + {WINED3DSIO_DP3, "dp3", "DP3", 1, 3, vshader_hw_map2gl, shader_glsl_dot, 0, 0}, + {WINED3DSIO_DP4, "dp4", "DP4", 1, 3, vshader_hw_map2gl, shader_glsl_dot, 0, 0}, + {WINED3DSIO_MIN, "min", "MIN", 1, 3, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_MAX, "max", "MAX", 1, 3, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_SLT, "slt", "SLT", 1, 3, vshader_hw_map2gl, shader_glsl_compare, 0, 0}, + {WINED3DSIO_SGE, "sge", "SGE", 1, 3, vshader_hw_map2gl, shader_glsl_compare, 0, 0}, + {WINED3DSIO_ABS, "abs", "ABS", 1, 2, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_EXP, "exp", "EX2", 1, 2, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_LOG, "log", "LG2", 1, 2, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_EXPP, "expp", "EXP", 1, 2, vshader_hw_map2gl, shader_glsl_expp, 0, 0}, + {WINED3DSIO_LOGP, "logp", "LOG", 1, 2, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_LIT, "lit", "LIT", 1, 2, vshader_hw_map2gl, shader_glsl_lit, 0, 0}, + {WINED3DSIO_DST, "dst", "DST", 1, 3, vshader_hw_map2gl, shader_glsl_dst, 0, 0}, + {WINED3DSIO_LRP, "lrp", "LRP", 1, 4, NULL, shader_glsl_lrp, 0, 0}, + {WINED3DSIO_FRC, "frc", "FRC", 1, 2, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_POW, "pow", "POW", 1, 3, NULL, shader_glsl_pow, 0, 0}, + {WINED3DSIO_CRS, "crs", "XPS", 1, 3, NULL, shader_glsl_cross, 0, 0}, + /* TODO: sng can possibly be performed a s + RCP tmp, vec + MUL out, tmp, vec*/ + {WINED3DSIO_SGN, "sgn", NULL, 1, 2, NULL, shader_glsl_map2gl, 0, 0}, + /* TODO: xyz normalise can be performed as VS_ARB using one temporary register, + DP3 tmp , vec, vec; + RSQ tmp, tmp.x; + MUL vec.xyz, vec, tmp; + but I think this is better because it accounts for w properly. + DP3 tmp , vec, vec; + RSQ tmp, tmp.x; + MUL vec, vec, tmp; + */ + {WINED3DSIO_NRM, "nrm", NULL, 1, 2, NULL, shader_glsl_map2gl, 0, 0}, + {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, NULL, shader_glsl_sincos, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)}, + {WINED3DSIO_SINCOS, "sincos", NULL, 1, 2, NULL, shader_glsl_sincos, WINED3DVS_VERSION(3,0), -1}, + /* Matrix */ + {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0}, + /* Declare registers */ + {WINED3DSIO_DCL, "dcl", NULL, 0, 2, NULL, NULL, 0, 0}, + /* Constant definitions */ + {WINED3DSIO_DEF, "def", NULL, 1, 5, NULL, NULL, 0, 0}, + {WINED3DSIO_DEFB, "defb", GLNAME_REQUIRE_GLSL, 1, 2, NULL, NULL, 0, 0}, + {WINED3DSIO_DEFI, "defi", GLNAME_REQUIRE_GLSL, 1, 5, NULL, NULL, 0, 0}, + /* Flow control - requires GLSL or software shaders */ + {WINED3DSIO_REP , "rep", NULL, 0, 1, NULL, shader_glsl_rep, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_ENDREP, "endrep", NULL, 0, 0, NULL, shader_glsl_end, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_IF, "if", NULL, 0, 1, NULL, shader_glsl_if, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_IFC, "ifc", NULL, 0, 2, NULL, shader_glsl_ifc, WINED3DVS_VERSION(2,1), -1}, + {WINED3DSIO_ELSE, "else", NULL, 0, 0, NULL, shader_glsl_else, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_ENDIF, "endif", NULL, 0, 0, NULL, shader_glsl_end, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_BREAK, "break", NULL, 0, 0, NULL, shader_glsl_break, WINED3DVS_VERSION(2,1), -1}, + {WINED3DSIO_BREAKC, "breakc", NULL, 0, 2, NULL, shader_glsl_breakc, WINED3DVS_VERSION(2,1), -1}, + {WINED3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, NULL, NULL, 0, 0}, + {WINED3DSIO_CALL, "call", NULL, 0, 1, NULL, shader_glsl_call, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_CALLNZ, "callnz", NULL, 0, 2, NULL, shader_glsl_callnz, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_LOOP, "loop", NULL, 0, 2, NULL, shader_glsl_loop, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_RET, "ret", NULL, 0, 0, NULL, NULL, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_ENDLOOP,"endloop", NULL, 0, 0, NULL, shader_glsl_end, WINED3DVS_VERSION(2,0), -1}, + {WINED3DSIO_LABEL, "label", NULL, 0, 1, NULL, shader_glsl_label, WINED3DVS_VERSION(2,0), -1}, + + {WINED3DSIO_SETP, "setp", GLNAME_REQUIRE_GLSL, 1, 3, NULL, NULL, 0, 0}, + {WINED3DSIO_TEXLDL, "texldl", NULL, 1, 3, NULL, shader_glsl_texldl, WINED3DVS_VERSION(3,0), -1}, + {0, NULL, NULL, 0, 0, NULL, NULL, 0, 0} +}; + +static void vshader_set_limits( + IWineD3DVertexShaderImpl *This) { + + This->baseShader.limits.texcoord = 0; + This->baseShader.limits.attributes = 16; + This->baseShader.limits.packed_input = 0; + + /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */ + This->baseShader.limits.constant_float = GL_LIMITS(vshader_constantsF); + + switch (This->baseShader.hex_version) { + case WINED3DVS_VERSION(1,0): + case WINED3DVS_VERSION(1,1): + This->baseShader.limits.temporary = 12; + This->baseShader.limits.constant_bool = 0; + This->baseShader.limits.constant_int = 0; + This->baseShader.limits.address = 1; + This->baseShader.limits.packed_output = 0; + This->baseShader.limits.sampler = 0; + This->baseShader.limits.label = 0; + break; + + case WINED3DVS_VERSION(2,0): + case WINED3DVS_VERSION(2,1): + This->baseShader.limits.temporary = 12; + This->baseShader.limits.constant_bool = 16; + This->baseShader.limits.constant_int = 16; + This->baseShader.limits.address = 1; + This->baseShader.limits.packed_output = 0; + This->baseShader.limits.sampler = 0; + This->baseShader.limits.label = 16; + break; + + case WINED3DVS_VERSION(3,0): + This->baseShader.limits.temporary = 32; + This->baseShader.limits.constant_bool = 32; + This->baseShader.limits.constant_int = 32; + This->baseShader.limits.address = 1; + This->baseShader.limits.packed_output = 12; + This->baseShader.limits.sampler = 4; + This->baseShader.limits.label = 16; /* FIXME: 2048 */ + break; + + default: This->baseShader.limits.temporary = 12; + This->baseShader.limits.constant_bool = 16; + This->baseShader.limits.constant_int = 16; + This->baseShader.limits.address = 1; + This->baseShader.limits.packed_output = 0; + This->baseShader.limits.sampler = 0; + This->baseShader.limits.label = 16; + FIXME("Unrecognized vertex shader version %#x\n", + This->baseShader.hex_version); + } +} + +/* This is an internal function, + * used to create fake semantics for shaders + * that don't have them - d3d8 shaders where the declaration + * stores the register for each input + */ +static void vshader_set_input( + IWineD3DVertexShaderImpl* This, + unsigned int regnum, + BYTE usage, BYTE usage_idx) { + + /* Fake usage: set reserved bit, usage, usage_idx */ + DWORD usage_token = (0x1 << 31) | + (usage << WINED3DSP_DCL_USAGE_SHIFT) | (usage_idx << WINED3DSP_DCL_USAGEINDEX_SHIFT); + + /* Fake register; set reserved bit, regnum, type: input, wmask: all */ + DWORD reg_token = (0x1 << 31) | + WINED3DSP_WRITEMASK_ALL | (WINED3DSPR_INPUT << WINED3DSP_REGTYPE_SHIFT) | regnum; + + This->semantics_in[regnum].usage = usage_token; + This->semantics_in[regnum].reg = reg_token; +} + +static BOOL match_usage(BYTE usage1, BYTE usage_idx1, BYTE usage2, BYTE usage_idx2) { + if (usage_idx1 != usage_idx2) return FALSE; + if (usage1 == usage2) return TRUE; + if (usage1 == WINED3DDECLUSAGE_POSITION && usage2 == WINED3DDECLUSAGE_POSITIONT) return TRUE; + if (usage2 == WINED3DDECLUSAGE_POSITION && usage1 == WINED3DDECLUSAGE_POSITIONT) return TRUE; + + return FALSE; +} + +BOOL vshader_get_input( + IWineD3DVertexShader* iface, + BYTE usage_req, BYTE usage_idx_req, + unsigned int* regnum) { + + IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface; + int i; + + for (i = 0; i < MAX_ATTRIBS; i++) { + DWORD usage_token = This->semantics_in[i].usage; + DWORD usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + DWORD usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + + if (usage_token && match_usage(usage, usage_idx, usage_req, usage_idx_req)) { + *regnum = i; + return TRUE; + } + } + return FALSE; +} + +BOOL vshader_input_is_color( + IWineD3DVertexShader* iface, + unsigned int regnum) { + + IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface; + IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device; + IWineD3DVertexDeclarationImpl *vertexDeclaration = (IWineD3DVertexDeclarationImpl *)deviceImpl->stateBlock->vertexDecl; + + DWORD usage_token = This->semantics_in[regnum].usage; + DWORD usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT; + DWORD usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT; + + if (vertexDeclaration) { + int i; + /* Find the declaration element that matches our register, then check + * if it has D3DCOLOR as it's type. This works for both d3d8 and d3d9. */ + for (i = 0; i < vertexDeclaration->declarationWNumElements-1; ++i) { + WINED3DVERTEXELEMENT *element = vertexDeclaration->pDeclarationWine + i; + if (match_usage(element->Usage, element->UsageIndex, usage, usage_idx)) { + return element->Type == WINED3DDECLTYPE_D3DCOLOR; + } + } + } + + ERR("Either no vertexdeclaration present, or register not matched. This should never happen.\n"); + return FALSE; +} + +/** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB + or GLSL and send it to the card */ +static VOID IWineD3DVertexShaderImpl_GenerateShader( + IWineD3DVertexShader *iface, + shader_reg_maps* reg_maps, + CONST DWORD *pFunction) { + + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + SHADER_BUFFER buffer; + +#if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders + it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */ + if (This->device->fixupVertexBufferSize < SHADER_PGMSIZE) { + HeapFree(GetProcessHeap(), 0, This->fixupVertexBuffer); + This->fixupVertexBuffer = HeapAlloc(GetProcessHeap() , 0, SHADER_PGMSIZE); + This->fixupVertexBufferSize = PGMSIZE; + This->fixupVertexBuffer[0] = 0; + } + buffer.buffer = This->device->fixupVertexBuffer; +#else + buffer.buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SHADER_PGMSIZE); +#endif + buffer.bsize = 0; + buffer.lineNo = 0; + buffer.newline = TRUE; + + if (This->baseShader.shader_mode == SHADER_GLSL) { + + /* Create the hw GLSL shader program and assign it as the baseShader.prgId */ + GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB)); + + /* Base Declarations */ + shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION); + + /* Base Shader Body */ + shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction); + + /* Unpack 3.0 outputs */ + if (This->baseShader.hex_version >= WINED3DVS_VERSION(3,0)) + vshader_glsl_output_unpack(&buffer, This->semantics_out); + + /* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */ + if (!reg_maps->fog) + shader_addline(&buffer, "gl_FogFragCoord = gl_Position.z;\n"); + + /* Write the final position. + * + * OpenGL coordinates specify the center of the pixel while d3d coords specify + * the corner. The offsets are stored in z and w in the 2nd row of the projection + * matrix to avoid wasting a free shader constant. Add them to the w and z coord + * of the 2nd row + */ + shader_addline(&buffer, "gl_Position.x = gl_Position.x + posFixup[2];\n"); + shader_addline(&buffer, "gl_Position.y = gl_Position.y + posFixup[3];\n"); + /* Account for any inverted textures (render to texture case) by reversing the y coordinate + * (this is handled in drawPrim() when it sets the MODELVIEW and PROJECTION matrices) + */ + shader_addline(&buffer, "gl_Position.y = gl_Position.y * posFixup[1];\n"); + + shader_addline(&buffer, "}\n"); + + TRACE("Compiling shader object %u\n", shader_obj); + GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL)); + GL_EXTCALL(glCompileShaderARB(shader_obj)); + print_glsl_info_log(&GLINFO_LOCATION, shader_obj); + + /* Store the shader object */ + This->baseShader.prgId = shader_obj; + + } else if (This->baseShader.shader_mode == SHADER_ARB) { + + /* Create the hw ARB shader */ + shader_addline(&buffer, "!!ARBvp1.0\n"); + + /* Mesa supports only 95 constants */ + if (GL_VEND(MESA) || GL_VEND(WINE)) + This->baseShader.limits.constant_float = + min(95, This->baseShader.limits.constant_float); + + /* Base Declarations */ + shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, &buffer, &GLINFO_LOCATION); + + /* We need a constant to fixup the final position */ + shader_addline(&buffer, "PARAM posFixup = program.env[%d];\n", ARB_SHADER_PRIVCONST_POS); + + /* Base Shader Body */ + shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction); + + /* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */ + if (!reg_maps->fog) + shader_addline(&buffer, "MOV result.fogcoord, TMP_OUT.z;\n"); + + /* Write the final position. + * + * OpenGL coordinates specify the center of the pixel while d3d coords specify + * the corner. The offsets are stored in the 2nd row of the projection matrix, + * the x offset in z and the y offset in w. Add them to the resulting position + */ + shader_addline(&buffer, "ADD TMP_OUT.x, TMP_OUT.x, posFixup.z;\n"); + shader_addline(&buffer, "ADD TMP_OUT.y, TMP_OUT.y, posFixup.w;\n"); + /* Account for any inverted textures (render to texture case) by reversing the y coordinate + * (this is handled in drawPrim() when it sets the MODELVIEW and PROJECTION matrices) + */ + shader_addline(&buffer, "MUL TMP_OUT.y, TMP_OUT.y, posFixup.y;\n"); + + shader_addline(&buffer, "MOV result.position, TMP_OUT;\n"); + + shader_addline(&buffer, "END\n"); + + /* TODO: change to resource.glObjectHandle or something like that */ + GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId)); + + TRACE("Creating a hw vertex shader, prg=%d\n", This->baseShader.prgId); + GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->baseShader.prgId)); + + TRACE("Created hw vertex shader, prg=%d\n", This->baseShader.prgId); + /* Create the program and check for errors */ + GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + buffer.bsize, buffer.buffer)); + + if (glGetError() == GL_INVALID_OPERATION) { + GLint errPos; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); + FIXME("HW VertexShader Error at position %d: %s\n", + errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB))); + This->baseShader.prgId = -1; + } + } + +#if 1 /* if were using the data buffer of device then we don't need to free it */ + HeapFree(GetProcessHeap(), 0, buffer.buffer); +#endif +} + +/* ******************************************* + IWineD3DVertexShader IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DBaseShader) + || IsEqualGUID(riid, &IID_IWineD3DVertexShader)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) { + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->ref); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) { + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->ref); + ref = InterlockedDecrement(&This->ref); + if (ref == 0) { + if(iface == ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->vertexShader) { + /* See comment in PixelShader::Release */ + IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_VSHADER); + } + + if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { + struct list *linked_programs = &This->baseShader.linked_programs; + + TRACE("Deleting linked programs\n"); + if (linked_programs->next) { + struct glsl_shader_prog_link *entry, *entry2; + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, vshader_entry) { + delete_glsl_program_entry(This->baseShader.device, entry); + } + } + + TRACE("Deleting shader object %u\n", This->baseShader.prgId); + GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId)); + checkGLcall("glDeleteObjectARB"); + } + shader_delete_constant_list(&This->baseShader.constantsF); + shader_delete_constant_list(&This->baseShader.constantsB); + shader_delete_constant_list(&This->baseShader.constantsI); + HeapFree(GetProcessHeap(), 0, This); + + } + return ref; +} + +/* ******************************************* + IWineD3DVertexShader IWineD3DVertexShader parts follow + ******************************************* */ + +static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){ + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + + *parent = This->parent; + IUnknown_AddRef(*parent); + TRACE("(%p) : returning %p\n", This, *parent); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader* iface, IWineD3DDevice **pDevice){ + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + IWineD3DDevice_AddRef(This->baseShader.device); + *pDevice = This->baseShader.device; + TRACE("(%p) returning %p\n", This, *pDevice); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader* impl, VOID* pData, UINT* pSizeOfData) { + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)impl; + TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData); + + if (NULL == pData) { + *pSizeOfData = This->baseShader.functionLength; + return WINED3D_OK; + } + if (*pSizeOfData < This->baseShader.functionLength) { + /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller + * than the required size we should write the required size and + * return D3DERR_MOREDATA. That's not actually true. */ + return WINED3DERR_INVALIDCALL; + } + if (NULL == This->baseShader.function) { /* no function defined */ + TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This, pData); + (*(DWORD **) pData) = NULL; + } else { + if(This->baseShader.functionLength == 0){ + + } + TRACE("(%p) : GetFunction copying to %p\n", This, pData); + memcpy(pData, This->baseShader.function, This->baseShader.functionLength); + } + return WINED3D_OK; +} + +/* Note that for vertex shaders CompileShader isn't called until the + * shader is first used. The reason for this is that we need the vertex + * declaration the shader will be used with in order to determine if + * the data in a register is of type D3DCOLOR, and needs swizzling. */ +static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) { + + IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface; + IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device; + HRESULT hr; + shader_reg_maps *reg_maps = &This->baseShader.reg_maps; + + TRACE("(%p) : pFunction %p\n", iface, pFunction); + + /* First pass: trace shader */ + shader_trace_init((IWineD3DBaseShader*) This, pFunction); + vshader_set_limits(This); + + /* Initialize immediate constant lists */ + list_init(&This->baseShader.constantsF); + list_init(&This->baseShader.constantsB); + list_init(&This->baseShader.constantsI); + + /* Second pass: figure out registers used, semantics, etc.. */ + memset(reg_maps, 0, sizeof(shader_reg_maps)); + hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps, + This->semantics_in, This->semantics_out, pFunction, NULL); + if (hr != WINED3D_OK) return hr; + + This->baseShader.shader_mode = deviceImpl->vs_selected_mode; + + /* copy the function ... because it will certainly be released by application */ + if (NULL != pFunction) { + void *function; + + function = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->baseShader.functionLength); + if (!function) return E_OUTOFMEMORY; + memcpy(function, pFunction, This->baseShader.functionLength); + This->baseShader.function = function; + } else { + This->baseShader.function = NULL; + } + + return WINED3D_OK; +} + +/* Preload semantics for d3d8 shaders */ +static void WINAPI IWineD3DVertexShaderImpl_FakeSemantics(IWineD3DVertexShader *iface, IWineD3DVertexDeclaration *vertex_declaration) { + IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface; + IWineD3DVertexDeclarationImpl* vdecl = (IWineD3DVertexDeclarationImpl*)vertex_declaration; + + int i; + for (i = 0; i < vdecl->declarationWNumElements - 1; ++i) { + WINED3DVERTEXELEMENT* element = vdecl->pDeclarationWine + i; + vshader_set_input(This, element->Reg, element->Usage, element->UsageIndex); + } +} + +/* Set local constants for d3d8 shaders */ +static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertexShader *iface, + UINT start_idx, const float *src_data, UINT count) { + IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface; + UINT i, end_idx; + + TRACE("(%p) : start_idx %u, src_data %p, count %u\n", This, start_idx, src_data, count); + + end_idx = start_idx + count; + if (end_idx > GL_LIMITS(vshader_constantsF)) { + WARN("end_idx %u > float constants limit %u\n", end_idx, GL_LIMITS(vshader_constantsF)); + end_idx = GL_LIMITS(vshader_constantsF); + } + + for (i = start_idx; i < end_idx; ++i) { + local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant)); + if (!lconst) return E_OUTOFMEMORY; + + lconst->idx = i; + memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float)); + list_add_head(&This->baseShader.constantsF, &lconst->entry); + } + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface) { + IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; + CONST DWORD *function = This->baseShader.function; + + TRACE("(%p) : function %p\n", iface, function); + + /* We're already compiled. */ + if (This->baseShader.is_compiled) return WINED3D_OK; + + /* We don't need to compile */ + if (!function) { + This->baseShader.is_compiled = TRUE; + return WINED3D_OK; + } + + /* Generate the HW shader */ + TRACE("(%p) : Generating hardware program\n", This); + IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function); + + This->baseShader.is_compiled = TRUE; + + return WINED3D_OK; +} + +const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl = +{ + /*** IUnknown methods ***/ + IWineD3DVertexShaderImpl_QueryInterface, + IWineD3DVertexShaderImpl_AddRef, + IWineD3DVertexShaderImpl_Release, + /*** IWineD3DBase methods ***/ + IWineD3DVertexShaderImpl_GetParent, + /*** IWineD3DBaseShader methods ***/ + IWineD3DVertexShaderImpl_SetFunction, + IWineD3DVertexShaderImpl_CompileShader, + /*** IWineD3DVertexShader methods ***/ + IWineD3DVertexShaderImpl_GetDevice, + IWineD3DVertexShaderImpl_GetFunction, + IWineD3DVertexShaderImpl_FakeSemantics, + IWIneD3DVertexShaderImpl_SetLocalConstantsF +}; diff --git a/reactos/dll/directx/wine/wined3d/volume.c b/reactos/dll/directx/wine/wined3d/volume.c new file mode 100644 index 00000000000..425a45ed7c8 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/volume.c @@ -0,0 +1,333 @@ +/* + * IWineD3DVolume implementation + * + * Copyright 2002-2005 Jason Edmeades + * Copyright 2002-2005 Raphael Junqueira + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +/* ******************************************* + IWineD3DVolume IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DVolumeImpl_QueryInterface(IWineD3DVolume *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DVolume)){ + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DVolumeImpl_AddRef(IWineD3DVolume *iface) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref); + return InterlockedIncrement(&This->resource.ref); +} + +static ULONG WINAPI IWineD3DVolumeImpl_Release(IWineD3DVolume *iface) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->resource.ref); + ref = InterlockedDecrement(&This->resource.ref); + if (ref == 0) { + IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + +/* **************************************************** + IWineD3DVolume IWineD3DResource parts follow + **************************************************** */ +static HRESULT WINAPI IWineD3DVolumeImpl_GetParent(IWineD3DVolume *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +static HRESULT WINAPI IWineD3DVolumeImpl_GetDevice(IWineD3DVolume *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +static HRESULT WINAPI IWineD3DVolumeImpl_SetPrivateData(IWineD3DVolume *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IWineD3DVolumeImpl_GetPrivateData(IWineD3DVolume *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IWineD3DVolumeImpl_FreePrivateData(IWineD3DVolume *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +static DWORD WINAPI IWineD3DVolumeImpl_SetPriority(IWineD3DVolume *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +static DWORD WINAPI IWineD3DVolumeImpl_GetPriority(IWineD3DVolume *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +static void WINAPI IWineD3DVolumeImpl_PreLoad(IWineD3DVolume *iface) { + IWineD3DResourceImpl_PreLoad((IWineD3DResource *)iface); +} + +static WINED3DRESOURCETYPE WINAPI IWineD3DVolumeImpl_GetType(IWineD3DVolume *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +/* ******************************************* + IWineD3DVolume parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DVolumeImpl_GetContainer(IWineD3DVolume *iface, REFIID riid, void** ppContainer) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + + TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer); + + if (!ppContainer) { + ERR("Called without a valid ppContainer.\n"); + } + + /* Although surfaces can be standalone, volumes can't */ + if (!This->container) { + ERR("Volume without an container. Should not happen.\n"); + } + + TRACE("Relaying to QueryInterface\n"); + return IUnknown_QueryInterface(This->container, riid, ppContainer); +} + +static HRESULT WINAPI IWineD3DVolumeImpl_GetDesc(IWineD3DVolume *iface, WINED3DVOLUME_DESC* pDesc) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + TRACE("(%p) : copying into %p\n", This, pDesc); + + *(pDesc->Format) = This->resource.format; + *(pDesc->Type) = This->resource.resourceType; + *(pDesc->Usage) = This->resource.usage; + *(pDesc->Pool) = This->resource.pool; + *(pDesc->Size) = This->resource.size; /* dx8 only */ + *(pDesc->Width) = This->currentDesc.Width; + *(pDesc->Height) = This->currentDesc.Height; + *(pDesc->Depth) = This->currentDesc.Depth; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVolumeImpl_LockBox(IWineD3DVolume *iface, WINED3DLOCKED_BOX* pLockedVolume, CONST WINED3DBOX* pBox, DWORD Flags) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + FIXME("(%p) : pBox=%p stub\n", This, pBox); + + if(!This->resource.allocatedMemory) { + This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size); + } + + /* fixme: should we really lock as such? */ + TRACE("(%p) : box=%p, output pbox=%p, allMem=%p\n", This, pBox, pLockedVolume, This->resource.allocatedMemory); + + pLockedVolume->RowPitch = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */ + pLockedVolume->SlicePitch = This->bytesPerPixel * This->currentDesc.Width * This->currentDesc.Height; /* Bytes / slice */ + if (!pBox) { + TRACE("No box supplied - all is ok\n"); + pLockedVolume->pBits = This->resource.allocatedMemory; + This->lockedBox.Left = 0; + This->lockedBox.Top = 0; + This->lockedBox.Front = 0; + This->lockedBox.Right = This->currentDesc.Width; + This->lockedBox.Bottom = This->currentDesc.Height; + This->lockedBox.Back = This->currentDesc.Depth; + } else { + TRACE("Lock Box (%p) = l %d, t %d, r %d, b %d, fr %d, ba %d\n", pBox, pBox->Left, pBox->Top, pBox->Right, pBox->Bottom, pBox->Front, pBox->Back); + pLockedVolume->pBits = This->resource.allocatedMemory + + (pLockedVolume->SlicePitch * pBox->Front) + /* FIXME: is front < back or vica versa? */ + (pLockedVolume->RowPitch * pBox->Top) + + (pBox->Left * This->bytesPerPixel); + This->lockedBox.Left = pBox->Left; + This->lockedBox.Top = pBox->Top; + This->lockedBox.Front = pBox->Front; + This->lockedBox.Right = pBox->Right; + This->lockedBox.Bottom = pBox->Bottom; + This->lockedBox.Back = pBox->Back; + } + + if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) { + /* Don't dirtify */ + } else { + /** + * Dirtify on lock + * as seen in msdn docs + */ + IWineD3DVolume_AddDirtyBox(iface, &This->lockedBox); + + /** Dirtify Container if needed */ + if (NULL != This->container) { + + IWineD3DVolumeTexture *cont = (IWineD3DVolumeTexture*) This->container; + WINED3DRESOURCETYPE containerType = IWineD3DBaseTexture_GetType((IWineD3DBaseTexture *) cont); + + if (containerType == WINED3DRTYPE_VOLUMETEXTURE) { + IWineD3DBaseTextureImpl* pTexture = (IWineD3DBaseTextureImpl*) cont; + pTexture->baseTexture.dirty = TRUE; + } else { + FIXME("Set dirty on container type %d\n", containerType); + } + } + } + + This->locked = TRUE; + TRACE("returning memory@%p rpitch(%d) spitch(%d)\n", pLockedVolume->pBits, pLockedVolume->RowPitch, pLockedVolume->SlicePitch); + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVolumeImpl_UnlockBox(IWineD3DVolume *iface) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + if (!This->locked) { + ERR("trying to lock unlocked volume@%p\n", This); + return WINED3DERR_INVALIDCALL; + } + TRACE("(%p) : unlocking volume\n", This); + This->locked = FALSE; + memset(&This->lockedBox, 0, sizeof(RECT)); + return WINED3D_OK; +} + +/* Internal use functions follow : */ + +static HRESULT WINAPI IWineD3DVolumeImpl_CleanDirtyBox(IWineD3DVolume *iface) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + This->dirty = FALSE; + This->lockedBox.Left = This->currentDesc.Width; + This->lockedBox.Top = This->currentDesc.Height; + This->lockedBox.Front = This->currentDesc.Depth; + This->lockedBox.Right = 0; + This->lockedBox.Bottom = 0; + This->lockedBox.Back = 0; + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVolumeImpl_AddDirtyBox(IWineD3DVolume *iface, CONST WINED3DBOX* pDirtyBox) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + This->dirty = TRUE; + if (NULL != pDirtyBox) { + This->lockedBox.Left = min(This->lockedBox.Left, pDirtyBox->Left); + This->lockedBox.Top = min(This->lockedBox.Top, pDirtyBox->Top); + This->lockedBox.Front = min(This->lockedBox.Front, pDirtyBox->Front); + This->lockedBox.Right = max(This->lockedBox.Right, pDirtyBox->Right); + This->lockedBox.Bottom = max(This->lockedBox.Bottom, pDirtyBox->Bottom); + This->lockedBox.Back = max(This->lockedBox.Back, pDirtyBox->Back); + } else { + This->lockedBox.Left = 0; + This->lockedBox.Top = 0; + This->lockedBox.Front = 0; + This->lockedBox.Right = This->currentDesc.Width; + This->lockedBox.Bottom = This->currentDesc.Height; + This->lockedBox.Back = This->currentDesc.Depth; + } + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVolumeImpl_SetContainer(IWineD3DVolume *iface, IWineD3DBase* container) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + + TRACE("This %p, container %p\n", This, container); + + /* We can't keep a reference to the container, since the container already keeps a reference to us. */ + + TRACE("Setting container to %p from %p\n", container, This->container); + This->container = container; + + return WINED3D_OK; +} + +static HRESULT WINAPI IWineD3DVolumeImpl_LoadTexture(IWineD3DVolume *iface, int gl_level, BOOL srgb_mode) { + IWineD3DVolumeImpl *This = (IWineD3DVolumeImpl *)iface; + WINED3DFORMAT format = This->resource.format; + const GlPixelFormatDesc *glDesc; + getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc); + + TRACE("(%p) : level %u, format %s (0x%08x)\n", This, gl_level, debug_d3dformat(format), format); + + if(GL_SUPPORT(EXT_TEXTURE3D)) { + TRACE("Calling glTexImage3D %x level=%d, intfmt=%x, w=%d, h=%d,d=%d, 0=%d, glFmt=%x, glType=%x, Mem=%p\n", + GL_TEXTURE_3D, + gl_level, + glDesc->glInternal, + This->currentDesc.Width, + This->currentDesc.Height, + This->currentDesc.Depth, + 0, + glDesc->glFormat, + glDesc->glType, + This->resource.allocatedMemory); + GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, + gl_level, + glDesc->glInternal, + This->currentDesc.Width, + This->currentDesc.Height, + This->currentDesc.Depth, + 0, + glDesc->glFormat, + glDesc->glType, + This->resource.allocatedMemory)); + checkGLcall("glTexImage3D"); + } else + WARN("This OpenGL implementation doesn't support 3D textures\n"); + + /* When adding code releasing This->resource.allocatedMemory to save data keep in mind that + * GL_UNPACK_CLIENT_STORAGE_APPLE is enabled by default if supported(GL_APPLE_client_storage). + * Thus do not release This->resource.allocatedMemory if GL_APPLE_client_storage is supported. + */ + return WINED3D_OK; + +} + +const IWineD3DVolumeVtbl IWineD3DVolume_Vtbl = +{ + /* IUnknown */ + IWineD3DVolumeImpl_QueryInterface, + IWineD3DVolumeImpl_AddRef, + IWineD3DVolumeImpl_Release, + /* IWineD3DResource */ + IWineD3DVolumeImpl_GetParent, + IWineD3DVolumeImpl_GetDevice, + IWineD3DVolumeImpl_SetPrivateData, + IWineD3DVolumeImpl_GetPrivateData, + IWineD3DVolumeImpl_FreePrivateData, + IWineD3DVolumeImpl_SetPriority, + IWineD3DVolumeImpl_GetPriority, + IWineD3DVolumeImpl_PreLoad, + IWineD3DVolumeImpl_GetType, + /* IWineD3DVolume */ + IWineD3DVolumeImpl_GetContainer, + IWineD3DVolumeImpl_GetDesc, + IWineD3DVolumeImpl_LockBox, + IWineD3DVolumeImpl_UnlockBox, + /* Internal interface */ + IWineD3DVolumeImpl_AddDirtyBox, + IWineD3DVolumeImpl_CleanDirtyBox, + IWineD3DVolumeImpl_LoadTexture, + IWineD3DVolumeImpl_SetContainer +}; diff --git a/reactos/dll/directx/wine/wined3d/volumetexture.c b/reactos/dll/directx/wine/wined3d/volumetexture.c new file mode 100644 index 00000000000..cf3f33934a0 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/volumetexture.c @@ -0,0 +1,324 @@ +/* + * IWineD3DVolumeTexture implementation + * + * Copyright 2002-2005 Jason Edmeades + * Copyright 2002-2005 Raphael Junqueira + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); +#define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info + +/* ******************************************* + IWineD3DTexture IUnknown parts follow + ******************************************* */ +static HRESULT WINAPI IWineD3DVolumeTextureImpl_QueryInterface(IWineD3DVolumeTexture *iface, REFIID riid, LPVOID *ppobj) +{ + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IWineD3DBase) + || IsEqualGUID(riid, &IID_IWineD3DResource) + || IsEqualGUID(riid, &IID_IWineD3DBaseTexture) + || IsEqualGUID(riid, &IID_IWineD3DVolumeTexture)) { + IUnknown_AddRef(iface); + *ppobj = This; + return S_OK; + } + *ppobj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IWineD3DVolumeTextureImpl_AddRef(IWineD3DVolumeTexture *iface) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref); + return InterlockedIncrement(&This->resource.ref); +} + +static ULONG WINAPI IWineD3DVolumeTextureImpl_Release(IWineD3DVolumeTexture *iface) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + ULONG ref; + TRACE("(%p) : Releasing from %d\n", This, This->resource.ref); + ref = InterlockedDecrement(&This->resource.ref); + if (ref == 0) { + IWineD3DVolumeTexture_Destroy(iface, D3DCB_DefaultDestroyVolume); + } + return ref; +} + +/* **************************************************** + IWineD3DVolumeTexture IWineD3DResource parts follow + **************************************************** */ +static HRESULT WINAPI IWineD3DVolumeTextureImpl_GetDevice(IWineD3DVolumeTexture *iface, IWineD3DDevice** ppDevice) { + return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_SetPrivateData(IWineD3DVolumeTexture *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) { + return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_GetPrivateData(IWineD3DVolumeTexture *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) { + return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_FreePrivateData(IWineD3DVolumeTexture *iface, REFGUID refguid) { + return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid); +} + +static DWORD WINAPI IWineD3DVolumeTextureImpl_SetPriority(IWineD3DVolumeTexture *iface, DWORD PriorityNew) { + return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew); +} + +static DWORD WINAPI IWineD3DVolumeTextureImpl_GetPriority(IWineD3DVolumeTexture *iface) { + return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface); +} + +static void WINAPI IWineD3DVolumeTextureImpl_PreLoad(IWineD3DVolumeTexture *iface) { + /* Overrider the IWineD3DResource Preload method */ + int i; + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; + BOOL srgb_mode = This->baseTexture.is_srgb; + BOOL srgb_was_toggled = FALSE; + + TRACE("(%p) : About to load texture\n", This); + + IWineD3DVolumeTexture_BindTexture(iface); + + if(!device->isInDraw) { + ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); + } else if (GL_SUPPORT(EXT_TEXTURE_SRGB) && This->baseTexture.bindCount > 0) { + srgb_mode = device->stateBlock->samplerState[This->baseTexture.sampler][WINED3DSAMP_SRGBTEXTURE]; + srgb_was_toggled = This->baseTexture.is_srgb != srgb_mode; + This->baseTexture.is_srgb = srgb_mode; + } + ENTER_GL(); + /* If the texture is marked dirty or the srgb sampler setting has changed since the last load then reload the surfaces */ + if (This->baseTexture.dirty) { + for (i = 0; i < This->baseTexture.levels; i++) + IWineD3DVolume_LoadTexture(This->volumes[i], i, srgb_mode); + } else if (srgb_was_toggled) { + if (This->baseTexture.srgb_mode_change_count < 20) + ++This->baseTexture.srgb_mode_change_count; + else + FIXME("Volumetexture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); + + for (i = 0; i < This->baseTexture.levels; i++) { + IWineD3DVolume_AddDirtyBox(This->volumes[i], NULL); + IWineD3DVolume_LoadTexture(This->volumes[i], i, srgb_mode); + } + } else { + TRACE("(%p) Texture not dirty, nothing to do\n" , iface); + } + LEAVE_GL(); + + /* No longer dirty */ + This->baseTexture.dirty = FALSE; + + return ; +} + +static WINED3DRESOURCETYPE WINAPI IWineD3DVolumeTextureImpl_GetType(IWineD3DVolumeTexture *iface) { + return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_GetParent(IWineD3DVolumeTexture *iface, IUnknown **pParent) { + return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent); +} + +/* ****************************************************** + IWineD3DVolumeTexture IWineD3DBaseTexture parts follow + ****************************************************** */ +static DWORD WINAPI IWineD3DVolumeTextureImpl_SetLOD(IWineD3DVolumeTexture *iface, DWORD LODNew) { + return IWineD3DBaseTextureImpl_SetLOD((IWineD3DBaseTexture *)iface, LODNew); +} + +static DWORD WINAPI IWineD3DVolumeTextureImpl_GetLOD(IWineD3DVolumeTexture *iface) { + return IWineD3DBaseTextureImpl_GetLOD((IWineD3DBaseTexture *)iface); +} + +static DWORD WINAPI IWineD3DVolumeTextureImpl_GetLevelCount(IWineD3DVolumeTexture *iface) { + return IWineD3DBaseTextureImpl_GetLevelCount((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_SetAutoGenFilterType(IWineD3DVolumeTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType) { + return IWineD3DBaseTextureImpl_SetAutoGenFilterType((IWineD3DBaseTexture *)iface, FilterType); +} + +static WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DVolumeTextureImpl_GetAutoGenFilterType(IWineD3DVolumeTexture *iface) { + return IWineD3DBaseTextureImpl_GetAutoGenFilterType((IWineD3DBaseTexture *)iface); +} + +static void WINAPI IWineD3DVolumeTextureImpl_GenerateMipSubLevels(IWineD3DVolumeTexture *iface) { + IWineD3DBaseTextureImpl_GenerateMipSubLevels((IWineD3DBaseTexture *)iface); +} + +/* Internal function, No d3d mapping */ +static BOOL WINAPI IWineD3DVolumeTextureImpl_SetDirty(IWineD3DVolumeTexture *iface, BOOL dirty) { + return IWineD3DBaseTextureImpl_SetDirty((IWineD3DBaseTexture *)iface, dirty); +} + +static BOOL WINAPI IWineD3DVolumeTextureImpl_GetDirty(IWineD3DVolumeTexture *iface) { + return IWineD3DBaseTextureImpl_GetDirty((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_BindTexture(IWineD3DVolumeTexture *iface) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + TRACE("(%p) : relay to BaseTexture\n", This); + return IWineD3DBaseTextureImpl_BindTexture((IWineD3DBaseTexture *)iface); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_UnBindTexture(IWineD3DVolumeTexture *iface) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + TRACE("(%p) : relay to BaseTexture\n", This); + return IWineD3DBaseTextureImpl_UnBindTexture((IWineD3DBaseTexture *)iface); +} + +static UINT WINAPI IWineD3DVolumeTextureImpl_GetTextureDimensions(IWineD3DVolumeTexture *iface) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + TRACE("(%p)\n", This); + return GL_TEXTURE_3D; +} + +static void WINAPI IWineD3DVolumeTextureImpl_ApplyStateChanges(IWineD3DVolumeTexture *iface, + const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], + const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + TRACE("(%p) : nothing to do, passing to base texture\n", This); + IWineD3DBaseTextureImpl_ApplyStateChanges((IWineD3DBaseTexture *)iface, textureStates, samplerStates); +} + + +/* ******************************************* + IWineD3DVolumeTexture IWineD3DVolumeTexture parts follow + ******************************************* */ +static void WINAPI IWineD3DVolumeTextureImpl_Destroy(IWineD3DVolumeTexture *iface, D3DCB_DESTROYVOLUMEFN D3DCB_DestroyVolume) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + int i; + TRACE("(%p) : Cleaning up\n",This); + for (i = 0; i < This->baseTexture.levels; i++) { + if (This->volumes[i] != NULL) { + /* Cleanup the container */ + IWineD3DVolume_SetContainer(This->volumes[i], 0); + D3DCB_DestroyVolume(This->volumes[i]); + } + } + IWineD3DBaseTextureImpl_CleanUp((IWineD3DBaseTexture *) iface); + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_GetLevelDesc(IWineD3DVolumeTexture *iface, UINT Level,WINED3DVOLUME_DESC *pDesc) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + if (Level < This->baseTexture.levels) { + TRACE("(%p) Level (%d)\n", This, Level); + return IWineD3DVolume_GetDesc((IWineD3DVolume *) This->volumes[Level], pDesc); + } else { + FIXME("(%p) Level (%d)\n", This, Level); + } + return WINED3D_OK; +} +static HRESULT WINAPI IWineD3DVolumeTextureImpl_GetVolumeLevel(IWineD3DVolumeTexture *iface, UINT Level, IWineD3DVolume** ppVolumeLevel) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + if (Level < This->baseTexture.levels) { + *ppVolumeLevel = (IWineD3DVolume *)This->volumes[Level]; + IWineD3DVolume_AddRef((IWineD3DVolume *) *ppVolumeLevel); + TRACE("(%p) -> level(%d) returning volume@%p\n", This, Level, *ppVolumeLevel); + } else { + FIXME("(%p) Level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + return WINED3DERR_INVALIDCALL; + } + return WINED3D_OK; + +} +static HRESULT WINAPI IWineD3DVolumeTextureImpl_LockBox(IWineD3DVolumeTexture *iface, UINT Level, WINED3DLOCKED_BOX* pLockedVolume, CONST WINED3DBOX* pBox, DWORD Flags) { + HRESULT hr; + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + + if (Level < This->baseTexture.levels) { + hr = IWineD3DVolume_LockBox((IWineD3DVolume *)This->volumes[Level], pLockedVolume, pBox, Flags); + TRACE("(%p) Level (%d) success(%u)\n", This, Level, hr); + + } else { + FIXME("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + return WINED3DERR_INVALIDCALL; + } + return hr; +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_UnlockBox(IWineD3DVolumeTexture *iface, UINT Level) { + HRESULT hr; + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + + if (Level < This->baseTexture.levels) { + hr = IWineD3DVolume_UnlockBox((IWineD3DVolume*) This->volumes[Level]); + TRACE("(%p) -> level(%d) success(%u)\n", This, Level, hr); + + } else { + FIXME("(%p) level(%d) overflow Levels(%d)\n", This, Level, This->baseTexture.levels); + return WINED3DERR_INVALIDCALL; + } + return hr; +} + +static HRESULT WINAPI IWineD3DVolumeTextureImpl_AddDirtyBox(IWineD3DVolumeTexture *iface, CONST WINED3DBOX* pDirtyBox) { + IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + This->baseTexture.dirty = TRUE; + TRACE("(%p) : dirtyfication of volume Level (0)\n", This); + return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) This->volumes[0], pDirtyBox); +} + +const IWineD3DVolumeTextureVtbl IWineD3DVolumeTexture_Vtbl = +{ + /* IUnknown */ + IWineD3DVolumeTextureImpl_QueryInterface, + IWineD3DVolumeTextureImpl_AddRef, + IWineD3DVolumeTextureImpl_Release, + /* resource */ + IWineD3DVolumeTextureImpl_GetParent, + IWineD3DVolumeTextureImpl_GetDevice, + IWineD3DVolumeTextureImpl_SetPrivateData, + IWineD3DVolumeTextureImpl_GetPrivateData, + IWineD3DVolumeTextureImpl_FreePrivateData, + IWineD3DVolumeTextureImpl_SetPriority, + IWineD3DVolumeTextureImpl_GetPriority, + IWineD3DVolumeTextureImpl_PreLoad, + IWineD3DVolumeTextureImpl_GetType, + /* BaseTexture */ + IWineD3DVolumeTextureImpl_SetLOD, + IWineD3DVolumeTextureImpl_GetLOD, + IWineD3DVolumeTextureImpl_GetLevelCount, + IWineD3DVolumeTextureImpl_SetAutoGenFilterType, + IWineD3DVolumeTextureImpl_GetAutoGenFilterType, + IWineD3DVolumeTextureImpl_GenerateMipSubLevels, + IWineD3DVolumeTextureImpl_SetDirty, + IWineD3DVolumeTextureImpl_GetDirty, + /* not in d3d */ + IWineD3DVolumeTextureImpl_BindTexture, + IWineD3DVolumeTextureImpl_UnBindTexture, + IWineD3DVolumeTextureImpl_GetTextureDimensions, + IWineD3DVolumeTextureImpl_ApplyStateChanges, + /* volume texture */ + IWineD3DVolumeTextureImpl_Destroy, + IWineD3DVolumeTextureImpl_GetLevelDesc, + IWineD3DVolumeTextureImpl_GetVolumeLevel, + IWineD3DVolumeTextureImpl_LockBox, + IWineD3DVolumeTextureImpl_UnlockBox, + IWineD3DVolumeTextureImpl_AddDirtyBox +}; diff --git a/reactos/dll/directx/wine/wined3d/wined3d.def b/reactos/dll/directx/wine/wined3d/wined3d.def new file mode 100644 index 00000000000..28647e8f363 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/wined3d.def @@ -0,0 +1,3 @@ +EXPORTS +WineDirect3DCreate@12 +WineDirect3DCreateClipper@4 diff --git a/reactos/dll/directx/wine/wined3d/wined3d.rbuild b/reactos/dll/directx/wine/wined3d/wined3d.rbuild new file mode 100644 index 00000000000..8190b895155 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/wined3d.rbuild @@ -0,0 +1,51 @@ + + + . + include/reactos/wine + + + 0x600 + 0x501 + 0x501 + + + + wine + user32 + opengl32 + gdi32 + advapi32 + kernel32 + uuid + msvcrt + + arb_program_shader.c + baseshader.c + basetexture.c + clipper.c + context.c + cubetexture.c + device.c + directx.c + drawprim.c + glsl_shader.c + indexbuffer.c + palette.c + pixelshader.c + query.c + resource.c + state.c + stateblock.c + surface.c + surface_gdi.c + swapchain.c + texture.c + utils.c + vertexbuffer.c + vertexdeclaration.c + vertexshader.c + volume.c + volumetexture.c + wined3d_main.c + version.rc + diff --git a/reactos/dll/directx/wine/wined3d/wined3d.spec b/reactos/dll/directx/wine/wined3d/wined3d.spec new file mode 100644 index 00000000000..fc36584fba1 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/wined3d.spec @@ -0,0 +1,2 @@ +@ stdcall WineDirect3DCreate(long long ptr) +@ stdcall WineDirect3DCreateClipper(ptr) diff --git a/reactos/dll/directx/wine/wined3d/wined3d_main.c b/reactos/dll/directx/wine/wined3d/wined3d_main.c new file mode 100644 index 00000000000..13ab258dbb8 --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/wined3d_main.c @@ -0,0 +1,291 @@ +/* + * Direct3D wine internal interface main + * + * Copyright 2002-2003 The wine-d3d team + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Jason Edmeades + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include "initguid.h" +#include "wined3d_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wine_d3d); + +int num_lock = 0; +void (*wine_tsx11_lock_ptr)(void) = NULL; +void (*wine_tsx11_unlock_ptr)(void) = NULL; + + +/* When updating default value here, make sure to update winecfg as well, + * where appropriate. */ +wined3d_settings_t wined3d_settings = +{ + VS_HW, /* Hardware by default */ + PS_HW, /* Hardware by default */ + VBO_HW, /* Hardware by default */ + FALSE, /* Use of GLSL disabled by default */ + ORM_BACKBUFFER, /* Use the backbuffer to do offscreen rendering */ + RTL_AUTO, /* Automatically determine best locking method */ + 64*1024*1024 /* 64MB texture memory by default */ +}; + +WineD3DGlobalStatistics *wineD3DGlobalStatistics = NULL; + +long globalChangeGlRam(long glram){ + /* FIXME: replace this function with object tracking */ + int result; + + wineD3DGlobalStatistics->glsurfaceram += glram; + TRACE("Adjusted gl ram by %ld to %d\n", glram, wineD3DGlobalStatistics->glsurfaceram); + result = wineD3DGlobalStatistics->glsurfaceram; + return result; + +} + +IWineD3D* WINAPI WineDirect3DCreate(UINT SDKVersion, UINT dxVersion, IUnknown *parent) { + IWineD3DImpl* object; + + if (!InitAdapters()) { + WARN("Failed to initialize direct3d adapters, Direct3D will not be available\n"); + if(dxVersion > 7) { + ERR("Direct3D%d is not available without opengl\n", dxVersion); + return NULL; + } + } + + object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DImpl)); + object->lpVtbl = &IWineD3D_Vtbl; + object->dxVersion = dxVersion; + object->ref = 1; + object->parent = parent; + + /*Create a structure for storing global data in*/ + if(wineD3DGlobalStatistics == NULL){ + TRACE("Creating global statistics store\n"); + wineD3DGlobalStatistics = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wineD3DGlobalStatistics)); + + } + + TRACE("Created WineD3D object @ %p for d3d%d support\n", object, dxVersion); + + return (IWineD3D *)object; +} + +static inline DWORD get_config_key(HKEY defkey, HKEY appkey, const char* name, char* buffer, DWORD size) +{ + if (0 != appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0; + if (0 != defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE) buffer, &size )) return 0; + return ERROR_FILE_NOT_FOUND; +} + +static void wined3d_do_nothing(void) +{ +} + +/* At process attach */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) +{ + TRACE("WineD3D DLLMain Reason=%d\n", fdwReason); + if (fdwReason == DLL_PROCESS_ATTACH) + { + HMODULE mod; + char buffer[MAX_PATH+10]; + DWORD size = sizeof(buffer); + HKEY hkey = 0; + HKEY appkey = 0; + DWORD len; + WNDCLASSA wc; + + wined3d_settings.emulated_textureram = 64*1024*1024; + + /* We need our own window class for a fake window which we use to retrieve GL capabilities */ + /* We might need CS_OWNDC in the future if we notice strange things on Windows. + * Various articles/posts about OpenGL problems on Windows recommend this. */ + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = DefWindowProcA; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstDLL; + wc.hIcon = LoadIconA(NULL, (LPCSTR)IDI_WINLOGO); + wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "WineD3D_OpenGL"; + + if (!RegisterClassA(&wc) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + { + ERR("Failed to register window class 'WineD3D_OpenGL'!\n"); + return FALSE; + } + + DisableThreadLibraryCalls(hInstDLL); + + mod = GetModuleHandleA( "winex11.drv" ); + if (mod) + { + wine_tsx11_lock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_lock" ); + wine_tsx11_unlock_ptr = (void *)GetProcAddress( mod, "wine_tsx11_unlock" ); + } + else /* We are most likely on Windows */ + { + wine_tsx11_lock_ptr = wined3d_do_nothing; + wine_tsx11_unlock_ptr = wined3d_do_nothing; + } + /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */ + if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey ) ) hkey = 0; + + len = GetModuleFileNameA( 0, buffer, MAX_PATH ); + if (len && len < MAX_PATH) + { + HKEY tmpkey; + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */ + if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey )) + { + char *p, *appname = buffer; + if ((p = strrchr( appname, '/' ))) appname = p + 1; + if ((p = strrchr( appname, '\\' ))) appname = p + 1; + strcat( appname, "\\Direct3D" ); + TRACE("appname = [%s]\n", appname); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + RegCloseKey( tmpkey ); + } + } + + if ( 0 != hkey || 0 != appkey ) + { + if ( !get_config_key( hkey, appkey, "VertexShaderMode", buffer, size) ) + { + if (!strcmp(buffer,"none")) + { + TRACE("Disable vertex shaders\n"); + wined3d_settings.vs_mode = VS_NONE; + } + } + if ( !get_config_key( hkey, appkey, "PixelShaderMode", buffer, size) ) + { + if (!strcmp(buffer,"enabled")) + { + TRACE("Allow pixel shaders\n"); + wined3d_settings.ps_mode = PS_HW; + } + if (!strcmp(buffer,"disabled")) + { + TRACE("Disable pixel shaders\n"); + wined3d_settings.ps_mode = PS_NONE; + } + } + if ( !get_config_key( hkey, appkey, "VertexBufferMode", buffer, size) ) + { + if (!strcmp(buffer,"none")) + { + TRACE("Disable Vertex Buffer Hardware support\n"); + wined3d_settings.vbo_mode = VBO_NONE; + } + else if (!strcmp(buffer,"hardware")) + { + TRACE("Allow Vertex Buffer Hardware support\n"); + wined3d_settings.vbo_mode = VBO_HW; + } + } + if ( !get_config_key( hkey, appkey, "UseGLSL", buffer, size) ) + { + if (!strcmp(buffer,"enabled")) + { + TRACE("Use of GL Shading Language enabled for systems that support it\n"); + wined3d_settings.glslRequested = TRUE; + } + else + { + TRACE("Use of GL Shading Language disabled\n"); + } + } + if ( !get_config_key( hkey, appkey, "OffscreenRenderingMode", buffer, size) ) + { + if (!strcmp(buffer,"backbuffer")) + { + TRACE("Using the backbuffer for offscreen rendering\n"); + wined3d_settings.offscreen_rendering_mode = ORM_BACKBUFFER; + } + else if (!strcmp(buffer,"pbuffer")) + { + TRACE("Using PBuffers for offscreen rendering\n"); + wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER; + } + else if (!strcmp(buffer,"fbo")) + { + TRACE("Using FBOs for offscreen rendering\n"); + wined3d_settings.offscreen_rendering_mode = ORM_FBO; + } + } + if ( !get_config_key( hkey, appkey, "RenderTargetLockMode", buffer, size) ) + { + if (!strcmp(buffer,"disabled")) + { + TRACE("Disabling render target locking\n"); + wined3d_settings.rendertargetlock_mode = RTL_DISABLE; + } + else if (!strcmp(buffer,"readdraw")) + { + TRACE("Using glReadPixels for render target reading and glDrawPixels for writing\n"); + wined3d_settings.rendertargetlock_mode = RTL_READDRAW; + } + else if (!strcmp(buffer,"readtex")) + { + TRACE("Using glReadPixels for render target reading and textures for writing\n"); + wined3d_settings.rendertargetlock_mode = RTL_READTEX; + } + else if (!strcmp(buffer,"texdraw")) + { + TRACE("Using textures for render target reading and glDrawPixels for writing\n"); + wined3d_settings.rendertargetlock_mode = RTL_TEXDRAW; + } + else if (!strcmp(buffer,"textex")) + { + TRACE("Reading render targets via textures and writing via textures\n"); + wined3d_settings.rendertargetlock_mode = RTL_TEXTEX; + } + } + if ( !get_config_key( hkey, appkey, "VideoMemorySize", buffer, size) ) + { + int TmpVideoMemorySize = atoi(buffer); + if(TmpVideoMemorySize > 0) + { + wined3d_settings.emulated_textureram = TmpVideoMemorySize *1024*1024; + TRACE("Use %iMB = %d byte for emulated_textureram\n", + TmpVideoMemorySize, + wined3d_settings.emulated_textureram); + } + else + ERR("VideoMemorySize is %i but must be >0\n", TmpVideoMemorySize); + } + } + if (wined3d_settings.vs_mode == VS_HW) + TRACE("Allow HW vertex shaders\n"); + if (wined3d_settings.ps_mode == PS_NONE) + TRACE("Disable pixel shaders\n"); + if (wined3d_settings.vbo_mode == VBO_NONE) + TRACE("Disable Vertex Buffer Hardware support\n"); + if (wined3d_settings.glslRequested) + TRACE("If supported by your system, GL Shading Language will be used\n"); + + if (appkey) RegCloseKey( appkey ); + if (hkey) RegCloseKey( hkey ); + } + return TRUE; +} diff --git a/reactos/dll/directx/wine/wined3d/wined3d_private.h b/reactos/dll/directx/wine/wined3d/wined3d_private.h new file mode 100644 index 00000000000..73e83d24ace --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/wined3d_private.h @@ -0,0 +1,2133 @@ +/* + * Direct3D wine internal private include file + * + * Copyright 2002-2003 The wine-d3d team + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2004 Jason Edmeades + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINED3D_PRIVATE_H +#define __WINE_WINED3D_PRIVATE_H + +#include +#include +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "wined3d_private_types.h" +#include "wine/wined3d_interface.h" +#include "wine/wined3d_caps.h" +#include "wine/wined3d_gl.h" +#include "wine/list.h" + +#define ceilf(x) (float)ceil((double)x) +BOOL WINAPI +DllMain(IN HINSTANCE hinstDLL, + IN DWORD dwReason, + IN LPVOID lpvReserved); + +/* Hash table functions */ +typedef unsigned int (hash_function_t)(void *key); +typedef BOOL (compare_function_t)(void *keya, void *keyb); + +typedef struct { + void *key; + void *value; + unsigned int hash; + struct list entry; +} hash_table_entry_t; + +typedef struct { + hash_function_t *hash_function; + compare_function_t *compare_function; + struct list *buckets; + unsigned int bucket_count; + hash_table_entry_t *entries; + unsigned int entry_count; + struct list free_entries; + unsigned int count; + unsigned int grow_size; + unsigned int shrink_size; +} hash_table_t; + +hash_table_t *hash_table_create(hash_function_t *hash_function, compare_function_t *compare_function); +void hash_table_destroy(hash_table_t *table); +void *hash_table_get(hash_table_t *table, void *key); +void hash_table_put(hash_table_t *table, void *key, void *value); +void hash_table_remove(hash_table_t *table, void *key); + +/* Device caps */ +#define MAX_PALETTES 256 +#define MAX_STREAMS 16 +#define MAX_TEXTURES 8 +#define MAX_FRAGMENT_SAMPLERS 16 +#define MAX_VERTEX_SAMPLERS 4 +#define MAX_COMBINED_SAMPLERS (MAX_FRAGMENT_SAMPLERS + MAX_VERTEX_SAMPLERS) +#define MAX_ACTIVE_LIGHTS 8 +#define MAX_CLIPPLANES WINED3DMAXUSERCLIPPLANES +#define MAX_LEVELS 256 + +#define MAX_CONST_I 16 +#define MAX_CONST_B 16 + +/* Used for CreateStateBlock */ +#define NUM_SAVEDPIXELSTATES_R 35 +#define NUM_SAVEDPIXELSTATES_T 18 +#define NUM_SAVEDPIXELSTATES_S 12 +#define NUM_SAVEDVERTEXSTATES_R 31 +#define NUM_SAVEDVERTEXSTATES_T 2 +#define NUM_SAVEDVERTEXSTATES_S 1 + +extern const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R]; +extern const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T]; +extern const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S]; +extern const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R]; +extern const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T]; +extern const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S]; + +typedef enum _WINELOOKUP { + WINELOOKUP_WARPPARAM = 0, + WINELOOKUP_MAGFILTER = 1, + MAX_LOOKUPS = 2 +} WINELOOKUP; + +extern int minLookup[MAX_LOOKUPS]; +extern int maxLookup[MAX_LOOKUPS]; +extern DWORD *stateLookup[MAX_LOOKUPS]; + +extern DWORD minMipLookup[WINED3DTEXF_ANISOTROPIC + 1][WINED3DTEXF_LINEAR + 1]; + +typedef struct _WINED3DGLTYPE { + int d3dType; + GLint size; + GLenum glType; + GLboolean normalized; + int typesize; +} WINED3DGLTYPE; + +/* NOTE: Make sure these are in the correct numerical order. (see /include/wined3d_types.h) */ +static WINED3DGLTYPE const glTypeLookup[WINED3DDECLTYPE_UNUSED] = { + {WINED3DDECLTYPE_FLOAT1, 1, GL_FLOAT , GL_FALSE ,sizeof(float)}, + {WINED3DDECLTYPE_FLOAT2, 2, GL_FLOAT , GL_FALSE ,sizeof(float)}, + {WINED3DDECLTYPE_FLOAT3, 3, GL_FLOAT , GL_FALSE ,sizeof(float)}, + {WINED3DDECLTYPE_FLOAT4, 4, GL_FLOAT , GL_FALSE ,sizeof(float)}, + {WINED3DDECLTYPE_D3DCOLOR, 4, GL_UNSIGNED_BYTE , GL_TRUE ,sizeof(BYTE)}, + {WINED3DDECLTYPE_UBYTE4, 4, GL_UNSIGNED_BYTE , GL_FALSE ,sizeof(BYTE)}, + {WINED3DDECLTYPE_SHORT2, 2, GL_SHORT , GL_FALSE ,sizeof(short int)}, + {WINED3DDECLTYPE_SHORT4, 4, GL_SHORT , GL_FALSE ,sizeof(short int)}, + {WINED3DDECLTYPE_UBYTE4N, 4, GL_UNSIGNED_BYTE , GL_TRUE ,sizeof(BYTE)}, + {WINED3DDECLTYPE_SHORT2N, 2, GL_SHORT , GL_TRUE ,sizeof(short int)}, + {WINED3DDECLTYPE_SHORT4N, 4, GL_SHORT , GL_TRUE ,sizeof(short int)}, + {WINED3DDECLTYPE_USHORT2N, 2, GL_UNSIGNED_SHORT , GL_TRUE ,sizeof(short int)}, + {WINED3DDECLTYPE_USHORT4N, 4, GL_UNSIGNED_SHORT , GL_TRUE ,sizeof(short int)}, + {WINED3DDECLTYPE_UDEC3, 3, GL_UNSIGNED_SHORT , GL_FALSE ,sizeof(short int)}, + {WINED3DDECLTYPE_DEC3N, 3, GL_SHORT , GL_TRUE ,sizeof(short int)}, + /* We should do an extension check for NV_HALF_FLOAT. However, without NV_HALF_FLOAT + * we won't be able to load the data at all, so at least for the moment it wouldn't + * gain us much. */ + {WINED3DDECLTYPE_FLOAT16_2, 2, GL_HALF_FLOAT_NV , GL_FALSE ,sizeof(GLhalfNV)}, + {WINED3DDECLTYPE_FLOAT16_4, 4, GL_HALF_FLOAT_NV , GL_FALSE ,sizeof(GLhalfNV)}}; + +#define WINED3D_ATR_TYPE(type) glTypeLookup[type].d3dType +#define WINED3D_ATR_SIZE(type) glTypeLookup[type].size +#define WINED3D_ATR_GLTYPE(type) glTypeLookup[type].glType +#define WINED3D_ATR_NORMALIZED(type) glTypeLookup[type].normalized +#define WINED3D_ATR_TYPESIZE(type) glTypeLookup[type].typesize + +/** + * Settings + */ +#define VS_NONE 0 +#define VS_HW 1 + +#define PS_NONE 0 +#define PS_HW 1 + +#define VBO_NONE 0 +#define VBO_HW 1 + +#define NP2_NONE 0 +#define NP2_REPACK 1 +#define NP2_NATIVE 2 + +#define ORM_BACKBUFFER 0 +#define ORM_PBUFFER 1 +#define ORM_FBO 2 + +#define SHADER_ARB 1 +#define SHADER_GLSL 2 +#define SHADER_NONE 3 + +#define RTL_DISABLE -1 +#define RTL_AUTO 0 +#define RTL_READDRAW 1 +#define RTL_READTEX 2 +#define RTL_TEXDRAW 3 +#define RTL_TEXTEX 4 + +/* NOTE: When adding fields to this structure, make sure to update the default + * values in wined3d_main.c as well. */ +typedef struct wined3d_settings_s { +/* vertex and pixel shader modes */ + int vs_mode; + int ps_mode; + int vbo_mode; +/* Ideally, we don't want the user to have to request GLSL. If the hardware supports GLSL, + we should use it. However, until it's fully implemented, we'll leave it as a registry + setting for developers. */ + BOOL glslRequested; + int offscreen_rendering_mode; + int rendertargetlock_mode; +/* Memory tracking and object counting */ + unsigned int emulated_textureram; +} wined3d_settings_t; + +extern wined3d_settings_t wined3d_settings; + +/* Shader backends */ + +typedef struct { + void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS); + void (*shader_select_depth_blt)(IWineD3DDevice *iface); + void (*shader_load_constants)(IWineD3DDevice *iface, char usePS, char useVS); + void (*shader_cleanup)(IWineD3DDevice *iface); +} shader_backend_t; + +extern const shader_backend_t glsl_shader_backend; +extern const shader_backend_t arb_program_shader_backend; +extern const shader_backend_t none_shader_backend; + +/* X11 locking */ + +extern void (*wine_tsx11_lock_ptr)(void); +extern void (*wine_tsx11_unlock_ptr)(void); + +/* As GLX relies on X, this is needed */ +extern int num_lock; + +#if 0 +#define ENTER_GL() ++num_lock; if (num_lock > 1) FIXME("Recursive use of GL lock to: %d\n", num_lock); wine_tsx11_lock_ptr() +#define LEAVE_GL() if (num_lock != 1) FIXME("Recursive use of GL lock: %d\n", num_lock); --num_lock; wine_tsx11_unlock_ptr() +#else +#define ENTER_GL() wine_tsx11_lock_ptr() +#define LEAVE_GL() wine_tsx11_unlock_ptr() +#endif + +/***************************************************************************** + * Defines + */ + +/* GL related defines */ +/* ------------------ */ +#define GL_SUPPORT(ExtName) (GLINFO_LOCATION.supported[ExtName] != 0) +#define GL_LIMITS(ExtName) (GLINFO_LOCATION.max_##ExtName) +#define GL_EXTCALL(FuncName) (GLINFO_LOCATION.FuncName) +#define GL_VEND(_VendName) (GLINFO_LOCATION.gl_vendor == VENDOR_##_VendName ? TRUE : FALSE) + +#define D3DCOLOR_B_R(dw) (((dw) >> 16) & 0xFF) +#define D3DCOLOR_B_G(dw) (((dw) >> 8) & 0xFF) +#define D3DCOLOR_B_B(dw) (((dw) >> 0) & 0xFF) +#define D3DCOLOR_B_A(dw) (((dw) >> 24) & 0xFF) + +#define D3DCOLOR_R(dw) (((float) (((dw) >> 16) & 0xFF)) / 255.0f) +#define D3DCOLOR_G(dw) (((float) (((dw) >> 8) & 0xFF)) / 255.0f) +#define D3DCOLOR_B(dw) (((float) (((dw) >> 0) & 0xFF)) / 255.0f) +#define D3DCOLOR_A(dw) (((float) (((dw) >> 24) & 0xFF)) / 255.0f) + +#define D3DCOLORTOGLFLOAT4(dw, vec) \ + (vec)[0] = D3DCOLOR_R(dw); \ + (vec)[1] = D3DCOLOR_G(dw); \ + (vec)[2] = D3DCOLOR_B(dw); \ + (vec)[3] = D3DCOLOR_A(dw); + +/* DirectX Device Limits */ +/* --------------------- */ +#define MAX_LEVELS 256 /* Maximum number of mipmap levels. Guessed at 256 */ + +#define MAX_STREAMS 16 /* Maximum possible streams - used for fixed size arrays + See MaxStreams in MSDN under GetDeviceCaps */ + /* Maximum number of constants provided to the shaders */ +#define HIGHEST_TRANSFORMSTATE 512 + /* Highest value in WINED3DTRANSFORMSTATETYPE */ +#define MAX_PALETTES 256 + +/* Checking of API calls */ +/* --------------------- */ +#define checkGLcall(A) \ +{ \ + GLint err = glGetError(); \ + if (err == GL_NO_ERROR) { \ + TRACE("%s call ok %s / %d\n", A, __FILE__, __LINE__); \ + \ + } else do { \ + FIXME(">>>>>>>>>>>>>>>>> %s (%#x) from %s @ %s / %d\n", \ + debug_glerror(err), err, A, __FILE__, __LINE__); \ + err = glGetError(); \ + } while (err != GL_NO_ERROR); \ +} + +/* Trace routines / diagnostics */ +/* ---------------------------- */ + +/* Dump out a matrix and copy it */ +#define conv_mat(mat,gl_mat) \ +do { \ + TRACE("%f %f %f %f\n", (mat)->u.s._11, (mat)->u.s._12, (mat)->u.s._13, (mat)->u.s._14); \ + TRACE("%f %f %f %f\n", (mat)->u.s._21, (mat)->u.s._22, (mat)->u.s._23, (mat)->u.s._24); \ + TRACE("%f %f %f %f\n", (mat)->u.s._31, (mat)->u.s._32, (mat)->u.s._33, (mat)->u.s._34); \ + TRACE("%f %f %f %f\n", (mat)->u.s._41, (mat)->u.s._42, (mat)->u.s._43, (mat)->u.s._44); \ + memcpy(gl_mat, (mat), 16 * sizeof(float)); \ +} while (0) + +/* Macro to dump out the current state of the light chain */ +#define DUMP_LIGHT_CHAIN() \ +{ \ + PLIGHTINFOEL *el = This->stateBlock->lights;\ + while (el) { \ + TRACE("Light %p (glIndex %ld, d3dIndex %ld, enabled %d)\n", el, el->glIndex, el->OriginalIndex, el->lightEnabled);\ + el = el->next; \ + } \ +} + +/* Trace vector and strided data information */ +#define TRACE_VECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w); +#define TRACE_STRIDED(sd,name) TRACE( #name "=(data:%p, stride:%d, type:%d, vbo %d, stream %u)\n", \ + sd->u.s.name.lpData, sd->u.s.name.dwStride, sd->u.s.name.dwType, sd->u.s.name.VBO, sd->u.s.name.streamNo); + +/* Defines used for optimizations */ + +/* Only reapply what is necessary */ +#define REAPPLY_ALPHAOP 0x0001 +#define REAPPLY_ALL 0xFFFF + +/* Advance declaration of structures to satisfy compiler */ +typedef struct IWineD3DStateBlockImpl IWineD3DStateBlockImpl; +typedef struct IWineD3DSurfaceImpl IWineD3DSurfaceImpl; +typedef struct IWineD3DPaletteImpl IWineD3DPaletteImpl; +typedef struct IWineD3DDeviceImpl IWineD3DDeviceImpl; + +/* Tracking */ + +/* TODO: Move some of this to the device */ +long globalChangeGlRam(long glram); + +/* Memory and object tracking */ + +/*Structure for holding information on all direct3d objects +useful for making sure tracking is ok and when release is called on a device! +and probably quite handy for debugging and dumping states out +*/ +typedef struct WineD3DGlobalStatistics { + int glsurfaceram; /* The aproximate amount of glTexture memory allocated for textures */ +} WineD3DGlobalStatistics; + +extern WineD3DGlobalStatistics* wineD3DGlobalStatistics; + +/* Global variables */ +extern const float identity[16]; + +/***************************************************************************** + * Compilable extra diagnostics + */ + +/* Trace information per-vertex: (extremely high amount of trace) */ +#if 0 /* NOTE: Must be 0 in cvs */ +# define VTRACE(A) TRACE A +#else +# define VTRACE(A) +#endif + +/* Checking of per-vertex related GL calls */ +/* --------------------- */ +#define vcheckGLcall(A) \ +{ \ + GLint err = glGetError(); \ + if (err == GL_NO_ERROR) { \ + VTRACE(("%s call ok %s / %d\n", A, __FILE__, __LINE__)); \ + \ + } else do { \ + FIXME(">>>>>>>>>>>>>>>>> %s (%#x) from %s @ %s / %d\n", \ + debug_glerror(err), err, A, __FILE__, __LINE__); \ + err = glGetError(); \ + } while (err != GL_NO_ERROR); \ +} + +/* TODO: Confirm each of these works when wined3d move completed */ +#if 0 /* NOTE: Must be 0 in cvs */ + /* To avoid having to get gigabytes of trace, the following can be compiled in, and at the start + of each frame, a check is made for the existence of C:\D3DTRACE, and if it exists d3d trace + is enabled, and if it doesn't exist it is disabled. */ +# define FRAME_DEBUGGING + /* Adding in the SINGLE_FRAME_DEBUGGING gives a trace of just what makes up a single frame, before + the file is deleted */ +# if 1 /* NOTE: Must be 1 in cvs, as this is mostly more useful than a trace from program start */ +# define SINGLE_FRAME_DEBUGGING +# endif + /* The following, when enabled, lets you see the makeup of the frame, by drawprimitive calls. + It can only be enabled when FRAME_DEBUGGING is also enabled + The contents of the back buffer are written into /tmp/backbuffer_* after each primitive + array is drawn. */ +# if 0 /* NOTE: Must be 0 in cvs, as this give a lot of ppm files when compiled in */ +# define SHOW_FRAME_MAKEUP 1 +# endif + /* The following, when enabled, lets you see the makeup of the all the textures used during each + of the drawprimitive calls. It can only be enabled when SHOW_FRAME_MAKEUP is also enabled. + The contents of the textures assigned to each stage are written into + /tmp/texture_*_.ppm after each primitive array is drawn. */ +# if 0 /* NOTE: Must be 0 in cvs, as this give a lot of ppm files when compiled in */ +# define SHOW_TEXTURE_MAKEUP 0 +# endif +extern BOOL isOn; +extern BOOL isDumpingFrames; +extern LONG primCounter; +#endif + +/***************************************************************************** + * Prototypes + */ + +/* Routine common to the draw primitive and draw indexed primitive routines */ +void drawPrimitive(IWineD3DDevice *iface, + int PrimitiveType, + long NumPrimitives, + /* for Indexed: */ + long StartVertexIndex, + UINT numberOfVertices, + long StartIdx, + short idxBytes, + const void *idxData, + int minIndex); + +void primitiveDeclarationConvertToStridedData( + IWineD3DDevice *iface, + BOOL useVertexShaderFunction, + WineDirect3DVertexStridedData *strided, + BOOL *fixup); + +DWORD get_flexible_vertex_size(DWORD d3dvtVertexType); + +void blt_to_drawable(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *surface); + +#define eps 1e-8 + +#define GET_TEXCOORD_SIZE_FROM_FVF(d3dvtVertexType, tex_num) \ + (((((d3dvtVertexType) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1) + +/* Routines and structures related to state management */ +typedef struct WineD3DContext WineD3DContext; +typedef void (*APPLYSTATEFUNC)(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *ctx); + +#define STATE_RENDER(a) (a) +#define STATE_IS_RENDER(a) ((a) >= STATE_RENDER(1) && (a) <= STATE_RENDER(WINEHIGHEST_RENDER_STATE)) + +#define STATE_TEXTURESTAGE(stage, num) (STATE_RENDER(WINEHIGHEST_RENDER_STATE) + (stage) * WINED3D_HIGHEST_TEXTURE_STATE + (num)) +#define STATE_IS_TEXTURESTAGE(a) ((a) >= STATE_TEXTURESTAGE(0, 1) && (a) <= STATE_TEXTURESTAGE(MAX_TEXTURES - 1, WINED3D_HIGHEST_TEXTURE_STATE)) + +/* + 1 because samplers start with 0 */ +#define STATE_SAMPLER(num) (STATE_TEXTURESTAGE(MAX_TEXTURES - 1, WINED3D_HIGHEST_TEXTURE_STATE) + 1 + (num)) +#define STATE_IS_SAMPLER(num) ((num) >= STATE_SAMPLER(0) && (num) <= STATE_SAMPLER(MAX_COMBINED_SAMPLERS - 1)) + +#define STATE_PIXELSHADER (STATE_SAMPLER(MAX_COMBINED_SAMPLERS - 1) + 1) +#define STATE_IS_PIXELSHADER(a) ((a) == STATE_PIXELSHADER) + +#define STATE_TRANSFORM(a) (STATE_PIXELSHADER + (a)) +#define STATE_IS_TRANSFORM(a) ((a) >= STATE_TRANSFORM(1) && (a) <= STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(255))) + +#define STATE_STREAMSRC (STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(255)) + 1) +#define STATE_IS_STREAMSRC(a) ((a) == STATE_STREAMSRC) +#define STATE_INDEXBUFFER (STATE_STREAMSRC + 1) +#define STATE_IS_INDEXBUFFER(a) ((a) == STATE_INDEXBUFFER) + +#define STATE_VDECL (STATE_INDEXBUFFER + 1) +#define STATE_IS_VDECL(a) ((a) == STATE_VDECL) + +#define STATE_VSHADER (STATE_VDECL + 1) +#define STATE_IS_VSHADER(a) ((a) == STATE_VSHADER) + +#define STATE_VIEWPORT (STATE_VSHADER + 1) +#define STATE_IS_VIEWPORT(a) ((a) == STATE_VIEWPORT) + +#define STATE_VERTEXSHADERCONSTANT (STATE_VIEWPORT + 1) +#define STATE_PIXELSHADERCONSTANT (STATE_VERTEXSHADERCONSTANT + 1) +#define STATE_IS_VERTEXSHADERCONSTANT(a) ((a) == STATE_VERTEXSHADERCONSTANT) +#define STATE_IS_PIXELSHADERCONSTANT(a) ((a) == STATE_PIXELSHADERCONSTANT) + +#define STATE_ACTIVELIGHT(a) (STATE_PIXELSHADERCONSTANT + (a) + 1) +#define STATE_IS_ACTIVELIGHT(a) ((a) >= STATE_ACTIVELIGHT(0) && (a) < STATE_ACTIVELIGHT(MAX_ACTIVE_LIGHTS)) + +#define STATE_SCISSORRECT (STATE_ACTIVELIGHT(MAX_ACTIVE_LIGHTS - 1) + 1) +#define STATE_IS_SCISSORRECT(a) ((a) == STATE_SCISSORRECT) + +#define STATE_CLIPPLANE(a) (STATE_SCISSORRECT + 1 + (a)) +#define STATE_IS_CLIPPLANE(a) ((a) >= STATE_CLIPPLANE(0) && (a) <= STATE_CLIPPLANE(MAX_CLIPPLANES - 1)) + +#define STATE_MATERIAL (STATE_CLIPPLANE(MAX_CLIPPLANES)) + +#define STATE_HIGHEST (STATE_MATERIAL) + +struct StateEntry +{ + DWORD representative; + APPLYSTATEFUNC apply; +}; + +/* Global state table */ +extern const struct StateEntry StateTable[]; + +/* The new context manager that should deal with onscreen and offscreen rendering */ +struct WineD3DContext { + /* State dirtification + * dirtyArray is an array that contains markers for dirty states. numDirtyEntries states are dirty, their numbers are in indices + * 0...numDirtyEntries - 1. isStateDirty is a redundant copy of the dirtyArray. Technically only one of them would be needed, + * but with the help of both it is easy to find out if a state is dirty(just check the array index), and for applying dirty states + * only numDirtyEntries array elements have to be checked, not STATE_HIGHEST states. + */ + DWORD dirtyArray[STATE_HIGHEST + 1]; /* Won't get bigger than that, a state is never marked dirty 2 times */ + DWORD numDirtyEntries; + DWORD isStateDirty[STATE_HIGHEST/32 + 1]; /* Bitmap to find out quickly if a state is dirty */ + + IWineD3DSurface *surface; + DWORD tid; /* Thread ID which owns this context at the moment */ + + /* Stores some inforation about the context state for optimization */ + BOOL last_was_rhw; /* true iff last draw_primitive was in xyzrhw mode */ + BOOL last_was_pshader; + BOOL last_was_vshader; + BOOL last_was_foggy_shader; + BOOL namedArraysLoaded, numberedArraysLoaded; + BOOL lastWasPow2Texture[MAX_TEXTURES]; + GLenum tracking_parm; /* Which source is tracking current colour */ + unsigned char num_untracked_materials; + GLenum untracked_materials[2]; + BOOL last_was_blit, last_was_ckey; + char texShaderBumpMap; + + /* The actual opengl context */ + HGLRC glCtx; + HWND win_handle; + HDC hdc; + HPBUFFERARB pbuffer; + BOOL isPBuffer; +}; + +typedef enum ContextUsage { + CTXUSAGE_RESOURCELOAD = 1, /* Only loads textures: No State is applied */ + CTXUSAGE_DRAWPRIM = 2, /* OpenGL states are set up for blitting DirectDraw surfacs */ + CTXUSAGE_BLIT = 3, /* OpenGL states are set up 3D drawing */ + CTXUSAGE_CLEAR = 4, /* Drawable and states are set up for clearing */ +} ContextUsage; + +void ActivateContext(IWineD3DDeviceImpl *device, IWineD3DSurface *target, ContextUsage usage); +WineD3DContext *CreateContext(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, HWND win, BOOL create_pbuffer, const WINED3DPRESENT_PARAMETERS *pPresentParms); +void DestroyContext(IWineD3DDeviceImpl *This, WineD3DContext *context); +void apply_fbo_state(IWineD3DDevice *iface); + +/* Macros for doing basic GPU detection based on opengl capabilities */ +#define WINE_D3D6_CAPABLE(gl_info) (gl_info->supported[ARB_MULTITEXTURE]) +#define WINE_D3D7_CAPABLE(gl_info) (gl_info->supported[ARB_TEXTURE_COMPRESSION] && gl_info->supported[ARB_TEXTURE_CUBE_MAP] && gl_info->supported[ARB_TEXTURE_ENV_DOT3]) +#define WINE_D3D8_CAPABLE(gl_info) WINE_D3D7_CAPABLE(gl_info) && (gl_info->supported[ARB_MULTISAMPLE] && gl_info->supported[ARB_TEXTURE_BORDER_CLAMP]) +#define WINE_D3D9_CAPABLE(gl_info) WINE_D3D8_CAPABLE(gl_info) && (gl_info->supported[ARB_FRAGMENT_PROGRAM] && gl_info->supported[ARB_VERTEX_SHADER]) + +/* Default callbacks for implicit object destruction */ +extern ULONG WINAPI D3DCB_DefaultDestroySurface(IWineD3DSurface *pSurface); + +extern ULONG WINAPI D3DCB_DefaultDestroyVolume(IWineD3DVolume *pSurface); + +/***************************************************************************** + * Internal representation of a light + */ +typedef struct PLIGHTINFOEL PLIGHTINFOEL; +struct PLIGHTINFOEL { + WINED3DLIGHT OriginalParms; /* Note D3D8LIGHT == D3D9LIGHT */ + DWORD OriginalIndex; + LONG glIndex; + BOOL changed; + BOOL enabledChanged; + + /* Converted parms to speed up swapping lights */ + float lightPosn[4]; + float lightDirn[4]; + float exponent; + float cutoff; + + struct list entry; +}; + +/* The default light parameters */ +extern const WINED3DLIGHT WINED3D_default_light; + +typedef struct WineD3D_PixelFormat +{ + int iPixelFormat; /* WGL pixel format */ + int redSize, greenSize, blueSize, alphaSize; + int depthSize, stencilSize; +} WineD3D_PixelFormat; + +/* The adapter structure */ +typedef struct GLPixelFormatDesc GLPixelFormatDesc; +struct WineD3DAdapter +{ + POINT monitorPoint; + WineD3D_GL_Info gl_info; + const char *driver; + const char *description; + WCHAR DeviceName[CCHDEVICENAME]; /* DeviceName for use with e.g. ChangeDisplaySettings */ + int nCfgs; + WineD3D_PixelFormat *cfgs; +}; + +extern BOOL InitAdapters(void); +extern BOOL initPixelFormats(WineD3D_GL_Info *gl_info); + +/***************************************************************************** + * High order patch management + */ +struct WineD3DRectPatch +{ + UINT Handle; + float *mem; + WineDirect3DVertexStridedData strided; + WINED3DRECTPATCH_INFO RectPatchInfo; + float numSegs[4]; + char has_normals, has_texcoords; + struct list entry; +}; + +HRESULT tesselate_rectpatch(IWineD3DDeviceImpl *This, struct WineD3DRectPatch *patch); + +/***************************************************************************** + * IWineD3D implementation structure + */ +typedef struct IWineD3DImpl +{ + /* IUnknown fields */ + const IWineD3DVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + /* WineD3D Information */ + IUnknown *parent; + UINT dxVersion; +} IWineD3DImpl; + +extern const IWineD3DVtbl IWineD3D_Vtbl; + +/* TODO: setup some flags in the registry to enable, disable pbuffer support +(since it will break quite a few things until contexts are managed properly!) */ +extern BOOL pbuffer_support; +/* allocate one pbuffer per surface */ +extern BOOL pbuffer_per_surface; + +typedef struct ResourceList { + IWineD3DResource *resource; + struct ResourceList *next; +} ResourceList; + +/* A helper function that dumps a resource list */ +void dumpResources(ResourceList *resources); + +/***************************************************************************** + * IWineD3DDevice implementation structure + */ +struct IWineD3DDeviceImpl +{ + /* IUnknown fields */ + const IWineD3DDeviceVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + /* WineD3D Information */ + IUnknown *parent; + IWineD3D *wineD3D; + struct WineD3DAdapter *adapter; + + /* Window styles to restore when switching fullscreen mode */ + LONG style; + LONG exStyle; + + /* X and GL Information */ + GLint maxConcurrentLights; + GLenum offscreenBuffer; + + /* Selected capabilities */ + int vs_selected_mode; + int ps_selected_mode; + const shader_backend_t *shader_backend; + hash_table_t *glsl_program_lookup; + + /* To store */ + BOOL view_ident; /* true iff view matrix is identity */ + BOOL untransformed; + BOOL vertexBlendUsed; /* To avoid needless setting of the blend matrices */ + unsigned char surface_alignment; /* Line Alignment of surfaces */ + + /* State block related */ + BOOL isRecordingState; + IWineD3DStateBlockImpl *stateBlock; + IWineD3DStateBlockImpl *updateStateBlock; + BOOL isInDraw; + + /* Internal use fields */ + WINED3DDEVICE_CREATION_PARAMETERS createParms; + UINT adapterNo; + WINED3DDEVTYPE devType; + + IWineD3DSwapChain **swapchains; + UINT NumberOfSwapChains; + + ResourceList *resources; /* a linked list to track resources created by the device */ + + /* Render Target Support */ + IWineD3DSurface **render_targets; + IWineD3DSurface *depthStencilBuffer; + IWineD3DSurface **fbo_color_attachments; + IWineD3DSurface *fbo_depth_attachment; + + IWineD3DSurface *stencilBufferTarget; + + /* Caches to avoid unneeded context changes */ + IWineD3DSurface *lastActiveRenderTarget; + IWineD3DSwapChain *lastActiveSwapChain; + + /* palettes texture management */ + PALETTEENTRY palettes[MAX_PALETTES][256]; + UINT currentPalette; + + /* For rendering to a texture using glCopyTexImage */ + BOOL render_offscreen; + WINED3D_DEPTHCOPYSTATE depth_copy_state; + GLuint fbo; + GLuint src_fbo; + GLuint dst_fbo; + GLenum *draw_buffers; + + /* Cursor management */ + BOOL bCursorVisible; + UINT xHotSpot; + UINT yHotSpot; + UINT xScreenSpace; + UINT yScreenSpace; + UINT cursorWidth, cursorHeight; + GLuint cursorTexture; + BOOL haveHardwareCursor; + HCURSOR hardwareCursor; + + /* Textures for when no other textures are mapped */ + UINT dummyTextureName[MAX_TEXTURES]; + + /* Debug stream management */ + BOOL debug; + + /* Device state management */ + HRESULT state; + BOOL d3d_initialized; + + /* A flag to check for proper BeginScene / EndScene call pairs */ + BOOL inScene; + + /* process vertex shaders using software or hardware */ + BOOL softwareVertexProcessing; + + /* DirectDraw stuff */ + HWND ddraw_window; + IWineD3DSurface *ddraw_primary; + DWORD ddraw_width, ddraw_height; + WINED3DFORMAT ddraw_format; + BOOL ddraw_fullscreen; + + /* Final position fixup constant */ + float posFixup[4]; + + /* With register combiners we can skip junk texture stages */ + DWORD texUnitMap[MAX_COMBINED_SAMPLERS]; + DWORD rev_tex_unit_map[MAX_COMBINED_SAMPLERS]; + BOOL fixed_function_usage_map[MAX_TEXTURES]; + + /* Stream source management */ + WineDirect3DVertexStridedData strided_streams; + WineDirect3DVertexStridedData *up_strided; + BOOL useDrawStridedSlow; + BOOL instancedDraw; + + /* Context management */ + WineD3DContext **contexts; /* Dynamic array containing pointers to context structures */ + WineD3DContext *activeContext; + DWORD lastThread; + UINT numContexts; + WineD3DContext *pbufferContext; /* The context that has a pbuffer as drawable */ + DWORD pbufferWidth, pbufferHeight; /* Size of the buffer drawable */ + + /* High level patch management */ +#define PATCHMAP_SIZE 43 +#define PATCHMAP_HASHFUNC(x) ((x) % PATCHMAP_SIZE) /* Primitive and simple function */ + struct list patches[PATCHMAP_SIZE]; + struct WineD3DRectPatch *currentPatch; +}; + +extern const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl; + +void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This); +void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state); +static inline BOOL isStateDirty(WineD3DContext *context, DWORD state) { + DWORD idx = state >> 5; + BYTE shift = state & 0x1f; + return context->isStateDirty[idx] & (1 << shift); +} + +/* Support for IWineD3DResource ::Set/Get/FreePrivateData. */ +typedef struct PrivateData +{ + struct list entry; + + GUID tag; + DWORD flags; /* DDSPD_* */ + DWORD uniqueness_value; + + union + { + LPVOID data; + LPUNKNOWN object; + } ptr; + + DWORD size; +} PrivateData; + +/***************************************************************************** + * IWineD3DResource implementation structure + */ +typedef struct IWineD3DResourceClass +{ + /* IUnknown fields */ + LONG ref; /* Note: Ref counting not required */ + + /* WineD3DResource Information */ + IUnknown *parent; + WINED3DRESOURCETYPE resourceType; + IWineD3DDeviceImpl *wineD3DDevice; + WINED3DPOOL pool; + UINT size; + DWORD usage; + WINED3DFORMAT format; + BYTE *allocatedMemory; + struct list privateData; + +} IWineD3DResourceClass; + +typedef struct IWineD3DResourceImpl +{ + /* IUnknown & WineD3DResource Information */ + const IWineD3DResourceVtbl *lpVtbl; + IWineD3DResourceClass resource; +} IWineD3DResourceImpl; + + +/***************************************************************************** + * IWineD3DVertexBuffer implementation structure (extends IWineD3DResourceImpl) + */ +typedef struct IWineD3DVertexBufferImpl +{ + /* IUnknown & WineD3DResource Information */ + const IWineD3DVertexBufferVtbl *lpVtbl; + IWineD3DResourceClass resource; + + /* WineD3DVertexBuffer specifics */ + DWORD fvf; + + /* Vertex buffer object support */ + GLuint vbo; + BYTE Flags; + LONG bindCount; + + UINT dirtystart, dirtyend; + LONG lockcount; + + LONG declChanges, draws; + /* Last description of the buffer */ + WineDirect3DVertexStridedData strided; +} IWineD3DVertexBufferImpl; + +extern const IWineD3DVertexBufferVtbl IWineD3DVertexBuffer_Vtbl; + +#define VBFLAG_LOAD 0x01 /* Data is written from allocatedMemory to the VBO */ +#define VBFLAG_OPTIMIZED 0x02 /* Optimize has been called for the VB */ +#define VBFLAG_DIRTY 0x04 /* Buffer data has been modified */ +#define VBFLAG_HASDESC 0x08 /* A vertex description has been found */ +#define VBFLAG_VBOCREATEFAIL 0x10 /* An attempt to create a vbo has failed */ + +/***************************************************************************** + * IWineD3DIndexBuffer implementation structure (extends IWineD3DResourceImpl) + */ +typedef struct IWineD3DIndexBufferImpl +{ + /* IUnknown & WineD3DResource Information */ + const IWineD3DIndexBufferVtbl *lpVtbl; + IWineD3DResourceClass resource; + + GLuint vbo; + UINT dirtystart, dirtyend; + LONG lockcount; + + /* WineD3DVertexBuffer specifics */ +} IWineD3DIndexBufferImpl; + +extern const IWineD3DIndexBufferVtbl IWineD3DIndexBuffer_Vtbl; + +/***************************************************************************** + * IWineD3DBaseTexture D3D- > openGL state map lookups + */ +#define WINED3DFUNC_NOTSUPPORTED -2 +#define WINED3DFUNC_UNIMPLEMENTED -1 + +typedef enum winetexturestates { + WINED3DTEXSTA_ADDRESSU = 0, + WINED3DTEXSTA_ADDRESSV = 1, + WINED3DTEXSTA_ADDRESSW = 2, + WINED3DTEXSTA_BORDERCOLOR = 3, + WINED3DTEXSTA_MAGFILTER = 4, + WINED3DTEXSTA_MINFILTER = 5, + WINED3DTEXSTA_MIPFILTER = 6, + WINED3DTEXSTA_MAXMIPLEVEL = 7, + WINED3DTEXSTA_MAXANISOTROPY = 8, + WINED3DTEXSTA_SRGBTEXTURE = 9, + WINED3DTEXSTA_ELEMENTINDEX = 10, + WINED3DTEXSTA_DMAPOFFSET = 11, + WINED3DTEXSTA_TSSADDRESSW = 12, + MAX_WINETEXTURESTATES = 13, +} winetexturestates; + +/***************************************************************************** + * IWineD3DBaseTexture implementation structure (extends IWineD3DResourceImpl) + */ +typedef struct IWineD3DBaseTextureClass +{ + UINT levels; + BOOL dirty; + UINT textureName; + UINT LOD; + WINED3DTEXTUREFILTERTYPE filterType; + DWORD states[MAX_WINETEXTURESTATES]; + LONG bindCount; + DWORD sampler; + BOOL is_srgb; + UINT srgb_mode_change_count; +} IWineD3DBaseTextureClass; + +typedef struct IWineD3DBaseTextureImpl +{ + /* IUnknown & WineD3DResource Information */ + const IWineD3DBaseTextureVtbl *lpVtbl; + IWineD3DResourceClass resource; + IWineD3DBaseTextureClass baseTexture; + +} IWineD3DBaseTextureImpl; + +/***************************************************************************** + * IWineD3DTexture implementation structure (extends IWineD3DBaseTextureImpl) + */ +typedef struct IWineD3DTextureImpl +{ + /* IUnknown & WineD3DResource/WineD3DBaseTexture Information */ + const IWineD3DTextureVtbl *lpVtbl; + IWineD3DResourceClass resource; + IWineD3DBaseTextureClass baseTexture; + + /* IWineD3DTexture */ + IWineD3DSurface *surfaces[MAX_LEVELS]; + + UINT width; + UINT height; + float pow2scalingFactorX; + float pow2scalingFactorY; + +} IWineD3DTextureImpl; + +extern const IWineD3DTextureVtbl IWineD3DTexture_Vtbl; + +/***************************************************************************** + * IWineD3DCubeTexture implementation structure (extends IWineD3DBaseTextureImpl) + */ +typedef struct IWineD3DCubeTextureImpl +{ + /* IUnknown & WineD3DResource/WineD3DBaseTexture Information */ + const IWineD3DCubeTextureVtbl *lpVtbl; + IWineD3DResourceClass resource; + IWineD3DBaseTextureClass baseTexture; + + /* IWineD3DCubeTexture */ + IWineD3DSurface *surfaces[6][MAX_LEVELS]; + + UINT edgeLength; + float pow2scalingFactor; + +} IWineD3DCubeTextureImpl; + +extern const IWineD3DCubeTextureVtbl IWineD3DCubeTexture_Vtbl; + +typedef struct _WINED3DVOLUMET_DESC +{ + UINT Width; + UINT Height; + UINT Depth; +} WINED3DVOLUMET_DESC; + +/***************************************************************************** + * IWineD3DVolume implementation structure (extends IUnknown) + */ +typedef struct IWineD3DVolumeImpl +{ + /* IUnknown & WineD3DResource fields */ + const IWineD3DVolumeVtbl *lpVtbl; + IWineD3DResourceClass resource; + + /* WineD3DVolume Information */ + WINED3DVOLUMET_DESC currentDesc; + IWineD3DBase *container; + UINT bytesPerPixel; + + BOOL lockable; + BOOL locked; + WINED3DBOX lockedBox; + WINED3DBOX dirtyBox; + BOOL dirty; + + +} IWineD3DVolumeImpl; + +extern const IWineD3DVolumeVtbl IWineD3DVolume_Vtbl; + +/***************************************************************************** + * IWineD3DVolumeTexture implementation structure (extends IWineD3DBaseTextureImpl) + */ +typedef struct IWineD3DVolumeTextureImpl +{ + /* IUnknown & WineD3DResource/WineD3DBaseTexture Information */ + const IWineD3DVolumeTextureVtbl *lpVtbl; + IWineD3DResourceClass resource; + IWineD3DBaseTextureClass baseTexture; + + /* IWineD3DVolumeTexture */ + IWineD3DVolume *volumes[MAX_LEVELS]; + + UINT width; + UINT height; + UINT depth; +} IWineD3DVolumeTextureImpl; + +extern const IWineD3DVolumeTextureVtbl IWineD3DVolumeTexture_Vtbl; + +typedef struct _WINED3DSURFACET_DESC +{ + WINED3DMULTISAMPLE_TYPE MultiSampleType; + DWORD MultiSampleQuality; + UINT Width; + UINT Height; +} WINED3DSURFACET_DESC; + +/***************************************************************************** + * Structure for DIB Surfaces (GetDC and GDI surfaces) + */ +typedef struct wineD3DSurface_DIB { + HBITMAP DIBsection; + void* bitmap_data; + HGDIOBJ holdbitmap; + BOOL client_memory; +} wineD3DSurface_DIB; + +typedef struct { + struct list entry; + GLuint id; + UINT width; + UINT height; +} renderbuffer_entry_t; + +/***************************************************************************** + * IWineD3DClipp implementation structure + */ +typedef struct IWineD3DClipperImpl +{ + const IWineD3DClipperVtbl *lpVtbl; + LONG ref; + + IUnknown *Parent; + HWND hWnd; +} IWineD3DClipperImpl; + + +/***************************************************************************** + * IWineD3DSurface implementation structure + */ +struct IWineD3DSurfaceImpl +{ + /* IUnknown & IWineD3DResource Information */ + const IWineD3DSurfaceVtbl *lpVtbl; + IWineD3DResourceClass resource; + + /* IWineD3DSurface fields */ + IWineD3DBase *container; + WINED3DSURFACET_DESC currentDesc; + IWineD3DPaletteImpl *palette; /* D3D7 style palette handling */ + PALETTEENTRY *palette9; /* D3D8/9 style palette handling */ + + UINT bytesPerPixel; + + /* TODO: move this off into a management class(maybe!) */ + DWORD Flags; + + UINT pow2Width; + UINT pow2Height; + + /* Oversized texture */ + RECT glRect; + +#if 0 + /* precalculated x and y scalings for texture coords */ + float pow2scalingFactorX; /* = (Width / pow2Width ) */ + float pow2scalingFactorY; /* = (Height / pow2Height) */ +#endif + + RECT lockedRect; + RECT dirtyRect; + int lockCount; +#define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy */ + + glDescriptor glDescription; + + /* For GetDC */ + wineD3DSurface_DIB dib; + HDC hDC; + + /* Color keys for DDraw */ + WINEDDCOLORKEY DestBltCKey; + WINEDDCOLORKEY DestOverlayCKey; + WINEDDCOLORKEY SrcOverlayCKey; + WINEDDCOLORKEY SrcBltCKey; + DWORD CKeyFlags; + + WINEDDCOLORKEY glCKey; + + struct list renderbuffers; + renderbuffer_entry_t *current_renderbuffer; + + /* DirectDraw clippers */ + IWineD3DClipper *clipper; +}; + +extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl; +extern const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl; + +/* Predeclare the shared Surface functions */ +HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj); +ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface); +ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent); +HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice); +HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags); +HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData); +HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid); +DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew); +DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface); +void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface); +WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer); +HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc); +HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags); +HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags); +HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_SetPixelFormat(IWineD3DSurface *iface, WINED3DFORMAT Format, BYTE *Surface, DWORD Size); +HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal); +HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal); +HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey); +HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface); +extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect); +HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container); +void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target); +void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription); +const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format); +HRESULT WINAPI IWineGDISurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter); +HRESULT WINAPI IWineGDISurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans); +HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal); +HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC); +HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC); +DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface); +HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem); +HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y); +HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y); +HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref); +HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX); +HRESULT WINAPI IWineD3DSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper); +HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper); + +/* Surface flags: */ +#define SFLAG_OVERSIZE 0x00000001 /* Surface is bigger than gl size, blts only */ +#define SFLAG_CONVERTED 0x00000002 /* Converted for color keying or Palettized */ +#define SFLAG_DIBSECTION 0x00000004 /* Has a DIB section attached for getdc */ +#define SFLAG_LOCKABLE 0x00000008 /* Surface can be locked */ +#define SFLAG_DISCARD 0x00000010 /* ??? */ +#define SFLAG_LOCKED 0x00000020 /* Surface is locked atm */ +#define SFLAG_INTEXTURE 0x00000040 /* The GL texture contains the newest surface content */ +#define SFLAG_INDRAWABLE 0x00000080 /* The gl drawable contains the most up to date data */ +#define SFLAG_INSYSMEM 0x00000100 /* The system memory copy is most up to date */ +#define SFLAG_NONPOW2 0x00000200 /* Surface sizes are not a power of 2 */ +#define SFLAG_DYNLOCK 0x00000400 /* Surface is often locked by the app */ +#define SFLAG_DYNCHANGE 0x00000C00 /* Surface contents are changed very often, implies DYNLOCK */ +#define SFLAG_DCINUSE 0x00001000 /* Set between GetDC and ReleaseDC calls */ +#define SFLAG_LOST 0x00002000 /* Surface lost flag for DDraw */ +#define SFLAG_USERPTR 0x00004000 /* The application allocated the memory for this surface */ +#define SFLAG_GLCKEY 0x00008000 /* The gl texture was created with a color key */ +#define SFLAG_CLIENT 0x00010000 /* GL_APPLE_client_storage is used on that texture */ +#define SFLAG_ALLOCATED 0x00020000 /* A gl texture is allocated for this surface */ + +/* In some conditions the surface memory must not be freed: + * SFLAG_OVERSIZE: Not all data can be kept in GL + * SFLAG_CONVERTED: Converting the data back would take too long + * SFLAG_DIBSECTION: The dib code manages the memory + * SFLAG_LOCKED: The app requires access to the surface data + * SFLAG_DYNLOCK: Avoid freeing the data for performance + * SFLAG_DYNCHANGE: Same reason as DYNLOCK + * SFLAG_CLIENT: OpenGL uses our memory as backup + */ +#define SFLAG_DONOTFREE (SFLAG_OVERSIZE | \ + SFLAG_CONVERTED | \ + SFLAG_DIBSECTION | \ + SFLAG_LOCKED | \ + SFLAG_DYNLOCK | \ + SFLAG_DYNCHANGE | \ + SFLAG_USERPTR | \ + SFLAG_CLIENT) + +BOOL CalculateTexRect(IWineD3DSurfaceImpl *This, RECT *Rect, float glTexCoord[4]); + +typedef enum { + NO_CONVERSION, + CONVERT_PALETTED, + CONVERT_PALETTED_CK, + CONVERT_CK_565, + CONVERT_CK_5551, + CONVERT_CK_4444, + CONVERT_CK_4444_ARGB, + CONVERT_CK_1555, + CONVERT_555, + CONVERT_CK_RGB24, + CONVERT_CK_8888, + CONVERT_CK_8888_ARGB, + CONVERT_RGB32_888, + CONVERT_V8U8, + CONVERT_X8L8V8U8, + CONVERT_Q8W8V8U8, + CONVERT_V16U16, + CONVERT_A4L4, + CONVERT_R32F, + CONVERT_R16F +} CONVERT_TYPES; + +HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp, BOOL srgb_mode); + +/***************************************************************************** + * IWineD3DVertexDeclaration implementation structure + */ +typedef struct IWineD3DVertexDeclarationImpl { + /* IUnknown Information */ + const IWineD3DVertexDeclarationVtbl *lpVtbl; + LONG ref; + + IUnknown *parent; + IWineD3DDeviceImpl *wineD3DDevice; + + WINED3DVERTEXELEMENT *pDeclarationWine; + UINT declarationWNumElements; + + DWORD streams[MAX_STREAMS]; + UINT num_streams; + BOOL position_transformed; +} IWineD3DVertexDeclarationImpl; + +extern const IWineD3DVertexDeclarationVtbl IWineD3DVertexDeclaration_Vtbl; + +/***************************************************************************** + * IWineD3DStateBlock implementation structure + */ + +/* Internal state Block for Begin/End/Capture/Create/Apply info */ +/* Note: Very long winded but gl Lists are not flexible enough */ +/* to resolve everything we need, so doing it manually for now */ +typedef struct SAVEDSTATES { + BOOL indices; + BOOL material; + BOOL fvf; + BOOL streamSource[MAX_STREAMS]; + BOOL streamFreq[MAX_STREAMS]; + BOOL textures[MAX_COMBINED_SAMPLERS]; + BOOL transform[HIGHEST_TRANSFORMSTATE + 1]; + BOOL viewport; + BOOL renderState[WINEHIGHEST_RENDER_STATE + 1]; + BOOL textureState[MAX_TEXTURES][WINED3D_HIGHEST_TEXTURE_STATE + 1]; + BOOL samplerState[MAX_COMBINED_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1]; + BOOL clipplane[MAX_CLIPPLANES]; + BOOL vertexDecl; + BOOL pixelShader; + BOOL pixelShaderConstantsB[MAX_CONST_B]; + BOOL pixelShaderConstantsI[MAX_CONST_I]; + BOOL *pixelShaderConstantsF; + BOOL vertexShader; + BOOL vertexShaderConstantsB[MAX_CONST_B]; + BOOL vertexShaderConstantsI[MAX_CONST_I]; + BOOL *vertexShaderConstantsF; + BOOL scissorRect; +} SAVEDSTATES; + +typedef struct { + struct list entry; + DWORD count; + DWORD idx[13]; +} constants_entry; + +struct StageState { + DWORD stage; + DWORD state; +}; + +struct IWineD3DStateBlockImpl +{ + /* IUnknown fields */ + const IWineD3DStateBlockVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + /* IWineD3DStateBlock information */ + IUnknown *parent; + IWineD3DDeviceImpl *wineD3DDevice; + WINED3DSTATEBLOCKTYPE blockType; + + /* Array indicating whether things have been set or changed */ + SAVEDSTATES changed; + struct list set_vconstantsF; + struct list set_pconstantsF; + + /* Drawing - Vertex Shader or FVF related */ + DWORD fvf; + /* Vertex Shader Declaration */ + IWineD3DVertexDeclaration *vertexDecl; + + IWineD3DVertexShader *vertexShader; + + /* Vertex Shader Constants */ + BOOL vertexShaderConstantB[MAX_CONST_B]; + INT vertexShaderConstantI[MAX_CONST_I * 4]; + float *vertexShaderConstantF; + + /* Stream Source */ + BOOL streamIsUP; + UINT streamStride[MAX_STREAMS]; + UINT streamOffset[MAX_STREAMS + 1 /* tesselated pseudo-stream */ ]; + IWineD3DVertexBuffer *streamSource[MAX_STREAMS]; + UINT streamFreq[MAX_STREAMS + 1]; + UINT streamFlags[MAX_STREAMS + 1]; /*0 | WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA */ + + /* Indices */ + IWineD3DIndexBuffer* pIndexData; + UINT baseVertexIndex; + UINT loadBaseVertexIndex; /* non-indexed drawing needs 0 here, indexed baseVertexIndex */ + + /* Transform */ + WINED3DMATRIX transforms[HIGHEST_TRANSFORMSTATE + 1]; + + /* Light hashmap . Collisions are handled using standard wine double linked lists */ +#define LIGHTMAP_SIZE 43 /* Use of a prime number recommended. Set to 1 for a linked list! */ +#define LIGHTMAP_HASHFUNC(x) ((x) % LIGHTMAP_SIZE) /* Primitive and simple function */ + struct list lightMap[LIGHTMAP_SIZE]; /* Mashmap containing the lights */ + PLIGHTINFOEL *activeLights[MAX_ACTIVE_LIGHTS]; /* Map of opengl lights to d3d lights */ + + /* Clipping */ + double clipplane[MAX_CLIPPLANES][4]; + WINED3DCLIPSTATUS clip_status; + + /* ViewPort */ + WINED3DVIEWPORT viewport; + + /* Material */ + WINED3DMATERIAL material; + + /* Pixel Shader */ + IWineD3DPixelShader *pixelShader; + + /* Pixel Shader Constants */ + BOOL pixelShaderConstantB[MAX_CONST_B]; + INT pixelShaderConstantI[MAX_CONST_I * 4]; + float *pixelShaderConstantF; + + /* RenderState */ + DWORD renderState[WINEHIGHEST_RENDER_STATE + 1]; + + /* Texture */ + IWineD3DBaseTexture *textures[MAX_COMBINED_SAMPLERS]; + int textureDimensions[MAX_COMBINED_SAMPLERS]; + + /* Texture State Stage */ + DWORD textureState[MAX_TEXTURES][WINED3D_HIGHEST_TEXTURE_STATE + 1]; + DWORD lowest_disabled_stage; + /* Sampler States */ + DWORD samplerState[MAX_COMBINED_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1]; + + /* Current GLSL Shader Program */ + struct glsl_shader_prog_link *glsl_program; + + /* Scissor test rectangle */ + RECT scissorRect; + + /* Contained state management */ + DWORD contained_render_states[WINEHIGHEST_RENDER_STATE + 1]; + unsigned int num_contained_render_states; + DWORD contained_transform_states[HIGHEST_TRANSFORMSTATE + 1]; + unsigned int num_contained_transform_states; + DWORD contained_vs_consts_i[MAX_CONST_I]; + unsigned int num_contained_vs_consts_i; + DWORD contained_vs_consts_b[MAX_CONST_B]; + unsigned int num_contained_vs_consts_b; + DWORD *contained_vs_consts_f; + unsigned int num_contained_vs_consts_f; + DWORD contained_ps_consts_i[MAX_CONST_I]; + unsigned int num_contained_ps_consts_i; + DWORD contained_ps_consts_b[MAX_CONST_B]; + unsigned int num_contained_ps_consts_b; + DWORD *contained_ps_consts_f; + unsigned int num_contained_ps_consts_f; + struct StageState contained_tss_states[MAX_TEXTURES * (WINED3D_HIGHEST_TEXTURE_STATE)]; + unsigned int num_contained_tss_states; + struct StageState contained_sampler_states[MAX_COMBINED_SAMPLERS * WINED3D_HIGHEST_SAMPLER_STATE]; + unsigned int num_contained_sampler_states; +}; + +extern void stateblock_savedstates_set( + IWineD3DStateBlock* iface, + SAVEDSTATES* states, + BOOL value); + +extern void stateblock_savedstates_copy( + IWineD3DStateBlock* iface, + SAVEDSTATES* dest, + SAVEDSTATES* source); + +extern void stateblock_copy( + IWineD3DStateBlock* destination, + IWineD3DStateBlock* source); + +extern const IWineD3DStateBlockVtbl IWineD3DStateBlock_Vtbl; + +/***************************************************************************** + * IWineD3DQueryImpl implementation structure (extends IUnknown) + */ +typedef struct IWineD3DQueryImpl +{ + const IWineD3DQueryVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + IUnknown *parent; + /*TODO: replace with iface usage */ +#if 0 + IWineD3DDevice *wineD3DDevice; +#else + IWineD3DDeviceImpl *wineD3DDevice; +#endif + + /* IWineD3DQuery fields */ + WINED3DQUERYTYPE type; + /* TODO: Think about using a IUnknown instead of a void* */ + void *extendedData; + + +} IWineD3DQueryImpl; + +extern const IWineD3DQueryVtbl IWineD3DQuery_Vtbl; + +/* Datastructures for IWineD3DQueryImpl.extendedData */ +typedef struct WineQueryOcclusionData { + GLuint queryId; +} WineQueryOcclusionData; + +typedef struct WineQueryEventData { + GLuint fenceId; +} WineQueryEventData; + +/***************************************************************************** + * IWineD3DSwapChainImpl implementation structure (extends IUnknown) + */ + +typedef struct IWineD3DSwapChainImpl +{ + /*IUnknown part*/ + const IWineD3DSwapChainVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + IUnknown *parent; + IWineD3DDeviceImpl *wineD3DDevice; + + /* IWineD3DSwapChain fields */ + IWineD3DSurface **backBuffer; + IWineD3DSurface *frontBuffer; + BOOL wantsDepthStencilBuffer; + WINED3DPRESENT_PARAMETERS presentParms; + DWORD orig_width, orig_height; + WINED3DFORMAT orig_fmt; + + long prev_time, frames; /* Performance tracking */ + unsigned int vSyncCounter; + + WineD3DContext **context; /* Later a array for multithreading */ + unsigned int num_contexts; + + HWND win_handle; +} IWineD3DSwapChainImpl; + +extern const IWineD3DSwapChainVtbl IWineD3DSwapChain_Vtbl; + +WineD3DContext *IWineD3DSwapChainImpl_CreateContextForThread(IWineD3DSwapChain *iface); + +/***************************************************************************** + * Utility function prototypes + */ + +/* Trace routines */ +const char* debug_d3dformat(WINED3DFORMAT fmt); +const char* debug_d3ddevicetype(WINED3DDEVTYPE devtype); +const char* debug_d3dresourcetype(WINED3DRESOURCETYPE res); +const char* debug_d3dusage(DWORD usage); +const char* debug_d3dusagequery(DWORD usagequery); +const char* debug_d3ddeclmethod(WINED3DDECLMETHOD method); +const char* debug_d3ddecltype(WINED3DDECLTYPE type); +const char* debug_d3ddeclusage(BYTE usage); +const char* debug_d3dprimitivetype(WINED3DPRIMITIVETYPE PrimitiveType); +const char* debug_d3drenderstate(DWORD state); +const char* debug_d3dsamplerstate(DWORD state); +const char* debug_d3dtexturefiltertype(WINED3DTEXTUREFILTERTYPE filter_type); +const char* debug_d3dtexturestate(DWORD state); +const char* debug_d3dtstype(WINED3DTRANSFORMSTATETYPE tstype); +const char* debug_d3dpool(WINED3DPOOL pool); +const char *debug_fbostatus(GLenum status); +const char *debug_glerror(GLenum error); +const char *debug_d3dbasis(WINED3DBASISTYPE basis); +const char *debug_d3ddegree(WINED3DDEGREETYPE order); + +/* Routines for GL <-> D3D values */ +GLenum StencilOp(DWORD op); +GLenum CompareFunc(DWORD func); +void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3); +void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx); +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords); + +void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height); +GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain); + +BOOL getColorBits(WINED3DFORMAT fmt, short *redSize, short *greenSize, short *blueSize, short *alphaSize, short *totalSize); +BOOL getDepthStencilBits(WINED3DFORMAT fmt, short *depthSize, short *stencilSize); + +/* Math utils */ +void multiply_matrix(WINED3DMATRIX *dest, const WINED3DMATRIX *src1, const WINED3DMATRIX *src2); + +/***************************************************************************** + * To enable calling of inherited functions, requires prototypes + * + * Note: Only require classes which are subclassed, ie resource, basetexture, + */ + /*** IUnknown methods ***/ + extern HRESULT WINAPI IWineD3DResourceImpl_QueryInterface(IWineD3DResource *iface, REFIID riid, void** ppvObject); + extern ULONG WINAPI IWineD3DResourceImpl_AddRef(IWineD3DResource *iface); + extern ULONG WINAPI IWineD3DResourceImpl_Release(IWineD3DResource *iface); + /*** IWineD3DResource methods ***/ + extern HRESULT WINAPI IWineD3DResourceImpl_GetParent(IWineD3DResource *iface, IUnknown **pParent); + extern HRESULT WINAPI IWineD3DResourceImpl_GetDevice(IWineD3DResource *iface, IWineD3DDevice ** ppDevice); + extern HRESULT WINAPI IWineD3DResourceImpl_SetPrivateData(IWineD3DResource *iface, REFGUID refguid, CONST void * pData, DWORD SizeOfData, DWORD Flags); + extern HRESULT WINAPI IWineD3DResourceImpl_GetPrivateData(IWineD3DResource *iface, REFGUID refguid, void * pData, DWORD * pSizeOfData); + extern HRESULT WINAPI IWineD3DResourceImpl_FreePrivateData(IWineD3DResource *iface, REFGUID refguid); + extern DWORD WINAPI IWineD3DResourceImpl_SetPriority(IWineD3DResource *iface, DWORD PriorityNew); + extern DWORD WINAPI IWineD3DResourceImpl_GetPriority(IWineD3DResource *iface); + extern void WINAPI IWineD3DResourceImpl_PreLoad(IWineD3DResource *iface); + extern WINED3DRESOURCETYPE WINAPI IWineD3DResourceImpl_GetType(IWineD3DResource *iface); + /*** class static members ***/ + void IWineD3DResourceImpl_CleanUp(IWineD3DResource *iface); + + /*** IUnknown methods ***/ + extern HRESULT WINAPI IWineD3DBaseTextureImpl_QueryInterface(IWineD3DBaseTexture *iface, REFIID riid, void** ppvObject); + extern ULONG WINAPI IWineD3DBaseTextureImpl_AddRef(IWineD3DBaseTexture *iface); + extern ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface); + /*** IWineD3DResource methods ***/ + extern HRESULT WINAPI IWineD3DBaseTextureImpl_GetParent(IWineD3DBaseTexture *iface, IUnknown **pParent); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_GetDevice(IWineD3DBaseTexture *iface, IWineD3DDevice ** ppDevice); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_SetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, CONST void * pData, DWORD SizeOfData, DWORD Flags); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_GetPrivateData(IWineD3DBaseTexture *iface, REFGUID refguid, void * pData, DWORD * pSizeOfData); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_FreePrivateData(IWineD3DBaseTexture *iface, REFGUID refguid); + extern DWORD WINAPI IWineD3DBaseTextureImpl_SetPriority(IWineD3DBaseTexture *iface, DWORD PriorityNew); + extern DWORD WINAPI IWineD3DBaseTextureImpl_GetPriority(IWineD3DBaseTexture *iface); + extern void WINAPI IWineD3DBaseTextureImpl_PreLoad(IWineD3DBaseTexture *iface); + extern WINED3DRESOURCETYPE WINAPI IWineD3DBaseTextureImpl_GetType(IWineD3DBaseTexture *iface); + /*** IWineD3DBaseTexture methods ***/ + extern DWORD WINAPI IWineD3DBaseTextureImpl_SetLOD(IWineD3DBaseTexture *iface, DWORD LODNew); + extern DWORD WINAPI IWineD3DBaseTextureImpl_GetLOD(IWineD3DBaseTexture *iface); + extern DWORD WINAPI IWineD3DBaseTextureImpl_GetLevelCount(IWineD3DBaseTexture *iface); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_SetAutoGenFilterType(IWineD3DBaseTexture *iface, WINED3DTEXTUREFILTERTYPE FilterType); + extern WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DBaseTextureImpl_GetAutoGenFilterType(IWineD3DBaseTexture *iface); + extern void WINAPI IWineD3DBaseTextureImpl_GenerateMipSubLevels(IWineD3DBaseTexture *iface); + extern BOOL WINAPI IWineD3DBaseTextureImpl_SetDirty(IWineD3DBaseTexture *iface, BOOL); + extern BOOL WINAPI IWineD3DBaseTextureImpl_GetDirty(IWineD3DBaseTexture *iface); + + extern BYTE* WINAPI IWineD3DVertexBufferImpl_GetMemory(IWineD3DVertexBuffer* iface, DWORD iOffset, GLint *vbo); + extern HRESULT WINAPI IWineD3DVertexBufferImpl_ReleaseMemory(IWineD3DVertexBuffer* iface); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface); + extern HRESULT WINAPI IWineD3DBaseTextureImpl_UnBindTexture(IWineD3DBaseTexture *iface); + extern void WINAPI IWineD3DBaseTextureImpl_ApplyStateChanges(IWineD3DBaseTexture *iface, const DWORD textureStates[WINED3D_HIGHEST_TEXTURE_STATE + 1], const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]); + /*** class static members ***/ + void IWineD3DBaseTextureImpl_CleanUp(IWineD3DBaseTexture *iface); + +struct SHADER_OPCODE_ARG; +typedef void (*SHADER_HANDLER) (struct SHADER_OPCODE_ARG*); + +/* Struct to maintain a list of GLSL shader programs and their associated pixel and + * vertex shaders. A list of this type is maintained on the DeviceImpl, and is only + * used if the user is using GLSL shaders. */ +struct glsl_shader_prog_link { + struct list vshader_entry; + struct list pshader_entry; + GLhandleARB programId; + GLhandleARB *vuniformF_locations; + GLhandleARB *puniformF_locations; + GLhandleARB vshader; + GLhandleARB pshader; +}; + +typedef struct { + GLhandleARB vshader; + GLhandleARB pshader; +} glsl_program_key_t; + +/* TODO: Make this dynamic, based on shader limits ? */ +#define MAX_REG_ADDR 1 +#define MAX_REG_TEMP 32 +#define MAX_REG_TEXCRD 8 +#define MAX_REG_INPUT 12 +#define MAX_REG_OUTPUT 12 +#define MAX_ATTRIBS 16 +#define MAX_CONST_I 16 +#define MAX_CONST_B 16 + +/* FIXME: This needs to go up to 2048 for + * Shader model 3 according to msdn (and for software shaders) */ +#define MAX_LABELS 16 + +typedef struct semantic { + DWORD usage; + DWORD reg; +} semantic; + +typedef struct local_constant { + struct list entry; + unsigned int idx; + DWORD value[4]; +} local_constant; + +typedef struct shader_reg_maps { + + char texcoord[MAX_REG_TEXCRD]; /* pixel < 3.0 */ + char temporary[MAX_REG_TEMP]; /* pixel, vertex */ + char address[MAX_REG_ADDR]; /* vertex */ + char packed_input[MAX_REG_INPUT]; /* pshader >= 3.0 */ + char packed_output[MAX_REG_OUTPUT]; /* vertex >= 3.0 */ + char attributes[MAX_ATTRIBS]; /* vertex */ + char labels[MAX_LABELS]; /* pixel, vertex */ + + /* Sampler usage tokens + * Use 0 as default (bit 31 is always 1 on a valid token) */ + DWORD samplers[max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS)]; + char bumpmat; + + /* Whether or not a loop is used in this shader */ + char loop; + + /* Whether or not this shader uses fog */ + char fog; + +} shader_reg_maps; + +#define SHADER_PGMSIZE 65535 +typedef struct SHADER_BUFFER { + char* buffer; + unsigned int bsize; + unsigned int lineNo; + BOOL newline; +} SHADER_BUFFER; + +/* Undocumented opcode controls */ +#define INST_CONTROLS_SHIFT 16 +#define INST_CONTROLS_MASK 0x00ff0000 + +typedef enum COMPARISON_TYPE { + COMPARISON_GT = 1, + COMPARISON_EQ = 2, + COMPARISON_GE = 3, + COMPARISON_LT = 4, + COMPARISON_NE = 5, + COMPARISON_LE = 6 +} COMPARISON_TYPE; + +typedef struct SHADER_OPCODE { + unsigned int opcode; + const char* name; + const char* glname; + char dst_token; + CONST UINT num_params; + SHADER_HANDLER hw_fct; + SHADER_HANDLER hw_glsl_fct; + DWORD min_version; + DWORD max_version; +} SHADER_OPCODE; + +typedef struct SHADER_OPCODE_ARG { + IWineD3DBaseShader* shader; + shader_reg_maps* reg_maps; + CONST SHADER_OPCODE* opcode; + DWORD opcode_token; + DWORD dst; + DWORD dst_addr; + DWORD predicate; + DWORD src[4]; + DWORD src_addr[4]; + SHADER_BUFFER* buffer; +} SHADER_OPCODE_ARG; + +typedef struct SHADER_LIMITS { + unsigned int temporary; + unsigned int texcoord; + unsigned int sampler; + unsigned int constant_int; + unsigned int constant_float; + unsigned int constant_bool; + unsigned int address; + unsigned int packed_output; + unsigned int packed_input; + unsigned int attributes; + unsigned int label; +} SHADER_LIMITS; + +/** Keeps track of details for TEX_M#x# shader opcodes which need to + maintain state information between multiple codes */ +typedef struct SHADER_PARSE_STATE { + unsigned int current_row; + DWORD texcoord_w[2]; +} SHADER_PARSE_STATE; + +/* Base Shader utility functions. + * (may move callers into the same file in the future) */ +extern int shader_addline( + SHADER_BUFFER* buffer, + const char* fmt, ...); + +extern const SHADER_OPCODE* shader_get_opcode( + IWineD3DBaseShader *iface, + const DWORD code); + +extern void shader_delete_constant_list( + struct list* clist); + +void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_link *entry); + +/* Vertex shader utility functions */ +extern BOOL vshader_get_input( + IWineD3DVertexShader* iface, + BYTE usage_req, BYTE usage_idx_req, + unsigned int* regnum); + +extern BOOL vshader_input_is_color( + IWineD3DVertexShader* iface, + unsigned int regnum); + +extern HRESULT allocate_shader_constants(IWineD3DStateBlockImpl* object); + +/* ARB_[vertex/fragment]_program helper functions */ +extern void shader_arb_load_constants( + IWineD3DDevice* device, + char usePixelShader, + char useVertexShader); + +/* ARB shader program Prototypes */ +extern void shader_hw_def(SHADER_OPCODE_ARG *arg); + +/* ARB pixel shader prototypes */ +extern void pshader_hw_bem(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_cnd(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_cmp(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_tex(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texreg2ar(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texbem(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg); +extern void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg); + +/* ARB vertex shader prototypes */ +extern void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg); +extern void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg); +extern void vshader_hw_rsq_rcp(SHADER_OPCODE_ARG* arg); + +/* GLSL helper functions */ +extern void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG *arg); +extern void shader_glsl_load_constants( + IWineD3DDevice* device, + char usePixelShader, + char useVertexShader); + +/** The following translate DirectX pixel/vertex shader opcodes to GLSL lines */ +extern void shader_glsl_cross(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_arith(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_mov(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_mad(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_mnxn(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_lrp(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_dot(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_rcp(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_rsq(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_cnd(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_compare(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_def(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_defi(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_defb(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_expp(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_cmp(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_lit(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_dst(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_sincos(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_loop(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_end(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_if(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_ifc(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_else(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_break(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_breakc(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_rep(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_call(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_callnz(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_label(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_pow(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_texldl(SHADER_OPCODE_ARG* arg); + +/** GLSL Pixel Shader Prototypes */ +extern void pshader_glsl_tex(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texcoord(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texdp3tex(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texdp3(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texdepth(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x2depth(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x2pad(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x2tex(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x3(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x3pad(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x3tex(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x3spec(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texkill(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texbem(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_bem(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texreg2ar(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texreg2gb(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_texreg2rgb(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_dp2add(SHADER_OPCODE_ARG* arg); +extern void pshader_glsl_input_pack( + SHADER_BUFFER* buffer, + semantic* semantics_out); + +/** GLSL Vertex Shader Prototypes */ +extern void vshader_glsl_output_unpack( + SHADER_BUFFER* buffer, + semantic* semantics_out); + +/***************************************************************************** + * IDirect3DBaseShader implementation structure + */ +typedef struct IWineD3DBaseShaderClass +{ + DWORD hex_version; + SHADER_LIMITS limits; + SHADER_PARSE_STATE parse_state; + CONST SHADER_OPCODE *shader_ins; + CONST DWORD *function; + UINT functionLength; + GLuint prgId; + BOOL is_compiled; + + /* Type of shader backend */ + int shader_mode; + + /* Programs this shader is linked with */ + struct list linked_programs; + + /* Immediate constants (override global ones) */ + struct list constantsB; + struct list constantsF; + struct list constantsI; + shader_reg_maps reg_maps; + + /* Pointer to the parent device */ + IWineD3DDevice *device; + +} IWineD3DBaseShaderClass; + +typedef struct IWineD3DBaseShaderImpl { + /* IUnknown */ + const IWineD3DBaseShaderVtbl *lpVtbl; + LONG ref; + + /* IWineD3DBaseShader */ + IWineD3DBaseShaderClass baseShader; +} IWineD3DBaseShaderImpl; + +extern HRESULT shader_get_registers_used( + IWineD3DBaseShader *iface, + shader_reg_maps* reg_maps, + semantic* semantics_in, + semantic* semantics_out, + CONST DWORD* pToken, + IWineD3DStateBlockImpl *stateBlock); + +extern void shader_generate_glsl_declarations( + IWineD3DBaseShader *iface, + shader_reg_maps* reg_maps, + SHADER_BUFFER* buffer, + WineD3D_GL_Info* gl_info); + +extern void shader_generate_arb_declarations( + IWineD3DBaseShader *iface, + shader_reg_maps* reg_maps, + SHADER_BUFFER* buffer, + WineD3D_GL_Info* gl_info); + +extern void shader_generate_main( + IWineD3DBaseShader *iface, + SHADER_BUFFER* buffer, + shader_reg_maps* reg_maps, + CONST DWORD* pFunction); + +extern void shader_dump_ins_modifiers( + const DWORD output); + +extern void shader_dump_param( + IWineD3DBaseShader *iface, + const DWORD param, + const DWORD addr_token, + int input); + +extern void shader_trace_init( + IWineD3DBaseShader *iface, + const DWORD* pFunction); + +extern int shader_get_param( + IWineD3DBaseShader* iface, + const DWORD* pToken, + DWORD* param, + DWORD* addr_token); + +extern int shader_skip_unrecognized( + IWineD3DBaseShader* iface, + const DWORD* pToken); + +extern void print_glsl_info_log( + WineD3D_GL_Info *gl_info, + GLhandleARB obj); + +static inline int shader_get_regtype(const DWORD param) { + return (((param & WINED3DSP_REGTYPE_MASK) >> WINED3DSP_REGTYPE_SHIFT) | + ((param & WINED3DSP_REGTYPE_MASK2) >> WINED3DSP_REGTYPE_SHIFT2)); +} + +extern unsigned int shader_get_float_offset(const DWORD reg); + +static inline BOOL shader_is_pshader_version(DWORD token) { + return 0xFFFF0000 == (token & 0xFFFF0000); +} + +static inline BOOL shader_is_vshader_version(DWORD token) { + return 0xFFFE0000 == (token & 0xFFFF0000); +} + +static inline BOOL shader_is_comment(DWORD token) { + return WINED3DSIO_COMMENT == (token & WINED3DSI_OPCODE_MASK); +} + +/* TODO: vFace (ps_3_0) */ +static inline BOOL shader_is_scalar(DWORD param) { + DWORD reg_type = shader_get_regtype(param); + + switch (reg_type) { + case WINED3DSPR_RASTOUT: + if ((param & WINED3DSP_REGNUM_MASK) != 0) { + /* oFog & oPts */ + return TRUE; + } + /* oPos */ + return FALSE; + + case WINED3DSPR_DEPTHOUT: /* oDepth */ + case WINED3DSPR_CONSTBOOL: /* b# */ + case WINED3DSPR_LOOP: /* aL */ + case WINED3DSPR_PREDICATE: /* p0 */ + return TRUE; + + default: + return FALSE; + } +} + +/* Internally used shader constants. Applications can use constants 0 to GL_LIMITS(vshader_constantsF) - 1, + * so upload them above that + */ +#define ARB_SHADER_PRIVCONST_BASE GL_LIMITS(vshader_constantsF) +#define ARB_SHADER_PRIVCONST_POS ARB_SHADER_PRIVCONST_BASE + 0 + +/***************************************************************************** + * IDirect3DVertexShader implementation structure + */ +typedef struct IWineD3DVertexShaderImpl { + /* IUnknown parts*/ + const IWineD3DVertexShaderVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + /* IWineD3DBaseShader */ + IWineD3DBaseShaderClass baseShader; + + /* IWineD3DVertexShaderImpl */ + IUnknown *parent; + + DWORD usage; + + /* Vertex shader input and output semantics */ + semantic semantics_in [MAX_ATTRIBS]; + semantic semantics_out [MAX_REG_OUTPUT]; + + /* run time datas... */ + VSHADERDATA *data; +#if 0 /* needs reworking */ + /* run time datas */ + VSHADERINPUTDATA input; + VSHADEROUTPUTDATA output; +#endif +} IWineD3DVertexShaderImpl; +extern const SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[]; +extern const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl; + +/***************************************************************************** + * IDirect3DPixelShader implementation structure + */ +typedef struct IWineD3DPixelShaderImpl { + /* IUnknown parts */ + const IWineD3DPixelShaderVtbl *lpVtbl; + LONG ref; /* Note: Ref counting not required */ + + /* IWineD3DBaseShader */ + IWineD3DBaseShaderClass baseShader; + + /* IWineD3DPixelShaderImpl */ + IUnknown *parent; + + /* Pixel shader input semantics */ + semantic semantics_in [MAX_REG_INPUT]; + + /* run time data */ + PSHADERDATA *data; + + /* Some information about the shader behavior */ + char needsbumpmat; + UINT bumpenvmatconst; + +#if 0 /* needs reworking */ + PSHADERINPUTDATA input; + PSHADEROUTPUTDATA output; +#endif +} IWineD3DPixelShaderImpl; + +extern const SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[]; +extern const IWineD3DPixelShaderVtbl IWineD3DPixelShader_Vtbl; + +/***************************************************************************** + * IWineD3DPalette implementation structure + */ +struct IWineD3DPaletteImpl { + /* IUnknown parts */ + const IWineD3DPaletteVtbl *lpVtbl; + LONG ref; + + IUnknown *parent; + IWineD3DDeviceImpl *wineD3DDevice; + + /* IWineD3DPalette */ + HPALETTE hpal; + WORD palVersion; /*| */ + WORD palNumEntries; /*| LOGPALETTE */ + PALETTEENTRY palents[256]; /*| */ + /* This is to store the palette in 'screen format' */ + int screen_palents[256]; + DWORD Flags; +}; + +extern const IWineD3DPaletteVtbl IWineD3DPalette_Vtbl; +DWORD IWineD3DPaletteImpl_Size(DWORD dwFlags); + +/* DirectDraw utility functions */ +extern WINED3DFORMAT pixelformat_for_depth(DWORD depth); + +/***************************************************************************** + * Pixel format management + */ +typedef struct { + WINED3DFORMAT format; + DWORD alphaMask, redMask, greenMask, blueMask; + UINT bpp; + short depthSize, stencilSize; + BOOL isFourcc; +} StaticPixelFormatDesc; + +const StaticPixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt, + WineD3D_GL_Info *gl_info, + const GlPixelFormatDesc **glDesc); + +static inline BOOL use_vs(IWineD3DDeviceImpl *device) { + return (device->vs_selected_mode != SHADER_NONE + && device->stateBlock->vertexShader + && ((IWineD3DVertexShaderImpl *)device->stateBlock->vertexShader)->baseShader.function + && !device->strided_streams.u.s.position_transformed); +} + +static inline BOOL use_ps(IWineD3DDeviceImpl *device) { + return (device->ps_selected_mode != SHADER_NONE + && device->stateBlock->pixelShader + && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function); +} + +void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect, + IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip); + +#endif diff --git a/reactos/dll/directx/wine/wined3d/wined3d_private_types.h b/reactos/dll/directx/wine/wined3d/wined3d_private_types.h new file mode 100644 index 00000000000..3550910101e --- /dev/null +++ b/reactos/dll/directx/wine/wined3d/wined3d_private_types.h @@ -0,0 +1,309 @@ +/* + * Direct3D wine internal header: D3D equivalent types + * + * Copyright 2002-2003 Jason Edmeades + * Copyright 2002-2003 Raphael Junqueira + * Copyright 2005 Oliver Stieber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINED3D_TYPES_INTERNAL_H +#define __WINE_WINED3D_TYPES_INTERNAL_H + +/* Depth copy state */ +typedef enum { + WINED3D_DCS_INITIAL = 0, + WINED3D_DCS_COPY = 1, + WINED3D_DCS_NO_COPY = 2 +} WINED3D_DEPTHCOPYSTATE; + +/** DCL usage masks **/ +#define WINED3DSP_DCL_USAGE_SHIFT 0 +#define WINED3DSP_DCL_USAGE_MASK 0x0000000f +#define WINED3DSP_DCL_USAGEINDEX_SHIFT 16 +#define WINED3DSP_DCL_USAGEINDEX_MASK 0x000f0000 + +/** DCL sampler texture type **/ +#define WINED3DSP_TEXTURETYPE_SHIFT 27 +#define WINED3DSP_TEXTURETYPE_MASK 0x78000000 + +typedef enum _WINED3DSAMPLER_TEXTURE_TYPE { + WINED3DSTT_UNKNOWN = 0 << WINED3DSP_TEXTURETYPE_SHIFT, + WINED3DSTT_1D = 1 << WINED3DSP_TEXTURETYPE_SHIFT, + WINED3DSTT_2D = 2 << WINED3DSP_TEXTURETYPE_SHIFT, + WINED3DSTT_CUBE = 3 << WINED3DSP_TEXTURETYPE_SHIFT, + WINED3DSTT_VOLUME = 4 << WINED3DSP_TEXTURETYPE_SHIFT, + + WINED3DSTT_FORCE_DWORD = 0x7FFFFFFF +} WINED3DSAMPLER_TEXTURE_TYPE; + +/** Register number mask **/ +#define WINED3DSP_REGNUM_MASK 0x000007FF + +/** Register type masks **/ +#define WINED3DSP_REGTYPE_SHIFT 28 +#define WINED3DSP_REGTYPE_SHIFT2 8 +#define WINED3DSP_REGTYPE_MASK (0x7 << WINED3DSP_REGTYPE_SHIFT) +#define WINED3DSP_REGTYPE_MASK2 0x00001800 + +/** Register types **/ +typedef enum _WINED3DSHADER_PARAM_REGISTER_TYPE { + WINED3DSPR_TEMP = 0, + WINED3DSPR_INPUT = 1, + WINED3DSPR_CONST = 2, + WINED3DSPR_ADDR = 3, + WINED3DSPR_TEXTURE = 3, + WINED3DSPR_RASTOUT = 4, + WINED3DSPR_ATTROUT = 5, + WINED3DSPR_TEXCRDOUT = 6, + WINED3DSPR_OUTPUT = 6, + WINED3DSPR_CONSTINT = 7, + WINED3DSPR_COLOROUT = 8, + WINED3DSPR_DEPTHOUT = 9, + WINED3DSPR_SAMPLER = 10, + WINED3DSPR_CONST2 = 11, + WINED3DSPR_CONST3 = 12, + WINED3DSPR_CONST4 = 13, + WINED3DSPR_CONSTBOOL = 14, + WINED3DSPR_LOOP = 15, + WINED3DSPR_TEMPFLOAT16 = 16, + WINED3DSPR_MISCTYPE = 17, + WINED3DSPR_LABEL = 18, + WINED3DSPR_PREDICATE = 19, + + WINED3DSPR_FORCE_DWORD = 0x7FFFFFFF +} WINED3DSHADER_PARAM_REGISTER_TYPE; + +/* RASTOUT register offsets */ +typedef enum _WINED3DVS_RASTOUT_OFFSETS { + WINED3DSRO_POSITION = 0, + WINED3DSRO_FOG = 1, + WINED3DSRO_POINT_SIZE = 2, + + WINED3DSRO_FORCE_DWORD = 0x7FFFFFFF +} WINED3DVS_RASTOUT_OFFSETS; + +/** Source register modifiers **/ +#define WINED3DVS_SWIZZLE_SHIFT 16 +#define WINED3DVS_SWIZZLE_MASK (0xFF << WINED3DVS_SWIZZLE_SHIFT) +#define WINED3DSP_SWIZZLE_SHIFT 16 +#define WINED3DSP_SWIZZLE_MASK (0xFF << WINED3DSP_SWIZZLE_SHIFT) + +#define WINED3DVS_X_X (0 << WINED3DVS_SWIZZLE_SHIFT) +#define WINED3DVS_X_Y (1 << WINED3DVS_SWIZZLE_SHIFT) +#define WINED3DVS_X_Z (2 << WINED3DVS_SWIZZLE_SHIFT) +#define WINED3DVS_X_W (3 << WINED3DVS_SWIZZLE_SHIFT) + +#define WINED3DVS_Y_X (0 << (WINED3DVS_SWIZZLE_SHIFT + 2)) +#define WINED3DVS_Y_Y (1 << (WINED3DVS_SWIZZLE_SHIFT + 2)) +#define WINED3DVS_Y_Z (2 << (WINED3DVS_SWIZZLE_SHIFT + 2)) +#define WINED3DVS_Y_W (3 << (WINED3DVS_SWIZZLE_SHIFT + 2)) + +#define WINED3DVS_Z_X (0 << (WINED3DVS_SWIZZLE_SHIFT + 4)) +#define WINED3DVS_Z_Y (1 << (WINED3DVS_SWIZZLE_SHIFT + 4)) +#define WINED3DVS_Z_Z (2 << (WINED3DVS_SWIZZLE_SHIFT + 4)) +#define WINED3DVS_Z_W (3 << (WINED3DVS_SWIZZLE_SHIFT + 4)) + +#define WINED3DVS_W_X (0 << (WINED3DVS_SWIZZLE_SHIFT + 6)) +#define WINED3DVS_W_Y (1 << (WINED3DVS_SWIZZLE_SHIFT + 6)) +#define WINED3DVS_W_Z (2 << (WINED3DVS_SWIZZLE_SHIFT + 6)) +#define WINED3DVS_W_W (3 << (WINED3DVS_SWIZZLE_SHIFT + 6)) + +#define WINED3DVS_NOSWIZZLE (WINED3DVS_X_X | WINED3DVS_Y_Y | WINED3DVS_Z_Z | WINED3DVS_W_W) + +#define WINED3DSP_NOSWIZZLE \ + ((0 << (WINED3DSP_SWIZZLE_SHIFT + 0)) | (1 << (WINED3DSP_SWIZZLE_SHIFT + 2)) | \ + (2 << (WINED3DSP_SWIZZLE_SHIFT + 4)) | (3 << (WINED3DSP_SWIZZLE_SHIFT + 6))) + +#define WINED3DSP_SRCMOD_SHIFT 24 +#define WINED3DSP_SRCMOD_MASK (0xF << WINED3DSP_SRCMOD_SHIFT) + +typedef enum _WINED3DSHADER_PARAM_SRCMOD_TYPE { + WINED3DSPSM_NONE = 0 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_NEG = 1 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_BIAS = 2 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_BIASNEG = 3 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_SIGN = 4 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_SIGNNEG = 5 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_COMP = 6 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_X2 = 7 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_X2NEG = 8 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_DZ = 9 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_DW = 10 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_ABS = 11 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_ABSNEG = 12 << WINED3DSP_SRCMOD_SHIFT, + WINED3DSPSM_NOT = 13 << WINED3DSP_SRCMOD_SHIFT, + + WINED3DSPSM_FORCE_DWORD = 0x7FFFFFFF +} WINED3DSHADER_PARAM_SRCMOD_TYPE; + +/** Destination register modifiers **/ +#define WINED3DSP_WRITEMASK_0 0x00010000 /* .x r */ +#define WINED3DSP_WRITEMASK_1 0x00020000 /* .y g */ +#define WINED3DSP_WRITEMASK_2 0x00040000 /* .z b */ +#define WINED3DSP_WRITEMASK_3 0x00080000 /* .w a */ +#define WINED3DSP_WRITEMASK_ALL 0x000F0000 /* all */ + +#define WINED3DSP_DSTMOD_SHIFT 20 +#define WINED3DSP_DSTMOD_MASK (0xF << WINED3DSP_DSTMOD_SHIFT) + +typedef enum _WINED3DSHADER_PARAM_DSTMOD_TYPE { + WINED3DSPDM_NONE = 0 << WINED3DSP_DSTMOD_SHIFT, + WINED3DSPDM_SATURATE = 1 << WINED3DSP_DSTMOD_SHIFT, + WINED3DSPDM_PARTIALPRECISION = 2 << WINED3DSP_DSTMOD_SHIFT, + WINED3DSPDM_MSAMPCENTROID = 4 << WINED3DSP_DSTMOD_SHIFT, + + WINED3DSPDM_FORCE_DWORD = 0x7FFFFFFF +} WINED3DSHADER_PARAM_DSTMOD_TYPE; + +#define WINED3DSP_DSTSHIFT_SHIFT 24 +#define WINED3DSP_DSTSHIFT_MASK (0xF << WINED3DSP_DSTSHIFT_SHIFT) + +/** Register addressing modes **/ +#define WINED3DSHADER_ADDRESSMODE_SHIFT 13 +#define WINED3DSHADER_ADDRESSMODE_MASK (1 << WINED3DSHADER_ADDRESSMODE_SHIFT) + +typedef enum _WINED3DSHADER_ADDRESSMODE_TYPE { + WINED3DSHADER_ADDRMODE_ABSOLUTE = 0 << WINED3DSHADER_ADDRESSMODE_SHIFT, + WINED3DSHADER_ADDRMODE_RELATIVE = 1 << WINED3DSHADER_ADDRESSMODE_SHIFT, + + WINED3DSHADER_ADDRMODE_FORCE_DWORD = 0x7FFFFFFF +} WINED3DSHADER_ADDRESSMODE_TYPE; + +/** Opcode types */ +typedef enum _WINED3DSHADER_INSTRUCTION_OPCODE_TYPE { + WINED3DSIO_NOP = 0, + WINED3DSIO_MOV = 1, + WINED3DSIO_ADD = 2, + WINED3DSIO_SUB = 3, + WINED3DSIO_MAD = 4, + WINED3DSIO_MUL = 5, + WINED3DSIO_RCP = 6, + WINED3DSIO_RSQ = 7, + WINED3DSIO_DP3 = 8, + WINED3DSIO_DP4 = 9, + WINED3DSIO_MIN = 10, + WINED3DSIO_MAX = 11, + WINED3DSIO_SLT = 12, + WINED3DSIO_SGE = 13, + WINED3DSIO_EXP = 14, + WINED3DSIO_LOG = 15, + WINED3DSIO_LIT = 16, + WINED3DSIO_DST = 17, + WINED3DSIO_LRP = 18, + WINED3DSIO_FRC = 19, + WINED3DSIO_M4x4 = 20, + WINED3DSIO_M4x3 = 21, + WINED3DSIO_M3x4 = 22, + WINED3DSIO_M3x3 = 23, + WINED3DSIO_M3x2 = 24, + WINED3DSIO_CALL = 25, + WINED3DSIO_CALLNZ = 26, + WINED3DSIO_LOOP = 27, + WINED3DSIO_RET = 28, + WINED3DSIO_ENDLOOP = 29, + WINED3DSIO_LABEL = 30, + WINED3DSIO_DCL = 31, + WINED3DSIO_POW = 32, + WINED3DSIO_CRS = 33, + WINED3DSIO_SGN = 34, + WINED3DSIO_ABS = 35, + WINED3DSIO_NRM = 36, + WINED3DSIO_SINCOS = 37, + WINED3DSIO_REP = 38, + WINED3DSIO_ENDREP = 39, + WINED3DSIO_IF = 40, + WINED3DSIO_IFC = 41, + WINED3DSIO_ELSE = 42, + WINED3DSIO_ENDIF = 43, + WINED3DSIO_BREAK = 44, + WINED3DSIO_BREAKC = 45, + WINED3DSIO_MOVA = 46, + WINED3DSIO_DEFB = 47, + WINED3DSIO_DEFI = 48, + + WINED3DSIO_TEXCOORD = 64, + WINED3DSIO_TEXKILL = 65, + WINED3DSIO_TEX = 66, + WINED3DSIO_TEXBEM = 67, + WINED3DSIO_TEXBEML = 68, + WINED3DSIO_TEXREG2AR = 69, + WINED3DSIO_TEXREG2GB = 70, + WINED3DSIO_TEXM3x2PAD = 71, + WINED3DSIO_TEXM3x2TEX = 72, + WINED3DSIO_TEXM3x3PAD = 73, + WINED3DSIO_TEXM3x3TEX = 74, + WINED3DSIO_TEXM3x3DIFF = 75, + WINED3DSIO_TEXM3x3SPEC = 76, + WINED3DSIO_TEXM3x3VSPEC = 77, + WINED3DSIO_EXPP = 78, + WINED3DSIO_LOGP = 79, + WINED3DSIO_CND = 80, + WINED3DSIO_DEF = 81, + WINED3DSIO_TEXREG2RGB = 82, + WINED3DSIO_TEXDP3TEX = 83, + WINED3DSIO_TEXM3x2DEPTH = 84, + WINED3DSIO_TEXDP3 = 85, + WINED3DSIO_TEXM3x3 = 86, + WINED3DSIO_TEXDEPTH = 87, + WINED3DSIO_CMP = 88, + WINED3DSIO_BEM = 89, + WINED3DSIO_DP2ADD = 90, + WINED3DSIO_DSX = 91, + WINED3DSIO_DSY = 92, + WINED3DSIO_TEXLDD = 93, + WINED3DSIO_SETP = 94, + WINED3DSIO_TEXLDL = 95, + WINED3DSIO_BREAKP = 96, + + WINED3DSIO_PHASE = 0xFFFD, + WINED3DSIO_COMMENT = 0xFFFE, + WINED3DSIO_END = 0XFFFF, + + WINED3DSIO_FORCE_DWORD = 0X7FFFFFFF /** for 32-bit alignment */ +} WINED3DSHADER_INSTRUCTION_OPCODE_TYPE; + +/** opcode-related masks **/ + +#define WINED3DSI_OPCODE_MASK 0x0000FFFF +#define WINED3DSI_INSTLENGTH_MASK 0x0F000000 +#define WINED3DSI_INSTLENGTH_SHIFT 24 + +#define WINED3DSI_COISSUE 0x40000000 + +#define WINED3DSI_COMMENTSIZE_SHIFT 16 +#define WINED3DSI_COMMENTSIZE_MASK (0x7FFF << WINED3DSI_COMMENTSIZE_SHIFT) +#define WINED3DSHADER_COMMENT(commentSize) \ + ((((commentSize) << WINED3DSI_COMMENTSIZE_SHIFT) & WINED3DSI_COMMENTSIZE_MASK) | WINED3DSIO_COMMENT) + +#define WINED3DSHADER_INSTRUCTION_PREDICATED (1 << 28) + +/* Undocumented opcode control to identify projective texture lookups in ps 2.0 and later */ +#define WINED3DSI_TEXLD_PROJECT 0x00010000 + +/** Shader version tokens, and shader end tokens **/ + +#define WINED3DPS_VERSION(major, minor) (0xFFFF0000 | ((major) << 8) | (minor)) +#define WINED3DVS_VERSION(major, minor) (0xFFFE0000 | ((major) << 8) | (minor)) +#define WINED3DSHADER_VERSION_MAJOR(version) (((version) >> 8) & 0xFF) +#define WINED3DSHADER_VERSION_MINOR(version) (((version) >> 0) & 0xFF) +#define WINED3DPS_END() 0x0000FFFF +#define WINED3DVS_END() 0x0000FFFF + +/* Multithreaded flag. Removed from the public header to signal that IWineD3D::CreateDevice ignores it */ +#define WINED3DCREATE_MULTITHREADED 0x00000004 + +#endif