]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grdirectdraw.cpp
Initial revision
[taylor/freespace2.git] / src / graphics / grdirectdraw.cpp
1 /*
2  * $Logfile: /Freespace2/code/Graphics/GrDirectDraw.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code for software 8-bpp rendering using DirectDraw
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 9     7/14/99 9:42a Dave
15  * Put in clear_color debug function. Put in base for 3dnow stuff / P3
16  * stuff
17  * 
18  * 8     6/29/99 10:35a Dave
19  * Interface polygon bitmaps! Whee!
20  * 
21  * 7     2/03/99 11:44a Dave
22  * Fixed d3d transparent textures.
23  * 
24  * 6     1/24/99 11:37p Dave
25  * First full rev of beam weapons. Very customizable. Removed some bogus
26  * Int3()'s in low level net code.
27  * 
28  * 5     12/18/98 1:13a Dave
29  * Rough 1024x768 support for Direct3D. Proper detection and usage through
30  * the launcher.
31  * 
32  * 4     12/06/98 2:36p Dave
33  * Drastically improved nebula fogging.
34  * 
35  * 3     11/30/98 1:07p Dave
36  * 16 bit conversion, first run.
37  * 
38  * 2     10/07/98 10:52a Dave
39  * Initial checkin.
40  * 
41  * 1     10/07/98 10:49a Dave
42  * 
43  * 17    5/22/98 10:28p John
44  * Made software movies not click your monitor when switching to 16-bpp.
45  * Total hack around my restrictive code, but at this point...
46  * 
47  * 16    5/20/98 9:45p John
48  * added code so the places in code that change half the palette don't
49  * have to clear the screen.
50  * 
51  * 15    5/17/98 5:03p John
52  * Fixed some bugs that make the taskbar interfere with the DEBUG-only
53  * mouse cursor.
54  * 
55  * 14    5/16/98 1:18p John
56  * Made softtware DirectDraw reset palette after Alt+TAB.
57  * 
58  * 13    5/15/98 9:34p John
59  * Removed the initial ugly little cursor part that drew right at program
60  * start.
61  * 
62  * 12    5/14/98 5:42p John
63  * Revamped the whole window position/mouse code for the graphics windows.
64  * 
65  * 11    5/12/98 8:15a John
66  * Made dd code not print out rgb surface info.
67  * 
68  * 10    5/07/98 6:58p Hoffoss
69  * Made changes to mouse code to fix a number of problems.
70  * 
71  * 9     5/06/98 5:30p John
72  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
73  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
74  * DirectX header files and libs that fixed the Direct3D alpha blending
75  * problems.
76  * 
77  * 8     4/23/98 8:24a John
78  * Changed the way palette effect works so that:
79  * 1. If gr_flash isn't called this frame, screen shows no flash.
80  * 2. With hardware, only 3d portion of screen gets flashed.
81  * 
82  * 7     4/21/98 5:22p John
83  * Fixed all the &^#@$ cursor bugs with popups.   For Glide, had problem
84  * with mouse restoring assuming back buffer was same buffer last frame,
85  * for software, problems with half drawn new frames, then mouse got
86  * restored on top of that with old data.
87  * 
88  * 6     4/17/98 3:56p Mike
89  * Fix palette trashing on MK's computer when he Alt-Tabs out of FreeSpace
90  * in software.  At John's suggestion.
91  * 
92  * 5     4/14/98 12:15p John
93  * Made 16-bpp movies work.
94  * 
95  * 4     4/13/98 8:08p John
96  * Made surface restoration also restore the palette.
97  * 
98  * 3     4/09/98 6:56p John
99  * Put in better code to restore surfaces when restoring them.  Worth a
100  * try for an Interplay QA bug I can't find.
101  * 
102  * 2     4/09/98 11:05a John
103  * Removed all traces of Direct3D out of the demo version of Freespace and
104  * the launcher.
105  * 
106  * 1     3/25/98 8:07p John
107  * Split software renderer into Win32 and DirectX
108  *
109  * $NoKeywords: $
110  */
111
112 #include <math.h>
113 #include <windows.h>
114 #include <windowsx.h>
115
116 #include "vddraw.h"
117
118 #include "osapi.h"
119 #include "2d.h"
120 #include "bmpman.h"
121 #include "key.h"
122 #include "floating.h"
123 #include "palman.h"
124 #include "grsoft.h"
125 #include "grinternal.h"
126
127 // Headers for 2d functions
128 #include "pixel.h"
129 #include "line.h"
130 #include "scaler.h"
131 #include "tmapper.h"
132 #include "circle.h"
133 #include "shade.h"
134 #include "rect.h"
135 #include "gradient.h"
136 #include "pcxutils.h"
137 #include "osapi.h"
138 #include "mouse.h"
139 #include "font.h"
140 #include "timer.h"
141 #include "colors.h"
142 #include "bitblt.h"
143 #include "grzbuffer.h"
144
145 static LPDIRECTDRAW                     lpDD = NULL;
146 static LPDIRECTDRAWSURFACE      lpBackBuffer = NULL;
147 static LPDIRECTDRAWSURFACE      lpFrontBuffer = NULL;
148 static LPDIRECTDRAWCLIPPER      lpClipper = NULL;
149 static LPDIRECTDRAWPALETTE      lpPalette = NULL;
150
151 void gr_directdraw_unlock();
152 void gr_directdraw_set_palette_internal( ubyte * new_pal );
153
154 void directdraw_clear_all_vram()
155 {
156 #ifndef HARDWARE_ONLY
157         DDSURFACEDESC ddsd;
158         HRESULT ddrval;
159         LPDIRECTDRAWSURFACE buffer[16];
160         
161         int i;
162         int num_buffers = 0;
163         for (i=0; i<16; i++ )   {
164                 memset( &ddsd, 0, sizeof( ddsd ) );
165
166                 ddsd.dwSize  = sizeof( ddsd );
167                 ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
168                 ddsd.dwWidth = gr_screen.max_w;
169                 ddsd.dwHeight = gr_screen.max_h;
170                 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
171
172                 // create the back buffer
173                 ddrval = lpDD->CreateSurface( &ddsd, &buffer[i], NULL );
174                 if ( ddrval == DD_OK )  {
175                         // Clear the surface
176                         DDBLTFX ddBltFx;
177
178                         memset(&ddBltFx, 0, sizeof(DDBLTFX));
179                         ddBltFx.dwSize = sizeof(DDBLTFX);
180                         ddBltFx.dwFillColor = 0;
181
182                         buffer[i]->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddBltFx);
183
184                 } else {
185                         num_buffers = i;
186                         buffer[i] = NULL;
187                         break;
188                 }
189         }
190
191         for (i=0; i<num_buffers; i++ )  {
192                 buffer[i]->Release();
193         }
194 #else
195         Int3();
196 #endif
197 }
198
199 LPDIRECTDRAW gr_directdraw_start_mve()
200 {
201 #ifndef HARDWARE_ONLY
202         ubyte tmp_pal[768];
203         memset( tmp_pal, 0, 768 );
204
205         gr_directdraw_set_palette_internal(tmp_pal);
206
207         // clear both buffers
208         gr_reset_clip();
209         gr_clear();
210         gr_flip();
211
212         gr_reset_clip();
213         gr_clear();
214         gr_flip();
215
216         gr_directdraw_unlock();
217
218         // Clear all of VRAM...
219         directdraw_clear_all_vram();
220
221         if ( lpPalette )        {
222                 lpPalette->Release();
223                 lpPalette = NULL;
224         }
225
226         if (lpFrontBuffer)      {
227                 lpFrontBuffer->Release();
228                 lpFrontBuffer = NULL;
229         }
230
231         
232         return lpDD;
233 #else
234         Int3();
235         return 0;
236 #endif
237 }
238
239
240 void gr_directdraw_stop_mve()
241 {
242 #ifndef HARDWARE_ONLY
243         DDSURFACEDESC ddsd;
244         HRESULT ddrval;
245
246         memset( &ddsd, 0, sizeof( ddsd ) );
247
248         ddsd.dwSize  = sizeof( ddsd );
249         ddsd.dwFlags = DDSD_CAPS;
250         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
251
252         ddrval = lpDD->CreateSurface( &ddsd, &lpFrontBuffer, NULL );
253         if ( ddrval != DD_OK )  {
254                 mprintf(( "GR_SOFT_INIT: CreateSurface (Front) failed.\n" ));
255                 lpDD->Release();
256                 exit(1);
257         }
258
259         int i;
260         PALETTEENTRY    pe[256];
261         for (i=0; i<256; i++ )  {
262                 pe[i].peFlags = PC_NOCOLLAPSE|PC_RESERVED;
263                 pe[i].peRed = gr_palette[i*3+0];
264                 pe[i].peGreen = gr_palette[i*3+1];
265                 pe[i].peBlue = gr_palette[i*3+2];
266         }       
267
268         ddrval = lpDD->CreatePalette( DDPCAPS_8BIT | DDPCAPS_ALLOW256, pe, &lpPalette, NULL);
269         if (ddrval != DD_OK) {
270                 mprintf(( "Error creating palette\n" ));
271         }
272
273         ddrval = lpFrontBuffer->SetPalette( lpPalette );
274         if (ddrval != DD_OK) {
275                 mprintf(( "Error setting palette in gr_directdraw_set_palette\n" ));
276         }
277
278         gr_reset_clip();
279         gr_clear();
280         gr_flip();
281 #else 
282         Int3();
283 #endif
284 }
285
286 //#define DD_FLIP 1
287
288 static int Locked = 0;
289
290 uint gr_directdraw_lock()
291 {
292 #ifndef HARDWARE_ONLY
293         if ( !Locked )  {
294
295                 HRESULT ddrval;
296                 DDSURFACEDESC ddsd;
297
298                 memset( &ddsd, 0, sizeof( ddsd ) );
299                 ddsd.dwSize = sizeof( ddsd );
300
301                 ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
302                 if ( ddrval != DD_OK )  {
303                         mprintf(( "Error locking surface in gr_d3d_lock\n" ));
304                         gr_screen.offscreen_buffer_base = NULL; //(void *)fake_vram;
305                         gr_screen.rowsize = 0;
306                         gr_screen.offscreen_buffer = gr_screen.offscreen_buffer_base;
307                 } else {
308                         gr_screen.offscreen_buffer_base = (void *)ddsd.lpSurface;
309                         gr_screen.rowsize = ddsd.lPitch;
310                         gr_screen.offscreen_buffer = gr_screen.offscreen_buffer_base;
311                         Locked = 1;
312                 }
313
314         }
315         return 1;
316 #else 
317         Int3();
318         return 0;
319 #endif
320 }
321
322 void gr_directdraw_unlock()
323 {
324 #ifndef HARDWARE_ONLY
325         if ( Locked )   {
326                 // Unlock the back buffer
327                 lpBackBuffer->Unlock( NULL );
328                 Locked = 0;
329         }
330 #else
331         Int3();
332 #endif
333 }
334
335 void gr_directdraw_unlock_fake()
336 {
337 }
338
339
340 static int Palette_flashed = 0;
341 static int Palette_flashed_last_frame = 0;
342
343
344 static volatile int Gr_dd_activated = 0;
345
346 void gr_dd_activate(int active)
347 {
348 #ifndef HARDWARE_ONLY
349         if ( active  )  {
350                 Gr_dd_activated++;
351         }
352 #else
353         Int3();
354 #endif
355 }
356
357
358 void gr_directdraw_flip()
359 {
360 #ifndef HARDWARE_ONLY
361         if ( Gr_dd_activated || ((!Palette_flashed) && (Palette_flashed_last_frame)) )  {
362                 // Reset flash
363                 gr_directdraw_set_palette_internal( gr_palette );
364                 Gr_dd_activated = 0;
365         }
366
367         Palette_flashed_last_frame = Palette_flashed;
368         Palette_flashed = 0;
369
370         gr_reset_clip();
371
372         int mx, my;
373
374         Grx_mouse_saved = 0;            // assume not saved
375
376         mouse_eval_deltas();
377         if ( mouse_is_visible() )       {
378                 gr_reset_clip();
379                 mouse_get_pos( &mx, &my );
380                 grx_save_mouse_area(mx,my,32,32);
381                 if ( Gr_cursor == -1 )  {
382                         gr_set_color(255,255,255);
383                         gr_line( mx, my, mx+7, my + 7 );
384                         gr_line( mx, my, mx+5, my );
385                         gr_line( mx, my, mx, my+5 );
386                 } else {
387                         gr_set_bitmap(Gr_cursor);
388                         gr_bitmap( mx, my );
389                 }
390         } 
391
392         gr_directdraw_unlock();
393
394 #ifdef DD_FLIP
395 TryFlipAgain:
396
397         if ( lpFrontBuffer->IsLost() == DDERR_SURFACELOST )     {
398                 lpFrontBuffer->Restore();
399                 ddrval = lpFrontBuffer->SetPalette( lpPalette );
400                 if (ddrval != DD_OK) {
401                         mprintf(( "Error setting palette after restore\n" ));
402                 }
403         }
404         if ( lpBackBuffer->IsLost() == DDERR_SURFACELOST )      {
405                 lpBackBuffer->Restore();
406         }
407
408         HRESULT ddrval = lpFrontBuffer->Flip( NULL, DDFLIP_WAIT  );
409         if ( ddrval == DDERR_SURFACELOST )      {
410                 mprintf(( "Front surface lost... attempting to restore...\n" ));
411                 os_sleep(1000); // Wait a second
412                 goto TryFlipAgain;
413         } else if (ddrval != DD_OK )    {
414                 mprintf(( "Fullscreen flip failed!\n" ));
415         }
416
417 #else
418         RECT src_rect, dst_rect;
419         POINT pt;
420         HRESULT ddrval;
421
422         HWND hWnd = (HWND)os_get_window();
423
424         if ( hWnd )     {
425                 // src_rect is relative to offscreen buffer
426                 GetClientRect( hWnd, &src_rect );
427
428                 // dst_rect is relative to screen space so needs translation
429                 pt.x = pt.y = 0;
430                 ClientToScreen( hWnd, &pt );
431                 dst_rect = src_rect;
432                 dst_rect.left += pt.x;
433                 dst_rect.right += pt.x;
434                 dst_rect.top += pt.y;
435                 dst_rect.bottom += pt.y;
436
437                 // perform the blit from backbuffer to primary, using
438                 // src_rect and dst_rect
439
440 TryFlipAgain:
441                 if ( lpFrontBuffer->IsLost() == DDERR_SURFACELOST )     {
442                         lpFrontBuffer->Restore();
443
444 /*                      ddrval = lpFrontBuffer->SetPalette( lpPalette );
445                         if (ddrval != DD_OK) {
446                                 mprintf(( "Error setting palette after restore\n" ));
447                         }
448 */              }
449                 if ( lpBackBuffer->IsLost() == DDERR_SURFACELOST )      {
450                         lpBackBuffer->Restore();
451                 }
452                 ddrval = lpFrontBuffer->Blt( &dst_rect, lpBackBuffer, &src_rect, DDBLT_WAIT, 0 );
453                 if ( ddrval == DDERR_SURFACELOST )      {
454                         mprintf(( "Front surface lost... attempting to restore...\n" ));
455                         os_sleep(1000); // Wait a second
456                         goto TryFlipAgain;
457                 } else if (ddrval != DD_OK )    {
458                         mprintf(( "Flip failed! $%x\n", ddrval ));
459                 }
460         }
461 #endif
462
463         if ( Grx_mouse_saved )  {
464                 grx_restore_mouse_area();
465         }
466 #else
467         Int3();
468 #endif
469 }
470
471 void gr_directdraw_flip_window(uint _hdc, int x, int y, int w, int h )
472 {
473 }
474
475 void gr_directdraw_start_frame()
476 {
477
478 }
479
480 void gr_directdraw_stop_frame()
481 {
482
483 }
484
485 void gr_directdraw_set_palette_internal( ubyte * new_pal )
486 {
487 #ifndef HARDWARE_ONLY
488         PALETTEENTRY    pe[256];
489
490         gr_directdraw_unlock();
491
492         int i;
493         for (i=0; i<256; i++ )  {
494                 pe[i].peFlags = PC_NOCOLLAPSE|PC_RESERVED;
495                 pe[i].peRed = new_pal[i*3+0];
496                 pe[i].peGreen = new_pal[i*3+1];
497                 pe[i].peBlue = new_pal[i*3+2];
498         }       
499
500         HRESULT ddrval;
501         ddrval = lpPalette->SetEntries( 0, 0, 256, pe );
502         if ( ddrval != DD_OK )  {
503                 mprintf(( "Error setting palette\n" ));
504         }
505
506         gr_lock();
507 #else
508         Int3();
509 #endif
510 }
511
512 void gr_directdraw_set_palette( ubyte * new_pal, int restrict_alphacolor )
513 {
514 #ifndef HARDWARE_ONLY
515         if ( !restrict_alphacolor )     {
516                 Mouse_hidden++;
517                 gr_reset_clip();
518                 gr_clear();
519                 gr_flip();
520                 Mouse_hidden--;
521         }
522
523         // Make sure color 0 is black
524         if ( (new_pal[0]!=0) || (new_pal[1]!=0) || (new_pal[2]!=0) )    {
525                 // color 0 isn't black!! switch it!
526                 int i;
527                 int black_index = -1;
528
529                 for (i=1; i<256; i++ )  {
530                         if ( (new_pal[i*3+0]==0) && (new_pal[i*3+1]==0) && (new_pal[i*3+2]==0) )        {       
531                                 black_index = i;
532                                 break;
533                         }
534                 }
535                 if ( black_index > -1 ) {
536                         // swap black and color 0, so color 0 is black
537                         ubyte tmp[3];
538                         tmp[0] = new_pal[black_index*3+0];
539                         tmp[1] = new_pal[black_index*3+1];
540                         tmp[2] = new_pal[black_index*3+2];
541
542                         new_pal[black_index*3+0] = new_pal[0];
543                         new_pal[black_index*3+1] = new_pal[1];
544                         new_pal[black_index*3+2] = new_pal[2];
545
546                         new_pal[0] = tmp[0];
547                         new_pal[1] = tmp[1];
548                         new_pal[2] = tmp[2];
549                 } else {
550                         // no black in palette, force color 0 to be black.
551                         new_pal[0] = 0;
552                         new_pal[1] = 0;
553                         new_pal[2] = 0;
554                 }
555         }
556
557         gr_directdraw_set_palette_internal( new_pal );
558 #else
559         Int3();
560 #endif
561 }
562
563 void gr_directdraw_flash( int r, int g, int b )
564 {
565 #ifndef HARDWARE_ONLY
566         int t,i;
567         ubyte new_pal[768];
568
569         if ( (r==0) && (b==0) && (g==0) )       {
570                 return;
571         }
572
573         Palette_flashed++;
574
575         for (i=0; i<256; i++ )  {
576                 t = gr_palette[i*3+0] + r;
577                 if ( t < 0 ) t = 0; else if (t>255) t = 255;
578                 new_pal[i*3+0] = (ubyte)t;
579
580                 t = gr_palette[i*3+1] + g;
581                 if ( t < 0 ) t = 0; else if (t>255) t = 255;
582                 new_pal[i*3+1] = (ubyte)t;
583
584                 t = gr_palette[i*3+2] + b;
585                 if ( t < 0 ) t = 0; else if (t>255) t = 255;
586                 new_pal[i*3+2] = (ubyte)t;
587         }
588
589         gr_directdraw_set_palette_internal( new_pal );
590 #else
591         Int3();
592 #endif
593 }
594
595
596 static int gr_palette_faded_out = 0;
597
598 #define FADE_TIME (F1_0/4)              // How long to fade out
599
600 void gr_directdraw_fade_out(int instantaneous)  
601 {
602 #ifndef HARDWARE_ONLY
603         int i;
604         ubyte new_pal[768];
605
606         if (!gr_palette_faded_out) {
607
608                 if ( !instantaneous )   {
609         
610                         int count = 0;
611                         fix start_time, stop_time, t1;
612
613                         start_time = timer_get_fixed_seconds();
614                         t1 = 0;
615
616                         do {
617                                 for (i=0; i<768; i++ )  {               
618                                         int c = (gr_palette[i]*(FADE_TIME-t1))/FADE_TIME;
619                                         if (c < 0 )
620                                                 c = 0;
621                                         else if ( c > 255 )
622                                                 c = 255;
623                         
624                                         new_pal[i] = (ubyte)c;
625                                 }
626                                 gr_directdraw_set_palette_internal( new_pal );
627                                 count++;
628
629                                 t1 = timer_get_fixed_seconds() - start_time;
630
631                         } while ( (t1 < FADE_TIME) && (t1>=0) );                // Loop as long as time not up and timer hasn't rolled
632
633                         stop_time = timer_get_fixed_seconds();
634
635                         mprintf(( "Took %d frames (and %.1f secs) to fade out\n", count, f2fl(stop_time-start_time) ));
636                 
637                 }
638                 gr_palette_faded_out = 1;
639         }
640
641         memset( new_pal, 0, 768 );
642         gr_directdraw_set_palette_internal( new_pal );
643 #else
644         Int3();
645 #endif
646 }
647
648
649 void gr_directdraw_fade_in(int instantaneous)   
650 {
651 #ifndef HARDWARE_ONLY
652         int i;
653         ubyte new_pal[768];
654
655         if (gr_palette_faded_out)       {
656
657                 if ( !instantaneous )   {
658                         int count = 0;
659                         fix start_time, stop_time, t1;
660
661                         start_time = timer_get_fixed_seconds();
662                         t1 = 0;
663
664                         do {
665                                 for (i=0; i<768; i++ )  {               
666                                         int c = (gr_palette[i]*t1)/FADE_TIME;
667                                         if (c < 0 )
668                                                 c = 0;
669                                         else if ( c > 255 )
670                                                 c = 255;
671                         
672                                         new_pal[i] = (ubyte)c;
673                                 }
674                                 gr_directdraw_set_palette_internal( new_pal );
675                                 count++;
676
677                                 t1 = timer_get_fixed_seconds() - start_time;
678
679                         } while ( (t1 < FADE_TIME) && (t1>=0) );                // Loop as long as time not up and timer hasn't rolled
680
681                         stop_time = timer_get_fixed_seconds();
682
683                         mprintf(( "Took %d frames (and %.1f secs) to fade in\n", count, f2fl(stop_time-start_time) ));
684                 }
685                 gr_palette_faded_out = 0;
686         }
687
688         memcpy( new_pal, gr_palette, 768 );
689         gr_directdraw_set_palette_internal( new_pal );
690 #else
691         Int3();
692 #endif
693 }
694
695 void gr_directdraw_get_region(int front, int w, int h, ubyte *data)
696 {
697 }
698
699 // sets the clipping region & offset
700 void gr_directdraw_set_clip(int x,int y,int w,int h)
701 {
702 #ifndef HARDWARE_ONLY
703         gr_screen.offset_x = x;
704         gr_screen.offset_y = y;
705
706         gr_screen.clip_left = 0;
707         gr_screen.clip_right = w-1;
708
709         gr_screen.clip_top = 0;
710         gr_screen.clip_bottom = h-1;
711
712         // check for sanity of parameters
713         if ( gr_screen.clip_left+x < 0 ) {
714                 gr_screen.clip_left = -x;
715         } else if ( gr_screen.clip_left+x > gr_screen.max_w-1 ) {
716                 gr_screen.clip_left = gr_screen.max_w-1-x;
717         }
718         if ( gr_screen.clip_right+x < 0 ) {
719                 gr_screen.clip_right = -x;
720         } else if ( gr_screen.clip_right+x >= gr_screen.max_w-1 )       {
721                 gr_screen.clip_right = gr_screen.max_w-1-x;
722         }
723
724         if ( gr_screen.clip_top+y < 0 ) {
725                 gr_screen.clip_top = -y;
726         } else if ( gr_screen.clip_top+y > gr_screen.max_h-1 )  {
727                 gr_screen.clip_top = gr_screen.max_h-1-y;
728         }
729
730         if ( gr_screen.clip_bottom+y < 0 ) {
731                 gr_screen.clip_bottom = -y;
732         } else if ( gr_screen.clip_bottom+y > gr_screen.max_h-1 )       {
733                 gr_screen.clip_bottom = gr_screen.max_h-1-y;
734         }
735
736         gr_screen.clip_width = gr_screen.clip_right - gr_screen.clip_left + 1;
737         gr_screen.clip_height = gr_screen.clip_bottom - gr_screen.clip_top + 1;
738 #else
739         Int3();
740 #endif
741 }
742
743 // resolution checking
744 int gr_directdraw_supports_res_ingame(int res)
745 {
746         return 1;
747 }
748
749 int gr_directdraw_supports_res_interface(int res)
750 {
751         return 1;
752 }
753
754 void gr_directdraw_set_cull(int cull)
755 {
756 }
757
758 // resets the clipping region to entire screen
759 //
760 // should call this before gr_surface_flip() if you clipped some portion of the screen but still 
761 // want a full-screen display
762 void gr_directdraw_reset_clip()
763 {
764 #ifndef HARDWARE_ONLY
765         gr_screen.offset_x = 0;
766         gr_screen.offset_y = 0;
767         gr_screen.clip_left = 0;
768         gr_screen.clip_top = 0;
769         gr_screen.clip_right = gr_screen.max_w - 1;
770         gr_screen.clip_bottom = gr_screen.max_h - 1;
771         gr_screen.clip_width = gr_screen.max_w;
772         gr_screen.clip_height = gr_screen.max_h;
773 #else
774         Int3();
775 #endif
776 }
777
778
779 // Sets the current bitmap
780 void gr_directdraw_set_bitmap( int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha, int sx, int sy )
781 {
782 #ifndef HARDWARE_ONLY
783         gr_screen.current_alpha = alpha;
784         gr_screen.current_alphablend_mode = alphablend_mode;
785         gr_screen.current_bitblt_mode = bitblt_mode;
786         gr_screen.current_bitmap = bitmap_num;
787         gr_screen.current_bitmap_sx = sx;
788         gr_screen.current_bitmap_sy = sy;
789 #else
790         Int3();
791 #endif
792 }
793
794 // clears entire clipping region to black.
795 void gr_directdraw_clear()
796 {
797 #ifndef HARDWARE_ONLY
798
799 #ifdef DD_FLIP
800         gr_directdraw_unlock();
801
802         DDBLTFX ddBltFx;
803
804         ddBltFx.dwSize = sizeof(DDBLTFX);
805         ddBltFx.dwFillColor = 0;
806
807         //DDBLT_WAIT | 
808         lpBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddBltFx);
809 //              ddBltFx.dwROP = BLACKNESS;
810 //              lpBackBuffer->Blt(NULL, NULL, NULL, DDBLT_ROP, &ddBltFx);
811
812         gr_lock();
813
814 #else
815         gr_lock();
816
817         int i,w;
818         ubyte *pDestBits;
819
820         w = gr_screen.clip_right-gr_screen.clip_left+1;
821         for (i=gr_screen.clip_top; i<=gr_screen.clip_bottom; i++)       {
822                 pDestBits = GR_SCREEN_PTR(ubyte,gr_screen.clip_left,i);
823                 memset( pDestBits, 0, w );
824         }       
825
826         gr_directdraw_unlock();
827 #endif
828 #else
829         Int3();
830 #endif
831 }
832
833 void gr_directdraw_force_windowed()
834 {
835 #ifndef HARDWARE_ONLY
836         gr_directdraw_unlock();
837
838         HWND hwnd = (HWND)os_get_window();
839
840         // Simulate Alt+Tab
841         PostMessage(hwnd,WM_SYSKEYUP, 0x9, 0xa00f0001 );
842         PostMessage(hwnd,WM_SYSKEYUP, 0x12, 0xc0380001 );
843
844         // Wait a second to give things a change to settle down.                                
845         Sleep(1000);
846 #else
847         Int3();
848 #endif
849 }
850
851 void gr_directdraw_cleanup()
852 {
853 #ifndef HARDWARE_ONLY
854         HWND hwnd = (HWND)os_get_window();
855         
856         gr_directdraw_unlock();
857
858         if ( lpPalette )        {
859                 lpPalette->Release();
860                 lpPalette = NULL;
861         }
862
863         if (lpClipper)  {
864                 lpClipper->Release();
865                 lpClipper = NULL;
866         }
867
868         if (lpBackBuffer)       {
869                 lpBackBuffer->Release();
870                 lpBackBuffer = NULL;
871         }
872
873         if (lpFrontBuffer)      {
874                 lpFrontBuffer->Release();
875                 lpFrontBuffer = NULL;
876         }
877
878
879 // JAS:  I took this out because my taskbar seems to get screwed up
880 // if I leave this in.   Doesn't make sense, hence this comment.
881         HRESULT ddrval = lpDD->RestoreDisplayMode();
882         if( ddrval != DD_OK )   {
883                 mprintf(( "WIN_DD32: RestoreDisplayMode failed (0x%x)\n", ddrval ));
884         }
885         ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL );
886         if( ddrval != DD_OK )   {
887                 mprintf(( "WIN_DD32: SetCooperativeLevel W Failed (0x%x)\n", ddrval ));
888         }
889
890         os_suspend();
891         if ( lpDD ) {
892                 lpDD->Release();
893                 lpDD = NULL; 
894         }
895         os_resume();
896 #else
897         Int3();
898 #endif
899 }
900
901 void dd_get_shift_masks( DDSURFACEDESC *ddsd )
902 {
903         unsigned long m;
904         int s;
905         int r, red_shift, red_scale, red_mask;
906         int g, green_shift, green_scale, green_mask;
907         int b, blue_shift, blue_scale, blue_mask;
908         int a, alpha_shift, alpha_scale, alpha_mask;
909         
910         if (gr_screen.bits_per_pixel == 8 ) {
911                 Gr_red.bits = 8;
912                 Gr_red.shift = 16;
913                 Gr_red.scale = 1;
914                 Gr_red.mask = 0xff0000;
915
916                 Gr_green.bits = 8;
917                 Gr_green.shift = 8;
918                 Gr_green.scale = 1;
919                 Gr_green.mask = 0xff00;
920
921                 Gr_blue.bits = 8;
922                 Gr_blue.shift = 0;
923                 Gr_blue.scale = 1;
924                 Gr_blue.mask = 0xff;
925                 return;
926         }
927
928         // Determine the red, green and blue masks' shift and scale.
929         for (s = 0, m = ddsd->ddpfPixelFormat.dwRBitMask; !(m & 1); s++, m >>= 1);
930         for (r = 0; m & 1; r++, m >>= 1);
931         red_shift = s;
932         red_scale = 255 / (ddsd->ddpfPixelFormat.dwRBitMask >> s);
933         red_mask = ddsd->ddpfPixelFormat.dwRBitMask;
934
935         for (s = 0, m = ddsd->ddpfPixelFormat.dwGBitMask; !(m & 1); s++, m >>= 1);
936         for (g = 0; m & 1; g++, m >>= 1);
937         green_shift = s;
938         green_scale = 255 / (ddsd->ddpfPixelFormat.dwGBitMask >> s);
939         green_mask = ddsd->ddpfPixelFormat.dwGBitMask;
940         
941         for (s = 0, m = ddsd->ddpfPixelFormat.dwBBitMask; !(m & 1); s++, m >>= 1);
942         for (b = 0; m & 1; b++, m >>= 1);
943         blue_shift = s;
944         blue_scale = 255 / (ddsd->ddpfPixelFormat.dwBBitMask >> s);
945         blue_mask = ddsd->ddpfPixelFormat.dwBBitMask;
946
947         if ( ddsd->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS ) {
948                 for (s = 0, m = ddsd->ddpfPixelFormat.dwRGBAlphaBitMask; !(m & 1); s++, m >>= 1);
949                 for (a = 0; m & 1; a++, m >>= 1);
950                 alpha_shift = s;
951                 alpha_scale = 255 / (ddsd->ddpfPixelFormat.dwRGBAlphaBitMask >> s);
952                 alpha_mask = ddsd->ddpfPixelFormat.dwRGBAlphaBitMask;
953         } else {
954                 alpha_shift = a = alpha_scale = alpha_mask = 0;
955         }
956
957 //      mprintf(( "Red    Bits:%2d, Shift:%2d, Scale:%3d, Mask:$%08x\n", r, red_shift, red_scale, red_mask ));
958 //      mprintf(( "Green  Bits:%2d, Shift:%2d, Scale:%3d, Mask:$%08x\n", g, green_shift, green_scale, green_mask ));
959 //      mprintf(( "Blue   Bits:%2d, Shift:%2d, Scale:%3d, Mask:$%08x\n", b, blue_shift, blue_scale, blue_mask ));
960 //      mprintf(( "Alpha  Bits:%2d, Shift:%2d, Scale:%3d, Mask:$%08x\n", a, alpha_shift, alpha_scale, alpha_mask ));
961
962         // we need to set stuff up so that the high bit is always an alpha bit. 
963
964         Gr_red.bits = r;
965         Gr_red.shift = red_shift;
966         Gr_red.scale = red_scale;
967         Gr_red.mask = red_mask;
968
969         Gr_green.bits = g;
970         Gr_green.shift = green_shift;
971         Gr_green.scale = green_scale;
972         Gr_green.mask = green_mask;
973
974         Gr_blue.bits = b;
975         Gr_blue.shift = blue_shift;
976         Gr_blue.scale = blue_scale;
977         Gr_blue.mask = blue_mask;
978 }
979
980 // cross fade
981 void gr_directdraw_cross_fade(int bmap1, int bmap2, int x1, int y1, int x2, int y2, float pct)
982 {
983         if ( pct <= 50 )        {
984                 gr_set_bitmap(bmap1);
985                 gr_bitmap(x1, y1);
986         } else {
987                 gr_set_bitmap(bmap2);
988                 gr_bitmap(x2, y2);
989         }       
990 }
991
992 // filter
993 void gr_directdraw_filter_set(int filter)
994 {
995 }
996
997 // set clear color
998 void gr_directdraw_set_clear_color(int r, int g, int b)
999 {
1000 }
1001
1002 void gr_directdraw_init()
1003 {
1004 #ifndef HARDWARE_ONLY
1005 //      int i;
1006         HRESULT ddrval;
1007
1008         Palette_flashed = 0;
1009         Palette_flashed_last_frame = 0;
1010
1011         gr_screen.bits_per_pixel = 8;
1012         gr_screen.bytes_per_pixel = 1;
1013
1014         Gr_dd_activated = 0;
1015
1016         HWND hwnd = (HWND)os_get_window();
1017
1018         if ( !hwnd )    {
1019                 mprintf(( "GR_SOFT_INIT: No window handle.\n" ));
1020                 exit(1);
1021         }
1022
1023         // Prepare the window to go full screen
1024 #ifndef NDEBUG
1025         mprintf(( "Window in debugging mode... mouse clicking may cause problems!\n" ));
1026         SetWindowLong( hwnd, GWL_EXSTYLE, 0 );
1027         SetWindowLong( hwnd, GWL_STYLE, WS_POPUP );
1028         ShowWindow(hwnd, SW_SHOWNORMAL );
1029         RECT work_rect;
1030         SystemParametersInfo( SPI_GETWORKAREA, 0, &work_rect, 0 );
1031         SetWindowPos( hwnd, HWND_NOTOPMOST, work_rect.left, work_rect.top, gr_screen.max_w, gr_screen.max_h, 0 );       
1032         SetActiveWindow(hwnd);
1033         SetForegroundWindow(hwnd);
1034 #else
1035         SetWindowLong( hwnd, GWL_EXSTYLE, 0 );
1036         SetWindowLong( hwnd, GWL_STYLE, WS_POPUP );
1037         ShowWindow(hwnd, SW_SHOWNORMAL );
1038         SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ), 0 );  
1039         SetActiveWindow(hwnd);
1040         SetForegroundWindow(hwnd);
1041 #endif
1042
1043         os_suspend();
1044         ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
1045         os_resume();
1046         if ( ddrval != DD_OK ) {
1047                 mprintf(( "GR_SOFT_INIT: DirectDrawCreate failed.\n" ));
1048                 exit(1);
1049         }
1050
1051         Assert( lpDD );
1052
1053         ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
1054         if ( ddrval != DD_OK )  {
1055                 mprintf(( "GR_SOFT_INIT: SetCooperativeLevel EXCLUSIVE failed.\n" ));
1056                 lpDD->Release();
1057                 exit(1);
1058         }
1059
1060         // Go to full screen!
1061         os_suspend();
1062         ddrval = lpDD->SetDisplayMode( gr_screen.max_w, gr_screen.max_h, gr_screen.bits_per_pixel );
1063         os_resume();
1064         if ( ddrval != DD_OK )  {
1065                 mprintf(( "GR_SOFT_INIT: SetDisplayMode failed.\n" ));
1066                 lpDD->Release();
1067                 exit(1);
1068         }
1069
1070
1071         DDSURFACEDESC ddsd;
1072
1073 #ifdef DD_FLIP
1074         DDSCAPS ddscaps;
1075
1076         memset( &ddsd, 0, sizeof( ddsd ));
1077
1078         ddsd.dwSize = sizeof( ddsd );
1079         ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
1080         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
1081         ddsd.dwBackBufferCount = 2;
1082
1083         ddrval = lpDD->CreateSurface( &ddsd, &lpFrontBuffer, NULL );
1084         if ( ddrval != DD_OK )  {
1085                 mprintf(( "GR_SOFT_INIT: CreateSurface (Front) failed.\n" ));
1086                 lpDD->Release();
1087                 exit(1);
1088         }
1089
1090         ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
1091
1092         ddrval = lpFrontBuffer->GetAttachedSurface( &ddscaps, &lpBackBuffer );
1093         if ( ddrval != DD_OK )  {
1094                 mprintf(( "GR_SOFT_INIT: GetAttachedSurface (Back) failed.\n" ));
1095                 lpDD->Release();
1096                 exit(1);
1097         }
1098
1099         lpClipper = NULL;
1100 #else
1101
1102         memset( &ddsd, 0, sizeof( ddsd ) );
1103
1104         ddsd.dwSize  = sizeof( ddsd );
1105         ddsd.dwFlags = DDSD_CAPS;
1106         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1107
1108         ddrval = lpDD->CreateSurface( &ddsd, &lpFrontBuffer, NULL );
1109         if ( ddrval != DD_OK )  {
1110                 mprintf(( "GR_SOFT_INIT: CreateSurface (Front) failed.\n" ));
1111                 lpDD->Release();
1112                 exit(1);
1113         }
1114
1115         ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
1116         ddsd.dwWidth = gr_screen.max_w;
1117         ddsd.dwHeight = gr_screen.max_h;
1118         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
1119
1120         // If debugging we have to create our surfaces in system memory
1121         // so that our debugger isn't hosed when locking surfaces.
1122
1123         //ddsd.ddsCaps.dwCaps |= DDSCAPS_NONLOCALVIDMEM;
1124         ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
1125
1126         // create the back buffer
1127         ddrval = lpDD->CreateSurface( &ddsd, &lpBackBuffer , NULL );
1128         if ( ddrval != DD_OK )  {
1129                 mprintf(( "GR_SOFT_INIT: CreateSurface (Back) failed.\n" ));
1130                 goto DDError;
1131         }
1132
1133         // create a clipper and attach it to our window
1134         ddrval = lpDD->CreateClipper( 0, &lpClipper, NULL );
1135         if ( ddrval != DD_OK )  {
1136                 mprintf(( "GR_SOFT_INIT: CreateClipper failed.\n" ));
1137                 goto DDError;
1138         }
1139
1140
1141         ddrval = lpClipper->SetHWnd( 0, hwnd );
1142         if ( ddrval != DD_OK )  {
1143                 mprintf(( "GR_SOFT_INIT: SetHWnd failed.\n" ));
1144                 goto DDError;
1145         }
1146
1147
1148         ddrval = lpFrontBuffer->SetClipper( lpClipper );
1149         if ( ddrval != DD_OK )  {
1150                 mprintf(( "GR_SOFT_INIT: SetClipper failed.\n" ));
1151                 goto DDError;
1152         }
1153 #endif
1154
1155         int i;
1156         PALETTEENTRY    pe[256];
1157         for (i=0; i<256; i++ )  {
1158                 pe[i].peFlags = PC_NOCOLLAPSE|PC_RESERVED;
1159                 pe[i].peRed = 0;
1160                 pe[i].peGreen = 0;
1161                 pe[i].peBlue = 0;
1162         }       
1163         ddrval = lpDD->CreatePalette( DDPCAPS_8BIT | DDPCAPS_ALLOW256, pe, &lpPalette, NULL);
1164         if (ddrval != DD_OK) {
1165                 mprintf(( "Error creating palette\n" ));
1166                 goto DDError;
1167         }
1168
1169         ddrval = lpFrontBuffer->SetPalette( lpPalette );
1170         if (ddrval != DD_OK) {
1171                 mprintf(( "Error setting palette in gr_directdraw_set_palette\n" ));
1172         }
1173
1174
1175         memset( &ddsd, 0, sizeof( ddsd ) );
1176         ddsd.dwSize = sizeof(ddsd);
1177         lpFrontBuffer->GetSurfaceDesc(&ddsd);   
1178         dd_get_shift_masks( &ddsd );
1179
1180         mprintf(( "Surfaces created...\n" ));
1181
1182         goto NoDDError;
1183
1184 DDError:
1185         lpDD->Release();
1186         exit(1);
1187                 
1188
1189 NoDDError:
1190                 ;
1191
1192         grx_init_alphacolors();
1193
1194         gr_screen.gf_flip = gr_directdraw_flip;
1195         gr_screen.gf_flip_window = gr_directdraw_flip_window;
1196         gr_screen.gf_set_clip = gr_directdraw_set_clip;
1197         gr_screen.gf_reset_clip = gr_directdraw_reset_clip;
1198         gr_screen.gf_set_font = grx_set_font;
1199         gr_screen.gf_set_color = grx_set_color;
1200         gr_screen.gf_set_bitmap = gr_directdraw_set_bitmap;
1201         gr_screen.gf_create_shader = grx_create_shader;
1202         gr_screen.gf_set_shader = grx_set_shader;
1203         gr_screen.gf_clear = gr_directdraw_clear;
1204         // gr_screen.gf_bitmap = grx_bitmap;
1205         // gr_screen.gf_bitmap_ex = grx_bitmap_ex;
1206
1207         gr_screen.gf_aabitmap = grx_aabitmap;
1208         gr_screen.gf_aabitmap_ex = grx_aabitmap_ex;
1209
1210         gr_screen.gf_rect = grx_rect;
1211         gr_screen.gf_shade = gr8_shade;
1212         gr_screen.gf_string = gr8_string;
1213         gr_screen.gf_circle = gr8_circle;
1214
1215         gr_screen.gf_line = gr8_line;
1216         gr_screen.gf_aaline = gr8_aaline;
1217         gr_screen.gf_pixel = gr8_pixel;
1218         gr_screen.gf_scaler = gr8_scaler;
1219         gr_screen.gf_aascaler = gr8_aascaler;
1220         gr_screen.gf_tmapper = grx_tmapper;
1221
1222         gr_screen.gf_gradient = gr8_gradient;
1223
1224         gr_screen.gf_set_palette = gr_directdraw_set_palette;
1225         gr_screen.gf_get_color = grx_get_color;
1226         gr_screen.gf_init_color = grx_init_color;
1227         gr_screen.gf_init_alphacolor = grx_init_alphacolor;
1228         gr_screen.gf_set_color_fast = grx_set_color_fast;
1229         gr_screen.gf_print_screen = grx_print_screen;
1230
1231         gr_screen.gf_start_frame = gr_directdraw_start_frame;
1232         gr_screen.gf_stop_frame = gr_directdraw_stop_frame;
1233
1234         gr_screen.gf_fade_in = gr_directdraw_fade_in;
1235         gr_screen.gf_fade_out = gr_directdraw_fade_out;
1236         gr_screen.gf_flash = gr_directdraw_flash;
1237
1238         // Retrieves the zbuffer mode.
1239         gr_screen.gf_zbuffer_get = gr8_zbuffer_get;
1240         gr_screen.gf_zbuffer_set = gr8_zbuffer_set;
1241         gr_screen.gf_zbuffer_clear = gr8_zbuffer_clear;
1242
1243         gr_screen.gf_save_screen = gr8_save_screen;
1244         gr_screen.gf_restore_screen = gr8_restore_screen;
1245         gr_screen.gf_free_screen = gr8_free_screen;
1246
1247         // Screen dumping stuff
1248         gr_screen.gf_dump_frame_start = gr8_dump_frame_start;
1249         gr_screen.gf_dump_frame_stop = gr8_dump_frame_stop;
1250         gr_screen.gf_dump_frame = gr8_dump_frame;
1251
1252         // Gamma stuff
1253         gr_screen.gf_set_gamma = gr8_set_gamma;
1254
1255         // Lock/unlock stuff
1256         gr_screen.gf_lock = gr_directdraw_lock;
1257         gr_screen.gf_unlock = gr_directdraw_unlock_fake;
1258
1259         // region
1260         gr_screen.gf_get_region = gr_directdraw_get_region;
1261
1262         // poly culling
1263         gr_screen.gf_set_cull = gr_directdraw_set_cull;
1264
1265         // cross fade
1266         gr_screen.gf_cross_fade = gr_directdraw_cross_fade;
1267
1268         // filter
1269         gr_screen.gf_filter_set = gr_directdraw_filter_set;
1270
1271         // set clear color
1272         gr_screen.gf_set_clear_color = gr_directdraw_set_clear_color;
1273
1274         gr_lock();
1275
1276         mprintf(( "Surfaces locked...\n" ));
1277
1278         Mouse_hidden++;
1279         gr_reset_clip();
1280         gr_clear();
1281         gr_flip();
1282         Mouse_hidden--;
1283 #else
1284         Int3();
1285 #endif
1286 }