Files
Hellfire/DX.CPP
T
Justin Marshall 101266ab72 Initial commit.
2026-04-27 10:35:40 -07:00

368 lines
10 KiB
C++

//******************************************************************
// dx.cpp
//******************************************************************
#include "diablo.h"
#pragma hdrstop
#include "storm/h/storm.h"
#include "palette.h"
#include "engine.h"
#include "resource.h"
#include "gendung.h"
//******************************************************************
// extern
//******************************************************************
void myDebugBreak();
void ErrorDlg(int nDlgId,DWORD dwErr,const char * pszFile,int nLine);
//******************************************************************
// public
//******************************************************************
BYTE * gpBuffer;
LPDIRECTDRAW lpDD; // DirectDraw object
LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw primary surface
LPDIRECTDRAWSURFACE lpDDSBackBuf; // optional back buffer
LPDIRECTDRAWPALETTE lpDDPal; // DirectDraw palette
BYTE gbForceBackBuf = FALSE;
BYTE gbUseDDEmulation = FALSE;
//******************************************************************
// private
//******************************************************************
static DWORD sgdwLockCount;
static CCritSect sgDrawCrit;
static BYTE * sgpBackBuf;
static HINSTANCE sghDDlib = NULL;
#ifndef NDEBUG
static DWORD sgdwLockTbl[256];
#endif
//******************************************************************
//******************************************************************
static void init_backbuf() {
app_assert(! gpBuffer);
app_assert(! sgdwLockCount);
app_assert(! sgpBackBuf);
// can we lock the primary surface?
DDSCAPS caps;
DDSURFACEDESC ddsd;
app_assert(lpDDSPrimary);
HRESULT ddrval = lpDDSPrimary->GetCaps(&caps);
ddraw_assert(ddrval);
app_assert(caps.dwCaps & DDSCAPS_PRIMARYSURFACE);
// is this a lockable surface?
extern BYTE gbForceBackBuf;
if (! gbForceBackBuf) {
ddsd.dwSize = sizeof(ddsd);
ddrval = lpDDSPrimary->Lock(NULL,&ddsd,DDLOCK_WAIT|DDLOCK_WRITEONLY,NULL);
if (ddrval == DD_OK) {
ddrval = lpDDSPrimary->Unlock(NULL);
// pjw.patch1.start.1/13/97
// commented out -- in NT it is possible to
// lose a video surface while it is locked
// ddraw_assert(ddrval);
// pjw.patch1.end.1/13/97
// surface is lockable, just create an offscreen memory buffer
sgpBackBuf = DiabloAllocPtrSig(BUFFERSIZE,'OFFS');
return;
}
// non-lockable surface?
if (ddrval != DDERR_CANTLOCKSURFACE)
ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
}
// create a secondary surface and lock it permanently
ZeroMemory(&ddsd,sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
ddsd.dwHeight = BUFFERY;
ddsd.dwWidth = BUFFERX;
ddsd.lPitch = BUFFERX;
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddrval = lpDDSPrimary->GetPixelFormat(&ddsd.ddpfPixelFormat);
if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
ddrval = lpDD->CreateSurface(&ddsd,&lpDDSBackBuf,NULL);
if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
}
//******************************************************************
//******************************************************************
static void init_primary() {
DDSURFACEDESC ddsd;
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
HRESULT ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
}
//******************************************************************
//******************************************************************
static HRESULT InDirectDrawCreate(
GUID * lpGUID,
LPDIRECTDRAW * lplpDD,
IUnknown * pUnkOuter
) {
// bind to DirectDrawCreate
typedef HRESULT (WINAPI * DDCREATETYPE)(GUID *,LPDIRECTDRAW *,IUnknown *);
DDCREATETYPE ddcreatefunc = (DDCREATETYPE)SDirectDrawCreate;
if (! ddcreatefunc) ErrorDlg(IDD_DDRAW_DLL_ERR,GetLastError(),__FILE__,__LINE__);
// call DirectDrawCreate
return ddcreatefunc(lpGUID,lplpDD,pUnkOuter);
}
//******************************************************************
//******************************************************************
void init_directx(HWND hWnd) {
HRESULT ddrval;
app_assert(! gpBuffer);
app_assert(! sgdwLockCount);
app_assert(! sgpBackBuf);
SetFocus(hWnd);
ShowWindow(hWnd,SW_SHOWNORMAL);
extern BYTE gbUseDDEmulation;
GUID * lpGUID = NULL;
if (gbUseDDEmulation) lpGUID = (GUID *) DDCREATE_EMULATIONONLY;
ddrval = InDirectDrawCreate(lpGUID,&lpDD,NULL);
if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
#if !ALLOW_WINDOWED_MODE
fullscreen = TRUE;
#endif
#if ALLOW_WINDOWED_MODE
if (!fullscreen) {
ddrval = lpDD->SetCooperativeLevel(hWnd,DDSCL_NORMAL | DDSCL_ALLOWREBOOT);
if (ddrval == DDERR_EXCLUSIVEMODEALREADYSET) myDebugBreak();
else if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
// turn off "topmost" flag so that we don't stick above debugger
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
else {
#endif
// Get exclusive mode
ddrval = lpDD->SetCooperativeLevel(hWnd,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
if (ddrval == DDERR_EXCLUSIVEMODEALREADYSET) myDebugBreak();
else if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
// Set the video mode to 640x480x8
ddrval = lpDD->SetDisplayMode( 640, 480, 8);
// pjw.patch1.start.1/13/97
// some notebook computers can't switch resolutions -- but
// we should be able to switch the color depth to 256 ???
if (ddrval != DD_OK) {
int nWdt = GetSystemMetrics(SM_CXSCREEN);
int nHgt = GetSystemMetrics(SM_CYSCREEN);
ddrval = lpDD->SetDisplayMode(nWdt, nHgt, 8);
}
// pjw.patch1.end.1/13/97
if (ddrval != DD_OK) ErrorDlg(IDD_DDRAW_ERR,ddrval,__FILE__,__LINE__);
#if ALLOW_WINDOWED_MODE
}
#endif
init_primary();
CreatePalette();
// Do not allow gdi batching
GdiSetBatchLimit(1);
// Get the full offscreen buffer including edges
init_backbuf();
// inform STORM library of our DirectDraw objects
BOOL bSuccess = SDrawManualInitialize(
hWnd, // window
lpDD, // direct draw
lpDDSPrimary, // primary
NULL, // secondary
NULL, // system
lpDDSBackBuf, // temporary
lpDDPal, // palette
NULL // gdi palette
);
app_assert(bSuccess);
}
//******************************************************************
//******************************************************************
static void lock_buf_priv() {
// don't allow any other threads access to the draw
// buffer while we have it locked
sgDrawCrit.Enter();
if (sgpBackBuf) {
gpBuffer = sgpBackBuf;
}
else if (! lpDDSBackBuf) {
// if the back buffer was destroyed by another thread
// it is because it is fataling...give it a chance to
// shut down the system before performing our own fatal
Sleep(20000);
app_fatal("lock_buf_priv");
}
else if (! sgdwLockCount) {
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(ddsd);
HRESULT ddrval = lpDDSBackBuf->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL);
ddraw_assert(ddrval);
gpBuffer = (BYTE *) ddsd.lpSurface;
app_assert(gpBuffer);
glClipY += (long) gpBuffer;
}
// increment lock count
sgdwLockCount++;
}
//******************************************************************
//******************************************************************
void lock_buf(BYTE bFcn) {
// for debugging -- make sure no lock count over/underflow
#ifndef NDEBUG
sgdwLockTbl[bFcn]++;
#endif
lock_buf_priv();
}
//******************************************************************
//******************************************************************
static void unlock_buf_priv() {
if (! sgdwLockCount) app_fatal("draw main unlock error");
if (! gpBuffer) app_fatal("draw consistency error");
if (! sgpBackBuf) app_assert(lpDDSBackBuf);
// decrement lock count
sgdwLockCount--;
if (! sgdwLockCount) {
glClipY -= (long) gpBuffer;
gpBuffer = NULL;
if (! sgpBackBuf) {
HRESULT ddrval = lpDDSBackBuf->Unlock(NULL);
ddraw_assert(ddrval);
}
}
sgDrawCrit.Leave();
}
//******************************************************************
//******************************************************************
void unlock_buf(BYTE bFcn) {
// for debugging -- make sure no lock count over/underflow
#ifndef NDEBUG
if (! sgdwLockTbl[bFcn]) app_fatal("Draw lock underflow: 0x%x",bFcn);
sgdwLockTbl[bFcn]--;
#endif
unlock_buf_priv();
}
//******************************************************************
// THIS FUNCTION MAY BE CALLED FROM ANY THREAD IN THE PROGRAM
// ALL OTHER PUBLIC FUNCTIONS IN THIS MODULE MAY ONLY BE CALLED
// FROM THE MAIN APPLICATION THREAD!
//******************************************************************
void free_directx() {
if (ghMainWnd) ShowWindow(ghMainWnd,SW_HIDE);
// tell SDraw that we're about to kill off direct draw
// so it doesn't try to re-use freed objects
SDrawDestroy();
sgDrawCrit.Enter();
if (sgpBackBuf) {
app_assert(! lpDDSBackBuf);
DiabloFreePtr(sgpBackBuf);
}
else if (lpDDSBackBuf) {
lpDDSBackBuf->Release();
lpDDSBackBuf = NULL;
}
sgdwLockCount = 0;
gpBuffer = NULL;
sgDrawCrit.Leave();
if (lpDDSPrimary) {
lpDDSPrimary->Release();
lpDDSPrimary = NULL;
}
if (lpDDPal) {
lpDDPal->Release();
lpDDPal = NULL;
}
if (lpDD) {
lpDD->Release();
lpDD = NULL;
}
// cannot free library now, still may be in use
// by directX window procedure...
/*
if (sghDDlib) {
FreeLibrary(sghDDlib);
sghDDlib = NULL;
}
*/
}
//******************************************************************
//******************************************************************
void ddraw_switch_modes() {
sgDrawCrit.Enter();
app_assert(ghMainWnd);
void savecrsr_reset();
savecrsr_reset();
// remove any locks this thread has on buffer
DWORD dwSaveCount = sgdwLockCount;
while (sgdwLockCount) unlock_buf_priv();
free_directx();
force_redraw = FULLDRAW;
init_directx(ghMainWnd);
// restore locks
while (dwSaveCount--) lock_buf_priv();
sgDrawCrit.Leave();
}
//******************************************************************
//******************************************************************
void ddraw_reinit() {
ddraw_switch_modes();
}