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.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: dd.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
23 #define WIN32_LEAN_AND_MEAN
42 // ----------------------------------------------------------------------------
44 LPDIRECTDRAW _lpDD=0; // Direct Draw Object
46 LPDIRECTDRAWSURFACE _lpDDSPrimary=0; // Page 0 and 1
47 LPDIRECTDRAWSURFACE _lpDDSBack=0; //
49 LPDIRECTDRAWCLIPPER _lpDDClipper=0; // Window clipper Object
50 LPDIRECTDRAWPALETTE _lpDDPalette=0; // Palette object
52 BOOL _DDFullScreen; // Game is in window, or fullscreen
53 BOOL _DDSysMemSurfacing=TRUE;
55 int _DDNumModes=0; // Number of graphic modes
56 DDMODEINFO _DDModeList[16]; // Mode information list
57 int _DDLockCounter=0; // DirectDraw Lock Surface counter
60 int W95DisplayMode, // Current display mode from list
61 W95OldDisplayMode;// Old display smode
63 dd_caps ddDriverCaps; // Direct Draw Caps?
65 static HWND DDWnd=NULL; // Current window that owns the display
66 static FILE *LogFile=NULL;
67 int DD_Emulation=0; // Do we force emulated modes?
69 RECT ViewportRect; // Current Viewport
72 // Function Prototypes
73 // ----------------------------------------------------------------------------
75 HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context);
76 BOOL CheckDDResult(HRESULT ddresult, char *funcname);
77 void DDEmulateTest(void);
79 #define WRITELOG(t) if (LogFile) { fprintf t; fflush(LogFile);}
84 // ----------------------------------------------------------------------------
93 if (FindArg("-logfile")) LogFile = fopen("dd.log", "wt");
97 // Create Direct Draw Object (Use Emulation if Hardware is off)
100 ddresult = DirectDrawCreate(NULL, &lpdd, NULL);
102 if (ddresult == DDERR_NODIRECTDRAWHW) {
103 if (FindArg("-ddemul")) {
104 ddresult = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpdd, NULL );
105 if (!CheckDDResult(ddresult, "InitDD:DirectDrawCreate emulation"))
108 logentry("DirectDraw: forcing emulation.\n");
111 CheckDDResult(ddresult, "InitDD:DirectDrawCreate noemulation");
115 else if (ddresult != DD_OK)
118 WRITELOG((LogFile, "System initiated.\n"));
122 DDWnd = GetLibraryWindow();
127 // Set cooperative mode
128 if (mode == DDGR_FULLSCREEN) {
129 flags = DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE;
132 if (!FindArg("-nomodex")) flags |= DDSCL_ALLOWMODEX;
134 flags |= DDSCL_ALLOWMODEX;
137 if (!FindArg("-disallowreboot")) flags |= DDSCL_ALLOWREBOOT;
139 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd, flags);
141 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel")) {
142 IDirectDraw_Release(lpdd);
146 _DDFullScreen = TRUE;
148 else if (mode == DDGR_WINDOW) {
149 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd,
151 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel"))
153 _DDFullScreen = FALSE;
154 if (!DDInitClipper()) return FALSE;
158 // Perform Emulation test
161 // Direct draw initialized. Begin post-initialization
162 if (!DDEnumerateModes()) return FALSE;
163 // DDSETDISPLAYMODE(SM95_640x480x8);
164 // DDSetDisplayMode(W95DisplayMode, 0);
170 void DDEmulateTest(void)
172 // Assume DirectDraw is init and we have exclusive access
178 if (FindArg("-emul")) {
183 ddresult = IDirectDraw_SetDisplayMode(_lpDD, 640,480,8);
184 if (ddresult != DD_OK) {
190 LPDIRECTDRAWSURFACE lpdds;
192 ZeroMemory(&ddsd, sizeof(ddsd));
193 ddsd.dwSize = sizeof(ddsd);
194 ddsd.dwFlags = DDSD_CAPS;
195 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
197 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
198 if (ddresult != DD_OK) {
203 // Performing lock test!
204 ZeroMemory(&ddsd, sizeof(ddsd));
205 ddsd.dwSize = sizeof(ddsd);
206 SetRect(&rect, 10,10,584,200);
207 ddresult = IDirectDrawSurface_Lock(lpdds, &rect, &ddsd, DDLOCK_WAIT, NULL);
208 if (ddresult != DD_OK) {
209 IDirectDrawSurface_Release(lpdds);
214 IDirectDrawSurface_Unlock(lpdds, ddsd.lpSurface);
215 IDirectDrawSurface_Release(lpdds);
220 // IDirectDrawSurface_Unlock(lpdds, ddsd.lpSurface);
221 // IDirectDrawSurface_Release(lpdds);
226 BOOL DDEnumerateModes(void)
231 // Invalidate all modes
232 for (i = 0; i < 16; i++)
234 _DDModeList[i].rw = _DDModeList[i].w = -1;
235 _DDModeList[i].rh = _DDModeList[i].h = -1;
238 // If we're full screen, enumerate modes.
240 ddresult = IDirectDraw_EnumDisplayModes(_lpDD, 0, NULL, 0,
242 if(!CheckDDResult(ddresult, "DDInit::EnumDisplayModes")) {
243 IDirectDraw_Release(_lpDD);
248 _DDModeList[SM95_640x480x8].rw = 640;
249 _DDModeList[SM95_640x480x8].rh = 480;
250 _DDModeList[SM95_640x480x8].w = 640;
251 _DDModeList[SM95_640x480x8].h = 480;
252 _DDModeList[SM95_640x480x8].emul = 1;
253 _DDModeList[SM95_640x480x8].dbuf = 0;
254 _DDModeList[SM95_640x480x8].modex = 0;
255 _DDModeList[SM95_640x480x8].paged = 0;
262 BOOL DDInitClipper(void)
269 // ----------------------------------------------------------------------------
275 // if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette);
276 if (_lpDDClipper) IDirectDrawClipper_Release(_lpDDClipper);
277 if (_lpDD) IDirectDraw_Release(_lpDD);
279 _DDFullScreen = FALSE;
280 _DDNumModes = _DDLockCounter = 0;
284 WRITELOG((LogFile, "System closed.\n"));
286 if (LogFile) fclose(LogFile);
291 // ----------------------------------------------------------------------------
293 void DDSetDisplayMode(int display_mode, int flags)
297 W95DisplayMode = display_mode;
300 // Change literal display mode of screen
302 WRITELOG((LogFile, "Setting display mode to (%dx%dx%d).\n", GRMODEINFO(w), GRMODEINFO(h), GRMODEINFO(bpp)));
304 ddresult = IDirectDraw_SetDisplayMode(_lpDD,
305 _DDModeList[W95DisplayMode].w,
306 _DDModeList[W95DisplayMode].h,
307 _DDModeList[W95DisplayMode].bpp);
309 if (!CheckDDResult(ddresult, "DDInit::SetDisplayMode")) {
310 Error("Unable to set display mode: %d [%dx%dx%d].( Err: %x ) \n", W95DisplayMode, _DDModeList[W95DisplayMode].w,
311 _DDModeList[W95DisplayMode].h,
312 _DDModeList[W95DisplayMode].bpp,
315 if (!DDCreateScreen()) exit(1);
319 Error("Windowed display modes not currently supported.");
322 W95OldDisplayMode = display_mode;
326 void DDResizeViewport()
331 GetClientRect(GetLibraryWindow(), &rect);
336 ClientToScreen(GetLibraryWindow(), &p1);
337 ClientToScreen(GetLibraryWindow(), &p2);
341 p2.x = _DDModeList[W95DisplayMode].w;
342 p2.y = _DDModeList[W95DisplayMode].h;
345 ViewportRect.left = p1.x;
346 ViewportRect.top = p1.y;
347 ViewportRect.right = p2.x;
348 ViewportRect.bottom = p2.y;
350 mprintf((0, "New Viewport: [%d,%d,%d,%d]\n", p1.x, p1.y, p2.x, p2.y));
354 BOOL DDCreateScreen(void)
357 DDCAPS ddcaps, ddcaps2;
361 // Determine capabilites of this display mode
362 memset(&ddcaps, 0, sizeof(ddcaps));
363 memset(&ddcaps2, 0, sizeof(ddcaps2));
364 ddcaps.dwSize = sizeof(ddcaps);
365 ddcaps2.dwSize = sizeof(ddcaps);
367 ddresult = IDirectDraw_GetCaps(_lpDD, &ddcaps, &ddcaps2);
368 if (!CheckDDResult(ddresult, "DDCreateScreen::GetCaps"))
371 WRITELOG((LogFile, "HAL: %8x\tHEL: %8x\n", ddcaps.dwCaps, ddcaps2.dwCaps));
372 WRITELOG((LogFile, "PAL: %8x\tDDS: %8x\n", ddcaps.dwPalCaps, ddcaps.ddsCaps.dwCaps));
374 // This makes the game plenty faster (3 fps extra on Highres)
375 ddDriverCaps.offscreen.sysmem = 1;
377 if (ddcaps.dwCaps & DDCAPS_COLORKEYHWASSIST) {
378 WRITELOG((LogFile, "Mode supports hardware colorkeying.\n"));
379 ddDriverCaps.hwcolorkey = 1;
381 else ddDriverCaps.hwcolorkey = 0;
383 if (ddcaps.dwCaps & DDCAPS_BLTSTRETCH) {
384 WRITELOG((LogFile, "Mode supports hardware blt stretching.\n"));
385 ddDriverCaps.hwbltstretch = 1;
387 else ddDriverCaps.hwbltstretch = 0;
390 // Create the screen surfaces
391 memset(&ddsd, 0, sizeof(ddsd));
392 ddsd.dwSize = sizeof(ddsd);
393 ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
396 if (GRMODEINFO(paged))
398 // Create a flipping surface if we can
400 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
401 ddsd.dwBackBufferCount = 1;
402 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
404 // ddsd.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
405 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
406 if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -paged"))
409 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
410 ddresult = IDirectDrawSurface_GetAttachedSurface(_lpDDSPrimary,
411 &ddscaps, &_lpDDSBack);
412 if (!CheckDDResult(ddresult, "DDCreateScreen::GetAttachedSurface"))
417 // Normal primary surface (non-emulated)
418 ddsd.dwFlags = DDSD_CAPS;
419 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
420 // ddsd.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8 | DDPF_RGB;
421 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
422 if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface"))
426 if (GRMODEINFO(emul))
428 // Create emulated 2nd page for window modes that don't let us render to the
430 _lpDDSBack = DDCreateSurface(_DDModeList[W95DisplayMode].rw,
431 _DDModeList[W95DisplayMode].rh, 1);
433 mprintf((0,"Call to create DDSBackBuffer failed."));
438 if (GRMODEINFO(bpp) == 8)
440 // for 8-bit palettized modes, assert that we use the RGB pixel format.
441 // Also create a base palette for this 8-bit mode.
445 memset(&ddsd, 0, sizeof(ddsd));
446 ddsd.dwSize = sizeof(ddsd);
447 IDirectDrawSurface_GetSurfaceDesc(_lpDDSPrimary, &ddsd);
449 WRITELOG((LogFile, "Surface pixel format: %x, %d\n", ddsd.ddpfPixelFormat.dwFlags, ddsd.ddpfPixelFormat.dwRGBBitCount));
451 if ((_lpDDPalette = DDCreatePalette(pal))!= NULL)
452 DDSetPalette(_lpDDPalette);
453 else Error("Failed to create palette for screen.\n");
460 void DDClearDisplay();
464 WRITELOG((LogFile, "Killing display mode (%dx%dx%d).\n", _DDModeList[W95OldDisplayMode].w, _DDModeList[W95OldDisplayMode].h, _DDModeList[W95OldDisplayMode].bpp));
466 // if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette);
467 if (_lpDDSBack && !GRMODEINFO(paged)) IDirectDrawSurface_Release(_lpDDSBack);
470 if (!GRMODEINFO(modex)) {
474 IDirectDrawSurface_Release(_lpDDSPrimary);
480 _lpDDSPrimary = NULL;
484 void DDClearDisplay()
489 memset(&ddbltfx, 0, sizeof(DDBLTFX));
490 ddbltfx.dwSize = sizeof( ddbltfx );
491 ddbltfx.dwFillColor = (WORD)(BM_XRGB(0,0,0));
493 ddresult = IDirectDrawSurface_Blt(
494 _lpDDSPrimary, // dest surface
498 DDBLT_COLORFILL | DDBLT_WAIT,
507 if (IDirectDrawSurface_GetFlipStatus(_lpDDSBack, DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING) return;
509 ddresult = IDirectDrawSurface_Flip(_lpDDSPrimary, NULL, DDFLIP_WAIT);
510 if (ddresult != DD_OK) {
511 WRITELOG((LogFile, "DDFlip:: Unable to flip screen (%X)\n", ddresult));
512 Int3(); // Bad flipping
518 // DirectDrawSurface Routines
519 // ----------------------------------------------------------------------------
521 LPDIRECTDRAWSURFACE DDCreateSurface(int width, int height, BOOL vram)
525 LPDIRECTDRAWSURFACE lpdds;
527 if (ddDriverCaps.offscreen.sysmem && !vram)
528 return DDCreateSysMemSurface(width, height);
530 memset(&ddsd, 0, sizeof(ddsd));
531 ddsd.dwSize = sizeof(ddsd);
532 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
533 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
534 ddsd.dwWidth = width;
535 ddsd.dwHeight = height;
537 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
538 if (ddresult != DD_OK) {
539 WRITELOG((LogFile, "CreateSurface err: %x\n", ddresult));
547 LPDIRECTDRAWSURFACE DDCreateSysMemSurface(int width, int height)
551 LPDIRECTDRAWSURFACE lpdds;
553 memset(&ddsd, 0, sizeof(ddsd));
554 ddsd.dwSize = sizeof(ddsd);
555 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
556 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
557 ddsd.dwWidth = width;
558 ddsd.dwHeight = height;
560 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
561 if (ddresult != DD_OK) {
562 logentry("DDRAW::CreateSysMemSurface err: %x\n", ddresult);
570 void DDFreeSurface(LPDIRECTDRAWSURFACE lpdds)
574 Assert(lpdds != NULL);
576 ddresult = IDirectDrawSurface_Release(lpdds);
577 if (ddresult != DD_OK) {
578 Error("DDFreeSurface: Unable to free surface: err %x", ddresult);
583 BOOL DDRestoreSurface(LPDIRECTDRAWSURFACE lpdds)
587 Assert(lpdds != NULL);
588 if (IDirectDrawSurface_IsLost(lpdds) == DD_OK) return TRUE;
589 ddresult = IDirectDrawSurface_Restore(lpdds);
590 if (ddresult != DD_OK)
598 // Locking and Unlocking of DD Surfaces
600 ubyte *DDLockSurface(LPDIRECTDRAWSURFACE lpdds, RECT *rect, int *pitch )
606 memset(&ddsd, 0, sizeof(ddsd));
607 ddsd.dwSize = sizeof(ddsd);
611 ddresult = IDirectDrawSurface_Lock(lpdds, rect, &ddsd, DDLOCK_WAIT, NULL);
613 if (ddresult != DD_OK)
615 if (ddresult == DDERR_SURFACELOST) {
616 if (!DDRestoreSurface(lpdds) || try_count) {
617 WRITELOG((LogFile, "Unable to restore surface for lock.\n"));
626 WRITELOG((LogFile, "Lock error: %x.\n", ddresult));
633 *pitch = (int)ddsd.lPitch;
634 return (ubyte *)ddsd.lpSurface;
638 void DDUnlockSurface(LPDIRECTDRAWSURFACE lpdds, char *data)
642 if (_DDLockCounter < 1) return;
644 ddresult = IDirectDrawSurface_Unlock(lpdds, data);
645 if (ddresult != DD_OK) {
646 Error("Unable to unlock canvas: %x\n", ddresult);
654 // DirectDrawPalette Utilities
655 // ----------------------------------------------------------------------------
657 LPDIRECTDRAWPALETTE DDGetPalette(LPDIRECTDRAWSURFACE lpdds)
660 LPDIRECTDRAWPALETTE lpddp;
662 ddresult = IDirectDrawSurface_GetPalette(lpdds, &lpddp);
663 if (ddresult != DD_OK) {
664 mprintf((1, "DDERR: GetPalette %x.\n", ddresult));
671 LPDIRECTDRAWPALETTE DDCreatePalette(ubyte *pal)
674 LPDIRECTDRAWPALETTE lpddpal;
675 PALETTEENTRY pe[256];
678 for (i = 0; i < 256; i++)
680 pe[i].peRed = pal[i*3];
681 pe[i].peGreen = pal[i*3+1];
682 pe[i].peBlue = pal[i*3+2];
686 ddresult = IDirectDraw_CreatePalette(_lpDD,
687 DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE,
690 if (ddresult != DD_OK) {
691 mprintf((1, "DDERR: CreatePalette %x.\n", ddresult));
699 void DDSetPalette(LPDIRECTDRAWPALETTE lpDDPal)
703 ddresult = IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal);
704 if (ddresult != DD_OK) {
705 if (ddresult == DDERR_SURFACELOST) {
706 IDirectDrawSurface_Restore(_lpDDSPrimary);
707 IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal);
710 Error("This driver requires you to set your desktop\n to 256 color mode before running Descent II.");
718 // ----------------------------------------------------------------------------
720 int DDCheckMode(int mode)
722 if (_DDModeList[mode].w==-1 && _DDModeList[mode].h==-1) return 1;
727 BOOL CheckDDResult(HRESULT ddresult, char *funcname)
731 if (ddresult != DD_OK) {
732 sprintf(buf, "DirectDraw error %x detected in\r\n\t%s\n", ddresult, funcname);
733 WRITELOG((LogFile, buf));
734 MessageBox(NULL, buf, "DESCENT2::DDRAW", MB_OK);
743 // ----------------------------------------------------------------------------
744 HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context)
746 DWORD width, height,bpp;
750 width = lpddsd->dwWidth;
751 height = lpddsd->dwHeight;
752 bpp = lpddsd->ddpfPixelFormat.dwRGBBitCount;
753 modex = lpddsd->ddsCaps.dwCaps;
755 modex = modex & DDSCAPS_MODEX;
757 if (width == 640 && height == 480 && bpp==8)
758 mode = SM95_640x480x8;
759 else if (width == 640 && height == 400 && bpp==8)
760 mode = SM95_640x400x8;
761 else if (width == 320 && height == 200 && bpp==8) {
762 mode = SM95_320x200x8X;
763 if (DD_Emulation) return DDENUMRET_OK;
765 else if (width == 800 && height == 600 && bpp==8)
766 mode = SM95_800x600x8;
767 else if (width == 1024 && height == 768 && bpp==8)
768 mode = SM95_1024x768x8;
772 _DDModeList[mode].rw = width;
773 _DDModeList[mode].rh = height;
774 _DDModeList[mode].emul = 0;
775 _DDModeList[mode].modex = 0;
776 _DDModeList[mode].paged = 0;
777 _DDModeList[mode].dbuf = 0;
778 _DDModeList[mode].w = width;
779 _DDModeList[mode].h = height;
780 _DDModeList[mode].bpp = bpp;
782 if (mode == SM95_320x200x8X) {
783 _DDModeList[mode].modex = 1;
784 _DDModeList[mode].dbuf = 1;
785 _DDModeList[mode].paged = 1;
787 else _DDModeList[mode].dbuf = 1;
789 if (DD_Emulation) _DDModeList[mode].emul = 1;
793 WRITELOG((LogFile, "Register mode (%dx%dx%d) (paged=%d) (dbuf=%d).\n", width, height, bpp, _DDModeList[mode].paged, _DDModeList[mode].dbuf));