2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
19 #define WIN32_LEAN_AND_MEAN
38 // ----------------------------------------------------------------------------
40 LPDIRECTDRAW _lpDD=0; // Direct Draw Object
42 LPDIRECTDRAWSURFACE _lpDDSPrimary=0; // Page 0 and 1
43 LPDIRECTDRAWSURFACE _lpDDSBack=0; //
45 LPDIRECTDRAWCLIPPER _lpDDClipper=0; // Window clipper Object
46 LPDIRECTDRAWPALETTE _lpDDPalette=0; // Palette object
48 BOOL _DDFullScreen; // Game is in window, or fullscreen
49 BOOL _DDSysMemSurfacing=TRUE;
51 int _DDNumModes=0; // Number of graphic modes
52 DDMODEINFO _DDModeList[16]; // Mode information list
53 int _DDLockCounter=0; // DirectDraw Lock Surface counter
56 int W95DisplayMode, // Current display mode from list
57 W95OldDisplayMode;// Old display smode
59 dd_caps ddDriverCaps; // Direct Draw Caps?
61 static HWND DDWnd=NULL; // Current window that owns the display
62 static FILE *LogFile=NULL;
63 int DD_Emulation=0; // Do we force emulated modes?
65 RECT ViewportRect; // Current Viewport
68 // Function Prototypes
69 // ----------------------------------------------------------------------------
71 HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context);
72 BOOL CheckDDResult(HRESULT ddresult, char *funcname);
73 void DDEmulateTest(void);
75 #define WRITELOG(t) if (LogFile) { fprintf t; fflush(LogFile);}
80 // ----------------------------------------------------------------------------
89 if (FindArg("-logfile")) LogFile = fopen("dd.log", "wt");
93 // Create Direct Draw Object (Use Emulation if Hardware is off)
96 ddresult = DirectDrawCreate(NULL, &lpdd, NULL);
98 if (ddresult == DDERR_NODIRECTDRAWHW) {
99 if (FindArg("-ddemul")) {
100 ddresult = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpdd, NULL );
101 if (!CheckDDResult(ddresult, "InitDD:DirectDrawCreate emulation"))
104 logentry("DirectDraw: forcing emulation.\n");
107 CheckDDResult(ddresult, "InitDD:DirectDrawCreate noemulation");
111 else if (ddresult != DD_OK)
114 WRITELOG((LogFile, "System initiated.\n"));
118 DDWnd = GetLibraryWindow();
123 // Set cooperative mode
124 if (mode == DDGR_FULLSCREEN) {
125 flags = DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE;
128 if (!FindArg("-nomodex")) flags |= DDSCL_ALLOWMODEX;
130 flags |= DDSCL_ALLOWMODEX;
133 if (!FindArg("-disallowreboot")) flags |= DDSCL_ALLOWREBOOT;
135 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd, flags);
137 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel")) {
138 IDirectDraw_Release(lpdd);
142 _DDFullScreen = TRUE;
144 else if (mode == DDGR_WINDOW) {
145 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd,
147 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel"))
149 _DDFullScreen = FALSE;
150 if (!DDInitClipper()) return FALSE;
154 // Perform Emulation test
157 // Direct draw initialized. Begin post-initialization
158 if (!DDEnumerateModes()) return FALSE;
159 // DDSETDISPLAYMODE(SM95_640x480x8);
160 // DDSetDisplayMode(W95DisplayMode, 0);
166 void DDEmulateTest(void)
168 // Assume DirectDraw is init and we have exclusive access
174 if (FindArg("-emul")) {
179 ddresult = IDirectDraw_SetDisplayMode(_lpDD, 640,480,8);
180 if (ddresult != DD_OK) {
186 LPDIRECTDRAWSURFACE lpdds;
188 ZeroMemory(&ddsd, sizeof(ddsd));
189 ddsd.dwSize = sizeof(ddsd);
190 ddsd.dwFlags = DDSD_CAPS;
191 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
193 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
194 if (ddresult != DD_OK) {
199 // Performing lock test!
200 ZeroMemory(&ddsd, sizeof(ddsd));
201 ddsd.dwSize = sizeof(ddsd);
202 SetRect(&rect, 10,10,584,200);
203 ddresult = IDirectDrawSurface_Lock(lpdds, &rect, &ddsd, DDLOCK_WAIT, NULL);
204 if (ddresult != DD_OK) {
205 IDirectDrawSurface_Release(lpdds);
210 IDirectDrawSurface_Unlock(lpdds, ddsd.lpSurface);
211 IDirectDrawSurface_Release(lpdds);
216 // IDirectDrawSurface_Unlock(lpdds, ddsd.lpSurface);
217 // IDirectDrawSurface_Release(lpdds);
222 BOOL DDEnumerateModes(void)
227 // Invalidate all modes
228 for (i = 0; i < 16; i++)
230 _DDModeList[i].rw = _DDModeList[i].w = -1;
231 _DDModeList[i].rh = _DDModeList[i].h = -1;
234 // If we're full screen, enumerate modes.
236 ddresult = IDirectDraw_EnumDisplayModes(_lpDD, 0, NULL, 0,
238 if(!CheckDDResult(ddresult, "DDInit::EnumDisplayModes")) {
239 IDirectDraw_Release(_lpDD);
244 _DDModeList[SM95_640x480x8].rw = 640;
245 _DDModeList[SM95_640x480x8].rh = 480;
246 _DDModeList[SM95_640x480x8].w = 640;
247 _DDModeList[SM95_640x480x8].h = 480;
248 _DDModeList[SM95_640x480x8].emul = 1;
249 _DDModeList[SM95_640x480x8].dbuf = 0;
250 _DDModeList[SM95_640x480x8].modex = 0;
251 _DDModeList[SM95_640x480x8].paged = 0;
258 BOOL DDInitClipper(void)
265 // ----------------------------------------------------------------------------
271 // if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette);
272 if (_lpDDClipper) IDirectDrawClipper_Release(_lpDDClipper);
273 if (_lpDD) IDirectDraw_Release(_lpDD);
275 _DDFullScreen = FALSE;
276 _DDNumModes = _DDLockCounter = 0;
280 WRITELOG((LogFile, "System closed.\n"));
282 if (LogFile) fclose(LogFile);
287 // ----------------------------------------------------------------------------
289 void DDSetDisplayMode(int display_mode, int flags)
293 W95DisplayMode = display_mode;
296 // Change literal display mode of screen
298 WRITELOG((LogFile, "Setting display mode to (%dx%dx%d).\n", GRMODEINFO(w), GRMODEINFO(h), GRMODEINFO(bpp)));
300 ddresult = IDirectDraw_SetDisplayMode(_lpDD,
301 _DDModeList[W95DisplayMode].w,
302 _DDModeList[W95DisplayMode].h,
303 _DDModeList[W95DisplayMode].bpp);
305 if (!CheckDDResult(ddresult, "DDInit::SetDisplayMode")) {
306 Error("Unable to set display mode: %d [%dx%dx%d].( Err: %x ) \n", W95DisplayMode, _DDModeList[W95DisplayMode].w,
307 _DDModeList[W95DisplayMode].h,
308 _DDModeList[W95DisplayMode].bpp,
311 if (!DDCreateScreen()) exit(1);
315 Error("Windowed display modes not currently supported.");
318 W95OldDisplayMode = display_mode;
322 void DDResizeViewport()
327 GetClientRect(GetLibraryWindow(), &rect);
332 ClientToScreen(GetLibraryWindow(), &p1);
333 ClientToScreen(GetLibraryWindow(), &p2);
337 p2.x = _DDModeList[W95DisplayMode].w;
338 p2.y = _DDModeList[W95DisplayMode].h;
341 ViewportRect.left = p1.x;
342 ViewportRect.top = p1.y;
343 ViewportRect.right = p2.x;
344 ViewportRect.bottom = p2.y;
346 mprintf((0, "New Viewport: [%d,%d,%d,%d]\n", p1.x, p1.y, p2.x, p2.y));
350 BOOL DDCreateScreen(void)
353 DDCAPS ddcaps, ddcaps2;
357 // Determine capabilites of this display mode
358 memset(&ddcaps, 0, sizeof(ddcaps));
359 memset(&ddcaps2, 0, sizeof(ddcaps2));
360 ddcaps.dwSize = sizeof(ddcaps);
361 ddcaps2.dwSize = sizeof(ddcaps);
363 ddresult = IDirectDraw_GetCaps(_lpDD, &ddcaps, &ddcaps2);
364 if (!CheckDDResult(ddresult, "DDCreateScreen::GetCaps"))
367 WRITELOG((LogFile, "HAL: %8x\tHEL: %8x\n", ddcaps.dwCaps, ddcaps2.dwCaps));
368 WRITELOG((LogFile, "PAL: %8x\tDDS: %8x\n", ddcaps.dwPalCaps, ddcaps.ddsCaps.dwCaps));
370 // This makes the game plenty faster (3 fps extra on Highres)
371 ddDriverCaps.offscreen.sysmem = 1;
373 if (ddcaps.dwCaps & DDCAPS_COLORKEYHWASSIST) {
374 WRITELOG((LogFile, "Mode supports hardware colorkeying.\n"));
375 ddDriverCaps.hwcolorkey = 1;
377 else ddDriverCaps.hwcolorkey = 0;
379 if (ddcaps.dwCaps & DDCAPS_BLTSTRETCH) {
380 WRITELOG((LogFile, "Mode supports hardware blt stretching.\n"));
381 ddDriverCaps.hwbltstretch = 1;
383 else ddDriverCaps.hwbltstretch = 0;
386 // Create the screen surfaces
387 memset(&ddsd, 0, sizeof(ddsd));
388 ddsd.dwSize = sizeof(ddsd);
389 ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
392 if (GRMODEINFO(paged))
394 // Create a flipping surface if we can
396 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
397 ddsd.dwBackBufferCount = 1;
398 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
400 // ddsd.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
401 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
402 if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -paged"))
405 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
406 ddresult = IDirectDrawSurface_GetAttachedSurface(_lpDDSPrimary,
407 &ddscaps, &_lpDDSBack);
408 if (!CheckDDResult(ddresult, "DDCreateScreen::GetAttachedSurface"))
413 // Normal primary surface (non-emulated)
414 ddsd.dwFlags = DDSD_CAPS;
415 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
416 // ddsd.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
417 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
418 if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface"))
422 if (GRMODEINFO(emul))
424 // Create emulated 2nd page for window modes that don't let us render to the
426 _lpDDSBack = DDCreateSurface(_DDModeList[W95DisplayMode].rw,
427 _DDModeList[W95DisplayMode].rh, 1);
429 mprintf((0,"Call to create DDSBackBuffer failed."));
434 if (GRMODEINFO(bpp) == 8)
436 // for 8-bit palettized modes, assert that we use the RGB pixel format.
437 // Also create a base palette for this 8-bit mode.
441 memset(&ddsd, 0, sizeof(ddsd));
442 ddsd.dwSize = sizeof(ddsd);
443 IDirectDrawSurface_GetSurfaceDesc(_lpDDSPrimary, &ddsd);
445 WRITELOG((LogFile, "Surface pixel format: %x, %d\n", ddsd.ddpfPixelFormat.dwFlags, ddsd.ddpfPixelFormat.dwRGBBitCount));
447 if ((_lpDDPalette = DDCreatePalette(pal))!= NULL)
448 DDSetPalette(_lpDDPalette);
449 else Error("Failed to create palette for screen.\n");
456 void DDClearDisplay();
460 WRITELOG((LogFile, "Killing display mode (%dx%dx%d).\n", _DDModeList[W95OldDisplayMode].w, _DDModeList[W95OldDisplayMode].h, _DDModeList[W95OldDisplayMode].bpp));
462 // if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette);
463 if (_lpDDSBack && !GRMODEINFO(paged)) IDirectDrawSurface_Release(_lpDDSBack);
466 if (!GRMODEINFO(modex)) {
470 IDirectDrawSurface_Release(_lpDDSPrimary);
476 _lpDDSPrimary = NULL;
480 void DDClearDisplay()
485 memset(&ddbltfx, 0, sizeof(DDBLTFX));
486 ddbltfx.dwSize = sizeof( ddbltfx );
487 ddbltfx.dwFillColor = (WORD)(BM_XRGB(0,0,0));
489 ddresult = IDirectDrawSurface_Blt(
490 _lpDDSPrimary, // dest surface
494 DDBLT_COLORFILL | DDBLT_WAIT,
503 if (IDirectDrawSurface_GetFlipStatus(_lpDDSBack, DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING) return;
505 ddresult = IDirectDrawSurface_Flip(_lpDDSPrimary, NULL, DDFLIP_WAIT);
506 if (ddresult != DD_OK) {
507 WRITELOG((LogFile, "DDFlip:: Unable to flip screen (%X)\n", ddresult));
508 Int3(); // Bad flipping
514 // DirectDrawSurface Routines
515 // ----------------------------------------------------------------------------
517 LPDIRECTDRAWSURFACE DDCreateSurface(int width, int height, BOOL vram)
521 LPDIRECTDRAWSURFACE lpdds;
523 if (ddDriverCaps.offscreen.sysmem && !vram)
524 return DDCreateSysMemSurface(width, height);
526 memset(&ddsd, 0, sizeof(ddsd));
527 ddsd.dwSize = sizeof(ddsd);
528 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
529 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
530 ddsd.dwWidth = width;
531 ddsd.dwHeight = height;
533 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
534 if (ddresult != DD_OK) {
535 WRITELOG((LogFile, "CreateSurface err: %x\n", ddresult));
543 LPDIRECTDRAWSURFACE DDCreateSysMemSurface(int width, int height)
547 LPDIRECTDRAWSURFACE lpdds;
549 memset(&ddsd, 0, sizeof(ddsd));
550 ddsd.dwSize = sizeof(ddsd);
551 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
552 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
553 ddsd.dwWidth = width;
554 ddsd.dwHeight = height;
556 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
557 if (ddresult != DD_OK) {
558 logentry("DDRAW::CreateSysMemSurface err: %x\n", ddresult);
566 void DDFreeSurface(LPDIRECTDRAWSURFACE lpdds)
570 Assert(lpdds != NULL);
572 ddresult = IDirectDrawSurface_Release(lpdds);
573 if (ddresult != DD_OK) {
574 Error("DDFreeSurface: Unable to free surface: err %x", ddresult);
579 BOOL DDRestoreSurface(LPDIRECTDRAWSURFACE lpdds)
583 Assert(lpdds != NULL);
584 if (IDirectDrawSurface_IsLost(lpdds) == DD_OK) return TRUE;
585 ddresult = IDirectDrawSurface_Restore(lpdds);
586 if (ddresult != DD_OK)
594 // Locking and Unlocking of DD Surfaces
596 ubyte *DDLockSurface(LPDIRECTDRAWSURFACE lpdds, RECT *rect, int *pitch )
602 memset(&ddsd, 0, sizeof(ddsd));
603 ddsd.dwSize = sizeof(ddsd);
607 ddresult = IDirectDrawSurface_Lock(lpdds, rect, &ddsd, DDLOCK_WAIT, NULL);
609 if (ddresult != DD_OK)
611 if (ddresult == DDERR_SURFACELOST) {
612 if (!DDRestoreSurface(lpdds) || try_count) {
613 WRITELOG((LogFile, "Unable to restore surface for lock.\n"));
622 WRITELOG((LogFile, "Lock error: %x.\n", ddresult));
629 *pitch = (int)ddsd.lPitch;
630 return (ubyte *)ddsd.lpSurface;
634 void DDUnlockSurface(LPDIRECTDRAWSURFACE lpdds, char *data)
638 if (_DDLockCounter < 1) return;
640 ddresult = IDirectDrawSurface_Unlock(lpdds, data);
641 if (ddresult != DD_OK) {
642 Error("Unable to unlock canvas: %x\n", ddresult);
650 // DirectDrawPalette Utilities
651 // ----------------------------------------------------------------------------
653 LPDIRECTDRAWPALETTE DDGetPalette(LPDIRECTDRAWSURFACE lpdds)
656 LPDIRECTDRAWPALETTE lpddp;
658 ddresult = IDirectDrawSurface_GetPalette(lpdds, &lpddp);
659 if (ddresult != DD_OK) {
660 mprintf((1, "DDERR: GetPalette %x.\n", ddresult));
667 LPDIRECTDRAWPALETTE DDCreatePalette(ubyte *pal)
670 LPDIRECTDRAWPALETTE lpddpal;
671 PALETTEENTRY pe[256];
674 for (i = 0; i < 256; i++)
676 pe[i].peRed = pal[i*3];
677 pe[i].peGreen = pal[i*3+1];
678 pe[i].peBlue = pal[i*3+2];
682 ddresult = IDirectDraw_CreatePalette(_lpDD,
683 DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE,
686 if (ddresult != DD_OK) {
687 mprintf((1, "DDERR: CreatePalette %x.\n", ddresult));
695 void DDSetPalette(LPDIRECTDRAWPALETTE lpDDPal)
699 ddresult = IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal);
700 if (ddresult != DD_OK) {
701 if (ddresult == DDERR_SURFACELOST) {
702 IDirectDrawSurface_Restore(_lpDDSPrimary);
703 IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal);
706 Error("This driver requires you to set your desktop\n to 256 color mode before running Descent II.");
714 // ----------------------------------------------------------------------------
716 int DDCheckMode(int mode)
718 if (_DDModeList[mode].w==-1 && _DDModeList[mode].h==-1) return 1;
723 BOOL CheckDDResult(HRESULT ddresult, char *funcname)
727 if (ddresult != DD_OK) {
728 sprintf(buf, "DirectDraw error %x detected in\r\n\t%s\n", ddresult, funcname);
729 WRITELOG((LogFile, buf));
730 MessageBox(NULL, buf, "DESCENT2::DDRAW", MB_OK);
739 // ----------------------------------------------------------------------------
740 HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context)
742 DWORD width, height,bpp;
746 width = lpddsd->dwWidth;
747 height = lpddsd->dwHeight;
748 bpp = lpddsd->ddpfPixelFormat.dwRGBBitCount;
749 modex = lpddsd->ddsCaps.dwCaps;
751 modex = modex & DDSCAPS_MODEX;
753 if (width == 640 && height == 480 && bpp==8)
754 mode = SM95_640x480x8;
755 else if (width == 640 && height == 400 && bpp==8)
756 mode = SM95_640x400x8;
757 else if (width == 320 && height == 200 && bpp==8) {
758 mode = SM95_320x200x8X;
759 if (DD_Emulation) return DDENUMRET_OK;
761 else if (width == 800 && height == 600 && bpp==8)
762 mode = SM95_800x600x8;
763 else if (width == 1024 && height == 768 && bpp==8)
764 mode = SM95_1024x768x8;
768 _DDModeList[mode].rw = width;
769 _DDModeList[mode].rh = height;
770 _DDModeList[mode].emul = 0;
771 _DDModeList[mode].modex = 0;
772 _DDModeList[mode].paged = 0;
773 _DDModeList[mode].dbuf = 0;
774 _DDModeList[mode].w = width;
775 _DDModeList[mode].h = height;
776 _DDModeList[mode].bpp = bpp;
778 if (mode == SM95_320x200x8X) {
779 _DDModeList[mode].modex = 1;
780 _DDModeList[mode].dbuf = 1;
781 _DDModeList[mode].paged = 1;
783 else _DDModeList[mode].dbuf = 1;
785 if (DD_Emulation) _DDModeList[mode].emul = 1;
789 WRITELOG((LogFile, "Register mode (%dx%dx%d) (paged=%d) (dbuf=%d).\n", width, height, bpp, _DDModeList[mode].paged, _DDModeList[mode].dbuf));