Cygwin support, using SDL.
[btb/d2x.git] / unused / win95 / ddraw.c
1 /*
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.
12 */
13
14
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: ddraw.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
18
19
20 #define WIN95
21 #define _WIN32
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #include "win\ddraw.h"
25
26 #include <stdio.h>
27 #include <mem.h>
28
29 #include "gr.h"
30 #include "mono.h"
31 #include "error.h"
32 #include "winapp.h"
33 #include "dd.h"
34 #include "args.h"
35
36
37 //      Direct X Variables ---------------------------------------------------------
38
39 LPDIRECTDRAW                    _lpDD=0;                                // Direct Draw Object
40 LPDIRECTDRAWSURFACE     _lpDDSPrimary=0;        // Primary Display Screen (Page 1)
41 LPDIRECTDRAWSURFACE     _lpDDSBack=0;           // Page 2 or offscreen canvas
42 LPDIRECTDRAWCLIPPER     _lpDDClipper=0; // Window Clipper Object
43 LPDIRECTDRAWPALETTE     _lpDDPalette=0; // Direct Draw Palette;
44 DDMODEINFO                              _DDModeList[16];        // Mode list for Exclusive mode.
45 int                                             _DDNumModes = 0;        // Number of display modes
46 BOOL                                            _DDFullScreen;          // Full Screen DD mode?
47 BOOL                                            _DDExclusive;           // Exclusive mode?
48 BOOL                                            _DDSysMemSurfacing=TRUE;
49 int                                             W95DisplayMode; // Display mode.
50 int                                             W95OldDisplayMode;
51
52 dd_caps                                 ddDriverCaps;           // Driver Caps.
53
54 int                                             _DDFlags=0;                     // Direct Draw Flags
55 int                                             _DDLockCounter=0;       // DirectDraw Lock Surface counter
56
57 static BOOL                             DDUseEmulation=FALSE;
58 static HWND                             DDWnd=NULL;
59
60 static int                              DDVideoLocks = 0;
61 static int                              DDSystemLocks = 0;
62
63 //      Function prototypes --------------------------------------------------------
64
65 HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context);
66 BOOL CheckDDResult(HRESULT ddresult, char *funcname);
67 BOOL DDRestoreCanvas(dd_grs_canvas *canvas);
68
69
70 //      Direct Draw Initialization
71 // ----------------------------------------------------------------------------
72
73 BOOL DDInit(int mode)
74 {
75         LPDIRECTDRAW lpdd;
76         DDCAPS ddcaps, ddcaps2;
77         HRESULT ddresult;
78         int num;
79
80         DDWnd = GetLibraryWindow();
81
82 //      Create Direct Draw Object (Use Emulation if Hardware is off)
83         if (!_lpDD)     {
84                 ddresult = DirectDrawCreate(NULL, &lpdd, NULL);
85                 
86                 if (ddresult == DDERR_NODIRECTDRAWHW) {
87          ddresult = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &lpdd, NULL );
88                         if (!CheckDDResult(ddresult, "InitDD:DirectDrawCreate emulation"))
89                                 return FALSE;
90                         DDUseEmulation = TRUE;
91                         logentry("DirectDraw: forcing emulation.\n");
92                 }
93                 else if (ddresult != DD_OK) return FALSE;
94                 logentry("DirectDraw: DirectX API hardware compliant.\n");
95         }
96         else return FALSE;
97
98         atexit(DDKill);
99
100 //      Determine hardware caps
101 //      Determine capture mode (fullscreen takes exclusive, window is normal)
102         if (mode == DDGR_FULLSCREEN) {
103                 DWORD flags;
104
105                 flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
106
107         #ifndef NDEBUG
108                 if (!FindArg("-nomodex")) flags |= DDSCL_ALLOWMODEX;
109         #else
110                 flags |= DDSCL_ALLOWMODEX;
111         #endif
112
113                 if (!FindArg("-disallowreboot")) flags |= DDSCL_ALLOWREBOOT;
114  
115                 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd, flags); 
116
117                 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel")) {  
118                         IDirectDraw_Release(lpdd);
119                         return FALSE;
120                 }
121
122                 _DDExclusive = TRUE;
123                 _DDFullScreen = TRUE;                   
124         }
125         else if (mode == DDGR_EXWINDOW) {
126                 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd,
127                                                                                 DDSCL_EXCLUSIVE |
128                                                                                 DDSCL_FULLSCREEN);
129                 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel"))
130                         return FALSE;
131                 _DDExclusive = TRUE;
132                 _DDFullScreen = FALSE;
133         }
134         else if (mode == DDGR_WINDOW) {
135                 ddresult = IDirectDraw_SetCooperativeLevel(lpdd, DDWnd,
136                                                                                 DDSCL_NORMAL);
137                 if (!CheckDDResult(ddresult, "DDInit::SetCooperativeLevel"))
138                         return FALSE;
139                 _DDExclusive = FALSE;
140                 _DDFullScreen = FALSE;
141         }
142         else return FALSE;
143         
144 //      Get Display modes/Window Sizes
145 //      Force invalidation of all modes for now
146         for (num = 0; num < 16; num++)
147         {
148                 _DDModeList[num].rw = _DDModeList[num].w = -1;
149                 _DDModeList[num].rh = _DDModeList[num].h = -1;
150         }
151
152         W95DisplayMode = SM95_640x480x8;
153         num = 0;
154         if (mode == DDGR_FULLSCREEN) {
155                 ddresult = IDirectDraw_EnumDisplayModes(lpdd, 0, NULL, 0, 
156                                                                         EnumDispModesCB);
157                 if(!CheckDDResult(ddresult, "DDInit::EnumDisplayModes")) {
158                         IDirectDraw_Release(lpdd);
159                         return FALSE;
160                 }
161         }
162         else if (mode == DDGR_EXWINDOW) {
163                 _DDModeList[SM95_320x200x8X].rw = 320;
164                 _DDModeList[SM95_320x200x8X].rh = 200;
165                 _DDModeList[SM95_320x200x8X].w = 640;
166                 _DDModeList[SM95_320x200x8X].h = 480;
167                 _DDModeList[SM95_320x200x8X].emul = 1;
168                 _DDModeList[SM95_320x200x8X].dbuf = 0;
169                 _DDModeList[SM95_320x200x8X].modex = 0;
170                 _DDModeList[SM95_320x200x8X].paged = 0; 
171
172                 _DDModeList[SM95_640x480x8].rw = 640;
173                 _DDModeList[SM95_640x480x8].rh = 480;
174                 _DDModeList[SM95_640x480x8].w = 640;
175                 _DDModeList[SM95_640x480x8].h = 480;
176                 _DDModeList[SM95_640x480x8].emul = 1;
177                 _DDModeList[SM95_640x480x8].dbuf = 0;
178                 _DDModeList[SM95_640x480x8].modex = 0;
179                 _DDModeList[SM95_640x480x8].paged = 0; 
180
181                 _DDModeList[SM95_800x600x8].rw = 800;
182                 _DDModeList[SM95_800x600x8].rh = 600;
183                 _DDModeList[SM95_800x600x8].w = 640;
184                 _DDModeList[SM95_800x600x8].h = 480;
185                 _DDModeList[SM95_800x600x8].emul = 1;
186                 _DDModeList[SM95_800x600x8].dbuf = 0;
187                 _DDModeList[SM95_800x600x8].modex = 0;
188                 _DDModeList[SM95_800x600x8].paged = 0; 
189                 _DDNumModes = 3;
190         }
191         else if (mode == DDGR_WINDOW) { 
192                 _DDModeList[SM95_320x200x8X].rw = 320;
193                 _DDModeList[SM95_320x200x8X].rh = 200;
194                 _DDModeList[SM95_320x200x8X].w = 640;
195                 _DDModeList[SM95_320x200x8X].h = 480;
196                 _DDModeList[SM95_320x200x8X].emul = 1;
197                 _DDModeList[SM95_320x200x8X].dbuf = 0;
198                 _DDModeList[SM95_320x200x8X].modex = 0;
199                 _DDModeList[SM95_320x200x8X].paged = 0; 
200
201                 _DDModeList[SM95_640x480x8].rw = 640;
202                 _DDModeList[SM95_640x480x8].rh = 480;
203                 _DDModeList[SM95_640x480x8].w = 640;
204                 _DDModeList[SM95_640x480x8].h = 480;
205                 _DDModeList[SM95_640x480x8].emul = 1;
206                 _DDModeList[SM95_640x480x8].dbuf = 0;
207                 _DDModeList[SM95_640x480x8].modex = 0;
208                 _DDModeList[SM95_640x480x8].paged = 0; 
209
210                 _DDModeList[SM95_800x600x8].rw = 800;
211                 _DDModeList[SM95_800x600x8].rh = 600;
212                 _DDModeList[SM95_800x600x8].w = 800;
213                 _DDModeList[SM95_800x600x8].h = 600;
214                 _DDModeList[SM95_800x600x8].emul = 1;
215                 _DDModeList[SM95_800x600x8].dbuf = 0;
216                 _DDModeList[SM95_800x600x8].modex = 0;
217                 _DDModeList[SM95_800x600x8].paged = 0; 
218                 _DDNumModes = 3;
219         }
220         else return FALSE;
221
222 //      Set appropriate display mode or window mode
223
224         _lpDD = lpdd;
225
226         memset(&ddcaps, 0, sizeof(ddcaps));
227         ddcaps.dwSize = sizeof(ddcaps);
228         ddcaps2.dwSize = sizeof(ddcaps);
229         ddresult = IDirectDraw_GetCaps(_lpDD, &ddcaps, NULL);
230         if (!CheckDDResult(ddresult, "InitDD::GetCaps")) 
231                 return FALSE;
232
233         logentry("DirectDraw: VRAM free:  %d\n", ddcaps.dwVidMemFree);  
234         logentry("DirectDraw: VRAM total: %d\n", ddcaps.dwVidMemTotal);
235
236 #ifndef NDEBUG
237         if (FindArg("-TsengDebug1")) {
238                 IDirectDraw_Release(lpdd);
239                 return FALSE;
240         }
241 #endif
242
243         DDSetDisplayMode(W95DisplayMode, 0);
244
245 #ifndef NDEBUG
246         if (FindArg("-TsengDebug2")) {
247                 IDirectDraw_Release(lpdd);
248                 return FALSE;
249         }
250 #endif
251         
252         // If 'windowed' do this.
253         if (!_DDFullScreen) 
254         {
255                         ddresult = IDirectDraw_CreateClipper(_lpDD, 0, &_lpDDClipper, NULL);
256                         if (!CheckDDResult(ddresult, "DDCreateScreen::CreateClipper"))
257                                 return FALSE;
258
259                         ddresult = IDirectDrawClipper_SetHWnd(_lpDDClipper, 0, DDWnd);
260                         if (!CheckDDResult(ddresult, "DDCreateScreen::SetHWnd"))
261                                 return FALSE;
262
263                         ddresult = IDirectDrawSurface_SetClipper(_lpDDSPrimary, _lpDDClipper);
264                         if (!CheckDDResult(ddresult, "DDCreateScreen::SetClipper"))
265                                 return FALSE;
266         }
267
268 //      Register Optimizations
269
270         ddcaps.dwSize = sizeof(ddcaps);
271         ddcaps2.dwSize = sizeof(ddcaps);
272         ddresult = IDirectDraw_GetCaps(lpdd, &ddcaps, &ddcaps2);
273         if (!CheckDDResult(ddresult, "DDInit::GetCaps"))
274                 return FALSE;
275
276 #ifndef NDEBUG
277         if (FindArg("-TsengDebug3")) {
278                 IDirectDraw_Release(lpdd);
279                 return FALSE;
280         }
281 #endif
282
283         if (FindArg("-vidram")) {
284                 logentry("DirectDraw: Forcing VRAM rendering.\n");
285                 _DDSysMemSurfacing = FALSE;
286         }
287         else if (FindArg("-sysram")) {
288                 logentry("DirectDraw: Forcing SRAM rendering.\n");
289                 _DDSysMemSurfacing = TRUE;
290         }
291         else if (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) {
292                 logentry("DirectDraw: Hardware is bank-switched.  Using SRAM rendering.\n");
293                 _DDSysMemSurfacing = TRUE;
294         }
295         else {
296                 logentry("DirectDraw: Hardware is not bank-switched.  Using VRAM rendering.\n");
297                 _DDSysMemSurfacing = FALSE;
298         }
299                 
300         if (ddcaps.dwCaps       & DDCAPS_COLORKEYHWASSIST) 
301                 ddDriverCaps.hwcolorkey = 1;
302         else 
303                 ddDriverCaps.hwcolorkey = 0;
304         if (ddcaps.dwCaps & DDCAPS_BLTSTRETCH)
305                 ddDriverCaps.hwbltstretch = 1;
306         else 
307                 ddDriverCaps.hwbltstretch = 0;
308                 
309
310 //@@    mprintf((0, "DD::Hardware="));
311 //@@    if (ddcaps.dwCaps & DDCAPS_NOHARDWARE) mprintf((0, "Off\n"));
312 //@@    else mprintf((0, "On\n"));
313 //@@
314 //@@    mprintf((0, "DD::VideoMem=%u bytes\n", ddcaps.dwVidMemTotal));
315
316 //@@    mprintf((0, "DD::SrcColorKey="));       
317 //@@    if (ddcaps.dwCKeyCaps & DDCKEYCAPS_SRCBLT) mprintf((0, "Hardware\n"));
318 //@@    else mprintf((0, "Emulation\n"));
319
320         return TRUE;
321 }
322
323
324 //      Direct Draw Destruction
325 // ----------------------------------------------------------------------------
326
327 void DDKill()
328 {
329 //      Perform cleanup for full screen case and window case
330         DDKillScreen();
331         if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette);
332         if (_lpDD) IDirectDraw_Release(_lpDD);
333
334         _DDExclusive = _DDFullScreen = FALSE;
335         _DDNumModes = 0;
336         _DDLockCounter = 0;
337         _lpDD = NULL;
338 }
339
340
341 //      Direct Draw Surface Creation
342 //              Create Screen (Page 0 and possibly Page 1 or offscreen buffer)
343 // ----------------------------------------------------------------------------
344
345 BOOL DDCreateScreen(int flags)
346 {
347         DDSCAPS ddscaps;
348         DDCAPS ddcaps, ddcaps2;
349         DDSURFACEDESC ddsd;
350         HRESULT ddresult;
351
352         memset(&ddcaps, 0, sizeof(ddcaps));
353         memset(&ddcaps2, 0, sizeof(ddcaps2));
354         ddcaps.dwSize = sizeof(ddcaps);
355         ddcaps2.dwSize = sizeof(ddcaps);
356         ddresult = IDirectDraw_GetCaps(_lpDD, &ddcaps, &ddcaps2);
357         if (!CheckDDResult(ddresult, "DDCreateScreen::GetCaps"))
358                 return FALSE;
359
360
361         logentry("DirectDraw HW Caps:  %x\nDirectDraw HEL Caps: %x\n",ddcaps.dwCaps,ddcaps2.dwCaps);
362         if (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) {
363                 logentry("DirectDraw: Hardware is bank-switched.  Using SRAM rendering.\n");
364                 _DDSysMemSurfacing = TRUE;
365         }
366         else {
367                 logentry("DirectDraw: Hardware is not bank-switched.  Using VRAM rendering.\n");
368                 _DDSysMemSurfacing = FALSE;
369         }
370
371 //      Determine GFX caps.
372         if (ddcaps.dwCaps       & DDCAPS_COLORKEYHWASSIST) 
373                 ddDriverCaps.hwcolorkey = 1;
374         else 
375                 ddDriverCaps.hwcolorkey = 0;
376         if (ddcaps.dwCaps & DDCAPS_BLTSTRETCH)
377                 ddDriverCaps.hwbltstretch = 1;
378         else 
379                 ddDriverCaps.hwbltstretch = 0;
380         
381         memset(&ddsd, 0, sizeof(ddsd));
382         ddsd.dwSize = sizeof(ddsd);
383
384         if (_DDFullScreen && GRMODEINFO(paged)) {
385         //      We should use page flipping
386                 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
387                 ddsd.dwBackBufferCount = 1;
388                 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
389                                                                                 DDSCAPS_FLIP |
390                                                                                 DDSCAPS_COMPLEX;
391                 ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
392                 if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -fullscreen"))
393                         return FALSE;
394                         
395                 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
396                 ddresult = IDirectDrawSurface_GetAttachedSurface(_lpDDSPrimary,
397                                                                                                         &ddscaps, &_lpDDSBack);
398                 if (!CheckDDResult(ddresult, "DDCreateScreen::GetAttachedSurface"))
399                         return FALSE;
400         }
401         else {
402         // We just create a primary and offscreen buffer
403                 if (GRMODEINFO(emul) && !_lpDDSPrimary) {
404                 // make sure we don't reinitialize the screen if we already made it
405                 //      beforehand for windowed version
406                         ddsd.dwFlags = DDSD_CAPS;
407                         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
408                         ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
409                         if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -windowed"))
410                                 return FALSE;
411                 }
412                 else if (!GRMODEINFO(emul)) {
413                 // If we aren't emulating
414                         ddsd.dwFlags = DDSD_CAPS;
415                         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
416                         ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &_lpDDSPrimary, NULL);
417                         if (!CheckDDResult(ddresult, "DDCreateScreen::CreateSurface -windowed"))
418                                 return FALSE;
419                 }
420
421                 if (GRMODEINFO(emul)) {
422                         _lpDDSBack = DDCreateSurface(_DDModeList[W95DisplayMode].rw, 
423                                                                                 _DDModeList[W95DisplayMode].rh, 1);
424                         if (!_lpDDSBack) {
425                                 mprintf((0,"Call to create DDSBackBuffer failed."));
426                                 return FALSE;
427                         }
428                 }
429                 else _lpDDSBack = NULL; 
430         
431         }
432
433 //      Create 8-bit palette
434         {
435                 ubyte pal[768];
436                 memset(pal, 0, 768);
437                 
438                 memset(&ddsd, 0, sizeof(ddsd));
439                 ddsd.dwSize = sizeof(ddsd);
440                 IDirectDrawSurface_GetSurfaceDesc(_lpDDSPrimary, &ddsd);
441
442                 logentry("Primary surface pixel format: %x, %d\n", ddsd.ddpfPixelFormat.dwFlags, ddsd.ddpfPixelFormat.dwRGBBitCount); 
443
444                 _lpDDPalette = DDCreatePalette(pal);
445                 Assert(_lpDDPalette != NULL);
446                 DDSetPalette(_lpDDPalette);
447         }
448
449         return TRUE;
450 }
451
452
453 //      DirectDraw Screen Kill
454 //      ----------------------------------------------------------------------------
455
456 void DDKillScreen()
457 {
458         if (_lpDDClipper) IDirectDrawClipper_Release(_lpDDClipper);
459         if (_lpDDPalette) IDirectDrawPalette_Release(_lpDDPalette);
460         if (_lpDDSBack) IDirectDrawSurface_Release(_lpDDSBack);
461         if (_lpDDSPrimary) {
462
463                 if (!GRMODEINFO(modex)) {
464                         DDBLTFX ddbltfx;
465                         HRESULT ddresult;
466
467                         memset(&ddbltfx, 0, sizeof(DDBLTFX));
468                 ddbltfx.dwSize = sizeof( ddbltfx );
469                    ddbltfx.dwFillColor = (WORD)(BM_XRGB(0,0,0));
470
471                 ddresult = IDirectDrawSurface_Blt(
472                             _lpDDSPrimary,                      // dest surface
473                             NULL,                       // dest rect
474                             NULL,                  // src surface
475                             NULL,                  // src rect
476                             DDBLT_COLORFILL | DDBLT_WAIT,
477                             &ddbltfx);
478                 }
479
480                 IDirectDrawSurface_Release(_lpDDSPrimary);
481         }
482
483         _lpDDClipper = NULL;
484         _lpDDPalette = NULL;
485         _lpDDSBack = NULL;
486         _lpDDSPrimary = NULL;
487 }       
488
489
490 void DDKillEmulatedScreen()
491 {
492         if (_lpDDSBack) IDirectDrawSurface_Release(_lpDDSBack);
493
494         _lpDDSBack = NULL;
495 }
496
497
498 //      DDSetDisplayMode
499 //      ----------------------------------------------------------------------------
500
501 void DDSetDisplayMode(int display_mode, int flags)
502 {
503         HRESULT ddresult;
504
505         W95DisplayMode = display_mode;
506         W95OldDisplayMode = display_mode;
507         if (_DDFullScreen) {
508                 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);
509         
510                 DDKillScreen();
511                 ddresult = IDirectDraw_SetDisplayMode(_lpDD, _DDModeList[W95DisplayMode].w,
512                                                                                 _DDModeList[W95DisplayMode].h,
513                                                                                 _DDModeList[W95DisplayMode].bpp);
514                 if (!CheckDDResult(ddresult, "DDInit::SetDisplayMode")) {
515                         Error("Unable to set display mode: %d.\n", W95DisplayMode);
516                 }
517                 DDCreateScreen(flags);
518         }
519         else {
520                 RECT rect;
521                 DWORD dwStyle;
522
523                 DDKillEmulatedScreen();
524
525                 dwStyle = GetWindowLong(DDWnd, GWL_STYLE);
526                 dwStyle &= ~WS_POPUP;
527                 dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
528
529                 SetRect(&rect, 0, 0, _DDModeList[W95DisplayMode].w,
530                                 _DDModeList[W95DisplayMode].h); 
531                 SetWindowLong(DDWnd, GWL_STYLE, dwStyle);
532                 AdjustWindowRectEx(&rect, 
533                                                 GetWindowLong(DDWnd, GWL_STYLE),
534                                                 GetMenu(DDWnd)!=NULL,
535                                                 GetWindowLong(DDWnd, GWL_EXSTYLE));
536
537                 SetWindowPos(DDWnd, NULL, 0,0,
538                                         rect.right-rect.left,
539                                         rect.bottom-rect.top,
540                                 SWP_NOMOVE | 
541                                 SWP_NOZORDER | 
542                                 SWP_NOACTIVATE);
543                 SetWindowPos(DDWnd, HWND_NOTOPMOST, 0, 0, 0, 0, 
544                                 SWP_NOSIZE |
545                                 SWP_NOMOVE |
546                                 SWP_NOACTIVATE);
547
548                 DDCreateScreen(flags);
549         }
550 }
551
552
553 //      DDRestoreScreen
554 //              Restore screens 
555 //      ----------------------------------------------------------------------------
556 int DDRestoreScreen()
557 {
558         mprintf((1, "Need to Restore DDraw Page0 and Page1.\n"));
559         if (!_lpDDSPrimary || IDirectDrawSurface_Restore(_lpDDSPrimary) !=DD_OK) {
560                 mprintf((1, "Warning: Unable to restore Primary Surface.\n"));
561                 return 0;
562         }
563         if (!GRMODEINFO(paged) && _lpDDSBack) {
564                 if (IDirectDrawSurface_Restore(_lpDDSBack) != DD_OK) {
565                         mprintf((1, "Warning: Unable to restore Back Surface.\n"));
566                         return 0;
567                 }
568         }
569         else if (!_DDFullScreen) {
570                 if (!_lpDDSBack || IDirectDrawSurface_Restore(_lpDDSBack) != DD_OK) {
571                         mprintf((1, "Warning: Unable to restore Back Surface.\n"));
572                         return 0;
573                 }
574         }
575
576         return 1;
577 }
578
579
580 //      DDFlip
581 //              Flip Screens using DirectDraw::Flip
582 //      ----------------------------------------------------------------------------
583 void DDFlip()
584 {
585         HRESULT ddresult;
586
587         ddresult = IDirectDrawSurface_Flip(_lpDDSPrimary, NULL, 0);
588         if (ddresult != DD_OK) {
589                 mprintf((1, "DDFlip:: Unable to flip screen (%X)\n", ddresult));
590                 Int3();                                                                 // Bad flipping
591         }
592 }
593
594
595 //      DDCreateSurface
596 //              Create an offscreen surface hopefully in video memory
597 //      ----------------------------------------------------------------------------
598 LPDIRECTDRAWSURFACE DDCreateSurface(int width, int height, BOOL vram)
599 {
600         DDSURFACEDESC ddsd;
601         HRESULT ddresult;
602         LPDIRECTDRAWSURFACE lpdds;
603         DDCOLORKEY ddck;
604
605         if (_DDSysMemSurfacing && !vram) return DDCreateSysMemSurface(width, height);
606
607         memset(&ddsd, 0, sizeof(ddsd));
608         ddsd.dwSize = sizeof(ddsd);
609         ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
610         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
611         ddsd.dwWidth = width;
612         ddsd.dwHeight = height;
613
614 //      logentry("Creating %dx%d sysram/vidram surface.\n", width, height);
615         ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
616         if (ddresult != DD_OK) {
617                 logentry("DDRAW::CreateSurface err: %x\n", ddresult);           
618                 return NULL;
619         }
620
621         return lpdds;
622 }
623
624
625 LPDIRECTDRAWSURFACE DDCreateSysMemSurface(int width, int height)
626 {
627         DDSURFACEDESC ddsd;
628         HRESULT ddresult;
629         LPDIRECTDRAWSURFACE lpdds;
630
631         memset(&ddsd, 0, sizeof(ddsd));
632         ddsd.dwSize = sizeof(ddsd);
633         ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
634         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
635         ddsd.dwWidth = width;
636         ddsd.dwHeight = height;
637
638 //      logentry("Creating %dx%d sysram surface.\n", width, height);
639         ddresult = IDirectDraw_CreateSurface(_lpDD, &ddsd, &lpdds, NULL);
640         if (ddresult != DD_OK) {
641                 logentry("DDRAW::CreateSysMemSurface err: %x\n", ddresult);             
642                 return NULL;
643         }
644
645         return lpdds;
646 }
647
648
649 //      DDGetPalette
650 //      ----------------------------------------------------------------------------
651 LPDIRECTDRAWPALETTE DDGetPalette(LPDIRECTDRAWSURFACE lpdds)
652 {
653         HRESULT ddresult;
654         LPDIRECTDRAWPALETTE lpddp;
655
656         ddresult = IDirectDrawSurface_GetPalette(lpdds, &lpddp);
657         if (ddresult != DD_OK) {
658                 mprintf((1, "DDERR: GetPalette %x.\n", ddresult));
659                 return NULL;
660         }
661         return lpddp;
662 }
663         
664
665 //      DDCreatePalette
666 //      ----------------------------------------------------------------------------
667 LPDIRECTDRAWPALETTE DDCreatePalette(ubyte *pal)
668 {
669         HRESULT ddresult;
670         LPDIRECTDRAWPALETTE lpddpal;
671         PALETTEENTRY pe[256];
672         int i;
673
674         for (i = 0; i < 256; i++)
675         {
676                 pe[i].peRed = pal[i*3];
677                 pe[i].peGreen = pal[i*3+1];
678                 pe[i].peBlue = pal[i*3+2];
679                 pe[i].peFlags = 0;
680         }
681
682         ddresult = IDirectDraw_CreatePalette(_lpDD, 
683                                                                 DDPCAPS_8BIT | DDPCAPS_ALLOW256, 
684                                                                 pe, 
685                                                                 &lpddpal, NULL);
686         if (ddresult != DD_OK) {
687                 mprintf((1, "DDERR: CreatePalette %x.\n", ddresult));
688                 return NULL;
689         }
690         
691         return lpddpal;
692 }
693
694
695 //      DDSetPalette
696 //      ----------------------------------------------------------------------------
697 void DDSetPalette(LPDIRECTDRAWPALETTE lpDDPal)
698 {
699         HRESULT ddresult;
700
701         ddresult = IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal);
702         if (ddresult != DD_OK) {
703                 if (ddresult == DDERR_SURFACELOST) {
704                         IDirectDrawSurface_Restore(_lpDDSPrimary);
705                         IDirectDrawSurface_SetPalette(_lpDDSPrimary, lpDDPal);
706                 }
707                 else {
708                         Error("Unable to attach palette to primary surface: %x.", ddresult);
709                 }
710         }
711 }
712
713
714 //      DDLock and DDUnlock Canvas
715 //              This is required to access any canvas.
716 //      ----------------------------------------------------------------------------
717 #ifndef NDEBUG
718 void DDLockCanvas_D(dd_grs_canvas *canvas, char *filename, int line)
719 {
720         HRESULT ddresult;
721         DDSURFACEDESC ddsd;
722         RECT rect;
723         grs_bitmap *bmp;
724
725
726         bmp = &canvas->canvas.cv_bitmap;
727         memset(&ddsd, 0, sizeof(ddsd));
728         ddsd.dwSize = sizeof(ddsd);
729         
730         if (canvas->lock_count == 0) {
731         // Obtain info about a rectangle on the surface
732                 SetRect(&rect, bmp->bm_x, bmp->bm_y, 
733                                 bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h);
734
735         RetryLock:
736
737                 ddresult = IDirectDrawSurface_Lock(canvas->lpdds,       
738                                                                                 &rect,
739                                                                                 &ddsd,
740                                                                                 DDLOCK_WAIT,
741                                                                                 NULL);
742                 if (ddresult != DD_OK) {
743                         if (ddresult == DDERR_SURFACELOST) {
744                                 if (!DDRestoreCanvas(canvas))
745                                         Error("Unable to restore surface for lock:%x (%s line %d)\n", ddresult, filename, line);
746                                 else goto RetryLock;
747                         }
748                         else {
749                                 while (canvas->lock_count) DDUnlockCanvas(canvas);
750                                 Error("Unable to lock canvas: %x (%s line %d)\n", ddresult, filename, line);
751                         }
752                 }
753                 bmp->bm_data = (unsigned char *)ddsd.lpSurface;
754                 bmp->bm_rowsize = (short)ddsd.lPitch;
755
756 //              if (canvas->sram && !GRMODEINFO(modex)) {
757 //              //      Manually calculate?
758 //                      bmp->bm_data = bmp->bm_data + (bmp->bm_y*bmp->bm_rowsize);
759 //                      bmp->bm_data += bmp->bm_x;
760 //              } 
761
762                 _DDLockCounter++;
763         }
764         canvas->lock_count++;
765 }
766 #endif
767
768
769 void DDLockCanvas(dd_grs_canvas *canvas)
770 {
771         HRESULT ddresult;
772         DDSURFACEDESC ddsd;
773         RECT rect;
774         grs_bitmap *bmp;
775
776
777         bmp = &canvas->canvas.cv_bitmap;
778         memset(&ddsd, 0, sizeof(ddsd));
779         ddsd.dwSize = sizeof(ddsd);
780         
781         if (canvas->lock_count == 0) {
782         // Obtain info about a rectangle on the surface
783                 SetRect(&rect, bmp->bm_x, bmp->bm_y, 
784                                 bmp->bm_x+bmp->bm_w, bmp->bm_y+bmp->bm_h);
785
786         RetryLock:
787
788                 ddresult = IDirectDrawSurface_Lock(canvas->lpdds,       
789                                                                                 &rect,
790                                                                                 &ddsd,
791                                                                                 DDLOCK_WAIT,
792                                                                                 NULL);
793                 if (ddresult != DD_OK) {
794                         if (ddresult == DDERR_SURFACELOST) {
795                                 if (!DDRestoreCanvas(canvas))
796                                         Error("Unable to restore surface for lock:");
797                                 else goto RetryLock;
798                         }
799                         else {
800                                 while (canvas->lock_count) DDUnlockCanvas(canvas);
801                                 Error("Unable to lock canvas: %x\n", ddresult);
802                         }
803                 }
804                 bmp->bm_data = (unsigned char *)ddsd.lpSurface;
805                 bmp->bm_rowsize = (short)ddsd.lPitch;
806
807 //              if (canvas->sram && !GRMODEINFO(modex)) {
808 //              //      Manually calculate?
809 //                      bmp->bm_data = bmp->bm_data + (bmp->bm_y*bmp->bm_rowsize);
810 //                      bmp->bm_data += bmp->bm_x;
811 //              } 
812
813                 _DDLockCounter++;
814         }
815         canvas->lock_count++;
816 }
817
818
819 void DDUnlockCanvas(dd_grs_canvas *canvas)
820 {
821         HRESULT ddresult;
822         grs_bitmap *bmp;
823
824         bmp = &canvas->canvas.cv_bitmap;
825         
826         if (canvas->lock_count == 1) {
827 //              if (canvas->sram && !GRMODEINFO(modex)) {
828 //                      bmp->bm_data = bmp->bm_data - bmp->bm_x;
829 //                      bmp->bm_data = bmp->bm_data - (bmp->bm_y*bmp->bm_rowsize);
830 //              }
831                 ddresult = IDirectDrawSurface_Unlock(canvas->lpdds, 
832                                                                 canvas->canvas.cv_bitmap.bm_data);
833                 if (ddresult != DD_OK) {        
834                                 Error("Unable to unlock canvas: %x\n", ddresult);
835                                 exit(1);
836                 }
837
838                 canvas->canvas.cv_bitmap.bm_data = NULL;
839                 canvas->canvas.cv_bitmap.bm_rowsize = 0;
840                 _DDLockCounter--;
841         }
842         canvas->lock_count--;
843 }
844
845
846 void DDLockDebug()
847 {
848         logentry("VRAM locks: %d.  SRAM locks: %d\n", DDVideoLocks, DDSystemLocks);
849 }
850
851
852
853 //      DDFreeSurface
854 //      ----------------------------------------------------------------------------
855 void DDFreeSurface(LPDIRECTDRAWSURFACE lpdds)
856 {
857         HRESULT ddresult;
858
859         Assert(lpdds != NULL);
860
861         ddresult = IDirectDrawSurface_Release(lpdds);
862         if (ddresult != DD_OK) {
863                 logentry("DDRAW::FreeSurface err: %x\n", ddresult);             
864                 Error("DDFreeSurface: Unable to free surface.");
865         }
866 }
867
868
869 //      DDRestoreCanvas
870 //      ----------------------------------------------------------------------------
871 BOOL DDRestoreCanvas(dd_grs_canvas *canvas)
872 {
873         HRESULT ddresult;
874         
875         Assert(canvas->lpdds != NULL);
876         
877         ddresult = IDirectDrawSurface_Restore(canvas->lpdds);
878         if (ddresult != DD_OK) {
879                 if (ddresult != DDERR_WRONGMODE) {
880                         logentry("DDRAW::RestoreCanvas::Surface err: %x\n", ddresult);          
881                         return FALSE;
882                 }
883                 mprintf((0, "Recreating surfaces:\n"));
884         // Must recreate canvas
885                 if (canvas->lpdds == _lpDDSPrimary || canvas->lpdds == _lpDDSBack) {
886                         mprintf((0, "DDRestoreCanvas::Screen memory was lost!\n"));
887                         exit(1);
888                 }
889                 if (canvas->sram) {
890                 // force sysmem canvas!
891                         canvas->lpdds = DDCreateSysMemSurface(canvas->canvas.cv_bitmap.bm_w,
892                                                                                         canvas->canvas.cv_bitmap.bm_h);
893                 }
894                 else {
895                         canvas->lpdds = DDCreateSurface(canvas->canvas.cv_bitmap.bm_w, 
896                                                                                         canvas->canvas.cv_bitmap.bm_h,
897                                                                                         _DDSysMemSurfacing);
898                 }                                       
899         }
900         return TRUE;
901 }
902
903
904
905 //      CheckDDResult
906 //      ----------------------------------------------------------------------------
907 BOOL CheckDDResult(HRESULT ddresult, char *funcname)
908 {
909         char buf[256];
910
911         if (ddresult != DD_OK) {
912                 sprintf(buf, "DirectDraw error %x detected in\r\n\t%s", ddresult, funcname);
913                 logentry(buf);
914                 MessageBox(NULL, buf, "DESCENT2::DDRAW", MB_OK);
915                 return FALSE;
916         }
917         else return TRUE;
918 }
919
920
921 //      EnumDispModesCB
922 //      ----------------------------------------------------------------------------
923 HRESULT CALLBACK EnumDispModesCB(LPDDSURFACEDESC lpddsd, LPVOID context)
924 {
925         DWORD width, height,bpp;
926         int mode;
927         DWORD modex;    
928
929         width = lpddsd->dwWidth;
930         height = lpddsd->dwHeight;
931         bpp = lpddsd->ddpfPixelFormat.dwRGBBitCount;
932         modex = lpddsd->ddsCaps.dwCaps;
933
934         modex = modex & DDSCAPS_MODEX;
935
936         if (width == 640 && height == 480 && bpp==8)   
937                 mode = SM95_640x480x8;
938         else if (width == 640 && height == 400 && bpp==8)
939                 mode = SM95_640x400x8;
940         else if (width == 320 && height == 200 && bpp==8) 
941                 mode = SM95_320x200x8X;
942         else if (width == 800 && height == 600 && bpp==8) 
943                 mode = SM95_800x600x8;
944         else if (width == 1024 && height == 768 && bpp==8)
945                 mode = SM95_1024x768x8;
946         else
947                 return DDENUMRET_OK;
948
949         _DDModeList[mode].rw            = width;
950         _DDModeList[mode].rh            = height;
951         _DDModeList[mode].emul          = 0;
952         _DDModeList[mode].modex         = 0;
953         _DDModeList[mode].paged         = 0;
954         _DDModeList[mode].dbuf          = 0;
955
956         if (mode == SM95_320x200x8X) {
957                 _DDModeList[mode].modex = 1;
958                 _DDModeList[mode].dbuf = 1;
959                 _DDModeList[mode].paged = 1;
960         }
961         else if (mode == SM95_640x400x8) {
962         //      Support a range of emulated modes
963         //      320x200x8 Double Pixeled
964                 _DDModeList[SM95_320x200x8].rw = 320;
965                 _DDModeList[SM95_320x200x8].rh = 200;
966                 _DDModeList[SM95_320x200x8].emul = 1;
967                 _DDModeList[SM95_320x200x8].dbuf = 0;
968                 _DDModeList[SM95_320x200x8].modex = 0;
969                 _DDModeList[SM95_320x200x8].paged = 0; 
970                 _DDModeList[SM95_320x200x8].w = 640;
971                 _DDModeList[SM95_320x200x8].h = 400;
972                 _DDModeList[SM95_320x200x8].bpp = 8;
973                 
974                 _DDModeList[SM95_320x400x8].rw = 320;
975                 _DDModeList[SM95_320x400x8].rh = 400;
976                 _DDModeList[SM95_320x400x8].emul = 1;
977                 _DDModeList[SM95_320x400x8].dbuf = 0;
978                 _DDModeList[SM95_320x400x8].modex = 0;
979                 _DDModeList[SM95_320x400x8].paged = 0; 
980                 _DDModeList[SM95_320x400x8].w = 640;
981                 _DDModeList[SM95_320x400x8].h = 400;
982                 _DDModeList[SM95_320x400x8].bpp = 8;
983
984                 _DDNumModes+=2;
985
986                 _DDModeList[mode].dbuf = 1;
987         }
988         else {
989                 _DDModeList[mode].dbuf = 1;
990         }
991
992    _DDModeList[mode].w   = width;
993    _DDModeList[mode].h   = height;
994    _DDModeList[mode].bpp = bpp;
995
996     _DDNumModes++;
997
998     return DDENUMRET_OK;
999 }
1000
1001
1002 int DDCheckMode(int mode)
1003 {
1004         if (_DDModeList[mode].w==-1 && _DDModeList[mode].h==-1) return 1;
1005         else return 0;
1006 }