2025-04-27 07:49:33 -04:00

350 lines
10 KiB
C++

#include "pch.cpp"
#pragma hdrstop
#include "d3drend.h"
#include "util.h"
#include "loadppm.h"
#include "globals.h"
D3dTexture::D3dTexture(void)
{
_pddsSrc = NULL;
_pdtexSrc = NULL;
_pddsDst = NULL;
_pdtexDst = NULL;
_pdtexNext = NULL;
}
/*
* D3dLoadSurface
* Loads a ppm file into a texture map DD surface in system memory.
*/
LPDIRECTDRAWSURFACE
D3dLoadSurface(LPDIRECTDRAW lpDD, LPCSTR lpName, LPDDSURFACEDESC lpFormat)
{
LPDIRECTDRAWSURFACE lpDDS;
DDSURFACEDESC ddsd;
int i, j;
LPDIRECTDRAWPALETTE lpDDPal;
PALETTEENTRY ppe[256];
HRESULT ddrval;
Image im;
ImageFormat ifmt;
BYTE *pbSrc, *pbDst;
UINT cbRow;
ifmt.nColorBits = lpFormat->ddpfPixelFormat.dwRGBBitCount;
ifmt.bQuantize =
(lpFormat->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) != 0;
if (!ifmt.bQuantize)
{
unsigned long m;
int s;
m = lpFormat->ddpfPixelFormat.dwRBitMask;
for (s = 0; !(m & 1); s++, m >>= 1) ;
ifmt.iRedShift = s;
for (s = 0; m != 0; s++, m >>= 1) ;
ifmt.iRedBits = s;
m = lpFormat->ddpfPixelFormat.dwGBitMask;
for (s = 0; !(m & 1); s++, m >>= 1) ;
ifmt.iGreenShift = s;
for (s = 0; m != 0; s++, m >>= 1) ;
ifmt.iGreenBits = s;
m = lpFormat->ddpfPixelFormat.dwBBitMask;
for (s = 0; !(m & 1); s++, m >>= 1) ;
ifmt.iBlueShift = s;
for (s = 0; m != 0; s++, m >>= 1) ;
ifmt.iBlueBits = s;
}
if (!LoadPPM(lpName, &ifmt, &im))
{
return NULL;
}
memcpy(&ddsd, lpFormat, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
ddsd.dwHeight = im.uiHeight;
ddsd.dwWidth = im.uiWidth;
ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
if (ddrval != DD_OK) {
/*
* If we failed, it might be the pixelformat flag bug in some ddraw
* hardware drivers. Try again without the flag.
*/
memcpy(&ddsd, lpFormat, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
ddsd.dwHeight = im.uiHeight;
ddsd.dwWidth = im.uiWidth;
ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL);
if (ddrval != DD_OK) {
Msg("CreateSurface for texture failed (loadtex).\n%s",
D3dErrorString(ddrval));
return NULL;
}
}
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddrval = lpDDS->Lock(NULL, &ddsd, 0, NULL);
if (ddrval != DD_OK) {
delete [] im.pvImage;
lpDDS->Release();
Msg("Lock failed while loading surface (loadtex).\n%s",
D3dErrorString(ddrval));
return NULL;
}
pbSrc = (BYTE *)im.pvImage;
pbDst = (BYTE *)ddsd.lpSurface;
cbRow = ((ifmt.nColorBits+7)/8)*im.uiWidth;
for (j = 0; (UINT)j < im.uiHeight; j++)
{
memcpy(pbDst, pbSrc, cbRow);
pbSrc += cbRow;
pbDst += ddsd.lPitch;
}
delete [] im.pvImage;
lpDDS->Unlock(NULL);
if (ifmt.bQuantize)
{
/*
* Now to create a palette
*/
memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
for (i = 0; (UINT)i < im.nColors; i++) {
ppe[i].peRed = (unsigned char)RGB_GETRED(im.dcolPalette[i]);
ppe[i].peGreen = (unsigned char)RGB_GETGREEN(im.dcolPalette[i]);
ppe[i].peBlue = (unsigned char)RGB_GETBLUE(im.dcolPalette[i]);
}
/*
* D3DPAL_RESERVED entries are ignored by the renderer.
*/
for (; i < 256; i++)
ppe[i].peFlags = D3DPAL_RESERVED;
ddrval = lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE |
DDPCAPS_ALLOW256,
ppe, &lpDDPal, NULL);
if (ddrval != DD_OK) {
lpDDS->Release();
Msg("Create palette failed while loading surface (loadtex).\n%s",
D3dErrorString(ddrval));
return (NULL);
}
/*
* Finally, bind the palette to the surface
*/
ddrval = lpDDS->SetPalette(lpDDPal);
if (ddrval != DD_OK) {
lpDDS->Release();
lpDDPal->Release();
Msg("SetPalette failed while loading surface (loadtex).\n%s",
D3dErrorString(ddrval));
return (NULL);
}
}
return lpDDS;
}
/*
* CreateVidTex
* Create a texture in video memory (if appropriate).
* If no hardware exists, this will be created in system memory, but we
* can still use load to swap textures.
*/
BOOL
D3dTexture::CreateVidTex(LPDIRECTDRAW pdd, UINT uiFlags)
{
DDSURFACEDESC ddsd;
LPDIRECTDRAWPALETTE lpDDPal = NULL;
PALETTEENTRY ppe[256];
BOOL bQuant;
BOOL bOnlySoftRender;
if (!GetDDSurfaceDesc(&ddsd, _pddsSrc))
return FALSE;
if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
bQuant = TRUE;
else
bQuant = FALSE;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
if (uiFlags & REND_BUFFER_SYSTEM_MEMORY)
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
hrLast = pdd->CreateSurface(&ddsd, &_pddsDst, NULL);
if (hrLast != DD_OK) {
Msg("Create surface in CreateVidTexture failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
if (!GetDDSurfaceDesc(&ddsd, _pddsDst))
return FALSE;
bOnlySoftRender = FALSE;
if ((_pdrend->_ddscapsHw.dwCaps & DDSCAPS_TEXTURE) &&
!(ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
bOnlySoftRender = TRUE;
if (stat.rgd.bHardwareAssisted && bOnlySoftRender) {
Msg("Failed to put texture surface in video memory for "
"hardware D3D device.\n");
return FALSE;
}
if (bQuant) {
memset(ppe, 0, sizeof(PALETTEENTRY) * 256);
hrLast = pdd->CreatePalette(DDPCAPS_8BIT, ppe, &lpDDPal, NULL);
if (hrLast != DD_OK) {
Msg("CreatePalette in CreateVidTexture failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
hrLast = _pddsDst->SetPalette(lpDDPal);
if (hrLast != DD_OK) {
RELEASE(lpDDPal);
Msg("SetPalette in CreateVidTexture failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
}
hrLast = _pddsDst->QueryInterface(IID_IDirect3DTexture,
(LPVOID*)&_pdtexDst);
if (hrLast != D3D_OK) {
RELEASE(lpDDPal);
Msg("QueryInterface in CreateVidTexture failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
return TRUE;
}
BOOL D3dTexture::Initialize(D3dRenderer* pdrend,
LPDIRECTDRAW pdd, LPDIRECT3DDEVICE pd3dev,
DDSURFACEDESC* pddsd, char* pszFile, UINT uiFlags,
D3dTexture* pdtexNext)
{
HRESULT ddrval;
PALETTEENTRY ppe[256];
LPDIRECTDRAWPALETTE lpDDPalSrc, lpDDPalDst;
BOOL bSucc;
bSucc = FALSE;
_pdrend = pdrend;
/*
* Load each image file as a "source" texture surface in system memory.
* Load each source texture surface into a "destination" texture (in video
* memory if appropriate). The destination texture handles are used in
* rendering. This scheme demos the Load call and allows dynamic texture
* swapping.
*/
if (!(_pddsSrc = D3dLoadSurface(pdd, pszFile, pddsd)))
{
return FALSE;
}
hrLast = _pddsSrc->QueryInterface(IID_IDirect3DTexture,
(LPVOID*)&_pdtexSrc);
if (hrLast != DD_OK) {
Msg("Could not create texture.\n%s", D3dErrorString(hrLast));
return FALSE;;
}
if (!CreateVidTex(pdd, uiFlags))
return FALSE;
hrLast = _pdtexDst->GetHandle(pd3dev, &_dthDst);
if (hrLast != D3D_OK) {
Msg("Could not get dest texture handle.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
if (_pddsDst->Blt(NULL, _pddsSrc, NULL,
DDBLT_WAIT, NULL) != DD_OK) {
Msg("Could not load src texture into dest.");
return FALSE;
}
ddrval = _pddsSrc->GetPalette(&lpDDPalSrc);
if (ddrval == DDERR_NOPALETTEATTACHED) {
return TRUE;
}
if (ddrval != DD_OK) {
Msg("Could not get source palette");
return FALSE;
}
ddrval = _pddsDst->GetPalette(&lpDDPalDst);
if (ddrval != DD_OK) {
Msg("Could not get dest palette");
goto EH_lpDDPalSrc;
}
ddrval = lpDDPalSrc->GetEntries(0, 0, 256, ppe);
if (ddrval != DD_OK) {
Msg("Could not get source palette entries");
goto EH_lpDDPalDst;
}
ddrval = lpDDPalDst->SetEntries(0, 0, 256, ppe);
if (ddrval != DD_OK)
{
Msg("Could not get source palette entries");
}
else
{
bSucc = TRUE;
_pdtexNext = pdtexNext;
}
EH_lpDDPalDst:
lpDDPalDst->Release();
EH_lpDDPalSrc:
lpDDPalSrc->Release();
return bSucc;
}
D3dTexture::~D3dTexture(void)
{
// ATTENTION - Tanks the texture list because the window isn't
// notified but it works for now
RELEASE(_pddsSrc);
RELEASE(_pdtexSrc);
RELEASE(_pddsDst);
RELEASE(_pdtexDst);
}
void D3dTexture::Release(void)
{
delete this;
}
D3DTEXTUREHANDLE D3dTexture::Handle(void)
{
return _dthDst;
}
BOOL D3dTexture::RestoreSurface(void)
{
if (_pddsSrc->IsLost() == DDERR_SURFACELOST)
{
hrLast = _pddsSrc->Restore();
if (hrLast != DD_OK)
{
Msg("Restore of a src texture surface failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
}
if (_pddsDst->IsLost() == DDERR_SURFACELOST)
{
hrLast = _pddsDst->Restore();
if (hrLast != DD_OK)
{
Msg("Restore of a dst texture surface failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
}
return TRUE;
}