#include "pch.h"
//////////////////////////////////////////////////////////////////////////////
//
// Engine Implementation
//
//////////////////////////////////////////////////////////////////////////////
class EngineImpl : public PrivateEngine {
private:
//////////////////////////////////////////////////////////////////////////////
//
// types
//
//////////////////////////////////////////////////////////////////////////////
typedef TList<PrivateSurface*> SurfaceList;
typedef TList<DeviceDependant*> DeviceDependantList;
//////////////////////////////////////////////////////////////////////////////
//
// members
//
//////////////////////////////////////////////////////////////////////////////
//
// State
//
bool m_bValid;
bool m_bValidDevice;
bool m_bFullscreen;
bool m_bAllowSecondary;
bool m_bAllow3DAcceleration;
DWORD m_dwMaxTextureSize;// yp Your_Persona August 2 2006 : MaxTextureSize Patch
bool m_b3DAccelerationImportant;
DWORD m_dwBPP; // KGJV 32B - user choosen bpp or desktop bbp
//
// Direct Draw Devices
//
TRef<DDDevice> m_pdddevice;
TRef<DDDevice> m_pdddeviceFullscreen;
TRef<DDDevice> m_pdddevicePrimary;
TRef<DDDevice> m_pdddeviceSecondary;
//
//
//
TRef<PixelFormat> m_ppf;
TRef<IDirectDrawSurfaceX> m_pdds;
HWND m_hwndClip;
WinPoint m_pointPrimary;
HWND m_hwndFocus;
WinPoint m_pointFullscreen;
WinPoint m_pointFullscreenCurrent;
TRef<PrivateSurface> m_psurfaceBack;
TRef<IDirectDrawClipper> m_pddClipper;
float m_gamma;
//
// Surface Cache
//
DeviceDependantList m_listDeviceDependant;
SurfaceList m_listSurfaces;
SurfaceList m_listDeviceFormatSurfaces;
//////////////////////////////////////////////////////////////////////////////
//
// Direct Draw Device Enumeration
//
//////////////////////////////////////////////////////////////////////////////
static BOOL PASCAL StaticDDDeviceCallback(
GUID FAR* lpGuid,
LPTSTR lpDriverDesc,
LPTSTR lpDriverName,
LPVOID lpvoid
) {
EngineImpl* pthis = (EngineImpl*)lpvoid;
return pthis->DDDeviceCallback(lpGuid, lpDriverDesc, lpDriverName);
}
BOOL DDDeviceCallback(
GUID FAR* lpGuid,
LPTSTR lpDriverDesc,
LPTSTR lpDriverName
) {
if (lpGuid != NULL) {
//
// Create the DD device.
//
TRef<IDirectDraw> pdd;
HRESULT hr = DirectDrawCreate(lpGuid, &pdd, NULL);
if (SUCCEEDED(hr)) {
TRef<IDirectDrawX> pddx;
DDCall(pdd->QueryInterface(IID_IDirectDrawX, (void**)&pddx));
//
// Create a device data object
//
TRef<DDDevice> pdddevice = CreateDDDevice(this, m_bAllow3DAcceleration, pddx);
if (pdddevice->IsValid()) {
pdddevice->SetPrimaryDevice(m_pdddevicePrimary);
//
// If the device has 3D acceleration we'll use it as our secondary device
//
if (
pdddevice->Has3DAcceleration()
&& (pdddevice->GetZBufferPixelFormat() != NULL)
) {
m_pdddeviceSecondary = pdddevice;
}
}
}
}
return DDENUMRET_OK;
}
//////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
//////////////////////////////////////////////////////////////////////////////
public:
EngineImpl(bool bAllow3DAcceleration, bool bAllowSecondary, DWORD dwBPP) :
m_pointFullscreen(800, 600),
m_pointFullscreenCurrent(0, 0),
m_bFullscreen(false),
m_bAllow3DAcceleration(bAllow3DAcceleration),
m_bAllowSecondary(bAllowSecondary),
m_b3DAccelerationImportant(false),
m_bValid(false),
m_bValidDevice(false),
m_hwndFocus(NULL),
m_hwndClip(NULL),
m_gamma(1.0f),
m_dwBPP(dwBPP) // KGJV 32B
{
//
// Get the primary device
//
m_pdddevicePrimary = CreateDDDevice(this, m_bAllow3DAcceleration, NULL);
if (!m_pdddevicePrimary->IsValid()) {
// !!! replace with a ZErrorHandler call
::MessageBox(
NULL,
"Unable to create primary DirectDraw Device.\n"
"Please update your DirectX installation",
"Initialization Error",
MB_ICONEXCLAMATION | MB_OK
);
return;
}
//
// Search for other devices with 3D support for fullscreen
//
DDCall(DirectDrawEnumerate(StaticDDDeviceCallback, this));
//
// Start on the primary device
//
m_pdddevice = m_pdddevicePrimary;
//
// Create a default pixel format
//
// KGJV 32B - set PixelFormat according to bpp
if (m_dwBPP == 0)
{
// fetch the desktop bpp
DDSDescription ddsd;
DDCall(m_pdddevicePrimary->GetDD()->GetDisplayMode(&ddsd));
m_dwBPP = ddsd.ddpfPixelFormat.dwRGBBitCount;
if (m_dwBPP != 32) m_dwBPP = 16; // fallback to 16 if desktop bpp isnt 32
}
if (m_dwBPP == 32)
m_ppf = new PixelFormat(32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
if (m_dwBPP == 16)
m_ppf = new PixelFormat(16, 0xf800, 0x07e0, 0x001f, 0x0000);
}
private:
//////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
//////////////////////////////////////////////////////////////////////////////
~EngineImpl()
{
}
//////////////////////////////////////////////////////////////////////////////
//
// Terminate Dependants
//
//////////////////////////////////////////////////////////////////////////////
void ClearDependants()
{
{
DeviceDependantList::Iterator iter(m_listDeviceDependant);
while (!iter.End()) {
iter.Value()->ClearDevice();
iter.Next();
}
}
{
SurfaceList::Iterator iter(m_listSurfaces);
while (!iter.End()) {
iter.Value()->ClearDevice();
iter.Next();
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Device Termination
//
//////////////////////////////////////////////////////////////////////////////
void TerminateDevice()
{
ClearDependants();
m_hwndClip = NULL;
m_psurfaceBack = NULL;
m_pddClipper = NULL;
m_pdds = NULL;
m_pdddevice->FreeEverything();
m_pdddevice = NULL;
}
//////////////////////////////////////////////////////////////////////////////
//
// Termination
//
//////////////////////////////////////////////////////////////////////////////
void Terminate()
{
ClearDependants();
m_hwndClip = NULL;
m_psurfaceBack = NULL;
m_pddClipper = NULL;
m_pdds = NULL;
m_pdddevice = NULL;
m_pdddevicePrimary->Terminate();
if (m_pdddeviceSecondary != NULL) {
m_pdddeviceSecondary->Terminate();
}
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
DDDevice* GetCurrentDevice()
{
return m_pdddevice;
}
DDDevice* GetPrimaryDevice()
{
return m_pdddevicePrimary;
}
DDSDescription GetPrimaryDDSD()
{
DDSDescription ddsd;
DDCall(m_pdds->GetSurfaceDesc(&ddsd));
return ddsd;
}
//////////////////////////////////////////////////////////////////////////////
//
// Validation
//
//////////////////////////////////////////////////////////////////////////////
bool IsValid()
{
return m_pdddevicePrimary->IsValid();
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
void SetFocusWindow(Window* pwindow, bool bStartFullscreen)
{
//
// This function can only be called once
//
ZAssert(m_hwndFocus == NULL && pwindow->GetHWND() != NULL);
ZAssert(!m_bValid);
m_hwndFocus = pwindow->GetHWND();
m_bFullscreen = bStartFullscreen;
}
//////////////////////////////////////////////////////////////////////////////
//
// Device Initialization
//
//////////////////////////////////////////////////////////////////////////////
void UpdateSurfacesPixelFormat()
{
//
// Tell all the Device format surfaces their new pixel format
//
{
SurfaceList::Iterator iterSurface(m_listDeviceFormatSurfaces);
while (!iterSurface.End()) {
iterSurface.Value()->SetPixelFormat(m_ppf);
iterSurface.Next();
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// SetGammaRamp
//
//////////////////////////////////////////////////////////////////////////////
void SetGammaRamp()
{
if (m_pdds) {
TRef<IDirectDrawGammaControlX> pddGammaControl;
DDCall(m_pdds->QueryInterface(IID_IDirectDrawGammaControlX, (void**)&(pddGammaControl)));
DDGAMMARAMP gammaRamp;
for (int index = 0; index < 256; index ++) {
float value = (float)index / 255;
float level = pow(value, 1.0f / m_gamma);
//float level = (m_gamma - 1) + (1 - (m_gamma - 1)) * value;
int ilevel = MakeInt(level * 65535.0f);
gammaRamp.red [index] = ilevel;
gammaRamp.green[index] = ilevel;
gammaRamp.blue [index] = ilevel;
};
//
// zero is always black
//
gammaRamp.red [0] = 0;
gammaRamp.green[0] = 0;
gammaRamp.blue [0] = 0;
pddGammaControl->SetGammaRamp(0, &gammaRamp);
}
}
void SetGammaLevel(float value)
{
m_gamma = bound(value, 1.0f, 2.0f);
SetGammaRamp();
}
float GetGammaLevel()
{
return m_gamma;
}
//////////////////////////////////////////////////////////////////////////////
//
// Create Primary Surface
//
//////////////////////////////////////////////////////////////////////////////
bool CreatePrimarySurface()
{
//
// Create the surface
//
DDSDescription ddsd;
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
m_pdds = NULL;
DDCall(m_pdddevice->GetDD()->CreateSurface(&ddsd, &m_pdds, NULL));
if (m_pdds == NULL) {
return false;
}
//
// Update the gamma ramp
//
SetGammaRamp();
//
// Get the pixel format
//
DDCall(m_pdds->GetSurfaceDesc(&ddsd));
m_ppf = GetPixelFormat(ddsd.GetPixelFormat());
//
// Create a clipper for the surface
//
DDCall(m_pdddevice->GetDD()->CreateClipper(0, &m_pddClipper, NULL));
DDCall(m_pdds->SetClipper(m_pddClipper));
return true;
};
//////////////////////////////////////////////////////////////////////////////
//
// Switch to windowed
//
//////////////////////////////////////////////////////////////////////////////
bool InitializeWindowed()
{
if (g_bWindowLog) {
ZDebugOutput("InitializeWindowed\n");
}
//
// If we were fullscreen go back to windowed mode
//
if (m_pdddeviceFullscreen != NULL) {
if (g_bWindowLog) {
ZDebugOutput("SetCooperativeLevel(Normal)\n");
}
DDCall(m_pdddeviceFullscreen->GetDD()->SetCooperativeLevel(NULL, DDSCL_NORMAL));
m_pdddeviceFullscreen = NULL;
}
//
// Free up all the device specific objects
//
TerminateDevice();
//
// switch to the windowed device
//
m_pdddevice = m_pdddevicePrimary;
m_pointFullscreenCurrent = WinPoint(0, 0);
//
// Get the primary surface
//
if (!CreatePrimarySurface()) {
return false;
}
//
// If the primary surface isn't 16bpp go to fullscreen automatically
//
// KGJV 32B : if game bpp != desktop bpp go fullscreen
if (m_ppf->PixelBits() != m_dwBPP) {
m_bFullscreen = true;
return false;
}
//
// Update any device format surfaces
//
UpdateSurfacesPixelFormat();
if (g_bWindowLog) {
ZDebugOutput("InitializeWindowed exiting\n");
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Create Fullscreen Surface
//
//////////////////////////////////////////////////////////////////////////////
bool CreateFullscreenSurface(DDDevice* pdddevice, bool& bError)
{
bError = false;
HRESULT hr;
//
// Create a double buffered surface
//
DDSDescription ddsd;
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps =
DDSCAPS_PRIMARYSURFACE
| DDSCAPS_FLIP
| DDSCAPS_COMPLEX
| DDSCAPS_3DDEVICE;
ddsd.dwBackBufferCount = 1;
hr = pdddevice->GetDD()->CreateSurface(&ddsd, &m_pdds, NULL);
if (hr == DDERR_OUTOFVIDEOMEMORY) {
ZAssert(m_pdds == NULL);
if (g_bWindowLog) {
ZDebugOutput("Not enough memory for primary surface\n");
}
return false;
}
if (hr == DDERR_NOEXCLUSIVEMODE) {
ZAssert(m_pdds == NULL);
if (g_bWindowLog) {
ZDebugOutput("Exclusive mode was lost\n");
}
bError = true;
return false;
}
if (hr == DDERR_UNSUPPORTEDMODE) {
ZAssert(m_pdds == NULL);
if (g_bWindowLog) {
ZDebugOutput("Unsupported mode\n");
}
bError = true;
return false;
}
DDCall(hr);
if (m_pdds == NULL) {
return false;
}
//
// Create a clipper for the surface
//
#ifndef DREAMCAST
DDCall(pdddevice->GetDD()->CreateClipper(0, &m_pddClipper, NULL));
DDCall(m_pdds->SetClipper(m_pddClipper));
#endif
//
// Update the gamma ramp
//
SetGammaRamp();
//
// Get the pixel format
//
DDCall(m_pdds->GetSurfaceDesc(&ddsd));
m_ppf = GetPixelFormat(ddsd.GetPixelFormat());
//
// Create the ZBuffer
//
TRef<IDirectDrawSurfaceX> pddsZBuffer;
if (pdddevice->GetAllow3DAcceleration()) {
#ifdef DREAMCAST
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS | DDSD_ZBUFFERBITDEPTH;
ddsd.dwWidth = ddsd.dwWidth;
ddsd.dwHeight = ddsd.dwHeight;
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
ddsd.dwZBufferBitDepth = 16UL;
ddsd.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
ddsd.ddpfPixelFormat.dwZBufferBitDepth = 16UL;
#else
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS | DDSD_PIXELFORMAT;
ddsd.dwWidth = ddsd.dwWidth;
ddsd.dwHeight = ddsd.dwHeight;
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
ddsd.ddpfPixelFormat = pdddevice->GetZBufferPixelFormat()->GetDDPF();
#endif
hr = pdddevice->GetDD()->CreateSurface(&ddsd, &pddsZBuffer, NULL);
if (hr == DDERR_OUTOFVIDEOMEMORY) {
if (g_bWindowLog) {
ZDebugOutput("Not enough memory for ZBuffer\n");
}
m_pdds = NULL;
return false;
}
if (hr == DDERR_NOZBUFFERHW) {
if (g_bWindowLog) {
ZDebugOutput("Device doesn't support ZBuffers\n");
}
m_pdds = NULL;
return false;
}
DDCall(hr);
}
//
// Get the back buffer
//
DDSCaps caps;
caps.dwCaps = DDSCAPS_BACKBUFFER;
TRef<IDirectDrawSurfaceX> pddsBack;
DDCall(m_pdds->GetAttachedSurface(&caps, &pddsBack));
if (pddsBack == NULL) {
m_pdds = NULL;
return false;
}
//
// Attach the ZBuffer to the back buffer
//
if (pddsZBuffer) {
if (FAILED(pddsBack->AddAttachedSurface(pddsZBuffer))) {
m_pdds = NULL;
return false;
}
}
//
// Create a surface wrapper
//
SurfaceType stype = SurfaceType2D() | SurfaceType3D() | SurfaceTypeZBuffer() | SurfaceTypeVideo();
m_psurfaceBack =
CreatePrivateSurface(
this,
CreateDDSurface(
pdddevice,
pddsBack,
pddsZBuffer,
m_ppf,
NULL,
stype
),
NULL
);
//
// Fill the surface with black
//
m_psurfaceBack->FillSurface(Color::Black());
Flip();
m_psurfaceBack->FillSurface(Color::Black());
return true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Switch to a device at a certain resolution
//
//////////////////////////////////////////////////////////////////////////////
bool SwitchToFullscreenDevice(DDDevice* pdddevice, const WinPoint& size, bool& bError)
{
bError = false;
if (g_bWindowLog) {
ZDebugOutput(
"SwitchToFullscreenDevice( "
+ pdddevice->GetName()
+ ", resolution: "
+ GetString(size)
+ ")\n"
);
}
//
// If switching to a different device go to normal mode
//
if (m_pdddeviceFullscreen != NULL && m_pdddeviceFullscreen != pdddevice) {
if (g_bWindowLog) {
ZDebugOutput("SetCooperativeLevel(" + pdddevice->GetName() + ", Normal)\n");
}
DDCall(m_pdddeviceFullscreen->GetDD()->SetCooperativeLevel(NULL, DDSCL_NORMAL));
m_pdddeviceFullscreen = NULL;
}
//
// Free up all the device specific objects
//
TerminateDevice();
m_pdddevice = pdddevice;
//
// If this is a new fullscreen device go to exclusive mode
//
if (m_pdddeviceFullscreen != pdddevice) {
if (g_bWindowLog) {
ZDebugOutput("SetCooperativeLevel(" + pdddevice->GetName() + ", Exclusive)\n");
}
HRESULT hr =
pdddevice->GetDD()->SetCooperativeLevel(
m_hwndFocus,
DDSCL_EXCLUSIVE
| DDSCL_FULLSCREEN
);
if (hr == DDERR_EXCLUSIVEMODEALREADYSET) {
if (g_bWindowLog) {
ZDebugOutput("Can't set exclusive mode\n");
}
bError = true;
return false;
}
DDCall(hr);
m_pdddeviceFullscreen = pdddevice;
}
//
// Switch resolutions
//
HRESULT hr =
m_pdddevice->GetDD()->SetDisplayMode(
size.X(),
size.Y(),
m_dwBPP, // KGJV 32B - set as parameter
0,
0
);
if (
hr == DDERR_NOEXCLUSIVEMODE
|| hr == DDERR_UNSUPPORTED
) {
if (g_bWindowLog) {
ZDebugOutput("Error setting display mode\n");
}
bError = true;
return false;
}
if (hr == DDERR_INVALIDMODE) {
pdddevice->EliminateModes(size);
if (g_bWindowLog) {
ZDebugOutput("Invalid resolution\n");
}
return false;
}
DDCall(hr);
//
// Create the primary surface and back buffer
//
if (!CreateFullscreenSurface(pdddevice, bError)) {
return false;
}
//
// Everything worked. Update any device format surfaces.
//
UpdateSurfacesPixelFormat();
if (g_bWindowLog) {
ZDebugOutput("SwitchToFullscreenDevice exiting\n");
}
return true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Switch to full screen
//
//////////////////////////////////////////////////////////////////////////////
bool InitializeFullscreen(bool& bChanges)
{
if (g_bWindowLog) {
ZDebugOutput("InitalizeFullscreen()\n");
}
//
// Try the secondary device first
//
DDDevice* pdddevice;
if (
m_bAllowSecondary
&& m_bAllow3DAcceleration
&& m_b3DAccelerationImportant
&& m_pdddeviceSecondary != NULL
&& m_pdddeviceSecondary->GetAllow3DAcceleration()
) {
pdddevice = m_pdddeviceSecondary;
} else {
pdddevice = m_pdddevicePrimary;
}
//
// Don't do anything if we don't need to change the device
// or resolution
//
if (
m_bValidDevice
&& m_pdddevice == pdddevice
&& m_pointFullscreenCurrent == m_pointFullscreen
) {
ZDebugOutput("Device and resolution match\n");
return true;
}
//
// Try different resolutions until we find one that actually works
//
bChanges = true;
while (true) {
//
// Try the current resolution
//
bool bError;
if (SwitchToFullscreenDevice(pdddevice, m_pointFullscreen, bError)) {
m_pointFullscreenCurrent = m_pointFullscreen;
return true;
}
//
// If there was an error just return
//
if (bError) {
return false;
}
//
// Didn't work goto to the next lower resolution
//
WinPoint pointNew = pdddevice->PreviousMode(m_pointFullscreen);
if (pointNew == m_pointFullscreen) {
if (g_bWindowLog) {
ZDebugOutput("No more valid resolutions\n");
}
return false;
}
m_pointFullscreen = pointNew;
}
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
void DebugSetWindowed()
{
#ifndef DREAMCAST
if (m_pdddevice != NULL) {
m_pdddevice->GetDD()->SetCooperativeLevel(NULL, DDSCL_NORMAL);
}
#endif
}
//////////////////////////////////////////////////////////////////////////////
//
// Set Attributes
//
//////////////////////////////////////////////////////////////////////////////
void SetAllowSecondary(bool bAllowSecondary)
{
if (m_bAllowSecondary != bAllowSecondary) {
m_bAllowSecondary = bAllowSecondary;
m_bValid = false;
m_bValidDevice = false;
}
}
void SetAllow3DAcceleration(bool bAllow3DAcceleration)
{
if (m_bAllow3DAcceleration != bAllow3DAcceleration) {
m_bAllow3DAcceleration = bAllow3DAcceleration;
m_pdddevicePrimary->SetAllow3DAcceleration(m_bAllow3DAcceleration);
m_bValid = false;
m_bValidDevice = false;
}
}
// yp Your_Persona August 2 2006 : MaxTextureSize Patch
void SetMaxTextureSize(DWORD dwMaxTextureSize)
{
if (m_dwMaxTextureSize != dwMaxTextureSize)
{
m_dwMaxTextureSize = dwMaxTextureSize;
m_pdddevicePrimary->SetMaxTextureSize(m_dwMaxTextureSize);
m_bValid = false;
m_bValidDevice = false;
}
}
void Set3DAccelerationImportant(bool b3DAccelerationImportant)
{
if (m_b3DAccelerationImportant != b3DAccelerationImportant) {
m_b3DAccelerationImportant = b3DAccelerationImportant;
m_bValid = false;
}
}
void SetFullscreen(bool bFullscreen)
{
if (m_bFullscreen != bFullscreen) {
m_bFullscreen = bFullscreen;
m_bValid = false;
m_bValidDevice = false;
}
}
void SetFullscreenSize(const WinPoint& point)
{
if (g_bWindowLog) {
ZDebugOutput("Engine::SetFullscreenSize(" + GetString(point) + ")\n");
}
if (m_pointFullscreen != point) {
m_pointFullscreen = point;
m_bValid = false;
}
if (g_bWindowLog) {
ZDebugOutput("Engine::SetFullscreenSize() Exiting\n");
}
}
void ChangeFullscreenSize(bool bLarger)
{
WinPoint point;
if (bLarger) {
point = m_pdddevice->NextMode(m_pointFullscreen);
} else {
point = m_pdddevice->PreviousMode(m_pointFullscreen);
}
SetFullscreenSize(point);
}
//////////////////////////////////////////////////////////////////////////////
//
// Get Attributes
//
//////////////////////////////////////////////////////////////////////////////
bool GetAllowSecondary()
{
return m_bAllowSecondary;
}
bool GetAllow3DAcceleration()
{
return m_bAllow3DAcceleration;
}
bool Get3DAccelerationImportant()
{
return m_b3DAccelerationImportant;
}
const WinPoint& GetFullscreenSize()
{
return m_pointFullscreen;
}
bool IsFullscreen()
{
return m_bFullscreen;
}
bool PrimaryHas3DAcceleration()
{
return
m_pdddevicePrimary->Has3DAcceleration()
&& (m_pdddevicePrimary->GetZBufferPixelFormat() != NULL);
}
ZString GetDeviceName()
{
return m_pdddevice->GetName();
}
bool GetUsing3DAcceleration()
{
return m_pdddevice->GetAllow3DAcceleration();
}
PrivateSurface* GetBackBuffer()
{
return m_psurfaceBack;
}
ZString GetPixelFormatName()
{
return ZString("Bits per pixel = ") + ZString((int)(GetPrimaryPixelFormat()->PixelBits()));
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
bool DeviceOK(bool& bChanges)
{
if (!m_bValid) {
if (m_bFullscreen) {
m_bValid = InitializeFullscreen(bChanges);
} else {
bChanges = true;
m_bValid = InitializeWindowed();
}
m_bValidDevice = m_bValid;
}
return m_bValid;
}
bool IsDeviceReady(bool& bChanges)
{
bChanges = false;
if (m_pdddevice) {
HRESULT hr = m_pdddevice->TestCooperativeLevel();
switch (hr) {
case DD_OK:
return DeviceOK(bChanges);
case DDERR_NOEXCLUSIVEMODE:
//
// fullscreen but not active
//
m_bValidDevice = false;
m_bValid = false;
break;
case DDERR_EXCLUSIVEMODEALREADYSET:
//
// windowed somebody else is fullscreen
//
m_bValidDevice = false;
m_bValid = false;
break;
case DDERR_WRONGMODE:
//
// windowed the pixel depth has changed
//
m_pdddevicePrimary->Reset(NULL);
m_bValidDevice = false;
m_bValid = false;
return DeviceOK(bChanges);
default:
ZError("Unexpected result\n");
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////
//
// Screen updates
//
//////////////////////////////////////////////////////////////////////////////
void Flip()
{
ZAssert(m_pdddeviceFullscreen);
DDSurface* pddsurface; CastTo(pddsurface, m_psurfaceBack->GetVideoSurface());
pddsurface->GetDDSX();
HRESULT hr = m_pdds->Flip(NULL, DDFLIP_WAIT);
if (
hr == DDERR_NOEXCLUSIVEMODE
|| hr == DDERR_SURFACELOST
) {
// These errors are ok if we are no longer active.
} else {
DDCall(hr);
}
}
void BltToWindow(Window* pwindow, const WinPoint& point, Surface* psurface, const WinRect& rectSource)
{
if (m_pdddeviceFullscreen == NULL) {
if (m_hwndClip != pwindow->GetHWND()) {
m_hwndClip = pwindow->GetHWND();
DDCall(m_pddClipper->SetHWnd(0, m_hwndClip));
}
m_pointPrimary = pwindow->ClientToScreen(WinPoint(0, 0));
WinRect
rectTarget(
m_pointPrimary + point,
m_pointPrimary + point + rectSource.Size()
);
PrivateSurface* pprivateSurface; CastTo(pprivateSurface, psurface);
DDSurface* pddsurface; CastTo(pddsurface, pprivateSurface->GetVideoSurface());
HRESULT hr =
m_pdds->Blt(
(RECT*)&rectTarget,
pddsurface->GetDDSX(),
(RECT*)&rectSource,
DDBLT_WAIT,
NULL
);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Pixel Format cache
//
//////////////////////////////////////////////////////////////////////////////
TVector<TRef<PixelFormat> > m_ppfs;
TRef<PixelFormat> GetPixelFormat(const DDPixelFormat& ddpf)
{
int count = m_ppfs.GetCount();
for(int index = 0; index < count; index++) {
if (m_ppfs[index]->Equivalent(ddpf)) {
return m_ppfs[index];
}
}
TRef<PixelFormat> ppf = new PixelFormat(ddpf);
m_ppfs.PushEnd(ppf);
return ppf;
}
TRef<PixelFormat> GetPixelFormat(
int bits,
DWORD redMask,
DWORD greenMask,
DWORD blueMask,
DWORD alphaMask
) {
DDPixelFormat ddpf;
ddpf.dwSize = sizeof(DDPIXELFORMAT);
ddpf.dwFlags = DDPF_RGB;
ddpf.dwFourCC = 0;
ddpf.dwRGBBitCount = bits;
ddpf.dwRBitMask = redMask;
ddpf.dwGBitMask = greenMask;
ddpf.dwBBitMask = blueMask;
ddpf.dwRGBAlphaBitMask = alphaMask;
return GetPixelFormat(ddpf);
}
PixelFormat* GetPrimaryPixelFormat()
{
return m_ppf;
}
//////////////////////////////////////////////////////////////////////////////
//
// Performance Counters
//
//////////////////////////////////////////////////////////////////////////////
int GetTotalTextureMemory() { return m_pdddevice->GetTotalTextureMemory(); }
int GetAvailableTextureMemory() { return m_pdddevice->GetAvailableTextureMemory(); }
int GetTotalVideoMemory() { return m_pdddevice->GetTotalVideoMemory(); }
int GetAvailableVideoMemory() { return m_pdddevice->GetAvailableVideoMemory(); }
//////////////////////////////////////////////////////////////////////////////
//
// Surface Cache
//
//////////////////////////////////////////////////////////////////////////////
void AddDeviceDependant(DeviceDependant* pdeviceDependant)
{
m_listDeviceDependant.PushFront(pdeviceDependant);
}
void RemoveDeviceDependant(DeviceDependant* pdeviceDependant)
{
m_listDeviceDependant.Remove(pdeviceDependant);
}
void RemovePrivateSurface(PrivateSurface* psurface)
{
//
// Remove from the surface lists
//
m_listDeviceFormatSurfaces.Remove(psurface);
m_listSurfaces.Remove(psurface);
//
// free up any device textures
//
DDSurface* pddsurface; CastTo(pddsurface, psurface->GetVideoSurfaceNoAlloc());
if (pddsurface) {
m_pdddevicePrimary->RemoveSurface(pddsurface);
if (m_pdddeviceSecondary != NULL) {
m_pdddeviceSecondary->RemoveSurface(pddsurface);
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// VideoSurface Constructors
//
//////////////////////////////////////////////////////////////////////////////
TRef<VideoSurface> CreateVideoSurface(
SurfaceType stype,
PixelFormat* ppf,
PrivatePalette* ppalette,
const WinPoint& size,
int pitch,
BYTE* pbits
) {
if (stype.Test(SurfaceTypeVideo())) {
return
CreateDDSurface(
m_pdddevice,
stype,
m_ppf,
NULL,
size
);
} else {
PrivatePalette* pprivatePalette; CastTo(pprivatePalette, ppalette);
return
CreateDDSurface(
m_pdddevicePrimary,
stype,
ppf,
ppalette,
size,
pitch,
pbits
);
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Surface Constructors
//
//////////////////////////////////////////////////////////////////////////////
TRef<PrivateSurface> AddSurface(PrivateSurface* psurface, bool bDevice)
{
m_listSurfaces.PushEnd(psurface);
if (bDevice) {
m_listDeviceFormatSurfaces.PushEnd(psurface);
}
return psurface;
}
//////////////////////////////////////////////////////////////////////////////
//
// Create a surface with the specified pixel format
//
//////////////////////////////////////////////////////////////////////////////
TRef<Surface> CreateSurface(
const WinPoint& size,
PixelFormat* ppf,
Palette* ppalette,
SurfaceType stype,
SurfaceSite* psite
) {
PrivatePalette* pprivatePalette; CastTo(pprivatePalette, ppalette);
return
AddSurface(
CreatePrivateSurface(
this,
ppf,
pprivatePalette,
size,
stype,
psite
),
false
);
}
//////////////////////////////////////////////////////////////////////////////
//
// Create a device format surface
//
//////////////////////////////////////////////////////////////////////////////
TRef<Surface> CreateSurface(
const WinPoint& size,
SurfaceType stype,
SurfaceSite* psite
) {
if (stype.Test(SurfaceTypeVideo())) {
TRef<DDSurface> pddsurface =
CreateDDSurface(
m_pdddevice,
stype,
m_ppf,
NULL,
size
);
if (pddsurface != NULL) {
TRef<PrivateSurface> psurface = CreatePrivateSurface(this, pddsurface, psite);
return AddSurface(psurface, true);
}
return NULL;
} else {
return
AddSurface(
CreatePrivateSurface(
this,
m_ppf,
NULL,
size,
stype,
psite
),
true
);
}
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
TRef<PrivateSurface> CreateCompatibleSurface(
PrivateSurface* psurface,
const WinPoint& size,
SurfaceType stype,
SurfaceSite* psite
) {
PrivatePalette* pprivatePalette; CastTo(pprivatePalette, psurface->GetPalette());
return
AddSurface(
CreatePrivateSurface(
this,
psurface->GetPixelFormat(),
pprivatePalette,
size,
stype,
psite
),
false
);
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
TRef<Surface> CreateSurface(HBITMAP hbitmap)
{
//
// Get the bitmap size
//
BITMAP bm;
ZVerify(::GetObject(hbitmap, sizeof(bm), &bm));
//
// Create a DC for the bitmap
//
HDC hdcBitmap = ::CreateCompatibleDC(NULL);
ZAssert(hdcBitmap != NULL);
HBITMAP hbitmapOld = (HBITMAP)::SelectObject(hdcBitmap, hbitmap);
ZAssert(hbitmapOld != NULL);
//
// Create a surface whose pixel format matches the bitmap
//
DDPixelFormat ddpf;
TRef<IDirectDrawPaletteX> pddpal;
ZVerify(FillDDPF(ddpf, m_pdddevicePrimary->GetDD(), hdcBitmap, hbitmap, &pddpal));
TRef<PrivatePalette> ppalette;
if (pddpal) {
ppalette = CreatePaletteImpl(pddpal);
}
//
// Create the source surface
//
TRef<PrivateSurface> psurface =
CreatePrivateSurface(
this,
GetPixelFormat(ddpf),
ppalette,
WinPoint(bm.bmWidth, bm.bmHeight),
SurfaceType2D(),
NULL
);
//
// Copy the bitmap to the surface
//
psurface->BitBltFromDC(hdcBitmap);
//
// Release the DC we created
//
ZVerify(::SelectObject(hdcBitmap, hbitmapOld));
ZVerify(::DeleteDC(hdcBitmap));
return AddSurface(psurface, false);
}
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
TRef<Surface> CreateSurface(
const WinPoint& size,
PixelFormat* ppf,
Palette* ppalette,
int pitch,
BYTE* pdata,
IObject* pobjectMemory
) {
PrivatePalette* pprivatePalette; CastTo(pprivatePalette, ppalette);
return
AddSurface(
CreatePrivateSurface(
this,
ppf,
pprivatePalette,
size,
pitch,
pdata,
pobjectMemory
),
false
);
}
};
//////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////
// KGJV 32B - BPP parameter
TRef<Engine> CreateEngine(bool bAllow3DAcceleration, bool bAllowSecondary, DWORD dwBPP)
{
return new EngineImpl(bAllow3DAcceleration, bAllowSecondary, dwBPP);
}