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