1136 lines
34 KiB
C++
1136 lines
34 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Microsoft Corporation, 1998.
|
|
//
|
|
// texmap.cpp
|
|
//
|
|
// Direct3D Reference Rasterizer - Texture Map Access Methods
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// FindOutSurfFormat
|
|
//
|
|
// Converts a DDPIXELFORMAT to RDSurfaceFormat.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
HRESULT FASTCALL
|
|
FindOutSurfFormat(LPDDPIXELFORMAT pDdPixFmt,
|
|
RDSurfaceFormat* pFmt,
|
|
BOOL* pbIsDepth)
|
|
{
|
|
if( pbIsDepth ) *pbIsDepth = FALSE;
|
|
|
|
if (pDdPixFmt->dwFourCC == D3DFMT_Q8W8V8U8 )
|
|
{
|
|
*pFmt = RD_SF_U8V8W8Q8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_W11V11U10 )
|
|
{
|
|
*pFmt = RD_SF_U10V11W11;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_V16U16 )
|
|
{
|
|
*pFmt = RD_SF_U16V16;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_R8G8B8 )
|
|
{
|
|
*pFmt = RD_SF_B8G8R8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_A8 )
|
|
{
|
|
*pFmt = RD_SF_A8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_A8P8 )
|
|
{
|
|
*pFmt = RD_SF_P8A8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_X4R4G4B4 )
|
|
{
|
|
*pFmt = RD_SF_B4G4R4X4;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_A2B10G10R10)
|
|
{
|
|
*pFmt = RD_SF_R10G10B10A2;
|
|
}
|
|
#if 0
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_A8B8G8R8)
|
|
{
|
|
*pFmt = RD_SF_R8G8B8A8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_X8B8G8R8)
|
|
{
|
|
*pFmt = RD_SF_R8G8B8X8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_W10V11U11)
|
|
{
|
|
*pFmt = RD_SF_U11V11W10;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_A8X8V8U8)
|
|
{
|
|
*pFmt = RD_SF_U8V8X8A8;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_L8X8V8U8)
|
|
{
|
|
*pFmt = RD_SF_U8V8X8L8;
|
|
}
|
|
#endif
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_G16R16)
|
|
{
|
|
*pFmt = RD_SF_R16G16;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == D3DFMT_A2W10V10U10)
|
|
{
|
|
*pFmt = RD_SF_U10V10W10A2;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('U', 'Y', 'V', 'Y'))
|
|
{
|
|
*pFmt = RD_SF_UYVY;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('Y', 'U', 'Y', '2'))
|
|
{
|
|
*pFmt = RD_SF_YUY2;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('D', 'X', 'T', '1'))
|
|
{
|
|
*pFmt = RD_SF_DXT1;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('D', 'X', 'T', '2'))
|
|
{
|
|
*pFmt = RD_SF_DXT2;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('D', 'X', 'T', '3'))
|
|
{
|
|
*pFmt = RD_SF_DXT3;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('D', 'X', 'T', '4'))
|
|
{
|
|
*pFmt = RD_SF_DXT4;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == MAKEFOURCC('D', 'X', 'T', '5'))
|
|
{
|
|
*pFmt = RD_SF_DXT5;
|
|
}
|
|
else if (pDdPixFmt->dwFourCC == 0xFF000004)
|
|
{
|
|
// This is an example of a IHV-specific format
|
|
// The HIWORD must be the PCI-ID of the IHV
|
|
// and the third byte must be zero.
|
|
// In this case, we're using a sample PCI-ID of
|
|
// FF00, and we're denoting the 4th format
|
|
// by that PCI-ID
|
|
*pFmt = RD_SF_Z32S0;
|
|
}
|
|
else if (pDdPixFmt->dwFlags & DDPF_ZBUFFER)
|
|
{
|
|
if( pbIsDepth ) *pbIsDepth = TRUE;
|
|
switch(pDdPixFmt->dwZBitMask)
|
|
{
|
|
default:
|
|
case 0x0000FFFF: *pFmt = RD_SF_Z16S0; break;
|
|
case 0xFFFFFF00:
|
|
switch(pDdPixFmt->dwStencilBitMask)
|
|
{
|
|
default:
|
|
case 0x00000000: *pFmt = RD_SF_Z24X8; break;
|
|
case 0x000000FF: *pFmt = RD_SF_Z24S8; break;
|
|
case 0x0000000F: *pFmt = RD_SF_Z24X4S4; break;
|
|
}
|
|
break;
|
|
case 0x00FFFFFF:
|
|
switch(pDdPixFmt->dwStencilBitMask)
|
|
{
|
|
default:
|
|
case 0x00000000: *pFmt = RD_SF_X8Z24; break;
|
|
case 0xFF000000: *pFmt = RD_SF_S8Z24; break;
|
|
case 0x0F000000: *pFmt = RD_SF_X4S4Z24; break;
|
|
}
|
|
break;
|
|
case 0x0000FFFE: *pFmt = RD_SF_Z15S1; break;
|
|
case 0x00007FFF: *pFmt = RD_SF_S1Z15; break;
|
|
case 0xFFFFFFFF: *pFmt = RD_SF_Z32S0; break;
|
|
}
|
|
}
|
|
else if (pDdPixFmt->dwFlags & DDPF_BUMPDUDV)
|
|
{
|
|
UINT uFmt = pDdPixFmt->dwBumpDvBitMask;
|
|
switch (uFmt)
|
|
{
|
|
case 0x0000ff00:
|
|
switch (pDdPixFmt->dwRGBBitCount)
|
|
{
|
|
case 32:
|
|
*pFmt = RD_SF_U8V8L8X8;
|
|
break;
|
|
case 16:
|
|
*pFmt = RD_SF_U8V8;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0x000003e0:
|
|
*pFmt = RD_SF_U5V5L6;
|
|
break;
|
|
}
|
|
}
|
|
else if (pDdPixFmt->dwFlags & DDPF_PALETTEINDEXED8)
|
|
{
|
|
if (pDdPixFmt->dwFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
*pFmt = RD_SF_P8A8;
|
|
}
|
|
else
|
|
{
|
|
*pFmt = RD_SF_PALETTE8;
|
|
}
|
|
}
|
|
else if (pDdPixFmt->dwFlags & DDPF_PALETTEINDEXED4)
|
|
{
|
|
*pFmt = RD_SF_PALETTE4;
|
|
}
|
|
else if (pDdPixFmt->dwFlags & DDPF_ALPHA)
|
|
{
|
|
if (pDdPixFmt->dwAlphaBitDepth == 8)
|
|
{
|
|
*pFmt = RD_SF_A8;
|
|
}
|
|
else
|
|
{
|
|
*pFmt = RD_SF_NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UINT uFmt = pDdPixFmt->dwGBitMask | pDdPixFmt->dwRBitMask;
|
|
|
|
if (pDdPixFmt->dwFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
uFmt |= pDdPixFmt->dwRGBAlphaBitMask;
|
|
}
|
|
|
|
switch (uFmt)
|
|
{
|
|
case 0x00ffff00:
|
|
switch (pDdPixFmt->dwRGBBitCount)
|
|
{
|
|
case 32:
|
|
*pFmt = RD_SF_B8G8R8X8;
|
|
break;
|
|
case 24:
|
|
*pFmt = RD_SF_B8G8R8;
|
|
break;
|
|
}
|
|
break;
|
|
case 0xffffff00:
|
|
*pFmt = RD_SF_B8G8R8A8;
|
|
break;
|
|
case 0xffe0:
|
|
if (pDdPixFmt->dwFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
*pFmt = RD_SF_B5G5R5A1;
|
|
}
|
|
else
|
|
{
|
|
*pFmt = RD_SF_B5G6R5;
|
|
}
|
|
break;
|
|
case 0x07fe0:
|
|
*pFmt = RD_SF_B5G5R5X1;
|
|
break;
|
|
case 0xff0:
|
|
*pFmt = RD_SF_B4G4R4X4;
|
|
break;
|
|
case 0xfff0:
|
|
*pFmt = RD_SF_B4G4R4A4;
|
|
break;
|
|
case 0xff:
|
|
if (pDdPixFmt->dwFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
*pFmt = RD_SF_L4A4;
|
|
}
|
|
else
|
|
{
|
|
*pFmt = RD_SF_L8;
|
|
}
|
|
break;
|
|
case 0xffff:
|
|
*pFmt = RD_SF_L8A8;
|
|
break;
|
|
case 0xfc:
|
|
*pFmt = RD_SF_B2G3R3;
|
|
break;
|
|
case 0xfffc:
|
|
*pFmt = RD_SF_B2G3R3A8;
|
|
break;
|
|
default:
|
|
*pFmt = RD_SF_NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return D3D_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// ValidMipmapSize
|
|
//
|
|
// Computes size of next smallest mipmap level, clamping at 1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL FASTCALL
|
|
ValidMipmapSize(INT16 iPreSize, INT16 iSize)
|
|
{
|
|
if (iPreSize == 1)
|
|
{
|
|
if (iSize == 1)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return ((iPreSize >> 1) == iSize);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RDPalette
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
const DWORD RDPalette::RDPAL_ALPHAINPALETTE = (1 << 0);
|
|
const DWORD RDPalette::m_dwNumEntries = 256;
|
|
|
|
HRESULT
|
|
RDPalette::Update( WORD StartIndex, WORD wNumEntries, PALETTEENTRY* pEntries )
|
|
{
|
|
_ASSERT( StartIndex < m_dwNumEntries, "Bad StartIndex\n" );
|
|
_ASSERT( StartIndex+wNumEntries <= m_dwNumEntries, "Too many entries\n" );
|
|
|
|
for( WORD i = 0; i < wNumEntries; i++ )
|
|
{
|
|
m_Entries[StartIndex+i] = D3DCOLOR_ARGB( pEntries[i].peFlags,
|
|
pEntries[i].peRed,
|
|
pEntries[i].peGreen,
|
|
pEntries[i].peBlue );
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Constructor/Destructor
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RDSurface2D::RDSurface2D( void )
|
|
{
|
|
m_pRefDev = NULL;
|
|
m_uFlags = 0;
|
|
m_iWidth = 0;
|
|
m_iHeight = 0;
|
|
m_iDepth = 0;
|
|
m_cLOD = 0;
|
|
m_SurfFormat = RD_SF_NULL;
|
|
m_dwColorKey = 0;
|
|
m_dwEmptyFaceColor = 0;
|
|
m_pPalette = 0;
|
|
m_pPalObj = NULL;
|
|
m_cLODDDS = 0;
|
|
m_hTex = 0;
|
|
m_bHasAlpha = 0;
|
|
|
|
memset(m_pBits, 0, sizeof(m_pBits));
|
|
memset(m_iPitch, 0, sizeof(m_iPitch));
|
|
memset(m_iSlicePitch, 0, sizeof(m_iSlicePitch));
|
|
memset(m_pDDSLcl, 0, sizeof(m_pDDSLcl));
|
|
|
|
m_cDimension = 0;
|
|
memset(m_fTexels, 0, sizeof(m_fTexels));
|
|
memset(m_cTexels, 0, sizeof(m_cTexels));
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
RDSurface2D::~RDSurface2D( void )
|
|
{
|
|
}
|
|
|
|
DWORD
|
|
RDSurface2D::ComputePitch( LPDDRAWI_DDRAWSURFACE_LCL pLcl,
|
|
RDSurfaceFormat SurfFormat,
|
|
DWORD width, DWORD height ) const
|
|
{
|
|
if ((SurfFormat == RD_SF_DXT1) ||
|
|
(SurfFormat == RD_SF_DXT2) ||
|
|
(SurfFormat == RD_SF_DXT3) ||
|
|
(SurfFormat == RD_SF_DXT4) ||
|
|
(SurfFormat == RD_SF_DXT5))
|
|
{
|
|
// Note, here is the assumption that:
|
|
// 1) width and height are reported correctly by the runtime.
|
|
// 2) The allocation of the memory is contiguous (as done by hel)
|
|
return (((width+3)>>2) *
|
|
g_DXTBlkSize[(int)SurfFormat - (int)RD_SF_DXT1]);
|
|
}
|
|
#if 0
|
|
else if( (SurfFormat == RD_SF_YUY2) ||
|
|
(SurfFormat == RD_SF_UYVY) )
|
|
{
|
|
// Same assumptions as for DXTn.
|
|
return (DDSurf_Pitch(pLcl)/height);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
return DDSurf_Pitch(pLcl);
|
|
}
|
|
}
|
|
|
|
DWORD
|
|
RDSurface2D::ComputePitch( LPDDRAWI_DDRAWSURFACE_LCL pLcl ) const
|
|
{
|
|
return ComputePitch( pLcl, m_SurfFormat, m_iWidth, m_iHeight );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RDSurface2D::Initialize()
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RDSurface2D::Initialize( LPDDRAWI_DDRAWSURFACE_LCL pLcl )
|
|
{
|
|
HRESULT hr = D3D_OK;
|
|
RDSurfaceFormat SurfFormat;
|
|
DDSCAPS2 ddscaps;
|
|
LPDDRAWI_DDRAWSURFACE_GBL pGbl = pLcl->lpGbl;
|
|
LPDDRAWI_DDRAWSURFACE_MORE pMore = pLcl->lpSurfMore;
|
|
memset(&ddscaps, 0, sizeof(ddscaps));
|
|
|
|
UINT wMultiSampleCount = 0xfL & pMore->ddsCapsEx.dwCaps3;
|
|
//Older than DX8 runtimes place a zero in this field
|
|
if (wMultiSampleCount == 0)
|
|
wMultiSampleCount = 1;
|
|
|
|
if( pLcl->ddsCaps.dwCaps & DDSCAPS_TEXTURE )
|
|
m_SurfType |= RR_ST_TEXTURE;
|
|
|
|
if( pLcl->ddsCaps.dwCaps & DDSCAPS_ZBUFFER )
|
|
{
|
|
m_iSamples = wMultiSampleCount;
|
|
m_SurfType |= RR_ST_RENDERTARGETDEPTH;
|
|
}
|
|
|
|
if( pLcl->ddsCaps.dwCaps & DDSCAPS_3DDEVICE )
|
|
{
|
|
m_iSamples = wMultiSampleCount;
|
|
m_SurfType |= RR_ST_RENDERTARGETCOLOR;
|
|
}
|
|
|
|
m_iWidth = DDSurf_Width(pLcl);
|
|
m_iHeight = DDSurf_Height(pLcl);
|
|
HR_RET(FindOutSurfFormat(&(DDSurf_PixFmt(pLcl)), &SurfFormat, NULL));
|
|
m_SurfFormat = SurfFormat;
|
|
|
|
if (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
|
|
{
|
|
// low word of ddsCaps.ddsCapsEx.dwCaps4 has depth
|
|
// (volume texture only).
|
|
m_iDepth = LOWORD(pMore->ddsCapsEx.dwCaps4);
|
|
}
|
|
else
|
|
{
|
|
m_iDepth = 0;
|
|
}
|
|
m_cTexels[0][0] = m_iWidth;
|
|
m_cTexels[0][1] = m_iHeight;
|
|
m_cTexels[0][2] = m_iDepth;
|
|
m_fTexels[0][0] = (float)m_cTexels[0][0];
|
|
m_fTexels[0][1] = (float)m_cTexels[0][1];
|
|
m_fTexels[0][2] = (float)m_cTexels[0][2];
|
|
|
|
m_cLOD = 0;
|
|
|
|
if( wMultiSampleCount > 1 )
|
|
{
|
|
RDCREATESURFPRIVATE* pPriv = (RDCREATESURFPRIVATE*)pGbl->dwReserved1;
|
|
m_pBits[0] = pPriv->pMultiSampleBits;
|
|
m_iPitch[0] = pPriv->dwMultiSamplePitch;
|
|
}
|
|
else
|
|
{
|
|
m_pBits[0] = (BYTE *)SURFACE_MEMORY(pLcl);
|
|
m_iPitch[0] = ComputePitch( pLcl );
|
|
}
|
|
|
|
if (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
|
|
{
|
|
// set slice pitch (volume texture only).
|
|
m_iSlicePitch[0] = pGbl->lSlicePitch;
|
|
}
|
|
else
|
|
{
|
|
m_iSlicePitch[0] = 0;
|
|
}
|
|
|
|
// If the surface is not a texture early out.
|
|
if( (pLcl->ddsCaps.dwCaps & DDSCAPS_TEXTURE) == 0 )
|
|
{
|
|
SetInitialized();
|
|
return S_OK;
|
|
}
|
|
|
|
// Set the transparent bit and the transparent color with pDDS[0]
|
|
if ((pLcl->dwFlags & DDRAWISURF_HASCKEYSRCBLT) != 0)
|
|
{
|
|
m_uFlags |= RR_TEXTURE_HAS_CK;
|
|
m_dwColorKey = pLcl->ddckCKSrcBlt.dwColorSpaceLowValue;
|
|
}
|
|
else
|
|
{
|
|
m_uFlags &= ~RR_TEXTURE_HAS_CK;
|
|
}
|
|
|
|
// set the empty face color with pDDS[0]
|
|
// note that ddckCKDestOverlay is unioned with dwEmptyFaceColor,
|
|
// but not in the internal structure
|
|
m_dwEmptyFaceColor = pLcl->ddckCKDestOverlay.dwColorSpaceLowValue;
|
|
|
|
if (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
|
|
{
|
|
m_uFlags |= RR_TEXTURE_VOLUME;
|
|
m_cDimension = 3;
|
|
}
|
|
else
|
|
{
|
|
m_cDimension = 2;
|
|
}
|
|
|
|
// Compute sizes and pitches
|
|
|
|
// We need to gather info on all surfaces under the top-level
|
|
// mipmap face (This test is DX7+ runtime dependent)
|
|
if ((0 == (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)) &&
|
|
(pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) )
|
|
{
|
|
m_uFlags |= RR_TEXTURE_CUBEMAP;
|
|
|
|
LPDDRAWI_DDRAWSURFACE_LCL pDDSNextLcl;
|
|
ddscaps.dwCaps = DDSCAPS_TEXTURE;
|
|
|
|
m_pDDSLcl[0] = pLcl;
|
|
m_pBits[0] = (BYTE *)SURFACE_MEMORY(m_pDDSLcl[0]);
|
|
m_iPitch[0] = ComputePitch( m_pDDSLcl[0] );
|
|
m_iSlicePitch[0] = 0;
|
|
|
|
// get rest of top level surfaces, in order
|
|
for (INT i = 1; i < 6; i++)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 1: ddscaps.dwCaps2 = DDSCAPS2_CUBEMAP_NEGATIVEX; break;
|
|
case 2: ddscaps.dwCaps2 = DDSCAPS2_CUBEMAP_POSITIVEY; break;
|
|
case 3: ddscaps.dwCaps2 = DDSCAPS2_CUBEMAP_NEGATIVEY; break;
|
|
case 4: ddscaps.dwCaps2 = DDSCAPS2_CUBEMAP_POSITIVEZ; break;
|
|
case 5: ddscaps.dwCaps2 = DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
|
|
}
|
|
ddscaps.dwCaps2 |= DDSCAPS2_CUBEMAP;
|
|
pDDSNextLcl = NULL;
|
|
hr = DDGetAttachedSurfaceLcl( pLcl, &ddscaps, &pDDSNextLcl);
|
|
if ((hr != D3D_OK) && (hr != DDERR_NOTFOUND))
|
|
{
|
|
return hr;
|
|
}
|
|
if (hr == DDERR_NOTFOUND)
|
|
{
|
|
m_pDDSLcl[i] = NULL;
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
m_pDDSLcl[i] = pDDSNextLcl;
|
|
}
|
|
|
|
m_pBits[i] = (BYTE *)SURFACE_MEMORY(m_pDDSLcl[i]);
|
|
m_iPitch[i] = ComputePitch( m_pDDSLcl[i] );
|
|
m_iSlicePitch[i] = 0;
|
|
|
|
m_cTexels[i][0] = DDSurf_Width(m_pDDSLcl[i]);
|
|
m_cTexels[i][1] = DDSurf_Height(m_pDDSLcl[i]);
|
|
m_fTexels[i][0] = (float)m_cTexels[i][0];
|
|
m_fTexels[i][1] = (float)m_cTexels[i][1];
|
|
}
|
|
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
pLcl = m_pDDSLcl[i];
|
|
m_cLOD = 0;
|
|
|
|
if (pLcl)
|
|
{
|
|
// Check for mipmap if any.
|
|
LPDDRAWI_DDRAWSURFACE_LCL pTmpSLcl;
|
|
|
|
// 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 = (INT16)m_iWidth;
|
|
INT16 iPreSizeV = (INT16)m_iHeight;
|
|
for (;;)
|
|
{
|
|
ddscaps.dwCaps = DDSCAPS_TEXTURE;
|
|
ddscaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
|
|
pTmpSLcl = NULL;
|
|
hr = DDGetAttachedSurfaceLcl( pLcl, &ddscaps, &pTmpSLcl);
|
|
if (hr != D3D_OK && hr != DDERR_NOTFOUND)
|
|
{
|
|
return hr;
|
|
}
|
|
if (hr == DDERR_NOTFOUND)
|
|
{
|
|
break;
|
|
}
|
|
pLcl = pTmpSLcl;
|
|
pGbl = pLcl->lpGbl;
|
|
pMore = pLcl->lpSurfMore;
|
|
m_cLOD ++;
|
|
INT iMap = m_cLOD*6+i;
|
|
m_pDDSLcl[iMap] = pLcl;
|
|
m_pBits[iMap] = (BYTE *)SURFACE_MEMORY(pLcl);
|
|
m_iPitch[iMap] = ComputePitch( pLcl, m_SurfFormat,
|
|
m_iWidth>>m_cLOD,
|
|
m_iHeight>>m_cLOD );
|
|
if (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
|
|
{
|
|
// set slice pitch
|
|
// (volume texture only).
|
|
m_iSlicePitch[iMap] = pGbl->lSlicePitch;
|
|
}
|
|
else
|
|
{
|
|
m_iSlicePitch[iMap] = 0;
|
|
}
|
|
m_cTexels[iMap][0] = DDSurf_Width(pLcl);
|
|
m_cTexels[iMap][1] = DDSurf_Height(pLcl);
|
|
m_fTexels[iMap][0] = (float)m_cTexels[iMap][0];
|
|
m_fTexels[iMap][1] = (float)m_cTexels[iMap][1];
|
|
|
|
// Check for invalid mipmap texture size
|
|
if (!ValidMipmapSize(iPreSizeU,
|
|
(INT16)DDSurf_Width(pLcl)) ||
|
|
!ValidMipmapSize(iPreSizeV,
|
|
(INT16)DDSurf_Height(pLcl)))
|
|
{
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
iPreSizeU = (INT16)DDSurf_Width(pLcl);
|
|
iPreSizeV = (INT16)DDSurf_Height(pLcl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((0 == (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL) &&
|
|
(0 == (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_CUBEMAP))) )
|
|
|
|
{
|
|
//This surface is not a top-level cubemap.
|
|
//Maybe it's a top-level mipmap. Go find its sublevels.
|
|
|
|
m_pDDSLcl[0] = pLcl;
|
|
// Check for mipmap if any.
|
|
LPDDRAWI_DDRAWSURFACE_LCL pTmpSLcl;
|
|
// 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 = (INT16)m_iWidth;
|
|
INT16 iPreSizeV = (INT16)m_iHeight;
|
|
for (;;)
|
|
{
|
|
ddscaps.dwCaps = DDSCAPS_TEXTURE;
|
|
ddscaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
|
|
pTmpSLcl = NULL;
|
|
hr = DDGetAttachedSurfaceLcl( pLcl, &ddscaps, &pTmpSLcl);
|
|
if (hr != D3D_OK && hr != DDERR_NOTFOUND)
|
|
{
|
|
return hr;
|
|
}
|
|
if (hr == DDERR_NOTFOUND)
|
|
{
|
|
break;
|
|
}
|
|
pLcl = pTmpSLcl;
|
|
pGbl = pLcl->lpGbl;
|
|
pMore = pLcl->lpSurfMore;
|
|
m_cLOD ++;
|
|
m_pDDSLcl[m_cLOD] = pLcl;
|
|
|
|
// Save the pointer to the real bits and the pitch.
|
|
m_pBits[m_cLOD] = (BYTE *)SURFACE_MEMORY(pLcl);
|
|
m_iPitch[m_cLOD] = ComputePitch( pLcl, m_SurfFormat,
|
|
m_iWidth>>m_cLOD,
|
|
m_iHeight>>m_cLOD );
|
|
if (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
|
|
{
|
|
// set slice pitch (volume texture only).
|
|
m_iSlicePitch[m_cLOD] = pGbl->lSlicePitch;
|
|
}
|
|
else
|
|
{
|
|
m_iSlicePitch[m_cLOD] = 0;
|
|
}
|
|
|
|
// Check for invalid mipmap texture size
|
|
if (!ValidMipmapSize(iPreSizeU, (INT16)DDSurf_Width(pLcl)) ||
|
|
!ValidMipmapSize(iPreSizeV, (INT16)DDSurf_Height(pLcl)))
|
|
{
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
iPreSizeU = (INT16)DDSurf_Width(pLcl);
|
|
iPreSizeV = (INT16)DDSurf_Height(pLcl);
|
|
|
|
m_cTexels[m_cLOD][0] = DDSurf_Width(pLcl);
|
|
m_cTexels[m_cLOD][1] = DDSurf_Height(pLcl);
|
|
if (pMore->ddsCapsEx.dwCaps2 & DDSCAPS2_VOLUME)
|
|
m_cTexels[m_cLOD][2] = LOWORD(pMore->ddsCapsEx.dwCaps4);
|
|
else
|
|
m_cTexels[m_cLOD][2] = 0;
|
|
m_fTexels[m_cLOD][0] = (float)m_cTexels[m_cLOD][0];
|
|
m_fTexels[m_cLOD][1] = (float)m_cTexels[m_cLOD][1];
|
|
m_fTexels[m_cLOD][2] = (float)m_cTexels[m_cLOD][2];
|
|
}
|
|
}
|
|
|
|
// Copy the palette
|
|
// UpdatePalette();
|
|
|
|
m_cLODDDS = m_cLOD;
|
|
|
|
if ( !(Validate()) )
|
|
{
|
|
return DDERR_GENERIC;
|
|
}
|
|
|
|
SetInitialized();
|
|
return D3D_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// UpdatePalette
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void
|
|
RDSurface2D::UpdatePalette()
|
|
{
|
|
// Update palette
|
|
if (m_SurfFormat == RD_SF_PALETTE8 || m_SurfFormat == RD_SF_PALETTE4 || m_SurfFormat == RD_SF_P8A8 )
|
|
{
|
|
#if 0
|
|
// This code needs to be revived in case the DX6 DDI
|
|
// emulation is ever implemented in RefDev.
|
|
if (m_pDDSLcl[0]->lpDDPalette)
|
|
{
|
|
LPDDRAWI_DDRAWPALETTE_GBL pPal =
|
|
m_pDDSLcl[0]->lpDDPalette->lpLcl->lpGbl;
|
|
m_pPalette = (DWORD*)pPal->lpColorTable;
|
|
if (pPal->dwFlags & DDRAWIPAL_ALPHA)
|
|
{
|
|
m_uFlags |= RR_TEXTURE_ALPHAINPALETTE;
|
|
}
|
|
else
|
|
{
|
|
m_uFlags &= ~RR_TEXTURE_ALPHAINPALETTE;
|
|
}
|
|
}
|
|
#endif
|
|
_ASSERT( m_pPalObj, "No Palette set for this paletted texture\n" );
|
|
m_pPalette = m_pPalObj->GetEntries();
|
|
if( m_SurfFormat == RD_SF_PALETTE8 || m_SurfFormat == RD_SF_PALETTE4 )
|
|
{
|
|
if( m_pPalObj->HasAlpha() )
|
|
{
|
|
m_uFlags |= RR_TEXTURE_ALPHAINPALETTE;
|
|
}
|
|
else
|
|
{
|
|
m_uFlags &= ~RR_TEXTURE_ALPHAINPALETTE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Validate - Updates private data. Must be called anytime public data is
|
|
// altered.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
RDSurface2D::Validate( void )
|
|
{
|
|
// validate inputs
|
|
if ( m_cLOD >= RD_MAX_CLOD ) // too many LODs
|
|
{
|
|
DPFRR(1,"RDSurface2D::Validate failed. Too many LODs");
|
|
return FALSE;
|
|
}
|
|
|
|
// compute the 'has alpha' flag
|
|
m_bHasAlpha = FALSE;
|
|
switch ( m_SurfFormat )
|
|
{
|
|
case RD_SF_A8:
|
|
case RD_SF_P8A8:
|
|
case RD_SF_B8G8R8A8:
|
|
case RD_SF_B5G5R5A1:
|
|
case RD_SF_B4G4R4A4:
|
|
case RD_SF_L8A8:
|
|
case RD_SF_L4A4:
|
|
case RD_SF_B2G3R3A8:
|
|
case RD_SF_DXT1:
|
|
case RD_SF_DXT2:
|
|
case RD_SF_DXT3:
|
|
case RD_SF_DXT4:
|
|
case RD_SF_DXT5:
|
|
m_bHasAlpha = TRUE;
|
|
break;
|
|
case RD_SF_PALETTE4:
|
|
case RD_SF_PALETTE8:
|
|
m_bHasAlpha = ( m_uFlags & RR_TEXTURE_ALPHAINPALETTE ) ? TRUE : FALSE;
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
inline UINT8 CLAMP_BYTE(double f)
|
|
{
|
|
if (f > 255.0) return 255;
|
|
if (f < 0.0) return 0;
|
|
return (BYTE) f;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// TexelFromBlock - decompress a color block and obtain texel color
|
|
//-----------------------------------------------------------------------------
|
|
UINT32 TexelFromBlock(RDSurfaceFormat surfType, char *pblockSrc,
|
|
int x, int y)
|
|
{
|
|
UINT32 index = ((y & 0x3)<<2) + (x & 0x3);
|
|
DDRGBA colorDst[DXT_BLOCK_PIXELS];
|
|
|
|
switch(surfType)
|
|
{
|
|
case RD_SF_DXT1:
|
|
DecodeBlockRGB((DXTBlockRGB *)pblockSrc, (DXT_COLOR *)colorDst);
|
|
break;
|
|
case RD_SF_DXT2:
|
|
case RD_SF_DXT3:
|
|
DecodeBlockAlpha4((DXTBlockAlpha4 *)pblockSrc,
|
|
(DXT_COLOR *)colorDst);
|
|
break;
|
|
case RD_SF_DXT4:
|
|
case RD_SF_DXT5:
|
|
DecodeBlockAlpha3((DXTBlockAlpha3 *)pblockSrc,
|
|
(DXT_COLOR *)colorDst);
|
|
break;
|
|
}
|
|
|
|
return RGBA_MAKE(colorDst[index].red,
|
|
colorDst[index].green,
|
|
colorDst[index].blue,
|
|
colorDst[index].alpha);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// ReadTexelColor - Reads texel from texture map at given LOD; converts to
|
|
// RDColor format, applying palette if necessary; also performs colorkey by
|
|
// returning match information
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RDSurface2D::ReadColor(
|
|
INT32 iX, INT32 iY, INT32 iZ, INT32 iLOD,
|
|
RDColor& Texel, BOOL &bColorKeyKill )
|
|
{
|
|
if ( (iLOD > m_cLOD) && !(m_uFlags & RR_TEXTURE_CUBEMAP) )
|
|
{
|
|
return;
|
|
}
|
|
if ( NULL == m_pBits[iLOD] ) { return; }
|
|
|
|
char* pSurfaceBits =
|
|
PixelAddress( iX, iY, iZ, m_pBits[iLOD],
|
|
m_iPitch[iLOD], m_iSlicePitch[iLOD], m_SurfFormat );
|
|
|
|
switch ( m_SurfFormat )
|
|
{
|
|
default:
|
|
Texel.ConvertFrom( m_SurfFormat, pSurfaceBits );
|
|
break;
|
|
|
|
case RD_SF_P8A8:
|
|
{
|
|
UINT8 uIndex = *((UINT8*)pSurfaceBits);
|
|
Texel.ConvertFrom( RD_SF_B8G8R8A8, (char*)((UINT32*)m_pPalette + uIndex) );
|
|
Texel.A = *((UINT8*)pSurfaceBits+1)/255.f;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_PALETTE8:
|
|
{
|
|
UINT8 uIndex = *((UINT8*)pSurfaceBits);
|
|
Texel.ConvertFrom( RD_SF_B8G8R8A8, (char*)((UINT32*)m_pPalette + uIndex) );
|
|
if ( !( m_uFlags & RR_TEXTURE_ALPHAINPALETTE ) ) Texel.A = 1.f;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_PALETTE4:
|
|
{
|
|
UINT8 uIndex = *((INT8*)pSurfaceBits);
|
|
if ((iX & 1) == 0) { uIndex &= 0xf; }
|
|
else { uIndex >>= 4; }
|
|
Texel.ConvertFrom( RD_SF_B8G8R8A8, (char*)((UINT32*)m_pPalette + uIndex) );
|
|
if ( !( m_uFlags & RR_TEXTURE_ALPHAINPALETTE ) ) Texel.A = 1.f;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_UYVY:
|
|
case RD_SF_YUY2:
|
|
// Converts a given YUV (8bits each) to RGB scaled between 0 and 255
|
|
// These are using the YCrCb to RGB algorithms given on page 30
|
|
// in "VIDEO DEMYSTIFIED" by Keith Jack
|
|
// ISBN#: 1-878707-09-4
|
|
// IN PC graphics, even though they call it YUV, it is really YCrCb
|
|
// formats that are used by most framegrabbers etc. Hence the pixel
|
|
// data we will obtain in these YUV surfaces will most likely be this
|
|
// and not the original YUV which is actually used in PAL broadcast
|
|
// only (NTSC uses YIQ). So really, U should be called Cb (Blue color
|
|
// difference) and V should be called Cr (Red color difference)
|
|
//
|
|
// These equations are meant to handle the following ranges
|
|
// (from the same book):
|
|
// Y (16 to 235), U and V (16 to 240, 128 = zero)
|
|
// -----------
|
|
// Y U V
|
|
// -----------
|
|
// White : 180 128 128
|
|
// Black : 16 128 128
|
|
// Red : 65 100 212
|
|
// Green : 112 72 58
|
|
// Blue : 35 212 114
|
|
// Yellow : 162 44 142
|
|
// Cyan : 131 156 44
|
|
// Magenta: 84 184 198
|
|
// -----------
|
|
// It is assumed that the gamma corrected RGB range is (0 - 255)
|
|
//
|
|
// UYVY: U0Y0 V0Y1 U2Y2 V2Y3 (low byte always has current Y)
|
|
// If iX is even, hight-byte has current U (Cb)
|
|
// If iX is odd, hight-byte has previous V (Cr)
|
|
//
|
|
// YUY2: Y0U0 Y1V0 Y2U2 Y3V2 (high byte always has current Y)
|
|
// (UYVY bytes flipped)
|
|
//
|
|
// In this algorithm, we use U and V values from two neighboring
|
|
// pixels
|
|
{
|
|
UINT8 Y, U, V;
|
|
UINT16 u16Curr = *((UINT16*)pSurfaceBits);
|
|
UINT16 u16ForU = 0; // Extract U from this
|
|
UINT16 u16ForV = 0; // Extract V from this
|
|
|
|
// By default we assume YUY2. Change it later if it is UYVY
|
|
int uvShift = 8;
|
|
int yShift = 0;
|
|
|
|
if (m_SurfFormat == RD_SF_UYVY)
|
|
{
|
|
uvShift = 0;
|
|
yShift = 8;
|
|
}
|
|
|
|
if ((iX & 1) == 0)
|
|
{
|
|
// For even numbered pixels:
|
|
// Current U is available.
|
|
// Current V is available in the next pixel.
|
|
u16ForU = u16Curr;
|
|
|
|
// Obtain V from the next pixel
|
|
u16ForV = *((UINT16*)PixelAddress( iX+1, iY, iZ,
|
|
m_pBits[iLOD],
|
|
m_iPitch[iLOD],
|
|
m_iSlicePitch[iLOD],
|
|
m_SurfFormat ));
|
|
|
|
U = (u16ForU >> uvShift) & 0xff;
|
|
V = (u16ForV >> uvShift) & 0xff;
|
|
}
|
|
else
|
|
{
|
|
UINT16 u16ForU1 = 0, u16ForU2 = 0;
|
|
UINT16 u16ForV1 = 0, u16ForV2 = 0;
|
|
|
|
// For odd numbered pixels. Neither current U nor V are
|
|
// available.
|
|
|
|
// Obtain U by interpolating U from i-1 and i+1 pixels.
|
|
_ASSERT( iX > 0, "iX is negative" );
|
|
u16ForU1 = *((UINT16*)PixelAddress( iX-1, iY, iZ,
|
|
m_pBits[iLOD],
|
|
m_iPitch[iLOD],
|
|
m_iSlicePitch[iLOD],
|
|
m_SurfFormat ));
|
|
|
|
if( (iX+1) < (m_iWidth >> iLOD) )
|
|
{
|
|
u16ForU2 = *((UINT16*)PixelAddress( iX+1, iY, iZ,
|
|
m_pBits[iLOD],
|
|
m_iPitch[iLOD],
|
|
m_iSlicePitch[iLOD],
|
|
m_SurfFormat ));
|
|
U = (((u16ForU1 >> uvShift) & 0xff) +
|
|
((u16ForU2 >> uvShift) & 0xff)) >> 1;
|
|
|
|
}
|
|
else
|
|
{
|
|
U = (u16ForU1 >> uvShift) & 0xff;
|
|
}
|
|
|
|
// Obtain V by interpolating V from i and i+2 pixels.
|
|
u16ForV1 = u16Curr;
|
|
if( (iX+2) < (m_iWidth >> iLOD) )
|
|
{
|
|
u16ForV2 = *((UINT16*)PixelAddress( iX+2, iY, iZ,
|
|
m_pBits[iLOD],
|
|
m_iPitch[iLOD],
|
|
m_iSlicePitch[iLOD],
|
|
m_SurfFormat ));
|
|
V = (((u16ForV1 >> uvShift) & 0xff) +
|
|
((u16ForV2 >> uvShift) & 0xff)) >> 1;
|
|
|
|
}
|
|
else
|
|
{
|
|
V = (u16ForV1 >> uvShift) & 0xff;
|
|
}
|
|
|
|
}
|
|
|
|
Y = (u16Curr >> yShift) & 0xff;
|
|
|
|
Texel = RGB_MAKE(
|
|
CLAMP_BYTE(1.164*(Y-16) + 1.596*(V-128)),
|
|
CLAMP_BYTE(1.164*(Y-16) - 0.813*(V-128) - 0.391*(U-128)),
|
|
CLAMP_BYTE(1.164*(Y-16) + 2.018*(U-128))
|
|
);
|
|
Texel.A = 1.f;
|
|
}
|
|
break;
|
|
|
|
// DXTn compressed formats:
|
|
// We have the address to the block, now extract the actual color
|
|
case RD_SF_DXT1:
|
|
case RD_SF_DXT2:
|
|
case RD_SF_DXT3:
|
|
case RD_SF_DXT4:
|
|
case RD_SF_DXT5:
|
|
Texel = TexelFromBlock(m_SurfFormat, pSurfaceBits, iX, iY);
|
|
break;
|
|
}
|
|
|
|
// colorkey
|
|
if ( m_pRefDev->ColorKeyEnabled() )
|
|
{
|
|
DWORD dwBits;
|
|
switch ( m_SurfFormat )
|
|
{
|
|
default:
|
|
case RD_SF_NULL:
|
|
return; // don't colorkey unknown or null surfaces
|
|
|
|
case RD_SF_PALETTE4:
|
|
{
|
|
UINT8 uIndex = *((INT8*)pSurfaceBits);
|
|
if ((iX & 1) == 0) { uIndex &= 0xf; }
|
|
else { uIndex >>= 4; }
|
|
dwBits = (DWORD)uIndex;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_L8:
|
|
case RD_SF_A8:
|
|
case RD_SF_PALETTE8:
|
|
case RD_SF_B2G3R3:
|
|
case RD_SF_L4A4:
|
|
{
|
|
UINT8 uBits = *((UINT8*)pSurfaceBits);
|
|
dwBits = (DWORD)uBits;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_B5G6R5:
|
|
case RD_SF_B5G5R5X1:
|
|
case RD_SF_B5G5R5A1:
|
|
case RD_SF_B4G4R4A4:
|
|
case RD_SF_B4G4R4X4:
|
|
case RD_SF_L8A8:
|
|
case RD_SF_P8A8:
|
|
case RD_SF_B2G3R3A8:
|
|
{
|
|
UINT16 uBits = *((UINT16*)pSurfaceBits);
|
|
dwBits = (DWORD)uBits;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_B8G8R8:
|
|
{
|
|
UINT32 uBits = 0;
|
|
uBits |= ( *((UINT8*)pSurfaceBits+0) ) << 0;
|
|
uBits |= ( *((UINT8*)pSurfaceBits+1) ) << 8;
|
|
uBits |= ( *((UINT8*)pSurfaceBits+2) ) << 16;
|
|
dwBits = (DWORD)uBits;
|
|
}
|
|
break;
|
|
|
|
case RD_SF_B8G8R8A8:
|
|
case RD_SF_B8G8R8X8:
|
|
{
|
|
UINT32 uBits = *((UINT32*)pSurfaceBits);
|
|
dwBits = (DWORD)uBits;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DWORD ColorKey = m_dwColorKey;
|
|
if ( dwBits == ColorKey )
|
|
{
|
|
if (m_pRefDev->GetRS()[D3DRENDERSTATE_COLORKEYENABLE])
|
|
{
|
|
bColorKeyKill = TRUE;
|
|
}
|
|
if (m_pRefDev->GetRS()[D3DRENDERSTATE_COLORKEYBLENDENABLE])
|
|
{
|
|
Texel.R = 0.F;
|
|
Texel.G = 0.F;
|
|
Texel.B = 0.F;
|
|
Texel.A = 0.F;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// end
|