Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

604 lines
18 KiB

//----------------------------------------------------------------------------
//
// 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;
}