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

515 lines
13 KiB
C++

#include "pch.cpp"
#pragma hdrstop
#include "d3drend.h"
#include "util.h"
#include "globals.h"
/*
* Last DD or D3D error
*/
HRESULT hrLast = S_OK;
D3dRenderer::D3dRenderer(void)
{
int i;
/*
* Direct3D globals
*/
_nD3dDrivers = 0;
for (i = 0; i < D3D_DRIVER_COUNT; i++)
{
memset(&_d3diDriver[i], 0, sizeof(D3dDriverInfo));
}
_iDD = -1;
_iD3D = -1;
_pdd = NULL;
_pd3d = NULL;
_bCurrentFullscreenMode = FALSE;
}
void D3dRenderer::Name(char* psz)
{
strcpy(psz, "Direct3D");
}
char* D3dRenderer::LastErrorString(void)
{
return D3dErrorString(hrLast);
}
BOOL D3dRenderer::Initialize(HWND hwndParent)
{
return TRUE;
}
void D3dRenderer::Uninitialize(void)
{
}
BOOL FAR PASCAL DDEnumCallback(GUID FAR* lpGUID, LPSTR lpDriverDesc,
LPSTR lpDriverName, LPVOID lpContext)
{
LPDIRECTDRAW lpDD;
DDCAPS DriverCaps, HELCaps;
D3dRenderer *pdrend = (D3dRenderer *)lpContext;
if (lpGUID) {
hrLast = DirectDrawCreate(lpGUID, &lpDD, NULL);
if (hrLast != DD_OK) {
Msg("Failing while creating a DD device for testing. "
"Continuing with execution.\n%s", D3dErrorString(hrLast));
return DDENUMRET_OK;
}
memset(&DriverCaps, 0, sizeof(DDCAPS));
DriverCaps.dwSize = sizeof(DDCAPS);
memset(&HELCaps, 0, sizeof(DDCAPS));
HELCaps.dwSize = sizeof(DDCAPS);
hrLast = lpDD->GetCaps(&DriverCaps, &HELCaps);
if (hrLast != DD_OK) {
Msg("GetCaps failed in while testing a DD device. "
"Continuing with execution.\n%s", D3dErrorString(hrLast));
RELEASE(lpDD);
return DDENUMRET_OK;
}
RELEASE(lpDD);
if (DriverCaps.dwCaps & DDCAPS_3D) {
/*
* We have found a 3d hardware device
*/
memcpy(&pdrend->_ddiDriver[pdrend->_nDdDrivers].guid,
lpGUID, sizeof(GUID));
memcpy(&pdrend->_ddiDriver[pdrend->_nDdDrivers].ddcapsHw,
&DriverCaps,
sizeof(DDCAPS));
lstrcpy(pdrend->_ddiDriver[pdrend->_nDdDrivers].achName,
lpDriverName);
pdrend->_ddiDriver[pdrend->_nDdDrivers].bIsPrimary = FALSE;
pdrend->_iDD = pdrend->_nDdDrivers;
++pdrend->_nDdDrivers;
if (pdrend->_nDdDrivers == 5)
return (D3DENUMRET_CANCEL);
}
} else {
/*
* It's the primary, fill in some fields.
*/
pdrend->_ddiDriver[pdrend->_nDdDrivers].bIsPrimary = TRUE;
lstrcpy(pdrend->_ddiDriver[pdrend->_nDdDrivers].achName,
"Primary Device");
pdrend->_iDD = pdrend->_nDdDrivers;
++pdrend->_nDdDrivers;
if (pdrend->_nDdDrivers == 5)
return (D3DENUMRET_CANCEL);
}
return DDENUMRET_OK;
}
BOOL D3dRenderer::EnumDisplayDrivers(RendEnumDriversFn pfn,
void* pvArg)
{
int i;
RendDriverDescription rdd;
_nDdDrivers = 0;
_iDD = 0;
hrLast = DirectDrawEnumerate(DDEnumCallback, this);
if (hrLast != DD_OK) {
Msg("DirectDrawEnumerate failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
for (i = 0; i < _nDdDrivers; i++)
{
rdd.rid = (RendId)i;
strcpy(rdd.achName, _ddiDriver[i].achName);
if (!pfn(&rdd, pvArg))
{
return FALSE;
}
}
return TRUE;
}
BOOL D3dRenderer::EnumGraphicsDrivers(RendEnumDriversFn pfn,
void* pvArg)
{
UINT i;
RendDriverDescription rdd;
for (i = 0; i < _nD3dDrivers; i++)
{
rdd.rid = (RendId)i;
strcpy(rdd.achName, _d3diDriver[i].achName);
if (!pfn(&rdd, pvArg))
{
return FALSE;
}
}
return TRUE;
}
/*
* enumDeviceFunc
* Enumeration function for EnumDevices
*/
HRESULT WINAPI EnumDeviceFunc(LPGUID pguid,
LPSTR lpDeviceDescription, LPSTR lpDeviceName,
LPD3DDEVICEDESC pd3ddHw, LPD3DDEVICEDESC pd3ddHel, LPVOID lpContext)
{
D3dRenderer *pdrend = (D3dRenderer *)lpContext;
if (pdrend->_ddiDriver[pdrend->_iDD].bIsPrimary)
{
if (pd3ddHw->dcmColorModel &&
!(pd3ddHw->dwDeviceRenderBitDepth & pdrend->_dwWinBpp))
{
return (D3DENUMRET_OK);
}
if (pd3ddHel->dcmColorModel &&
!(pd3ddHel->dwDeviceRenderBitDepth & pdrend->_dwWinBpp))
{
return (D3DENUMRET_OK);
}
}
pdrend->_d3diDriver[pdrend->_nD3dDrivers].pguid = pguid;
lstrcpy(pdrend->_d3diDriver[pdrend->_nD3dDrivers].achDesc,
lpDeviceDescription);
lstrcpy(pdrend->_d3diDriver[pdrend->_nD3dDrivers].achName, lpDeviceName);
memcpy(&pdrend->_d3diDriver[pdrend->_nD3dDrivers].d3ddHw, pd3ddHw,
sizeof(D3DDEVICEDESC));
memcpy(&pdrend->_d3diDriver[pdrend->_nD3dDrivers].d3ddHel, pd3ddHel,
sizeof(D3DDEVICEDESC));
pdrend->_nD3dDrivers++;
if (pdrend->_nD3dDrivers == 5)
return (D3DENUMRET_CANCEL);
return (D3DENUMRET_OK);
}
/*
* EnumDisplayModesCallback
* Callback to save the display mode information.
*/
HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd,
LPVOID Context)
{
D3dRenderer *pdrend = (D3dRenderer *)Context;
// ATTENTION - Why the bpp restriction?
if (pddsd->dwWidth >= WIN_WIDTH && pddsd->dwHeight >= WIN_HEIGHT &&
pddsd->ddpfPixelFormat.dwRGBBitCount == 16)
{
pdrend->_mleModeList[pdrend->_nModes].iWidth = pddsd->dwWidth;
pdrend->_mleModeList[pdrend->_nModes].iHeight = pddsd->dwHeight;
pdrend->_mleModeList[pdrend->_nModes].iDepth =
pddsd->ddpfPixelFormat.dwRGBBitCount;
pdrend->_nModes++;
}
return DDENUMRET_OK;
}
/*
* CompareModes
* Compare two display modes for sorting purposes.
*/
int __cdecl CompareModes(const void* element1, const void* element2) {
ModeListElement *lpMode1, *lpMode2;
lpMode1 = (ModeListElement*)element1;
lpMode2 = (ModeListElement*)element2;
// XXX
if (lpMode1->iWidth < lpMode2->iWidth)
return -1;
else if (lpMode2->iWidth < lpMode1->iWidth)
return 1;
else if (lpMode1->iHeight < lpMode2->iHeight)
return -1;
else if (lpMode2->iHeight < lpMode1->iHeight)
return 1;
else
return 0;
}
BOOL
D3dRenderer::EnumerateDisplayModes(void)
{
hrLast = _pdd->EnumDisplayModes(0, NULL, this, EnumDisplayModesCallback);
if(hrLast != DD_OK ) {
Msg("EnumDisplayModes failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
qsort((void *)&_mleModeList[0], (size_t) _nModes,
sizeof(ModeListElement), CompareModes);
if (_nModes == 0) {
Msg("The available display modes are not of sufficient "
"size or are not 16-bit\n");
return FALSE;
}
_iCurrentMode = 0;
return TRUE;
}
/*
* GetDDCaps
* Determines Z buffer depth.
*/
BOOL
D3dRenderer::GetDDCaps(void)
{
DDCAPS DriverCaps, HELCaps;
memset(&DriverCaps, 0, sizeof(DriverCaps));
DriverCaps.dwSize = sizeof(DDCAPS);
memset(&HELCaps, 0, sizeof(HELCaps));
HELCaps.dwSize = sizeof(DDCAPS);
hrLast = _pdd->GetCaps(&DriverCaps, &HELCaps);
if (hrLast != DD_OK) {
Msg("GetCaps failed in while checking driver capabilities.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
memcpy(&_ddscapsHw, &DriverCaps.ddsCaps, sizeof(DDSCAPS));
return TRUE;
}
/*
* BPPToDDBD
* Convert an integer bit per pixel number to a DirectDraw bit depth flag
*/
DWORD
BPPToDDBD(int bpp)
{
switch(bpp) {
case 1:
return DDBD_1;
case 2:
return DDBD_2;
case 4:
return DDBD_4;
case 8:
return DDBD_8;
case 16:
return DDBD_16;
case 24:
return DDBD_24;
case 32:
return DDBD_32;
default:
return (DWORD)0;
}
}
BOOL D3dRenderer::SelectDisplayDriver(RendId rid)
{
if (_iDD >= 0)
{
RELEASE(_pd3d);
RELEASE(_pdd);
}
_iDD = (int)rid;
if (_ddiDriver[_iDD].bIsPrimary) {
_bCurrentFullscreenMode = FALSE;
hrLast = DirectDrawCreate(NULL, &_pdd, NULL);
if (hrLast != DD_OK) {
Msg("DirectDrawCreate failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
} else {
/*
* If it's not the primary device, assume we can only do fullscreen.
*/
_bCurrentFullscreenMode = TRUE;
hrLast = DirectDrawCreate(&_ddiDriver[_iDD].guid, &_pdd, NULL);
if (hrLast != DD_OK) {
Msg("DirectDrawCreate failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
if (!EnumerateDisplayModes())
return FALSE;
}
hrLast = _pdd->SetCooperativeLevel(app.hDlg, DDSCL_NORMAL);
if(hrLast != DD_OK ) {
Msg("SetCooperativeLevel failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
hrLast = _pdd->QueryInterface(IID_IDirect3D, (LPVOID*)&_pd3d);
if (hrLast != DD_OK) {
Msg("Creation of IDirect3D failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
GetDDCaps();
if (_ddiDriver[_iDD].bIsPrimary) {
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
hrLast = _pdd->GetDisplayMode(&ddsd);
if (hrLast != DD_OK)
{
Msg("Getting the current display mode failed.\n%s",
D3dErrorString(hrLast));
return FALSE;
}
_dwWinBpp = BPPToDDBD(ddsd.ddpfPixelFormat.dwRGBBitCount);
} // else _dwWinBpp is not used
_nD3dDrivers = 0;
hrLast = _pd3d->EnumDevices(EnumDeviceFunc, this);
if (hrLast != DD_OK) {
Msg("EnumDevices failed.\n%s", D3dErrorString(hrLast));
return FALSE;
}
return TRUE;
}
BOOL D3dRenderer::SelectGraphicsDriver(RendId rid)
{
_iD3D = (int)rid;
if (_d3diDriver[_iD3D].d3ddHw.dcmColorModel)
{
_dwZDepth = _d3diDriver[_iD3D].d3ddHw.dwDeviceZBufferBitDepth;
_dwZType = DDSCAPS_VIDEOMEMORY;
}
else
{
_dwZDepth = _d3diDriver[_iD3D].d3ddHel.dwDeviceZBufferBitDepth;
_dwZType = DDSCAPS_SYSTEMMEMORY;
}
if (_dwZDepth & DDBD_32)
{
_dwZDepth = 32;
}
else if (_dwZDepth & DDBD_24)
{
_dwZDepth = 24;
}
else if (_dwZDepth & DDBD_16)
{
_dwZDepth = 16;
}
else if (_dwZDepth & DDBD_8)
{
_dwZDepth = 8;
}
else
{
_dwZDepth = 0;
}
return TRUE;
}
BOOL D3dRenderer::DescribeDisplay(RendDisplayDescription* prdd)
{
DDSURFACEDESC ddsd;
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
hrLast = _pdd->GetDisplayMode(&ddsd);
if (hrLast != DD_OK)
{
return FALSE;
}
prdd->bPrimary = _ddiDriver[_iDD].bIsPrimary;
prdd->nColorBits = ddsd.ddpfPixelFormat.dwRGBBitCount;
if (prdd->bPrimary)
{
prdd->uiWidth = ddsd.dwWidth;
prdd->uiHeight = ddsd.dwHeight;
}
else
{
prdd->uiWidth = _mleModeList[_iCurrentMode].iWidth;
prdd->uiHeight = _mleModeList[_iCurrentMode].iHeight;
}
return TRUE;
}
BOOL D3dRenderer::DescribeGraphics(RendGraphicsDescription* prgd)
{
D3DDEVICEDESC *pd3dd;
if (_d3diDriver[_iD3D].d3ddHw.dcmColorModel)
{
prgd->bHardwareAssisted = TRUE;
pd3dd = &_d3diDriver[_iD3D].d3ddHw;
}
else
{
prgd->bHardwareAssisted = FALSE;
pd3dd = &_d3diDriver[_iD3D].d3ddHel;
}
prgd->uiColorTypes =
((pd3dd->dpcTriCaps.dwShadeCaps &
D3DPSHADECAPS_COLORGOURAUDMONO) ? REND_COLOR_MONO : 0) |
((pd3dd->dpcTriCaps.dwShadeCaps &
D3DPSHADECAPS_COLORGOURAUDRGB) ? REND_COLOR_RGBA : 0);
prgd->nZBits = _dwZDepth;
prgd->uiExeBufFlags =
((pd3dd->dwDevCaps & D3DDEVCAPS_EXECUTESYSTEMMEMORY) ?
REND_BUFFER_SYSTEM_MEMORY : 0) |
((pd3dd->dwDevCaps & D3DDEVCAPS_EXECUTEVIDEOMEMORY) ?
REND_BUFFER_VIDEO_MEMORY : 0);
prgd->bPerspectiveCorrect = (pd3dd->dpcTriCaps.dwTextureCaps &
D3DPTEXTURECAPS_PERSPECTIVE) != 0;
prgd->bSpecularLighting = (pd3dd->dpcTriCaps.dwShadeCaps &
(D3DPSHADECAPS_SPECULARGOURAUDMONO |
D3DPSHADECAPS_SPECULARGOURAUDRGB)) != 0;
prgd->bCopyTextureBlend = (pd3dd->dpcTriCaps.dwTextureBlendCaps &
D3DPTBLENDCAPS_COPY) != 0;
return TRUE;
}
BOOL D3dRenderer::FlipToDesktop(void)
{
return _pdd->FlipToGDISurface() == DD_OK;
}
BOOL D3dRenderer::RestoreDesktop(void)
{
#if 0
// ATTENTION - Window has been destroyed at this point
// Is this really necessary?
_pdd->SetCooperativeLevel(hwnd, DDSCL_NORMAL);
#endif
return _pdd->RestoreDisplayMode() == DD_OK;
}
RendWindow* D3dRenderer::NewWindow(int x, int y, UINT uiWidth, UINT uiHeight,
UINT uiBuffers)
{
D3dWindow *pdwinRend;
pdwinRend = new D3dWindow;
if (pdwinRend == NULL)
{
return NULL;
}
if (!pdwinRend->Initialize(this, _pdd, _pd3d, _d3diDriver[_iD3D].pguid,
x, y, uiWidth, uiHeight, uiBuffers))
{
delete pdwinRend;
return NULL;
}
return pdwinRend;
}
static D3dRenderer d3drend;
Renderer* GetD3dRenderer(void)
{
return &d3drend;
}