/*==========================================================================; * * Copyright (C) 1997 Microsoft Corporation. All Rights Reserved. * * File: devstate.c * Content: device state management * ***************************************************************************/ #include "pch.cpp" #pragma hdrstop #include "drawprim.hpp" #include "pvvid.h" #include "d3dfei.h" extern HRESULT checkDeviceSurface(LPDIRECT3DDEVICEI lpD3DDev, LPDIRECTDRAWSURFACE lpDDS); extern HRESULT CalcDDSurfInfo(LPDIRECT3DDEVICEI lpDevI, BOOL bUpdateZBufferFields); //--------------------------------------------------------------------- inline void UpdateFogFactor(LPDIRECT3DDEVICEI lpDevI) { if (lpDevI->lighting.fog_end == lpDevI->lighting.fog_start) lpDevI->lighting.fog_factor = D3DVAL(0.0); else lpDevI->lighting.fog_factor = D3DVAL(255) / (lpDevI->lighting.fog_end - lpDevI->lighting.fog_start); } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::SetRenderState" HRESULT D3DAPI DIRECT3DDEVICEI::SetRenderState(D3DRENDERSTATETYPE dwState, DWORD value) { #if DBG if (dwState >= D3D_MAXRENDERSTATES || dwState == 0 ) { D3D_ERR( "Invalid render state type" ); return DDERR_INVALIDPARAMS; } #endif // Takes D3D lock (MT only). CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); try { if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { if(this->CheckForRetiredRenderState(dwState)) { m_pStateSets->InsertRenderState(dwState, value, CanHandleRenderState(dwState)); } else { D3D_ERR("invalid renderstate %d", dwState); return DDERR_INVALIDPARAMS; } } else this->SetRenderStateFast(dwState, value); return D3D_OK; } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetRenderStateFast" HRESULT D3DAPI DIRECT3DDEVICEI::SetRenderStateFast(D3DRENDERSTATETYPE dwState, DWORD value) { #if DBG if (dwState >= D3D_MAXRENDERSTATES || dwState == 0 ) { D3D_ERR( "Invalid render state type" ); return DDERR_INVALIDPARAMS; } #endif if (!(rsVec[dwState >> D3D_RSVEC_SHIFT] & (1ul << (dwState & D3D_RSVEC_MASK)))) { // Fast path. We do not need any processing done in UpdateInternalState other than updating rstates array if (this->rstates[dwState] == value) { D3D_WARN(4,"Ignoring redundant SetRenderState"); return D3D_OK; } this->rstates[dwState] = value; // Output state to the device driver return SetRenderStateI(dwState, value); } else { try { // Wrap modes could be re-programmed. We need to restore them before // filtering redundant values if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } if (this->rstates[dwState] == value) { D3D_WARN(4,"Ignoring redundant SetRenderState"); return D3D_OK; } this->UpdateInternalState(dwState, value); if (CanHandleRenderState(dwState)) { if(CheckForRetiredRenderState(dwState)) return SetRenderStateI(dwState, value); D3D_ERR("invalid renderstate %d", dwState); return DDERR_INVALIDPARAMS; } } catch(HRESULT ret) { return ret; } } return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::SetRenderStateInternal" HRESULT DIRECT3DDEVICEI::SetRenderStateInternal(D3DRENDERSTATETYPE dwState, DWORD dwValue) { if (this->rstates[dwState] == dwValue) { D3D_WARN(4,"Ignoring redundant SetRenderState"); return D3D_OK; } try { this->UpdateInternalState(dwState, dwValue); if (CanHandleRenderState(dwState)) return SetRenderStateI(dwState, dwValue); return D3D_OK; } catch(HRESULT ret) { return ret; } } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetRenderState" HRESULT D3DAPI DIRECT3DDEVICEI::GetRenderState(D3DRENDERSTATETYPE dwState, LPDWORD lpdwValue) { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (MT only). #if DBG if (dwState >= D3D_MAXRENDERSTATES || dwState == 0) { D3D_ERR( "Invalid render state value" ); return DDERR_INVALIDPARAMS; } #endif if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_PTR(lpdwValue, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer" ); return DDERR_INVALIDPARAMS; } if(!CheckForRetiredRenderState(dwState)) { D3D_ERR("invalid renderstate %d", dwState); return DDERR_INVALIDPARAMS; } // WRAP render states could be re-mapped so we have to return the original // value if (dwState >= D3DRENDERSTATE_WRAP0 && dwState <= D3DRENDERSTATE_WRAP7) { if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { DWORD dwTexCoordIndex = dwState - D3DRENDERSTATE_WRAP0; for (DWORD i=0; i < this->dwNumTextureStages; i++) { LPD3DFE_TEXTURESTAGE pStage = &this->textureStage[i]; if (pStage->dwInpCoordIndex == dwTexCoordIndex) { if (pStage->dwInpCoordIndex != pStage->dwOutCoordIndex) { *lpdwValue = pStage->dwOrgWrapMode; return D3D_OK; } } } } } *lpdwValue = this->rstates[dwState]; return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetTexture" HRESULT D3DAPI DIRECT3DDEVICEI::GetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 *lplpTex) { // Takes D3D lock (MT only). // Lock released in the destructor. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); #if DBG if (dwStage >= D3DHAL_TSS_MAXSTAGES) { D3D_ERR( "Invalid texture stage or state index" ); return DDERR_INVALIDPARAMS; } #endif if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_PTR(lplpTex, sizeof(LPVOID))) { D3D_ERR( "Invalid pointer to LPDIRECTDRAWSURFACE7" ); return DDERR_INVALIDPARAMS; } if (this->lpD3DMappedTexI[dwStage]) { if(this->lpD3DMappedTexI[dwStage]->D3DManaged()) *lplpTex = this->lpD3DMappedTexI[dwStage]->lpDDSSys; else *lplpTex = this->lpD3DMappedTexI[dwStage]->lpDDS; (*lplpTex)->AddRef(); } else { *lplpTex = NULL; } return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::VerifyTexture" HRESULT DIRECT3DDEVICEI::VerifyTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpTex) { if (dwStage >= D3DHAL_TSS_MAXSTAGES) { D3D_ERR( "Invalid texture stage or state index" ); return DDERR_INVALIDPARAMS; } if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if (lpTex) { if (!VALID_DDSURF_PTR(lpTex)) { D3D_ERR( "Invalid surface pointer" ); return DDERR_INVALIDOBJECT; } if((((LPDDRAWI_DDRAWSURFACE_INT)lpTex)->lpLcl->lpSurfMore->ddsCapsEx.dwCaps2 & (DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_D3DTEXTUREMANAGE)) && !(this->dwFEFlags & D3DFE_REALHAL)) { D3D_ERR( "Managed textures cannot be used with a software device" ); return DDERR_INVALIDPARAMS; } if(!IsToplevel(((LPDDRAWI_DDRAWSURFACE_INT)lpTex)->lpLcl)) { D3D_ERR( "Cannot set a mipmap sublevel or a cubemap subface" ); return DDERR_INVALIDPARAMS; } LPDIRECT3DTEXTUREI lpTexI = reinterpret_cast(((LPDDRAWI_DDRAWSURFACE_INT)lpTex)->lpLcl->lpSurfMore->lpTex); if(lpTexI == NULL) { D3D_ERR( "Surface must have DDSCAPS_TEXTURE set to use in SetTexture" ); return DDERR_INVALIDPARAMS; } if (!lpTexI->D3DManaged()) { if((((LPDDRAWI_DDRAWSURFACE_INT)(lpTexI->lpDDS))->lpLcl->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY) && (!(lpD3DHALGlobalDriverData->hwCaps.dwDevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY))) { D3D_ERR( "Device cannot render using texture surface from system memory" ); return DDERR_INVALIDPARAMS; } } CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // we access DDraw gbl in VerifyTextureCaps return VerifyTextureCaps(lpTexI); } return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::SetTexture" HRESULT D3DAPI DIRECT3DDEVICEI::SetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpTex) { try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); #if DBG HRESULT ret = VerifyTexture(dwStage, lpTex); if(ret != D3D_OK) return ret; #endif if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { m_pStateSets->InsertTexture(dwStage, lpTex); return D3D_OK; } return SetTextureInternal(dwStage, lpTex); } catch(HRESULT ret) { return ret; } } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::SetTextureInternal" HRESULT D3DAPI DIRECT3DDEVICEI::SetTextureInternal(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpTex) { #if DBG HRESULT ret = VerifyTexture(dwStage, lpTex); if(ret != D3D_OK) return ret; #endif #if COLLECTSTATS this->IncNumTexturesSet(); #endif LPDIRECT3DTEXTUREI lpTexI = lpTex ? reinterpret_cast(((LPDDRAWI_DDRAWSURFACE_INT)lpTex)->lpLcl->lpSurfMore->lpTex) : NULL; if (lpD3DMappedTexI[dwStage] == lpTexI) { return D3D_OK; } if (lpD3DMappedTexI[dwStage]) { lpD3DMappedTexI[dwStage]->Release(); } lpD3DMappedTexI[dwStage] = lpTexI; if (lpTexI) { lpTexI->AddRef(); #if COLLECTSTATS if(lpTexI->D3DManaged()) { this->lpDirect3DI->lpTextureManager->IncNumTexturesSet(); if(lpTexI->InVidmem()) this->lpDirect3DI->lpTextureManager->IncNumSetTexInVid(); } #endif } m_dwStageDirty |= (1 << dwStage); // Need to call UpdateTextures() this->dwFEFlags |= D3DFE_NEED_TEXTURE_UPDATE; return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetTextureStageState" HRESULT D3DAPI DIRECT3DDEVICEI::SetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { #if DBG if (dwStage >= D3DHAL_TSS_MAXSTAGES || dwState == 0 || dwState >= D3DTSS_MAX) { D3D_ERR( "Invalid texture stage or state index" ); return DDERR_INVALIDPARAMS; } #endif //DBG try { // Holds D3D lock until exit. CLockD3DMT ldmLock(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { m_pStateSets->InsertTextureStageState(dwStage, dwState, dwValue); return D3D_OK; } return this->SetTextureStageStateFast(dwStage, dwState, dwValue); } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetTextureStageStateFast" HRESULT D3DAPI DIRECT3DDEVICEI::SetTextureStageStateFast(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { #if DBG if (dwStage >= D3DHAL_TSS_MAXSTAGES || dwState == 0 || dwState >= D3DTSS_MAX) { D3D_ERR( "Invalid texture stage or state index" ); return DDERR_INVALIDPARAMS; } #endif //DBG // Fast path. We do not need any processing done in UpdateInternalTSS other than updating tsstates array if (NeedInternalTSSUpdate(dwState)) { // Texture stages could be re-programmed. We need to restore them before // filtering redundant values if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } if (this->tsstates[dwStage][dwState] == dwValue) { D3D_WARN(4,"Ignoring redundant SetTextureStageState"); return D3D_OK; } if(this->UpdateInternalTextureStageState(dwStage, dwState, dwValue)) return D3D_OK; } else { if (this->tsstates[dwStage][dwState] == dwValue) { D3D_WARN(4,"Ignoring redundant SetTextureStageState"); return D3D_OK; } tsstates[dwStage][dwState] = dwValue; } if (dwStage >= this->dwMaxTextureBlendStages) return D3D_OK; return SetTSSI(dwStage, dwState, dwValue); } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetTextureStageState" HRESULT D3DAPI DIRECT3DDEVICEI::GetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, LPDWORD pdwValue) { // Takes D3D lock (MT only). // Lock released in the destructor. CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); #if DBG if (dwStage >= D3DHAL_TSS_MAXSTAGES || dwState == 0 || dwState >= D3DTSS_MAX) { D3D_ERR( "Invalid texture stage or state index" ); return DDERR_INVALIDPARAMS; } #endif //DBG if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_PTR(pdwValue, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer" ); return DDERR_INVALIDPARAMS; } // If texture indices were re-mapped we have to find and return the original value if (dwState == D3DTSS_TEXCOORDINDEX && this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } // Don't bother to check for DX6 support, just return the // cached value. *pdwValue = tsstates[dwStage][dwState]; return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3D::CreateDevice" extern HRESULT WINAPI Direct3DCreateDevice(REFCLSID riid, LPUNKNOWN lpDirect3D, LPDIRECTDRAWSURFACE lpDDSTarget, LPUNKNOWN* lplpD3DDevice, IUnknown* pUnkOuter); HRESULT D3DAPI DIRECT3DI::CreateDevice(REFCLSID devType, LPDIRECTDRAWSURFACE7 lpDDS7, LPDIRECT3DDEVICE7 *lplpDirect3DDevice) { HRESULT ret; LPUNKNOWN lpUnkDevice; LPDIRECTDRAWSURFACE lpDDS; try { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. // Release in the destructor if (!VALID_DIRECT3D_PTR(this)) { D3D_ERR( "Invalid Direct3D pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_OUTPTR(lplpDirect3DDevice)) { D3D_ERR( "Invalid pointer to Device object pointer" ); return DDERR_INVALIDPARAMS; } if (!VALID_D3D_DIRECTDRAWSURFACE7_PTR(((LPDDRAWI_DDRAWSURFACE_INT)lpDDS7))) { D3D_ERR( "Invalid DirectDrawSurface7 pointer" ); return DDERR_INVALIDOBJECT; } *lplpDirect3DDevice = NULL; // QI lpDDS7 for lpDDS interface ret = lpDDS7->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)&lpDDS); if (FAILED(ret)) return ret; lpDDS->Release(); ret = Direct3DCreateDevice(devType, &this->mD3DUnk, lpDDS, (LPUNKNOWN *) &lpUnkDevice, NULL); if(FAILED(ret) || (lpUnkDevice==NULL)) return ret; // QI device1 for a device7 interface ret = lpUnkDevice->QueryInterface(IID_IDirect3DDevice7, (LPVOID*)lplpDirect3DDevice); lpUnkDevice->Release(); // release unneeded interface return ret; } catch (HRESULT ret) { return ret; } } //---------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetTransformI" void DIRECT3DDEVICEI::SetTransformI(D3DTRANSFORMSTATETYPE state, LPD3DMATRIX lpMat) { switch (state) { case D3DTRANSFORMSTATE_WORLD : *(D3DMATRIX*)&this->transform.world[0] = *lpMat; this->dwFEFlags |= D3DFE_WORLDMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTRANSFORMSTATE_WORLD1 : *(D3DMATRIX*)&this->transform.world[1] = *lpMat; this->dwFEFlags |= D3DFE_WORLDMATRIX1_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTRANSFORMSTATE_WORLD2 : *(D3DMATRIX*)&this->transform.world[2] = *lpMat; this->dwFEFlags |= D3DFE_WORLDMATRIX2_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTRANSFORMSTATE_WORLD3 : *(D3DMATRIX*)&this->transform.world[3] = *lpMat; this->dwFEFlags |= D3DFE_WORLDMATRIX3_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTRANSFORMSTATE_VIEW : *(D3DMATRIX*)&this->transform.view = *lpMat; this->dwFEFlags |= D3DFE_VIEWMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DTRANSFORMSTATE_PROJECTION : *(D3DMATRIX*)&this->transform.proj = *lpMat; this->dwFEFlags |= D3DFE_PROJMATRIX_DIRTY | D3DFE_FRONTEND_DIRTY; if (!(this->dwFEFlags & D3DFE_EXECUTESTATEMODE)) { this->UpdateDrvWInfo(); } break; case D3DTRANSFORMSTATE_TEXTURE0: case D3DTRANSFORMSTATE_TEXTURE1: case D3DTRANSFORMSTATE_TEXTURE2: case D3DTRANSFORMSTATE_TEXTURE3: case D3DTRANSFORMSTATE_TEXTURE4: case D3DTRANSFORMSTATE_TEXTURE5: case D3DTRANSFORMSTATE_TEXTURE6: case D3DTRANSFORMSTATE_TEXTURE7: { this->dwDeviceFlags |= D3DDEV_TEXTRANSFORMDIRTY; DWORD dwIndex = state - D3DTRANSFORMSTATE_TEXTURE0; *(D3DMATRIX*)&this->mTexture[dwIndex] = *lpMat; break; } } } //---------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetTransform" HRESULT D3DAPI DIRECT3DDEVICEI::SetTransform(D3DTRANSFORMSTATETYPE state, LPD3DMATRIX lpMat) { #if DBG if (!VALID_PTR(lpMat, sizeof(D3DMATRIX))) { D3D_ERR( "Invalid matrix pointer" ); return DDERR_INVALIDPARAMS; } switch (state) { case D3DTRANSFORMSTATE_WORLD: case D3DTRANSFORMSTATE_WORLD1: case D3DTRANSFORMSTATE_WORLD2: case D3DTRANSFORMSTATE_WORLD3: case D3DTRANSFORMSTATE_VIEW : case D3DTRANSFORMSTATE_PROJECTION : case D3DTRANSFORMSTATE_TEXTURE0: case D3DTRANSFORMSTATE_TEXTURE1: case D3DTRANSFORMSTATE_TEXTURE2: case D3DTRANSFORMSTATE_TEXTURE3: case D3DTRANSFORMSTATE_TEXTURE4: case D3DTRANSFORMSTATE_TEXTURE5: case D3DTRANSFORMSTATE_TEXTURE6: case D3DTRANSFORMSTATE_TEXTURE7: break; default : D3D_ERR( "Invalid state value passed to SetTransform" ); return DDERR_INVALIDPARAMS; /* Work Item: Generate new meaningful return code */ } #endif try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (MT only). if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) m_pStateSets->InsertTransform(state, lpMat); else this->SetTransformI(state, lpMat); return D3D_OK; } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::GetTransform" HRESULT D3DAPI DIRECT3DDEVICEI::GetTransform(D3DTRANSFORMSTATETYPE dtsTransformState, LPD3DMATRIX lpMat) { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (MT only). HRESULT ret = D3D_OK; #if DBG if (!lpMat) { D3D_ERR( "NULL matrix pointer" ); return DDERR_INVALIDPARAMS; } #endif switch (dtsTransformState) { case D3DTRANSFORMSTATE_WORLD : *lpMat = *(LPD3DMATRIX)&this->transform.world[0]._11; break; case D3DTRANSFORMSTATE_WORLD1 : *lpMat = *(LPD3DMATRIX)&this->transform.world[1]._11; break; case D3DTRANSFORMSTATE_WORLD2 : *lpMat = *(LPD3DMATRIX)&this->transform.world[2]._11; break; case D3DTRANSFORMSTATE_WORLD3 : *lpMat = *(LPD3DMATRIX)&this->transform.world[3]._11; break; case D3DTRANSFORMSTATE_VIEW : *lpMat = *(LPD3DMATRIX)&this->transform.view._11; break; case D3DTRANSFORMSTATE_PROJECTION : *lpMat = *(LPD3DMATRIX)&this->transform.proj._11; break; case D3DTRANSFORMSTATE_TEXTURE0: case D3DTRANSFORMSTATE_TEXTURE1: case D3DTRANSFORMSTATE_TEXTURE2: case D3DTRANSFORMSTATE_TEXTURE3: case D3DTRANSFORMSTATE_TEXTURE4: case D3DTRANSFORMSTATE_TEXTURE5: case D3DTRANSFORMSTATE_TEXTURE6: case D3DTRANSFORMSTATE_TEXTURE7: *lpMat = *(LPD3DMATRIX)&this->mTexture[dtsTransformState-D3DTRANSFORMSTATE_TEXTURE0]._11; break; default : D3D_ERR( "Invalid state value passed to GetTransform" ); ret = DDERR_INVALIDPARAMS; /* Work Item: Generate new meaningful return code */ break; } return ret; } // end of D3DDev2_GetTransform() void InvalidateHandles(LPDIRECT3DDEVICEI lpDevI) { /* free up all textures created by this object */ LPD3DI_TEXTUREBLOCK tBlock=LIST_FIRST(&lpDevI->texBlocks); while (tBlock) { D3DI_RemoveTextureHandle(tBlock); tBlock=LIST_NEXT(tBlock,devList); } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::UpdateDriverStates" HRESULT DIRECT3DDEVICEI::UpdateDriverStates() { // note we can't do a loop from 1 to D3DHAL_MAX_RSTATES(256) as some of rstates are not // valid states, passin them down to drivers(like voodoo2 DX6 driver) will crash. for (DWORD i = D3DRENDERSTATE_ANTIALIAS ; i < D3DRENDERSTATE_WRAPBIAS+8; ++i) { HRESULT ret = this->SetRenderStateI((D3DRENDERSTATETYPE)i, this->rstates[i]); if (ret != D3D_OK) return ret; } return D3D_OK; } void DIRECT3DDEVICEI::SetRenderTargetI(LPDIRECTDRAWSURFACE lpDDS, LPDIRECTDRAWSURFACE lpZ) { HRESULT ret; // Flush before switching RenderTarget.. ret = FlushStates(); if (ret != D3D_OK) { D3D_ERR("Error trying to FlushStates in SetRenderTarget"); throw ret; } if (this->lpD3DHALCallbacks2->SetRenderTarget) { D3DHAL_SETRENDERTARGETDATA rtData; rtData.dwhContext = this->dwhContext; #ifndef WIN95 if (dwFEFlags & D3DFE_REALHAL) { if (lpDDS) rtData.lpDDSLcl = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDS)->lpLcl; else rtData.lpDDSLcl = NULL; if (lpZ) rtData.lpDDSZLcl = ((LPDDRAWI_DDRAWSURFACE_INT)lpZ)->lpLcl; else rtData.lpDDSZLcl = NULL; } else #endif //WIN95 { rtData.lpDDS = lpDDS; rtData.lpDDSZ = lpZ; } rtData.ddrval = 0; CALL_HAL2ONLY(ret, this, SetRenderTarget, &rtData); if ((ret != DDHAL_DRIVER_HANDLED) || (rtData.ddrval != DD_OK)) { D3D_ERR( "Driver call failed in SetRenderTarget" ); // Need sensible return value in this case, // currently we return whatever the driver stuck in here. ret = rtData.ddrval; throw ret; } } else { D3DHAL_CONTEXTCREATEDATA cdata; D3DHAL_CONTEXTDESTROYDATA ddata; /* Destroy old context */ memset(&ddata, 0, sizeof(D3DHAL_CONTEXTDESTROYDATA)); ddata.dwhContext = this->dwhContext; CALL_HALONLY(ret, this, ContextDestroy, &ddata); if (ret != DDHAL_DRIVER_HANDLED || ddata.ddrval != DD_OK) { DPF(0, "(ERROR) ContextDestroy. Failed. dwhContext = %d", ddata.dwhContext); // Need sensible return value in this case, // currently we return whatever the driver stuck in here. ret = ddata.ddrval; throw ret; } /* Create new context */ memset(&cdata, 0, sizeof(D3DHAL_CONTEXTCREATEDATA)); cdata.lpDDGbl = this->lpDDGbl; cdata.lpDDS = lpDDS; cdata.lpDDSZ = lpZ; // Hack Alert!! dwhContext is used to inform the driver which version // of the D3D interface is calling it. cdata.dwhContext = 3; cdata.dwPID = GetCurrentProcessId(); // Hack Alert!! ddrval is used to inform the driver which driver type // the runtime thinks it is (DriverStyle registry setting) cdata.ddrval = this->deviceType; CALL_HALONLY(ret, this, ContextCreate, &cdata); if (ret != DDHAL_DRIVER_HANDLED || cdata.ddrval != DD_OK) { D3D_ERR("HAL call to ContextCreate failed in SetRenderTarget"); // Need sensible return value in this case, // currently we return whatever the driver stuck in here. throw cdata.ddrval; } this->dwhContext = (DWORD)cdata.dwhContext; D3D_INFO(9, "in halCreateContext. Succeeded. dwhContext = %d", cdata.dwhContext); ret = this->UpdateDriverStates(); if (ret != D3D_OK) throw ret; } InvalidateHandles(this); } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetRenderTarget" HRESULT D3DAPI DIRECT3DDEVICEI::SetRenderTarget(LPDIRECTDRAWSURFACE7 lpDDS7, DWORD dwFlags) { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. // Release in the destructor LPDIRECTDRAWSURFACE lpZ=NULL,lpDDS=NULL; LPDIRECTDRAWSURFACE7 lpZ_DDS7=NULL; LPDIRECTDRAWPALETTE lpPal=NULL; try { DDSCAPS2 ddscaps; memset(&ddscaps, 0, sizeof(ddscaps)); DDSURFACEDESC2 ddsd; HRESULT ret, ddrval; DWORD i, j; if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice7 pointer" ); return DDERR_INVALIDOBJECT; } if (!VALID_D3D_DIRECTDRAWSURFACE7_PTR(((LPDDRAWI_DDRAWSURFACE_INT)lpDDS7))) { D3D_ERR( "Invalid DirectDrawSurface7 pointer" ); return DDERR_INVALIDOBJECT; } /* * Check if the 3D cap is set on the surface. */ memset(&ddsd, 0, sizeof ddsd); ddsd.dwSize = sizeof ddsd; ddrval = lpDDS7->GetSurfaceDesc(&ddsd); if (ddrval != DD_OK) { D3D_ERR("Failed to get surface description of device's surface."); return (ddrval); } if (!(ddsd.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)) { D3D_ERR("**** The DDSCAPS_3DDEVICE is not set on this surface."); D3D_ERR("**** You need to add DDSCAPS_3DDEVICE to ddsCaps.dwCaps"); D3D_ERR("**** when creating the surface."); return (DDERR_INVALIDCAPS); } if (!(this->lpD3DHALGlobalDriverData->hwCaps.dwDeviceRenderBitDepth & BitDepthToDDBD(ddsd.ddpfPixelFormat.dwRGBBitCount))) { D3D_ERR("Rendering surface's RGB bit count not supported by hardware device"); return (DDERR_INVALIDCAPS); } if (ddsd.dwWidth > 2048 || ddsd.dwHeight > 2048) { D3D_ERR("Surface dimension > 2048"); return DDERR_INVALIDPARAMS; } /* The z-buffer... */ ddscaps.dwCaps = DDSCAPS_ZBUFFER; ret = lpDDS7->GetAttachedSurface(&ddscaps, &lpZ_DDS7); if ((ret != DD_OK) && (ret != DDERR_NOTFOUND)) { /* * NOTE: Not an error if the z-buffer is not found. We will let the * dirver handle that (it might fail or create its own z-buffer). */ D3D_ERR("Supplied DirectDraw Z-Buffer is invalid - can't set render target"); throw DDERR_INVALIDPARAMS; } if (lpZ_DDS7) lpZ_DDS7->Release(); // We do not need to addref this one; // QI lpDDS7 for lpDDS interface, which will be used internally by D3D ret = lpDDS7->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)&lpDDS); if(FAILED(ret)) throw ret; /* The palette... */ ret = lpDDS->GetPalette(&lpPal); if ((ret != DD_OK) && (ret != DDERR_NOPALETTEATTACHED)) { /* * NOTE: Again, not an error (yet) if there is no palette attached. * But if there is palette and we can't get at it for some reason * - fail. */ D3D_ERR("Supplied DirectDraw Palette is invalid - can't create device"); throw DDERR_INVALIDPARAMS; } /* * We're going to check now whether we should have got a palette. */ if (ret == DDERR_NOPALETTEATTACHED) { if (ddsd.ddpfPixelFormat.dwRGBBitCount < 16) { D3D_ERR("No palette supplied for palettized surface"); throw DDERR_NOPALETTEATTACHED; } } /* Verify Z buffer */ if (lpZ_DDS7!=NULL) { memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); if ((ret=lpZ_DDS7->GetSurfaceDesc(&ddsd)) != DD_OK) { D3D_ERR("Failed to getsurfacedesc on Z"); throw ret; } // QI lpDDS7 for lpDDS interface, which will be used internally by D3D ret = lpZ_DDS7->QueryInterface(IID_IDirectDrawSurface, (LPVOID*)&lpZ); if(FAILED(ret)) throw ret; } SetRenderTargetI(lpDDS, lpZ); // this indicates that the device need no longer be flushed when Locking, Blting // or GetDC'ing from the previous rendertarget if (this->lpDDSTarget) ((LPDDRAWI_DDRAWSURFACE_INT)this->lpDDSTarget)->lpLcl->lpSurfMore->qwBatch.QuadPart = 0; // this indicates that the device need no longer be flushed when Locking, Blting // or GetDC'ing from the previous zbuffer if (this->lpDDSZBuffer) ((LPDDRAWI_DDRAWSURFACE_INT)this->lpDDSZBuffer)->lpLcl->lpSurfMore->qwBatch.QuadPart = 0; // this indicates that the device should always be flushed when Locking, Blting // or GetDC'ing a rendertarget ((LPDDRAWI_DDRAWSURFACE_INT)lpDDS7)->lpLcl->lpSurfMore->qwBatch.QuadPart = _UI64_MAX; // this indicates that the device should always be flushed when Locking, Blting // or GetDC'ing a zbuffer if(lpZ_DDS7) ((LPDDRAWI_DDRAWSURFACE_INT)lpZ_DDS7)->lpLcl->lpSurfMore->qwBatch.QuadPart = _UI64_MAX; // release old device DDS/DDS7 interfaces and replace with the new ones, // which are mostly already AddRef'd (except for lpDDS7) /// DDSZBuffer /// if(this->lpDDSZBuffer) this->lpDDSZBuffer->Release(); // lpZ AddRef'd by QI this->lpDDSZBuffer = lpZ; /// DDSZBuffer DDS7 /// this->lpDDSZBuffer_DDS7=lpZ_DDS7; // This needs no AddRef or Release /// DDSTarget /// this->lpDDSTarget = lpDDS; #ifndef WIN95 hSurfaceTarget = (unsigned long)((LPDDRAWI_DDRAWSURFACE_INT)lpDDS)->lpLcl->hDDSurface; #else hSurfaceTarget = (unsigned long)((LPDDRAWI_DDRAWSURFACE_INT)lpDDS)->lpLcl->lpSurfMore->dwSurfaceHandle; #endif // lpDDS AddRef'd by QI so release it this->lpDDSTarget->Release(); /// DDSTarget DDS7 /// this->lpDDSTarget_DDS7->Release(); lpDDS7->AddRef(); // ensure lpDDS7 (which was an argument) doesnt disappear this->lpDDSTarget_DDS7=lpDDS7; if (this->lpDDPalTarget) this->lpDDPalTarget->Release(); // already AddRef'd by GetPalette() this->lpDDPalTarget = lpPal; ret=CalcDDSurfInfo(this,TRUE); // this call will never fail due to external error DDASSERT(ret==D3D_OK); return ret; } catch (HRESULT ret) { if(lpPal) lpPal->Release(); if(lpZ) lpZ->Release(); if(lpZ_DDS7) lpZ_DDS7->Release(); if(lpDDS) lpDDS->Release(); return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::GetRenderTarget" HRESULT D3DAPI DIRECT3DDEVICEI::GetRenderTarget(LPDIRECTDRAWSURFACE7* lplpDDS) { CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock. // Release in the destructor if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if ( !VALID_OUTPTR( lplpDDS ) ) { D3D_ERR( "Invalid ptr to DDS ptr" ); return DDERR_INVALIDPARAMS; } *lplpDDS = this->lpDDSTarget_DDS7; this->lpDDSTarget_DDS7->AddRef(); return D3D_OK; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetClipStatus" #define D3DSTATUS_VALID 0x80000000L /* Reserved Status flag to indicate SetClipStatus is called */ HRESULT D3DAPI DIRECT3DDEVICEI::SetClipStatus(LPD3DCLIPSTATUS status) { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (MT only). // Release in the destructor #if DBG if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if (! VALID_PTR(status, sizeof(D3DCLIPSTATUS)) ) { D3D_ERR( "Invalid status pointer" ); return DDERR_INVALIDPARAMS; } #endif // D3DCLIPSTATUS_EXTENTS3 not supported in Device7 if (status->dwFlags & D3DCLIPSTATUS_EXTENTS3) { D3D_ERR( "D3DCLIPSTATUS_EXTENTS3 not supported for Device7" ); return DDERR_INVALIDPARAMS; } if (status->dwFlags & D3DCLIPSTATUS_STATUS) this->iClipStatus = status->dwStatus; if (status->dwFlags & (D3DCLIPSTATUS_EXTENTS2 | D3DCLIPSTATUS_EXTENTS3)) { this->rExtents.x1 = status->minx; this->rExtents.y1 = status->miny; this->rExtents.x2 = status->maxx; this->rExtents.y2 = status->maxy; } return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::GetClipStatus" HRESULT D3DAPI DIRECT3DDEVICEI::GetClipStatus(LPD3DCLIPSTATUS status) { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (MT only). // Release in the destructor #if DBG if (!VALID_DIRECT3DDEVICE_PTR(this)) { D3D_ERR( "Invalid Direct3DDevice pointer" ); return DDERR_INVALIDOBJECT; } if (! VALID_PTR(status, sizeof(D3DCLIPSTATUS)) ) { D3D_ERR( "Invalid status pointer" ); return DDERR_INVALIDPARAMS; } #endif status->dwStatus = iClipStatus; status->dwFlags = D3DCLIPSTATUS_EXTENTS2; status->minx = this->rExtents.x1; status->miny = this->rExtents.y1; status->maxx = this->rExtents.x2; status->maxy = this->rExtents.y2; return D3D_OK; } #undef DPF_MODNAME #define DPF_MODNAME "Direct3DDevice::UpdateTextures" HRESULT DIRECT3DDEVICEI::UpdateTextures() { HRESULT result = D3D_OK; DWORD dwSavedFlags = this->dwFlags; this->dwFlags |= D3DPV_WITHINPRIMITIVE; for (DWORD dwStage = 0; dwStage < this->dwMaxTextureBlendStages; dwStage++) { D3DTEXTUREHANDLE dwDDIHandle; LPDIRECT3DTEXTUREI lpTexI = this->lpD3DMappedTexI[dwStage]; if(lpTexI) { if (lpTexI->bDirty) { if (lpTexI->InVidmem()) { CLockD3DST lockObject(this, DPF_MODNAME, REMIND("")); // we access DDraw gbl in CopySurface // 0xFFFFFFFF is equivalent to ALL_FACES, but in addition indicates to CopySurface // that this is a sysmem -> vidmem transfer. result = CopySurface(lpTexI->lpDDS,NULL,lpTexI->lpDDSSys,NULL,0xFFFFFFFF); if (DD_OK != result) { D3D_ERR("Error copying surface while updating textures"); goto l_exit; } else { lpTexI->bDirty=FALSE; D3D_INFO(4,"UpdateTextures: Dirty texture updated"); } } } LPD3DI_TEXTUREBLOCK lpBlock; if (m_dwStageDirty & (1 << dwStage)) { lpBlock = NULL; // indicates to GetTextureDDIHandle to find the block for this (tex,dev) } else { lpBlock = this->lpD3DMappedBlock[dwStage]; // use the cached block DDASSERT(lpBlock); if (lpBlock->hTex) // have we created a handle for this (tex,dev)? { continue; //nothing need to be done further } } result = GetTextureDDIHandle(lpTexI, &lpBlock); if (result != D3D_OK) { D3D_ERR("Failed to get texture handle"); goto l_exit; } else { dwDDIHandle = lpBlock->hTex; this->lpD3DMappedBlock[dwStage] = lpBlock; BatchTexture(((LPDDRAWI_DDRAWSURFACE_INT)lpTexI->lpDDS)->lpLcl); m_dwStageDirty &= ~(1 << dwStage); // reset stage dirty } } else if (m_dwStageDirty & (1 << dwStage)) { this->lpD3DMappedBlock[dwStage]=NULL; //a SetTexture(Stage,NULL) issued dwDDIHandle = 0; //tell driver to disable this texture m_dwStageDirty &= ~(1 << dwStage); // reset stage dirty } else { continue; //both zero, no action needed } #ifdef WIN95 if (IS_DP2HAL_DEVICE(this)) { #endif CDirect3DDeviceIDP2 *dp2dev = static_cast(this); result = dp2dev->SetTSSI(dwStage, (D3DTEXTURESTAGESTATETYPE)D3DTSS_TEXTUREMAP, dwDDIHandle); if(result != D3D_OK) { D3D_ERR("Failed to batch set texture instruction"); goto l_exit; } // Update runtime copy of state. dp2dev->tsstates[dwStage][D3DTSS_TEXTUREMAP] = dwDDIHandle; #ifdef WIN95 } else { if(this->dwFEFlags & D3DFE_DISABLE_TEXTURES) break; CDirect3DDeviceIHW *dev = static_cast(this); result = dev->SetRenderStateI(D3DRENDERSTATE_TEXTUREHANDLE, dwDDIHandle); if(result != D3D_OK) { D3D_ERR("Failed to batch setrenderstate instruction"); goto l_exit; } // Update runtime copy of state. dev->rstates[D3DRENDERSTATE_TEXTUREHANDLE] = dwDDIHandle; } #endif } l_exit: this->dwFlags = dwSavedFlags; return result; } //--------------------------------------------------------------------- // This function is called from HALEXE.CPP, from device::SetRenderState and // from device::SetTexture. // #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::UpdateInternalState" void DIRECT3DDEVICEI::UpdateInternalState(D3DRENDERSTATETYPE type, DWORD value) { switch (type) { case D3DRENDERSTATE_LIGHTING: if (value) this->dwDeviceFlags |= D3DDEV_LIGHTING; else this->dwDeviceFlags &= ~D3DDEV_LIGHTING; ForceFVFRecompute(); break; case D3DRENDERSTATE_FOGENABLE: rstates[type] = value; // set rstates BEFORE calling SetFogFlags SetFogFlags(); break; case D3DRENDERSTATE_SPECULARENABLE: this->dwFEFlags |= D3DFE_MATERIAL_DIRTY | D3DFE_LIGHTS_DIRTY | D3DFE_FRONTEND_DIRTY; if (value) this->dwDeviceFlags |= D3DDEV_SPECULARENABLE; else this->dwDeviceFlags &= ~D3DDEV_SPECULARENABLE; ForceFVFRecompute(); break; case D3DRENDERSTATE_AMBIENT: { const D3DVALUE SCALE = 1.0f/255.0f; this->lighting.ambientSceneScaled.r = D3DVAL(RGBA_GETRED(value)); this->lighting.ambientSceneScaled.g = D3DVAL(RGBA_GETGREEN(value)); this->lighting.ambientSceneScaled.b = D3DVAL(RGBA_GETBLUE(value)); this->lighting.ambientScene.r = this->lighting.ambientSceneScaled.r * SCALE; this->lighting.ambientScene.g = this->lighting.ambientSceneScaled.g * SCALE; this->lighting.ambientScene.b = this->lighting.ambientSceneScaled.b * SCALE; this->lighting.ambient_save = value; this->dwFEFlags |= D3DFE_MATERIAL_DIRTY | D3DFE_FRONTEND_DIRTY; break; } case D3DRENDERSTATE_RANGEFOGENABLE: if (value) this->dwDeviceFlags |= D3DDEV_RANGEBASEDFOG; else this->dwDeviceFlags &= ~D3DDEV_RANGEBASEDFOG; break; case D3DRENDERSTATE_FOGVERTEXMODE: this->lighting.fog_mode = (D3DFOGMODE)value; SetFogFlags(); break; case D3DRENDERSTATE_COLORVERTEX: if (value) this->dwDeviceFlags |= D3DDEV_COLORVERTEX; else this->dwDeviceFlags &= ~D3DDEV_COLORVERTEX; // Just to make it not take the FE fast path and call DoUpdateState() // This is necessary since we update lighting.alpha and // lighting.alphaSpecular in DoUpdateState. ForceFVFRecompute(); break; case D3DRENDERSTATE_CLIPPING: if (!value) { this->dwDeviceFlags |= D3DDEV_DONOTCLIP; // Clear clip union and intersection flags this->dwClipIntersection = 0; this->dwClipUnion = 0; } else this->dwDeviceFlags &= ~D3DDEV_DONOTCLIP; // This does not really require a "FVF" recompute, // but is a convenient way of switching back from // the fast path for DrawPrimitiveTL. ForceFVFRecompute(); break; case D3DRENDERSTATE_EXTENTS: if (!value) this->dwDeviceFlags |= D3DDEV_DONOTUPDATEEXTENTS; else this->dwDeviceFlags &= ~D3DDEV_DONOTUPDATEEXTENTS; // This does not really require a "FVF" recompute, // but is a convenient way of switching back from // the fast path for DrawPrimitiveTL. ForceFVFRecompute(); break; case D3DRENDERSTATE_FOGDENSITY: this->lighting.fog_density = *(D3DVALUE*)&value; break; case D3DRENDERSTATE_FOGSTART: this->lighting.fog_start = *(D3DVALUE*)&value; UpdateFogFactor(this); break; case D3DRENDERSTATE_FOGEND: this->lighting.fog_end = *(D3DVALUE*)&value; UpdateFogFactor(this); break; case D3DRENDERSTATE_LOCALVIEWER: if (value) this->dwDeviceFlags |= D3DDEV_LOCALVIEWER; else this->dwDeviceFlags &= ~D3DDEV_LOCALVIEWER; this->dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_FRONTEND_DIRTY; break; case D3DRENDERSTATE_NORMALIZENORMALS: if (value) { if (this->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING) { this->dwDeviceFlags &= ~D3DDEV_MODELSPACELIGHTING; this->dwFEFlags |= D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY; } this->dwDeviceFlags |= D3DDEV_NORMALIZENORMALS; } else { this->dwDeviceFlags &= ~D3DDEV_NORMALIZENORMALS; if (!(this->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)) this->dwFEFlags |= D3DFE_NEEDCHECKWORLDVIEWVMATRIX | D3DFE_FRONTEND_DIRTY; } break; case D3DRENDERSTATE_EMISSIVEMATERIALSOURCE: this->lighting.dwEmissiveSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: this->lighting.dwEmissiveSrcIndex = 0; break; case D3DMCS_COLOR2: this->lighting.dwEmissiveSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for DIFFUSEMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_DIFFUSEMATERIALSOURCE: this->lighting.dwDiffuseSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: this->lighting.dwDiffuseSrcIndex = 0; break; case D3DMCS_COLOR2: this->lighting.dwDiffuseSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for DIFFUSEMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_AMBIENTMATERIALSOURCE: this->lighting.dwAmbientSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: this->lighting.dwAmbientSrcIndex = 0; break; case D3DMCS_COLOR2: this->lighting.dwAmbientSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for AMBIENTMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_SPECULARMATERIALSOURCE: this->lighting.dwSpecularSrcIndex = 2; switch (value) { case D3DMCS_COLOR1: this->lighting.dwSpecularSrcIndex = 0; break; case D3DMCS_COLOR2: this->lighting.dwSpecularSrcIndex = 1; break; #if DBG case D3DMCS_MATERIAL: break; default: D3D_ERR("Illegal value for SPECULARMATERIALSOURCE"); goto error_exit; #endif } break; case D3DRENDERSTATE_VERTEXBLEND: { DWORD numBlendMatrices; switch (value) { case D3DVBLEND_DISABLE: numBlendMatrices = 0; break; case D3DVBLEND_1WEIGHT: numBlendMatrices = 2; break; case D3DVBLEND_2WEIGHTS: numBlendMatrices = 3; break; case D3DVBLEND_3WEIGHTS: numBlendMatrices = 4; break; #if DBG default: D3D_ERR("Illegal value for D3DRENDERSTATE_VERTEXBLEND"); goto error_exit; #endif } this->dwFEFlags |= D3DFE_VERTEXBLEND_DIRTY | D3DFE_FRONTEND_DIRTY; } break; case D3DRENDERSTATE_CLIPPLANEENABLE: { this->dwFEFlags |= D3DFE_CLIPPLANES_DIRTY | D3DFE_FRONTEND_DIRTY; this->dwMaxUserClipPlanes = 0; break; } case D3DRENDERSTATE_SHADEMODE: rstates[type] = value; // SetInterpolationFlags depends on the rstates SetInterpolationFlags(this); break; default: // WRAP render states could be re-mapped so we have to restore them before // setting a new value if (type >= D3DRENDERSTATE_WRAP0 && type <= D3DRENDERSTATE_WRAP7) { if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } } break; } rstates[type] = value; // set rstates for all other cases return; #if DBG error_exit: throw DDERR_INVALIDPARAMS; #endif } //--------------------------------------------------------------------- #if DBG static char ProfileStr[PROF_DRAWINDEXEDPRIMITIVEVB+1][32]= { "Execute", "Begin", "BeginIndexed", "DrawPrimitive(Device2)", "DrawIndexedPrimitive(Device2)", "DrawPrimitiveStrided", "DrawIndexedPrimitiveStrided", "DrawPrimitive(Device7)", "DrawIndexedPrimitive(Device7)", "DrawPrimitiveVB", "DrawIndexedPrimitiveVB", }; static char PrimitiveStr[D3DPT_TRIANGLEFAN][16]= { "POINTLIST", "LINELIST", "LINESTRIP", "TRIANGLELIST", "TRIANGLESTRIP", "TRIANGLEFAN", }; static char VertexStr[D3DVT_TLVERTEX][16]= { "D3DVERTEX", "D3DLVERTEX", "D3DTLVERTEX", }; #define PROFILE_LEVEL 0 void DIRECT3DDEVICEI::Profile(DWORD caller, D3DPRIMITIVETYPE dwPrimitive, DWORD dwVertex) { DWORD bitwisecaller= 1 << caller; DWORD bitwisePrimitive = 1 << (DWORD)dwPrimitive; DWORD bitwiseVertex1 = 1 << (dwVertex & 0x001F); DWORD bitwiseVertex2 = 1 << ((dwVertex & 0x03E0) >> 5); char str[256]; DDASSERT(PROF_DRAWINDEXEDPRIMITIVEVB >= caller); DDASSERT(D3DPT_TRIANGLEFAN >= dwPrimitive && D3DPT_POINTLIST<= dwPrimitive); if (dwCaller & bitwisecaller) { if (dwPrimitiveType[caller] & bitwisePrimitive) { if ((dwVertexType1[caller] & bitwiseVertex1) && (dwVertexType2[caller] & bitwiseVertex2)) { return; //matching a previous api call, no spew, could count stat though } else { dwVertexType1[caller] |= bitwiseVertex1; dwVertexType2[caller] |= bitwiseVertex2; } } else { dwPrimitiveType[caller] |= bitwisePrimitive; dwVertexType1[caller] |= bitwiseVertex1; dwVertexType2[caller] |= bitwiseVertex2; } } else { this->dwCaller |= bitwisecaller; dwPrimitiveType[caller] |= bitwisePrimitive; dwVertexType1[caller] |= bitwiseVertex1; dwVertexType2[caller] |= bitwiseVertex2; } wsprintf( (LPSTR) str, ProfileStr[caller]); strcat(str,":"); strcat(str,PrimitiveStr[dwPrimitive-1]); if (dwVertex > D3DVT_TLVERTEX) { if (dwVertex == D3DFVF_VERTEX) { dwVertex = D3DVT_VERTEX; } else if (dwVertex == D3DFVF_LVERTEX) { dwVertex = D3DVT_LVERTEX; } else if (dwVertex == D3DFVF_TLVERTEX) { dwVertex = D3DVT_TLVERTEX; } else { D3D_INFO(PROFILE_LEVEL,"Profile:%s FVFType=%08lx",str,dwVertex); return; } } else { DDASSERT(dwVertex >= D3DVT_VERTEX); } strcat(str,":"); strcat(str,VertexStr[dwVertex-1]); D3D_INFO(PROFILE_LEVEL,"Profile:%s",str); } #endif // DBG //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::MultiplyTransform" // MultiplyTransform -- this preconcatenates the new matrix to the specified // transform matrix // // this really screams for overloaded matrix ops... // HRESULT D3DAPI DIRECT3DDEVICEI::MultiplyTransform(D3DTRANSFORMSTATETYPE dtsTransformState, LPD3DMATRIX lpMat) { #if DBG if (!VALID_D3DMATRIX_PTR(lpMat)) { D3D_ERR( "Invalid matrix pointer" ); return DDERR_INVALIDPARAMS; } #endif try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); // Takes D3D lock (MT only). D3DMATRIXI mResult; switch (dtsTransformState) { case D3DTRANSFORMSTATE_WORLD : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.world[0]); break; case D3DTRANSFORMSTATE_WORLD1 : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.world[1]); break; case D3DTRANSFORMSTATE_WORLD2 : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.world[2]); break; case D3DTRANSFORMSTATE_WORLD3 : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.world[3]); break; case D3DTRANSFORMSTATE_VIEW : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.view); break; case D3DTRANSFORMSTATE_PROJECTION : MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->transform.proj); break; case D3DTRANSFORMSTATE_TEXTURE0: case D3DTRANSFORMSTATE_TEXTURE1: case D3DTRANSFORMSTATE_TEXTURE2: case D3DTRANSFORMSTATE_TEXTURE3: case D3DTRANSFORMSTATE_TEXTURE4: case D3DTRANSFORMSTATE_TEXTURE5: case D3DTRANSFORMSTATE_TEXTURE6: case D3DTRANSFORMSTATE_TEXTURE7: { DWORD dwIndex = dtsTransformState - D3DTRANSFORMSTATE_TEXTURE0; MatrixProduct(&mResult, (D3DMATRIXI*)lpMat, &this->mTexture[dwIndex]); break; } default : D3D_ERR( "Invalid state value passed to MultiplyTransform" ); return DDERR_INVALIDPARAMS; /* Work Item: Generate new meaningful return code */ } SetTransformI(dtsTransformState, (D3DMATRIX*)&mResult); return D3D_OK; } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::BeginStateBlock" HRESULT D3DAPI DIRECT3DDEVICEI::BeginStateBlock() { try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { D3D_ERR("Already in the state record mode"); return D3DERR_INBEGINSTATEBLOCK; } if (m_pStateSets->StartNewSet() != D3D_OK) return DDERR_OUTOFMEMORY; this->dwFEFlags |= D3DFE_RECORDSTATEMODE; #ifdef VTABLE_HACK VtblSetRenderStateRecord(); VtblSetTextureStageStateRecord(); VtblSetTextureRecord(); VtblApplyStateBlockRecord(); #endif VTABLE_HACK return D3D_OK; } catch (HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::EndStateBlock" HRESULT D3DAPI DIRECT3DDEVICEI::EndStateBlock(LPDWORD pdwHandle) { if (!VALID_PTR(pdwHandle, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer" ); return DDERR_INVALIDPARAMS; } try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (!(this->dwFEFlags & D3DFE_RECORDSTATEMODE)) { D3D_ERR("Not in state record mode"); return D3DERR_NOTINBEGINSTATEBLOCK; } this->dwFEFlags &= ~D3DFE_RECORDSTATEMODE; m_pStateSets->EndSet(); #ifdef VTABLE_HACK if (IS_DP2HAL_DEVICE(this) && (!IS_MT_DEVICE(this))) { VtblSetRenderStateExecute(); VtblSetTextureStageStateExecute(); VtblSetTextureExecute(); VtblApplyStateBlockExecute(); } #endif VTABLE_HACK this->WriteStateSetToDevice((D3DSTATEBLOCKTYPE)0); *pdwHandle = m_pStateSets->GetCurrentHandle(); return D3D_OK; } catch(HRESULT ret) { m_pStateSets->Cleanup(m_pStateSets->GetCurrentHandle()); *pdwHandle = 0xFFFFFFFF; return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::DeleteStateBlock" HRESULT D3DAPI DIRECT3DDEVICEI::DeleteStateBlock(DWORD dwHandle) { try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { D3D_ERR("We are in state record mode"); return D3DERR_INBEGINSTATEBLOCK; } m_pStateSets->DeleteStateSet(this, dwHandle); return D3D_OK; } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::ApplyStateBlock" HRESULT D3DAPI DIRECT3DDEVICEI::ApplyStateBlock(DWORD dwHandle) { try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { D3D_ERR("We are in state record mode"); return D3DERR_INBEGINSTATEBLOCK; } return ApplyStateBlockInternal(dwHandle); } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::ApplyStateBlockInternal" HRESULT D3DAPI DIRECT3DDEVICEI::ApplyStateBlockInternal(DWORD dwHandle) { try { m_pStateSets->Execute(this, dwHandle); return D3D_OK; } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::CaptureStateBlock" HRESULT D3DAPI DIRECT3DDEVICEI::CaptureStateBlock(DWORD dwHandle) { try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { D3D_ERR("Cannot capture when in the state record mode"); return D3DERR_INBEGINSTATEBLOCK; } m_pStateSets->Capture(this, dwHandle); return D3D_OK; } catch (HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::CreateStateBlock" HRESULT D3DAPI DIRECT3DDEVICEI::CreateStateBlock(D3DSTATEBLOCKTYPE sbt, LPDWORD pdwHandle) { if (!VALID_PTR(pdwHandle, sizeof(DWORD))) { D3D_ERR( "Invalid DWORD pointer" ); return DDERR_INVALIDPARAMS; } try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) { D3D_ERR("Cannot create state block when in the state record mode"); return D3DERR_INBEGINSTATEBLOCK; } if (m_pStateSets->StartNewSet() != D3D_OK) return DDERR_OUTOFMEMORY; m_pStateSets->CreatePredefined(this, sbt); m_pStateSets->EndSet(); this->WriteStateSetToDevice(sbt); *pdwHandle = m_pStateSets->GetCurrentHandle(); return D3D_OK; } catch (HRESULT ret) { m_pStateSets->Cleanup(m_pStateSets->GetCurrentHandle()); *pdwHandle = 0xFFFFFFFF; return ret; } } //--------------------------------------------------------------------- // Input: // type - FVF control dword // // Returns D3D_OK, if the control dword is valid. // DDERR_INVALIDPARAMS otherwise // #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::ValidateFVF" HRESULT DIRECT3DDEVICEI::ValidateFVF(DWORD type) { DWORD dwTexCoord = FVF_TEXCOORD_NUMBER(type); DWORD vertexType = type & D3DFVF_POSITION_MASK; // Texture format bits above texture count should be zero // Reserved field 0 and 2 should be 0 // Reserved 1 should be set only for LVERTEX // Only two vertex position types allowed if (type & g_TextureFormatMask[dwTexCoord]) { D3D_ERR("FVF has incorrect texture format"); goto error; } if (type & 0xFFFF0000 && vertexType == D3DFVF_XYZRHW && this->deviceType < D3DDEVTYPE_DX7HAL) { D3D_ERR("The D3D device supports only two floats per texture coordinate set"); goto error; } if (type & (D3DFVF_RESERVED2 | D3DFVF_RESERVED0) || (type & D3DFVF_RESERVED1 && !(type & D3DFVF_LVERTEX))) { D3D_ERR("FVF has reserved bit(s) set"); goto error; } if (!(vertexType == D3DFVF_XYZRHW || vertexType == D3DFVF_XYZ || vertexType == D3DFVF_XYZB1 || vertexType == D3DFVF_XYZB2 || vertexType == D3DFVF_XYZB3 || vertexType == D3DFVF_XYZB4 || vertexType == D3DFVF_XYZB5)) { D3D_ERR("FVF has incorrect position type"); goto error; } if (vertexType == D3DFVF_XYZRHW && type & D3DFVF_NORMAL) { D3D_ERR("Normal should not be used with XYZRHW position type"); goto error; } return D3D_OK; error: D3D_ERR("ValidateFVF() returns DDERR_INVALIDPARAMS"); return DDERR_INVALIDPARAMS; } //--------------------------------------------------------------------- // The function should bot be called by ProcessVertices. // Computes nOutTexCoord and dwTextureIndexToCopy in case when a pre-DX6 // driver is used. // void ComputeTCI2CopyLegacy(LPDIRECT3DDEVICEI lpDevI, DWORD dwNumInpTexCoord, DWORD* pdwInpTexCoordSize, BOOL bVertexTransformed) { lpDevI->dwTextureIndexToCopy = 0; lpDevI->nOutTexCoord = 0; lpDevI->dwTextureCoordSizeTotal = 0; lpDevI->dwTextureCoordSize[0] = 0; // If texture is enabled we care about texture gen mode and the texture // index to copy if (lpDevI->tsstates[0][D3DTSS_COLOROP] != D3DTOP_DISABLE) { DWORD dwTexIndex = lpDevI->tsstates[0][D3DTSS_TEXCOORDINDEX]; DWORD dwTexGenMode = dwTexIndex & ~0xFFFF; dwTexIndex &= 0xFFFF; if (bVertexTransformed) { lpDevI->dwTextureIndexToCopy = dwTexIndex; // In case of clipping we need to clip as many texture // coordinates as set in the texture stage state. lpDevI->nOutTexCoord = min(dwNumInpTexCoord, lpDevI->dwTextureIndexToCopy+1); for (DWORD i=0; i < lpDevI->nOutTexCoord; i++) { lpDevI->dwTextureCoordSizeTotal += pdwInpTexCoordSize[i]; lpDevI->dwTextureCoordSize[i] = pdwInpTexCoordSize[i]; } } else if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL || dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION || dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { if (dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) lpDevI->dwDeviceFlags |= D3DDEV_NORMALINCAMERASPACE | D3DDEV_POSITIONINCAMERASPACE; else if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL) lpDevI->dwDeviceFlags |= D3DDEV_NORMALINCAMERASPACE; else if (dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION) lpDevI->dwDeviceFlags |= D3DDEV_POSITIONINCAMERASPACE; lpDevI->dwDeviceFlags |= D3DDEV_REMAPTEXTUREINDICES; LPD3DFE_TEXTURESTAGE pStage = &lpDevI->textureStage[0]; pStage->dwInpCoordIndex = 0; pStage->dwTexGenMode = dwTexGenMode; pStage->dwOrgStage = 0; pStage->dwInpOffset = 0; pStage->dwOutCoordIndex = 0; if (lpDevI->dwFlags2 & __FLAGS2_TEXTRANSFORM0) { pStage->pmTextureTransform = &lpDevI->mTexture[0]; pStage->dwTexTransformFuncIndex = MakeTexTransformFuncIndex(3, 2); } else { pStage->pmTextureTransform = NULL; } pStage->dwOrgWrapMode = lpDevI->rstates[D3DRENDERSTATE_WRAP0]; // Texture index is used as an index to the new WRAP mode DWORD dwNewWrapMode = lpDevI->rstates[D3DRENDERSTATE_WRAP0 + dwTexIndex]; if (dwNewWrapMode != pStage->dwOrgWrapMode) { lpDevI->rstates[D3DRENDERSTATE_WRAP0] = dwNewWrapMode; lpDevI->SetRenderStateI(D3DRENDERSTATE_WRAP0, dwNewWrapMode); } lpDevI->nOutTexCoord = 1; lpDevI->dwNumTextureStages = 1; lpDevI->dwTextureCoordSizeTotal = 8; lpDevI->dwTextureCoordSize[0] = 8; } else if (dwNumInpTexCoord != 0) { lpDevI->nOutTexCoord = 1; lpDevI->dwTextureIndexToCopy = dwTexIndex; lpDevI->dwTextureCoordSizeTotal = 8; lpDevI->dwTextureCoordSize[0] = 8; } } } //--------------------------------------------------------------------- // Computes output FVF id, based on input FVF id and device settingd // Also computes nTexCoord field // Number of texture coordinates is set based on dwVIDIn. ValidateFVF sould // make sure that it is not greater than supported by the driver // Last settings for dwVIDOut and dwVIDIn are saved to speed up processing // #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetupFVFData" HRESULT DIRECT3DDEVICEI::SetupFVFData(DWORD *pdwInpVertexSize) { // We have to restore texture stage indices if previous primitive // re-mapped them if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); } this->dwFEFlags &= ~D3DFE_FVF_DIRTY; this->nTexCoord = FVF_TEXCOORD_NUMBER(this->dwVIDIn); DWORD dwInpTexSizeTotal = ComputeTextureCoordSize(this->dwVIDIn, this->dwInpTextureCoordSize); // Compute size of dwVIDIn DWORD dwInpVertexSize = GetVertexSizeFVF(this->dwVIDIn) + dwInpTexSizeTotal; if (pdwInpVertexSize) { *pdwInpVertexSize = dwInpVertexSize; } // Compute how many texture coordinates to copy ComputeTCI2CopyLegacy(this, this->nTexCoord, this->dwInpTextureCoordSize, FVF_TRANSFORMED(this->dwVIDIn)); if (FVF_TRANSFORMED(this->dwVIDIn)) { this->dwVIDOut = this->dwVIDIn; ComputeOutputVertexOffsets(this); this->dwOutputSize = dwInpVertexSize; return D3D_OK; } else { this->dwVIDOut = D3DFVF_TLVERTEX; this->dwOutputSize = sizeof(D3DTLVERTEX); } if (!(this->dwFlags & D3DPV_VBCALL)) UpdateGeometryLoopData(this); this->dwDeviceFlags &= ~D3DDEV_TEXTURETRANSFORM; // Stage 0 bit is used for the texture transform if (this->dwFlags2 & __FLAGS2_TEXTRANSFORM0) { this->pmTexture[0] = &this->mTexture[0]; this->dwDeviceFlags |= D3DDEV_TEXTURETRANSFORM; if ((this->tsstates[0][D3DTSS_TEXTURETRANSFORMFLAGS] & 0xFF) != 2) { D3D_ERR("The texture transform for the device should use 2 floats"); return DDERR_INVALIDPARAMS; } } else if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { D3D_ERR("Cannot use texture generation without texture transform for pre-DX6 device"); return DDERR_INVALIDPARAMS; } // In case if COLORVERTEX is TRUE, the vertexAlpha could be overriden // by vertex alpha this->lighting.alpha = (DWORD)this->lighting.materialAlpha; this->lighting.alphaSpecular = (DWORD)this->lighting.materialAlphaS; return D3D_OK; } //--------------------------------------------------------------------- // Returns TRUE, if driver state should not be updated // #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::UpdateInternalTextureStageState" BOOL DIRECT3DDEVICEI::UpdateInternalTextureStageState (DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue) { BOOL ret = FALSE; // return TRUE if TSS should NOT be batched if(dwState == D3DTSS_COLOROP) { if(dwValue == D3DTOP_DISABLE || tsstates[dwStage][D3DTSS_COLOROP] == D3DTOP_DISABLE) ForceFVFRecompute(); } else if (dwState == D3DTSS_TEXCOORDINDEX) { if (this->dwDeviceFlags & D3DDEV_REMAPTEXTUREINDICES) { RestoreTextureStages(this); ForceFVFRecompute(); } else if (TextureTransformEnabled(this)) { // Force re-compute if a texture transfrom is enabled ForceFVFRecompute(); } DWORD dwTexGenMode = 0; if (dwValue >= D3DDP_MAXTEXCOORD) { dwTexGenMode = dwValue & ~0xFFFF; if(!IS_TLHAL_DEVICE(this)) ret = TRUE; #if DBG DWORD dwTexIndex = dwValue & 0xFFFF; if (!(dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL || dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION || dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) || dwTexIndex > D3DDP_MAXTEXCOORD) { D3D_ERR("Incorrect texture coordinate set index"); throw DDERR_INVALIDPARAMS; } #endif } DWORD dwTexGenBit = 0; if (dwTexGenMode == D3DTSS_TCI_CAMERASPACENORMAL || dwTexGenMode == D3DTSS_TCI_CAMERASPACEPOSITION || dwTexGenMode == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { dwTexGenBit = __FLAGS2_TEXGEN0 << dwStage; // To set internal "enable" dword } // Force to re-compute FVF only if enable state is changed if ((this->dwFlags2 & dwTexGenBit) != dwTexGenBit) { ForceFVFRecompute(); this->dwFlags2 = (this->dwFlags2 & ~dwTexGenBit) | dwTexGenBit; this->dwDeviceFlags &= ~(D3DDEV_POSITIONINCAMERASPACE | D3DDEV_NORMALINCAMERASPACE); } if (!(this->dwDeviceFlags & D3DDEV_FVF)) { ForceFVFRecompute(); if (dwValue != 0) ret = TRUE; } } else if (dwState == D3DTSS_TEXTURETRANSFORMFLAGS) { DWORD dwEnableBit = 1 << dwStage; // To check internal "enable" dword // Force to re-compute FVF only if enable state is changed if (dwValue == D3DTTFF_DISABLE) { if (this->dwFlags2 & dwEnableBit) { ForceFVFRecompute(); this->dwFlags2 &= ~dwEnableBit; } } else { if (!(this->dwFlags2 & dwEnableBit)) { ForceFVFRecompute(); this->dwFlags2 |= dwEnableBit; } } if(this->deviceType == D3DDEVTYPE_DP2HAL) ret = TRUE; } else if(dwState > D3DTSS_TEXTURETRANSFORMFLAGS) { if(this->deviceType == D3DDEVTYPE_DP2HAL) ret = TRUE; } // Update runtime copy of state. tsstates[dwStage][dwState] = dwValue; return ret; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetClipPlaneI" void DIRECT3DDEVICEI::SetClipPlaneI(DWORD dwPlaneIndex, D3DVALUE* pPlaneEquation) { D3DVALUE *p = &this->transform.userClipPlane[dwPlaneIndex].x; p[0] = pPlaneEquation[0]; p[1] = pPlaneEquation[1]; p[2] = pPlaneEquation[2]; p[3] = pPlaneEquation[3]; this->dwFEFlags |= D3DFE_CLIPPLANES_DIRTY | D3DFE_FRONTEND_DIRTY; this->dwMaxUserClipPlanes = 0; } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::SetClipPlane" HRESULT D3DAPI DIRECT3DDEVICEI::SetClipPlane(DWORD dwPlaneIndex, D3DVALUE* pPlaneEquation) { #if DBG if (dwPlaneIndex >= max(this->transform.dwMaxUserClipPlanes, __MAXUSERCLIPPLANES)) { D3D_ERR("Plane index is too big"); return DDERR_INVALIDPARAMS; } if (!VALID_PTR(pPlaneEquation, sizeof(D3DVALUE)*4)) { D3D_ERR( "Invalid plane pointer" ); return DDERR_INVALIDPARAMS; } #endif try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); if (this->dwFEFlags & D3DFE_RECORDSTATEMODE) m_pStateSets->InsertClipPlane(dwPlaneIndex, pPlaneEquation); else SetClipPlaneI(dwPlaneIndex, pPlaneEquation); return D3D_OK; } catch(HRESULT ret) { return ret; } } //--------------------------------------------------------------------- #undef DPF_MODNAME #define DPF_MODNAME "DIRECT3DDEVICEI::GetClipPlane" HRESULT D3DAPI DIRECT3DDEVICEI::GetClipPlane(DWORD dwPlaneIndex, D3DVALUE* pPlaneEquation) { #if DBG if (dwPlaneIndex >= max(this->transform.dwMaxUserClipPlanes, __MAXUSERCLIPPLANES)) { D3D_ERR("Plane index is too big"); return DDERR_INVALIDPARAMS; } if (!VALID_PTR(pPlaneEquation, sizeof(D3DVALUE)*4)) { D3D_ERR( "Invalid plane pointer" ); return DDERR_INVALIDPARAMS; } #endif try { CLockD3DMT lockObject(this, DPF_MODNAME, REMIND("")); D3DVALUE *p = &this->transform.userClipPlane[dwPlaneIndex].x; pPlaneEquation[0] = p[0]; pPlaneEquation[1] = p[1]; pPlaneEquation[2] = p[2]; pPlaneEquation[3] = p[3]; return D3D_OK; } catch(HRESULT ret) { return ret; } }