avp/3dc/win95/DD_FUNC.CPP
Rebellion Developments 218ca90543 Import Aliens vs Predator - Gold (Build 116)
Source code release, imported from:
https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code

All text files were converted to Unix format.
2019-08-19 05:45:17 +02:00

2260 lines
56 KiB
C++

extern "C" {
#include "3dc.h"
#include "vramtime.h"
#include "dxlog.h"
#include "inline.h"
#include "scrshot.hpp"
#include "awTexLd.h" // to set the surface format for Aw gfx dd surface loads
#define UseLocalAssert No
#include "ourasert.h"
// for 640x480x8 experiment
#define InterlaceExperiment No
// In as separate define to debug because we
// might want to leave it even in a published
// game.
#define AllowReboot Yes
// In as #define since there is no
// obvious good behaviour on failure
#define CheckForModeXInSubWindow No
// Temporary hack!
#define NoPalette No
extern void TimeStampedMessage(char *s);
// Nasty hack to try and fix non-appearance of font
// on some machines, probably due to there not being
// enough video memory for the font and BltFast
// not working outside display memory.
// According to Roxby, source colour keying won't work
// on Blt in the Beta 3, so expect a grotty font with this on.
// PS Source colour keying works, but the font
// still doesn't appear on my machine in SubWindow
// mode... Ho hum...
#define NoBltFastOnFont No
// Check to see if video mode is valid
// and rewrite it if it isn't reported
#define CheckVideoMode No
/*
Globals
*/
LPDIRECTDRAW lpDD; // DirectDraw object
LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw primary surface
LPDIRECTDRAWSURFACE lpDDSBack; // DirectDraw back surface
LPDIRECTDRAWSURFACE lpDDSHiddenBack; // for system memory rendering target, stable configuration
LPDIRECTDRAWPALETTE lpDDPal[MaxPalettes]; // DirectDraw palette
#if debug || PreBeta
LPDIRECTDRAWSURFACE lpDDDbgFont; // Debugging font, specific to current video mode
#endif
// For SubWindow mode
LPDIRECTDRAWCLIPPER lpDDClipper;
// DirectDraw gdi surface
LPDIRECTDRAWSURFACE lpDDGDI;
int VideoModeColourDepth;
long BackBufferPitch;
// To describe available video hardware
int TotalVideoMemory;
int NumAvailableVideoModes;
VIDEOMODEINFO AvailableVideoModes[MaxAvailableVideoModes];
// Must be kept up to date with jump table!!!!
VIDEOMODEINFO EngineVideoModes[] = {
// Mode 320x200x8
320, // width
200, // height
8, // colour depth (bits per pixel)
// Mode 320x200x8T
320, // width
200, // height
8, // colour depth (bits per pixel)
// Mode 320x200x15
320, // width
200, // height
16, // colour depth (bits per pixel)
// Mode 320x240x8
320, // width
240, // height
8, // colour depth (bits per pixel)
// Mode 640x480x8
640, // width
480, // height
8, // colour depth (bits per pixel)
// Mode 640x480x8T
640, // width
480, // height
8, // colour depth (bits per pixel)
// Mode 640x480x15
640, // width
480, // height
16, // colour depth (bits per pixel)
// Mode 640x480x24
640, // width
480, // height
24 // colour depth (bits per pixel)
};
// Flag for backdrop composition
// for 640x480x8 experiment
#if InterlaceExperiment
int oddDraw;
#endif
// Surface for Backdrop composition
LPDIRECTDRAWSURFACE lpDDBackdrop;
// Pointer into Backdrop DD surface
unsigned char* BackScreenBuffer;
// Pitch on auxilliary backdrop surface
static long BackScreenPitch;
DDPIXELFORMAT DisplayPixelFormat;
// For locking against other processes, e.g.
// mouse pointer display
unsigned char GlobalFlipLock = No;
/* Externs */
extern int VideoMode;
extern int VideoModeTypeScreen;
extern int VideoModeType;
extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
extern unsigned char *ScreenBuffer;
extern HWND hWndMain;
extern unsigned char LPTestPalette[];
extern unsigned char TestPalette[];
extern int WindowMode;
extern WINSCALEXY TopLeftSubWindow;
extern WINSCALEXY ExtentXYSubWindow;
extern int WinWidth;
extern int WinHeight;
extern int WinLeftX;
extern int WinTopY;
extern int WinRightX;
extern int WinBotY;
extern int DXMemoryMode;
extern int RasterisationRequestMode;
extern int DXMemoryRequestMode;
extern int WindowRequestMode;
extern int VideoRequestMode;
extern int ZBufferRequestMode;
extern int SoftwareScanDrawRequestMode;
extern unsigned char AttemptVideoModeRestart;
extern VIDEORESTARTMODES VideoRestartMode;
extern BOOL MMXAvailable;
extern BOOL D3DHardwareAvailable;
extern int cosine[];
extern int sine[];
BOOL really_32_bit = 0;
void GenerateDirectDrawSurface()
{
DDCAPS ddcaps;
HRESULT ddrval;
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
unsigned char Mode8T;
// Check for combination of a MODEX type mode
// and SubWindowing
#if AllowReboot
// THIS MAY NOT WORK!!!
if (WindowMode == WindowModeSubWindow)
ddrval = lpDD->SetCooperativeLevel(hWndMain,
DDSCL_NORMAL);
else
ddrval = lpDD->SetCooperativeLevel(hWndMain,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT );
LOGDXERR(ddrval);
#else
// More stable even if crashes cannot be booted
// out of?
if (WindowMode == WindowModeSubWindow)
ddrval = lpDD->SetCooperativeLevel(hWndMain,
DDSCL_NORMAL);
else
ddrval = lpDD->SetCooperativeLevel(hWndMain,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX);
LOGDXERR(ddrval);
#endif
TimeStampedMessage("Allow reboot thingy");
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x2);
}
#else
return;
#endif
switch (ScreenDescriptorBlock.SDB_ScreenDepth)
{
case VideoModeType_8:
VideoModeColourDepth = 8;
Mode8T = No;
break;
case VideoModeType_15:
VideoModeColourDepth = 16;
Mode8T = No;
break;
case VideoModeType_24:
if (really_32_bit)
VideoModeColourDepth = 32;
else
VideoModeColourDepth = 24;
Mode8T = No;
break;
case VideoModeType_8T:
VideoModeColourDepth = 8;
Mode8T = Yes;
break;
default:
VideoModeColourDepth = 16; // default is 16 bit colour
break;
}
// Note that SetDisplayMode is now technically part
// of the DirectDraw2 COM interface, not DirectDraw.
// However, as long as we do not wish to change
// monitor refresh rates we do not need to use the
// DirectDraw2 version or set up a separate secondary
// DD interface object, which be just plain fiddly.
// MAY NOT WORK LIKE THIS IN SUBWINDOW MODE!!!!
if (WindowMode == WindowModeFullScreen)
{
ddrval = lpDD->SetDisplayMode(ScreenDescriptorBlock.SDB_Width,
ScreenDescriptorBlock.SDB_Height, VideoModeColourDepth);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
if ((ddrval == DDERR_INVALIDMODE) ||
(ddrval == DDERR_GENERIC) ||
(ddrval == DDERR_INVALIDPIXELFORMAT))
{
AttemptVideoModeRestart = Yes;
VideoRestartMode = RestartDisplayModeNotAvailable;
}
return;
}
#endif
}
TimeStampedMessage("after SetDisplayMode");
// Create primary surface and back buffer
// IMPORTANT!!! Currently no support for triple
// buffering in SubWindow mode!!!
if (WindowMode == WindowModeSubWindow)
{
// Create primary
memset(&ddsd,0,sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_CAPS;
// Request a 3D capable device so that
// Direct3D accesses will work
// note primary must be in video memory
ddsd.ddsCaps.dwCaps = (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE);
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x41);
}
#else
return;
#endif
// Create back buffer
memset(&ddsd,0,sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwHeight = ScreenDescriptorBlock.SDB_Height;
ddsd.dwWidth = ScreenDescriptorBlock.SDB_Width;
// Request a 3D capable device so that
// Direct3D accesses will work
if (DXMemoryMode == SystemMemoryPreferred)
ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE);
else // video memory if possible
ddsd.ddsCaps.dwCaps= (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE);
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x5);
}
#else
return;
#endif
// Create clipper objects
ddrval = lpDD->CreateClipper(0, &lpDDClipper, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x55);
}
#else
return;
#endif
ddrval = lpDDClipper->SetHWnd(0, hWndMain);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x51);
}
#else
return;
#endif
ddrval = lpDDSPrimary->SetClipper(lpDDClipper);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x52);
}
#else
return;
#endif
}
else // default to FullScreen...
{
TimeStampedMessage("after 'default to FullScreen'");
if (DXMemoryMode == VideoMemoryPreferred)
{
ddcaps.dwSize = sizeof (ddcaps);
memset (&ddsd, 0, sizeof (ddsd));
ddsd.dwSize = sizeof (ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
// Request a 3D capable device so that
// Direct3D accesses will work
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX |
DDSCAPS_3DDEVICE;
ddsd.dwBackBufferCount = 1;
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
LOGDXERR(ddrval);
TimeStampedMessage("after vm CreateSurface");
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x41);
}
#else
{
// For dubious modex emulation
// problem fix and dubious driver
// cannot change to different bit depths
// fix.
// Note that this must be kept up to date!!!!
if ((ddrval == DDERR_OUTOFVIDEOMEMORY) &&
((VideoMode == VideoMode_DX_320x200x8) ||
(VideoMode == VideoMode_DX_320x200x8T) ||
(VideoMode == VideoMode_DX_320x240x8) ||
(VideoMode == VideoMode_DX_320x200x15)))
{
AttemptVideoModeRestart = Yes;
VideoRestartMode = RestartOutOfVidMemForPrimary;
}
else if ((ddrval == DDERR_INVALIDMODE) ||
(ddrval == DDERR_GENERIC) ||
(ddrval == DDERR_INVALIDPIXELFORMAT))
{
AttemptVideoModeRestart = Yes;
VideoRestartMode = RestartDisplayModeNotAvailable;
}
return;
}
#endif
// get a pointer to the back buffer
// DO I NEED TO SET A SIZE FIELD HERE??
// SEEMS I _CAN'T_, ANYWAY...
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack);
LOGDXERR(ddrval);
TimeStampedMessage("after vm GetAttachedSurface");
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x5);
}
#else
return;
#endif
}
// assume we want a system memory
// rendering target, e.g. for MMX
else
{
DDPIXELFORMAT TempPixelFormat;
// Make primary, with back buffer in video memory
ddcaps.dwSize = sizeof (ddcaps);
memset (&ddsd, 0, sizeof (ddsd));
ddsd.dwSize = sizeof (ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
// Request a 3D capable device so that
// Direct3D accesses will work
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX |
DDSCAPS_3DDEVICE;
ddsd.dwBackBufferCount = 1;
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
LOGDXERR(ddrval);
TimeStampedMessage("after vm CreateSurface");
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
return;
}
#endif
// get a pointer to the back buffer
// Note that in this configuration the back
// buffer is hidden from the rendering system,
// since other configurations do not seem to be
// stable in ModeX emulation modes
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = lpDDSPrimary->GetAttachedSurface(
&ddscaps,
&lpDDSHiddenBack);
LOGDXERR(ddrval);
TimeStampedMessage("after vm GetAttachedSurface");
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
return;
#endif
// Save pixel format of primary
memcpy(&TempPixelFormat, &ddsd.ddpfPixelFormat,
sizeof(DDPIXELFORMAT));
TimeStampedMessage("after memcpy 1");
// Create rendering target
memset(&ddsd,0,sizeof(DDSURFACEDESC));
ddsd.dwSize = sizeof(DDSURFACEDESC);
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwHeight = ScreenDescriptorBlock.SDB_Height;
ddsd.dwWidth = ScreenDescriptorBlock.SDB_Width;
// Ensure rendering target has same format as primary
memcpy(&ddsd.ddpfPixelFormat, &TempPixelFormat,
sizeof(DDPIXELFORMAT));
TimeStampedMessage("after memcpy 2");
// Request a 3D capable device so that
// Direct3D accesses will work
ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE);
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL);
TimeStampedMessage("after CreateSurface");
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
return;
#endif
}
}
// Set the Colour Palette (paletted modes only)
#if NoPalette
#else
if (VideoModeColourDepth == 8)
{
TimeStampedMessage("SHOULD NEVER GET HERE");
if (WindowMode == WindowModeSubWindow)
// Use system palette in a SubWindow case
{
// Standard windows RGB + flags palette
// structure prototyped in various versions
// (Though not, apparently, others) of objbase.h
PALETTEENTRY SystemPalette[256];
// Get system palette via GDI device context
HDC hdc = GetDC(NULL);
GetSystemPaletteEntries(hdc, 0, (1 << 8), SystemPalette);
// Restrict system to two palette entries only.
SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
ReleaseDC(NULL, hdc);
// Flag system palette entries
// Will this work?
// I sure hope so...
{
int i;
// Take all but 20 basic entries for our
// greedy little sod of a game window
for (i=0; i<1; i++)
SystemPalette[i].peFlags = PC_EXPLICIT;
for (i=1; i<(256-1); i++)
{
SystemPalette[i].peRed = LPTestPalette[i*4];
SystemPalette[i].peGreen = LPTestPalette[(i*4)+1];
SystemPalette[i].peBlue = LPTestPalette[(i*4)+2];
SystemPalette[i].peFlags = PC_RESERVED;
}
for (i=(256-1); i<256; i++)
SystemPalette[i].peFlags = PC_EXPLICIT;
}
// Create the palette within DirectDraw, using
// DD palette initialisation rather than ours
ddrval = lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256,
SystemPalette, &lpDDPal[0], NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x7);
}
#else
return;
#endif
// Set palette on both buffers
ddrval = lpDDSBack->SetPalette(lpDDPal[0]);
LOGDXERR(ddrval);
ddrval = lpDDSPrimary->SetPalette(lpDDPal[0]);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
return;
#endif
// Save palette in internal format for
// use later
// Out because it causes problems with
// window mode swapping.
// ConvertDDToInternalPalette((unsigned char*) SystemPalette, TestPalette, 256);
}
else // default to FullScreen
{
if ((ScreenDescriptorBlock.SDB_Flags
& SDB_Flag_Raw256) || (Mode8T))// full 256 colours
ddrval = lpDD->CreatePalette((DDPCAPS_8BIT | DDPCAPS_ALLOW256),
(LPPALETTEENTRY)(LPTestPalette),
&lpDDPal[0],
NULL);
else // default is 222
ddrval = lpDD->CreatePalette((DDPCAPS_8BIT),
(LPPALETTEENTRY)(LPTestPalette),
&lpDDPal[0],
NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x7);
}
#else
return;
#endif
ddrval = lpDDSPrimary->SetPalette(lpDDPal[0]);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x8);
}
#else
return;
#endif
// Set palette on BOTH buffers to work around
// bug in Direct3D initialisation!!!
ddrval = lpDDSBack->SetPalette(lpDDPal[0]);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(0x8);
}
#else
return;
#endif
}
}
#endif // for NoPalette
// Get the surface desc for AW DDSurface loads
memset(&ddsd,0,sizeof ddsd);
ddsd.dwSize = sizeof ddsd;
ddrval = lpDDSPrimary->GetSurfaceDesc(&ddsd);
LOGDXERR(ddrval);
GLOBALASSERT(DD_OK==ddrval);
TimeStampedMessage("after memset");
AwSetSurfaceFormat(&ddsd);
TimeStampedMessage("after AwSetSurfaceFormat");
// Do an initial lock and unlock on the back buffer
// to pull out vital information such as the
// surface description
LockSurfaceAndGetBufferPointer();
UnlockSurface();
TimeStampedMessage("after Lock & Unlock");
}
// Lock back buffer and get screen pointer
void LockSurfaceAndGetBufferPointer()
{
DDSURFACEDESC ddsdback;
HRESULT ddrval;
int count = 0;
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_ISBLTDONE) != DD_OK);
#endif
memset(&ddsdback, 0, sizeof(ddsdback));
ddsdback.dwSize = sizeof(ddsdback);
// DDLOCK_WAIT is another safety option that
// should in theory be removable by using
// the GetBltStatus call above.
// Or of course the while loop...
while ((ddrval = lpDDSBack->Lock(NULL, &ddsdback, DDLOCK_WAIT, NULL)) == DDERR_WASSTILLDRAWING)
{
count++;
if (count>1) // was 10000, for test purposes ONLY!!!
{
LOGDXERR(ddrval);
ReleaseDirect3D();
exit(0x2001);
}
}
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
/* ddsdback now contains my lpSurface)*/
ScreenBuffer = (unsigned char *)ddsdback.lpSurface;
BackBufferPitch = ddsdback.lPitch;
// Get pixel format description of
// rendering target
memcpy(&DisplayPixelFormat, &ddsdback.ddpfPixelFormat,
sizeof(DDPIXELFORMAT));
}
void UnlockSurface(void)
{
HRESULT ddrval;
ddrval = lpDDSBack->Unlock((LPVOID)ScreenBuffer);
LOGDXERR(ddrval);
#if debug
if (ddrval != DD_OK)
{
ReleaseDirect3D();
exit(ddrval);
}
#endif
}
void FlipBuffers(void)
{
HRESULT ddrval;
// for locking against other draw processes,
// e.g. mouse pointer
GlobalFlipLock = Yes;
// IMPORTANT!!! OptimiseFlip, Blit are
// not supported in SubWindow mode!!!
if (WindowMode == WindowModeSubWindow)
{
RECT dest;
// For SubWindow mode, we cannot flip, but
// must instead do a (stretched, in principle)
// blit to the front buffer to combine with GDI
// surfaces.
// The whole back buffer should be taken.
dest.left = WinLeftX;
dest.top = WinTopY;
dest.right = WinRightX;
dest.bottom = WinBotY;
ddrval = lpDDSPrimary->Blt(&dest, lpDDSBack,
NULL, DDBLT_WAIT, NULL);
}
else // default to FullScreen
{
// we hope to flip, and flip to hope
// we are the tumbling jongleurs...
if (DXMemoryMode == VideoMemoryPreferred)
{
#if optimiseflip
while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING)
ProcessProjectWhileWaitingToBeFlippable();
#endif
// we are going to flip with DDFLIP_WAIT on
// even if optimiseflip is set.
// IT'S THE ONLY WAY TO BE SURE.
ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT);
while(1)
{
if (ddrval == DD_OK)
break;
if (ddrval == DDERR_SURFACELOST)
{
ddrval = lpDDSPrimary->Restore();
if (ddrval != DD_OK)
break;
}
if (ddrval != DDERR_WASSTILLDRAWING)
break;
}
}
else // assume system memory rendering target
{
// Take rendering target to back buffer
// Rendering target should map fully onto back buffer
ddrval = lpDDSHiddenBack->Blt(NULL, lpDDSBack,
NULL, DDBLT_WAIT, NULL);
// And now do a standard flip
#if optimiseflip
while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING)
ProcessProjectWhileWaitingToBeFlippable();
#endif
// we are going to flip with DDFLIP_WAIT on
// even if optimiseflip is set.
// IT'S THE ONLY WAY TO BE SURE.
ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT);
while(1)
{
if (ddrval == DD_OK)
break;
if (ddrval == DDERR_SURFACELOST)
{
ddrval = lpDDSPrimary->Restore();
if (ddrval != DD_OK)
break;
}
if (ddrval != DDERR_WASSTILLDRAWING)
break;
}
}
}
GlobalFlipLock = No;
ProjectSpecificBufferFlipPostProcessing();
HandleScreenShot();
#if InterlaceExperiment
oddDraw ^= 1;
#endif
}
void InGameFlipBuffers(void)
{
FlipBuffers();
return;
HRESULT ddrval;
// for locking against other draw processes,
// e.g. mouse pointer
GlobalFlipLock = Yes;
// IMPORTANT!!! OptimiseFlip, Blit are
// not supported in SubWindow mode!!!
if (WindowMode == WindowModeSubWindow)
{
RECT dest;
// For SubWindow mode, we cannot flip, but
// must instead do a (stretched, in principle)
// blit to the front buffer to combine with GDI
// surfaces.
// The whole back buffer should be taken.
dest.left = WinLeftX;
dest.top = WinTopY;
dest.right = WinRightX;
dest.bottom = WinBotY;
ddrval = lpDDSPrimary->Blt(&dest, lpDDSBack,
NULL, DDBLT_WAIT, NULL);
}
else // default to FullScreen
{
// we hope to flip, and flip to hope
// we are the tumbling jongleurs...
if (DXMemoryMode == VideoMemoryPreferred)
{
#if optimiseflip
while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING)
ProcessProjectWhileWaitingToBeFlippable();
#endif
// we are going to flip with DDFLIP_WAIT on
// even if optimiseflip is set.
// IT'S THE ONLY WAY TO BE SURE.
ddrval = lpDDSPrimary->Flip(NULL, 0);
while(0)
{
if (ddrval == DD_OK)
break;
if (ddrval == DDERR_SURFACELOST)
{
ddrval = lpDDSPrimary->Restore();
if (ddrval != DD_OK)
break;
}
if (ddrval != DDERR_WASSTILLDRAWING)
break;
}
}
else // assume system memory rendering target
{
LOCALASSERT(0);
// Take rendering target to back buffer
// Rendering target should map fully onto back buffer
ddrval = lpDDSHiddenBack->Blt(NULL, lpDDSBack,
NULL, DDBLT_WAIT, NULL);
// And now do a standard flip
#if optimiseflip
while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING)
ProcessProjectWhileWaitingToBeFlippable();
#endif
// we are going to flip with DDFLIP_WAIT on
// even if optimiseflip is set.
// IT'S THE ONLY WAY TO BE SURE.
ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT);
while(1)
{
if (ddrval == DD_OK)
break;
if (ddrval == DDERR_SURFACELOST)
{
ddrval = lpDDSPrimary->Restore();
if (ddrval != DD_OK)
break;
}
if (ddrval != DDERR_WASSTILLDRAWING)
break;
}
}
}
GlobalFlipLock = No;
ProjectSpecificBufferFlipPostProcessing();
HandleScreenShot();
#if InterlaceExperiment
oddDraw ^= 1;
#endif
}
// As of 29/4/96, slightly later in the day,
// it now deallocates NOTHING explcitly, but
// just calls Release on the entire DD object,
// which seems a better approach. Ho hum.
// This function is now OBSOLETE (25 / 7 / 96)
// CALL RELEASEDIRECT3D INSTEAD!!!
void finiObjects(void)
{
if (lpDD != NULL)
{
lpDD->Release();
lpDD = NULL;
}
}
// Release ONE direct draw surface, to be used
// when replacing images via imageheader array,
// e.g. in LoadBackdrop.
void ReleaseDDSurface(void* DDSurface)
{
LPDIRECTDRAWSURFACE lpSurface;
WaitForVRamReady(VWS_DDRELEASE);
lpSurface = (LPDIRECTDRAWSURFACE) DDSurface;
if (lpSurface != NULL)
{
lpSurface->Release();
lpSurface = NULL;
}
}
// Blt member is used rather BltFast because BltFast does not
// allow a colour fill
void ColourFillBackBuffer(int FillColour)
{
HRESULT ddrval;
DDBLTFX ddbltfx;
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = FillColour;
/* lets blt a color to the surface*/
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK);
#endif
#if optimiseblit
ddrval = lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &ddbltfx);
if (ddrval == DDERR_WASSTILLDRAWING)
ddrval = lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT,
&ddbltfx);
#else
ddrval = lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
}
// Blt member is used rather BltFast because BltFast does not
// allow a colour fill
void ColourFillBackBufferQuad(int FillColour, int LeftX,
int TopY, int RightX, int BotY)
{
HRESULT ddrval;
DDBLTFX ddbltfx;
RECT destRect;
destRect.left = LeftX;
destRect.top = TopY;
destRect.right = RightX;
destRect.bottom = BotY;
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = FillColour;
/* lets blt a color to the surface*/
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK);
#endif
#if optimiseblit
ddrval = lpDDSBack->Blt(&destRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &ddbltfx);
if (ddrval == DDERR_WASSTILLDRAWING)
ddrval = lpDDSBack->Blt(&destRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
#else
ddrval = lpDDSBack->Blt(&destRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
}
// Note Blt is used rather than BltFast because BltFast will
// always attempt to invoke an asynchronous blit and this appears
// to be unstable at present (cf. problems with optimiseblit)
// CHECK THIS -- WITH DDBLTFASTWAIT???
// COMMENT ABOVE NOW OBSOLETE...
void BlitToBackBuffer(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr)
{
HRESULT ddrval;
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK);
#endif
#if optimiseblit
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_ASYNC, NULL);
if (ddrval == DDERR_WASSTILLDRAWING)
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT, NULL);
#else
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT, NULL);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
}
// Note Blt is used rather than BltFast because BltFast does not
// support DDBLTFX and therefore cannot be used to attempt to
// prevent tearing
void BlitToBackBufferWithoutTearing(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr)
{
HRESULT ddrval;
DDBLTFX ddbltfx;
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK);
#endif
#if optimiseblit
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_ASYNC | DDBLT_DDFX, &ddbltfx);
if (ddrval == DDERR_WASSTILLDRAWING)
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT | DDBLT_DDFX, &ddbltfx);
#else
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT | DDBLT_DDFX, &ddbltfx);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
}
#if 0
// Note Blt is used rather than BltFast because BltFast does
// not support the DDBLTFX structure and therefore cannot accept
// a rotated blit
void RotatedBlitToBackBuffer(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr, int RollZ)
{
HRESULT ddrval;
DDBLTFX ddbltfx;
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwRotationAngle = RollZ;
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK);
#endif
#if optimiseblit
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_ASYNC | DDBLT_ROTATIONANGLE, &ddbltfx);
if (ddrval == DDERR_WASSTILLDRAWING)
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT | DDBLT_ROTATIONANGLE, &ddbltfx);
#else
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT | DDBLT_ROTATIONANGLE, &ddbltfx);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
}
// Note Blt is used rather than BltFast because BltFast does not
// support DDBLTFX and therefore cannot be used to attempt to
// prevent tearing
void RotatedBlitToBackBufferWithoutTearing(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr, int RollZ)
{
HRESULT ddrval;
DDBLTFX ddbltfx;
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
ddbltfx.dwRotationAngle = RollZ;
#if optimiseblit
while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK);
#endif
#if optimiseblit
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_ASYNC | DDBLT_DDFX | DDBLT_ROTATIONANGLE, &ddbltfx);
if (ddrval == DDERR_WASSTILLDRAWING)
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT | DDBLT_DDFX | DDBLT_ROTATIONANGLE, &ddbltfx);
#else
ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground,
srcRectPtr, DDBLT_WAIT | DDBLT_DDFX | DDBLT_ROTATIONANGLE, &ddbltfx);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return;
#endif
}
}
#endif
// Note x, y are assumed to be TOP LEFT of character
// BltFast is used here, partially as an experiment (ahem...)
// THIS FUNCTION ASSUMES A VERTICAL FONT BRUSH!!!
// FIXME!!! This function does not always seem to
// produce visible text in SubWindow mode; i.e.
// as of 29/4/96 it works on Roxby's and fails on
// mine. I suspect this is because we are using
// BltFast, which 'works only on display memory',
// and there isn't enough video RAM on my card
// to put the debug font in video memory in SubWindow
// mode. Or something.
// At present I have done nothing about this, since Roxby
// claims that as of Beta 3 he can't get source colour
// keying working on the blitter without using BltFast, and
// we need source colour keying to get the font to
// look right.
// Will have to be looked at at some stage, 'tho.
#if debug || PreBeta
void BlitWin95Char(int x, int y, unsigned char toprint)
{
static int bltwin95char_ok=1;
if (!bltwin95char_ok) return;
int FontIndex;
RECT source;
HRESULT ddrval;
#if NoBltFastOnFont
RECT destination;
#endif
// Check for data out of range for font
if ((toprint < FontStart) || (toprint > FontEnd))
return;
// Check for character being on screen
if ((x < ScreenDescriptorBlock.SDB_ClipLeft) ||
((x + CharWidth) > ScreenDescriptorBlock.SDB_ClipRight) ||
(y < ScreenDescriptorBlock.SDB_ClipUp) ||
((y + CharHeight) > ScreenDescriptorBlock.SDB_ClipDown))
return;
// Generate font index and source rectangle
// Assumes vertical brush
FontIndex = (toprint - FontStart);
source.left = 0;
source.top = (FontIndex * CharHeight);
source.right = CharWidth;
source.bottom = ((FontIndex + 1) * CharHeight);
// Do blit
#if NoBltFastOnFont
destination.left = x;
destination.top = y;
destination.right = (x+CharWidth);
destination.bottom = (y+CharHeight);
ddrval = lpDDSBack->Blt(&destination, lpDDDbgFont,
&source, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
#else
ddrval = lpDDSBack->BltFast(x, y,
lpDDDbgFont, &source,
DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
#endif
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug && 0
{
ReleaseDirect3D();
exit(0x11);
}
#else
bltwin95char_ok = 0;
return;
#endif
}
#else
void BlitWin95Char(int x, int y, unsigned char toprint)
{
}
#endif
// IMPORTANT!!! FIXME!!!!
// This function has been hacked to FORCE images into
// system memory due to what appears to be a bug in
// DirectDraw's defaulting to system memory...
// Has HOPEFULLY now been fixed to deal with non 8 bit
// images... but I wouldn't count on it...
// If SysMem is TRUE, the image should go into system memory. If it is
// FALSE, we will try for video memory. And may God walk at our side in
// the valley of the shadow.
// This callback enumerates all the DirectDraw
// devices present on a system searching for one
// with hardware 3D support available. If such
// a device is present, it will always be selected.
// Otherwise, no valid device will be returned.
static BOOL bHardwareDDObj = FALSE;
static BOOL bNoHardwareDD = FALSE;
BOOL FAR PASCAL EnumDDObjectsCallback(GUID FAR* lpGUID, LPSTR lpDriverDesc,
LPSTR lpDriverName, LPVOID lpContext)
{
LPDIRECTDRAW lpDDTest;
DDCAPS DriverCaps, HELCaps;
HRESULT ddrval;
/*
A NULL GUID* indicates the DirectDraw HEL which we are not interested
in at the moment, because we are cruel and heartless and really
really nasty people, after all.
*/
if (lpGUID)
{
// Create the DirectDraw device using this driver. If it fails,
// just move on to the next driver.
ddrval = DirectDrawCreate(lpGUID, &lpDDTest, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
return DDENUMRET_OK;
// Get the capabilities of this DirectDraw driver. If it fails,
// just move on to the next driver.
memset(&DriverCaps, 0, sizeof(DDCAPS));
DriverCaps.dwSize = sizeof(DDCAPS);
memset(&HELCaps, 0, sizeof(DDCAPS));
HELCaps.dwSize = sizeof(DDCAPS);
ddrval = lpDDTest->GetCaps(&DriverCaps, &HELCaps);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
lpDDTest->Release();
return DDENUMRET_OK;
}
// JH - changed so that debugging in a window works if you've got two cards or something
if (DriverCaps.dwCaps & DDCAPS_3D && WindowRequestMode != WindowModeSubWindow)
{
// We have found a 3d hardware device. Return the DD object
// and stop enumeration.
// This assumes that 3d capable DD hardware
// drivers cannot operate in a window.
// True? CHECKME!!!
WindowMode = WindowModeFullScreen;
*(LPDIRECTDRAW*)lpContext = lpDDTest;
return DDENUMRET_CANCEL;
}
lpDDTest->Release();
}
return DDENUMRET_OK;
}
// Set up the DirectDraw object for the
// system. Using this we can determine the
// system capabilities. The DirectDraw object
// in question should never be released until
// ExitSystem, even if window or video modes
// are changed. Note that as well as checking
// for valid video modes etc, this function will
// also search for hardware DirectDraw objects
// and use one if appropriate.
// Note that GenerateDirectDrawSurface and
// SetVideoMode now just set a video mode,
// rather than (as previously) initialising the
// DirectDraw model.
// This function should be called
// during InitialiseSystem, so that we can
// be sure that SetVideoMode (called later)
// will be setting a valid mode. The function
// must be called after InitialVideoMode (which
// sets the mode it validates) and before
// InitialiseWindowsSystem, since in the
// current version that needs to know the
// WindowMode, not the VideoMode. Note that
// InitialiseWindowsSystem itself must be called
// after InitialVideoMode (it is currently
// called at the start of InitialiseSystem).
DDCAPS direct_draw_caps;
BOOL InitialiseDirectDrawObject(void)
{
HRESULT ddrval;
LPDIRECTDRAW lpDDHardware = NULL;
// Set up DirectDraw object.
// If we are not in emulation only mode,
// search for a hardware 3D capable DirectDraw
// driver and use it. If this fails, or if we
// are in emulation, go straight for the HEL.
if (RasterisationRequestMode != RequestSoftwareRasterisation)
{
ddrval = DirectDrawEnumerate(EnumDDObjectsCallback, &lpDDHardware);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
{
#if debug
ReleaseDirect3D();
exit(ddrval);
#else
return FALSE;
#endif
}
}
// If we don't have a hardware driver, either
// because there wasn't one or because we are in
// HEL... then make one.
if (!lpDDHardware)
{
if (RasterisationRequestMode != RequestSoftwareRasterisation)
bNoHardwareDD = TRUE;
bHardwareDDObj = FALSE;
ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
ReleaseDirect3D(); // for safety
return FALSE;
}
#endif
}
else
{
bHardwareDDObj = TRUE;
lpDD = lpDDHardware;
}
AwSetDDObject(lpDD);
// Get caps for hardware DD driver/HEL layer
memset(&direct_draw_caps, 0, sizeof(direct_draw_caps));
direct_draw_caps.dwSize = sizeof(direct_draw_caps);
ddrval = lpDD->GetCaps(&direct_draw_caps, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
ReleaseDirect3D(); // for safety
return FALSE;
}
#endif
// Put statistics into globals
TotalVideoMemory = (int) (direct_draw_caps.dwVidMemTotal);
// At some stage, we should set up a proper
// structure here with the general system
// capabilities in it.
// Notably, we may need to check DD surface
// alignment values and the stride.
// NOTE THAT AS GARRY HAS POINTED OUT, TOTAL
// FREE VIDMEM CAN CHANGE AFTER SETTING THE
// VIDEO MODE OR COOPERATIVE LEVEL, SO WE
// SHOULD REALLY BE RUNNING THIS GETCAPS MEMBER
// ON THE DDOBJECT AGAIN AFTER GENERATESURFACE, OR
// POSSIBLY WHENEVER THE USER WANTS.
// ***FIXME!!!***
// Run the display modes enumerator
// Note that NULL in the second entry
// means enumerate all available display
// modes on the driver.
NumAvailableVideoModes = 0;
ddrval = lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
ReleaseDirect3D(); // for safety
return FALSE;
}
#endif
// Check that the video mode asked
// for (initially at least in
// InitialVideoMode) is actually
// available. If it is not, attempt to
// default to 640x480x8 and 640x480x15
// (liable to be the most common modes)
// and if that fails, exit altogether
// with a failure code.
// Note!!! This only matters in FullScreen
// mode. In SubWindow mode we must use the
// Windows display mode anyway. Obviously
// initialisation of the video mode will fail
// in SubWindow mode if the colour depth of
// the Windows display is different to the
// VideoMode colour depth, but I have not bothered
// to check for this since SubWindow mode is
// only intended for debugging and the failure
// case exits with an appropriate DirectDraw
// error anyway.
#if CheckVideoMode
if (WindowMode == WindowModeFullScreen)
{
if (!(CheckForVideoModes(VideoMode)))
{
VideoMode = VideoMode_DX_640x480x8;
if (!(CheckForVideoModes(VideoMode)))
{
VideoMode = VideoMode_DX_640x480x15;
if (!(CheckForVideoModes(VideoMode)))
{
ReleaseDirect3D(); // for safety
return FALSE;
}
}
}
}
#endif // for CheckVideoMode
return TRUE; // Successful completion
}
// return TRUE on success
static BOOL ReallyChangeDDObj(void)
{
finiObjects();
if (InitialiseDirectDrawObject()
== FALSE)
/*
If we cannot get a video mode,
fail. No point in a non debugging option
for this.
*/
{
#if debug
ReleaseDirect3D();
exit(0x997798);
#else
return FALSE;
#endif
}
/*
Initialise global to say whether
we think there is an onboard 3D
acceleration card / motherboard
built-in
*/
#if 0
TestInitD3DObject();
/*
This is (HOPEFULLY!!) now the right
place to put this call. Note that it is
not absolutely certain that we can do test
blits from DirectDraw without setting
a cooperative level, however... And note also
that MMX works better with the back buffer in
system memory...
*/
TestMemoryAccess();
#endif
return TRUE;
}
int SelectDirectDrawObject(LPGUID pGUID)
{
HRESULT ddrval;
LPDIRECTDRAW lpDDHardware = NULL;
// Set up DirectDraw object.
bNoHardwareDD = TRUE;
bHardwareDDObj = FALSE;
ddrval = DirectDrawCreate(pGUID, &lpDD, NULL);
AwSetDDObject(lpDD);
// Get caps for hardware DD driver/HEL layer
memset(&direct_draw_caps, 0, sizeof(direct_draw_caps));
direct_draw_caps.dwSize = sizeof(direct_draw_caps);
ddrval = lpDD->GetCaps(&direct_draw_caps, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
ReleaseDirect3D(); // for safety
return FALSE;
}
#endif
// Put statistics into globals
TotalVideoMemory = (int) (direct_draw_caps.dwVidMemTotal);
// At some stage, we should set up a proper
// structure here with the general system
// capabilities in it.
// Notably, we may need to check DD surface
// alignment values and the stride.
// NOTE THAT AS GARRY HAS POINTED OUT, TOTAL
// FREE VIDMEM CAN CHANGE AFTER SETTING THE
// VIDEO MODE OR COOPERATIVE LEVEL, SO WE
// SHOULD REALLY BE RUNNING THIS GETCAPS MEMBER
// ON THE DDOBJECT AGAIN AFTER GENERATESURFACE, OR
// POSSIBLY WHENEVER THE USER WANTS.
// ***FIXME!!!***
// Run the display modes enumerator
// Note that NULL in the second entry
// means enumerate all available display
// modes on the driver.
NumAvailableVideoModes = 0;
ddrval = lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
{
ReleaseDirect3D(); // for safety
return FALSE;
}
#endif
// Check that the video mode asked
// for (initially at least in
// InitialVideoMode) is actually
// available. If it is not, attempt to
// default to 640x480x8 and 640x480x15
// (liable to be the most common modes)
// and if that fails, exit altogether
// with a failure code.
// Note!!! This only matters in FullScreen
// mode. In SubWindow mode we must use the
// Windows display mode anyway. Obviously
// initialisation of the video mode will fail
// in SubWindow mode if the colour depth of
// the Windows display is different to the
// VideoMode colour depth, but I have not bothered
// to check for this since SubWindow mode is
// only intended for debugging and the failure
// case exits with an appropriate DirectDraw
// error anyway.
#if CheckVideoMode
if (WindowMode == WindowModeFullScreen)
{
if (!(CheckForVideoModes(VideoMode)))
{
VideoMode = VideoMode_DX_640x480x8;
if (!(CheckForVideoModes(VideoMode)))
{
VideoMode = VideoMode_DX_640x480x15;
if (!(CheckForVideoModes(VideoMode)))
{
ReleaseDirect3D(); // for safety
return FALSE;
}
}
}
}
#endif // for CheckVideoMode
return TRUE; // Successful completion
}
BOOL ChangeDirectDrawObject(void)
{
if (RequestSoftwareRasterisation==RasterisationRequestMode)
{
// software modes required
if (bHardwareDDObj)
{
// but was previously hardware DD
return ReallyChangeDDObj();
}
}
else
{
// hardware modes requested if available
if (!bHardwareDDObj && !bNoHardwareDD)
{
// but was previously software DD and
// we haven't established that hardware isn't available
return ReallyChangeDDObj();
}
}
return TRUE;
}
BOOL CheckForVideoModes(int TestVideoMode)
{
int i=0;
BOOL EarlyExit = FALSE;
do
{
if ((EngineVideoModes[TestVideoMode].Width
== AvailableVideoModes[i].Width) &&
(EngineVideoModes[TestVideoMode].Height
== AvailableVideoModes[i].Height) &&
(EngineVideoModes[TestVideoMode].ColourDepth
== AvailableVideoModes[i].ColourDepth))
EarlyExit = TRUE;
else
i++;
}
while ((i < NumAvailableVideoModes) &&
(!EarlyExit));
return(EarlyExit);
}
HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context)
{
AvailableVideoModes[NumAvailableVideoModes].Width = pddsd->dwWidth;
AvailableVideoModes[NumAvailableVideoModes].Height = pddsd->dwHeight;
AvailableVideoModes[NumAvailableVideoModes].ColourDepth = pddsd->ddpfPixelFormat.dwRGBBitCount;
NumAvailableVideoModes++;
if (NumAvailableVideoModes < MaxAvailableVideoModes)
return DDENUMRET_OK;
else
return DDENUMRET_CANCEL;
}
// Deallocate all objects except the basic
// DirectDraw objects, which we want to do
// before shifting display modes or window
// mode. Note that ExitWindowsSystem must be
// called separately. Note also that ExitSystem
// should be called for a full system shutdown.
// FIXME!!! BACKDROPS?!?!? -- done in
// DeallocateAllImages (called from ReleaseDirect3D
// and ReleaseDirect3DNotDD)
// Note that getting the right sequence for releases
// here is CRUCIAL. Note also that the font surface
// is NOT explicitly deallocated; hopefully it will just
// go when we kill the primary (as an offscreen surface).
// Could this cause problems for DeallocateAllImages??
// Um, err, I sure hope not...
void finiObjectsExceptDD(void)
{
if (WindowMode == WindowModeSubWindow)
{
if (lpDDClipper != NULL)
{
lpDDClipper->Release();
lpDDClipper = NULL;
}
}
if (lpDDPal[0] != NULL) // should be killed neway???
{
lpDDPal[0]->Release();
lpDDPal[0] = NULL;
}
if (lpDDSBack != NULL)
{
lpDDSBack->Release();
lpDDSBack = NULL;
}
if (lpDDSPrimary != NULL)
{
lpDDSPrimary->Release();
lpDDSPrimary = NULL;
}
}
// This will hopefully allow us to change
// the palette at runtime, assuming that
// we are in a palettised mode. It will
// wait for vertical blank to make it work
// on all video cards (I hope). Note that
// the palette should be passed in engine
// internal format, i.e. 6 bits, and will be
// converted to the DirectDraw format internally.
// Note we assume entry 0 in the lpDDPal array!!!
// Note for 222 mode we set the FIRST 64 entries!!!
// Not certain that's right, actually...
int ChangePalette (unsigned char* NewPalette)
{
unsigned char DDPalette[1024]; // 256 colours, 4 bytes each
int NumEntries;
// Check for palettised mode
// Note we must use VideoModeTypeScreen
// due to nature of Direct3D ramp driver
// interface.
if ((VideoModeTypeScreen != VideoModeType_8) &&
(VideoModeTypeScreen != VideoModeType_8T))
return No;
// Check for FullScreen mode
// if (WindowMode != WindowModeFullScreen)
// return No;
// Set up number of entries to change
if (ScreenDescriptorBlock.SDB_Flags & SDB_Flag_222)
NumEntries = 256; // actually, this seems to be right...
else if ((ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256)
|| (VideoModeTypeScreen == VideoModeType_8T))
NumEntries = 256;
else
return No; // undefined behaviour
// Convert to DirectDraw 4 bytes, 8 bit format
// with all flag entries set to zero
ConvertToDDPalette(NewPalette, DDPalette, NumEntries, 0);
// Wait for beginning of next vertical
// blanking interval
lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
// Set all entries in palette to new values
lpDDPal[0]->SetEntries(0,0,NumEntries,(LPPALETTEENTRY)
DDPalette);
return Yes;
}
// At some stage it may be worth expanding this function
// to get more than video memory, or replacing it
// with one that uses GetCaps to fill out a general
// structure.
int GetAvailableVideoMemory(void)
{
DDCAPS ddcaps;
HRESULT ddrval;
// Get caps for DirectDraw object
memset(&ddcaps, 0, sizeof(ddcaps));
ddcaps.dwSize = sizeof(ddcaps);
ddrval = lpDD->GetCaps(&ddcaps, NULL);
LOGDXERR(ddrval);
if (ddrval != DD_OK)
#if debug
{
ReleaseDirect3D();
exit(ddrval);
}
#else
return -1;
#endif
return (int) (ddcaps.dwVidMemFree);
}
/*
This is designed to allow for ModeX
emulation failures where the system
boots up in a low memory cost mode
which actually takes up much more than
a high cost mode because GDI cannot be
evicted. Note that the VideoMode reset
done here is in any case a last ditch
measure, since the higher res version will
be much slower as well as (normally) more
costly in terms of memory.
It will also now do start errors due to the
driver not being able to change to a mode of
a different colour depth, and this not being reported
by the DirectDraw object's enum display modes
callback. Hopefully.
NOTE THAT THIS MUST BE CALLED FROM YOUR WINMAIN
AFTER SETVIDEOMODE IF IT IS TO WORK.
NOTE ALSO THAT THE ACTIVATION CODE FOR THIS IS
IN GENERATEDIRECTDRAWSURFACE AND WILL NOT BE TURNED
ON UNLESS -->DEBUG<-- IS -->OFF<--.
*/
void HandleVideoModeRestarts(HINSTANCE hInstance, int nCmdShow)
{
if (AttemptVideoModeRestart)
{
switch (VideoRestartMode)
{
case RestartDisplayModeNotAvailable:
{
// Rewrite mode as equivalent resolution,
// different bit depth, before trying again.
// Note this must be kept up to date!!!
switch (VideoMode)
{
case VideoMode_DX_320x200x8:
{
ReleaseDirect3D();
exit(0xfedd);
}
VideoMode = VideoMode_DX_320x200x15;
break;
case VideoMode_DX_320x200x8T:
VideoMode = VideoMode_DX_320x200x15;
break;
case VideoMode_DX_320x200x15:
VideoMode = VideoMode_DX_320x200x8T;
break;
case VideoMode_DX_320x240x8:
VideoMode = VideoMode_DX_320x200x15;
break;
case VideoMode_DX_640x480x8:
VideoMode = VideoMode_DX_640x480x15;
break;
case VideoMode_DX_640x480x8T:
VideoMode = VideoMode_DX_640x480x15;
break;
case VideoMode_DX_640x480x15:
VideoMode = VideoMode_DX_640x480x8T;
break;
case VideoMode_DX_640x480x24:
VideoMode = VideoMode_DX_640x480x15;
break;
default: // hmm...
break;
}
// Clear variables
AttemptVideoModeRestart = No;
VideoRestartMode = NoRestartRequired;
ChangeDisplayModes(hInstance, nCmdShow,
VideoMode, WindowRequestMode,
ZBufferRequestMode, RasterisationRequestMode,
SoftwareScanDrawRequestMode, DXMemoryRequestMode);
}
break;
case RestartOutOfVidMemForPrimary:
{
// Guess mode reset
// Note this must be kept up to date!!!
if ((VideoMode == VideoMode_DX_320x200x8) ||
(VideoMode == VideoMode_DX_320x200x8T) ||
(VideoMode == VideoMode_DX_320x240x8))
VideoMode = VideoMode_DX_640x480x8;
else if (VideoMode == VideoMode_DX_320x200x15)
VideoMode = VideoMode_DX_640x480x15;
// Clear variables
AttemptVideoModeRestart = No;
VideoRestartMode = NoRestartRequired;
ChangeDisplayModes(hInstance, nCmdShow,
VideoMode, WindowRequestMode,
ZBufferRequestMode, RasterisationRequestMode,
SoftwareScanDrawRequestMode, DXMemoryRequestMode);
}
break;
default: // err...
break;
}
}
}
// Take a 24 bit RGB colour and return it in the
// correct format for the current primary surface
// We will assume that the primary is NOT in a
// palettised mode, since the mapping if we have
// already set a palette is undefined.
int GetSingleColourForPrimary(int Colour)
{
unsigned long m;
int s;
int red_shift, red_scale;
int green_shift, green_scale;
int blue_shift, blue_scale;
int RetVal = 0;
int r, g ,b;
// Fail for palettised modes
if ((VideoModeTypeScreen == VideoModeType_8)
|| (VideoModeTypeScreen == VideoModeType_8T))
return -1;
// Extra! check for palettised modes
if ((DisplayPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
|| (DisplayPixelFormat.dwFlags & DDPF_PALETTEINDEXED4))
return -1;
// Determine r, g, b masks and scale
for (s = 0, m = DisplayPixelFormat.dwRBitMask;
!(m & 1); s++, m >>= 1);
red_shift = s;
red_scale = 255 / (DisplayPixelFormat.dwRBitMask >> s);
for (s = 0, m = DisplayPixelFormat.dwGBitMask;
!(m & 1); s++, m >>= 1);
green_shift = s;
green_scale = 255 / (DisplayPixelFormat.dwGBitMask >> s);
for (s = 0, m = DisplayPixelFormat.dwBBitMask;
!(m & 1); s++, m >>= 1);
blue_shift = s;
blue_scale = 255 / (DisplayPixelFormat.dwBBitMask >> s);
// Extract r,g,b components from input colour
r = (Colour >> 16) & 0xff;
g = (Colour >> 8) & 0xff;
b = Colour & 0xff;
// Scale and shift each value
r /= red_scale;
g /= green_scale;
b /= blue_scale;
RetVal = (r << red_shift) | (g << green_shift)
| (b << blue_shift);
return(RetVal);
}
#if triplebuffer
// NOTE TRIPLE BUFFERING SUPPORT HAS BEEN -->REMOVED<--
// ON THE GROUNDS THAT THE SECOND BACK BUFFER TAKES UP
// EXTRA MEMORY AND IT'S NOT GOING TO GO ANY FASTER
// ANYWAY UNLESS YOUR VIDEO CARD FLIPS IN HARDWARE AND
// TAKES MORE THAN ABOUT 10 MILLISECONDS TO DO IT.
// WHICH I CERTAINLY HOPE ISN'T TRUE...
// NOTE ALSO: THIS FUNCTION DOESN'T WORK! (DESPITE
// THE DOCUMENTATION). YOU NEED TO USE GETATTACHEDSURFACE
// TWICE INSTEAD. SEE ARSEWIPE CODE FOR A WORKING
// EXAMPLE (NOTE THAT TRIPLE BUFFERING CAN BE OPTIMAL
// IN ARSEWIPE BECAUSE IT'S 2D, AND THE TIME TO THE NEXT
// SURFACE LOCK IN A RENDERING CYCLE CAN THUS BE MUCH LESS
// THAN IN 3DC).
// defines this function as FAR PASCAL, i.e.
// using Windows standard parameter passing convention,
// which will be neecessary for all callbacks
HRESULT WINAPI InitTripleBuffers(LPDIRECTDRAWSURFACE lpdd,
LPDDSURFACEDESC lpsd, LPVOID lpc)
{
if ((lpsd->ddsCaps.dwCaps & DDSCAPS_FLIP) &&
(!(lpsd->ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER))
&& (BackBufferEnum < MaxBackBuffers))
lpDDSBack[BackBufferEnum++] = lpdd;
if (BackBufferEnum == MaxBackBuffers)
return(DDENUMRET_CANCEL);
else
return(DDENUMRET_OK);
}
#endif
/* new versions of these functions, provided by neil */
static GDIObjectReferenceCount = 0;
BOOL GetGDISurface(void)
{
HRESULT hr = DD_OK;
if(WindowMode == WindowModeSubWindow) return TRUE;
if(!lpDDGDI)
{
hr = lpDD->GetGDISurface(&lpDDGDI);
if(hr != DD_OK)
{
ReleaseDirect3D();
exit(hr);
}
}
// flip the buffer to the GDI surface
hr = lpDD->FlipToGDISurface();
if(hr != DD_OK)
{
ReleaseDirect3D();
exit(hr);
}
GDIObjectReferenceCount++;
// release windows palette entries -
// whenever we flip to the GDI surface,
// we will want the full palette.
if (VideoModeColourDepth == 8)
{
HDC hdc = GetDC(NULL);
SetSystemPaletteUse(hdc, SYSPAL_STATIC);
ReleaseDC(NULL, hdc);
}
return TRUE;
}
BOOL LeaveGDISurface(void)
{
HRESULT hr = DD_OK;
if(WindowMode == WindowModeSubWindow) return TRUE;
if (GDIObjectReferenceCount <= 1)
{
ReleaseDDSurface(lpDDGDI);
}
// recapture system static palette
// entries (see note above in
// GetGDISurface... )
if (VideoModeColourDepth == 8)
{
HDC hdc = GetDC(NULL);
SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
ReleaseDC(NULL, hdc);
}
return TRUE;
}
/************ for extern "C"*****************/
};