9bd1ba7c47
which included commits to RCS files with non-trunk default branches.
534 lines
10 KiB
C++
534 lines
10 KiB
C++
#include "pch.h"
|
|
#include "texture.h"
|
|
|
|
#include "d3dframe.h"
|
|
extern CD3DFramework* g_pFramework;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CTexture::s_bLocked = FALSE;
|
|
DDSURFACEDESC2 CTexture::s_ddsd;
|
|
|
|
|
|
HRESULT CTexture::Initialize (BYTE *rgbSource, ULONG ulWidth, ULONG ulHeight, ULONG ulPitch)
|
|
{
|
|
m_rgbSource = rgbSource;
|
|
m_ulWidthSource = ulWidth;
|
|
m_ulHeightSource = ulHeight;
|
|
m_ulPitchSource = ulPitch;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CTexture::Allocate (CPaletteInfo *ppi)
|
|
{
|
|
HRESULT hr;
|
|
|
|
ASSERT (m_spddsMemory == NULL);
|
|
|
|
if (ppi->IsPow2 ())
|
|
{
|
|
m_ulWidth = 1;
|
|
while (m_ulWidth < m_ulWidthSource)
|
|
m_ulWidth *= 2;
|
|
|
|
m_ulHeight = 1;
|
|
while (m_ulHeight < m_ulHeightSource)
|
|
m_ulHeight *= 2;
|
|
}
|
|
else
|
|
{
|
|
m_ulWidth = m_ulWidthSource;
|
|
m_ulHeight = m_ulHeightSource;
|
|
}
|
|
|
|
if (ppi->IsSquare ())
|
|
{
|
|
if (m_ulHeight > m_ulWidth)
|
|
{
|
|
m_ulWidth = m_ulHeight;
|
|
}
|
|
else
|
|
{
|
|
m_ulHeight = m_ulWidth;
|
|
}
|
|
}
|
|
|
|
m_flAdjX = (D3DVALUE) m_ulWidthSource / (D3DVALUE) m_ulWidth;
|
|
m_flAdjY = (D3DVALUE) m_ulHeightSource / (D3DVALUE) m_ulHeight;
|
|
|
|
DDSURFACEDESC2 ddsd;
|
|
ZeroMemory (&ddsd, sizeof (ddsd));
|
|
ddsd.dwSize = sizeof (ddsd);
|
|
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
|
|
ddsd.dwWidth = m_ulWidth;
|
|
ddsd.dwHeight = m_ulHeight;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
|
|
ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
|
|
ppi->GetPixelFormat (&ddsd.ddpfPixelFormat);
|
|
|
|
hr = g_pFramework->GetDirectDraw ()->CreateSurface(&ddsd, &m_spddsMemory, NULL);
|
|
ASSERT (SUCCEEDED (hr));
|
|
if (FAILED (hr))
|
|
return hr;
|
|
|
|
ASSERT (m_spddsMemory != NULL);
|
|
|
|
m_spddtMemory = m_spddsMemory;
|
|
|
|
DirtyMemory ();
|
|
|
|
DDCOLORKEY ddck;
|
|
if (ppi->IsIndexed ())
|
|
{
|
|
ddck.dwColorSpaceLowValue = 255;
|
|
ddck.dwColorSpaceHighValue = 255;
|
|
}
|
|
else
|
|
{
|
|
ddck.dwColorSpaceLowValue = 0;
|
|
ddck.dwColorSpaceHighValue = 0;
|
|
}
|
|
hr = m_spddsMemory->SetColorKey (DDCKEY_SRCBLT, &ddck);
|
|
ASSERT (SUCCEEDED (hr));
|
|
|
|
if (ppi->GetPalette () != NULL)
|
|
{
|
|
hr = m_spddsMemory->SetPalette (ppi->GetPalette ());
|
|
ASSERT (SUCCEEDED (hr));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTexture::Free (void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
m_spddtMemory = m_spddsMemory = NULL;
|
|
|
|
m_ulWidth = 0;
|
|
m_ulHeight = 0;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTexture::Lock (void)
|
|
{
|
|
HRESULT hr;
|
|
if (!s_bLocked)
|
|
{
|
|
s_bLocked = TRUE;
|
|
|
|
s_ddsd.dwSize = sizeof (s_ddsd);
|
|
hr = m_spddsMemory->Lock (
|
|
NULL,
|
|
&s_ddsd,
|
|
#ifndef NDEBUG
|
|
DDLOCK_NOSYSLOCK |
|
|
#endif
|
|
DDLOCK_WAIT,
|
|
NULL);
|
|
ASSERT (SUCCEEDED (hr));
|
|
}
|
|
else
|
|
{
|
|
// already locked
|
|
hr = E_FAIL;
|
|
ASSERT (FALSE);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTexture::Unlock (void)
|
|
{
|
|
HRESULT hr;
|
|
if (s_bLocked)
|
|
{
|
|
hr = m_spddsMemory->Unlock (NULL);
|
|
ASSERT (SUCCEEDED (hr));
|
|
|
|
s_bLocked = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// not locked
|
|
hr = E_FAIL;
|
|
ASSERT (FALSE);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
void CTexture::PlotPixel (ULONG ulX, ULONG ulY, BYTE b)
|
|
{
|
|
ASSERT (ulX <= m_ulWidth);
|
|
ASSERT (ulY <= m_ulHeight);
|
|
|
|
ASSERT (s_bLocked);
|
|
ASSERT (s_ddsd.lpSurface != NULL);
|
|
|
|
switch (s_ddsd.ddpfPixelFormat.dwRGBBitCount)
|
|
{
|
|
case 8:
|
|
{
|
|
* (((LPBYTE) s_ddsd.lpSurface) + ulX + ulY * s_ddsd.lPitch) = b;
|
|
|
|
break;
|
|
}
|
|
case 16:
|
|
{
|
|
WORD w;
|
|
if (!(m_bTransparent && b == 255))
|
|
{
|
|
w = m_ppi->Read16 (b);
|
|
}
|
|
else
|
|
{
|
|
w = 0;
|
|
}
|
|
* (WORD *) (((LPBYTE) s_ddsd.lpSurface) + ulX * 2 + ulY * s_ddsd.lPitch) = w;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CTexture::SetBitmapData (BYTE *rgb, BOOL bRle)
|
|
{
|
|
m_rgbSource = rgb;
|
|
m_bRle = bRle;
|
|
DirtyMemory ();
|
|
}
|
|
|
|
void CTexture::CopyFromSource (void)
|
|
{
|
|
if (SUCCEEDED (Lock ()))
|
|
{
|
|
if (m_bRle)
|
|
{
|
|
PBYTE pbLine = m_rgbSource + m_ulHeightSource + 4;;
|
|
for (ULONG y = 0; y < m_ulHeightSource; y ++)
|
|
{
|
|
ULONG x = 0;
|
|
PBYTE pbSrc = pbLine;
|
|
|
|
while (1)
|
|
{
|
|
const BYTE RLE_CODE = 0xE0;
|
|
BYTE b = *pbSrc++;
|
|
if ((b & RLE_CODE) != RLE_CODE)
|
|
{
|
|
PlotPixel (x++, y, b);
|
|
}
|
|
else
|
|
{
|
|
BYTE cb = b & (~RLE_CODE);
|
|
if (cb == 0)
|
|
break;
|
|
|
|
b = *pbSrc++;
|
|
while (cb--)
|
|
PlotPixel (x++, y, b);
|
|
}
|
|
}
|
|
ASSERT (x <= m_ulWidthSource);
|
|
|
|
pbLine += m_rgbSource [y + 4];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPBYTE lpbDest = (LPBYTE) s_ddsd.lpSurface;
|
|
LPBYTE lpbSrc = m_rgbSource;
|
|
|
|
switch (s_ddsd.ddpfPixelFormat.dwRGBBitCount)
|
|
{
|
|
case 8:
|
|
{
|
|
for (ULONG y = m_ulHeightSource; y != 0; y--)
|
|
{
|
|
memcpy (lpbDest, lpbSrc, m_ulPitchSource);
|
|
lpbDest += s_ddsd.lPitch;
|
|
lpbSrc += m_ulPitchSource;
|
|
}
|
|
break;
|
|
}
|
|
case 16:
|
|
{
|
|
for (ULONG y = m_ulHeightSource; y != 0; y--)
|
|
{
|
|
LPBYTE lpbLineSrc = lpbSrc;
|
|
LPWORD lpwLineDest = (LPWORD) lpbDest;
|
|
|
|
if (m_bTransparent)
|
|
{
|
|
for (ULONG x = m_ulWidthSource; x != 0; x--)
|
|
{
|
|
BYTE b = *lpbLineSrc++;
|
|
*lpwLineDest++ = (b == 255) ? 0 : m_ppi->Read16 (b);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (ULONG x = m_ulWidthSource; x != 0; x--)
|
|
{
|
|
*lpwLineDest++ = m_ppi->Read16 (*lpbLineSrc++);
|
|
}
|
|
}
|
|
lpbDest += s_ddsd.lPitch;
|
|
lpbSrc += m_ulPitchSource;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ASSERT (FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Unlock ();
|
|
}
|
|
else
|
|
{
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
HRESULT CTexture::CleanMemory (void)
|
|
{
|
|
CopyFromSource ();
|
|
m_bDirtyMemory = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
IDirect3DTexture2 *CTexture::GetTexture ()
|
|
{
|
|
if (m_bDirtyMemory)
|
|
{
|
|
CleanMemory ();
|
|
}
|
|
|
|
return m_spddtMemory;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct FindTextureData
|
|
{
|
|
DWORD bpp; // we want a texture format of this bpp
|
|
DDPIXELFORMAT ddpf; // place the format here
|
|
};
|
|
|
|
|
|
HRESULT CALLBACK FindTextureCallback(LPDDPIXELFORMAT pddpf, LPVOID lParam)
|
|
{
|
|
FindTextureData * FindData = (FindTextureData *)lParam;
|
|
|
|
//
|
|
// we use GetDC/BitBlt to init textures so we only
|
|
// want to use formats that GetDC will support.
|
|
//
|
|
if (pddpf->dwFlags & (DDPF_ALPHA|DDPF_ALPHAPIXELS))
|
|
return DDENUMRET_OK;
|
|
|
|
/*
|
|
if (pddpf->dwRGBBitCount == 16)
|
|
{
|
|
FindData->ddpf = ddpf;
|
|
}
|
|
|
|
return DDENUMRET_OK;
|
|
*/
|
|
|
|
|
|
// if (!(pddpf->dwFlags & DDPF_ALPHAPIXELS))
|
|
// return DDENUMRET_OK;
|
|
|
|
if (pddpf->dwRGBBitCount < 8)
|
|
return DDENUMRET_OK;
|
|
|
|
if (pddpf->dwRGBBitCount == 8 && !(pddpf->dwFlags & DDPF_PALETTEINDEXED8))
|
|
return DDENUMRET_OK;
|
|
|
|
if (pddpf->dwRGBBitCount > 8 && !(pddpf->dwFlags & DDPF_RGB))
|
|
return DDENUMRET_OK;
|
|
|
|
//
|
|
// keep the texture format that is nearest to the bitmap we have
|
|
//
|
|
if (FindData->ddpf.dwRGBBitCount == 0 ||
|
|
(pddpf->dwRGBBitCount >= FindData->bpp && pddpf->dwRGBBitCount <= FindData->ddpf.dwRGBBitCount) //&&
|
|
//(pddpf->dwAlphaBitDepth != 0 && pddpf->dwAlphaBitDepth > FindData->ddpf.dwAlphaBitDepth) // ALPHA BIT DEPTHS ARE REVERSED!!!!
|
|
)
|
|
{
|
|
FindData->ddpf = *pddpf;
|
|
}
|
|
|
|
return DDENUMRET_OK;
|
|
}
|
|
|
|
void ChooseTextureFormat(LPDIRECT3DDEVICE3 Device, DWORD bpp, DDPIXELFORMAT *pddpf)
|
|
{
|
|
HRESULT hr;
|
|
FindTextureData FindData;
|
|
ZeroMemory(&FindData, sizeof(FindData));
|
|
FindData.bpp = bpp;
|
|
hr = Device->EnumTextureFormats(FindTextureCallback, (LPVOID)&FindData);
|
|
ASSERT(hr == S_OK);
|
|
*pddpf = FindData.ddpf;
|
|
}
|
|
|
|
HRESULT CPaletteInfo::Initialize ()
|
|
{
|
|
m_spddpPalette = NULL;
|
|
|
|
//
|
|
// find the best texture format to use.
|
|
//
|
|
ChooseTextureFormat (g_pFramework->GetD3DDevice (), 8, &m_ddpfPixelFormat);
|
|
|
|
m_cshftR = GetShift (m_mskR = m_ddpfPixelFormat.dwRBitMask);
|
|
m_cshftG = GetShift (m_mskG = m_ddpfPixelFormat.dwGBitMask);
|
|
m_cshftB = GetShift (m_mskB = m_ddpfPixelFormat.dwBBitMask);
|
|
|
|
HRESULT hr;
|
|
|
|
D3DDEVICEDESC descHAL, descHEL;
|
|
descHAL.dwSize = descHEL.dwSize = sizeof (descHAL);
|
|
hr = g_pFramework->GetD3DDevice ()->GetCaps (&descHAL, &descHEL);
|
|
ASSERT (SUCCEEDED (hr));
|
|
|
|
if (!descHAL.dwFlags) {
|
|
m_bPow2 = (descHEL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) != 0;
|
|
m_bSquare = (descHEL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0;
|
|
} else {
|
|
m_bPow2 = (descHAL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2) != 0;
|
|
m_bSquare = (descHAL.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0;
|
|
}
|
|
|
|
if (IsIndexed ())
|
|
{
|
|
hr = g_pFramework->GetDirectDraw ()->CreatePalette (DDPCAPS_8BIT | DDPCAPS_ALLOW256, m_rgpe, &m_spddpPalette, NULL);
|
|
ASSERT (SUCCEEDED (hr));
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CPaletteInfo::Uninitialize ()
|
|
{
|
|
m_spddpPalette = NULL; // smart pointer release
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CPaletteInfo::SetPaletteEntries (PALETTEENTRY rgpe [256])
|
|
{
|
|
// okay, we don't really need to cache the palette values
|
|
// we could implement ReadPalette by individual Getentries calls...
|
|
memcpy (m_rgpe, rgpe, sizeof (m_rgpe));
|
|
|
|
if (m_spddpPalette != NULL)
|
|
{
|
|
HRESULT hr = m_spddpPalette->SetEntries (0, 0, 256, m_rgpe);
|
|
ASSERT (SUCCEEDED (hr));
|
|
}
|
|
}
|
|
|
|
void CPaletteInfo::GetPaletteEntries (PALETTEENTRY rgpe [256])
|
|
{
|
|
if (m_spddpPalette != NULL)
|
|
{
|
|
HRESULT hr = m_spddpPalette->GetEntries (0, 0, 256, m_rgpe);
|
|
ASSERT (SUCCEEDED (hr));
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
CPaletteInfo *CTexture::m_ppi;
|
|
|
|
HRESULT CTextureSet::Initialize ()
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = m_pi.Initialize ();
|
|
ASSERT (SUCCEEDED (hr));
|
|
|
|
CTexture::m_ppi = &m_pi;
|
|
|
|
for (TEXTURE_SET::iterator iter = m_setTextures.begin ();
|
|
iter != m_setTextures.end ();
|
|
iter ++)
|
|
{
|
|
(*iter)->Allocate (&m_pi);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CTextureSet::Uninitialize ()
|
|
{
|
|
for (TEXTURE_SET::iterator iter = m_setTextures.begin ();
|
|
iter != m_setTextures.end ();
|
|
iter ++)
|
|
{
|
|
(*iter)->Free ();
|
|
}
|
|
|
|
m_pi.Uninitialize ();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
CTexture *CTextureSet::CreateTexture (BYTE *rgbSource, ULONG dx, ULONG dy, ULONG ulPitch)
|
|
{
|
|
CTexture *pTexture = new CTexture;
|
|
|
|
pTexture->Initialize (rgbSource, dx, dy, ulPitch);
|
|
pTexture->Allocate (&m_pi);
|
|
|
|
m_setTextures.insert (pTexture);
|
|
|
|
return pTexture;
|
|
}
|
|
|
|
void CTextureSet::FreeTexture (CTexture *pTexture)
|
|
{
|
|
m_setTextures.erase (pTexture);
|
|
|
|
delete pTexture;
|
|
}
|
|
|
|
void CTextureSet::DirtyTextures (void)
|
|
{
|
|
for (TEXTURE_SET::iterator iter = m_setTextures.begin ();
|
|
iter != m_setTextures.end ();
|
|
iter ++)
|
|
{
|
|
(*iter)->DirtyMemory ();
|
|
}
|
|
}
|
|
|
|
|
|
void CTextureSet::SetPaletteEntries (PALETTEENTRY rgpe [256])
|
|
{
|
|
m_pi.SetPaletteEntries (rgpe);
|
|
|
|
if (!m_pi.IsIndexed ())
|
|
{
|
|
DirtyTextures ();
|
|
}
|
|
}
|
|
|
|
void CTextureSet::GetPaletteEntries (PALETTEENTRY rgpe [256])
|
|
{
|
|
m_pi.GetPaletteEntries (rgpe);
|
|
}
|