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 
DDInit(int mode)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 
DDKill()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 
DDCreateScreen(int flags)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 
DDKillScreen()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 
DDKillEmulatedScreen()490 void DDKillEmulatedScreen()
491 {
492 	if (_lpDDSBack) IDirectDrawSurface_Release(_lpDDSBack);
493 
494 	_lpDDSBack = NULL;
495 }
496 
497 
498 //	DDSetDisplayMode
499 //	----------------------------------------------------------------------------
500 
DDSetDisplayMode(int display_mode,int flags)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 //	----------------------------------------------------------------------------
DDRestoreScreen()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 //	----------------------------------------------------------------------------
DDFlip()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 //	----------------------------------------------------------------------------
DDCreateSurface(int width,int height,BOOL vram)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 
DDCreateSysMemSurface(int width,int height)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 //	----------------------------------------------------------------------------
DDGetPalette(LPDIRECTDRAWSURFACE lpdds)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 //	----------------------------------------------------------------------------
DDCreatePalette(ubyte * pal)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 //	----------------------------------------------------------------------------
DDSetPalette(LPDIRECTDRAWPALETTE lpDDPal)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
DDLockCanvas_D(dd_grs_canvas * canvas,char * filename,int line)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 
DDLockCanvas(dd_grs_canvas * canvas)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 
DDUnlockCanvas(dd_grs_canvas * canvas)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 
DDLockDebug()846 void DDLockDebug()
847 {
848 	logentry("VRAM locks: %d.  SRAM locks: %d\n", DDVideoLocks, DDSystemLocks);
849 }
850 
851 
852 
853 //	DDFreeSurface
854 //	----------------------------------------------------------------------------
DDFreeSurface(LPDIRECTDRAWSURFACE lpdds)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 //	----------------------------------------------------------------------------
DDRestoreCanvas(dd_grs_canvas * canvas)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 //	----------------------------------------------------------------------------
CheckDDResult(HRESULT ddresult,char * funcname)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 //	----------------------------------------------------------------------------
EnumDispModesCB(LPDDSURFACEDESC lpddsd,LPVOID context)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 
DDCheckMode(int mode)1002 int DDCheckMode(int mode)
1003 {
1004 	if (_DDModeList[mode].w==-1 && _DDModeList[mode].h==-1) return 1;
1005 	else return 0;
1006 }
1007