From 218ca90543758a20ac326e444ca0643174ca7384 Mon Sep 17 00:00:00 2001 From: Rebellion Developments Date: Thu, 16 Mar 2000 11:25:00 +0100 Subject: 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. --- 3dc/win95/DD_FUNC.CPP | 2260 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2260 insertions(+) create mode 100644 3dc/win95/DD_FUNC.CPP (limited to '3dc/win95/DD_FUNC.CPP') diff --git a/3dc/win95/DD_FUNC.CPP b/3dc/win95/DD_FUNC.CPP new file mode 100644 index 0000000..3be2188 --- /dev/null +++ b/3dc/win95/DD_FUNC.CPP @@ -0,0 +1,2260 @@ +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"*****************/ + +}; + -- cgit v1.3