| /* | |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #include <math.h> | |
| #include <stdarg.h> | |
| #define NONAMELESSUNION | |
| #define NONAMELESSSTRUCT | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winuser.h" | |
| #include "wingdi.h" | |
| #include "wine/debug.h" | |
| /** define GL_GLEXT_PROTOTYPES for having extensions prototypes defined */ | |
| /*#define GL_GLEXT_PROTOTYPES*/ | |
| /*#undef GLX_GLXEXT_LEGACY*/ | |
| #include "d3d8_private.h" | |
| /** currently desactiving 1_4 support as mesa doesn't implement all 1_4 support while defining it */ | |
| #undef GL_VERSION_1_4 | |
| /* Uncomment the next line to get extra traces, important but impact speed */ | |
| /* #define EXTRA_TRACES */ | |
| WINE_DEFAULT_DEBUG_CHANNEL(d3d); | |
| WINE_DECLARE_DEBUG_CHANNEL(d3d_shader); | |
| WINE_DECLARE_DEBUG_CHANNEL(d3d_fps); | |
| IDirect3DVertexShaderImpl* VertexShaders[64]; | |
| IDirect3DVertexShaderDeclarationImpl* VertexShaderDeclarations[64]; | |
| IDirect3DPixelShaderImpl* PixelShaders[64]; | |
| /* Debugging aids: */ | |
| #ifdef FRAME_DEBUGGING | |
| BOOL isOn = FALSE; | |
| BOOL isDumpingFrames = FALSE; | |
| LONG primCounter = 0; | |
| #endif | |
| /* | |
| * Utility functions or macros | |
| */ | |
| #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) | |
| /* Apply the current values to the specified texture stage */ | |
| void setupTextureStates(LPDIRECT3DDEVICE8 iface, DWORD Stage, DWORD Flags) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| int i = 0; | |
| float col[4]; | |
| BOOL changeTexture = TRUE; | |
| TRACE("-----------------------> Updating the texture at stage %ld to have new texture state information\n", Stage); | |
| for (i = 1; i < HIGHEST_TEXTURE_STATE; i++) { | |
| BOOL skip = FALSE; | |
| switch (i) { | |
| /* Performance: For texture states where multiples effect the outcome, only bother | |
| applying the last one as it will pick up all the other values */ | |
| case D3DTSS_COLORARG0: /* Will be picked up when setting color op */ | |
| case D3DTSS_COLORARG1: /* Will be picked up when setting color op */ | |
| case D3DTSS_COLORARG2: /* Will be picked up when setting color op */ | |
| case D3DTSS_ALPHAARG0: /* Will be picked up when setting alpha op */ | |
| case D3DTSS_ALPHAARG1: /* Will be picked up when setting alpha op */ | |
| case D3DTSS_ALPHAARG2: /* Will be picked up when setting alpha op */ | |
| skip = TRUE; | |
| break; | |
| /* Performance: If the texture states only impact settings for the texture unit | |
| (compared to the texture object) then there is no need to reapply them. The | |
| only time they need applying is the first time, since we cheat and put the | |
| values into the stateblock without applying. | |
| Per-texture unit: texture function (eg. combine), ops and args | |
| texture env color | |
| texture generation settings | |
| Note: Due to some special conditions there may be a need to do particular ones | |
| of these, which is what the Flags allows */ | |
| case D3DTSS_COLOROP: | |
| case D3DTSS_TEXCOORDINDEX: | |
| if (!(Flags == REAPPLY_ALL)) skip=TRUE; | |
| break; | |
| case D3DTSS_ALPHAOP: | |
| if (!(Flags & REAPPLY_ALPHAOP)) skip=TRUE; | |
| break; | |
| default: | |
| skip = FALSE; | |
| } | |
| if (skip == FALSE) { | |
| /* Performance: Only change to this texture if we have to */ | |
| if (changeTexture) { | |
| /* Make appropriate texture active */ | |
| if (GL_SUPPORT(ARB_MULTITEXTURE)) { | |
| #if defined(GL_VERSION_1_3) | |
| glActiveTexture(GL_TEXTURE0 + Stage); | |
| checkGLcall("glActiveTexture"); | |
| #else | |
| glActiveTextureARB(GL_TEXTURE0_ARB + Stage); | |
| checkGLcall("glActiveTextureARB"); | |
| #endif | |
| } else if (Stage > 0) { | |
| FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); | |
| } | |
| changeTexture = FALSE; | |
| } | |
| /* Now apply the change */ | |
| IDirect3DDevice8Impl_SetTextureStageState(iface, Stage, i, This->StateBlock->texture_state[Stage][i]); | |
| } | |
| } | |
| /* Note the D3DRS value applies to all textures, but GL has one | |
| * per texture, so apply it now ready to be used! | |
| */ | |
| D3DCOLORTOGLFLOAT4(This->StateBlock->renderstate[D3DRS_TEXTUREFACTOR], col); | |
| glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &col[0]); | |
| checkGLcall("glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);"); | |
| TRACE("-----------------------> Updated the texture at stage %ld to have new texture state information\n", Stage); | |
| } | |
| /* Convert the D3DLIGHT8 properties into equivalent gl lights */ | |
| void setup_light(LPDIRECT3DDEVICE8 iface, LONG Index, PLIGHTINFOEL *lightInfo) { | |
| float quad_att; | |
| float colRGBA[] = {0.0, 0.0, 0.0, 0.0}; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| /* Light settings are affected by the model view in OpenGL, the View transform in direct3d*/ | |
| glMatrixMode(GL_MODELVIEW); | |
| glPushMatrix(); | |
| glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_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"); | |
| /* 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"); | |
| quad_att = 1.4/(lightInfo->OriginalParms.Range*lightInfo->OriginalParms.Range); | |
| if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2; | |
| glLightf(GL_LIGHT0+Index, GL_QUADRATIC_ATTENUATION, quad_att); | |
| checkGLcall("glLightf"); | |
| switch (lightInfo->OriginalParms.Type) { | |
| case D3DLIGHT_POINT: | |
| /* Position */ | |
| glLightfv(GL_LIGHT0+Index, GL_POSITION, &lightInfo->lightPosn[0]); | |
| checkGLcall("glLightfv"); | |
| glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff); | |
| checkGLcall("glLightf"); | |
| /* FIXME: Range */ | |
| break; | |
| case D3DLIGHT_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"); | |
| /* FIXME: Range */ | |
| break; | |
| case D3DLIGHT_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(); | |
| } | |
| /* Setup this textures matrix */ | |
| static void set_texture_matrix(const float *smat, DWORD flags) | |
| { | |
| float mat[16]; | |
| glMatrixMode(GL_TEXTURE); | |
| if (flags == D3DTTFF_DISABLE) { | |
| glLoadIdentity(); | |
| checkGLcall("glLoadIdentity()"); | |
| return; | |
| } | |
| if (flags == (D3DTTFF_COUNT1|D3DTTFF_PROJECTED)) { | |
| ERR("Invalid texture transform flags: D3DTTFF_COUNT1|D3DTTFF_PROJECTED\n"); | |
| checkGLcall("glLoadIdentity()"); | |
| return; | |
| } | |
| memcpy(mat, smat, 16*sizeof(float)); | |
| switch (flags & ~D3DTTFF_PROJECTED) { | |
| case D3DTTFF_COUNT1: mat[1] = mat[5] = mat[9] = mat[13] = 0; | |
| case D3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; | |
| default: mat[3] = mat[7] = mat[11] = 0, mat[15] = 1; | |
| } | |
| if (flags & D3DTTFF_PROJECTED) switch (flags & ~D3DTTFF_PROJECTED) { | |
| case D3DTTFF_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 D3DTTFF_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; | |
| } | |
| glLoadMatrixf(mat); | |
| checkGLcall("glLoadMatrixf(mat)"); | |
| } | |
| /* IDirect3D IUnknown parts follow: */ | |
| HRESULT WINAPI IDirect3DDevice8Impl_QueryInterface(LPDIRECT3DDEVICE8 iface,REFIID riid,LPVOID *ppobj) | |
| { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| if (IsEqualGUID(riid, &IID_IUnknown) | |
| || IsEqualGUID(riid, &IID_IDirect3DDevice8)) { | |
| IDirect3DDevice8Impl_AddRef(iface); | |
| *ppobj = This; | |
| return D3D_OK; | |
| } | |
| WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); | |
| return E_NOINTERFACE; | |
| } | |
| ULONG WINAPI IDirect3DDevice8Impl_AddRef(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| ULONG ref = InterlockedIncrement(&This->ref); | |
| TRACE("(%p) : AddRef from %ld\n", This, ref - 1); | |
| return ref; | |
| } | |
| ULONG WINAPI IDirect3DDevice8Impl_Release(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| ULONG ref = InterlockedDecrement(&This->ref); | |
| TRACE("(%p) : ReleaseRef to %ld\n", This, ref); | |
| if (ref == 0) { | |
| IDirect3DDevice8Impl_CleanRender(iface); | |
| IDirect3D8_Release((LPDIRECT3D8) This->direct3d8); | |
| IWineD3DDevice_Release(This->WineD3DDevice); | |
| HeapFree(GetProcessHeap(), 0, This); | |
| } | |
| return ref; | |
| } | |
| /* IDirect3DDevice Interface follow: */ | |
| HRESULT WINAPI IDirect3DDevice8Impl_TestCooperativeLevel(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : stub\n", This); /* No way of notifying yet! */ | |
| return D3D_OK; | |
| } | |
| UINT WINAPI IDirect3DDevice8Impl_GetAvailableTextureMem(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : stub, emulating 32Mb for now\n", This); | |
| /* | |
| * pretend we have 32MB of any type of memory queried. | |
| */ | |
| return (1024*1024*32); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_ResourceManagerDiscardBytes(LPDIRECT3DDEVICE8 iface, DWORD Bytes) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetDirect3D(LPDIRECT3DDEVICE8 iface, IDirect3D8** ppD3D8) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : returning %p\n", This, This->direct3d8); | |
| /* Inc ref count */ | |
| IDirect3D8_AddRef((LPDIRECT3D8) This->direct3d8); | |
| *ppD3D8 = (IDirect3D8 *)This->direct3d8; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetDeviceCaps(LPDIRECT3DDEVICE8 iface, D3DCAPS8* pCaps) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub, calling idirect3d for now\n", This); | |
| IDirect3D8Impl_GetDeviceCaps((LPDIRECT3D8) This->direct3d8, This->adapterNo, This->devType, pCaps); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetDisplayMode(LPDIRECT3DDEVICE8 iface, D3DDISPLAYMODE* pMode) { | |
| HDC hdc; | |
| int bpp = 0; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| pMode->Width = GetSystemMetrics(SM_CXSCREEN); | |
| pMode->Height = GetSystemMetrics(SM_CYSCREEN); | |
| pMode->RefreshRate = 85; /*FIXME: How to identify? */ | |
| hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); | |
| bpp = GetDeviceCaps(hdc, BITSPIXEL); | |
| DeleteDC(hdc); | |
| switch (bpp) { | |
| case 8: pMode->Format = D3DFMT_R8G8B8; break; | |
| case 16: pMode->Format = D3DFMT_R5G6B5; break; | |
| case 24: /*pMode->Format = D3DFMT_R8G8B8; break; */ | |
| case 32: pMode->Format = D3DFMT_A8R8G8B8; break; | |
| default: | |
| FIXME("Unrecognized display mode format\n"); | |
| pMode->Format = D3DFMT_UNKNOWN; | |
| } | |
| FIXME("(%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 D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetCreationParameters(LPDIRECT3DDEVICE8 iface, D3DDEVICE_CREATION_PARAMETERS *pParameters) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) copying to %p\n", This, pParameters); | |
| memcpy(pParameters, &This->CreateParms, sizeof(D3DDEVICE_CREATION_PARAMETERS)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetCursorProperties(LPDIRECT3DDEVICE8 iface, UINT XHotSpot, UINT YHotSpot, IDirect3DSurface8* pCursorBitmap) { | |
| IDirect3DSurface8Impl* pSur = (IDirect3DSurface8Impl*) pCursorBitmap; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot); | |
| if (D3DFMT_A8R8G8B8 != pSur->myDesc.Format) { | |
| ERR("(%p) : surface(%p) have a invalid format\n", This, pCursorBitmap); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (32 != pSur->myDesc.Height || 32 != pSur->myDesc.Width) { | |
| ERR("(%p) : surface(%p) have a invalid size\n", This, pCursorBitmap); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| This->xHotSpot = XHotSpot; | |
| This->yHotSpot = YHotSpot; | |
| return D3D_OK; | |
| } | |
| void WINAPI IDirect3DDevice8Impl_SetCursorPosition(LPDIRECT3DDEVICE8 iface, UINT XScreenSpace, UINT YScreenSpace, DWORD Flags) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace); | |
| This->xScreenSpace = XScreenSpace; | |
| This->yScreenSpace = YScreenSpace; | |
| return; | |
| } | |
| BOOL WINAPI IDirect3DDevice8Impl_ShowCursor(LPDIRECT3DDEVICE8 iface, BOOL bShow) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : visible(%d)\n", This, bShow); | |
| This->bCursorVisible = bShow; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateAdditionalSwapChain(LPDIRECT3DDEVICE8 iface, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain8** pSwapChain) { | |
| IDirect3DSwapChain8Impl* object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDevice8Impl)); | |
| if (NULL == object) { | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| object->lpVtbl = &Direct3DSwapChain8_Vtbl; | |
| object->ref = 1; | |
| TRACE("(%p)->(DepthStencil:(%u,%s), BackBufferFormat:(%u,%s))\n", This, | |
| pPresentationParameters->AutoDepthStencilFormat, debug_d3dformat(pPresentationParameters->AutoDepthStencilFormat), | |
| pPresentationParameters->BackBufferFormat, debug_d3dformat(pPresentationParameters->BackBufferFormat)); | |
| if (pPresentationParameters->Windowed && ((pPresentationParameters->BackBufferWidth == 0) || | |
| (pPresentationParameters->BackBufferHeight == 0))) { | |
| RECT Rect; | |
| GetClientRect(This->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); | |
| } | |
| } | |
| /* Save the presentation parms now filled in correctly */ | |
| memcpy(&object->PresentParms, pPresentationParameters, sizeof(D3DPRESENT_PARAMETERS)); | |
| IDirect3DDevice8Impl_CreateRenderTarget((LPDIRECT3DDEVICE8) object, | |
| pPresentationParameters->BackBufferWidth, | |
| pPresentationParameters->BackBufferHeight, | |
| pPresentationParameters->BackBufferFormat, | |
| pPresentationParameters->MultiSampleType, | |
| TRUE, | |
| (LPDIRECT3DSURFACE8*) &object->frontBuffer); | |
| IDirect3DDevice8Impl_CreateRenderTarget((LPDIRECT3DDEVICE8) object, | |
| pPresentationParameters->BackBufferWidth, | |
| pPresentationParameters->BackBufferHeight, | |
| pPresentationParameters->BackBufferFormat, | |
| pPresentationParameters->MultiSampleType, | |
| TRUE, | |
| (LPDIRECT3DSURFACE8*) &object->backBuffer); | |
| if (pPresentationParameters->EnableAutoDepthStencil) { | |
| IDirect3DDevice8Impl_CreateDepthStencilSurface((LPDIRECT3DDEVICE8) object, | |
| pPresentationParameters->BackBufferWidth, | |
| pPresentationParameters->BackBufferHeight, | |
| pPresentationParameters->AutoDepthStencilFormat, | |
| D3DMULTISAMPLE_NONE, | |
| (LPDIRECT3DSURFACE8*) &object->depthStencilBuffer); | |
| } else { | |
| object->depthStencilBuffer = NULL; | |
| } | |
| *pSwapChain = (IDirect3DSwapChain8*) object; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_Reset(LPDIRECT3DDEVICE8 iface, D3DPRESENT_PARAMETERS* pPresentationParameters) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_Present(LPDIRECT3DDEVICE8 iface, | |
| CONST RECT* pSourceRect, CONST RECT* pDestRect, | |
| HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : complete stub!\n", This); | |
| ENTER_GL(); | |
| if (pSourceRect || pDestRect) FIXME("Unhandled present options %p/%p\n", pSourceRect, pDestRect); | |
| glXSwapBuffers(This->display, This->drawable); | |
| /* Don't call checkGLcall, as glGetError is not applicable here */ | |
| TRACE("glXSwapBuffers called, Starting new frame\n"); | |
| /* FPS support */ | |
| if (TRACE_ON(d3d_fps)) | |
| { | |
| static long prev_time, frames; | |
| DWORD time = GetTickCount(); | |
| frames++; | |
| /* every 1.5 seconds */ | |
| if (time - prev_time > 1500) { | |
| TRACE_(d3d_fps)("@ approx %.2ffps\n", 1000.0*frames/(time - prev_time)); | |
| prev_time = time; | |
| 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("Singe 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(); | |
| /* Although this is not strictly required, a simple demo showed this does occur | |
| on (at least non-debug) d3d */ | |
| if (This->PresentParms.SwapEffect == D3DSWAPEFFECT_DISCARD) { | |
| IDirect3DDevice8Impl_Clear(iface, 0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00, 1.0, 0); | |
| } | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetBackBuffer(LPDIRECT3DDEVICE8 iface, UINT BackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface8** ppBackBuffer) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| *ppBackBuffer = (LPDIRECT3DSURFACE8) This->backBuffer; | |
| TRACE("(%p) : BackBuf %d Type %d returning %p\n", This, BackBuffer, Type, *ppBackBuffer); | |
| if (BackBuffer > This->PresentParms.BackBufferCount - 1) { | |
| FIXME("Only one backBuffer currently supported\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| /* Note inc ref on returned surface */ | |
| IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) *ppBackBuffer); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetRasterStatus(LPDIRECT3DDEVICE8 iface, D3DRASTER_STATUS* pRasterStatus) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| return D3D_OK; | |
| } | |
| void WINAPI IDirect3DDevice8Impl_SetGammaRamp(LPDIRECT3DDEVICE8 iface, DWORD Flags, CONST D3DGAMMARAMP* pRamp) { | |
| HDC hDC; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : pRamp@%p\n", This, pRamp); | |
| hDC = GetDC(This->win_handle); | |
| SetDeviceGammaRamp(hDC, (LPVOID) pRamp); | |
| ReleaseDC(This->win_handle, hDC); | |
| return; | |
| } | |
| void WINAPI IDirect3DDevice8Impl_GetGammaRamp(LPDIRECT3DDEVICE8 iface, D3DGAMMARAMP* pRamp) { | |
| HDC hDC; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : pRamp@%p\n", This, pRamp); | |
| hDC = GetDC(This->win_handle); | |
| GetDeviceGammaRamp(hDC, pRamp); | |
| ReleaseDC(This->win_handle, hDC); | |
| return; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateTexture(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, UINT Levels, DWORD Usage, | |
| D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture8** ppTexture) { | |
| IDirect3DTexture8Impl *object; | |
| unsigned int i; | |
| UINT tmpW; | |
| UINT tmpH; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| /* Allocate the storage for the device */ | |
| TRACE("(%p) : W(%d) H(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%d)\n", This, Width, Height, Levels, Usage, Format, debug_d3dformat(Format), Pool); | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DTexture8Impl)); | |
| object->lpVtbl = &Direct3DTexture8_Vtbl; | |
| object->Device = This; | |
| object->ResourceType = D3DRTYPE_TEXTURE; | |
| object->ref = 1; | |
| object->width = Width; | |
| object->height = Height; | |
| object->levels = Levels; | |
| object->usage = Usage; | |
| object->format = Format; | |
| /* Calculate levels for mip mapping */ | |
| if (Levels == 0) { | |
| object->levels++; | |
| tmpW = Width; | |
| tmpH = Height; | |
| while (tmpW > 1 && tmpH > 1) { | |
| tmpW = max(1, tmpW / 2); | |
| tmpH = max(1, tmpH / 2); | |
| object->levels++; | |
| } | |
| TRACE("Calculated levels = %d\n", object->levels); | |
| } | |
| /* Generate all the surfaces */ | |
| tmpW = Width; | |
| tmpH = Height; | |
| for (i = 0; i < object->levels; i++) | |
| { | |
| IDirect3DDevice8Impl_CreateImageSurface(iface, tmpW, tmpH, Format, (LPDIRECT3DSURFACE8*) &object->surfaces[i]); | |
| object->surfaces[i]->Container = (IUnknown*) object; | |
| object->surfaces[i]->myDesc.Usage = Usage; | |
| object->surfaces[i]->myDesc.Pool = Pool; | |
| /** | |
| * As written in msdn in IDirect3DTexture8::LockRect | |
| * Textures created in D3DPOOL_DEFAULT are not lockable. | |
| */ | |
| if (D3DPOOL_DEFAULT == Pool) { | |
| object->surfaces[i]->lockable = FALSE; | |
| } | |
| TRACE("Created surface level %d @ %p, memory at %p\n", i, object->surfaces[i], object->surfaces[i]->allocatedMemory); | |
| tmpW = max(1, tmpW / 2); | |
| tmpH = max(1, tmpH / 2); | |
| } | |
| *ppTexture = (LPDIRECT3DTEXTURE8) object; | |
| TRACE("(%p) : Created texture %p\n", This, object); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateVolumeTexture(LPDIRECT3DDEVICE8 iface, | |
| UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, | |
| D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture8** ppVolumeTexture) { | |
| IDirect3DVolumeTexture8Impl *object; | |
| unsigned int i; | |
| UINT tmpW; | |
| UINT tmpH; | |
| UINT tmpD; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| /* Allocate the storage for it */ | |
| TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, Width, Height, Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool)); | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVolumeTexture8Impl)); | |
| object->lpVtbl = &Direct3DVolumeTexture8_Vtbl; | |
| object->ResourceType = D3DRTYPE_VOLUMETEXTURE; | |
| object->Device = This; | |
| object->ref = 1; | |
| object->width = Width; | |
| object->height = Height; | |
| object->depth = Depth; | |
| object->levels = Levels; | |
| object->usage = Usage; | |
| object->format = Format; | |
| /* Calculate levels for mip mapping */ | |
| if (Levels == 0) { | |
| object->levels++; | |
| tmpW = Width; | |
| tmpH = Height; | |
| tmpD = Depth; | |
| while (tmpW > 1 && tmpH > 1 && tmpD > 1) { | |
| tmpW = max(1, tmpW / 2); | |
| tmpH = max(1, tmpH / 2); | |
| tmpD = max(1, tmpD / 2); | |
| object->levels++; | |
| } | |
| TRACE("Calculated levels = %d\n", object->levels); | |
| } | |
| /* Generate all the surfaces */ | |
| tmpW = Width; | |
| tmpH = Height; | |
| tmpD = Depth; | |
| for (i = 0; i < object->levels; i++) | |
| { | |
| IDirect3DVolume8Impl* volume; | |
| /* Create the volume - No entry point for this seperately?? */ | |
| volume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVolume8Impl)); | |
| object->volumes[i] = (IDirect3DVolume8Impl *) volume; | |
| volume->lpVtbl = &Direct3DVolume8_Vtbl; | |
| volume->Device = This; | |
| volume->ResourceType = D3DRTYPE_VOLUME; | |
| volume->Container = (IUnknown*) object; | |
| volume->ref = 1; | |
| volume->myDesc.Width = Width; | |
| volume->myDesc.Height = Height; | |
| volume->myDesc.Depth = Depth; | |
| volume->myDesc.Format = Format; | |
| volume->myDesc.Type = D3DRTYPE_VOLUME; | |
| volume->myDesc.Pool = Pool; | |
| volume->myDesc.Usage = Usage; | |
| volume->bytesPerPixel = D3DFmtGetBpp(This, Format); | |
| /* Note: Volume textures cannot be dxtn, hence no need to check here */ | |
| volume->myDesc.Size = (Width * volume->bytesPerPixel) * Height * Depth; | |
| volume->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, volume->myDesc.Size); | |
| volume->lockable = TRUE; | |
| volume->locked = FALSE; | |
| memset(&volume->lockedBox, 0, sizeof(D3DBOX)); | |
| volume->Dirty = FALSE; | |
| IDirect3DVolume8Impl_CleanDirtyBox((LPDIRECT3DVOLUME8) volume); | |
| TRACE("(%p) : Volume at w(%d) h(%d) d(%d) fmt(%u,%s) surf@%p, surfmem@%p, %d bytes\n", | |
| This, Width, Height, Depth, Format, debug_d3dformat(Format), | |
| volume, volume->allocatedMemory, volume->myDesc.Size); | |
| tmpW = max(1, tmpW / 2); | |
| tmpH = max(1, tmpH / 2); | |
| tmpD = max(1, tmpD / 2); | |
| } | |
| *ppVolumeTexture = (LPDIRECT3DVOLUMETEXTURE8) object; | |
| TRACE("(%p) : Created volume texture %p\n", This, object); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateCubeTexture(LPDIRECT3DDEVICE8 iface, UINT EdgeLength, UINT Levels, DWORD Usage, | |
| D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture8** ppCubeTexture) { | |
| IDirect3DCubeTexture8Impl *object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| unsigned int i,j; | |
| UINT tmpW; | |
| /* Allocate the storage for it */ | |
| TRACE("(%p) : Len(%d), Lvl(%d) Usage(%ld), Fmt(%u,%s), Pool(%s)\n", This, EdgeLength, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool)); | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DCubeTexture8Impl)); | |
| object->lpVtbl = &Direct3DCubeTexture8_Vtbl; | |
| object->ref = 1; | |
| object->Device = This; | |
| object->ResourceType = D3DRTYPE_CUBETEXTURE; | |
| object->edgeLength = EdgeLength; | |
| object->levels = Levels; | |
| object->usage = Usage; | |
| object->format = Format; | |
| /* Calculate levels for mip mapping */ | |
| if (Levels == 0) { | |
| object->levels++; | |
| tmpW = EdgeLength; | |
| while (tmpW > 1) { | |
| tmpW = max(1, tmpW / 2); | |
| object->levels++; | |
| } | |
| TRACE("Calculated levels = %d\n", object->levels); | |
| } | |
| /* Generate all the surfaces */ | |
| tmpW = EdgeLength; | |
| for (i = 0; i < object->levels; i++) { | |
| /* Create the 6 faces */ | |
| for (j = 0; j < 6; j++) { | |
| IDirect3DDevice8Impl_CreateImageSurface(iface, tmpW, tmpW, Format, (LPDIRECT3DSURFACE8*) &object->surfaces[j][i]); | |
| object->surfaces[j][i]->Container = (IUnknown*) object; | |
| object->surfaces[j][i]->myDesc.Usage = Usage; | |
| object->surfaces[j][i]->myDesc.Pool = Pool; | |
| /** | |
| * As written in msdn in IDirect3DCubeTexture8::LockRect | |
| * Textures created in D3DPOOL_DEFAULT are not lockable. | |
| */ | |
| if (D3DPOOL_DEFAULT == Pool) { | |
| object->surfaces[j][i]->lockable = FALSE; | |
| } | |
| TRACE("Created surface level %d @ %p, memory at %p\n", i, object->surfaces[j][i], object->surfaces[j][i]->allocatedMemory); | |
| } | |
| tmpW = max(1, tmpW / 2); | |
| } | |
| TRACE("(%p) : Iface@%p\n", This, object); | |
| *ppCubeTexture = (LPDIRECT3DCUBETEXTURE8) object; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateVertexBuffer(LPDIRECT3DDEVICE8 iface, UINT Size, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer8** ppVertexBuffer) { | |
| IDirect3DVertexBuffer8Impl *object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| /* Allocate the storage for the device */ | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DVertexBuffer8Impl)); | |
| object->lpVtbl = &Direct3DVertexBuffer8_Vtbl; | |
| object->Device = This; | |
| object->ResourceType = D3DRTYPE_VERTEXBUFFER; | |
| object->ref = 1; | |
| object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size); | |
| object->currentDesc.Usage = Usage; | |
| object->currentDesc.Pool = Pool; | |
| object->currentDesc.FVF = FVF; | |
| object->currentDesc.Size = Size; | |
| TRACE("(%p) : Size=%d, Usage=%ld, FVF=%lx, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->allocatedMemory, object); | |
| *ppVertexBuffer = (LPDIRECT3DVERTEXBUFFER8) object; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateIndexBuffer(LPDIRECT3DDEVICE8 iface, UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer8** ppIndexBuffer) { | |
| IDirect3DIndexBuffer8Impl *object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : Len=%d, Use=%lx, Format=(%u,%s), Pool=%d\n", This, Length, Usage, Format, debug_d3dformat(Format), Pool); | |
| /* Allocate the storage for the device */ | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DIndexBuffer8Impl)); | |
| object->lpVtbl = &Direct3DIndexBuffer8_Vtbl; | |
| object->Device = This; | |
| object->ref = 1; | |
| object->ResourceType = D3DRTYPE_INDEXBUFFER; | |
| object->currentDesc.Type = D3DRTYPE_INDEXBUFFER; | |
| object->currentDesc.Usage = Usage; | |
| object->currentDesc.Pool = Pool; | |
| object->currentDesc.Format = Format; | |
| object->currentDesc.Size = Length; | |
| object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Length); | |
| TRACE("(%p) : Iface@%p allocatedMem @ %p\n", This, object, object->allocatedMemory); | |
| *ppIndexBuffer = (LPDIRECT3DINDEXBUFFER8) object; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateRenderTarget(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, BOOL Lockable, IDirect3DSurface8** ppSurface) { | |
| IDirect3DSurface8Impl *object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DSurface8Impl)); | |
| if (NULL == object) { | |
| *ppSurface = NULL; | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| *ppSurface = (LPDIRECT3DSURFACE8) object; | |
| object->lpVtbl = &Direct3DSurface8_Vtbl; | |
| object->Device = This; | |
| object->ResourceType = D3DRTYPE_SURFACE; | |
| object->Container = (IUnknown*) This; | |
| object->ref = 1; | |
| object->myDesc.Width = Width; | |
| object->myDesc.Height = Height; | |
| object->myDesc.Format = Format; | |
| object->myDesc.Type = D3DRTYPE_SURFACE; | |
| object->myDesc.Usage = D3DUSAGE_RENDERTARGET; | |
| object->myDesc.Pool = D3DPOOL_DEFAULT; | |
| object->myDesc.MultiSampleType = MultiSample; | |
| object->bytesPerPixel = D3DFmtGetBpp(This, Format); | |
| if (Format == D3DFMT_DXT1) { | |
| object->myDesc.Size = (Width * object->bytesPerPixel)/2 * Height; /* DXT1 is half byte per pixel */ | |
| } else { | |
| object->myDesc.Size = (Width * object->bytesPerPixel) * Height; | |
| } | |
| object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->myDesc.Size); | |
| object->lockable = Lockable; | |
| object->locked = FALSE; | |
| memset(&object->lockedRect, 0, sizeof(RECT)); | |
| IDirect3DSurface8Impl_CleanDirtyRect((LPDIRECT3DSURFACE8) object); | |
| 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), Lockable, *ppSurface, object->allocatedMemory, object->myDesc.Size); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateDepthStencilSurface(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, IDirect3DSurface8** ppSurface) { | |
| IDirect3DSurface8Impl *object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DSurface8Impl)); | |
| if (NULL == object) { | |
| *ppSurface = NULL; | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| *ppSurface = (LPDIRECT3DSURFACE8) object; | |
| object->lpVtbl = &Direct3DSurface8_Vtbl; | |
| object->Device = This; | |
| object->ResourceType = D3DRTYPE_SURFACE; | |
| object->Container = (IUnknown*) This; | |
| object->ref = 1; | |
| object->myDesc.Width = Width; | |
| object->myDesc.Height = Height; | |
| object->myDesc.Format = Format; | |
| object->myDesc.Type = D3DRTYPE_SURFACE; | |
| object->myDesc.Usage = D3DUSAGE_DEPTHSTENCIL; | |
| object->myDesc.Pool = D3DPOOL_DEFAULT; | |
| object->myDesc.MultiSampleType = MultiSample; | |
| object->bytesPerPixel = D3DFmtGetBpp(This, Format); | |
| if (Format == D3DFMT_DXT1) { | |
| object->myDesc.Size = (Width * object->bytesPerPixel)/2 * Height; /* DXT1 is half byte per pixel */ | |
| } else { | |
| object->myDesc.Size = (Width * object->bytesPerPixel) * Height; | |
| } | |
| object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->myDesc.Size); | |
| object->lockable = (D3DFMT_D16_LOCKABLE == Format) ? TRUE : FALSE; | |
| object->locked = FALSE; | |
| memset(&object->lockedRect, 0, sizeof(RECT)); | |
| IDirect3DSurface8Impl_CleanDirtyRect((LPDIRECT3DSURFACE8) object); | |
| TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) surf@%p, surfmem@%p, %d bytes\n", This, Width, Height, Format, debug_d3dformat(Format), *ppSurface, object->allocatedMemory, object->myDesc.Size); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateImageSurface(LPDIRECT3DDEVICE8 iface, UINT Width, UINT Height, D3DFORMAT Format, IDirect3DSurface8** ppSurface) { | |
| IDirect3DSurface8Impl *object; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DSurface8Impl)); | |
| *ppSurface = (LPDIRECT3DSURFACE8) object; | |
| object->lpVtbl = &Direct3DSurface8_Vtbl; | |
| object->Device = This; | |
| object->ResourceType = D3DRTYPE_SURFACE; | |
| object->Container = (IUnknown*) This; | |
| object->ref = 1; | |
| object->myDesc.Width = Width; | |
| object->myDesc.Height = Height; | |
| object->myDesc.Format = Format; | |
| object->myDesc.Type = D3DRTYPE_SURFACE; | |
| object->myDesc.Usage = 0; | |
| object->myDesc.Pool = D3DPOOL_SYSTEMMEM; | |
| object->bytesPerPixel = D3DFmtGetBpp(This, Format); | |
| /* 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 (Format == D3DFMT_DXT1) { | |
| object->myDesc.Size = ((max(Width,4) * object->bytesPerPixel) * max(Height,4)) / 2; /* DXT1 is half byte per pixel */ | |
| } else if (Format == D3DFMT_DXT2 || Format == D3DFMT_DXT3 || | |
| Format == D3DFMT_DXT4 || Format == D3DFMT_DXT5) { | |
| object->myDesc.Size = ((max(Width,4) * object->bytesPerPixel) * max(Height,4)); | |
| } else { | |
| object->myDesc.Size = (Width * object->bytesPerPixel) * Height; | |
| } | |
| object->allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->myDesc.Size); | |
| object->lockable = TRUE; | |
| object->locked = FALSE; | |
| memset(&object->lockedRect, 0, sizeof(RECT)); | |
| IDirect3DSurface8Impl_CleanDirtyRect((LPDIRECT3DSURFACE8) object); | |
| TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) surf@%p, surfmem@%p, %d bytes\n", This, Width, Height, Format, debug_d3dformat(Format), *ppSurface, object->allocatedMemory, object->myDesc.Size); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CopyRects(LPDIRECT3DDEVICE8 iface, | |
| IDirect3DSurface8* pSourceSurface, CONST RECT* pSourceRectsArray, UINT cRects, | |
| IDirect3DSurface8* pDestinationSurface, CONST POINT* pDestPointsArray) { | |
| HRESULT rc = D3D_OK; | |
| IDirect3DBaseTexture8* texture = NULL; | |
| IDirect3DSurface8Impl* src = (IDirect3DSurface8Impl*) pSourceSurface; | |
| IDirect3DSurface8Impl* dst = (IDirect3DSurface8Impl*) pDestinationSurface; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) pSrcSur=%p, pSourceRects=%p, cRects=%d, pDstSur=%p, pDestPtsArr=%p\n", This, | |
| pSourceSurface, pSourceRectsArray, cRects, pDestinationSurface, pDestPointsArray); | |
| /* Note: Not sure about the d3dfmt_unknown bit, but seems to avoid a problem inside | |
| a sample and doesn't seem to break anything as far as I can tell */ | |
| if (src->myDesc.Format != dst->myDesc.Format && (dst->myDesc.Format != D3DFMT_UNKNOWN)) { | |
| TRACE("Formats do not match (%x,%s) / (%x,%s)\n", | |
| src->myDesc.Format, debug_d3dformat(src->myDesc.Format), | |
| dst->myDesc.Format, debug_d3dformat(dst->myDesc.Format)); | |
| rc = D3DERR_INVALIDCALL; | |
| } else if (dst->myDesc.Format == D3DFMT_UNKNOWN) { | |
| TRACE("Converting dest to same format as source, since dest was unknown\n"); | |
| dst->myDesc.Format = src->myDesc.Format; | |
| /* Convert container as well */ | |
| rc = IDirect3DSurface8Impl_GetContainer((LPDIRECT3DSURFACE8) dst, &IID_IDirect3DBaseTexture8, (void**) &texture); /* FIXME: Which refid? */ | |
| if (SUCCEEDED(rc) && NULL != texture) { | |
| ((IDirect3DBaseTexture8Impl*) texture)->format = src->myDesc.Format; | |
| /** Releasing texture after GetContainer */ | |
| IDirect3DBaseTexture8_Release(texture); | |
| texture = NULL; | |
| } | |
| } | |
| /* Quick if complete copy ... */ | |
| if (SUCCEEDED(rc)) { | |
| if (cRects == 0 && pSourceRectsArray == NULL && pDestPointsArray == NULL) { | |
| if (src->myDesc.Width == dst->myDesc.Width && src->myDesc.Height == dst->myDesc.Height) { | |
| D3DLOCKED_RECT lrSrc; | |
| D3DLOCKED_RECT lrDst; | |
| IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) src, &lrSrc, NULL, D3DLOCK_READONLY); | |
| IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) dst, &lrDst, NULL, 0L); | |
| TRACE("Locked src and dst, Direct copy as surfaces are equal, w=%d, h=%d\n", dst->myDesc.Width, dst->myDesc.Height); | |
| memcpy(lrDst.pBits, lrSrc.pBits, src->myDesc.Size); | |
| IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) src); | |
| rc = IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) dst); | |
| TRACE("Unlocked src and dst\n"); | |
| } else { | |
| FIXME("Wanted to copy all surfaces but size not compatible\n"); | |
| rc = D3DERR_INVALIDCALL; | |
| } | |
| } else { | |
| if (NULL != pSourceRectsArray && NULL != pDestPointsArray) { | |
| int bytesPerPixel = ((IDirect3DSurface8Impl*) pSourceSurface)->bytesPerPixel; | |
| unsigned int i; | |
| /* Copy rect by rect */ | |
| for (i = 0; i < cRects; i++) { | |
| CONST RECT* r = &pSourceRectsArray[i]; | |
| CONST POINT* p = &pDestPointsArray[i]; | |
| int copyperline; | |
| int j; | |
| D3DLOCKED_RECT lrSrc; | |
| D3DLOCKED_RECT lrDst; | |
| RECT dest_rect; | |
| TRACE("Copying rect %d (%ld,%ld),(%ld,%ld) -> (%ld,%ld)\n", i, r->left, r->top, r->right, r->bottom, p->x, p->y); | |
| if (src->myDesc.Format == D3DFMT_DXT1) { | |
| copyperline = ((r->right - r->left) * bytesPerPixel)/2; /* DXT1 is half byte per pixel */ | |
| } else { | |
| copyperline = ((r->right - r->left) * bytesPerPixel); | |
| } | |
| IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) src, &lrSrc, r, D3DLOCK_READONLY); | |
| dest_rect.left = p->x; | |
| dest_rect.top = p->y; | |
| dest_rect.right = p->x + (r->right - r->left); | |
| dest_rect.bottom= p->y + (r->bottom - r->top); | |
| IDirect3DSurface8Impl_LockRect((LPDIRECT3DSURFACE8) dst, &lrDst, &dest_rect, 0L); | |
| TRACE("Locked src and dst\n"); | |
| /* Find where to start */ | |
| for (j = 0; j < (r->bottom - r->top - 1); j++) { | |
| memcpy((char*) lrDst.pBits + (j * lrDst.Pitch), (char*) lrSrc.pBits + (j * lrSrc.Pitch), copyperline); | |
| } | |
| IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) src); | |
| rc = IDirect3DSurface8Impl_UnlockRect((LPDIRECT3DSURFACE8) dst); | |
| TRACE("Unlocked src and dst\n"); | |
| } | |
| } else { | |
| FIXME("Wanted to copy partial surfaces not implemented\n"); | |
| rc = D3DERR_INVALIDCALL; | |
| } | |
| } | |
| } | |
| return rc; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_UpdateTexture(LPDIRECT3DDEVICE8 iface, IDirect3DBaseTexture8* pSourceTexture, IDirect3DBaseTexture8* pDestinationTexture) { | |
| IDirect3DBaseTexture8Impl* src = (IDirect3DBaseTexture8Impl*) pSourceTexture; | |
| IDirect3DBaseTexture8Impl* dst = (IDirect3DBaseTexture8Impl*) pDestinationTexture; | |
| D3DRESOURCETYPE srcType; | |
| D3DRESOURCETYPE dstType; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : first try\n", This); | |
| srcType = IDirect3DBaseTexture8Impl_GetType(pSourceTexture); | |
| dstType = IDirect3DBaseTexture8Impl_GetType(pDestinationTexture); | |
| if (srcType != dstType) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (D3DPOOL_SYSTEMMEM != IDirect3DResource8Impl_GetPool((LPDIRECT3DRESOURCE8) src)) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (D3DPOOL_DEFAULT != IDirect3DResource8Impl_GetPool((LPDIRECT3DRESOURCE8) dst)) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (IDirect3DBaseTexture8Impl_IsDirty(pSourceTexture)) { | |
| /** Only copy Dirty textures */ | |
| DWORD srcLevelCnt = IDirect3DBaseTexture8Impl_GetLevelCount(pSourceTexture); | |
| DWORD dstLevelCnt = IDirect3DBaseTexture8Impl_GetLevelCount(pDestinationTexture); | |
| DWORD skipLevels = (dstLevelCnt < srcLevelCnt) ? srcLevelCnt - dstLevelCnt : 0; | |
| UINT i, j; | |
| for (i = skipLevels; i < srcLevelCnt; ++i) { | |
| HRESULT hr; | |
| switch (srcType) { | |
| case D3DRTYPE_TEXTURE: | |
| { | |
| IDirect3DSurface8* srcSur = NULL; | |
| IDirect3DSurface8* dstSur = NULL; | |
| hr = IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) src, i, &srcSur); | |
| hr = IDirect3DTexture8Impl_GetSurfaceLevel((LPDIRECT3DTEXTURE8) dst, i - skipLevels, &dstSur); | |
| /* Fixme: Work out how to just do the dirty regions (src or dst dirty region, and what | |
| about dst with less levels than the source?) */ | |
| IDirect3DDevice8Impl_CopyRects(iface, srcSur, NULL, 0, dstSur, NULL); | |
| IDirect3DSurface8Impl_Release(srcSur); | |
| IDirect3DSurface8Impl_Release(dstSur); | |
| } | |
| break; | |
| case D3DRTYPE_VOLUMETEXTURE: | |
| { | |
| FIXME("D3DRTYPE_VOLUMETEXTURE reload currently not implemented\n"); | |
| } | |
| break; | |
| case D3DRTYPE_CUBETEXTURE: | |
| { | |
| IDirect3DSurface8* srcSur = NULL; | |
| IDirect3DSurface8* dstSur = NULL; | |
| for (j = 0; j < 5; ++j) { | |
| hr = IDirect3DCubeTexture8Impl_GetCubeMapSurface((LPDIRECT3DCUBETEXTURE8) src, j, i, &srcSur); | |
| hr = IDirect3DCubeTexture8Impl_GetCubeMapSurface((LPDIRECT3DCUBETEXTURE8) dst, j, i - skipLevels, &srcSur); | |
| FIXME("D3DRTYPE_CUBETEXTURE does not support UpdateTexture yet\n"); | |
| IDirect3DSurface8Impl_Release(srcSur); | |
| IDirect3DSurface8Impl_Release(dstSur); | |
| } | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| IDirect3DBaseTexture8Impl_SetDirty(pSourceTexture, FALSE); | |
| } | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetFrontBuffer(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8* pDestSurface) { | |
| HRESULT hr; | |
| D3DLOCKED_RECT lockedRect; | |
| RECT wantedRect; | |
| GLint prev_store; | |
| GLenum prev_read; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : Should return whole screen, only returns GL context window in top left corner\n", This); | |
| if (D3DFMT_A8R8G8B8 != ((IDirect3DSurface8Impl*) pDestSurface)->myDesc.Format) { | |
| ERR("(%p) : surface(%p) have a invalid format\n", This, pDestSurface); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| wantedRect.left = 0; | |
| wantedRect.top = 0; | |
| wantedRect.right = This->PresentParms.BackBufferWidth; | |
| wantedRect.bottom = This->PresentParms.BackBufferHeight; | |
| hr = IDirect3DSurface8Impl_LockRect(pDestSurface, &lockedRect, &wantedRect, 0); | |
| if (FAILED(hr)) { | |
| ERR("(%p) : cannot lock surface\n", This); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| ENTER_GL(); | |
| glFlush(); | |
| vcheckGLcall("glFlush"); | |
| glGetIntegerv(GL_READ_BUFFER, &prev_read); | |
| vcheckGLcall("glIntegerv"); | |
| glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store); | |
| vcheckGLcall("glIntegerv"); | |
| glReadBuffer(GL_FRONT); | |
| vcheckGLcall("glReadBuffer"); | |
| glPixelStorei(GL_PACK_SWAP_BYTES, TRUE); | |
| vcheckGLcall("glPixelStorei"); | |
| /* stupid copy */ | |
| { | |
| unsigned long j; | |
| for (j = 0; j < This->PresentParms.BackBufferHeight; ++j) { | |
| glReadPixels(0, This->PresentParms.BackBufferHeight - j - 1, This->PresentParms.BackBufferWidth, 1, | |
| GL_BGRA, GL_UNSIGNED_BYTE, ((char*) lockedRect.pBits) + (j * lockedRect.Pitch)); | |
| vcheckGLcall("glReadPixels"); | |
| } | |
| } | |
| glPixelStorei(GL_PACK_SWAP_BYTES, prev_store); | |
| vcheckGLcall("glPixelStorei"); | |
| glReadBuffer(prev_read); | |
| vcheckGLcall("glReadBuffer"); | |
| LEAVE_GL(); | |
| hr = IDirect3DSurface8Impl_UnlockRect(pDestSurface); | |
| return hr; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetRenderTarget(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8* pRenderTarget, IDirect3DSurface8* pNewZStencil) { | |
| HRESULT hr = D3D_OK; | |
| D3DVIEWPORT8 viewport; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| /* If pRenderTarget == NULL, it seems to default to back buffer */ | |
| if (pRenderTarget == NULL) pRenderTarget = (IDirect3DSurface8*)This->backBuffer; | |
| /* For ease of code later on, handle a null depth as leave alone | |
| - Have not tested real d3d for this case but doing this avoids | |
| numerous null pointer checks */ | |
| if (pNewZStencil == NULL) pNewZStencil = (IDirect3DSurface8*)This->stencilBufferTarget; | |
| /* If we are trying to set what we already have, don't bother */ | |
| if ((IDirect3DSurface8Impl*) pRenderTarget == This->renderTarget && (IDirect3DSurface8Impl*) pNewZStencil == This->stencilBufferTarget) { | |
| TRACE("Trying to do a NOP SetRenderTarget operation\n"); | |
| } else { | |
| /* Otherwise, set the render target up */ | |
| TRACE("(%p) : newRender@%p newZStencil@%p (default is backbuffer=(%p))\n", This, pRenderTarget, pNewZStencil, This->backBuffer); | |
| IDirect3DDevice8Impl_CleanRender(iface); | |
| hr = IDirect3DDevice8Impl_ActiveRender(iface, pRenderTarget, pNewZStencil); | |
| } | |
| if (SUCCEEDED(hr)) { | |
| /* Finally, reset the viewport as the MSDN states. */ | |
| viewport.Height = ((IDirect3DSurface8Impl*)pRenderTarget)->myDesc.Height; | |
| viewport.Width = ((IDirect3DSurface8Impl*)pRenderTarget)->myDesc.Width; | |
| viewport.X = 0; | |
| viewport.Y = 0; | |
| viewport.MaxZ = 1.0f; | |
| viewport.MinZ = 0.0f; | |
| IDirect3DDevice8Impl_SetViewport(iface, &viewport); | |
| } | |
| return hr; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetRenderTarget(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8** ppRenderTarget) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)->returning (%p) default is backbuffer=(%p)\n", This, This->renderTarget, This->backBuffer); | |
| *ppRenderTarget = (LPDIRECT3DSURFACE8) This->renderTarget; | |
| IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) *ppRenderTarget); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetDepthStencilSurface(LPDIRECT3DDEVICE8 iface, IDirect3DSurface8** ppZStencilSurface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)->(%p) default(%p)\n", This, This->stencilBufferTarget, This->depthStencilBuffer); | |
| /* Note inc ref on returned surface */ | |
| *ppZStencilSurface = (LPDIRECT3DSURFACE8) This->stencilBufferTarget; | |
| if (NULL != *ppZStencilSurface) IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) *ppZStencilSurface); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_BeginScene(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| return IWineD3DDevice_BeginScene(This->WineD3DDevice); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_EndScene(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DBaseTexture8* cont = NULL; | |
| HRESULT hr; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| ENTER_GL(); | |
| glFlush(); | |
| checkGLcall("glFlush"); | |
| #if 0 /* Useful for debugging sometimes! */ | |
| printf("Hit Enter ...\n"); | |
| getchar(); | |
| #endif | |
| if ((This->frontBuffer != This->renderTarget) && (This->backBuffer != This->renderTarget)) { | |
| #if 0 | |
| GLenum prev_read; | |
| glGetIntegerv(GL_READ_BUFFER, &prev_read); | |
| vcheckGLcall("glIntegerv"); | |
| glReadBuffer(GL_FRONT); | |
| vcheckGLcall("glReadBuffer"); | |
| { | |
| long j; | |
| long pitch = This->renderTarget->myDesc.Width * This->renderTarget->bytesPerPixel; | |
| if (This->renderTarget->myDesc.Format == D3DFMT_DXT1) /* DXT1 is half byte per pixel */ | |
| pitch = pitch / 2; | |
| for (j = 0; j < This->renderTarget->myDesc.Height; ++j) { | |
| glReadPixels(0, | |
| This->renderTarget->myDesc.Height - j - 1, | |
| This->renderTarget->myDesc.Width, | |
| 1, | |
| D3DFmt2GLFmt(This, This->renderTarget->myDesc.Format), | |
| D3DFmt2GLType(This, This->renderTarget->myDesc.Format), | |
| This->renderTarget->allocatedMemory + j * pitch); | |
| vcheckGLcall("glReadPixels"); | |
| } | |
| } | |
| glReadBuffer(prev_read); | |
| vcheckGLcall("glReadBuffer"); | |
| #endif | |
| hr = IDirect3DSurface8_GetContainer((LPDIRECT3DSURFACE8) This->renderTarget, &IID_IDirect3DBaseTexture8, (void**) &cont); | |
| if (SUCCEEDED(hr) && NULL != cont) { | |
| /** always dirtify for now. we must find a better way to see that surface have been modified */ | |
| This->renderTarget->inPBuffer = TRUE; | |
| This->renderTarget->inTexture = FALSE; | |
| IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE); | |
| IDirect3DBaseTexture8_PreLoad(cont); | |
| This->renderTarget->inPBuffer = FALSE; | |
| IDirect3DBaseTexture8Impl_Release(cont); | |
| cont = NULL; | |
| } | |
| } | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_Clear(LPDIRECT3DDEVICE8 iface, DWORD Count, CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| /* TODO: From MSDN This method fails if you specify the D3DCLEAR_ZBUFFER or D3DCLEAR_STENCIL flags when the | |
| render target does not have an attached depth buffer. Similarly, if you specify the D3DCLEAR_STENCIL flag | |
| when the depth-buffer format does not contain stencil buffer information, this method fails. */ | |
| GLbitfield glMask = 0; | |
| GLboolean old_ztest; | |
| GLfloat old_z_clear_value; | |
| GLint old_stencil_clear_value; | |
| GLfloat old_color_clear_value[4]; | |
| unsigned int i; | |
| CONST D3DRECT* curRect; | |
| TRACE("(%p) Count (%ld), pRects (%p), Flags (%lx), Z (%f), Stencil (%ld)\n", This, | |
| Count, pRects, Flags, Z, Stencil); | |
| ENTER_GL(); | |
| glEnable(GL_SCISSOR_TEST); | |
| checkGLcall("glEnable GL_SCISSOR_TEST"); | |
| if (Count > 0 && pRects) { | |
| curRect = pRects; | |
| } else { | |
| curRect = NULL; | |
| } | |
| /* Only set the values up once, as they are not changing */ | |
| if (Flags & D3DCLEAR_STENCIL) { | |
| glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value); | |
| glClearStencil(Stencil); | |
| checkGLcall("glClearStencil"); | |
| glMask = glMask | GL_STENCIL_BUFFER_BIT; | |
| glStencilMask(0xFFFFFFFF); | |
| } | |
| if (Flags & D3DCLEAR_ZBUFFER) { | |
| glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest); | |
| glDepthMask(GL_TRUE); | |
| glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value); | |
| glClearDepth(Z); | |
| checkGLcall("glClearDepth"); | |
| glMask = glMask | GL_DEPTH_BUFFER_BIT; | |
| } | |
| if (Flags & D3DCLEAR_TARGET) { | |
| TRACE("Clearing screen with glClear to color %lx\n", Color); | |
| glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value); | |
| glClearColor(((Color >> 16) & 0xFF) / 255.0f, | |
| ((Color >> 8) & 0xFF) / 255.0f, | |
| ((Color >> 0) & 0xFF) / 255.0f, | |
| ((Color >> 24) & 0xFF) / 255.0f); | |
| checkGLcall("glClearColor"); | |
| /* Clear ALL colors! */ | |
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |
| glMask = glMask | GL_COLOR_BUFFER_BIT; | |
| } | |
| /* Now process each rect in turn */ | |
| for (i = 0; i < Count || i == 0; i++) { | |
| if (curRect) { | |
| /* Note gl uses lower left, width/height */ | |
| TRACE("(%p) %p Rect=(%ld,%ld)->(%ld,%ld) glRect=(%ld,%ld), len=%ld, hei=%ld\n", This, curRect, | |
| curRect->x1, curRect->y1, curRect->x2, curRect->y2, | |
| curRect->x1, (This->renderTarget->myDesc.Height - curRect->y2), | |
| curRect->x2 - curRect->x1, curRect->y2 - curRect->y1); | |
| glScissor(curRect->x1, (This->renderTarget->myDesc.Height - curRect->y2), | |
| curRect->x2 - curRect->x1, curRect->y2 - curRect->y1); | |
| checkGLcall("glScissor"); | |
| } else { | |
| glScissor(This->StateBlock->viewport.X, | |
| (This->renderTarget->myDesc.Height - (This->StateBlock->viewport.Y + This->StateBlock->viewport.Height)), | |
| This->StateBlock->viewport.Width, | |
| This->StateBlock->viewport.Height); | |
| checkGLcall("glScissor"); | |
| } | |
| /* Clear the selected rectangle (or full screen) */ | |
| glClear(glMask); | |
| checkGLcall("glClear"); | |
| /* Step to the next rectangle */ | |
| if (curRect) curRect = curRect + sizeof(D3DRECT); | |
| } | |
| /* Restore the old values (why..?) */ | |
| if (Flags & D3DCLEAR_STENCIL) { | |
| glClearStencil(old_stencil_clear_value); | |
| glStencilMask(This->StateBlock->renderstate[D3DRS_STENCILWRITEMASK]); | |
| } | |
| if (Flags & D3DCLEAR_ZBUFFER) { | |
| glDepthMask(old_ztest); | |
| glClearDepth(old_z_clear_value); | |
| } | |
| if (Flags & D3DCLEAR_TARGET) { | |
| glClearColor(old_color_clear_value[0], | |
| old_color_clear_value[1], | |
| old_color_clear_value[2], | |
| old_color_clear_value[3]); | |
| glColorMask(This->StateBlock->renderstate[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE, | |
| This->StateBlock->renderstate[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE, | |
| This->StateBlock->renderstate[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE, | |
| This->StateBlock->renderstate[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE); | |
| } | |
| glDisable(GL_SCISSOR_TEST); | |
| checkGLcall("glDisable"); | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE d3dts, CONST D3DMATRIX* lpmatrix) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| unsigned int k; | |
| /* Most of this routine, comments included copied from ddraw tree initially: */ | |
| TRACE("(%p) : State=%d\n", This, d3dts); | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| This->UpdateStateBlock->Changed.transform[d3dts] = TRUE; | |
| This->UpdateStateBlock->Set.transform[d3dts] = TRUE; | |
| memcpy(&This->UpdateStateBlock->transforms[d3dts], lpmatrix, sizeof(D3DMATRIX)); | |
| return D3D_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 dumb reason. | |
| * | |
| * From here on we assume that the new matrix is different, wherever it matters | |
| * but note | |
| */ | |
| if (!memcmp(&This->StateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(D3DMATRIX))) { | |
| TRACE("The app is setting the same matrix over again\n"); | |
| return D3D_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 */ | |
| if (d3dts == D3DTS_WORLDMATRIX(0)) { | |
| This->modelview_valid = FALSE; | |
| return D3D_OK; | |
| } else if (d3dts == D3DTS_PROJECTION) { | |
| This->proj_valid = FALSE; | |
| return D3D_OK; | |
| } else if (d3dts >= D3DTS_WORLDMATRIX(1) && d3dts <= D3DTS_WORLDMATRIX(255)) { /* Indexed Vertex Blending Matrices 256 -> 511 */ | |
| /* Use arb_vertex_blend or NV_VERTEX_WEIGHTING? */ | |
| FIXME("D3DTS_WORLDMATRIX(1..255) not handled\n"); | |
| return D3D_OK; | |
| } | |
| /* Chances are we really are going to have to change a matrix */ | |
| ENTER_GL(); | |
| if (d3dts >= D3DTS_TEXTURE0 && d3dts <= D3DTS_TEXTURE7) { /* handle texture matrices */ | |
| if (d3dts < GL_LIMITS(textures)) { | |
| int tex = d3dts - D3DTS_TEXTURE0; | |
| #if defined(GL_VERSION_1_3) | |
| glActiveTexture(GL_TEXTURE0 + tex); | |
| checkGLcall("glActiveTexture"); | |
| #else | |
| glActiveTextureARB(GL_TEXTURE0_ARB + tex); | |
| checkGLcall("glActiveTextureARB"); | |
| #endif | |
| set_texture_matrix((const float *)lpmatrix, This->UpdateStateBlock->texture_state[tex][D3DTSS_TEXTURETRANSFORMFLAGS]); | |
| } | |
| } else if (d3dts == D3DTS_VIEW) { /* handle the VIEW matrice */ | |
| PLIGHTINFOEL *lightChain = NULL; | |
| float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; | |
| This->modelview_valid = FALSE; | |
| This->view_ident = !memcmp(lpmatrix, identity, 16*sizeof(float)); | |
| glMatrixMode(GL_MODELVIEW); | |
| checkGLcall("glMatrixMode(GL_MODELVIEW)"); | |
| glPushMatrix(); | |
| glLoadMatrixf((const float *)lpmatrix); | |
| checkGLcall("glLoadMatrixf(...)"); | |
| /* 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 | |
| */ | |
| /* Reset lights */ | |
| lightChain = This->StateBlock->lights; | |
| while (lightChain && lightChain->glIndex != -1) { | |
| glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_POSITION, lightChain->lightPosn); | |
| checkGLcall("glLightfv posn"); | |
| glLightfv(GL_LIGHT0 + lightChain->glIndex, GL_SPOT_DIRECTION, lightChain->lightDirn); | |
| checkGLcall("glLightfv dirn"); | |
| lightChain = lightChain->next; | |
| } | |
| /* Reset Clipping Planes if clipping is enabled */ | |
| for (k = 0; k < GL_LIMITS(clipplanes); k++) { | |
| glClipPlane(GL_CLIP_PLANE0 + k, This->StateBlock->clipplane[k]); | |
| checkGLcall("glClipPlane"); | |
| } | |
| glPopMatrix(); | |
| } else { /* What was requested!?? */ | |
| WARN("invalid matrix specified: %i\n", d3dts); | |
| } | |
| /* Release lock, all done */ | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE State,D3DMATRIX* pMatrix) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : for State %d\n", This, State); | |
| memcpy(pMatrix, &This->StateBlock->transforms[State], sizeof(D3DMATRIX)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_MultiplyTransform(LPDIRECT3DDEVICE8 iface, D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix) { | |
| D3DMATRIX *mat = NULL; | |
| D3DMATRIX temp; | |
| /* Note: Using UpdateStateBlock means it would be recorded in a state block change, | |
| but works regardless of recording being on. | |
| If this is found to be wrong, change to StateBlock. */ | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : For state %u\n", This, State); | |
| if (State < HIGHEST_TRANSFORMSTATE) | |
| { | |
| mat = &This->UpdateStateBlock->transforms[State]; | |
| } else { | |
| FIXME("Unhandled transform state!!\n"); | |
| } | |
| /* Copied from ddraw code: */ | |
| temp.u.s._11 = (mat->u.s._11 * pMatrix->u.s._11) + (mat->u.s._21 * pMatrix->u.s._12) + (mat->u.s._31 * pMatrix->u.s._13) + (mat->u.s._41 * pMatrix->u.s._14); | |
| temp.u.s._21 = (mat->u.s._11 * pMatrix->u.s._21) + (mat->u.s._21 * pMatrix->u.s._22) + (mat->u.s._31 * pMatrix->u.s._23) + (mat->u.s._41 * pMatrix->u.s._24); | |
| temp.u.s._31 = (mat->u.s._11 * pMatrix->u.s._31) + (mat->u.s._21 * pMatrix->u.s._32) + (mat->u.s._31 * pMatrix->u.s._33) + (mat->u.s._41 * pMatrix->u.s._34); | |
| temp.u.s._41 = (mat->u.s._11 * pMatrix->u.s._41) + (mat->u.s._21 * pMatrix->u.s._42) + (mat->u.s._31 * pMatrix->u.s._43) + (mat->u.s._41 * pMatrix->u.s._44); | |
| temp.u.s._12 = (mat->u.s._12 * pMatrix->u.s._11) + (mat->u.s._22 * pMatrix->u.s._12) + (mat->u.s._32 * pMatrix->u.s._13) + (mat->u.s._42 * pMatrix->u.s._14); | |
| temp.u.s._22 = (mat->u.s._12 * pMatrix->u.s._21) + (mat->u.s._22 * pMatrix->u.s._22) + (mat->u.s._32 * pMatrix->u.s._23) + (mat->u.s._42 * pMatrix->u.s._24); | |
| temp.u.s._32 = (mat->u.s._12 * pMatrix->u.s._31) + (mat->u.s._22 * pMatrix->u.s._32) + (mat->u.s._32 * pMatrix->u.s._33) + (mat->u.s._42 * pMatrix->u.s._34); | |
| temp.u.s._42 = (mat->u.s._12 * pMatrix->u.s._41) + (mat->u.s._22 * pMatrix->u.s._42) + (mat->u.s._32 * pMatrix->u.s._43) + (mat->u.s._42 * pMatrix->u.s._44); | |
| temp.u.s._13 = (mat->u.s._13 * pMatrix->u.s._11) + (mat->u.s._23 * pMatrix->u.s._12) + (mat->u.s._33 * pMatrix->u.s._13) + (mat->u.s._43 * pMatrix->u.s._14); | |
| temp.u.s._23 = (mat->u.s._13 * pMatrix->u.s._21) + (mat->u.s._23 * pMatrix->u.s._22) + (mat->u.s._33 * pMatrix->u.s._23) + (mat->u.s._43 * pMatrix->u.s._24); | |
| temp.u.s._33 = (mat->u.s._13 * pMatrix->u.s._31) + (mat->u.s._23 * pMatrix->u.s._32) + (mat->u.s._33 * pMatrix->u.s._33) + (mat->u.s._43 * pMatrix->u.s._34); | |
| temp.u.s._43 = (mat->u.s._13 * pMatrix->u.s._41) + (mat->u.s._23 * pMatrix->u.s._42) + (mat->u.s._33 * pMatrix->u.s._43) + (mat->u.s._43 * pMatrix->u.s._44); | |
| temp.u.s._14 = (mat->u.s._14 * pMatrix->u.s._11) + (mat->u.s._24 * pMatrix->u.s._12) + (mat->u.s._34 * pMatrix->u.s._13) + (mat->u.s._44 * pMatrix->u.s._14); | |
| temp.u.s._24 = (mat->u.s._14 * pMatrix->u.s._21) + (mat->u.s._24 * pMatrix->u.s._22) + (mat->u.s._34 * pMatrix->u.s._23) + (mat->u.s._44 * pMatrix->u.s._24); | |
| temp.u.s._34 = (mat->u.s._14 * pMatrix->u.s._31) + (mat->u.s._24 * pMatrix->u.s._32) + (mat->u.s._34 * pMatrix->u.s._33) + (mat->u.s._44 * pMatrix->u.s._34); | |
| temp.u.s._44 = (mat->u.s._14 * pMatrix->u.s._41) + (mat->u.s._24 * pMatrix->u.s._42) + (mat->u.s._34 * pMatrix->u.s._43) + (mat->u.s._44 * pMatrix->u.s._44); | |
| /* Apply change via set transform - will reapply to eg. lights this way */ | |
| IDirect3DDevice8Impl_SetTransform(iface, State, &temp); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetViewport(LPDIRECT3DDEVICE8 iface, CONST D3DVIEWPORT8* pViewport) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| This->UpdateStateBlock->Changed.viewport = TRUE; | |
| This->UpdateStateBlock->Set.viewport = TRUE; | |
| memcpy(&This->UpdateStateBlock->viewport, pViewport, sizeof(D3DVIEWPORT8)); | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| ENTER_GL(); | |
| TRACE("(%p) : x=%ld, y=%ld, wid=%ld, hei=%ld, minz=%f, maxz=%f\n", This, | |
| pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ); | |
| glDepthRange(pViewport->MinZ, pViewport->MaxZ); | |
| checkGLcall("glDepthRange"); | |
| /* Note: GL requires lower left, DirectX supplies upper left */ | |
| glViewport(pViewport->X, (This->renderTarget->myDesc.Height - (pViewport->Y + pViewport->Height)), | |
| pViewport->Width, pViewport->Height); | |
| checkGLcall("glViewport"); | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetViewport(LPDIRECT3DDEVICE8 iface, D3DVIEWPORT8* pViewport) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| memcpy(pViewport, &This->StateBlock->viewport, sizeof(D3DVIEWPORT8)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetMaterial(LPDIRECT3DDEVICE8 iface, CONST D3DMATERIAL8* pMaterial) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| This->UpdateStateBlock->Changed.material = TRUE; | |
| This->UpdateStateBlock->Set.material = TRUE; | |
| memcpy(&This->UpdateStateBlock->material, pMaterial, sizeof(D3DMATERIAL8)); | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| ENTER_GL(); | |
| 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); | |
| glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->UpdateStateBlock->material.Ambient); | |
| checkGLcall("glMaterialfv"); | |
| glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->UpdateStateBlock->material.Diffuse); | |
| checkGLcall("glMaterialfv"); | |
| /* Only change material color if specular is enabled, otherwise it is set to black */ | |
| if (This->StateBlock->renderstate[D3DRS_SPECULARENABLE]) { | |
| glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->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"); | |
| } | |
| glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->UpdateStateBlock->material.Emissive); | |
| checkGLcall("glMaterialfv"); | |
| glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->UpdateStateBlock->material.Power); | |
| checkGLcall("glMaterialf"); | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetMaterial(LPDIRECT3DDEVICE8 iface, D3DMATERIAL8* pMaterial) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| memcpy(pMaterial, &This->UpdateStateBlock->material, sizeof (D3DMATERIAL8)); | |
| 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 D3D_OK; | |
| } | |
| /* 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 are any | |
| one point in time! Therefore since the indexes can be anything, we need a linked list of them. | |
| However, this causes stateblock problems. When capturing the state block, I duplicate the list, | |
| but when recording, just build a chain pretty much of commands to be replayed. */ | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetLight(LPDIRECT3DDEVICE8 iface, DWORD Index, CONST D3DLIGHT8* pLight) { | |
| float rho; | |
| PLIGHTINFOEL *object, *temp; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight); | |
| /* If recording state block, just add to end of lights chain */ | |
| if (This->isRecordingState) { | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL)); | |
| if (NULL == object) { | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| memcpy(&object->OriginalParms, pLight, sizeof(D3DLIGHT8)); | |
| object->OriginalIndex = Index; | |
| object->glIndex = -1; | |
| object->changed = TRUE; | |
| /* Add to the END of the chain of lights changes to be replayed */ | |
| if (This->UpdateStateBlock->lights == NULL) { | |
| This->UpdateStateBlock->lights = object; | |
| } else { | |
| temp = This->UpdateStateBlock->lights; | |
| while (temp->next != NULL) temp=temp->next; | |
| temp->next = object; | |
| } | |
| TRACE("Recording... not performing anything more\n"); | |
| return D3D_OK; | |
| } | |
| /* Ok, not recording any longer so do real work */ | |
| object = This->StateBlock->lights; | |
| while (object != NULL && object->OriginalIndex != Index) object = object->next; | |
| /* If we didn't find it in the list of lights, time to add it */ | |
| if (object == NULL) { | |
| PLIGHTINFOEL *insertAt,*prevPos; | |
| object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL)); | |
| if (NULL == object) { | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| object->OriginalIndex = Index; | |
| object->glIndex = -1; | |
| /* Add it to the front of list with the idea that lights will be changed as needed | |
| BUT after any lights currently assigned GL indexes */ | |
| insertAt = This->StateBlock->lights; | |
| prevPos = NULL; | |
| while (insertAt != NULL && insertAt->glIndex != -1) { | |
| prevPos = insertAt; | |
| insertAt = insertAt->next; | |
| } | |
| if (insertAt == NULL && prevPos == NULL) { /* Start of list */ | |
| This->StateBlock->lights = object; | |
| } else if (insertAt == NULL) { /* End of list */ | |
| prevPos->next = object; | |
| object->prev = prevPos; | |
| } else { /* Middle of chain */ | |
| if (prevPos == NULL) { | |
| This->StateBlock->lights = object; | |
| } else { | |
| prevPos->next = object; | |
| } | |
| object->prev = prevPos; | |
| object->next = insertAt; | |
| insertAt->prev = object; | |
| } | |
| } | |
| /* Initialze the object */ | |
| TRACE("Light %ld 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(D3DLIGHT8)); | |
| switch (pLight->Type) { | |
| case D3DLIGHT_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 D3DLIGHT_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 D3DLIGHT_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)); | |
| 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) { | |
| setup_light(iface, object->glIndex, object); | |
| } | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetLight(LPDIRECT3DDEVICE8 iface, DWORD Index,D3DLIGHT8* pLight) { | |
| PLIGHTINFOEL *lightInfo = NULL; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : Idx(%ld), pLight(%p)\n", This, Index, pLight); | |
| /* Locate the light in the live lights */ | |
| lightInfo = This->StateBlock->lights; | |
| while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next; | |
| if (lightInfo == NULL) { | |
| TRACE("Light information requested but light not defined\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| memcpy(pLight, &lightInfo->OriginalParms, sizeof(D3DLIGHT8)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_LightEnable(LPDIRECT3DDEVICE8 iface, DWORD Index,BOOL Enable) { | |
| PLIGHTINFOEL *lightInfo = NULL; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : Idx(%ld), enable? %d\n", This, Index, Enable); | |
| /* If recording state block, just add to end of lights chain with changedEnable set to true */ | |
| if (This->isRecordingState) { | |
| lightInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PLIGHTINFOEL)); | |
| if (NULL == lightInfo) { | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| lightInfo->OriginalIndex = Index; | |
| lightInfo->glIndex = -1; | |
| lightInfo->enabledChanged = TRUE; | |
| /* Add to the END of the chain of lights changes to be replayed */ | |
| if (This->UpdateStateBlock->lights == NULL) { | |
| This->UpdateStateBlock->lights = lightInfo; | |
| } else { | |
| PLIGHTINFOEL *temp = This->UpdateStateBlock->lights; | |
| while (temp->next != NULL) temp=temp->next; | |
| temp->next = lightInfo; | |
| } | |
| TRACE("Recording... not performing anything more\n"); | |
| return D3D_OK; | |
| } | |
| /* Not recording... So, locate the light in the live lights */ | |
| lightInfo = This->StateBlock->lights; | |
| while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next; | |
| /* Special case - enabling an undefined light creates one with a strict set of parms! */ | |
| if (lightInfo == NULL) { | |
| D3DLIGHT8 lightParms; | |
| /* Warning - untested code :-) Prob safe to change fixme to a trace but | |
| wait until someone confirms it seems to work! */ | |
| TRACE("Light enabled requested but light not defined, so defining one!\n"); | |
| lightParms.Type = D3DLIGHT_DIRECTIONAL; | |
| lightParms.Diffuse.r = 1.0; | |
| lightParms.Diffuse.g = 1.0; | |
| lightParms.Diffuse.b = 1.0; | |
| lightParms.Diffuse.a = 0.0; | |
| lightParms.Specular.r = 0.0; | |
| lightParms.Specular.g = 0.0; | |
| lightParms.Specular.b = 0.0; | |
| lightParms.Specular.a = 0.0; | |
| lightParms.Ambient.r = 0.0; | |
| lightParms.Ambient.g = 0.0; | |
| lightParms.Ambient.b = 0.0; | |
| lightParms.Ambient.a = 0.0; | |
| lightParms.Position.x = 0.0; | |
| lightParms.Position.y = 0.0; | |
| lightParms.Position.z = 0.0; | |
| lightParms.Direction.x = 0.0; | |
| lightParms.Direction.y = 0.0; | |
| lightParms.Direction.z = 1.0; | |
| lightParms.Range = 0.0; | |
| lightParms.Falloff = 0.0; | |
| lightParms.Attenuation0 = 0.0; | |
| lightParms.Attenuation1 = 0.0; | |
| lightParms.Attenuation2 = 0.0; | |
| lightParms.Theta = 0.0; | |
| lightParms.Phi = 0.0; | |
| IDirect3DDevice8Impl_SetLight(iface, Index, &lightParms); | |
| /* Search for it again! Should be fairly quick as near head of list */ | |
| lightInfo = This->StateBlock->lights; | |
| while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next; | |
| if (lightInfo == NULL) { | |
| FIXME("Adding default lights has failed dismally\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| } | |
| /* OK, we now have a light... */ | |
| if (Enable == FALSE) { | |
| /* If we are disabling it, check it was enabled, and | |
| still only do something if it has assigned a glIndex (which it should have!) */ | |
| if (lightInfo->lightEnabled && (lightInfo->glIndex != -1)) { | |
| TRACE("Disabling light set up at gl idx %ld\n", lightInfo->glIndex); | |
| ENTER_GL(); | |
| glDisable(GL_LIGHT0 + lightInfo->glIndex); | |
| checkGLcall("glDisable GL_LIGHT0+Index"); | |
| LEAVE_GL(); | |
| } else { | |
| TRACE("Nothing to do as light was not enabled\n"); | |
| } | |
| lightInfo->lightEnabled = FALSE; | |
| } else { | |
| /* We are enabling it. If it is enabled, its really simple */ | |
| if (lightInfo->lightEnabled) { | |
| /* nop */ | |
| TRACE("Nothing to do as light was enabled\n"); | |
| /* If it already has a glIndex, its still simple */ | |
| } else if (lightInfo->glIndex != -1) { | |
| TRACE("Reusing light as already set up at gl idx %ld\n", lightInfo->glIndex); | |
| lightInfo->lightEnabled = TRUE; | |
| ENTER_GL(); | |
| glEnable(GL_LIGHT0 + lightInfo->glIndex); | |
| checkGLcall("glEnable GL_LIGHT0+Index already setup"); | |
| LEAVE_GL(); | |
| /* Otherwise got to find space - lights are ordered gl indexes first */ | |
| } else { | |
| PLIGHTINFOEL *bsf = NULL; | |
| PLIGHTINFOEL *pos = This->StateBlock->lights; | |
| PLIGHTINFOEL *prev = NULL; | |
| int Index= 0; | |
| int glIndex = -1; | |
| /* Try to minimize changes as much as possible */ | |
| while (pos != NULL && pos->glIndex != -1 && Index < This->maxConcurrentLights) { | |
| /* Try to remember which index can be replaced if necessary */ | |
| if (bsf==NULL && pos->lightEnabled == FALSE) { | |
| /* Found a light we can replace, save as best replacement */ | |
| bsf = pos; | |
| } | |
| /* Step to next space */ | |
| prev = pos; | |
| pos = pos->next; | |
| Index ++; | |
| } | |
| /* If we have too many active lights, fail the call */ | |
| if ((Index == This->maxConcurrentLights) && (bsf == NULL)) { | |
| FIXME("Program requests too many concurrent lights\n"); | |
| return D3DERR_INVALIDCALL; | |
| /* If we have allocated all lights, but not all are enabled, | |
| reuse one which is not enabled */ | |
| } else if (Index == This->maxConcurrentLights) { | |
| /* use bsf - Simply swap the new light and the BSF one */ | |
| PLIGHTINFOEL *bsfNext = bsf->next; | |
| PLIGHTINFOEL *bsfPrev = bsf->prev; | |
| /* Sort out ends */ | |
| if (lightInfo->next != NULL) lightInfo->next->prev = bsf; | |
| if (bsf->prev != NULL) { | |
| bsf->prev->next = lightInfo; | |
| } else { | |
| This->StateBlock->lights = lightInfo; | |
| } | |
| /* If not side by side, lots of chains to update */ | |
| if (bsf->next != lightInfo) { | |
| lightInfo->prev->next = bsf; | |
| bsf->next->prev = lightInfo; | |
| bsf->next = lightInfo->next; | |
| bsf->prev = lightInfo->prev; | |
| lightInfo->next = bsfNext; | |
| lightInfo->prev = bsfPrev; | |
| } else { | |
| /* Simple swaps */ | |
| bsf->prev = lightInfo; | |
| bsf->next = lightInfo->next; | |
| lightInfo->next = bsf; | |
| lightInfo->prev = bsfPrev; | |
| } | |
| /* Update states */ | |
| glIndex = bsf->glIndex; | |
| bsf->glIndex = -1; | |
| lightInfo->glIndex = glIndex; | |
| lightInfo->lightEnabled = TRUE; | |
| /* Finally set up the light in gl itself */ | |
| TRACE("Replacing light which was set up at gl idx %ld\n", lightInfo->glIndex); | |
| ENTER_GL(); | |
| setup_light(iface, glIndex, lightInfo); | |
| glEnable(GL_LIGHT0 + glIndex); | |
| checkGLcall("glEnable GL_LIGHT0 new setup"); | |
| LEAVE_GL(); | |
| /* If we reached the end of the allocated lights, with space in the | |
| gl lights, setup a new light */ | |
| } else if (pos->glIndex == -1) { | |
| /* We reached the end of the allocated gl lights, so already | |
| know the index of the next one! */ | |
| glIndex = Index; | |
| lightInfo->glIndex = glIndex; | |
| lightInfo->lightEnabled = TRUE; | |
| /* In an ideal world, its already in the right place */ | |
| if (lightInfo->prev == NULL || lightInfo->prev->glIndex!=-1) { | |
| /* No need to move it */ | |
| } else { | |
| /* Remove this light from the list */ | |
| lightInfo->prev->next = lightInfo->next; | |
| if (lightInfo->next != NULL) { | |
| lightInfo->next->prev = lightInfo->prev; | |
| } | |
| /* Add in at appropriate place (inbetween prev and pos) */ | |
| lightInfo->prev = prev; | |
| lightInfo->next = pos; | |
| if (prev == NULL) { | |
| This->StateBlock->lights = lightInfo; | |
| } else { | |
| prev->next = lightInfo; | |
| } | |
| if (pos != NULL) { | |
| pos->prev = lightInfo; | |
| } | |
| } | |
| /* Finally set up the light in gl itself */ | |
| TRACE("Defining new light at gl idx %ld\n", lightInfo->glIndex); | |
| ENTER_GL(); | |
| setup_light(iface, glIndex, lightInfo); | |
| glEnable(GL_LIGHT0 + glIndex); | |
| checkGLcall("glEnable GL_LIGHT0 new setup"); | |
| LEAVE_GL(); | |
| } | |
| } | |
| } | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetLightEnable(LPDIRECT3DDEVICE8 iface, DWORD Index,BOOL* pEnable) { | |
| PLIGHTINFOEL *lightInfo = NULL; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : for idx(%ld)\n", This, Index); | |
| /* Locate the light in the live lights */ | |
| lightInfo = This->StateBlock->lights; | |
| while (lightInfo != NULL && lightInfo->OriginalIndex != Index) lightInfo = lightInfo->next; | |
| if (lightInfo == NULL) { | |
| TRACE("Light enabled state requested but light not defined\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| *pEnable = lightInfo->lightEnabled; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetClipPlane(LPDIRECT3DDEVICE8 iface, DWORD Index,CONST float* pPlane) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : for idx %ld, %p\n", This, Index, pPlane); | |
| /* Validate Index */ | |
| if (Index >= GL_LIMITS(clipplanes)) { | |
| TRACE("Application has requested clipplane this device doesn't support\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| This->UpdateStateBlock->Changed.clipplane[Index] = TRUE; | |
| This->UpdateStateBlock->Set.clipplane[Index] = TRUE; | |
| 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 D3D_OK; | |
| } | |
| /* Apply it */ | |
| ENTER_GL(); | |
| /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */ | |
| glMatrixMode(GL_MODELVIEW); | |
| glPushMatrix(); | |
| glLoadMatrixf((float *) &This->StateBlock->transforms[D3DTS_VIEW].u.m[0][0]); | |
| TRACE("Clipplane [%f,%f,%f,%f]\n", | |
| This->UpdateStateBlock->clipplane[Index][0], | |
| This->UpdateStateBlock->clipplane[Index][1], | |
| This->UpdateStateBlock->clipplane[Index][2], | |
| This->UpdateStateBlock->clipplane[Index][3]); | |
| glClipPlane(GL_CLIP_PLANE0 + Index, This->UpdateStateBlock->clipplane[Index]); | |
| checkGLcall("glClipPlane"); | |
| glPopMatrix(); | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetClipPlane(LPDIRECT3DDEVICE8 iface, DWORD Index,float* pPlane) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : for idx %ld\n", This, Index); | |
| /* Validate Index */ | |
| if (Index >= GL_LIMITS(clipplanes)) { | |
| TRACE("Application has requested clipplane this device doesn't support\n"); | |
| return D3DERR_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 D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetRenderState(LPDIRECT3DDEVICE8 iface, D3DRENDERSTATETYPE State,DWORD Value) { | |
| union { | |
| DWORD d; | |
| float f; | |
| } tmpvalue; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| DWORD OldValue = This->StateBlock->renderstate[State]; | |
| TRACE("(%p)->state = %s(%d), value = %ld\n", This, debug_d3drenderstate(State), State, Value); | |
| This->UpdateStateBlock->Changed.renderstate[State] = TRUE; | |
| This->UpdateStateBlock->Set.renderstate[State] = TRUE; | |
| This->UpdateStateBlock->renderstate[State] = Value; | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| ENTER_GL(); | |
| switch (State) { | |
| case D3DRS_FILLMODE : | |
| switch ((D3DFILLMODE) Value) { | |
| case D3DFILL_POINT : glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); break; | |
| case D3DFILL_WIREFRAME : glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); break; | |
| case D3DFILL_SOLID : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; | |
| default: | |
| FIXME("Unrecognized D3DRS_FILLMODE value %ld\n", Value); | |
| } | |
| checkGLcall("glPolygonMode (fillmode)"); | |
| break; | |
| case D3DRS_LIGHTING : | |
| if (Value) { | |
| glEnable(GL_LIGHTING); | |
| checkGLcall("glEnable GL_LIGHTING"); | |
| } else { | |
| glDisable(GL_LIGHTING); | |
| checkGLcall("glDisable GL_LIGHTING"); | |
| } | |
| break; | |
| case D3DRS_ZENABLE : | |
| switch ((D3DZBUFFERTYPE) Value) { | |
| case D3DZB_FALSE: | |
| glDisable(GL_DEPTH_TEST); | |
| checkGLcall("glDisable GL_DEPTH_TEST"); | |
| break; | |
| case D3DZB_TRUE: | |
| glEnable(GL_DEPTH_TEST); | |
| checkGLcall("glEnable GL_DEPTH_TEST"); | |
| break; | |
| case D3DZB_USEW: | |
| glEnable(GL_DEPTH_TEST); | |
| checkGLcall("glEnable GL_DEPTH_TEST"); | |
| FIXME("W buffer is not well handled\n"); | |
| break; | |
| default: | |
| FIXME("Unrecognized D3DZBUFFERTYPE value %ld\n", Value); | |
| } | |
| break; | |
| case D3DRS_CULLMODE : | |
| /* If we are culling "back faces with clockwise vertices" then | |
| set front faces to be counter clockwise and enable culling | |
| of back faces */ | |
| switch ((D3DCULL) Value) { | |
| case D3DCULL_NONE: | |
| glDisable(GL_CULL_FACE); | |
| checkGLcall("glDisable GL_CULL_FACE"); | |
| break; | |
| case D3DCULL_CW: | |
| glEnable(GL_CULL_FACE); | |
| checkGLcall("glEnable GL_CULL_FACE"); | |
| if (This->renderUpsideDown) { | |
| glFrontFace(GL_CW); | |
| checkGLcall("glFrontFace GL_CW"); | |
| } else { | |
| glFrontFace(GL_CCW); | |
| checkGLcall("glFrontFace GL_CCW"); | |
| } | |
| glCullFace(GL_BACK); | |
| break; | |
| case D3DCULL_CCW: | |
| glEnable(GL_CULL_FACE); | |
| checkGLcall("glEnable GL_CULL_FACE"); | |
| if (This->renderUpsideDown) { | |
| glFrontFace(GL_CCW); | |
| checkGLcall("glFrontFace GL_CCW"); | |
| } else { | |
| glFrontFace(GL_CW); | |
| checkGLcall("glFrontFace GL_CW"); | |
| } | |
| glCullFace(GL_BACK); | |
| break; | |
| default: | |
| FIXME("Unrecognized/Unhandled D3DCULL value %ld\n", Value); | |
| } | |
| break; | |
| case D3DRS_SHADEMODE : | |
| switch ((D3DSHADEMODE) Value) { | |
| case D3DSHADE_FLAT: | |
| glShadeModel(GL_FLAT); | |
| checkGLcall("glShadeModel"); | |
| break; | |
| case D3DSHADE_GOURAUD: | |
| glShadeModel(GL_SMOOTH); | |
| checkGLcall("glShadeModel"); | |
| break; | |
| case D3DSHADE_PHONG: | |
| FIXME("D3DSHADE_PHONG isn't supported?\n"); | |
| LEAVE_GL(); | |
| return D3DERR_INVALIDCALL; | |
| default: | |
| FIXME("Unrecognized/Unhandled D3DSHADEMODE value %ld\n", Value); | |
| } | |
| break; | |
| case D3DRS_DITHERENABLE : | |
| if (Value) { | |
| glEnable(GL_DITHER); | |
| checkGLcall("glEnable GL_DITHER"); | |
| } else { | |
| glDisable(GL_DITHER); | |
| checkGLcall("glDisable GL_DITHER"); | |
| } | |
| break; | |
| case D3DRS_ZWRITEENABLE : | |
| if (Value) { | |
| glDepthMask(1); | |
| checkGLcall("glDepthMask"); | |
| } else { | |
| glDepthMask(0); | |
| checkGLcall("glDepthMask"); | |
| } | |
| break; | |
| case D3DRS_ZFUNC : | |
| { | |
| int glParm = GL_LESS; | |
| switch ((D3DCMPFUNC) Value) { | |
| case D3DCMP_NEVER: glParm=GL_NEVER; break; | |
| case D3DCMP_LESS: glParm=GL_LESS; break; | |
| case D3DCMP_EQUAL: glParm=GL_EQUAL; break; | |
| case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break; | |
| case D3DCMP_GREATER: glParm=GL_GREATER; break; | |
| case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break; | |
| case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break; | |
| case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break; | |
| default: | |
| FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value); | |
| } | |
| glDepthFunc(glParm); | |
| checkGLcall("glDepthFunc"); | |
| } | |
| break; | |
| case D3DRS_AMBIENT : | |
| { | |
| float col[4]; | |
| D3DCOLORTOGLFLOAT4(Value, 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"); | |
| } | |
| break; | |
| case D3DRS_ALPHABLENDENABLE : | |
| if (Value) { | |
| glEnable(GL_BLEND); | |
| checkGLcall("glEnable GL_BLEND"); | |
| } else { | |
| glDisable(GL_BLEND); | |
| checkGLcall("glDisable GL_BLEND"); | |
| }; | |
| break; | |
| case D3DRS_SRCBLEND : | |
| case D3DRS_DESTBLEND : | |
| { | |
| int newVal = GL_ZERO; | |
| switch (Value) { | |
| case D3DBLEND_ZERO : newVal = GL_ZERO; break; | |
| case D3DBLEND_ONE : newVal = GL_ONE; break; | |
| case D3DBLEND_SRCCOLOR : newVal = GL_SRC_COLOR; break; | |
| case D3DBLEND_INVSRCCOLOR : newVal = GL_ONE_MINUS_SRC_COLOR; break; | |
| case D3DBLEND_SRCALPHA : newVal = GL_SRC_ALPHA; break; | |
| case D3DBLEND_INVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; break; | |
| case D3DBLEND_DESTALPHA : newVal = GL_DST_ALPHA; break; | |
| case D3DBLEND_INVDESTALPHA : newVal = GL_ONE_MINUS_DST_ALPHA; break; | |
| case D3DBLEND_DESTCOLOR : newVal = GL_DST_COLOR; break; | |
| case D3DBLEND_INVDESTCOLOR : newVal = GL_ONE_MINUS_DST_COLOR; break; | |
| case D3DBLEND_SRCALPHASAT : newVal = GL_SRC_ALPHA_SATURATE; break; | |
| case D3DBLEND_BOTHSRCALPHA : newVal = GL_SRC_ALPHA; | |
| This->srcBlend = newVal; | |
| This->dstBlend = newVal; | |
| break; | |
| case D3DBLEND_BOTHINVSRCALPHA : newVal = GL_ONE_MINUS_SRC_ALPHA; | |
| This->srcBlend = newVal; | |
| This->dstBlend = newVal; | |
| break; | |
| default: | |
| FIXME("Unrecognized src/dest blend value %ld (%d)\n", Value, State); | |
| } | |
| if (State == D3DRS_SRCBLEND) This->srcBlend = newVal; | |
| if (State == D3DRS_DESTBLEND) This->dstBlend = newVal; | |
| TRACE("glBlendFunc src=%x, dst=%x\n", This->srcBlend, This->dstBlend); | |
| glBlendFunc(This->srcBlend, This->dstBlend); | |
| checkGLcall("glBlendFunc"); | |
| } | |
| break; | |
| case D3DRS_ALPHATESTENABLE : | |
| if (Value) { | |
| glEnable(GL_ALPHA_TEST); | |
| checkGLcall("glEnable GL_ALPHA_TEST"); | |
| } else { | |
| glDisable(GL_ALPHA_TEST); | |
| checkGLcall("glDisable GL_ALPHA_TEST"); | |
| } | |
| break; | |
| case D3DRS_ALPHAFUNC : | |
| { | |
| int glParm = GL_LESS; | |
| float ref = ((float) This->StateBlock->renderstate[D3DRS_ALPHAREF]) / 255.0f; | |
| switch ((D3DCMPFUNC) Value) { | |
| case D3DCMP_NEVER: glParm = GL_NEVER; break; | |
| case D3DCMP_LESS: glParm = GL_LESS; break; | |
| case D3DCMP_EQUAL: glParm = GL_EQUAL; break; | |
| case D3DCMP_LESSEQUAL: glParm = GL_LEQUAL; break; | |
| case D3DCMP_GREATER: glParm = GL_GREATER; break; | |
| case D3DCMP_NOTEQUAL: glParm = GL_NOTEQUAL; break; | |
| case D3DCMP_GREATEREQUAL: glParm = GL_GEQUAL; break; | |
| case D3DCMP_ALWAYS: glParm = GL_ALWAYS; break; | |
| default: | |
| FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value); | |
| } | |
| TRACE("glAlphaFunc with Parm=%x, ref=%f\n", glParm, ref); | |
| glAlphaFunc(glParm, ref); | |
| This->alphafunc = glParm; | |
| checkGLcall("glAlphaFunc"); | |
| } | |
| break; | |
| case D3DRS_ALPHAREF : | |
| { | |
| int glParm = This->alphafunc; | |
| float ref = 1.0f; | |
| ref = ((float) Value) / 255.0f; | |
| TRACE("glAlphaFunc with Parm=%x, ref=%f\n", glParm, ref); | |
| glAlphaFunc(glParm, ref); | |
| checkGLcall("glAlphaFunc"); | |
| } | |
| break; | |
| case D3DRS_CLIPPLANEENABLE : | |
| case D3DRS_CLIPPING : | |
| { | |
| /* Ensure we only do the changed clip planes */ | |
| DWORD enable = 0xFFFFFFFF; | |
| DWORD disable = 0x00000000; | |
| /* If enabling / disabling all */ | |
| if (State == D3DRS_CLIPPING) { | |
| if (Value) { | |
| enable = This->StateBlock->renderstate[D3DRS_CLIPPLANEENABLE]; | |
| disable = 0x00; | |
| } else { | |
| disable = This->StateBlock->renderstate[D3DRS_CLIPPLANEENABLE]; | |
| enable = 0x00; | |
| } | |
| } else { | |
| enable = Value & ~OldValue; | |
| disable = ~Value & OldValue; | |
| } | |
| if (enable & D3DCLIPPLANE0) { glEnable(GL_CLIP_PLANE0); checkGLcall("glEnable(clip plane 0)"); } | |
| if (enable & D3DCLIPPLANE1) { glEnable(GL_CLIP_PLANE1); checkGLcall("glEnable(clip plane 1)"); } | |
| if (enable & D3DCLIPPLANE2) { glEnable(GL_CLIP_PLANE2); checkGLcall("glEnable(clip plane 2)"); } | |
| if (enable & D3DCLIPPLANE3) { glEnable(GL_CLIP_PLANE3); checkGLcall("glEnable(clip plane 3)"); } | |
| if (enable & D3DCLIPPLANE4) { glEnable(GL_CLIP_PLANE4); checkGLcall("glEnable(clip plane 4)"); } | |
| if (enable & D3DCLIPPLANE5) { glEnable(GL_CLIP_PLANE5); checkGLcall("glEnable(clip plane 5)"); } | |
| if (disable & D3DCLIPPLANE0) { glDisable(GL_CLIP_PLANE0); checkGLcall("glDisable(clip plane 0)"); } | |
| if (disable & D3DCLIPPLANE1) { glDisable(GL_CLIP_PLANE1); checkGLcall("glDisable(clip plane 1)"); } | |
| if (disable & D3DCLIPPLANE2) { glDisable(GL_CLIP_PLANE2); checkGLcall("glDisable(clip plane 2)"); } | |
| if (disable & D3DCLIPPLANE3) { glDisable(GL_CLIP_PLANE3); checkGLcall("glDisable(clip plane 3)"); } | |
| if (disable & D3DCLIPPLANE4) { glDisable(GL_CLIP_PLANE4); checkGLcall("glDisable(clip plane 4)"); } | |
| if (disable & D3DCLIPPLANE5) { glDisable(GL_CLIP_PLANE5); checkGLcall("glDisable(clip plane 5)"); } | |
| /** update clipping status */ | |
| if (enable) { | |
| This->StateBlock->clip_status.ClipUnion = 0; | |
| This->StateBlock->clip_status.ClipIntersection = 0xFFFFFFFF; | |
| } else { | |
| This->StateBlock->clip_status.ClipUnion = 0; | |
| This->StateBlock->clip_status.ClipIntersection = 0; | |
| } | |
| } | |
| break; | |
| case D3DRS_BLENDOP : | |
| { | |
| int glParm = GL_FUNC_ADD; | |
| switch ((D3DBLENDOP) Value) { | |
| case D3DBLENDOP_ADD : glParm = GL_FUNC_ADD; break; | |
| case D3DBLENDOP_SUBTRACT : glParm = GL_FUNC_SUBTRACT; break; | |
| case D3DBLENDOP_REVSUBTRACT : glParm = GL_FUNC_REVERSE_SUBTRACT; break; | |
| case D3DBLENDOP_MIN : glParm = GL_MIN; break; | |
| case D3DBLENDOP_MAX : glParm = GL_MAX; break; | |
| default: | |
| FIXME("Unrecognized/Unhandled D3DBLENDOP value %ld\n", Value); | |
| } | |
| TRACE("glBlendEquation(%x)\n", glParm); | |
| glBlendEquation(glParm); | |
| checkGLcall("glBlendEquation"); | |
| } | |
| break; | |
| case D3DRS_TEXTUREFACTOR : | |
| { | |
| unsigned int i; | |
| /* Note the texture color applies to all textures whereas | |
| GL_TEXTURE_ENV_COLOR applies to active only */ | |
| float col[4]; | |
| D3DCOLORTOGLFLOAT4(Value, col); | |
| /* Set the default alpha blend color */ | |
| glBlendColor(col[0], col[1], col[2], col[3]); | |
| checkGLcall("glBlendColor"); | |
| /* And now the default texture color as well */ | |
| for (i = 0; i < GL_LIMITS(textures); i++) { | |
| /* Note the D3DRS value applies to all textures, but GL has one | |
| per texture, so apply it now ready to be used! */ | |
| if (GL_SUPPORT(ARB_MULTITEXTURE)) { | |
| #if defined(GL_VERSION_1_3) | |
| glActiveTexture(GL_TEXTURE0 + i); | |
| #else | |
| glActiveTextureARB(GL_TEXTURE0_ARB + i); | |
| #endif | |
| checkGLcall("Activate texture.. to update const color"); | |
| } 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);"); | |
| } | |
| } | |
| break; | |
| case D3DRS_SPECULARENABLE : | |
| { | |
| /* 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 (Value) { | |
| glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->UpdateStateBlock->material.Specular); | |
| checkGLcall("glMaterialfv"); | |
| 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)"); | |
| } 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)"); | |
| } | |
| } | |
| break; | |
| case D3DRS_STENCILENABLE : | |
| if (Value) { | |
| glEnable(GL_STENCIL_TEST); | |
| checkGLcall("glEnable GL_STENCIL_TEST"); | |
| } else { | |
| glDisable(GL_STENCIL_TEST); | |
| checkGLcall("glDisable GL_STENCIL_TEST"); | |
| } | |
| break; | |
| case D3DRS_STENCILFUNC : | |
| { | |
| int glParm = GL_ALWAYS; | |
| int ref = This->StateBlock->renderstate[D3DRS_STENCILREF]; | |
| GLuint mask = This->StateBlock->renderstate[D3DRS_STENCILMASK]; | |
| switch ((D3DCMPFUNC) Value) { | |
| case D3DCMP_NEVER: glParm=GL_NEVER; break; | |
| case D3DCMP_LESS: glParm=GL_LESS; break; | |
| case D3DCMP_EQUAL: glParm=GL_EQUAL; break; | |
| case D3DCMP_LESSEQUAL: glParm=GL_LEQUAL; break; | |
| case D3DCMP_GREATER: glParm=GL_GREATER; break; | |
| case D3DCMP_NOTEQUAL: glParm=GL_NOTEQUAL; break; | |
| case D3DCMP_GREATEREQUAL: glParm=GL_GEQUAL; break; | |
| case D3DCMP_ALWAYS: glParm=GL_ALWAYS; break; | |
| default: | |
| FIXME("Unrecognized/Unhandled D3DCMPFUNC value %ld\n", Value); | |
| } | |
| TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask); | |
| This->stencilfunc = glParm; | |
| glStencilFunc(glParm, ref, mask); | |
| checkGLcall("glStencilFunc"); | |
| } | |
| break; | |
| case D3DRS_STENCILREF : | |
| { | |
| int glParm = This->stencilfunc; | |
| int ref = 0; | |
| GLuint mask = This->StateBlock->renderstate[D3DRS_STENCILMASK]; | |
| ref = Value; | |
| TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask); | |
| glStencilFunc(glParm, ref, mask); | |
| checkGLcall("glStencilFunc"); | |
| } | |
| break; | |
| case D3DRS_STENCILMASK : | |
| { | |
| int glParm = This->stencilfunc; | |
| int ref = This->StateBlock->renderstate[D3DRS_STENCILREF]; | |
| GLuint mask = Value; | |
| TRACE("glStencilFunc with Parm=%x, ref=%d, mask=%x\n", glParm, ref, mask); | |
| glStencilFunc(glParm, ref, mask); | |
| checkGLcall("glStencilFunc"); | |
| } | |
| break; | |
| case D3DRS_STENCILFAIL : | |
| { | |
| GLenum fail ; | |
| GLenum zpass ; | |
| GLenum zfail ; | |
| fail = StencilOp(Value); | |
| glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass); | |
| checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);"); | |
| glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail); | |
| checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);"); | |
| TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass); | |
| glStencilOp(fail, zfail, zpass); | |
| checkGLcall("glStencilOp(fail, zfail, zpass);"); | |
| } | |
| break; | |
| case D3DRS_STENCILZFAIL : | |
| { | |
| GLenum fail ; | |
| GLenum zpass ; | |
| GLenum zfail ; | |
| glGetIntegerv(GL_STENCIL_FAIL, &fail); | |
| checkGLcall("glGetIntegerv(GL_STENCIL_FAIL, &fail);"); | |
| glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass); | |
| checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &zpass);"); | |
| zfail = StencilOp(Value); | |
| TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass); | |
| glStencilOp(fail, zfail, zpass); | |
| checkGLcall("glStencilOp(fail, zfail, zpass);"); | |
| } | |
| break; | |
| case D3DRS_STENCILPASS : | |
| { | |
| GLenum fail ; | |
| GLenum zpass ; | |
| GLenum zfail ; | |
| glGetIntegerv(GL_STENCIL_FAIL, &fail); | |
| checkGLcall("glGetIntegerv(GL_STENCIL_FAIL, &fail);"); | |
| zpass = StencilOp(Value); | |
| glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail); | |
| checkGLcall("glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &zfail);"); | |
| TRACE("StencilOp fail=%x, zfail=%x, zpass=%x\n", fail, zfail, zpass); | |
| glStencilOp(fail, zfail, zpass); | |
| checkGLcall("glStencilOp(fail, zfail, zpass);"); | |
| } | |
| break; | |
| case D3DRS_STENCILWRITEMASK : | |
| { | |
| glStencilMask(Value); | |
| TRACE("glStencilMask(%lu)\n", Value); | |
| checkGLcall("glStencilMask"); | |
| } | |
| break; | |
| case D3DRS_FOGENABLE : | |
| { | |
| if (Value/* && This->StateBlock->renderstate[D3DRS_FOGTABLEMODE] != D3DFOG_NONE*/) { | |
| glEnable(GL_FOG); | |
| checkGLcall("glEnable GL_FOG"); | |
| } else { | |
| glDisable(GL_FOG); | |
| checkGLcall("glDisable GL_FOG"); | |
| } | |
| } | |
| break; | |
| case D3DRS_RANGEFOGENABLE : | |
| { | |
| if (Value) { | |
| TRACE("Enabled RANGEFOG"); | |
| } else { | |
| TRACE("Disabled RANGEFOG"); | |
| } | |
| } | |
| break; | |
| case D3DRS_FOGCOLOR : | |
| { | |
| float col[4]; | |
| D3DCOLORTOGLFLOAT4(Value, col); | |
| /* Set the default alpha blend color */ | |
| glFogfv(GL_FOG_COLOR, &col[0]); | |
| checkGLcall("glFog GL_FOG_COLOR"); | |
| } | |
| break; | |
| case D3DRS_FOGTABLEMODE : | |
| { | |
| glHint(GL_FOG_HINT, GL_NICEST); | |
| switch (Value) { | |
| case D3DFOG_NONE: /* I don't know what to do here */ checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; | |
| case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; | |
| case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break; | |
| case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break; | |
| default: | |
| FIXME("Unsupported Value(%lu) for D3DRS_FOGTABLEMODE!\n", Value); | |
| } | |
| if (GL_SUPPORT(NV_FOG_DISTANCE)) { | |
| glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); | |
| } | |
| } | |
| break; | |
| case D3DRS_FOGVERTEXMODE : | |
| { | |
| glHint(GL_FOG_HINT, GL_FASTEST); | |
| switch (Value) { | |
| case D3DFOG_NONE: /* I don't know what to do here */ checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; | |
| case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; | |
| case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break; | |
| case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break; | |
| default: | |
| FIXME("Unsupported Value(%lu) for D3DRS_FOGTABLEMODE!\n", Value); | |
| } | |
| if (GL_SUPPORT(NV_FOG_DISTANCE)) { | |
| glFogi(GL_FOG_DISTANCE_MODE_NV, This->StateBlock->renderstate[D3DRS_RANGEFOGENABLE] ? GL_EYE_RADIAL_NV : GL_EYE_PLANE_ABSOLUTE_NV); | |
| } | |
| } | |
| break; | |
| case D3DRS_FOGSTART : | |
| { | |
| tmpvalue.d = Value; | |
| glFogfv(GL_FOG_START, &tmpvalue.f); | |
| checkGLcall("glFogf(GL_FOG_START, (float) Value)"); | |
| TRACE("Fog Start == %f\n", tmpvalue.f); | |
| } | |
| break; | |
| case D3DRS_FOGEND : | |
| { | |
| tmpvalue.d = Value; | |
| glFogfv(GL_FOG_END, &tmpvalue.f); | |
| checkGLcall("glFogf(GL_FOG_END, (float) Value)"); | |
| TRACE("Fog End == %f\n", tmpvalue.f); | |
| } | |
| break; | |
| case D3DRS_FOGDENSITY : | |
| { | |
| tmpvalue.d = Value; | |
| glFogfv(GL_FOG_DENSITY, &tmpvalue.f); | |
| checkGLcall("glFogf(GL_FOG_DENSITY, (float) Value)"); | |
| } | |
| break; | |
| case D3DRS_VERTEXBLEND : | |
| { | |
| This->UpdateStateBlock->vertex_blend = (D3DVERTEXBLENDFLAGS) Value; | |
| TRACE("Vertex Blending state to %ld\n", Value); | |
| } | |
| break; | |
| case D3DRS_TWEENFACTOR : | |
| { | |
| tmpvalue.d = Value; | |
| This->UpdateStateBlock->tween_factor = tmpvalue.f; | |
| TRACE("Vertex Blending Tween Factor to %f\n", This->UpdateStateBlock->tween_factor); | |
| } | |
| break; | |
| case D3DRS_INDEXEDVERTEXBLENDENABLE : | |
| { | |
| TRACE("Indexed Vertex Blend Enable to %ul\n", (BOOL) Value); | |
| } | |
| break; | |
| case D3DRS_COLORVERTEX : | |
| case D3DRS_DIFFUSEMATERIALSOURCE : | |
| case D3DRS_SPECULARMATERIALSOURCE : | |
| case D3DRS_AMBIENTMATERIALSOURCE : | |
| case D3DRS_EMISSIVEMATERIALSOURCE : | |
| { | |
| GLenum Parm = GL_AMBIENT_AND_DIFFUSE; | |
| if (This->StateBlock->renderstate[D3DRS_COLORVERTEX]) { | |
| TRACE("diff %ld, amb %ld, emis %ld, spec %ld\n", | |
| This->StateBlock->renderstate[D3DRS_DIFFUSEMATERIALSOURCE], | |
| This->StateBlock->renderstate[D3DRS_AMBIENTMATERIALSOURCE], | |
| This->StateBlock->renderstate[D3DRS_EMISSIVEMATERIALSOURCE], | |
| This->StateBlock->renderstate[D3DRS_SPECULARMATERIALSOURCE]); | |
| if (This->StateBlock->renderstate[D3DRS_DIFFUSEMATERIALSOURCE] == D3DMCS_COLOR1) { | |
| if (This->StateBlock->renderstate[D3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) { | |
| Parm = GL_AMBIENT_AND_DIFFUSE; | |
| } else { | |
| Parm = GL_DIFFUSE; | |
| } | |
| } else if (This->StateBlock->renderstate[D3DRS_AMBIENTMATERIALSOURCE] == D3DMCS_COLOR1) { | |
| Parm = GL_AMBIENT; | |
| } else if (This->StateBlock->renderstate[D3DRS_EMISSIVEMATERIALSOURCE] == D3DMCS_COLOR1) { | |
| Parm = GL_EMISSION; | |
| } else if (This->StateBlock->renderstate[D3DRS_SPECULARMATERIALSOURCE] == D3DMCS_COLOR1) { | |
| Parm = GL_SPECULAR; | |
| } else { | |
| Parm = -1; | |
| } | |
| if (Parm == -1) { | |
| if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE; | |
| } else { | |
| This->tracking_color = NEEDS_TRACKING; | |
| This->tracking_parm = Parm; | |
| } | |
| } else { | |
| if (This->tracking_color != DISABLED_TRACKING) This->tracking_color = NEEDS_DISABLE; | |
| } | |
| } | |
| break; | |
| case D3DRS_LINEPATTERN : | |
| { | |
| union { | |
| DWORD d; | |
| D3DLINEPATTERN lp; | |
| } tmppattern; | |
| tmppattern.d = Value; | |
| 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);"); | |
| } | |
| } | |
| break; | |
| case D3DRS_ZBIAS : | |
| { | |
| if (Value) { | |
| tmpvalue.d = Value; | |
| 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);"); | |
| } | |
| } | |
| break; | |
| case D3DRS_NORMALIZENORMALS : | |
| if (Value) { | |
| glEnable(GL_NORMALIZE); | |
| checkGLcall("glEnable(GL_NORMALIZE);"); | |
| } else { | |
| glDisable(GL_NORMALIZE); | |
| checkGLcall("glDisable(GL_NORMALIZE);"); | |
| } | |
| break; | |
| case D3DRS_POINTSIZE : | |
| tmpvalue.d = Value; | |
| TRACE("Set point size to %f\n", tmpvalue.f); | |
| glPointSize(tmpvalue.f); | |
| checkGLcall("glPointSize(...);"); | |
| break; | |
| case D3DRS_POINTSIZE_MIN : | |
| if (GL_SUPPORT(EXT_POINT_PARAMETERS)) { | |
| tmpvalue.d = Value; | |
| GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MIN_EXT, tmpvalue.f); | |
| checkGLcall("glPointParameterfEXT(...);"); | |
| } else { | |
| FIXME("D3DRS_POINTSIZE_MIN not supported on this opengl\n"); | |
| } | |
| break; | |
| case D3DRS_POINTSIZE_MAX : | |
| if (GL_SUPPORT(EXT_POINT_PARAMETERS)) { | |
| tmpvalue.d = Value; | |
| GL_EXTCALL(glPointParameterfEXT)(GL_POINT_SIZE_MAX_EXT, tmpvalue.f); | |
| checkGLcall("glPointParameterfEXT(...);"); | |
| } else { | |
| FIXME("D3DRS_POINTSIZE_MAX not supported on this opengl\n"); | |
| } | |
| break; | |
| case D3DRS_POINTSCALE_A : | |
| case D3DRS_POINTSCALE_B : | |
| case D3DRS_POINTSCALE_C : | |
| case D3DRS_POINTSCALEENABLE : | |
| { | |
| /* If enabled, supply the parameters, otherwise fall back to defaults */ | |
| if (This->StateBlock->renderstate[D3DRS_POINTSCALEENABLE]) { | |
| GLfloat att[3] = {1.0f, 0.0f, 0.0f}; | |
| att[0] = *((float*)&This->StateBlock->renderstate[D3DRS_POINTSCALE_A]); | |
| att[1] = *((float*)&This->StateBlock->renderstate[D3DRS_POINTSCALE_B]); | |
| att[2] = *((float*)&This->StateBlock->renderstate[D3DRS_POINTSCALE_C]); | |
| if (GL_SUPPORT(EXT_POINT_PARAMETERS)) { | |
| GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att); | |
| checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...);"); | |
| } else { | |
| TRACE("D3DRS_POINTSCALEENABLE not supported on this opengl\n"); | |
| } | |
| } else { | |
| GLfloat att[3] = {1.0f, 0.0f, 0.0f}; | |
| if (GL_SUPPORT(EXT_POINT_PARAMETERS)) { | |
| GL_EXTCALL(glPointParameterfvEXT)(GL_DISTANCE_ATTENUATION_EXT, att); | |
| checkGLcall("glPointParameterfvEXT(GL_DISTANCE_ATTENUATION_EXT, ...);"); | |
| } else { | |
| TRACE("D3DRS_POINTSCALEENABLE not supported, but not on either\n"); | |
| } | |
| } | |
| break; | |
| } | |
| case D3DRS_COLORWRITEENABLE : | |
| { | |
| TRACE("Color mask: r(%d) g(%d) b(%d) a(%d)\n", | |
| Value & D3DCOLORWRITEENABLE_RED ? 1 : 0, | |
| Value & D3DCOLORWRITEENABLE_GREEN ? 1 : 0, | |
| Value & D3DCOLORWRITEENABLE_BLUE ? 1 : 0, | |
| Value & D3DCOLORWRITEENABLE_ALPHA ? 1 : 0); | |
| glColorMask(Value & D3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE, | |
| Value & D3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE, | |
| Value & D3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE, | |
| Value & D3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE); | |
| checkGLcall("glColorMask(...)"); | |
| } | |
| break; | |
| case D3DRS_LOCALVIEWER : | |
| { | |
| GLint state = (Value) ? 1 : 0; | |
| TRACE("Local Viewer Enable to %ul\n", (BOOL) Value); | |
| glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, state); | |
| } | |
| break; | |
| case D3DRS_LASTPIXEL : | |
| { | |
| if (Value) { | |
| TRACE("Last Pixel Drawing Enabled\n"); | |
| } else { | |
| FIXME("Last Pixel Drawing Disabled, not handled yet\n"); | |
| } | |
| } | |
| break; | |
| case D3DRS_SOFTWAREVERTEXPROCESSING : | |
| { | |
| if (Value) { | |
| TRACE("Software Processing Enabled\n"); | |
| } else { | |
| TRACE("Software Processing Disabled\n"); | |
| } | |
| } | |
| break; | |
| /** not supported */ | |
| case D3DRS_ZVISIBLE : | |
| { | |
| LEAVE_GL(); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| /* Unhandled yet...! */ | |
| case D3DRS_EDGEANTIALIAS : | |
| case D3DRS_WRAP0 : | |
| case D3DRS_WRAP1 : | |
| case D3DRS_WRAP2 : | |
| case D3DRS_WRAP3 : | |
| case D3DRS_WRAP4 : | |
| case D3DRS_WRAP5 : | |
| case D3DRS_WRAP6 : | |
| case D3DRS_WRAP7 : | |
| case D3DRS_POINTSPRITEENABLE : | |
| case D3DRS_MULTISAMPLEANTIALIAS : | |
| case D3DRS_MULTISAMPLEMASK : | |
| case D3DRS_PATCHEDGESTYLE : | |
| case D3DRS_PATCHSEGMENTS : | |
| case D3DRS_DEBUGMONITORTOKEN : | |
| case D3DRS_POSITIONORDER : | |
| case D3DRS_NORMALORDER : | |
| /*Put back later: FIXME("(%p)->(%d,%ld) not handled yet\n", This, State, Value); */ | |
| FIXME("(%p)->(%d,%ld) not handled yet\n", This, State, Value); | |
| break; | |
| default: | |
| FIXME("(%p)->(%d,%ld) unrecognized\n", This, State, Value); | |
| } | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetRenderState(LPDIRECT3DDEVICE8 iface, D3DRENDERSTATETYPE State,DWORD* pValue) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) for State %d = %ld\n", This, State, This->UpdateStateBlock->renderstate[State]); | |
| *pValue = This->StateBlock->renderstate[State]; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_BeginStateBlock(LPDIRECT3DDEVICE8 iface) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| return IDirect3DDeviceImpl_BeginStateBlock(This); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_EndStateBlock(LPDIRECT3DDEVICE8 iface, DWORD* pToken) { | |
| IDirect3DStateBlockImpl* pSB; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| HRESULT res; | |
| TRACE("(%p)\n", This); | |
| res = IDirect3DDeviceImpl_EndStateBlock(This, &pSB); | |
| *pToken = (DWORD) pSB; | |
| return res; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_ApplyStateBlock(LPDIRECT3DDEVICE8 iface, DWORD Token) { | |
| IDirect3DStateBlockImpl* pSB = (IDirect3DStateBlockImpl*) Token; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| return IDirect3DDeviceImpl_ApplyStateBlock(This, pSB); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CaptureStateBlock(LPDIRECT3DDEVICE8 iface, DWORD Token) { | |
| IDirect3DStateBlockImpl* pSB = (IDirect3DStateBlockImpl*) Token; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| return IDirect3DDeviceImpl_CaptureStateBlock(This, pSB); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DeleteStateBlock(LPDIRECT3DDEVICE8 iface, DWORD Token) { | |
| IDirect3DStateBlockImpl* pSB = (IDirect3DStateBlockImpl*) Token; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p)\n", This); | |
| return IDirect3DDeviceImpl_DeleteStateBlock(This, pSB); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateStateBlock(LPDIRECT3DDEVICE8 iface, D3DSTATEBLOCKTYPE Type, DWORD* pToken) { | |
| IDirect3DStateBlockImpl* pSB; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| HRESULT res; | |
| TRACE("(%p) : for type %d\n", This, Type); | |
| res = IDirect3DDeviceImpl_CreateStateBlock(This, Type, &pSB); | |
| *pToken = (DWORD) pSB; | |
| return res; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetClipStatus(LPDIRECT3DDEVICE8 iface, CONST D3DCLIPSTATUS8* pClipStatus) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| if (NULL == pClipStatus) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| This->UpdateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion; | |
| This->UpdateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetClipStatus(LPDIRECT3DDEVICE8 iface, D3DCLIPSTATUS8* pClipStatus) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| if (NULL == pClipStatus) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| pClipStatus->ClipUnion = This->UpdateStateBlock->clip_status.ClipUnion; | |
| pClipStatus->ClipIntersection = This->UpdateStateBlock->clip_status.ClipIntersection; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetTexture(LPDIRECT3DDEVICE8 iface, DWORD Stage,IDirect3DBaseTexture8** ppTexture) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : returning %p for stage %ld\n", This, This->UpdateStateBlock->textures[Stage], Stage); | |
| *ppTexture = (LPDIRECT3DBASETEXTURE8) This->UpdateStateBlock->textures[Stage]; | |
| if (*ppTexture) | |
| IDirect3DBaseTexture8Impl_AddRef(*ppTexture); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetTexture(LPDIRECT3DDEVICE8 iface, DWORD Stage, IDirect3DBaseTexture8* pTexture) { | |
| IDirect3DBaseTexture8 *oldTxt; | |
| BOOL reapplyStates = TRUE; | |
| INT oldTextureDimensions = -1; | |
| DWORD reapplyFlags = 0; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| D3DRESOURCETYPE textureType; | |
| oldTxt = This->UpdateStateBlock->textures[Stage]; | |
| TRACE("(%p) : Stage(%ld), Texture (%p)\n", This, Stage, pTexture); | |
| /* Reject invalid texture units */ | |
| if (Stage >= GL_LIMITS(textures)) { | |
| TRACE("Attempt to access invalid texture rejected\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| This->UpdateStateBlock->Set.textures[Stage] = TRUE; | |
| This->UpdateStateBlock->Changed.textures[Stage] = TRUE; | |
| This->UpdateStateBlock->textures[Stage] = pTexture; | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| oldTextureDimensions = This->UpdateStateBlock->textureDimensions[Stage]; | |
| ENTER_GL(); | |
| /* Make appropriate texture active */ | |
| if (GL_SUPPORT(ARB_MULTITEXTURE)) { | |
| #if defined(GL_VERSION_1_3) | |
| glActiveTexture(GL_TEXTURE0 + Stage); | |
| checkGLcall("glActiveTexture"); | |
| #else | |
| glActiveTextureARB(GL_TEXTURE0_ARB + Stage); | |
| checkGLcall("glActiveTextureARB"); | |
| #endif | |
| } else if (Stage>0) { | |
| FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); | |
| } | |
| /* Decrement the count of the previous texture */ | |
| if (NULL != oldTxt) { | |
| IDirect3DBaseTexture8Impl_Release(oldTxt); | |
| } | |
| if (NULL != pTexture) { | |
| IDirect3DBaseTexture8Impl_AddRef((LPDIRECT3DBASETEXTURE8) This->UpdateStateBlock->textures[Stage]); | |
| /* Now setup the texture appropraitly */ | |
| textureType = IDirect3DBaseTexture8Impl_GetType(pTexture); | |
| if (textureType == D3DRTYPE_TEXTURE) { | |
| if (oldTxt == pTexture && IDirect3DBaseTexture8Impl_IsDirty(pTexture)) { | |
| TRACE("Skipping setting texture as old == new\n"); | |
| reapplyStates = FALSE; | |
| } else { | |
| /* Standard 2D texture */ | |
| TRACE("Standard 2d texture\n"); | |
| This->UpdateStateBlock->textureDimensions[Stage] = GL_TEXTURE_2D; | |
| /* Load up the texture now */ | |
| IDirect3DTexture8Impl_PreLoad((LPDIRECT3DTEXTURE8) pTexture); | |
| } | |
| } else if (textureType == D3DRTYPE_VOLUMETEXTURE) { | |
| if (oldTxt == pTexture && IDirect3DBaseTexture8Impl_IsDirty(pTexture)) { | |
| TRACE("Skipping setting texture as old == new\n"); | |
| reapplyStates = FALSE; | |
| } else { | |
| /* Standard 3D (volume) texture */ | |
| TRACE("Standard 3d texture\n"); | |
| This->UpdateStateBlock->textureDimensions[Stage] = GL_TEXTURE_3D; | |
| /* Load up the texture now */ | |
| IDirect3DVolumeTexture8Impl_PreLoad((LPDIRECT3DVOLUMETEXTURE8) pTexture); | |
| } | |
| } else if (textureType == D3DRTYPE_CUBETEXTURE) { | |
| if (oldTxt == pTexture && IDirect3DBaseTexture8Impl_IsDirty(pTexture)) { | |
| TRACE("Skipping setting texture as old == new\n"); | |
| reapplyStates = FALSE; | |
| } else { | |
| /* Standard Cube texture */ | |
| TRACE("Standard Cube texture\n"); | |
| This->UpdateStateBlock->textureDimensions[Stage] = GL_TEXTURE_CUBE_MAP_ARB; | |
| /* Load up the texture now */ | |
| IDirect3DCubeTexture8Impl_PreLoad((LPDIRECT3DCUBETEXTURE8) pTexture); | |
| } | |
| } else { | |
| FIXME("(%p) : Incorrect type for a texture : (%d,%s)\n", This, textureType, debug_d3dressourcetype(textureType)); | |
| } | |
| } else { | |
| TRACE("Setting to no texture (ie default texture)\n"); | |
| This->UpdateStateBlock->textureDimensions[Stage] = GL_TEXTURE_1D; | |
| glBindTexture(GL_TEXTURE_1D, This->dummyTextureName[Stage]); | |
| checkGLcall("glBindTexture"); | |
| TRACE("Bound dummy Texture to stage %ld (gl name %d)\n", Stage, This->dummyTextureName[Stage]); | |
| } | |
| /* Disable the old texture binding and enable the new one (unless operations are disabled) */ | |
| if (oldTextureDimensions != This->UpdateStateBlock->textureDimensions[Stage]) { | |
| glDisable(oldTextureDimensions); | |
| checkGLcall("Disable oldTextureDimensions"); | |
| if (This->StateBlock->texture_state[Stage][D3DTSS_COLOROP] != D3DTOP_DISABLE) { | |
| glEnable(This->UpdateStateBlock->textureDimensions[Stage]); | |
| checkGLcall("glEnable new texture dimensions"); | |
| } | |
| /* If Alpha arg1 is texture then handle the special case when there changes between a | |
| texture and no texture - See comments in set_tex_op */ | |
| if ((This->StateBlock->texture_state[Stage][D3DTSS_ALPHAARG1] == D3DTA_TEXTURE) && | |
| (((oldTxt == NULL) && (pTexture != NULL)) || ((pTexture == NULL) && (oldTxt != NULL)))) | |
| { | |
| reapplyFlags |= REAPPLY_ALPHAOP; | |
| } | |
| } | |
| /* Even if the texture has been set to null, reapply the stages as a null texture to directx requires | |
| a dummy texture in opengl, and we always need to ensure the current view of the TextureStates apply */ | |
| if (reapplyStates) { | |
| setupTextureStates(iface, Stage, reapplyFlags); | |
| } | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetTextureStageState(LPDIRECT3DDEVICE8 iface, DWORD Stage,D3DTEXTURESTAGESTATETYPE Type,DWORD* pValue) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : requesting Stage %ld, Type %d getting %ld\n", This, Stage, Type, This->UpdateStateBlock->texture_state[Stage][Type]); | |
| *pValue = This->UpdateStateBlock->texture_state[Stage][Type]; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetTextureStageState(LPDIRECT3DDEVICE8 iface, DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| union { | |
| float f; | |
| DWORD d; | |
| } tmpvalue; | |
| /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */ | |
| TRACE("(%p) : Stage=%ld, Type=%s(%d), Value=%ld\n", This, Stage, debug_d3dtexturestate(Type), Type, Value); | |
| /* Reject invalid texture units */ | |
| if (Stage >= GL_LIMITS(textures)) { | |
| TRACE("Attempt to access invalid texture rejected\n"); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| This->UpdateStateBlock->Changed.texture_state[Stage][Type] = TRUE; | |
| This->UpdateStateBlock->Set.texture_state[Stage][Type] = TRUE; | |
| This->UpdateStateBlock->texture_state[Stage][Type] = Value; | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| ENTER_GL(); | |
| /* Make appropriate texture active */ | |
| VTRACE(("Activating appropriate texture state %ld\n", Stage)); | |
| if (GL_SUPPORT(ARB_MULTITEXTURE)) { | |
| #if defined(GL_VERSION_1_3) | |
| glActiveTexture(GL_TEXTURE0 + Stage); | |
| vcheckGLcall("glActiveTexture"); | |
| #else | |
| glActiveTextureARB(GL_TEXTURE0_ARB + Stage); | |
| vcheckGLcall("glActiveTextureARB"); | |
| #endif | |
| } else if (Stage > 0) { | |
| FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n"); | |
| } | |
| switch (Type) { | |
| case D3DTSS_MINFILTER : | |
| case D3DTSS_MIPFILTER : | |
| { | |
| DWORD ValueMIN = This->StateBlock->texture_state[Stage][D3DTSS_MINFILTER]; | |
| DWORD ValueMIP = This->StateBlock->texture_state[Stage][D3DTSS_MIPFILTER]; | |
| GLint realVal = GL_LINEAR; | |
| if (ValueMIN == D3DTEXF_NONE) { | |
| /* Doesn't really make sense - Windows just seems to disable | |
| mipmapping when this occurs */ | |
| FIXME("Odd - minfilter of none, just disabling mipmaps\n"); | |
| realVal = GL_LINEAR; | |
| } else if (ValueMIN == D3DTEXF_POINT) { | |
| /* GL_NEAREST_* */ | |
| if (ValueMIP == D3DTEXF_NONE) { | |
| realVal = GL_NEAREST; | |
| } else if (ValueMIP == D3DTEXF_POINT) { | |
| realVal = GL_NEAREST_MIPMAP_NEAREST; | |
| } else if (ValueMIP == D3DTEXF_LINEAR) { | |
| realVal = GL_NEAREST_MIPMAP_LINEAR; | |
| } else { | |
| FIXME("Unhandled D3DTSS_MIPFILTER value of %ld\n", ValueMIP); | |
| realVal = GL_NEAREST; | |
| } | |
| } else if (ValueMIN == D3DTEXF_LINEAR) { | |
| /* GL_LINEAR_* */ | |
| if (ValueMIP == D3DTEXF_NONE) { | |
| realVal = GL_LINEAR; | |
| } else if (ValueMIP == D3DTEXF_POINT) { | |
| realVal = GL_LINEAR_MIPMAP_NEAREST; | |
| } else if (ValueMIP == D3DTEXF_LINEAR) { | |
| realVal = GL_LINEAR_MIPMAP_LINEAR; | |
| } else { | |
| FIXME("Unhandled D3DTSS_MIPFILTER value of %ld\n", ValueMIP); | |
| realVal = GL_LINEAR; | |
| } | |
| } else if (ValueMIN == D3DTEXF_ANISOTROPIC) { | |
| if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { | |
| if (ValueMIP == D3DTEXF_NONE) { | |
| realVal = GL_LINEAR_MIPMAP_LINEAR; | |
| } else if (ValueMIP == D3DTEXF_POINT) { | |
| realVal = GL_LINEAR_MIPMAP_NEAREST; | |
| } else if (ValueMIP == D3DTEXF_LINEAR) { | |
| realVal = GL_LINEAR_MIPMAP_LINEAR; | |
| } else { | |
| FIXME("Unhandled D3DTSS_MIPFILTER value of %ld\n", ValueMIP); | |
| realVal = GL_LINEAR; | |
| } | |
| } else { | |
| WARN("Trying to use ANISOTROPIC_FILTERING for D3DTSS_MINFILTER. But not supported by OpenGL driver\n"); | |
| realVal = GL_LINEAR; | |
| } | |
| } else { | |
| FIXME("Unhandled D3DTSS_MINFILTER value of %ld\n", ValueMIN); | |
| realVal = GL_LINEAR_MIPMAP_LINEAR; | |
| } | |
| TRACE("ValueMIN=%ld, ValueMIP=%ld, setting MINFILTER to %x\n", ValueMIN, ValueMIP, realVal); | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], GL_TEXTURE_MIN_FILTER, realVal); | |
| checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ..."); | |
| /** | |
| * if we juste choose to use ANISOTROPIC filtering, refresh openGL state | |
| */ | |
| if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && D3DTEXF_ANISOTROPIC == ValueMIN) { | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], | |
| GL_TEXTURE_MAX_ANISOTROPY_EXT, | |
| This->StateBlock->texture_state[Stage][D3DTSS_MAXANISOTROPY]); | |
| checkGLcall("glTexParameter GL_TEXTURE_MAX_ANISOTROPY_EXT, ..."); | |
| } | |
| } | |
| break; | |
| case D3DTSS_MAGFILTER : | |
| { | |
| DWORD ValueMAG = This->StateBlock->texture_state[Stage][D3DTSS_MAGFILTER]; | |
| GLint realVal = GL_NEAREST; | |
| if (ValueMAG == D3DTEXF_POINT) { | |
| realVal = GL_NEAREST; | |
| } else if (ValueMAG == D3DTEXF_LINEAR) { | |
| realVal = GL_LINEAR; | |
| } else if (ValueMAG == D3DTEXF_ANISOTROPIC) { | |
| if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { | |
| realVal = GL_LINEAR; | |
| } else { | |
| FIXME("Trying to use ANISOTROPIC_FILTERING for D3DTSS_MAGFILTER. But not supported by current OpenGL driver\n"); | |
| realVal = GL_NEAREST; | |
| } | |
| } else { | |
| FIXME("Unhandled D3DTSS_MAGFILTER value of %ld\n", ValueMAG); | |
| realVal = GL_NEAREST; | |
| } | |
| TRACE("ValueMAG=%ld setting MAGFILTER to %x\n", ValueMAG, realVal); | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], GL_TEXTURE_MAG_FILTER, realVal); | |
| checkGLcall("glTexParameter GL_TEXTURE_MAG_FILTER, ..."); | |
| /** | |
| * if we juste choose to use ANISOTROPIC filtering, refresh openGL state | |
| */ | |
| if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && D3DTEXF_ANISOTROPIC == ValueMAG) { | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], | |
| GL_TEXTURE_MAX_ANISOTROPY_EXT, | |
| This->StateBlock->texture_state[Stage][D3DTSS_MAXANISOTROPY]); | |
| checkGLcall("glTexParameter GL_TEXTURE_MAX_ANISOTROPY_EXT, ..."); | |
| } | |
| } | |
| break; | |
| case D3DTSS_MAXMIPLEVEL : | |
| { | |
| /** | |
| * Not really the same, but the more apprioprate than nothing | |
| */ | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], | |
| GL_TEXTURE_BASE_LEVEL, | |
| This->StateBlock->texture_state[Stage][D3DTSS_MAXMIPLEVEL]); | |
| checkGLcall("glTexParameteri GL_TEXTURE_BASE_LEVEL ..."); | |
| } | |
| break; | |
| case D3DTSS_MAXANISOTROPY : | |
| { | |
| if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC)) { | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], | |
| GL_TEXTURE_MAX_ANISOTROPY_EXT, | |
| This->StateBlock->texture_state[Stage][D3DTSS_MAXANISOTROPY]); | |
| checkGLcall("glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT ..."); | |
| } | |
| } | |
| break; | |
| case D3DTSS_MIPMAPLODBIAS : | |
| { | |
| if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) { | |
| tmpvalue.d = Value; | |
| glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, | |
| GL_TEXTURE_LOD_BIAS_EXT, | |
| tmpvalue.f); | |
| checkGLcall("glTexEnvi GL_TEXTURE_LOD_BIAS_EXT ..."); | |
| } | |
| } | |
| break; | |
| case D3DTSS_ALPHAOP : | |
| case D3DTSS_COLOROP : | |
| { | |
| if ((Value == D3DTOP_DISABLE) && (Type == D3DTSS_COLOROP)) { | |
| /* TODO: Disable by making this and all later levels disabled */ | |
| glDisable(GL_TEXTURE_1D); | |
| checkGLcall("Disable GL_TEXTURE_1D"); | |
| glDisable(GL_TEXTURE_2D); | |
| checkGLcall("Disable GL_TEXTURE_2D"); | |
| glDisable(GL_TEXTURE_3D); | |
| checkGLcall("Disable GL_TEXTURE_3D"); | |
| break; /* Don't bother setting the texture operations */ | |
| } else { | |
| /* Enable only the appropriate texture dimension */ | |
| if (Type == D3DTSS_COLOROP) { | |
| if (This->StateBlock->textureDimensions[Stage] == GL_TEXTURE_1D) { | |
| glEnable(GL_TEXTURE_1D); | |
| checkGLcall("Enable GL_TEXTURE_1D"); | |
| } else { | |
| glDisable(GL_TEXTURE_1D); | |
| checkGLcall("Disable GL_TEXTURE_1D"); | |
| } | |
| if (This->StateBlock->textureDimensions[Stage] == GL_TEXTURE_2D) { | |
| if (GL_SUPPORT(NV_TEXTURE_SHADER) && This->texture_shader_active) { | |
| glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D); | |
| checkGLcall("Enable GL_TEXTURE_2D"); | |
| } else { | |
| glEnable(GL_TEXTURE_2D); | |
| checkGLcall("Enable GL_TEXTURE_2D"); | |
| } | |
| } else { | |
| glDisable(GL_TEXTURE_2D); | |
| checkGLcall("Disable GL_TEXTURE_2D"); | |
| } | |
| if (This->StateBlock->textureDimensions[Stage] == GL_TEXTURE_3D) { | |
| glEnable(GL_TEXTURE_3D); | |
| checkGLcall("Enable GL_TEXTURE_3D"); | |
| } else { | |
| glDisable(GL_TEXTURE_3D); | |
| checkGLcall("Disable GL_TEXTURE_3D"); | |
| } | |
| if (This->StateBlock->textureDimensions[Stage] == GL_TEXTURE_CUBE_MAP_ARB) { | |
| glEnable(GL_TEXTURE_CUBE_MAP_ARB); | |
| checkGLcall("Enable GL_TEXTURE_CUBE_MAP"); | |
| } else { | |
| glDisable(GL_TEXTURE_CUBE_MAP_ARB); | |
| checkGLcall("Disable GL_TEXTURE_CUBE_MAP"); | |
| } | |
| } | |
| } | |
| /* Drop through... (Except disable case) */ | |
| case D3DTSS_COLORARG0 : | |
| case D3DTSS_COLORARG1 : | |
| case D3DTSS_COLORARG2 : | |
| case D3DTSS_ALPHAARG0 : | |
| case D3DTSS_ALPHAARG1 : | |
| case D3DTSS_ALPHAARG2 : | |
| { | |
| BOOL isAlphaArg = (Type == D3DTSS_ALPHAOP || Type == D3DTSS_ALPHAARG1 || | |
| Type == D3DTSS_ALPHAARG2 || Type == D3DTSS_ALPHAARG0); | |
| if (isAlphaArg) { | |
| set_tex_op(iface, TRUE, Stage, This->StateBlock->texture_state[Stage][D3DTSS_ALPHAOP], | |
| This->StateBlock->texture_state[Stage][D3DTSS_ALPHAARG1], | |
| This->StateBlock->texture_state[Stage][D3DTSS_ALPHAARG2], | |
| This->StateBlock->texture_state[Stage][D3DTSS_ALPHAARG0]); | |
| } else { | |
| set_tex_op(iface, FALSE, Stage, This->StateBlock->texture_state[Stage][D3DTSS_COLOROP], | |
| This->StateBlock->texture_state[Stage][D3DTSS_COLORARG1], | |
| This->StateBlock->texture_state[Stage][D3DTSS_COLORARG2], | |
| This->StateBlock->texture_state[Stage][D3DTSS_COLORARG0]); | |
| } | |
| } | |
| break; | |
| } | |
| case D3DTSS_ADDRESSU : | |
| case D3DTSS_ADDRESSV : | |
| case D3DTSS_ADDRESSW : | |
| { | |
| GLint wrapParm = GL_REPEAT; | |
| switch (Value) { | |
| case D3DTADDRESS_WRAP: wrapParm = GL_REPEAT; break; | |
| case D3DTADDRESS_CLAMP: wrapParm = GL_CLAMP_TO_EDGE; break; | |
| case D3DTADDRESS_BORDER: | |
| { | |
| if (GL_SUPPORT(ARB_TEXTURE_BORDER_CLAMP)) { | |
| wrapParm = GL_CLAMP_TO_BORDER_ARB; | |
| } else { | |
| /* FIXME: Not right, but better */ | |
| FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type); | |
| wrapParm = GL_REPEAT; | |
| } | |
| } | |
| break; | |
| case D3DTADDRESS_MIRROR: | |
| { | |
| if (GL_SUPPORT(ARB_TEXTURE_MIRRORED_REPEAT)) { | |
| wrapParm = GL_MIRRORED_REPEAT_ARB; | |
| } else { | |
| /* Unsupported in OpenGL pre-1.4 */ | |
| FIXME("Unsupported D3DTADDRESS_MIRROR (needs GL_ARB_texture_mirrored_repeat) state %d\n", Type); | |
| wrapParm = GL_REPEAT; | |
| } | |
| } | |
| break; | |
| case D3DTADDRESS_MIRRORONCE: | |
| { | |
| if (GL_SUPPORT(ATI_TEXTURE_MIRROR_ONCE)) { | |
| wrapParm = GL_MIRROR_CLAMP_TO_EDGE_ATI; | |
| } else { | |
| FIXME("Unsupported D3DTADDRESS_MIRRORONCE (needs GL_ATI_texture_mirror_once) state %d\n", Type); | |
| wrapParm = GL_REPEAT; | |
| } | |
| } | |
| break; | |
| default: | |
| FIXME("Unrecognized or unsupported D3DTADDRESS_* value %ld, state %d\n", Value, Type); | |
| wrapParm = GL_REPEAT; | |
| } | |
| switch (Type) { | |
| case D3DTSS_ADDRESSU: | |
| TRACE("Setting WRAP_S to %d for %x\n", wrapParm, This->StateBlock->textureDimensions[Stage]); | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_S, wrapParm); | |
| checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_S, wrapParm)"); | |
| break; | |
| case D3DTSS_ADDRESSV: | |
| TRACE("Setting WRAP_T to %d for %x\n", wrapParm, This->StateBlock->textureDimensions[Stage]); | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_T, wrapParm); | |
| checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_T, wrapParm)"); | |
| break; | |
| case D3DTSS_ADDRESSW: | |
| TRACE("Setting WRAP_R to %d for %x\n", wrapParm, This->StateBlock->textureDimensions[Stage]); | |
| glTexParameteri(This->StateBlock->textureDimensions[Stage], GL_TEXTURE_WRAP_R, wrapParm); | |
| checkGLcall("glTexParameteri(..., GL_TEXTURE_WRAP_R, wrapParm)"); | |
| break; | |
| default: /* nop */ | |
| break; /** stupic compilator */ | |
| } | |
| } | |
| break; | |
| case D3DTSS_BORDERCOLOR : | |
| { | |
| float col[4]; | |
| D3DCOLORTOGLFLOAT4(Value, col); | |
| TRACE("Setting border color for %x to %lx\n", This->StateBlock->textureDimensions[Stage], Value); | |
| glTexParameterfv(This->StateBlock->textureDimensions[Stage], GL_TEXTURE_BORDER_COLOR, &col[0]); | |
| checkGLcall("glTexParameteri(..., GL_TEXTURE_BORDER_COLOR, ...)"); | |
| } | |
| break; | |
| case D3DTSS_TEXCOORDINDEX : | |
| { | |
| /* Values 0-7 are indexes into the FVF tex coords - See comments in DrawPrimitive */ | |
| /* FIXME: From MSDN: The D3DTSS_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, D3DTSS_TEXCOORDINDEX, D3DTSS_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 D3DRS_WRAP1 render | |
| state. We do not (yet) support the D3DRENDERSTATE_WRAPx values, nor tie them up | |
| to the TEXCOORDINDEX value */ | |
| /** | |
| * Be careful the value of the mask 0xF0000 come from d3d8types.h infos | |
| */ | |
| switch (Value & 0xFFFF0000) { | |
| case D3DTSS_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); | |
| checkGLcall("glDisable(GL_TEXTURE_GEN_S,T,R)"); | |
| break; | |
| case D3DTSS_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("D3DTSS_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("D3DTSS_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 D3DTSS_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("D3DTSS_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(); | |
| 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 D3DTSS_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("D3DTSS_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(); | |
| 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); | |
| FIXME("Unhandled D3DTSS_TEXCOORDINDEX %lx\n", Value); | |
| break; | |
| } | |
| } | |
| break; | |
| /* Unhandled */ | |
| case D3DTSS_TEXTURETRANSFORMFLAGS : | |
| set_texture_matrix((float *)&This->StateBlock->transforms[D3DTS_TEXTURE0 + Stage].u.m[0][0], Value); | |
| break; | |
| case D3DTSS_BUMPENVMAT00 : | |
| case D3DTSS_BUMPENVMAT01 : | |
| TRACE("BUMPENVMAT0%u Stage=%ld, Type=%d, Value =%ld\n", Type - D3DTSS_BUMPENVMAT00, Stage, Type, Value); | |
| break; | |
| case D3DTSS_BUMPENVMAT10 : | |
| case D3DTSS_BUMPENVMAT11 : | |
| TRACE("BUMPENVMAT1%u Stage=%ld, Type=%d, Value =%ld\n", Type - D3DTSS_BUMPENVMAT10, Stage, Type, Value); | |
| break; | |
| case D3DTSS_BUMPENVLSCALE : | |
| TRACE("BUMPENVLSCALE Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value); | |
| break; | |
| case D3DTSS_BUMPENVLOFFSET : | |
| TRACE("BUMPENVLOFFSET Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value); | |
| break; | |
| case D3DTSS_RESULTARG : | |
| TRACE("RESULTARG Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value); | |
| break; | |
| default: | |
| /* Put back later: FIXME("(%p) : stub, Stage=%ld, Type=%d, Value =%ld\n", This, Stage, Type, Value); */ | |
| TRACE("Still a stub, Stage=%ld, Type=%d, Value =%ld\n", Stage, Type, Value); | |
| } | |
| LEAVE_GL(); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_ValidateDevice(LPDIRECT3DDEVICE8 iface, DWORD* pNumPasses) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : stub\n", This); /* FIXME: Needs doing, but called often and is harmless */ | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetInfo(LPDIRECT3DDEVICE8 iface, DWORD DevInfoID, void* pDevInfoStruct, DWORD DevInfoStructSize) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetPaletteEntries(LPDIRECT3DDEVICE8 iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : setting p[%u] <= RGBA(%02x,%02x,%02x,%02x)\n", This, PaletteNumber, | |
| pEntries->peRed, pEntries->peGreen, pEntries->peBlue, pEntries->peFlags); | |
| if (PaletteNumber >= MAX_PALETTES) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| memcpy(This->palettes[PaletteNumber], pEntries, 256 * sizeof(PALETTEENTRY)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetPaletteEntries(LPDIRECT3DDEVICE8 iface, UINT PaletteNumber, PALETTEENTRY* pEntries) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| if (PaletteNumber >= MAX_PALETTES) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| memcpy(pEntries, This->palettes[PaletteNumber], 256 * sizeof(PALETTEENTRY)); | |
| FIXME("(%p) : returning p[%u] => RGBA(%02x,%02x,%02x,%02x)\n", This, PaletteNumber, | |
| pEntries->peRed, pEntries->peGreen, pEntries->peBlue, pEntries->peFlags); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetCurrentTexturePalette(LPDIRECT3DDEVICE8 iface, UINT PaletteNumber) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : Setting to (%u)\n", This, PaletteNumber); | |
| if (PaletteNumber >= MAX_PALETTES) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| This->currentPalette = PaletteNumber; | |
| #if defined(GL_EXT_paletted_texture) | |
| if (GL_SUPPORT(EXT_PALETTED_TEXTURE)) { | |
| ENTER_GL(); | |
| GL_EXTCALL(glColorTableEXT)(GL_TEXTURE_2D, /* target */ | |
| GL_RGBA, /* internal format */ | |
| 256, /* table size */ | |
| GL_RGBA, /* table format */ | |
| GL_UNSIGNED_BYTE, /* table type */ | |
| This->palettes[PaletteNumber]); | |
| checkGLcall("glColorTableEXT"); | |
| LEAVE_GL(); | |
| } else { | |
| /* Delayed palette handling ... waiting for software emulation into preload code */ | |
| } | |
| #endif | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetCurrentTexturePalette(LPDIRECT3DDEVICE8 iface, UINT *PaletteNumber) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| *PaletteNumber = This->currentPalette; | |
| FIXME("(%p) : Returning (%u)\n", This, *PaletteNumber); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DrawPrimitive(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| This->StateBlock->streamIsUP = FALSE; | |
| TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType), StartVertex, PrimitiveCount); | |
| drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, -1, 0, NULL, 0); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DrawIndexedPrimitive(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType, | |
| UINT minIndex,UINT NumVertices,UINT startIndex,UINT primCount) { | |
| UINT idxStride = 2; | |
| IDirect3DIndexBuffer8 *pIB; | |
| D3DINDEXBUFFER_DESC IdxBufDsc; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| pIB = This->StateBlock->pIndexData; | |
| This->StateBlock->streamIsUP = FALSE; | |
| TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d \n", This, | |
| PrimitiveType, debug_d3dprimitivetype(PrimitiveType), | |
| minIndex, NumVertices, startIndex, primCount); | |
| IDirect3DIndexBuffer8Impl_GetDesc(pIB, &IdxBufDsc); | |
| if (IdxBufDsc.Format == D3DFMT_INDEX16) { | |
| idxStride = 2; | |
| } else { | |
| idxStride = 4; | |
| } | |
| drawPrimitive(iface, PrimitiveType, primCount, This->StateBlock->baseVertexIndex, startIndex, idxStride, ((IDirect3DIndexBuffer8Impl *) pIB)->allocatedMemory, | |
| minIndex); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DrawPrimitiveUP(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType,UINT PrimitiveCount,CONST void* pVertexStreamZeroData,UINT VertexStreamZeroStride) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType), | |
| PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride); | |
| if (This->StateBlock->stream_source[0] != NULL) IDirect3DVertexBuffer8Impl_Release(This->StateBlock->stream_source[0]); | |
| /* Note in the following, its not this type, but thats the purpose of streamIsUP */ | |
| This->StateBlock->stream_source[0] = (IDirect3DVertexBuffer8 *)pVertexStreamZeroData; | |
| This->StateBlock->stream_stride[0] = VertexStreamZeroStride; | |
| This->StateBlock->streamIsUP = TRUE; | |
| drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0); | |
| This->StateBlock->stream_stride[0] = 0; | |
| This->StateBlock->stream_source[0] = NULL; | |
| /*stream zero settings set to null at end */ | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DrawIndexedPrimitiveUP(LPDIRECT3DDEVICE8 iface, D3DPRIMITIVETYPE PrimitiveType,UINT MinVertexIndex, | |
| UINT NumVertexIndices,UINT PrimitiveCount,CONST void* pIndexData, | |
| D3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData, | |
| UINT VertexStreamZeroStride) { | |
| int idxStride; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| 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, NumVertexIndices, PrimitiveCount, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride); | |
| if (This->StateBlock->stream_source[0] != NULL) IDirect3DVertexBuffer8Impl_Release(This->StateBlock->stream_source[0]); | |
| if (IndexDataFormat == D3DFMT_INDEX16) { | |
| idxStride = 2; | |
| } else { | |
| idxStride = 4; | |
| } | |
| /* Note in the following, its not this type, but thats the purpose of streamIsUP */ | |
| This->StateBlock->stream_source[0] = (IDirect3DVertexBuffer8 *)pVertexStreamZeroData; | |
| This->StateBlock->streamIsUP = TRUE; | |
| This->StateBlock->stream_stride[0] = VertexStreamZeroStride; | |
| drawPrimitive(iface, PrimitiveType, PrimitiveCount, This->StateBlock->baseVertexIndex, 0, idxStride, pIndexData, MinVertexIndex); | |
| /*stream zero settings set to null at end */ | |
| This->StateBlock->stream_source[0] = NULL; | |
| This->StateBlock->stream_stride[0] = 0; | |
| IDirect3DDevice8Impl_SetIndices(iface, NULL, 0); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_ProcessVertices(LPDIRECT3DDEVICE8 iface, UINT SrcStartIndex,UINT DestIndex,UINT VertexCount,IDirect3DVertexBuffer8* pDestBuffer,DWORD Flags) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreateVertexShader(LPDIRECT3DDEVICE8 iface, CONST DWORD* pDeclaration, CONST DWORD* pFunction, DWORD* pHandle, DWORD Usage) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| IDirect3DVertexShaderImpl* object; | |
| IDirect3DVertexShaderDeclarationImpl* attached_decl; | |
| HRESULT res; | |
| UINT i; | |
| TRACE_(d3d_shader)("(%p) : VertexShader not fully supported yet : Decl=%p, Func=%p, Usage=%lu\n", This, pDeclaration, pFunction, Usage); | |
| if (NULL == pDeclaration || NULL == pHandle) { /* pFunction can be NULL see MSDN */ | |
| return D3DERR_INVALIDCALL; | |
| } | |
| for (i = 1; NULL != VertexShaders[i] && i < sizeof(VertexShaders) / sizeof(IDirect3DVertexShaderImpl*); ++i) ; | |
| if (i >= sizeof(VertexShaders) / sizeof(IDirect3DVertexShaderImpl*)) { | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| /** Create the Vertex Shader */ | |
| res = IDirect3DDeviceImpl_CreateVertexShader(This, pFunction, Usage, &object); | |
| /** TODO: check FAILED(res) */ | |
| /** Create and Bind the Vertex Shader Declaration */ | |
| res = IDirect3DDeviceImpl_CreateVertexShaderDeclaration8(This, pDeclaration, &attached_decl); | |
| /** TODO: check FAILED(res) */ | |
| VertexShaders[i] = object; | |
| VertexShaderDeclarations[i] = attached_decl; | |
| *pHandle = VS_HIGHESTFIXEDFXF + i; | |
| TRACE("Finished creating vertex shader %lx\n", *pHandle); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetVertexShader(LPDIRECT3DDEVICE8 iface, DWORD Handle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| This->UpdateStateBlock->VertexShader = Handle; | |
| This->UpdateStateBlock->Changed.vertexShader = TRUE; | |
| This->UpdateStateBlock->Set.vertexShader = TRUE; | |
| if (Handle > VS_HIGHESTFIXEDFXF) { /* only valid with non FVF shaders */ | |
| TRACE_(d3d_shader)("(%p) : Created shader, Handle=%lx\n", This, Handle); | |
| This->UpdateStateBlock->vertexShaderDecl = VERTEX_SHADER_DECL(Handle); | |
| This->UpdateStateBlock->Changed.vertexShaderDecl = TRUE; | |
| This->UpdateStateBlock->Set.vertexShaderDecl = TRUE; | |
| } else { /* use a fvf, so desactivate the vshader decl */ | |
| TRACE("(%p) : FVF Shader, Handle=%lx\n", This, Handle); | |
| This->UpdateStateBlock->vertexShaderDecl = NULL; | |
| This->UpdateStateBlock->Changed.vertexShaderDecl = TRUE; | |
| This->UpdateStateBlock->Set.vertexShaderDecl = TRUE; | |
| } | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| /** | |
| * TODO: merge HAL shaders context switching from prototype | |
| */ | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShader(LPDIRECT3DDEVICE8 iface, DWORD* pHandle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE_(d3d_shader)("(%p) : GetVertexShader returning %ld\n", This, This->StateBlock->VertexShader); | |
| *pHandle = This->StateBlock->VertexShader; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DeleteVertexShader(LPDIRECT3DDEVICE8 iface, DWORD Handle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| IDirect3DVertexShaderImpl* object; | |
| IDirect3DVertexShaderDeclarationImpl* attached_decl; | |
| if (Handle <= VS_HIGHESTFIXEDFXF) { /* only delete user defined shaders */ | |
| return D3DERR_INVALIDCALL; | |
| } | |
| /** | |
| * Delete Vertex Shader | |
| */ | |
| object = VertexShaders[Handle - VS_HIGHESTFIXEDFXF]; | |
| if (NULL == object) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| TRACE_(d3d_shader)("(%p) : freing VertexShader %p\n", This, object); | |
| /* TODO: check validity of object */ | |
| HeapFree(GetProcessHeap(), 0, (void *)object->function); | |
| if (object->prgId != 0) { | |
| GL_EXTCALL(glDeleteProgramsARB( 1, &object->prgId )); | |
| } | |
| HeapFree(GetProcessHeap(), 0, (void *)object->data); | |
| HeapFree(GetProcessHeap(), 0, (void *)object); | |
| VertexShaders[Handle - VS_HIGHESTFIXEDFXF] = NULL; | |
| /** | |
| * Delete Vertex Shader Declaration | |
| */ | |
| attached_decl = VertexShaderDeclarations[Handle - VS_HIGHESTFIXEDFXF]; | |
| if (NULL == attached_decl) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| TRACE_(d3d_shader)("(%p) : freing VertexShaderDeclaration %p\n", This, attached_decl); | |
| /* TODO: check validity of object */ | |
| HeapFree(GetProcessHeap(), 0, (void *)attached_decl->pDeclaration8); | |
| HeapFree(GetProcessHeap(), 0, (void *)attached_decl); | |
| VertexShaderDeclarations[Handle - VS_HIGHESTFIXEDFXF] = NULL; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetVertexShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, CONST void* pConstantData, DWORD ConstantCount) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| if (Register + ConstantCount > D3D8_VSHADER_MAX_CONSTANTS) { | |
| ERR_(d3d_shader)("(%p) : SetVertexShaderConstant C[%lu] invalid\n", This, Register); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (NULL == pConstantData) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (ConstantCount > 1) { | |
| const FLOAT* f = (const FLOAT*)pConstantData; | |
| UINT i; | |
| TRACE_(d3d_shader)("(%p) : SetVertexShaderConstant C[%lu..%lu]=\n", This, Register, Register + ConstantCount - 1); | |
| for (i = 0; i < ConstantCount; ++i) { | |
| TRACE_(d3d_shader)("{%f, %f, %f, %f}\n", f[0], f[1], f[2], f[3]); | |
| f += 4; | |
| } | |
| } else { | |
| const FLOAT* f = (const FLOAT*) pConstantData; | |
| TRACE_(d3d_shader)("(%p) : SetVertexShaderConstant, C[%lu]={%f, %f, %f, %f}\n", This, Register, f[0], f[1], f[2], f[3]); | |
| } | |
| This->UpdateStateBlock->Changed.vertexShaderConstant = TRUE; | |
| memcpy(&This->UpdateStateBlock->vertexShaderConstant[Register], pConstantData, ConstantCount * 4 * sizeof(FLOAT)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, void* pConstantData, DWORD ConstantCount) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE_(d3d_shader)("(%p) : C[%lu] count=%ld\n", This, Register, ConstantCount); | |
| if (Register + ConstantCount > D3D8_VSHADER_MAX_CONSTANTS) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (NULL == pConstantData) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| memcpy(pConstantData, &This->UpdateStateBlock->vertexShaderConstant[Register], ConstantCount * 4 * sizeof(FLOAT)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShaderDeclaration(LPDIRECT3DDEVICE8 iface, DWORD Handle, void* pData, DWORD* pSizeOfData) { | |
| /*IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;*/ | |
| IDirect3DVertexShaderDeclarationImpl* attached_decl; | |
| attached_decl = VERTEX_SHADER_DECL(Handle); | |
| if (NULL == attached_decl) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| return IDirect3DVertexShaderDeclarationImpl_GetDeclaration8(attached_decl, pData, (UINT*) pSizeOfData); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetVertexShaderFunction(LPDIRECT3DDEVICE8 iface, DWORD Handle, void* pData, DWORD* pSizeOfData) { | |
| /*IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;*/ | |
| IDirect3DVertexShaderImpl* object; | |
| object = VERTEX_SHADER(Handle); | |
| if (NULL == object) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| return IDirect3DVertexShaderImpl_GetFunction(object, pData, (UINT*) pSizeOfData); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetIndices(LPDIRECT3DDEVICE8 iface, IDirect3DIndexBuffer8* pIndexData, UINT BaseVertexIndex) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| IDirect3DIndexBuffer8 *oldIdxs; | |
| TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex); | |
| oldIdxs = This->StateBlock->pIndexData; | |
| This->UpdateStateBlock->Changed.Indices = TRUE; | |
| This->UpdateStateBlock->Set.Indices = TRUE; | |
| This->UpdateStateBlock->pIndexData = pIndexData; | |
| This->UpdateStateBlock->baseVertexIndex = BaseVertexIndex; | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| if (oldIdxs) IDirect3DIndexBuffer8Impl_Release(oldIdxs); | |
| if (pIndexData) IDirect3DIndexBuffer8Impl_AddRef(This->StateBlock->pIndexData); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetIndices(LPDIRECT3DDEVICE8 iface, IDirect3DIndexBuffer8** ppIndexData,UINT* pBaseVertexIndex) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); | |
| *ppIndexData = This->StateBlock->pIndexData; | |
| /* up ref count on ppindexdata */ | |
| if (*ppIndexData) IDirect3DIndexBuffer8Impl_AddRef(*ppIndexData); | |
| *pBaseVertexIndex = This->StateBlock->baseVertexIndex; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_CreatePixelShader(LPDIRECT3DDEVICE8 iface, CONST DWORD* pFunction, DWORD* pHandle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| IDirect3DPixelShaderImpl* object; | |
| HRESULT res; | |
| UINT i; | |
| TRACE_(d3d_shader)("(%p) : PixelShader not fully supported yet : Func=%p\n", This, pFunction); | |
| if (NULL == pFunction || NULL == pHandle) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| for (i = 1; NULL != PixelShaders[i] && i < sizeof(PixelShaders) / sizeof(IDirect3DPixelShaderImpl*); ++i) ; | |
| if (i >= sizeof(PixelShaders) / sizeof(IDirect3DPixelShaderImpl*)) { | |
| return D3DERR_OUTOFVIDEOMEMORY; | |
| } | |
| /** Create the Pixel Shader */ | |
| res = IDirect3DDeviceImpl_CreatePixelShader(This, pFunction, &object); | |
| if (SUCCEEDED(res)) { | |
| PixelShaders[i] = object; | |
| *pHandle = VS_HIGHESTFIXEDFXF + i; | |
| return D3D_OK; | |
| } | |
| *pHandle = 0xFFFFFFFF; | |
| return res; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetPixelShader(LPDIRECT3DDEVICE8 iface, DWORD Handle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| This->UpdateStateBlock->PixelShader = Handle; | |
| This->UpdateStateBlock->Changed.pixelShader = TRUE; | |
| This->UpdateStateBlock->Set.pixelShader = TRUE; | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE_(d3d_shader)("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| if (Handle != 0) { | |
| TRACE_(d3d_shader)("(%p) : Set pixel shader with handle %lx\n", This, Handle); | |
| } else { | |
| TRACE_(d3d_shader)("(%p) : Remove pixel shader\n", This); | |
| } | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShader(LPDIRECT3DDEVICE8 iface, DWORD* pHandle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE_(d3d_shader)("(%p) : GetPixelShader returning %ld\n", This, This->StateBlock->PixelShader); | |
| *pHandle = This->StateBlock->PixelShader; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DeletePixelShader(LPDIRECT3DDEVICE8 iface, DWORD Handle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| IDirect3DPixelShaderImpl* object; | |
| if (Handle <= VS_HIGHESTFIXEDFXF) { /* only delete user defined shaders */ | |
| return D3DERR_INVALIDCALL; | |
| } | |
| object = PixelShaders[Handle - VS_HIGHESTFIXEDFXF]; | |
| if (NULL == object) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| TRACE_(d3d_shader)("(%p) : freeing PixelShader %p\n", This, object); | |
| /* TODO: check validity of object before free */ | |
| HeapFree(GetProcessHeap(), 0, (void *)object->function); | |
| if (object->prgId != 0) { | |
| GL_EXTCALL(glDeleteProgramsARB( 1, &object->prgId )); | |
| } | |
| HeapFree(GetProcessHeap(), 0, (void *)object->data); | |
| HeapFree(GetProcessHeap(), 0, (void *)object); | |
| PixelShaders[Handle - VS_HIGHESTFIXEDFXF] = NULL; | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetPixelShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, CONST void* pConstantData, DWORD ConstantCount) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| if (Register + ConstantCount > D3D8_PSHADER_MAX_CONSTANTS) { | |
| ERR_(d3d_shader)("(%p) : SetPixelShaderConstant C[%lu] invalid\n", This, Register); | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (NULL == pConstantData) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (ConstantCount > 1) { | |
| const FLOAT* f = (const FLOAT*)pConstantData; | |
| UINT i; | |
| TRACE_(d3d_shader)("(%p) : SetPixelShaderConstant C[%lu..%lu]=\n", This, Register, Register + ConstantCount - 1); | |
| for (i = 0; i < ConstantCount; ++i) { | |
| TRACE_(d3d_shader)("{%f, %f, %f, %f}\n", f[0], f[1], f[2], f[3]); | |
| f += 4; | |
| } | |
| } else { | |
| const FLOAT* f = (const FLOAT*) pConstantData; | |
| TRACE_(d3d_shader)("(%p) : SetPixelShaderConstant, C[%lu]={%f, %f, %f, %f}\n", This, Register, f[0], f[1], f[2], f[3]); | |
| } | |
| This->UpdateStateBlock->Changed.pixelShaderConstant = TRUE; | |
| memcpy(&This->UpdateStateBlock->pixelShaderConstant[Register], pConstantData, ConstantCount * 4 * sizeof(FLOAT)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShaderConstant(LPDIRECT3DDEVICE8 iface, DWORD Register, void* pConstantData, DWORD ConstantCount) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE_(d3d_shader)("(%p) : C[%lu] count=%ld\n", This, Register, ConstantCount); | |
| if (Register + ConstantCount > D3D8_PSHADER_MAX_CONSTANTS) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| if (NULL == pConstantData) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| memcpy(pConstantData, &This->UpdateStateBlock->pixelShaderConstant[Register], ConstantCount * 4 * sizeof(FLOAT)); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetPixelShaderFunction(LPDIRECT3DDEVICE8 iface, DWORD Handle, void* pData, DWORD* pSizeOfData) { | |
| IDirect3DPixelShaderImpl* object; | |
| object = PIXEL_SHADER(Handle); | |
| if (NULL == object) { | |
| return D3DERR_INVALIDCALL; | |
| } | |
| return IDirect3DPixelShaderImpl_GetFunction(object, pData, (UINT*) pSizeOfData); | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DrawRectPatch(LPDIRECT3DDEVICE8 iface, UINT Handle,CONST float* pNumSegs,CONST D3DRECTPATCH_INFO* pRectPatchInfo) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DrawTriPatch(LPDIRECT3DDEVICE8 iface, UINT Handle,CONST float* pNumSegs,CONST D3DTRIPATCH_INFO* pTriPatchInfo) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_DeletePatch(LPDIRECT3DDEVICE8 iface, UINT Handle) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| FIXME("(%p) : stub\n", This); return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_SetStreamSource(LPDIRECT3DDEVICE8 iface, UINT StreamNumber,IDirect3DVertexBuffer8* pStreamData,UINT Stride) { | |
| IDirect3DVertexBuffer8 *oldSrc; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| oldSrc = This->StateBlock->stream_source[StreamNumber]; | |
| TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride); | |
| This->UpdateStateBlock->Changed.stream_source[StreamNumber] = TRUE; | |
| This->UpdateStateBlock->Set.stream_source[StreamNumber] = TRUE; | |
| This->UpdateStateBlock->stream_stride[StreamNumber] = Stride; | |
| This->UpdateStateBlock->stream_source[StreamNumber] = pStreamData; | |
| /* Handle recording of state blocks */ | |
| if (This->isRecordingState) { | |
| TRACE("Recording... not performing anything\n"); | |
| return D3D_OK; | |
| } | |
| if (oldSrc != NULL) IDirect3DVertexBuffer8Impl_Release(oldSrc); | |
| if (pStreamData != NULL) IDirect3DVertexBuffer8Impl_AddRef(pStreamData); | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_GetStreamSource(LPDIRECT3DDEVICE8 iface, UINT StreamNumber,IDirect3DVertexBuffer8** pStream,UINT* pStride) { | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber, This->StateBlock->stream_source[StreamNumber], This->StateBlock->stream_stride[StreamNumber]); | |
| *pStream = This->StateBlock->stream_source[StreamNumber]; | |
| *pStride = This->StateBlock->stream_stride[StreamNumber]; | |
| if (*pStream != NULL) IDirect3DVertexBuffer8Impl_AddRef((LPDIRECT3DVERTEXBUFFER8) *pStream); | |
| return D3D_OK; | |
| } | |
| 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 | |
| }; | |
| HRESULT WINAPI IDirect3DDevice8Impl_CleanRender(LPDIRECT3DDEVICE8 iface) | |
| { | |
| #if defined(GL_VERSION_1_3) /* @see comments on ActiveRender */ | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| ENTER_GL(); | |
| #if 0 | |
| if (This->glCtx != This->render_ctx) { | |
| glXDestroyContext(This->display, This->render_ctx); | |
| This->render_ctx = This->glCtx; | |
| } | |
| #endif | |
| if (This->win != This->drawable) { | |
| glXDestroyPbuffer(This->display, This->drawable); | |
| This->drawable = This->win; | |
| } | |
| LEAVE_GL(); | |
| #endif | |
| return D3D_OK; | |
| } | |
| HRESULT WINAPI IDirect3DDevice8Impl_ActiveRender(LPDIRECT3DDEVICE8 iface, | |
| IDirect3DSurface8* RenderSurface, | |
| IDirect3DSurface8* StencilSurface) { | |
| HRESULT ret = D3DERR_INVALIDCALL; | |
| /** | |
| * Currently only active for GLX >= 1.3 | |
| * for others versions we'll have to use GLXPixmaps | |
| * | |
| * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct | |
| * as they implements GLX 1.3 but only define GLX_VERSION_1_2 | |
| * so only check OpenGL version | |
| */ | |
| #if defined(GL_VERSION_1_3) | |
| GLXFBConfig* cfgs = NULL; | |
| int nCfgs = 0; | |
| int attribs[256]; | |
| int nAttribs = 0; | |
| D3DFORMAT BackBufferFormat = ((IDirect3DSurface8Impl*) RenderSurface)->myDesc.Format; | |
| D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IDirect3DSurface8Impl*) StencilSurface)->myDesc.Format : 0; | |
| UINT Width = ((IDirect3DSurface8Impl*) RenderSurface)->myDesc.Width; | |
| UINT Height = ((IDirect3DSurface8Impl*) RenderSurface)->myDesc.Height; | |
| IDirect3DSurface8Impl* tmp; | |
| IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; | |
| #define PUSH1(att) attribs[nAttribs++] = (att); | |
| #define PUSH2(att,value) attribs[nAttribs++] = (att); attribs[nAttribs++] = (value); | |
| PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT); | |
| PUSH2(GLX_X_RENDERABLE, TRUE); | |
| PUSH2(GLX_DOUBLEBUFFER, TRUE); | |
| switch (BackBufferFormat) { | |
| /* color buffer */ | |
| case D3DFMT_P8: | |
| PUSH2(GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT); | |
| PUSH2(GLX_BUFFER_SIZE, 8); | |
| PUSH2(GLX_DOUBLEBUFFER, TRUE); | |
| break; | |
| case D3DFMT_R3G3B2: | |
| PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT); | |
| PUSH2(GLX_RED_SIZE, 3); | |
| PUSH2(GLX_GREEN_SIZE, 3); | |
| PUSH2(GLX_BLUE_SIZE, 2); | |
| break; | |
| case D3DFMT_A1R5G5B5: | |
| PUSH2(GLX_ALPHA_SIZE, 1); | |
| case D3DFMT_X1R5G5B5: | |
| PUSH2(GLX_RED_SIZE, 5); | |
| PUSH2(GLX_GREEN_SIZE, 5); | |
| PUSH2(GLX_BLUE_SIZE, 5); | |
| break; | |
| case D3DFMT_R5G6B5: | |
| PUSH2(GLX_RED_SIZE, 5); | |
| PUSH2(GLX_GREEN_SIZE, 6); | |
| PUSH2(GLX_BLUE_SIZE, 5); | |
| break; | |
| case D3DFMT_A4R4G4B4: | |
| PUSH2(GLX_ALPHA_SIZE, 4); | |
| case D3DFMT_X4R4G4B4: | |
| PUSH2(GLX_RED_SIZE, 4); | |
| PUSH2(GLX_GREEN_SIZE, 4); | |
| PUSH2(GLX_BLUE_SIZE, 4); | |
| break; | |
| case D3DFMT_A8R8G8B8: | |
| PUSH2(GLX_ALPHA_SIZE, 8); | |
| case D3DFMT_R8G8B8: | |
| case D3DFMT_X8R8G8B8: | |
| PUSH2(GLX_RED_SIZE, 8); | |
| PUSH2(GLX_GREEN_SIZE, 8); | |
| PUSH2(GLX_BLUE_SIZE, 8); | |
| break; | |
| default: | |
| break; | |
| } | |
| switch (StencilBufferFormat) { | |
| case D3DFMT_D16_LOCKABLE: | |
| case D3DFMT_D16: | |
| PUSH2(GLX_DEPTH_SIZE, 16); | |
| break; | |
| case D3DFMT_D15S1: | |
| PUSH2(GLX_DEPTH_SIZE, 15); | |
| break; | |
| case D3DFMT_D24X8: | |
| PUSH2(GLX_DEPTH_SIZE, 24); | |
| break; | |
| case D3DFMT_D24X4S4: | |
| PUSH2(GLX_DEPTH_SIZE, 24); | |
| PUSH2(GLX_STENCIL_SIZE, 4); | |
| break; | |
| case D3DFMT_D24S8: | |
| PUSH2(GLX_DEPTH_SIZE, 24); | |
| PUSH2(GLX_STENCIL_SIZE, 8); | |
| break; | |
| case D3DFMT_D32: | |
| PUSH2(GLX_DEPTH_SIZE, 32); | |
| break; | |
| default: | |
| break; | |
| } | |
| PUSH1(None); | |
| ENTER_GL(); | |
| cfgs = glXChooseFBConfig(This->display, DefaultScreen(This->display), attribs, &nCfgs); | |
| if (NULL != cfgs) { | |
| #ifdef EXTRA_TRACES | |
| int i; | |
| for (i = 0; i < nCfgs; ++i) { | |
| TRACE("for (%u,%s)/(%u,%s) found config[%d]@%p\n", BackBufferFormat, debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat), i, cfgs[i]); | |
| } | |
| #endif | |
| if (NULL != This->renderTarget) { | |
| /*GLenum prev_read; */ | |
| glFlush(); | |
| vcheckGLcall("glFlush"); | |
| #ifdef EXTRA_TRACES | |
| /** very very usefull debug code */ | |
| glXSwapBuffers(This->display, This->drawable); | |
| printf("Hit Enter to get next frame ...\n"); | |
| getchar(); | |
| #endif | |
| #if 0 | |
| glGetIntegerv(GL_READ_BUFFER, &prev_read); | |
| vcheckGLcall("glIntegerv"); | |
| glReadBuffer(GL_BACK); | |
| vcheckGLcall("glReadBuffer"); | |
| { | |
| long j; | |
| long pitch = This->renderTarget->myDesc.Width * This->renderTarget->bytesPerPixel; | |
| if (This->renderTarget->myDesc.Format == D3DFMT_DXT1) /* DXT1 is half byte per pixel */ | |
| pitch = pitch / 2; | |
| for (j = 0; j < This->renderTarget->myDesc.Height; ++j) { | |
| glReadPixels(0, | |
| This->renderTarget->myDesc.Height - j - 1, | |
| This->renderTarget->myDesc.Width, | |
| 1, | |
| D3DFmt2GLFmt(This, This->renderTarget->myDesc.Format), | |
| D3DFmt2GLType(This, This->renderTarget->myDesc.Format), | |
| This->renderTarget->allocatedMemory + j * pitch); | |
| vcheckGLcall("glReadPixels"); | |
| } | |
| } | |
| glReadBuffer(prev_read); | |
| vcheckGLcall("glReadBuffer"); | |
| #endif | |
| } | |
| if (BackBufferFormat != This->renderTarget->myDesc.Format && | |
| StencilBufferFormat != This->stencilBufferTarget->myDesc.Format) { | |
| nAttribs = 0; | |
| PUSH2(GLX_PBUFFER_WIDTH, Width); | |
| PUSH2(GLX_PBUFFER_HEIGHT, Height); | |
| PUSH1(None); | |
| This->drawable = glXCreatePbuffer(This->display, cfgs[0], attribs); | |
| This->render_ctx = glXCreateNewContext(This->display, cfgs[0], GLX_RGBA_TYPE, This->glCtx, TRUE); | |
| if (NULL == This->render_ctx) { | |
| ERR("cannot create glxContext\n"); | |
| } | |
| glFlush(); | |
| glXSwapBuffers(This->display, This->drawable); | |
| if (glXMakeContextCurrent(This->display, This->drawable, This->drawable, This->render_ctx) == False) { | |
| TRACE("Error in setting current context: context %p drawable %ld (default %ld)!\n", This->glCtx, This->drawable, This->win); | |
| } | |
| checkGLcall("glXMakeContextCurrent"); | |
| } | |
| tmp = This->renderTarget; | |
| This->renderTarget = (IDirect3DSurface8Impl*) RenderSurface; | |
| IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) This->renderTarget); | |
| IDirect3DSurface8Impl_Release((LPDIRECT3DSURFACE8) tmp); | |
| tmp = This->stencilBufferTarget; | |
| This->stencilBufferTarget = (IDirect3DSurface8Impl*) StencilSurface; | |
| if (NULL != This->stencilBufferTarget) IDirect3DSurface8Impl_AddRef((LPDIRECT3DSURFACE8) This->stencilBufferTarget); | |
| if (NULL != tmp) IDirect3DSurface8Impl_Release((LPDIRECT3DSURFACE8) tmp); | |
| { | |
| DWORD value; | |
| /* The surface must be rendered upside down to cancel the flip produce by glCopyTexImage */ | |
| This->renderUpsideDown = (This->renderTarget != This->frontBuffer) && (This->renderTarget != This->backBuffer); | |
| /* Force updating the cull mode */ | |
| IDirect3DDevice8_GetRenderState(iface, D3DRS_CULLMODE, &value); | |
| IDirect3DDevice8_SetRenderState(iface, D3DRS_CULLMODE, value); | |
| /* Force updating projection matrix */ | |
| This->last_was_rhw = FALSE; | |
| This->proj_valid = FALSE; | |
| } | |
| ret = D3D_OK; | |
| } else { | |
| ERR("cannot get valides GLXFBConfig for (%u,%s)/(%u,%s)\n", BackBufferFormat, debug_d3dformat(BackBufferFormat), StencilBufferFormat, debug_d3dformat(StencilBufferFormat)); | |
| } | |
| #undef PUSH1 | |
| #undef PUSH2 | |
| LEAVE_GL(); | |
| #endif | |
| return ret; | |
| } |