|
|
//----------------------------------------------------------------------------
//
// rasttex.cpp
//
// Texture functions.
//
// Copyright (C) Microsoft Corporation, 1997.
//
//----------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
//----------------------------------------------------------------------------
//
// SetSizesSpanTexture
//
// Initialize pSpanTex data using current iMaxMipLevel info, Getting the
// surfaces from pSurf. Assumes InitSpanTexture has been called first.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::SetSizesSpanTexture(PD3DI_SPANTEX pSpanTex) { LPDDRAWI_DDRAWSURFACE_LCL pLcl; INT iFirstSurf = min(pSpanTex->iMaxMipLevel, pSpanTex->cLODTex); LPDIRECTDRAWSURFACE pDDS = pSpanTex->pSurf[iFirstSurf]; INT i;
// Init
pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)pDDS)->lpLcl;
pSpanTex->iSizeU = (INT16)DDSurf_Width(pLcl); pSpanTex->iSizeV = (INT16)DDSurf_Height(pLcl); pSpanTex->uMaskU = (INT16)(pSpanTex->iSizeU - 1); pSpanTex->uMaskV = (INT16)(pSpanTex->iSizeV - 1); pSpanTex->iShiftU = (INT16)IntLog2(pSpanTex->iSizeU); if (0 != DDSurf_BitDepth(pLcl)) { pSpanTex->iShiftPitch[0] = (INT16)IntLog2((UINT32)(DDSurf_Pitch(pLcl) * 8)/DDSurf_BitDepth(pLcl)); } else { pSpanTex->iShiftPitch[0] = (INT16)IntLog2(((UINT32)DDSurf_Width(pLcl) * 8)); } pSpanTex->iShiftV = (INT16)IntLog2(pSpanTex->iSizeV); pSpanTex->uMaskV = pSpanTex->uMaskV;
// Check if the texture size is power of 2
if (!ValidTextureSize(pSpanTex->iSizeU, pSpanTex->iShiftU, pSpanTex->iSizeV, pSpanTex->iShiftV)) { // this texture can only be used for a ramp fill
pSpanTex->uFlags |= D3DI_SPANTEX_NON_POWER_OF_2; pSpanTex->cLODTex = 0; }
// Check for mipmap if any.
// iPreSizeU and iPreSizeV store the size(u and v) of the previous level
// mipmap. They are init'ed with the first texture size.
INT16 iPreSizeU = pSpanTex->iSizeU, iPreSizeV = pSpanTex->iSizeV; for ( i = iFirstSurf + 1; i <= pSpanTex->cLODTex; i++) { pDDS = pSpanTex->pSurf[i]; // Check for invalid mipmap texture size
pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)pDDS)->lpLcl; if (!ValidMipmapSize(iPreSizeU, (INT16)DDSurf_Width(pLcl)) || !ValidMipmapSize(iPreSizeV, (INT16)DDSurf_Height(pLcl))) { return DDERR_INVALIDPARAMS; } if (0 != DDSurf_BitDepth(pLcl)) { pSpanTex->iShiftPitch[i - iFirstSurf] = (INT16)IntLog2(((UINT32)DDSurf_Pitch(pLcl)*8)/DDSurf_BitDepth(pLcl)); } else { pSpanTex->iShiftPitch[0] = (INT16)IntLog2(((UINT32)DDSurf_Width(pLcl)*8)); } iPreSizeU = (INT16)DDSurf_Width(pLcl); iPreSizeV = (INT16)DDSurf_Height(pLcl); } pSpanTex->iMaxScaledLOD = ((pSpanTex->cLODTex + 1) << LOD_SHIFT) - 1; pSpanTex->uFlags &= ~D3DI_SPANTEX_MAXMIPLEVELS_DIRTY;
return D3D_OK; }
//----------------------------------------------------------------------------
//
// InitSpanTexture
//
// Initializes the entire array of pSurf's (regardless of iMaxMipLevel) pointed
// to by the root surface of pDDS. Sets all pSpanTex state that will not ever
// change in SetSizesSpanTexture.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::InitSpanTexture(PD3DI_SPANTEX pSpanTex, LPDIRECTDRAWSURFACE pDDS) { HRESULT hr; LPDDRAWI_DDRAWSURFACE_LCL pLcl; DDSCAPS ddscaps; static INT32 iGeneration = 0;
// Init
pSpanTex->iGeneration = iGeneration++;
// Note that all pSpanTex elements are initialized to 0
pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)pDDS)->lpLcl;
// Set the transparent bit and the transparent color with pSurf[0]
// initially
if ((pLcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT) != 0) { pSpanTex->uFlags |= D3DI_SPANTEX_HAS_TRANSPARENT; pSpanTex->TransparentColor = pLcl->ddckCKSrcBlt.dwColorSpaceHighValue; } else { pSpanTex->uFlags &= ~D3DI_SPANTEX_HAS_TRANSPARENT; }
HR_RET(FindOutSurfFormat(&(DDSurf_PixFmt(pLcl)), &(pSpanTex->Format)));
if (pSpanTex->Format == D3DI_SPTFMT_PALETTE8 || pSpanTex->Format == D3DI_SPTFMT_PALETTE4) { if (pLcl->lpDDPalette) { LPDDRAWI_DDRAWPALETTE_GBL pPal = pLcl->lpDDPalette->lpLcl->lpGbl; if (pPal->dwFlags & DDRAWIPAL_ALPHA) { pSpanTex->uFlags |= D3DI_SPANTEX_ALPHAPALETTE; } pSpanTex->pPalette = (PUINT32)pPal->lpColorTable; } if (pSpanTex->Format == D3DI_SPTFMT_PALETTE8) { pSpanTex->iPaletteSize = 256; } else { // PALETTE4
pSpanTex->iPaletteSize = 16; } } pSpanTex->TexAddrU = D3DTADDRESS_WRAP; pSpanTex->TexAddrV = D3DTADDRESS_WRAP; pSpanTex->BorderColor = RGBA_MAKE(0xff, 0x00, 0xff, 0xff);
// assign first pSurf here (mipmap chain gets assigned below)
pSpanTex->pSurf[0] = pDDS;
// Check for mipmap if any.
LPDIRECTDRAWSURFACE pTmpS; // iPreSizeU and iPreSizeV store the size(u and v) of the previous level
// mipmap. They are init'ed with the first texture size.
INT16 iPreSizeU = pSpanTex->iSizeU, iPreSizeV = pSpanTex->iSizeV; for (;;) { memset(&ddscaps, 0, sizeof(DDSCAPS)); ddscaps.dwCaps = DDSCAPS_TEXTURE; hr = pDDS->GetAttachedSurface(&ddscaps, &pTmpS); //implicit AddRef
if (hr == DDERR_NOTFOUND) { break; } else if (hr != D3D_OK) { return hr; } pDDS = pTmpS;
pSpanTex->cLODTex ++; pSpanTex->pSurf[pSpanTex->cLODTex] = pTmpS; }
pSpanTex->dwSize = sizeof(D3DI_SPANTEX);
return D3D_OK; }
//----------------------------------------------------------------------------
//
// RemoveTexture
//
// Check to see if the to-be-destroyed pSpanTex is currently used by the
// context. If yes, set the according entry to be NULL to disable texture.
//
//----------------------------------------------------------------------------
void D3DContext::RemoveTexture(PD3DI_SPANTEX pSpanTex) { INT i; INT cActTex = (INT)m_RastCtx.cActTex;
for (i = 0; i < cActTex; i++) { if (m_RastCtx.pTexture[i] == pSpanTex) { // NULL out the according texture and set dirty bits
m_RastCtx.cActTex --; StateChanged(D3DRENDERSTATE_TEXTUREHANDLE); m_RastCtx.pTexture[i] = NULL; for (int j=pSpanTex->cLODTex;j>0;j--) //release attached surfs
{ pSpanTex->pSurf[j]->Release(); } } } } //----------------------------------------------------------------------------
//
// RastTextureCreate
//
// Creates a RAST texture and initializes it with the info passed in.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastTextureCreate(LPD3DHAL_TEXTURECREATEDATA pTexData) { PD3DI_SPANTEX *ppSpanTex; PD3DI_SPANTEX pSpanTex; D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastTextureCreate", pTexData);
// Create the span texture
ppSpanTex = new PD3DI_SPANTEX; pSpanTex = new D3DI_SPANTEX; if (ppSpanTex == NULL || pSpanTex == NULL) { delete ppSpanTex; delete pSpanTex; D3D_ERR("(Rast) Out of memory in RastTextureCreate"); pTexData->ddrval = DDERR_OUTOFMEMORY; return DDHAL_DRIVER_HANDLED; } memset(pSpanTex, 0, sizeof(D3DI_SPANTEX));
// Point indirector to this texture initially.
*ppSpanTex = pSpanTex;
// Init the span texture
if ((pTexData->ddrval = pDCtx->InitSpanTexture(pSpanTex, pTexData->lpDDS)) != D3D_OK) { delete ppSpanTex; delete pSpanTex; return DDHAL_DRIVER_HANDLED; } if ((pTexData->ddrval = pDCtx->SetSizesSpanTexture(pSpanTex)) != D3D_OK) { delete ppSpanTex; delete pSpanTex; return DDHAL_DRIVER_HANDLED; }
// ppSpanTex is used as the texture handle returned to d3dim.
pTexData->dwHandle = (UINT32)(ULONG_PTR)ppSpanTex;
pTexData->ddrval = D3D_OK; return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// RastTextureDestroy
//
// Destroy a RAST texture.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastTextureDestroy(LPD3DHAL_TEXTUREDESTROYDATA pTexDestroyData) { PD3DI_SPANTEX *ppSpanTex; PD3DI_SPANTEX pSpanTex; D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastTextureDestroy", pTexDestroyData); if (!VALID_D3DI_SPANTEX_PTR_PTR( (PD3DI_SPANTEX*)ULongToPtr(pTexDestroyData->dwHandle))) { D3D_ERR("(Rast) in RastTextureDestroy, invalid texture handle"); pTexDestroyData->ddrval = DDERR_INVALIDPARAMS; return DDHAL_DRIVER_HANDLED; }
// Find the texture
ppSpanTex = (PD3DI_SPANTEX *)ULongToPtr(pTexDestroyData->dwHandle); pSpanTex = *ppSpanTex;
pDCtx->RemoveTexture(pSpanTex);
// Delete it
if (pSpanTex) { delete ppSpanTex; delete pSpanTex; } else { pTexDestroyData->ddrval = DDERR_INVALIDPARAMS; }
return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// RastTextureSwap
//
// Swaps over the ownership of two texture handles.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastTextureSwap(LPD3DHAL_TEXTURESWAPDATA pTexSwapData) { D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastTextureSwap", pTexSwapData);
// Check out the span textures
PD3DI_SPANTEX pSpanTex1, pSpanTex2; pSpanTex1 = HANDLE_TO_SPANTEX(pTexSwapData->dwHandle1); pSpanTex2 = HANDLE_TO_SPANTEX(pTexSwapData->dwHandle2);
// Swap
if (pSpanTex1 != NULL && pSpanTex2 != NULL) { HANDLE_TO_SPANTEX(pTexSwapData->dwHandle1) = pSpanTex2; HANDLE_TO_SPANTEX(pTexSwapData->dwHandle2) = pSpanTex1; pTexSwapData->ddrval = D3D_OK; } else { pTexSwapData->ddrval = DDERR_INVALIDPARAMS; }
return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// RastTextureGetSurf
//
// Returns the surface pointer associate with a texture handle.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastTextureGetSurf(LPD3DHAL_TEXTUREGETSURFDATA pTexGetSurf) { D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastTextureGetSurf", pTexGetSurf);
// Check out the span texture
PD3DI_SPANTEX pSpanTex; pSpanTex = HANDLE_TO_SPANTEX(pTexGetSurf->dwHandle);
if (pSpanTex) { pTexGetSurf->lpDDS = (UINT_PTR)pSpanTex->pSurf[0]; pTexGetSurf->ddrval = D3D_OK; } else { pTexGetSurf->ddrval = DDERR_INVALIDPARAMS; } return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// RastLockSpanTexture
//
// Lock current texture surface before the texture bits are accessed.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::RastLockSpanTexture(void) { INT i, j; PD3DI_SPANTEX pSpanTex; HRESULT hr;
if (IsTextureOff()) { return D3D_OK; }
DDASSERT((m_uFlags & D3DCONTEXT_TEXTURE_LOCKED) == 0);
for (j = 0; j < (INT)m_RastCtx.cActTex; j++) { pSpanTex = m_RastCtx.pTexture[j]; if (pSpanTex->uFlags & D3DI_SPANTEX_MAXMIPLEVELS_DIRTY) { hr = SetSizesSpanTexture(pSpanTex); if (hr != D3D_OK) { goto EH_Unlock; } } INT iFirstSurf = min(pSpanTex->iMaxMipLevel, pSpanTex->cLODTex);
// Currently recursive locks are not allowed.
DDASSERT((pSpanTex->uFlags & D3DI_SPANTEX_SURFACES_LOCKED) == 0);
for (i = iFirstSurf; i <= pSpanTex->cLODTex; i++) { hr = LockSurface(pSpanTex->pSurf[i], (LPVOID*)&(pSpanTex->pBits[i-iFirstSurf])); if (hr != D3D_OK) { // Unlock any partial mipmap locks we've taken, as
// RastUnlock can only handle entire textures being
// locked or unlocked.
while (--i >= 0) { UnlockSurface(pSpanTex->pSurf[i]); }
// Make sure that i is signed and that the above
// loop exited properly.
DDASSERT(i < 0);
goto EH_Unlock; } }
pSpanTex->uFlags |= D3DI_SPANTEX_SURFACES_LOCKED; }
m_uFlags |= D3DCONTEXT_TEXTURE_LOCKED;
return D3D_OK;
EH_Unlock: if (j > 0) { // Unlock complete textures we've already locked.
// RastUnlock will check the flags to figure
// out which ones to unlock.
RastUnlockSpanTexture(); }
return hr; }
//----------------------------------------------------------------------------
//
// RastUnlockTexture
//
// Unlock texture surface after the texture bits are accessed.
// The input is a D3DI_SPANTEX. NULL texture needs to be checked before this
// function gets called.
//
//----------------------------------------------------------------------------
void D3DContext::RastUnlockSpanTexture(void) { INT i, j; PD3DI_SPANTEX pSpanTex;;
if (IsTextureOff()) { return; }
DDASSERT((m_uFlags & D3DCONTEXT_TEXTURE_LOCKED) != 0);
for (j = 0; j < (INT)m_RastCtx.cActTex; j++) { pSpanTex = m_RastCtx.pTexture[j];
INT iFirstSurf = min(pSpanTex->iMaxMipLevel, pSpanTex->cLODTex); // RastUnlock is used for cleanup in RastLock so it needs to
// be able to handle partially locked mipmap chains.
if (pSpanTex->uFlags & D3DI_SPANTEX_SURFACES_LOCKED) { for (i = iFirstSurf; i <= pSpanTex->cLODTex; i++) { UnlockSurface(pSpanTex->pSurf[i]); }
pSpanTex->uFlags &= ~D3DI_SPANTEX_SURFACES_LOCKED; } } m_uFlags &= ~D3DCONTEXT_TEXTURE_LOCKED; }
//----------------------------------------------------------------------------
//
// UpdateColorKeyAndPalette
//
// Updates the color key value and palette.
//
// Also, if the ColorKey enable for the texture has changed, set the texture handle
// dirty bit so the new mode is recognized in span init.
//
//----------------------------------------------------------------------------
void D3DContext::UpdateColorKeyAndPalette(void) { INT j; PD3DI_SPANTEX pSpanTex;
// Set the transparent bit and the transparent color with pSurf[0]
LPDDRAWI_DDRAWSURFACE_LCL pLcl; for (j = 0; j < (INT)m_RastCtx.cActTex; j++) { pSpanTex = m_RastCtx.pTexture[j]; if ((pSpanTex != NULL) && (pSpanTex->pSurf[0] != NULL)) { pLcl = ((LPDDRAWI_DDRAWSURFACE_INT) pSpanTex->pSurf[0])->lpLcl;
// Palette might be changed
if (pSpanTex->Format == D3DI_SPTFMT_PALETTE8 || pSpanTex->Format == D3DI_SPTFMT_PALETTE4) { if (pLcl->lpDDPalette) { LPDDRAWI_DDRAWPALETTE_GBL pPal = pLcl->lpDDPalette->lpLcl->lpGbl; if (pPal->dwFlags & DDRAWIPAL_ALPHA) { pSpanTex->uFlags |= D3DI_SPANTEX_ALPHAPALETTE; } pSpanTex->pPalette = (PUINT32)pPal->lpColorTable; } }
if ((pLcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT) != 0) { // texture has a ColorKey value
pSpanTex->TransparentColor = pLcl->ddckCKSrcBlt.dwColorSpaceHighValue; if (!(pSpanTex->uFlags & D3DI_SPANTEX_HAS_TRANSPARENT)) { pSpanTex->uFlags |= D3DI_SPANTEX_HAS_TRANSPARENT;
// make sure this state change is recognized, and a new
// texture read function is used
StateChanged(D3DHAL_TSS_OFFSET(j, D3DTSS_TEXTUREMAP)); } } else { // texture does not have a ColorKey value
if (pSpanTex->uFlags & D3DI_SPANTEX_HAS_TRANSPARENT) { pSpanTex->uFlags &= ~D3DI_SPANTEX_HAS_TRANSPARENT;
// make sure this state change is recognized, and a new
// texture read function is used
StateChanged(D3DHAL_TSS_OFFSET(j, D3DTSS_TEXTUREMAP)); } } } } }
//----------------------------------------------------------------------------
//
// Dp2TextureStageState
//
// Called by Drawprim2 to set texture stage states..
//
//----------------------------------------------------------------------------
HRESULT D3DContext::Dp2TextureStageState(LPD3DHAL_DP2COMMAND pCmd, DWORD dwFvf) { WORD wStateCount = pCmd->wStateCount; INT i; HRESULT hr; LPD3DHAL_DP2TEXTURESTAGESTATE pTexStageState = (D3DHAL_DP2TEXTURESTAGESTATE *)(pCmd + 1); // Flush the prim proc before any state changs
HR_RET(End(FALSE));
for (i = 0; i < (INT)wStateCount; i++, pTexStageState++) { HR_RET(SetRenderState(D3DHAL_TSS_OFFSET((DWORD)pTexStageState->wStage, (DWORD)pTexStageState->TSState), pTexStageState->dwValue)); }
HR_RET(CheckFVF(dwFvf));
hr = Begin(); return hr; }
|