JurassicParkTrespasser/jp2_pc/Source/InitGUIApp/DDDevice.cpp

553 lines
14 KiB
C++
Raw Permalink Normal View History

2018-01-01 22:07:24 +00:00
/***********************************************************************************************
*
* Copyright <EFBFBD> DreamWorks Interactive. 1997
*
* Implementation of DDDevice.hpp.
*
***********************************************************************************************
*
* $Log:: /JP2_PC/Source/trespass/DDDevice.cpp $
*
* 19 8/12/98 10:11p Pkeet
* Disabled requiring the blend source alpha caps bit be set for hardware water to work.
*
* 18 8/06/98 7:28p Pkeet
* Added the 'bModulatedAlpha' flag. Added the 'bGetModulatedAlpha' function.
*
* 17 8/05/98 10:10p Pkeet
* Changed the way cards are listed.
*
* 16 8/05/98 9:40p Pkeet
* The Z buffer bit depth is now determined and stored in the registry. Moved the
* 'iZBufferBitDepth' data member to the Direct3D structure. Removed unnecessary code.
*
* 15 8/05/98 9:09p Pkeet
*
* 14 7/20/98 10:42p Pkeet
* Changed devices to work with new DirectX 6.0 interfaces.
*
* 13 7/20/98 10:24p Pkeet
*
* 12 7/05/98 8:05p Pkeet
* Added code to prevent the enumeration of display modes greater than 640x480.
*
* 11 7/05/98 7:00p Pkeet
* Added a release to complement a DirectDraw device creation.
*
* 10 6/29/98 9:19p Pkeet
* Simplified code to find GUIDs for DirectDraw and Direct3D.
*
* 9 6/15/98 7:48p Shernd
* Make builds for machines that don't have c:\jp2_pc as the build environment
*
* 8 6/15/98 12:10p Pkeet
* Added includes for compiling with 'InitGUIApp.'
*
* 7 6/09/98 9:22a Shernd
* Removing Refresh Rates for EnumDisplayMode
*
* 6 6/08/98 4:16p Pkeet
* Added commented out includes.
*
* 5 1/26/98 1:45p Shernd
* Adding setup for precompiled headers
*
* 4 12/15/97 2:29p Shernd
* Don't GPF when d3d can't be initialized.
*
* 3 12/09/97 6:48p Pkeet
* Added a query to get the direct draw 2 interface.
*
* 2 12/09/97 6:21p Pkeet
* Added code to set and get D3D driver information.
*
* 1 12/08/97 6:36p Pkeet
* Initial implementation.
*
**********************************************************************************************/
#ifndef TRESPASS
#include <windows.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#else
#include "precomp.h"
#pragma hdrstop
#include <assert.h>
#endif
#include "../Lib/Sys/RegInit.hpp"
#include "../Lib/Sys/Reg.h"
#if (1)
#include "ddraw.h"
2018-01-01 22:07:24 +00:00
#define D3D_OVERLOADS
#include "d3d.h"
2018-01-01 22:07:24 +00:00
#endif
#include "DDDevice.hpp"
BOOL bSecondaryCard = FALSE;
BOOL bDeviceFound = FALSE;
//
// Function prototypes.
//
//*********************************************************************************************
//
HRESULT WINAPI D3DEnumCallback
(
LPGUID lpGUID,
LPSTR lpszDeviceDesc,
LPSTR lpszDeviceName,
LPD3DDEVICEDESC lpd3dHWDeviceDesc,
LPD3DDEVICEDESC lpd3dSWDeviceDesc,
LPVOID lpUserArg
);
//
// Enumeration callback for direct3D drivers.
//
//**************************************
//**********************************************************************************************
//
BOOL WINAPI DDEnumCallbackAuto
(
GUID FAR* lpGUID,
LPSTR lpDriverDescription,
LPSTR lpDriverName,
LPVOID lpContext
);
//
// Callback used to enumerate DirectDraw devices.
//
//**************************************
//
// Function implementations.
//
//**********************************************************************************************
//
static HRESULT CALLBACK EnumDisplayMode
(
DDSURFACEDESC* pddsd, // Surface descriptor for a screen mode.
void* pv_context // Resolution array.
)
//
// Callback for IDirectDraw::EnumDisplayModes(). Adds the display mode
// in ascrmdList via AddScreenMode().
//
// Returns DDENUMRET_OK to indicate success.
//
//**********************************
{
assert(pddsd);
assert(pv_context);
// If the mode is not 16 bits, ignore it.
if (pddsd->ddpfPixelFormat.dwRGBBitCount != 16)
return DDENUMRET_OK;
// Do not enumerate screen resolutions higher than 640x480.
if (pddsd->dwWidth > 640)
return DDENUMRET_OK;
// Get the next available element.
SResolution* pr = &((SResolution*)pv_context)[SResolution::iResolutionsCount++];
assert(pr);
// Set the width, height and refresh rate of the element.
pr->iWidth = int(pddsd->dwWidth);
pr->iHeight = int(pddsd->dwHeight);
pr->iRefreshHz = int(pddsd->dwRefreshRate);
return DDENUMRET_OK;
}
//**********************************************************************************************
BOOL bFindResolutions(GUID& guid, SResolution* ar, int& ri_num_resolutions)
{
LPDIRECTDRAW pdd = 0; // DirectDraw device.
BOOL b_created;
// Initialize the device count.
SResolution::iResolutionsCount = 0;
// Create the direct draw device.
b_created = DirectDrawCreate(pConvertGUID(guid), &pdd, 0) == DD_OK;
assert(b_created);
assert(pdd);
// Enumerate resolutions.
pdd->EnumDisplayModes(0, 0, (void*)ar, EnumDisplayMode);
// Release the direct draw device.
pdd->Release();
//
// To do:
// Verify there is enough video memory for the selected video mode and for textures
// that may be used by direct draw.
//
// Copy the resolutions count.
ri_num_resolutions = SResolution::iResolutionsCount;
return TRUE;
}
//**********************************************************************************************
DWORD FlagsToBitDepth(DWORD dwFlags)
{
if (dwFlags & DDBD_1)
return 1;
else if (dwFlags & DDBD_2)
return 2;
else if (dwFlags & DDBD_4)
return 4;
else if (dwFlags & DDBD_8)
return 8;
else if (dwFlags & DDBD_16)
return 16;
else if (dwFlags & DDBD_24)
return 24;
else if (dwFlags & DDBD_32)
return 32;
else
return 0;
}
//*****************************************************************************************
//
bool bGetModulatedAlpha(LPD3DDEVICEDESC lpd3dHWDeviceDesc)
//
// Returns 'true' if modulated alpha is supported.
//
// To do:
// Add in a test based on the pixel format.
//
//**************************************
{
assert(lpd3dHWDeviceDesc);
// Test the modulate caps bit.
if (!(lpd3dHWDeviceDesc->dwTextureOpCaps & D3DTEXOPCAPS_MODULATE))
return false;
// Test to ensure a 4444 texture format is supported.
//DDPIXELFORMAT pixform = ddpfFormats[ed3dtexSCREEN_ALPHA];
//if (iCountBits(pixform.dwRGBAlphaBitMask) != 4 || !(pixform.dwFlags & DDPF_ALPHAPIXELS))
//return false;
// Test if source alpha blending is supported.
//if (!(lpd3dHWDeviceDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_SRCALPHA))
//return false;
// This feature is supported.
return true;
}
//**********************************************************************************************
HRESULT WINAPI D3DEnumCallback(LPGUID lpGUID, LPSTR lpszDeviceDesc, LPSTR lpszDeviceName,
LPD3DDEVICEDESC lpd3dHWDeviceDesc, LPD3DDEVICEDESC lpd3dSWDeviceDesc,
LPVOID lpUserArg)
{
assert(lpszDeviceName);
assert(lpszDeviceDesc);
assert(lpUserArg);
// Cast to get the device slot.
SD3DDevice* pd3d = (SD3DDevice*)lpUserArg;
// If the device is not in hardware, ignore it.
if (!lpd3dHWDeviceDesc)
// If the device does not support RGB lighting, ignore it.
if (lpd3dHWDeviceDesc->dcmColorModel != D3DCOLOR_RGB)
return D3DENUMRET_OK;
// If the device does not support a 16 bit bitdepth, ignore it.
if ((lpd3dHWDeviceDesc->dwDeviceRenderBitDepth & DDBD_16) == 0)
return D3DENUMRET_OK;
// If the device does not support Gouraud shading, ignore it.
if ((lpd3dHWDeviceDesc->dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB) == 0)
return D3DENUMRET_OK;
// If the device does not support a z buffer, ignore it.
if (!lpd3dHWDeviceDesc->dwDeviceZBufferBitDepth)
return D3DENUMRET_OK;
// Get and store the bit depth of the Z buffer.
int i_zbuffer_bitdepth = FlagsToBitDepth(lpd3dHWDeviceDesc->dwDeviceZBufferBitDepth);
if (!i_zbuffer_bitdepth)
return D3DENUMRET_OK;
// Copy the GUID.
if (lpGUID)
{
pd3d->guidID = *lpGUID;
}
else
{
memset(&pd3d->guidID, 0, sizeof(pd3d->guidID));
}
// Copy the Z buffer bitdepth.
pd3d->iZBufferBitDepth = i_zbuffer_bitdepth;
// Set the modulated alpha flag.
pd3d->bModulatedAlpha = bGetModulatedAlpha(lpd3dHWDeviceDesc);
// Copy the name and device description and return.
strcpy(pd3d->strName, lpszDeviceName);
strcpy(pd3d->strDescription, lpszDeviceDesc);
pd3d->bSupported = TRUE;
return D3DENUMRET_OK;
}
//**********************************************************************************************
BOOL WINAPI DDEnumCallbackAuto(GUID FAR* lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName,
LPVOID lpContext)
{
assert(lpContext);
assert(lpDriverDescription);
assert(lpDriverName);
SDDDevice ddd; // Device for this callback.
CEnumerateDevices *penumdev = (CEnumerateDevices*)lpContext; // Enumeration of devices.
// Set the GUID.
if (lpGUID)
{
// Just copy it.
ddd.guidID = *lpGUID;
}
else
{
// Set it to null.
memset(&ddd.guidID, 0, sizeof(GUID));
}
// Copy the name and device description.
strcpy(ddd.strName, lpDriverName);
strcpy(ddd.strDescription, lpDriverDescription);
// Add the device to the list.
penumdev->AddDDDevice(ddd);
return DDENUMRET_OK;
}
//**********************************************************************************************
BOOL bFindD3D(GUID& guid, SD3DDevice* pd3d_device)
{
LPDIRECTDRAW pdd = 0; // DirectDraw device.
LPDIRECTDRAW4 pdd2 = 0; // DirectDraw2 device.
LPDIRECT3D3 pd3d = 0; // Direct3D3 device.
BOOL b_retval = FALSE;
HRESULT hres;
// Create the direct draw device.
hres = DirectDrawCreate(pConvertGUID(guid), &pdd, 0);
if (FAILED(hres) || !pdd)
return FALSE;
// Get the direct draw 2 interface.
hres = pdd->QueryInterface(IID_IDirectDraw4, (LPVOID*)&pdd2);
if (FAILED(hres) || !pdd2)
{
pdd->Release();
return FALSE;
}
// Query the DirectDraw object to get the D3D object
hres = pdd2->QueryInterface(IID_IDirect3D3, (void**)&pd3d);
if (FAILED(hres) || !pd3d)
{
pdd->Release();
pdd2->Release();
return FALSE;
}
// Enumerate d3d drivers.
pd3d->EnumDevices(D3DEnumCallback, (void*)pd3d_device);
// If the enumeration failed to find a supported device, fail this driver.
if (!pd3d_device->bSupported)
goto FINISH_RELEASE;
//
// Verify that DirectDraw and Direct3D can support this device.
//
// All tests have succeeded.
b_retval = TRUE;
FINISH_RELEASE:
// Release the various interfaces and return.
pd3d->Release();
pdd2->Release();
pdd->Release();
return b_retval;
}
//**********************************************************************************************
void CEnumerateDevices::RemoveDevice(int i)
{
for (int j = i + 1; j < iNumDevices; ++j)
Devices[j - 1] = Devices[j];
--iNumDevices;
}
//**********************************************************************************************
void CEnumerateDevices::AddDDDevice(const SDDDevice& ddd)
{
// Stop adding devices if the array is full.
if (iNumDevices >= iMaxDevices - 1)
return;
// Copy the device information.
Devices[iNumDevices].ddDevice = ddd;
Devices[iNumDevices].bD3DDeviceFound = false;
// Clear the Direct3D device information.
strcpy(Devices[iNumDevices].d3dDevice.strName, "None");
strcpy(Devices[iNumDevices].d3dDevice.strDescription, "None");
// Defaults.
Devices[iNumDevices].d3dDevice.iZBufferBitDepth = 0;
Devices[iNumDevices].d3dDevice.bSupported = FALSE;
Devices[iNumDevices].d3dDevice.bModulatedAlpha = FALSE;
++iNumDevices;
}
//**********************************************************************************************
void CEnumerateDevices::GetTitle(int i, char* str) const
{
assert(i >= 0);
assert(i < iNumDevices);
CEnumerateDevices::SDevice dev = devGetDevice(i);
strcpy(str, dev.ddDevice.strDescription);
strcat(str, " (");
strcat(str, dev.ddDevice.strName);
strcat(str, ")");
}
//**********************************************************************************************
void CEnumerateDevices::SelectDevice(char* str)
{
char str_title[2048];
for (int i = 0; i < iNumDevices; ++i)
{
GetTitle(i, str_title);
if (strcmpi(str, str_title) == 0)
{
iSelectedDevice = i;
return;
}
}
assert(0);
}
//**********************************************************************************************
CEnumerateDevices::CEnumerateDevices()
: iNumDevices(0), iSelectedDevice(0)
{
// Enumerate DirectDraw devices.
DirectDrawEnumerate(DDEnumCallbackAuto, (void*)this);
//
// Attempt to find Direct3D support for each of the devices.
//
for (int i = 0; i < iNumDevices; ++i)
{
Devices[i].bD3DDeviceFound = bFindD3D
(
Devices[i].ddDevice.guidID,
&Devices[i].d3dDevice
);
}
for (int i = iNumDevices - 1; i >= 0; --i)
2018-01-01 22:07:24 +00:00
{
if (!Devices[i].bD3DDeviceFound)
RemoveDevice(i);
}
//
// The last device should be Trespasser's software renderer.
//
{
SDDDevice ddd;
memset(&ddd.guidID, 0, sizeof(GUID));
strcpy(ddd.strName, "display");
strcpy(ddd.strDescription, "Trespasser's software driver");
Devices[iNumDevices].ddDevice = ddd;
Devices[iNumDevices].bD3DDeviceFound = FALSE;
strcpy(Devices[iNumDevices].d3dDevice.strName, "Trespasser");
strcpy(Devices[iNumDevices].d3dDevice.strDescription, "Software");
Devices[iNumDevices].d3dDevice.iZBufferBitDepth = 0;
Devices[iNumDevices].d3dDevice.bModulatedAlpha = FALSE;
iSelectedDevice = iNumDevices;
++iNumDevices;
}
}
void CEnumerateDevices::WriteSelectedDeviceToRegistry()
{
SDevice dev = devGetSelectedDevice();
if (!dev.bD3DDeviceFound)
{
GUID guid;
// Write software version to the registry.
SetD3D(FALSE);
memset(&guid, 0, sizeof(GUID));
WriteDDGUID(guid);
WriteD3DGUID(guid);
}
else
{
// Write the hardware version to the registry.
SetD3D(TRUE);
WriteDDGUID(dev.ddDevice.guidID);
WriteD3DGUID(dev.d3dDevice.guidID);
}
// Write the common information to the registry.
bSetInitFlag(TRUE);
{
// Set the title.
char str_title[2048];
GetTitle(iSelectedDevice, str_title);
SetRegString(strD3D_TITLE, str_title);
}
SetZBufferBitdepth(dev.d3dDevice.iZBufferBitDepth);
}
//
// Global variables.
//
int SResolution::iResolutionsCount;
CEnumerateDevices *penumdevDevices = 0;