dxx-rebirth/arch/win32/texture.cpp

534 lines
10 KiB
C++
Raw Normal View History

2006-03-20 17:12:09 +00:00
#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);
}