/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #pragma off (unreferenced) static char rcsid[] = "$Id: ddraw.c 1.10 1996/08/20 16:30:52 samir Exp $"; #pragma on (unreferenced) #define WIN95 #define _WIN32 #define WIN32_LEAN_AND_MEAN #include #include "win\ddraw.h" #include #include #include "gr.h" #include "mono.h" #include "error.h" #include "winapp.h" #include "dd.h" #include "args.h" // Direct X Variables --------------------------------------------------------- LPDIRECTDRAW _lpDD=0; // Direct Draw Object LPDIRECTDRAWSURFACE _lpDDSPrimary=0; // Primary Display Screen (Page 1) LPDIRECTDRAWSURFACE _lpDDSBack=0; // Page 2 or offscreen canvas LPDIRECTDRAWCLIPPER _lpDDClipper=0; // Window Clipper Object LPDIRECTDRAWPALETTE _lpDDPalette=0; // Direct Draw Palette; DDMODEINFO _DDModeList[16]; // Mode list for Exclusive mode. int _DDNumModes = 0; // Number of display modes BOOL _DDFullScreen; // Full Screen DD mode? BOOL _DDExclusive; // Exclusive mode? BOOL _DDSysMemSurfacing=TRUE; int W95DisplayMode; // Display mode. int W95OldDisplayMode; dd_caps ddDriverCaps; // Driver Caps. int _DDFlags=0; // Direct Draw Flags int _DDLockCounter=0; // DirectDraw Lock Surface counter static BOOL DDUseEmulation=FALSE; static HWND DDWnd=NULL; static int DDVideoLocks = 0; static int DDSystemLocks = 0; // Function prototypes -------------------------------------------------------- HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context); BOOL CheckDDResult(HRESULT ddresult, char *funcname); BOOL DDRestoreCanvas(dd_grs_canvas *canvas); // Direct Draw Initialization // ---------------------------------------------------------------------------- BOOL DDInit(int mode) { LPDIRECTDRAW lpdd; DDCAPS ddcaps, ddcaps2; HRESULT ddresult; int num; DDWnd = GetLibraryWindow(); // Create Direct Draw Object (Use Emulation if Hardware is off) if (!_lpDD) { ddresult = DirectDrawCreate(NULL, &lpdd, NULL); if (ddresult == DDERR_NODIRECTDRAWHW) { ddresult = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpdd, NULL ); if (!CheckDDResult(ddresult, "InitDD:DirectDrawCreate emulation")) return FALSE; DDUseEmulation = TRUE; logentry("DirectDraw: forcing emulation.\n"); } else if (ddresult != DD_OK) return FALSE; logentry("DirectDraw: DirectX API hardware compliant.\n"); } else return FALSE; atexit(DDKill); // Determine hardware caps // Determine capture mode (fullscreen takes exclusive, window is normal) if (mode == DDGR_FULLSCREEN) { DWORD flags; flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN; #ifndef NDEBUG if (!FindArg("-nomodex")) flags |= DDSCL_ALLOWMODEX; #else flags |= DDSCL_ALLOWMODEX; #endif if (!FindArg("-disallowreboot")) flags |= DDSCL_ALLOWREBOOT; ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd, flags); if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel")) { IDirectDraw_Release(lpdd); return FALSE; } _DDExclusive = TRUE; _DDFullScreen = TRUE; } else if (mode == DDGR_EXWINDOW) { ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel")) return FALSE; _DDExclusive = TRUE; _DDFullScreen = FALSE; } else if (mode == DDGR_WINDOW) { ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd, DDSCL_NORMAL); if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel")) return FALSE; _DDExclusive = FALSE; _DDFullScreen = FALSE; } else return FALSE; // Get Display modes/Window Sizes // Force invalidation of all modes for now for (num = 0; num < 16; num++) { _DDModeList[num].rw = _DDModeList[num].w = -1; _DDModeList[num].rh = _DDModeList[num].h = -1; } W95DisplayMode = SM95_640x480x8; num = 0; if (mode == DDGR_FULLSCREEN) { ddresult = IDirectDraw_EnumDisplayModes(lpdd, 0, NULL, 0, EnumDispModesCB); if(!CheckDDResult(ddresult, "DDInit::EnumDisplayModes")) { IDirectDraw_Release(lpdd); return FALSE; } } else if (mode == DDGR_EXWINDOW) { _DDModeList[SM95_320x200x8X].rw = 320; _DDModeList[SM95_320x200x8X].rh = 200; _DDModeList[SM95_320x200x8X].w = 640; _DDModeList[SM95_320x200x8X].h = 480; _DDModeList[SM95_320x200x8X].emul = 1; _DDModeList[SM95_320x200x8X].dbuf = 0; _DDModeList[SM95_320x200x8X].modex = 0; _DDModeList[SM95_320x200x8X].paged = 0; _DDModeList[SM95_640x480x8].rw = 640; _DDModeList[SM95_640x480x8].rh = 480; _DDModeList[SM95_640x480x8].w = 640; _DDModeList[SM95_640x480x8].h = 480; _DDModeList[SM95_640x480x8].emul = 1; _DDModeList[SM95_640x480x8].dbuf = 0; _DDModeList[SM95_640x480x8].modex = 0; _DDModeList[SM95_640x480x8].paged = 0; _DDModeList[SM95_800x600x8].rw = 800; _DDModeList[SM95_800x600x8].rh = 600; _DDModeList[SM95_800x600x8].w = 640; _DDModeList[SM95_800x600x8].h = 480; _DDModeList[SM95_800x600x8].emul = 1; _DDModeList[SM95_800x600x8].dbuf = 0; _DDModeList[SM95_800x600x8].modex = 0; _DDModeList[SM95_800x600x8].paged = 0; _DDNumModes = 3; } else if (mode == DDGR_WINDOW) { _DDModeList[SM95_320x200x8X].rw = 320; _DDModeList[SM95_320x200x8X].rh = 200; _DDModeList[SM95_320x200x8X].w = 640; _DDModeList[SM95_320x200x8X].h = 480; _DDModeList[SM95_320x200x8X].emul = 1; _DDModeList[SM95_320x200x8X].dbuf = 0; _DDModeList[SM95_320x200x8X].modex = 0; _DDModeList[SM95_320x200x8X].paged = 0; _DDModeList[SM95_640x480x8].rw = 640; _DDModeList[SM95_640x480x8].rh = 480; _DDModeList[SM95_640x480x8].w = 640; _DDModeList[SM95_640x480x8].h = 480; _DDModeList[SM95_640x480x8].emul = 1; _DDModeList[SM95_640x480x8].dbuf = 0; _DDModeList[SM95_640x480x8].modex = 0; _DDModeList[SM95_640x480x8].paged = 0; _DDModeList[SM95_800x600x8].rw = 800; _DDModeList[SM95_800x600x8].rh = 600; _DDModeList[SM95_800x600x8].w = 800; _DDModeList[SM95_800x600x8].h = 600; _DDModeList[SM95_800x600x8].emul = 1; _DDModeList[SM95_800x600x8].dbuf = 0; _DDModeList[SM95_800x600x8].modex = 0; _DDModeList[SM95_800x600x8].paged = 0; _DDNumModes = 3; } else return FALSE; // Set appropriate display mode or window mode _lpDD = lpdd; memset(&ddcaps, 0, sizeof(ddcaps)); ddcaps.dwSize = sizeof(ddcaps); ddcaps2.dwSize = sizeof(ddcaps); ddresult = IDirectDraw_GetCaps(_lpDD, &ddcaps, NULL); if (!CheckDDResult(ddresult, "InitDD::GetCaps")) return FALSE; logentry("DirectDraw: VRAM free: %d\n", ddcaps.dwVidMemFree); logentry("DirectDraw: VRAM total: %d\n", ddcaps.dwVidMemTotal); #ifndef NDEBUG if (FindArg("-TsengDebug1")) { IDirectDraw_Release(lpdd); return FALSE; } #endif DDSetDisplayMode(W95DisplayMode, 0); #ifndef NDEBUG if (FindArg("-TsengDebug2")) { IDirectDraw_Release(lpdd); return FALSE; } #endif // If 'windowed' do this. if (!_DDFullScreen) { ddresult = IDirectDraw_CreateClipper(_lpDD, 0, &_lpDDClipper, NULL); if (!CheckDDResult(ddresult, "DDCreateScreen::CreateClipper")) return FALSE; ddresult = IDirectDrawClipper_SetHWnd(_lpDDClipper, 0, DDWnd); if (!CheckDDResult(ddresult, "DDCreateScreen::SetHWnd")) return FALSE; ddresult = IDirectDrawSurface_SetClipper(_lpDDSPrimary, _lpDDClipper); if (!CheckDDResult(ddresult, "DDCreateScreen::SetClipper")) return FALSE; } // Register Optimizations ddcaps.dwSize = sizeof(ddcaps); ddcaps2.dwSize = sizeof(ddcaps); ddresult = IDirectDraw_GetCaps(lpdd, &ddcaps, &ddcaps2); if (!CheckDDResult(ddresult, "DDInit::GetCaps")) return FALSE; #ifndef NDEBUG if (FindArg("-TsengDebug3")) { IDirectDraw_Release(lpdd); return FALSE; } #endif if (FindArg("-vidram")) { logentry("DirectDraw: Forcing VRAM rendering.\n"); _DDSysMemSurfacing = FALSE; } else if (FindArg("-sysram")) { logentry("DirectDraw: Forcing SRAM rendering.\n"); _DDSysMemSurfacing = TRUE; } else if (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) { logentry("DirectDraw: Hardware is bank-switched. Using SRAM rendering.\n"); _DDSysMemSurfacing = TRUE; } else { logentry("DirectDraw: Hardware is not bank-switched. Using VRAM rendering.\n"); _DDSysMemSurfacing = FALSE; } if (ddcaps.dwCaps & DDCAPS_COLORKEYHWASSIST) ddDriverCaps.hwcolorkey = 1; else ddDriverCaps.hwcolorkey = 0; if (ddcaps.dwCaps & DDCAPS_BLTSTRETCH) ddDriverCaps.hwbltstretch = 1; else ddDriverCaps.hwbltstretch = 0; //@@ mprintf((0, "DD::Hardware=")); //@@ if (ddcaps.dwCaps & DDCAPS_NOHARDWARE) mprintf((0, "Off\n")); //@@ else mprintf((0, "On\n")); //@@ //@@ mprintf((0, "DD::VideoMem=%u bytes\n", ddcaps.dwVidMemTotal)); //@@ mprintf((0, "DD::SrcColorKey=")); //@@ if (ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) mprintf((0, "Hardware\n")); //@@ else mprintf((0, "Emulation\n")); return TRUE; } // Direct Draw Destruction // ---------------------------------------------------------------------------- void DDKill() { // Perform cleanup for full screen case and window case DDKillScreen(); if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette); if (_lpDD) IDirectDraw_Release(_lpDD); _DDExclusive = _DDFullScreen = FALSE; _DDNumModes = 0; _DDLockCounter = 0; _lpDD = NULL; } // Direct Draw Surface Creation // Create Screen (Page 0 and possibly Page 1 or offscreen buffer) // ---------------------------------------------------------------------------- BOOL DDCreateScreen(int flags) { DDSCAPS ddscaps; DDCAPS ddcaps, ddcaps2; DDSURFACEDESC ddsd; HRESULT ddresult; memset(&ddcaps, 0, sizeof(ddcaps)); memset(&ddcaps2, 0, sizeof(ddcaps2)); ddcaps.dwSize = sizeof(ddcaps); ddcaps2.dwSize = sizeof(ddcaps); ddresult = IDirectDraw_GetCaps(_lpDD, &ddcaps, &ddcaps2); if (!CheckDDResult(ddresult, "DDCreateScreen::GetCaps")) return FALSE; logentry("DirectDraw HW Caps: %x\nDirectDraw HEL Caps: %x\n",ddcaps.dwCaps,ddcaps2.dwCaps); if (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) { logentry("DirectDraw: Hardware is bank-switched. Using SRAM rendering.\n"); _DDSysMemSurfacing = TRUE; } else { logentry("DirectDraw: Hardware is not bank-switched. Using VRAM rendering.\n"); _DDSysMemSurfacing = FALSE; } // Determine GFX caps. if (ddcaps.dwCaps & DDCAPS_COLORKEYHWASSIST) ddDriverCaps.hwcolorkey = 1; else ddDriverCaps.hwcolorkey = 0; if (ddcaps.dwCaps & DDCAPS_BLTSTRETCH) ddDriverCaps.hwbltstretch = 1; else ddDriverCaps.hwbltstretch = 0; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); if (_DDFullScreen && GRMODEINFO(paged)) { // We should use page flipping ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.dwBackBufferCount = 1; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL); if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -fullscreen")) return FALSE; ddscaps.dwCaps = DDSCAPS_BACKBUFFER; ddresult = IDirectDrawSurface_GetAttachedSurface(_lpDDSPrimary, &ddscaps, &_lpDDSBack); if (!CheckDDResult(ddresult, "DDCreateScreen::GetAttachedSurface")) return FALSE; } else { // We just create a primary and offscreen buffer if (GRMODEINFO(emul) && !_lpDDSPrimary) { // make sure we don't reinitialize the screen if we already made it // beforehand for windowed version ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL); if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -windowed")) return FALSE; } else if (!GRMODEINFO(emul)) { // If we aren't emulating ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL); if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -windowed")) return FALSE; } if (GRMODEINFO(emul)) { _lpDDSBack = DDCreateSurface(_DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh, 1); if (!_lpDDSBack) { mprintf((0,"Call to create DDSBackBuffer failed.")); return FALSE; } } else _lpDDSBack = NULL; } // Create 8-bit palette { ubyte pal[768]; memset(pal, 0, 768); memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); IDirectDrawSurface_GetSurfaceDesc(_lpDDSPrimary, &ddsd); logentry("Primary surface pixel format: %x, %d\n", ddsd.ddpfPixelFormat.dwFlags, ddsd.ddpfPixelFormat.dwRGBBitCount); _lpDDPalette = DDCreatePalette(pal); Assert(_lpDDPalette != NULL); DDSetPalette(_lpDDPalette); } return TRUE; } // DirectDraw Screen Kill // ---------------------------------------------------------------------------- void DDKillScreen() { if (_lpDDClipper) IDirectDrawClipper_Release(_lpDDClipper); if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette); if (_lpDDSBack) IDirectDrawSurface_Release(_lpDDSBack); if (_lpDDSPrimary) { if (!GRMODEINFO(modex)) { DDBLTFX ddbltfx; HRESULT ddresult; memset(&ddbltfx, 0, sizeof(DDBLTFX)); ddbltfx.dwSize = sizeof( ddbltfx ); ddbltfx.dwFillColor = (WORD)(BM_XRGB(0,0,0)); ddresult = IDirectDrawSurface_Blt( _lpDDSPrimary, // dest surface NULL, // dest rect NULL, // src surface NULL, // src rect DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); } IDirectDrawSurface_Release(_lpDDSPrimary); } _lpDDClipper = NULL; _lpDDPalette = NULL; _lpDDSBack = NULL; _lpDDSPrimary = NULL; } void DDKillEmulatedScreen() { if (_lpDDSBack) IDirectDrawSurface_Release(_lpDDSBack); _lpDDSBack = NULL; } // DDSetDisplayMode // ---------------------------------------------------------------------------- void DDSetDisplayMode(int display_mode, int flags) { HRESULT ddresult; W95DisplayMode = display_mode; W95OldDisplayMode = display_mode; if (_DDFullScreen) { logentry("Setting screen display mode to (%dx%dx%d::%dx%dx%d).\n", _DDModeList[W95DisplayMode].w, _DDModeList[W95DisplayMode].h, _DDModeList[W95DisplayMode].bpp,_DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh, _DDModeList[W95DisplayMode].bpp); DDKillScreen(); ddresult = IDirectDraw_SetDisplayMode(_lpDD, _DDModeList[W95DisplayMode].w, _DDModeList[W95DisplayMode].h, _DDModeList[W95DisplayMode].bpp); if (!CheckDDResult(ddresult, "DDInit::SetDisplayMode")) { Error("Unable to set display mode: %d.\n", W95DisplayMode); } DDCreateScreen(flags); } else { RECT rect; DWORD dwStyle; DDKillEmulatedScreen(); dwStyle = GetWindowLong(DDWnd, GWL_STYLE); dwStyle &= ~WS_POPUP; dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX; SetRect(&rect, 0, 0, _DDModeList[W95DisplayMode].w, _DDModeList[W95DisplayMode].h); SetWindowLong(DDWnd, GWL_STYLE, dwStyle); AdjustWindowRectEx(&rect, GetWindowLong(DDWnd, GWL_STYLE), GetMenu(DDWnd)!=NULL, GetWindowLong(DDWnd, GWL_EXSTYLE)); SetWindowPos(DDWnd, NULL, 0,0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); SetWindowPos(DDWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); DDCreateScreen(flags); } } // DDRestoreScreen // Restore screens // ---------------------------------------------------------------------------- int DDRestoreScreen() { mprintf((1, "Need to Restore DDraw Page0 and Page1.\n")); if (!_lpDDSPrimary || IDirectDrawSurface_Restore(_lpDDSPrimary) !=DD_OK) { mprintf((1, "Warning: Unable to restore Primary Surface.\n")); return 0; } if (!GRMODEINFO(paged) && _lpDDSBack) { if (IDirectDrawSurface_Restore(_lpDDSBack) != DD_OK) { mprintf((1, "Warning: Unable to restore Back Surface.\n")); return 0; } } else if (!_DDFullScreen) { if (!_lpDDSBack || IDirectDrawSurface_Restore(_lpDDSBack) != DD_OK) { mprintf((1, "Warning: Unable to restore Back Surface.\n")); return 0; } } return 1; } // DDFlip // Flip Screens using DirectDraw::Flip // ---------------------------------------------------------------------------- void DDFlip() { HRESULT ddresult; ddresult = IDirectDrawSurface_Flip(_lpDDSPrimary, NULL, 0); if (ddresult != DD_OK) { mprintf((1, "DDFlip:: Unable to flip screen (%X)\n", ddresult)); Int3(); // Bad flipping } } // DDCreateSurface // Create an offscreen surface hopefully in video memory // ---------------------------------------------------------------------------- LPDIRECTDRAWSURFACE DDCreateSurface(int width, int height, BOOL vram) { DDSURFACEDESC ddsd; HRESULT ddresult; LPDIRECTDRAWSURFACE lpdds; DDCOLORKEY ddck; if (_DDSysMemSurfacing && !vram) return DDCreateSysMemSurface(width, height); memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = width; ddsd.dwHeight = height; // logentry("Creating %dx%d sysram/vidram surface.\n", width, height); ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL); if (ddresult != DD_OK) { logentry("DDRAW::CreateSurface err: %x\n", ddresult); return NULL; } return lpdds; } LPDIRECTDRAWSURFACE DDCreateSysMemSurface(int width, int height) { DDSURFACEDESC ddsd; HRESULT ddresult; LPDIRECTDRAWSURFACE lpdds; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = width; ddsd.dwHeight = height; // logentry("Creating %dx%d sysram surface.\n", width, height); ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL); if (ddresult != DD_OK) { logentry("DDRAW::CreateSysMemSurface err: %x\n", ddresult); return NULL; } return lpdds; } // DDGetPalette // ---------------------------------------------------------------------------- LPDIRECTDRAWPALETTE DDGetPalette(LPDIRECTDRAWSURFACE lpdds) { HRESULT ddresult; LPDIRECTDRAWPALETTE lpddp; ddresult = IDirectDrawSurface_GetPalette(lpdds, &lpddp); if (ddresult != DD_OK) { mprintf((1, "DDERR: GetPalette %x.\n", ddresult)); return NULL; } return lpddp; } // DDCreatePalette // ---------------------------------------------------------------------------- LPDIRECTDRAWPALETTE DDCreatePalette(ubyte *pal) { HRESULT ddresult; LPDIRECTDRAWPALETTE lpddpal; PALETTEENTRY pe[256]; int i; for (i = 0; i < 256; i++) { pe[i].peRed = pal[i*3]; pe[i].peGreen = pal[i*3+1]; pe[i].peBlue = pal[i*3+2]; pe[i].peFlags = 0; } ddresult = IDirectDraw_CreatePalette(_lpDD, DDPCAPS_8BIT | DDPCAPS_ALLOW256, pe, &lpddpal, NULL); if (ddresult != DD_OK) { mprintf((1, "DDERR: CreatePalette %x.\n", ddresult)); return NULL; } return lpddpal; } // DDSetPalette // ---------------------------------------------------------------------------- void DDSetPalette(LPDIRECTDRAWPALETTE lpDDPal) { HRESULT ddresult; ddresult = IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal); if (ddresult != DD_OK) { if (ddresult == DDERR_SURFACELOST) { IDirectDrawSurface_Restore(_lpDDSPrimary); IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal); } else { Error("Unable to attach palette to primary surface: %x.", ddresult); } } } // DDLock and DDUnlock Canvas // This is required to access any canvas. // ---------------------------------------------------------------------------- #ifndef NDEBUG void DDLockCanvas_D(dd_grs_canvas *canvas, char *filename, int line) { HRESULT ddresult; DDSURFACEDESC ddsd; RECT rect; grs_bitmap *bmp; bmp = &canvas->canvas.cv_bitmap; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); if (canvas->lock_count == 0) { // Obtain info about a rectangle on the surface SetRect(&rect, bmp->bm_x, bmp->bm_y, bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h); RetryLock: ddresult = IDirectDrawSurface_Lock(canvas->lpdds, &rect, &ddsd, DDLOCK_WAIT, NULL); if (ddresult != DD_OK) { if (ddresult == DDERR_SURFACELOST) { if (!DDRestoreCanvas(canvas)) Error("Unable to restore surface for lock:%x (%s line %d)\n", ddresult, filename, line); else goto RetryLock; } else { while (canvas->lock_count) DDUnlockCanvas(canvas); Error("Unable to lock canvas: %x (%s line %d)\n", ddresult, filename, line); } } bmp->bm_data = (unsigned char *)ddsd.lpSurface; bmp->bm_rowsize = (short)ddsd.lPitch; // if (canvas->sram && !GRMODEINFO(modex)) { // // Manually calculate? // bmp->bm_data = bmp->bm_data + (bmp->bm_y*bmp->bm_rowsize); // bmp->bm_data += bmp->bm_x; // } _DDLockCounter++; } canvas->lock_count++; } #endif void DDLockCanvas(dd_grs_canvas *canvas) { HRESULT ddresult; DDSURFACEDESC ddsd; RECT rect; grs_bitmap *bmp; bmp = &canvas->canvas.cv_bitmap; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); if (canvas->lock_count == 0) { // Obtain info about a rectangle on the surface SetRect(&rect, bmp->bm_x, bmp->bm_y, bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h); RetryLock: ddresult = IDirectDrawSurface_Lock(canvas->lpdds, &rect, &ddsd, DDLOCK_WAIT, NULL); if (ddresult != DD_OK) { if (ddresult == DDERR_SURFACELOST) { if (!DDRestoreCanvas(canvas)) Error("Unable to restore surface for lock:"); else goto RetryLock; } else { while (canvas->lock_count) DDUnlockCanvas(canvas); Error("Unable to lock canvas: %x\n", ddresult); } } bmp->bm_data = (unsigned char *)ddsd.lpSurface; bmp->bm_rowsize = (short)ddsd.lPitch; // if (canvas->sram && !GRMODEINFO(modex)) { // // Manually calculate? // bmp->bm_data = bmp->bm_data + (bmp->bm_y*bmp->bm_rowsize); // bmp->bm_data += bmp->bm_x; // } _DDLockCounter++; } canvas->lock_count++; } void DDUnlockCanvas(dd_grs_canvas *canvas) { HRESULT ddresult; grs_bitmap *bmp; bmp = &canvas->canvas.cv_bitmap; if (canvas->lock_count == 1) { // if (canvas->sram && !GRMODEINFO(modex)) { // bmp->bm_data = bmp->bm_data - bmp->bm_x; // bmp->bm_data = bmp->bm_data - (bmp->bm_y*bmp->bm_rowsize); // } ddresult = IDirectDrawSurface_Unlock(canvas->lpdds, canvas->canvas.cv_bitmap.bm_data); if (ddresult != DD_OK) { Error("Unable to unlock canvas: %x\n", ddresult); exit(1); } canvas->canvas.cv_bitmap.bm_data = NULL; canvas->canvas.cv_bitmap.bm_rowsize = 0; _DDLockCounter--; } canvas->lock_count--; } void DDLockDebug() { logentry("VRAM locks: %d. SRAM locks: %d\n", DDVideoLocks, DDSystemLocks); } // DDFreeSurface // ---------------------------------------------------------------------------- void DDFreeSurface(LPDIRECTDRAWSURFACE lpdds) { HRESULT ddresult; Assert(lpdds != NULL); ddresult = IDirectDrawSurface_Release(lpdds); if (ddresult != DD_OK) { logentry("DDRAW::FreeSurface err: %x\n", ddresult); Error("DDFreeSurface: Unable to free surface."); } } // DDRestoreCanvas // ---------------------------------------------------------------------------- BOOL DDRestoreCanvas(dd_grs_canvas *canvas) { HRESULT ddresult; Assert(canvas->lpdds != NULL); ddresult = IDirectDrawSurface_Restore(canvas->lpdds); if (ddresult != DD_OK) { if (ddresult != DDERR_WRONGMODE) { logentry("DDRAW::RestoreCanvas::Surface err: %x\n", ddresult); return FALSE; } mprintf((0, "Recreating surfaces:\n")); // Must recreate canvas if (canvas->lpdds == _lpDDSPrimary || canvas->lpdds == _lpDDSBack) { mprintf((0, "DDRestoreCanvas::Screen memory was lost!\n")); exit(1); } if (canvas->sram) { // force sysmem canvas! canvas->lpdds = DDCreateSysMemSurface(canvas->canvas.cv_bitmap.bm_w, canvas->canvas.cv_bitmap.bm_h); } else { canvas->lpdds = DDCreateSurface(canvas->canvas.cv_bitmap.bm_w, canvas->canvas.cv_bitmap.bm_h, _DDSysMemSurfacing); } } return TRUE; } // CheckDDResult // ---------------------------------------------------------------------------- BOOL CheckDDResult(HRESULT ddresult, char *funcname) { char buf[256]; if (ddresult != DD_OK) { sprintf(buf, "DirectDraw error %x detected in\r\n\t%s", ddresult, funcname); logentry(buf); MessageBox(NULL, buf, "DESCENT2::DDRAW", MB_OK); return FALSE; } else return TRUE; } // EnumDispModesCB // ---------------------------------------------------------------------------- HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context) { DWORD width, height,bpp; int mode; DWORD modex; width = lpddsd->dwWidth; height = lpddsd->dwHeight; bpp = lpddsd->ddpfPixelFormat.dwRGBBitCount; modex = lpddsd->ddsCaps.dwCaps; modex = modex & DDSCAPS_MODEX; if (width == 640 && height == 480 && bpp==8) mode = SM95_640x480x8; else if (width == 640 && height == 400 && bpp==8) mode = SM95_640x400x8; else if (width == 320 && height == 200 && bpp==8) mode = SM95_320x200x8X; else if (width == 800 && height == 600 && bpp==8) mode = SM95_800x600x8; else if (width == 1024 && height == 768 && bpp==8) mode = SM95_1024x768x8; else return DDENUMRET_OK; _DDModeList[mode].rw = width; _DDModeList[mode].rh = height; _DDModeList[mode].emul = 0; _DDModeList[mode].modex = 0; _DDModeList[mode].paged = 0; _DDModeList[mode].dbuf = 0; if (mode == SM95_320x200x8X) { _DDModeList[mode].modex = 1; _DDModeList[mode].dbuf = 1; _DDModeList[mode].paged = 1; } else if (mode == SM95_640x400x8) { // Support a range of emulated modes // 320x200x8 Double Pixeled _DDModeList[SM95_320x200x8].rw = 320; _DDModeList[SM95_320x200x8].rh = 200; _DDModeList[SM95_320x200x8].emul = 1; _DDModeList[SM95_320x200x8].dbuf = 0; _DDModeList[SM95_320x200x8].modex = 0; _DDModeList[SM95_320x200x8].paged = 0; _DDModeList[SM95_320x200x8].w = 640; _DDModeList[SM95_320x200x8].h = 400; _DDModeList[SM95_320x200x8].bpp = 8; _DDModeList[SM95_320x400x8].rw = 320; _DDModeList[SM95_320x400x8].rh = 400; _DDModeList[SM95_320x400x8].emul = 1; _DDModeList[SM95_320x400x8].dbuf = 0; _DDModeList[SM95_320x400x8].modex = 0; _DDModeList[SM95_320x400x8].paged = 0; _DDModeList[SM95_320x400x8].w = 640; _DDModeList[SM95_320x400x8].h = 400; _DDModeList[SM95_320x400x8].bpp = 8; _DDNumModes+=2; _DDModeList[mode].dbuf = 1; } else { _DDModeList[mode].dbuf = 1; } _DDModeList[mode].w = width; _DDModeList[mode].h = height; _DDModeList[mode].bpp = bpp; _DDNumModes++; return DDENUMRET_OK; } int DDCheckMode(int mode) { if (_DDModeList[mode].w==-1 && _DDModeList[mode].h==-1) return 1; else return 0; }