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