]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grsoft.cpp
Initial revision
[taylor/freespace2.git] / src / graphics / grsoft.cpp
1 /*
2  * $Logfile: /Freespace2/code/Graphics/GrSoft.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code for our software renderer using standard Win32 functions.  (Dibsections, etc)
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 12    7/14/99 9:42a Dave
15  * Put in clear_color debug function. Put in base for 3dnow stuff / P3
16  * stuff
17  * 
18  * 11    7/09/99 9:51a Dave
19  * Added thick polyline code.
20  * 
21  * 10    6/29/99 10:35a Dave
22  * Interface polygon bitmaps! Whee!
23  * 
24  * 9     2/03/99 11:44a Dave
25  * Fixed d3d transparent textures.
26  * 
27  * 8     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  * 7     12/18/98 1:13a Dave
32  * Rough 1024x768 support for Direct3D. Proper detection and usage through
33  * the launcher.
34  * 
35  * 6     12/06/98 2:36p Dave
36  * Drastically improved nebula fogging.
37  * 
38  * 5     11/30/98 5:31p Dave
39  * Fixed up Fred support for software mode.
40  * 
41  * 4     11/30/98 1:07p Dave
42  * 16 bit conversion, first run.
43  * 
44  * 3     11/11/98 5:37p Dave
45  * Checkin for multiplayer testing.
46  * 
47  * 2     10/07/98 10:53a Dave
48  * Initial checkin.
49  * 
50  * 1     10/07/98 10:49a Dave
51  * 
52  * 84    5/20/98 9:46p John
53  * added code so the places in code that change half the palette don't
54  * have to clear the screen.
55  * 
56  * 83    5/18/98 11:17a John
57  * Fixed some bugs with software window and output window.
58  * 
59  * 82    5/17/98 5:03p John
60  * Fixed some bugs that make the taskbar interfere with the DEBUG-only
61  * mouse cursor.
62  * 
63  * 81    5/15/98 2:44p John
64  * Made windowed mode not touch the window if no handle to window found.
65  * 
66  * 80    5/14/98 5:42p John
67  * Revamped the whole window position/mouse code for the graphics windows.
68  * 
69  * 79    5/07/98 6:58p Hoffoss
70  * Made changes to mouse code to fix a number of problems.
71  * 
72  * 78    5/06/98 5:30p John
73  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
74  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
75  * DirectX header files and libs that fixed the Direct3D alpha blending
76  * problems.
77  * 
78  * 77    4/23/98 8:24a John
79  * Changed the way palette effect works so that:
80  * 1. If gr_flash isn't called this frame, screen shows no flash.
81  * 2. With hardware, only 3d portion of screen gets flashed.
82  * 
83  * 76    4/21/98 5:22p John
84  * Fixed all the &^#@$ cursor bugs with popups.   For Glide, had problem
85  * with mouse restoring assuming back buffer was same buffer last frame,
86  * for software, problems with half drawn new frames, then mouse got
87  * restored on top of that with old data.
88  * 
89  * 75    4/14/98 12:15p John
90  * Made 16-bpp movies work.
91  * 
92  * 74    4/11/98 12:48p John
93  * Made software fade out actually clear screen to black.
94  * 
95  * 73    4/01/98 9:21p John
96  * Made NDEBUG, optimized build with no warnings or errors.
97  * 
98  * 72    3/25/98 8:07p John
99  * Restructured software rendering into two modules; One for windowed
100  * debug mode and one for DirectX fullscreen.   
101  * 
102  * 71    3/24/98 3:58p John
103  * Put in (hopefully) final gamma setting code.
104  * 
105  * 70    3/17/98 5:55p John
106  * Added code to dump Glide frames.   Moved Allender's  "hack" code out of
107  * Freespace.cpp into the proper place, graphics lib.
108  * 
109  * 69    3/14/98 5:46p John
110  * 
111  * 68    3/14/98 5:43p John
112  * Saved area under mouse cursor.  Made save_Screen restore it so no mouse
113  * is on those screens.
114  * 
115  * 67    3/12/98 8:50a John
116  * took out "allocating zbuffer" mprintf
117  * 
118  * 66    3/10/98 4:18p John
119  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
120  * & Glide have popups and print screen.  Took out all >8bpp software
121  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
122  * support Fred.  Made zbuffering key off of functions rather than one
123  * global variable.
124  * 
125  * 65    3/06/98 4:09p John
126  * Changed the way we do bitmap RLE'ing... this speds up HUD bitmaps by
127  * about 2x
128  * 
129  * 64    3/05/98 4:28p John
130  * Made mouse cursor hide while setting palette.
131  * 
132  * 63    3/02/98 5:42p John
133  * Removed WinAVI stuff from Freespace.  Made all HUD gauges wriggle from
134  * afterburner.  Made gr_set_clip work good with negative x &y.  Made
135  * model_caching be on by default.  Made each cached model have it's own
136  * bitmap id.  Made asteroids not rotate when model_caching is on.  
137  * 
138  * 62    2/24/98 3:50p John
139  * Made Alt+Tabbing work with Glide.  Made Int3's restore Glide screen on
140  * next flip.
141  * 
142  * 61    2/24/98 1:59p John
143  * Made gr_aabitmap_ex clip properly
144  * 
145  * 60    2/05/98 9:21p John
146  * Some new Direct3D code.   Added code to monitor a ton of stuff in the
147  * game.
148  * 
149  * 59    1/19/98 6:15p John
150  * Fixed all my Optimized Build compiler warnings
151  * 
152  * 58    1/15/98 4:07p John
153  * added grx_set_palette_internal which doesn't clear the screen and flip
154  * before setting the palette.
155  * 
156  * 57    1/15/98 4:02p John
157  * Fixed stupid bug on my part where I called graphics rendering functions
158  * from another thread!!! Duh!  Fixed it by setting a variable and then
159  * resetting the palette at the next flip.
160  * 
161  * 56    1/08/98 5:06p John
162  * Replaced Int3 with a mprintf
163  * 
164  * 55    1/08/98 3:10p John
165  * Undid my palette changes for interplay rev
166  * 
167  * 54    1/08/98 3:03p John
168  * 
169  * 53    1/05/98 11:52a Jasen
170  * JAS: Made graphics code work if os_get_window returns NULL when trying
171  * to go fullscreen.
172  * 
173  * 52    12/30/97 6:47p John
174  * Made fade time correct
175  * 
176  * 51    12/30/97 6:46p John
177  * Added first rev of palette fade in out functions
178  * 
179  * 50    12/21/97 4:33p John
180  * Made debug console functions a class that registers itself
181  * automatically, so you don't need to add the function to
182  * debugfunctions.cpp.  
183  * 
184  * 49    12/05/97 4:26p John
185  * made palette set code be like it was before.
186  * 
187  * 48    12/04/97 8:05p John
188  * added test code to brighten palette
189  * 
190  * 47    12/03/97 2:16p John
191  * Took out blur code and fake_vram buffer.
192  * 
193  * 46    12/02/97 4:00p John
194  * Added first rev of thruster glow, along with variable levels of
195  * translucency, which retquired some restructing of palman.
196  * 
197  * 45    11/30/97 12:18p John
198  * added more 24 & 32-bpp primitives
199  * 
200  * 44    11/29/97 2:06p John
201  * added mode 16-bpp support
202  * 
203  * 43    11/21/97 11:32a John
204  * Added nebulas.   Fixed some warpout bugs.
205  * 
206  * 42    11/20/97 9:51a John
207  * added code to force screen to 16-bit even if rendering 8.
208  * 
209  * 41    11/17/97 10:33a John
210  * updated force_windowed code.
211  * 
212  * 40    11/14/97 3:54p John
213  * Added triple buffering.
214  * 
215  * 39    11/14/97 3:08p Johnson
216  * fixed bug with fred.
217  * 
218  * 38    11/14/97 12:30p John
219  * Fixed some DirectX bugs.  Moved the 8-16 xlat tables into Graphics
220  * libs.  Made 16-bpp DirectX modes know what bitmap format they're in.
221  * 
222  * 37    11/06/97 4:12p John
223  * Took out debug code that returned NULL for DD.
224  * 
225  * 36    11/05/97 12:35p John
226  * added correct gr_bitmap_ex that does clipping
227  * 
228  * 
229  * 35    10/31/97 9:43a John
230  * fixed red background color bug.
231  * 
232  * 34    10/19/97 1:53p John
233  * hacked in a fix to a zbuffer error caused by inaccuracies.
234  * 
235  * 33    10/19/97 12:55p John
236  * new code to lock / unlock surfaces for smooth directx integration.
237  * 
238  * 32    10/15/97 4:48p John
239  * added 16-bpp aascaler
240  * 
241  * 31    10/14/97 4:50p John
242  * more 16 bpp stuff.
243  * 
244  * 30    10/14/97 8:08a John
245  * added a bunch more 16 bit support
246  * 
247  * 29    10/09/97 5:23p John
248  * Added support for more 16-bpp functions
249  * 
250  * 28    10/03/97 9:10a John
251  * added better antialiased line drawer
252  * 
253  * 27    9/23/97 11:50a Lawrance
254  * jas: added xparency to rle'd bitblts
255  * 
256  * 26    9/23/97 10:45a John
257  * made so you can tell bitblt code to rle a bitmap by passing flag to
258  * gr_set_bitmap
259  * 
260  * 25    9/20/97 10:48a John
261  * added motion blur code.
262  * 
263  * 24    9/09/97 10:39a Sandeep
264  * fixed warning level 4
265  * 
266  * 23    9/07/97 2:34p John
267  * fixed bug with fullscreen toggling not working when in > 8bpp mode.
268  * 
269  * 22    9/03/97 4:32p John
270  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
271  * to bm_load functions not needed.   Made bmpman keep track of palettes
272  * for bitmaps not mapped into game palettes.
273  * 
274  * 21    8/26/97 11:30a John
275  * removed call to restoredisplymode when going from fullscreen to
276  * windowed, which hopefully fixes the screwey taskbar problem.
277  * 
278  * 20    8/04/97 4:47p John
279  * added gr_aascaler.
280  * 
281  * 19    7/17/97 9:31a John
282  * made all directX header files name start with a v
283  * 
284  * 18    7/10/97 2:06p John
285  * added code to specify alphablending type for bitmaps.
286  * 
287  * 17    6/20/97 1:50p John
288  * added rle code to bmpman.  made gr8_aabitmap use it.
289  * 
290  * 16    6/17/97 12:03p John
291  * Moved color/alphacolor functions into their own module.  Made all color
292  * functions be part of the low-level graphics drivers, not just the
293  * grsoft.
294  * 
295  * 15    6/13/97 5:35p John
296  * added some antialiased bitmaps and lines
297  * 
298  * 14    6/12/97 2:50a Lawrance
299  * bm_unlock() now passed bitmap number, not pointer
300  * 
301  * 13    6/11/97 5:49p John
302  * Changed palette code to only recalculate alphacolors when needed, not
303  * when palette changes.
304  * 
305  * 12    6/11/97 1:12p John
306  * Started fixing all the text colors in the game.
307  * 
308  * 11    6/06/97 5:03p John
309  * fixed bug withalpha colors failing after gr_init
310  * 
311  * 10    6/06/97 4:41p John
312  * Fixed alpha colors to be smoothly integrated into gr_set_color_fast
313  * code.
314  * 
315  * 9     5/29/97 3:09p John
316  * Took out debug menu.  
317  * Made software scaler draw larger bitmaps.
318  * Optimized Direct3D some.
319  * 
320  * 8     5/16/97 9:11a John
321  * fixed bug that made Ctrl+Break in fullscreen hang
322  * 
323  * 7     5/14/97 4:40p John
324  * took out mprintf
325  * 
326  * 6     5/14/97 4:38p John
327  * Fixed print_screen bug.
328  * 
329  * 5     5/14/97 2:09p John
330  * made fullscreen use 254 palette entries.    Used
331  * CreateCompatibleDC(NULL) Instead of GetDC(HWND_DESKTOP) because the
332  * GetDC method fails when you change screen depth dynamically under NT.
333  * 
334  * 4     5/14/97 10:53a John
335  * fixed some discrepencies between d3d and software palette setting.
336  * 
337  * 3     5/14/97 8:53a John
338  * Fixed a palette bug when switching into/outof d3d mode.
339  * 
340  * 2     5/13/97 12:39p John
341  * Got fullscreen mode working.
342  * 
343  * 1     5/12/97 12:14p John
344  *
345  * $NoKeywords: $
346  */
347
348 #include <math.h>
349 #include <windows.h>
350 #include <windowsx.h>
351
352 #include "osapi.h"
353 #include "2d.h"
354 #include "bmpman.h"
355 #include "key.h"
356 #include "floating.h"
357 #include "palman.h"
358 #include "grsoft.h"
359 #include "grinternal.h"
360
361 // Headers for 2d functions
362 #include "pixel.h"
363 #include "line.h"
364 #include "scaler.h"
365 #include "tmapper.h"
366 #include "circle.h"
367 #include "shade.h"
368 #include "rect.h"
369 #include "gradient.h"
370 #include "pcxutils.h"
371 #include "osapi.h"
372 #include "mouse.h"
373 #include "font.h"
374 #include "timer.h"
375 #include "colors.h"
376 #include "bitblt.h"
377
378  // Window's specific
379
380 // This structure is the same as LOGPALETTE except that LOGPALETTE
381 // requires you to malloc out space for the palette, which just isn't
382 // worth the trouble.
383
384 typedef struct {
385     WORD         palVersion; 
386     WORD         palNumEntries; 
387     PALETTEENTRY palPalEntry[256]; 
388 } EZ_LOGPALETTE; 
389
390 // This structure is the same as BITMAPINFO except that BITMAPINFO
391 // requires you to malloc out space for the palette, which just isn't
392 // worth the trouble.   I also went ahead and threw a handy union to
393 // easily reference the hicolor masks in 15/16 bpp modes.
394 typedef struct  {
395         BITMAPINFOHEADER Header;
396         union {
397                 RGBQUAD aColors[256];
398                 ushort PalIndex[256];
399                 uint hicolor_masks[3];
400         } Colors;
401 } EZ_BITMAPINFO;
402
403 EZ_BITMAPINFO DibInfo;
404 HBITMAP hDibSection = NULL;
405 HBITMAP hOldBitmap = NULL;
406 HDC hDibDC = NULL;
407 void *lpDibBits=NULL;
408
409 HPALETTE hOldPalette=NULL, hPalette = NULL;     
410
411 int Gr_soft_inited = 0;
412
413 static volatile int Grsoft_activated = 0;                               // If set, that means application got focus, so reset palette
414
415 void gr_buffer_release()
416 {
417         if ( hPalette ) {
418                 if (hDibDC)
419                         SelectPalette( hDibDC, hOldPalette, FALSE );
420                 if (!DeleteObject(hPalette))    {
421                         mprintf(( "JOHN: Couldn't delete palette object\n" ));
422                 }
423                 hPalette = NULL;
424         }
425
426         if ( hDibDC )   {
427                 SelectObject(hDibDC, hOldBitmap );
428                 DeleteDC(hDibDC);
429                 hDibDC = NULL;
430         }
431
432         if ( hDibSection )      {
433                 DeleteObject(hDibSection);
434                 hDibSection = NULL;
435         }
436 }
437
438
439 void gr_buffer_create( int w, int h, int bpp )
440 {
441         int i;
442
443         if (w & 3) {
444                 Int3(); // w must be multiple 4
445                 return;
446         }
447
448         gr_buffer_release();
449
450         memset( &DibInfo, 0, sizeof(EZ_BITMAPINFO));
451    DibInfo.Header.biSize = sizeof(BITMAPINFOHEADER);
452         DibInfo.Header.biWidth = w;
453         DibInfo.Header.biHeight = h;
454         DibInfo.Header.biPlanes = 1; 
455         DibInfo.Header.biClrUsed = 0;
456
457         switch( bpp )   {
458         case 8:
459                 Gr_red.bits = 8;
460                 Gr_red.shift = 16;
461                 Gr_red.scale = 1;
462                 Gr_red.mask = 0xff0000;
463
464                 Gr_green.bits = 8;
465                 Gr_green.shift = 8;
466                 Gr_green.scale = 1;
467                 Gr_green.mask = 0xff00;
468
469                 Gr_blue.bits = 8;
470                 Gr_blue.shift = 0;
471                 Gr_blue.scale = 1;
472                 Gr_blue.mask = 0xff;
473
474                 DibInfo.Header.biCompression = BI_RGB; 
475                 DibInfo.Header.biBitCount = 8; 
476                 for (i=0; i<256; i++ )  {
477                         DibInfo.Colors.aColors[i].rgbRed = 0;
478                         DibInfo.Colors.aColors[i].rgbGreen = 0;
479                         DibInfo.Colors.aColors[i].rgbBlue = 0;
480                         DibInfo.Colors.aColors[i].rgbReserved = 0;
481                 }
482                 break;
483
484         case 15:
485                 Gr_red.bits = 5;
486                 Gr_red.shift = 10;
487                 Gr_red.scale = 8;
488                 Gr_red.mask = 0x7C00;
489
490                 Gr_green.bits = 5;
491                 Gr_green.shift = 5;
492                 Gr_green.scale = 8;
493                 Gr_green.mask = 0x3E0;
494
495                 Gr_blue.bits = 5;
496                 Gr_blue.shift = 0;
497                 Gr_blue.scale = 8;
498                 Gr_blue.mask = 0x1F;
499
500                 DibInfo.Header.biCompression = BI_BITFIELDS;
501                 DibInfo.Header.biBitCount = 16; 
502                 DibInfo.Colors.hicolor_masks[0] = Gr_red.mask;
503                 DibInfo.Colors.hicolor_masks[1] = Gr_green.mask;
504                 DibInfo.Colors.hicolor_masks[2] = Gr_blue.mask;
505
506
507                 break;
508
509         case 16:
510                 Gr_red.bits = 5;
511                 Gr_red.shift = 11;
512                 Gr_red.scale = 8;
513                 Gr_red.mask = 0xF800;
514
515                 Gr_green.bits = 6;
516                 Gr_green.shift = 5;
517                 Gr_green.scale = 4;
518                 Gr_green.mask = 0x7E0;
519
520                 Gr_blue.bits = 5;
521                 Gr_blue.shift = 0;
522                 Gr_blue.scale = 8;
523                 Gr_blue.mask = 0x1F;
524
525                 DibInfo.Header.biCompression = BI_BITFIELDS;
526                 DibInfo.Header.biBitCount = 16; 
527                 DibInfo.Colors.hicolor_masks[0] = Gr_red.mask;
528                 DibInfo.Colors.hicolor_masks[1] = Gr_green.mask;
529                 DibInfo.Colors.hicolor_masks[2] = Gr_blue.mask;
530                 break;
531
532         case 24:
533         case 32:
534                 Gr_red.bits = 8;
535                 Gr_red.shift = 16;
536                 Gr_red.scale = 1;
537                 Gr_red.mask = 0xff0000;
538
539                 Gr_green.bits = 8;
540                 Gr_green.shift = 8;
541                 Gr_green.scale = 1;
542                 Gr_green.mask = 0xff00;
543
544                 Gr_blue.bits = 8;
545                 Gr_blue.shift = 0;
546                 Gr_blue.scale = 1;
547                 Gr_blue.mask = 0xff;
548
549                 DibInfo.Header.biCompression = BI_RGB; 
550                 DibInfo.Header.biBitCount = unsigned short(bpp); 
551                 break;
552
553         default:
554                 Int3(); // Illegal bpp
555         }
556
557         lpDibBits = NULL;
558
559         hDibDC = CreateCompatibleDC(NULL);
560         hDibSection = CreateDIBSection(hDibDC,(BITMAPINFO *)&DibInfo,DIB_RGB_COLORS,&lpDibBits,NULL,NULL);
561         hOldBitmap = (HBITMAP)SelectObject(hDibDC, hDibSection );
562
563         if ( hDibSection == NULL )      {
564                 Int3(); // couldn't allocate dib section
565         }
566 }
567
568
569 // This makes a best-fit palette from the 256 target colors and
570 // the system colors which should look better than only using the
571 // colors in the range 10-246, but it will totally reorder the palette.
572 // All colors get changed in target_palette.
573
574
575 HPALETTE gr_create_palette_0(ubyte * target_palette)
576 {
577         EZ_LOGPALETTE LogicalPalette;
578         HDC ScreenDC;
579         HPALETTE hpal,hpalOld;
580         PALETTEENTRY pe[256];
581         int NumSysColors, NumColors;
582         int i;
583
584         // Create a 1-1 mapping of the system palette
585         LogicalPalette.palVersion = 0x300;
586         LogicalPalette.palNumEntries = 256;
587
588         // Pack in all the colors
589         for (i=0;i<256; i++)    {
590                 LogicalPalette.palPalEntry[i].peRed = target_palette[i*3+0];
591                 LogicalPalette.palPalEntry[i].peGreen = target_palette[i*3+1];
592                 LogicalPalette.palPalEntry[i].peBlue = target_palette[i*3+2];
593                 LogicalPalette.palPalEntry[i].peFlags = 0;      //PC_EXPLICIT;
594         } 
595
596         hpal = CreatePalette( (LOGPALETTE *)&LogicalPalette );
597
598         ScreenDC = CreateCompatibleDC(NULL);
599
600         if ( !(GetDeviceCaps(ScreenDC,RASTERCAPS) & RC_PALETTE) ) {
601                 DeleteDC(ScreenDC);
602                 return hpal;
603         }
604          
605         NumSysColors = GetDeviceCaps( ScreenDC, NUMCOLORS );
606         NumColors = GetDeviceCaps( ScreenDC, SIZEPALETTE );
607
608         // Reset all the Palette Manager tables
609         SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC );
610         SetSystemPaletteUse( ScreenDC, SYSPAL_STATIC );
611
612         // Enter our palette's values into the free slots
613         hpalOld=SelectPalette( ScreenDC, hpal, FALSE );
614         RealizePalette( ScreenDC );
615         SelectPalette( ScreenDC, hpalOld, FALSE );
616
617         GetSystemPaletteEntries(ScreenDC,0,NumColors,pe);
618
619         for (i=0; i<NumSysColors/2; i++ )       {
620                 pe[i].peFlags = 0;
621         }
622         for (; i<NumColors - NumSysColors/2; i++ )      {
623                 pe[i].peFlags = PC_NOCOLLAPSE;
624         }
625         for (; i<NumColors; i++ )       {
626                 pe[i].peFlags = 0;
627         }
628         ResizePalette( hpal, NumColors);
629         SetPaletteEntries( hpal, 0, NumColors, pe );
630                 
631         for (i=0; i<256; i++ )  {
632                 target_palette[i*3+0] = pe[i].peRed;
633                 target_palette[i*3+1] = pe[i].peGreen;
634                 target_palette[i*3+2] = pe[i].peBlue;
635         }
636
637         DeleteDC(ScreenDC);
638
639         return hpal;
640 }
641
642 HPALETTE gr_create_palette_256( ubyte * target_palette )
643 {
644         EZ_LOGPALETTE LogicalPalette;
645         int i;
646
647         // Pack in all the colors
648         for (i=0;i<256; i++)    {
649                 LogicalPalette.palPalEntry[i].peRed = target_palette[i*3+0];
650                 LogicalPalette.palPalEntry[i].peGreen = target_palette[i*3+1];
651                 LogicalPalette.palPalEntry[i].peBlue = target_palette[i*3+2];
652                 LogicalPalette.palPalEntry[i].peFlags = 0;      //PC_RESERVED;  //PC_EXPLICIT;
653         } 
654
655         // Create a 1-1 mapping of the system palette
656         LogicalPalette.palVersion = 0x300;
657         LogicalPalette.palNumEntries = 256;
658
659         return CreatePalette( (LOGPALETTE *)&LogicalPalette );
660 }
661
662 // This makes an indentity logical palette that saves entries 10-246
663 // and leaves them in place.  Colors 0-9 and 246-255 get changed in 
664 // target_palette.  trash_flag tells us whether to trash the system palette
665 // or not
666 HPALETTE gr_create_palette_236( ubyte * target_palette )
667 {
668         EZ_LOGPALETTE LogicalPalette;
669         HDC ScreenDC;
670         int NumSysColors, NumColors, UserLowest, UserHighest;
671         int i;
672
673         // Pack in all the colors
674         for (i=0;i<256; i++)    {
675                 LogicalPalette.palPalEntry[i].peRed = target_palette[i*3+0];
676                 LogicalPalette.palPalEntry[i].peGreen = target_palette[i*3+1];
677                 LogicalPalette.palPalEntry[i].peBlue = target_palette[i*3+2];
678                 LogicalPalette.palPalEntry[i].peFlags = 0;      //PC_EXPLICIT;
679         } 
680
681         // Create a 1-1 mapping of the system palette
682         LogicalPalette.palVersion = 0x300;
683         LogicalPalette.palNumEntries = 256;
684
685         ScreenDC = CreateCompatibleDC(NULL);
686
687         // Reset all the Palette Manager tables
688         SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC );
689         SetSystemPaletteUse( ScreenDC, SYSPAL_STATIC );
690                 
691         if ( !(GetDeviceCaps(ScreenDC,RASTERCAPS) & RC_PALETTE) ) {
692                 DeleteDC(ScreenDC);
693                 return CreatePalette( (LOGPALETTE *)&LogicalPalette );
694         }
695
696         NumSysColors = GetDeviceCaps( ScreenDC, NUMCOLORS );
697         NumColors = GetDeviceCaps( ScreenDC, SIZEPALETTE );
698
699         Assert( NumColors <= 256 );
700
701         UserLowest = NumSysColors/2;                                                            // 10 normally
702         UserHighest = NumColors - NumSysColors/2 - 1;           // 245 normally
703
704         Assert( (UserHighest - UserLowest + 1) >= 236 );
705                         
706         GetSystemPaletteEntries(ScreenDC,0,NumSysColors/2,LogicalPalette.palPalEntry);
707         GetSystemPaletteEntries(ScreenDC,UserHighest+1,NumSysColors/2,LogicalPalette.palPalEntry+1+UserHighest);
708
709         DeleteDC(ScreenDC);
710                 
711         for (i=0; i<256; i++ )  {
712
713                 if ( (i >= UserLowest) && (i<=UserHighest) )    {
714                         LogicalPalette.palPalEntry[i].peFlags = PC_NOCOLLAPSE;
715                 } else
716                         LogicalPalette.palPalEntry[i].peFlags = 0;
717
718                 target_palette[i*3+0] = LogicalPalette.palPalEntry[i].peRed;
719                 target_palette[i*3+1] = LogicalPalette.palPalEntry[i].peGreen;
720                 target_palette[i*3+2] = LogicalPalette.palPalEntry[i].peBlue;
721         }
722
723         return CreatePalette( (LOGPALETTE *)&LogicalPalette );
724 }
725
726 HPALETTE gr_create_palette_254( ubyte * target_palette )
727 {
728         EZ_LOGPALETTE LogicalPalette;
729         HDC ScreenDC;
730         int NumSysColors, NumColors, UserLowest, UserHighest;
731         int i;
732
733         // Pack in all the colors
734         for (i=0;i<256; i++)    {
735                 LogicalPalette.palPalEntry[i].peRed = target_palette[i*3+0];
736                 LogicalPalette.palPalEntry[i].peGreen = target_palette[i*3+1];
737                 LogicalPalette.palPalEntry[i].peBlue = target_palette[i*3+2];
738                 LogicalPalette.palPalEntry[i].peFlags = 0;      //PC_EXPLICIT;
739         } 
740
741         // Create a 1-1 mapping of the system palette
742         LogicalPalette.palVersion = 0x300;
743         LogicalPalette.palNumEntries = 256;
744
745         ScreenDC = CreateCompatibleDC(NULL);
746
747         // Reset all the Palette Manager tables
748         SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC );
749         SetSystemPaletteUse( ScreenDC, SYSPAL_STATIC );
750                 
751         if ( !(GetDeviceCaps(ScreenDC,RASTERCAPS) & RC_PALETTE) ) {
752                 DeleteDC(ScreenDC);
753                 return CreatePalette( (LOGPALETTE *)&LogicalPalette );
754         }
755
756         SetSystemPaletteUse( ScreenDC, SYSPAL_NOSTATIC );
757         NumSysColors = 2;
758         NumColors = GetDeviceCaps( ScreenDC, SIZEPALETTE );
759
760         Assert( NumColors <= 256 );
761
762         UserLowest = NumSysColors/2;                                                            // 10 normally
763         UserHighest = NumColors - NumSysColors/2 - 1;           // 245 normally
764
765         Assert( (UserHighest - UserLowest + 1) >= 236 );
766                         
767         GetSystemPaletteEntries(ScreenDC,0,NumSysColors/2,LogicalPalette.palPalEntry);
768         GetSystemPaletteEntries(ScreenDC,UserHighest+1,NumSysColors/2,LogicalPalette.palPalEntry+1+UserHighest);
769
770         DeleteDC(ScreenDC);
771         
772         for (i=0; i<256; i++ )  {
773
774                 if ( (i >= UserLowest) && (i<=UserHighest) )    {
775                         LogicalPalette.palPalEntry[i].peFlags = PC_NOCOLLAPSE;
776                 } else
777                         LogicalPalette.palPalEntry[i].peFlags = 0;
778
779                 target_palette[i*3+0] = LogicalPalette.palPalEntry[i].peRed;
780                 target_palette[i*3+1] = LogicalPalette.palPalEntry[i].peGreen;
781                 target_palette[i*3+2] = LogicalPalette.palPalEntry[i].peBlue;
782         }
783
784         return CreatePalette( (LOGPALETTE *)&LogicalPalette );
785 }
786
787 void grx_set_palette_internal( ubyte * new_pal )
788 {
789         if ( hPalette ) {
790                 if (hDibDC)
791                         SelectPalette( hDibDC, hOldPalette, FALSE );
792                 if (!DeleteObject(hPalette))    {
793                         mprintf(( "JOHN: Couldn't delete palette object\n" ));
794                 }
795                 hPalette = NULL;
796         }
797
798
799         // Make sure color 0 is black
800         if ( (new_pal[0]!=0) || (new_pal[1]!=0) || (new_pal[2]!=0) )    {
801                 // color 0 isn't black!! switch it!
802                 int i;
803                 int black_index = -1;
804
805                 for (i=1; i<256; i++ )  {
806                         if ( (new_pal[i*3+0]==0) && (new_pal[i*3+1]==0) && (new_pal[i*3+2]==0) )        {       
807                                 black_index = i;
808                                 break;
809                         }
810                 }
811                 if ( black_index > -1 ) {
812                         // swap black and color 0, so color 0 is black
813                         ubyte tmp[3];
814                         tmp[0] = new_pal[black_index*3+0];
815                         tmp[1] = new_pal[black_index*3+1];
816                         tmp[2] = new_pal[black_index*3+2];
817
818                         new_pal[black_index*3+0] = new_pal[0];
819                         new_pal[black_index*3+1] = new_pal[1];
820                         new_pal[black_index*3+2] = new_pal[2];
821
822                         new_pal[0] = tmp[0];
823                         new_pal[1] = tmp[1];
824                         new_pal[2] = tmp[2];
825                 } else {
826                         // no black in palette, force color 0 to be black.
827                         new_pal[0] = 0;
828                         new_pal[1] = 0;
829                         new_pal[2] = 0;
830                 }
831         }
832
833
834
835         if ( gr_screen.bits_per_pixel==8 )      {
836
837                 // Name                    n_preserved  One-one     Speed      Windowed? 
838                 // -------------------------------------------------------------------
839                 // gr_create_palette_256   256          0-255       Slow       Yes
840                 // gr_create_palette_254   254          1-254       Fast       No
841                 // gr_create_palette_236   236          10-245      Fast       Yes
842                 // gr_create_palette_0     0            none        Fast       Yes              
843
844 /*
845                 n_preserved = 256;
846
847                 if ( n_preserved <= 0 ) {
848                         hPalette = gr_create_palette_0(new_pal);        // No colors mapped one-to-one, but probably has close to all 256 colors in it somewhere.
849                 } else if ( n_preserved <= 236 )        {
850                         hPalette = gr_create_palette_236(new_pal);      // All colors except low 10 and high 10 mapped one-to-one
851                 } else if ( n_preserved <= 254 )        {
852                         hPalette = gr_create_palette_254(new_pal);      // All colors except 0 and 255 mapped one-to-one, but changes system colors.  Not pretty in a window.
853                 } else {
854 */
855                 hPalette = gr_create_palette_256(new_pal);      // All 256 mapped one-to-one, but BLT's are slow.
856
857                 if ( hDibDC )   {
858                         int i; 
859                         for (i=0; i<256; i++ )  {
860                                 DibInfo.Colors.aColors[i].rgbRed = new_pal[i*3+0];
861                                 DibInfo.Colors.aColors[i].rgbGreen = new_pal[i*3+1];
862                                 DibInfo.Colors.aColors[i].rgbBlue = new_pal[i*3+2];
863                                 DibInfo.Colors.aColors[i].rgbReserved = 0;
864                         }
865
866                         hOldPalette = SelectPalette( hDibDC, hPalette, FALSE );
867                         SetDIBColorTable( hDibDC, 0, 256, DibInfo.Colors.aColors );
868                 }
869         } else {
870                 hPalette = NULL;
871         }
872 }
873
874
875
876 void grx_set_palette( ubyte * new_pal, int is_alphacolor )
877 {
878         if ( hPalette ) {
879                 Mouse_hidden++;
880                 gr_reset_clip();
881                 gr_clear();
882                 gr_flip();
883                 Mouse_hidden--;
884         }
885
886         grx_set_palette_internal(new_pal);
887 }
888
889
890 void grx_print_screen(char * filename)
891 {
892         int i;
893         ubyte **row_data = (ubyte **)malloc( gr_screen.max_h * sizeof(ubyte *) );
894         if ( !row_data )        {
895                 mprintf(( "couldn't allocate enough memory to dump screen\n" ));
896                 return;
897         }
898
899         gr_lock();
900
901         for (i=0; i<gr_screen.max_h; i++ )      {
902                 row_data[i] = GR_SCREEN_PTR(ubyte,0,i);
903         }
904
905         pcx_write_bitmap( filename, gr_screen.max_w, gr_screen.max_h, row_data, Gr_current_palette );
906
907         gr_unlock();
908
909         free(row_data);
910 }
911
912
913 uint gr_soft_lock()
914 {
915         return 1;
916 }
917
918 void gr_soft_unlock()
919 {
920 }
921
922
923 void grx_set_palette_internal( ubyte * new_pal );
924
925 int Grx_mouse_saved = 0;
926 int Grx_mouse_saved_x1 = 0;
927 int Grx_mouse_saved_y1 = 0;
928 int Grx_mouse_saved_x2 = 0;
929 int Grx_mouse_saved_y2 = 0;
930 int Grx_mouse_saved_w = 0;
931 int Grx_mouse_saved_h = 0;
932 #define MAX_SAVE_SIZE (32*32)
933 ubyte Grx_mouse_saved_data[MAX_SAVE_SIZE];
934
935 // Clamps X between R1 and R2
936 #define CLAMP(x,r1,r2) do { if ( (x) < (r1) ) (x) = (r1); else if ((x) > (r2)) (x) = (r2); } while(0)
937
938 void grx_save_mouse_area(int x, int y, int w, int h )
939 {
940         Grx_mouse_saved_x1 = x; 
941         Grx_mouse_saved_y1 = y;
942         Grx_mouse_saved_x2 = x+w-1;
943         Grx_mouse_saved_y2 = y+h-1;
944          
945         CLAMP(Grx_mouse_saved_x1, gr_screen.clip_left, gr_screen.clip_right );
946         CLAMP(Grx_mouse_saved_x2, gr_screen.clip_left, gr_screen.clip_right );
947         CLAMP(Grx_mouse_saved_y1, gr_screen.clip_top, gr_screen.clip_bottom );
948         CLAMP(Grx_mouse_saved_y2, gr_screen.clip_top, gr_screen.clip_bottom );
949
950         Grx_mouse_saved_w = Grx_mouse_saved_x2 - Grx_mouse_saved_x1 + 1;
951         Grx_mouse_saved_h = Grx_mouse_saved_y2 - Grx_mouse_saved_y1 + 1;
952
953         if ( Grx_mouse_saved_w < 1 ) return;
954         if ( Grx_mouse_saved_h < 1 ) return;
955
956         // Make sure we're not saving too much!
957         Assert( (Grx_mouse_saved_w*Grx_mouse_saved_h) <= MAX_SAVE_SIZE );
958
959         Grx_mouse_saved = 1;
960
961         gr_lock();
962
963         ubyte *sptr, *dptr;
964
965         dptr = Grx_mouse_saved_data;
966
967         for (int i=0; i<Grx_mouse_saved_h; i++ )        {
968                 sptr = GR_SCREEN_PTR(ubyte,Grx_mouse_saved_x1,Grx_mouse_saved_y1+i);
969
970                 for(int j=0; j<Grx_mouse_saved_w; j++ ) {
971                         *dptr++ = *sptr++;
972                 }
973         }
974
975         gr_unlock();
976 }
977
978
979 void grx_restore_mouse_area()
980 {
981         if ( !Grx_mouse_saved ) {
982                 return;
983         }
984
985         gr_lock();
986
987         ubyte *sptr, *dptr;
988
989         sptr = Grx_mouse_saved_data;
990
991         for (int i=0; i<Grx_mouse_saved_h; i++ )        {
992                 dptr = GR_SCREEN_PTR(ubyte,Grx_mouse_saved_x1,Grx_mouse_saved_y1+i);
993
994                 for(int j=0; j<Grx_mouse_saved_w; j++ ) {
995                         *dptr++ = *sptr++;
996                 }
997         }
998
999         gr_unlock();
1000 }
1001
1002
1003 void gr_soft_activate(int active)
1004 {
1005         if ( active  )  {
1006                 Grsoft_activated++;
1007         }
1008 }
1009
1010
1011
1012 static int Palette_flashed = 0;
1013 static int Palette_flashed_last_frame = 0;
1014
1015 void grx_change_palette( ubyte *pal );
1016
1017 void grx_flip()
1018 {
1019         if ( (!Palette_flashed) && (Palette_flashed_last_frame) )       {
1020                 // Reset flash
1021                 grx_change_palette( gr_palette );
1022         }
1023
1024         Palette_flashed_last_frame = Palette_flashed;
1025         Palette_flashed = 0;
1026
1027         // If program reactivated, flip set new palette.
1028         // We do the cnt temporary variable because Grsoft_activated
1029         // can be set during interrupts.
1030
1031         int cnt = Grsoft_activated;
1032         if ( cnt )      {
1033                 Grsoft_activated -= cnt;
1034
1035                 ubyte new_pal[768];
1036                 memcpy( new_pal, gr_palette, 768 );
1037                 grx_set_palette_internal( new_pal );            // Call internal one so it doesn't clear screen and call flip
1038         }
1039
1040         gr_reset_clip();
1041
1042 //      if (0) {
1043 //              int i;
1044 //              for (i=0; i<gr_screen.max_h; i++ )      {
1045 //                      memset( gr_screen.row_data[i], i & 255, abs(gr_screen.rowsize) );
1046 //              }
1047 //      }
1048
1049         int mx, my;
1050
1051         Grx_mouse_saved = 0;            // assume not saved
1052
1053         mouse_eval_deltas();
1054         if ( mouse_is_visible() )       {
1055                 gr_reset_clip();
1056                 mouse_get_pos( &mx, &my );
1057                 grx_save_mouse_area(mx,my,32,32);
1058                 if ( Gr_cursor == -1 )  {
1059                         gr_set_color(255,255,255);
1060                         gr_line( mx, my, mx+7, my + 7 );
1061                         gr_line( mx, my, mx+5, my );
1062                         gr_line( mx, my, mx, my+5 );
1063                 } else {
1064                         gr_set_bitmap(Gr_cursor);
1065                         gr_bitmap( mx, my );
1066                 }
1067         } 
1068
1069         fix t1, t2, d, t;
1070
1071         HWND hwnd = (HWND)os_get_window();
1072
1073         if ( hwnd )     {
1074                 int x = gr_screen.offset_x;
1075                 int y = gr_screen.offset_y;
1076                 int w = gr_screen.clip_width;
1077                 int h = gr_screen.clip_height;
1078
1079                 HPALETTE hOldPalette = NULL;
1080                 HDC hdc = GetDC(hwnd);
1081
1082                 if ( hdc )      {
1083                         t1 = timer_get_fixed_seconds();
1084
1085                         if (hPalette)   {
1086                                 hOldPalette=SelectPalette(hdc,hPalette, FALSE );
1087                                 uint nColors = RealizePalette( hdc );
1088                                 nColors;
1089                                 //if (nColors)  mprintf(( "Actually set %d palette colors.\n", nColors ));
1090                         }
1091
1092 #if 0 
1093                         BitBlt(hdc,0,h/2,w,h/2,hDibDC,x,y+h/2,SRCCOPY);
1094 #else
1095                         BitBlt(hdc,0,0,w,h,hDibDC,x,y,SRCCOPY);
1096 #endif
1097
1098                         if ( hOldPalette )      
1099                                 SelectPalette(hdc,hOldPalette, FALSE );
1100
1101                         ReleaseDC( hwnd, hdc );
1102
1103                         t2 = timer_get_fixed_seconds();
1104                         d = t2 - t1;
1105                         t = (w*h*gr_screen.bytes_per_pixel)/1024;
1106                         //mprintf(( "%d MB/s\n", fixmuldiv(t,65,d) ));
1107
1108                 }
1109         }
1110
1111         if ( Grx_mouse_saved )  {
1112                 grx_restore_mouse_area();
1113         }
1114 }
1115
1116
1117 // switch onscreen, offscreen
1118 // Set msg to 0 if calling outside of the window handler.
1119 void grx_flip_window(uint _hdc, int x, int y, int w, int h )
1120 {
1121         HDC hdc = (HDC)_hdc;
1122         HPALETTE hOldPalette = NULL;
1123         int min_w, min_h;
1124
1125         if (hPalette)   {
1126                 hOldPalette=SelectPalette(hdc,hPalette, FALSE );
1127                 RealizePalette( hdc );
1128         }
1129
1130         min_w = gr_screen.clip_width;
1131         if ( w < min_w ) min_w = w;
1132
1133         min_h = gr_screen.clip_height;
1134         if ( h < min_h ) min_h = h;
1135
1136         BitBlt(hdc,x,y,min_w,min_h,hDibDC,gr_screen.offset_x,gr_screen.offset_y,SRCCOPY);
1137
1138         //StretchBlt( hdc, 0, 0, w, h, hDibDC, 0, 0, 640, 480, SRCCOPY );
1139         
1140         if ( hOldPalette ){     
1141                 SelectPalette(hdc,hOldPalette, FALSE );
1142         }
1143 }
1144
1145
1146 // sets the clipping region & offset
1147 void grx_set_clip(int x,int y,int w,int h)
1148 {
1149         gr_screen.offset_x = x;
1150         gr_screen.offset_y = y;
1151
1152         gr_screen.clip_left = 0;
1153         gr_screen.clip_right = w-1;
1154
1155         gr_screen.clip_top = 0;
1156         gr_screen.clip_bottom = h-1;
1157
1158         // check for sanity of parameters
1159         if ( gr_screen.clip_left+x < 0 ) {
1160                 gr_screen.clip_left = -x;
1161         } else if ( gr_screen.clip_left+x > gr_screen.max_w-1 ) {
1162                 gr_screen.clip_left = gr_screen.max_w-1-x;
1163         }
1164         if ( gr_screen.clip_right+x < 0 ) {
1165                 gr_screen.clip_right = -x;
1166         } else if ( gr_screen.clip_right+x >= gr_screen.max_w-1 )       {
1167                 gr_screen.clip_right = gr_screen.max_w-1-x;
1168         }
1169
1170         if ( gr_screen.clip_top+y < 0 ) {
1171                 gr_screen.clip_top = -y;
1172         } else if ( gr_screen.clip_top+y > gr_screen.max_h-1 )  {
1173                 gr_screen.clip_top = gr_screen.max_h-1-y;
1174         }
1175
1176         if ( gr_screen.clip_bottom+y < 0 ) {
1177                 gr_screen.clip_bottom = -y;
1178         } else if ( gr_screen.clip_bottom+y > gr_screen.max_h-1 )       {
1179                 gr_screen.clip_bottom = gr_screen.max_h-1-y;
1180         }
1181
1182         gr_screen.clip_width = gr_screen.clip_right - gr_screen.clip_left + 1;
1183         gr_screen.clip_height = gr_screen.clip_bottom - gr_screen.clip_top + 1;
1184 }
1185
1186 // resets the clipping region to entire screen
1187 //
1188 // should call this before gr_surface_flip() if you clipped some portion of the screen but still 
1189 // want a full-screen display
1190 void grx_reset_clip()
1191 {
1192         gr_screen.offset_x = 0;
1193         gr_screen.offset_y = 0;
1194         gr_screen.clip_left = 0;
1195         gr_screen.clip_top = 0;
1196         gr_screen.clip_right = gr_screen.max_w - 1;
1197         gr_screen.clip_bottom = gr_screen.max_h - 1;
1198         gr_screen.clip_width = gr_screen.max_w;
1199         gr_screen.clip_height = gr_screen.max_h;
1200 }
1201
1202
1203 // Sets the current bitmap
1204 void grx_set_bitmap( int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha, int sx, int sy )
1205 {
1206         gr_screen.current_alpha = alpha;
1207         gr_screen.current_alphablend_mode = alphablend_mode;
1208         gr_screen.current_bitblt_mode = bitblt_mode;
1209         gr_screen.current_bitmap = bitmap_num;
1210         gr_screen.current_bitmap_sx = sx;
1211         gr_screen.current_bitmap_sy = sy;
1212 }
1213
1214
1215 // clears entire clipping region to black.
1216 void grx_clear()
1217 {
1218         gr_lock();
1219
1220         int i,w;
1221         ubyte *pDestBits;
1222
1223         w = gr_screen.clip_right-gr_screen.clip_left+1;
1224         for (i=gr_screen.clip_top; i<=gr_screen.clip_bottom; i++)       {
1225                 pDestBits = GR_SCREEN_PTR(ubyte,gr_screen.clip_left,i);
1226                 memset( pDestBits, 0, w );
1227         }       
1228
1229         gr_unlock();
1230 }
1231
1232
1233
1234 void grx_start_frame()
1235 {
1236 }
1237
1238 void grx_stop_frame()
1239 {
1240 }
1241
1242 void gr_soft_fog_set(int fog_mode, int r, int g, int b, float near, float far)
1243 {
1244 }
1245
1246 void gr_soft_get_pixel(int x, int y, int *r, int *g, int *b)
1247 {
1248 }
1249
1250 void grx_fade_in(int instantaneous);
1251 void grx_fade_out(int instantaneous);
1252 void grx_flash(int r, int g, int b);
1253
1254 static ubyte *Gr_saved_screen = NULL;
1255 static uint Gr_saved_screen_palette_checksum = 0;
1256 static ubyte Gr_saved_screen_palette[768];
1257
1258 int gr8_save_screen()
1259 {
1260         int i;
1261         gr_reset_clip();
1262
1263         if (gr_screen.bits_per_pixel != 8) {
1264                 mprintf(( "Save Screen only works in 8 bpp!\n" ));
1265                 return -1;
1266         }
1267
1268         if ( Gr_saved_screen )  {
1269                 mprintf(( "Screen alread saved!\n" ));
1270                 return -1;
1271         }
1272
1273         Gr_saved_screen = (ubyte *)malloc( gr_screen.max_w*gr_screen.max_h );
1274         if (!Gr_saved_screen) {
1275                 mprintf(( "Couldn't get memory for saved screen!\n" ));
1276                 return -1;
1277         }
1278
1279         Gr_saved_screen_palette_checksum = gr_palette_checksum;
1280         memcpy( Gr_saved_screen_palette, gr_palette, 768 );
1281
1282         gr_lock();
1283
1284         for (i=0; i<gr_screen.max_h; i++ )      {
1285                 ubyte *dptr = GR_SCREEN_PTR(ubyte,0,i);
1286                 memcpy( &Gr_saved_screen[gr_screen.max_w*i], dptr, gr_screen.max_w );
1287         }
1288
1289         gr_unlock();
1290
1291         return 0;
1292 }
1293
1294
1295 void gr8_restore_screen(int id)
1296 {
1297         int i;
1298         gr_reset_clip();
1299
1300         if ( !Gr_saved_screen ) {
1301                 gr_clear();
1302                 return;
1303         }
1304
1305         if ( Gr_saved_screen_palette_checksum != gr_palette_checksum )  {
1306                 // Palette changed! Remap the bitmap!
1307                 ubyte xlat[256];
1308                 for (i=0; i<256; i++ )  {
1309                         xlat[i] = (ubyte)palette_find( Gr_saved_screen_palette[i*3+0], Gr_saved_screen_palette[i*3+1], Gr_saved_screen_palette[i*3+2] );
1310                 }       
1311
1312                 for (i=0; i<gr_screen.max_h*gr_screen.max_w; i++ )      {
1313                         Gr_saved_screen[i] = xlat[Gr_saved_screen[i]];
1314                 }
1315
1316                 memcpy( Gr_saved_screen_palette, gr_palette, 768 );
1317                 Gr_saved_screen_palette_checksum = gr_palette_checksum;
1318         }
1319
1320         gr_lock();
1321
1322         for (i=0; i<gr_screen.max_h; i++ )      {
1323                 ubyte *dptr = GR_SCREEN_PTR(ubyte,0,i);
1324                 memcpy( dptr, &Gr_saved_screen[gr_screen.max_w*i], gr_screen.max_w );
1325         }
1326
1327         gr_unlock();
1328 }
1329
1330
1331 void gr8_free_screen(int id)
1332 {
1333         if ( Gr_saved_screen )  {
1334                 free( Gr_saved_screen );
1335                 Gr_saved_screen = NULL;
1336         }
1337 }
1338
1339 static int Gr8_dump_frames = 0;
1340 static ubyte *Gr8_dump_buffer = NULL;
1341 static int Gr8_dump_frame_number = 0;
1342 static int Gr8_dump_frame_count = 0;
1343 static int Gr8_dump_frame_count_max = 0;
1344 static int Gr8_dump_frame_size = 0;
1345
1346
1347 void gr8_dump_frame_start(int first_frame, int frames_between_dumps)
1348 {
1349         if ( Gr8_dump_frames )  {
1350                 Int3();         //  We're already dumping frames.  See John.
1351                 return;
1352         }       
1353         Gr8_dump_frames = 1;
1354         Gr8_dump_frame_number = first_frame;
1355         Gr8_dump_frame_count = 0;
1356         Gr8_dump_frame_count_max = frames_between_dumps;
1357         Gr8_dump_frame_size = 640 * 480;
1358         
1359         if ( !Gr8_dump_buffer ) {
1360                 int size = Gr8_dump_frame_count_max * Gr8_dump_frame_size;
1361                 Gr8_dump_buffer = (ubyte *)malloc(size);
1362                 if ( !Gr8_dump_buffer ) {
1363                         Error(LOCATION, "Unable to malloc %d bytes for dump buffer", size );
1364                 }
1365         }
1366 }
1367
1368 // A hacked function to dump the frame buffer contents
1369 void gr8_dump_screen_hack( void * dst )
1370 {
1371         int i;
1372
1373         gr_lock();
1374         for (i = 0; i < 480; i++)       {
1375                 memcpy( (ubyte *)dst+(i*640), GR_SCREEN_PTR(ubyte,0,i), 640 );
1376         }
1377         gr_unlock();
1378 }
1379
1380 void gr8_flush_frame_dump()
1381 {
1382         ubyte *buffer[480];
1383         char filename[MAX_PATH_LEN], *movie_path = "";
1384
1385         int i;
1386         for (i = 0; i < Gr8_dump_frame_count; i++) {
1387                 int j;
1388
1389                 for ( j = 0; j < 480; j++ )
1390                         buffer[j] = Gr8_dump_buffer+(i*Gr8_dump_frame_size)+(j*640);
1391
1392                 sprintf(filename, NOX("%sfrm%04d"), movie_path, Gr8_dump_frame_number );
1393                 pcx_write_bitmap(filename, 640, 480, buffer, gr_palette);
1394                 Gr8_dump_frame_number++;
1395         }
1396 }
1397
1398 void gr8_dump_frame()
1399 {
1400         // A hacked function to dump the frame buffer contents
1401         gr8_dump_screen_hack( Gr8_dump_buffer+(Gr8_dump_frame_count*Gr8_dump_frame_size) );
1402
1403         Gr8_dump_frame_count++;
1404
1405         if ( Gr8_dump_frame_count == Gr8_dump_frame_count_max ) {
1406                 gr8_flush_frame_dump();
1407                 Gr8_dump_frame_count = 0;
1408         }
1409 }
1410
1411 void grx_get_region(int front, int w, int h, ubyte *data)
1412 {
1413 }
1414
1415 // resolution checking
1416 int gr_soft_supports_res_ingame(int res)
1417 {
1418         return 1;
1419 }
1420
1421 int gr_soft_supports_res_interface(int res)
1422 {
1423         return 1;
1424 }
1425
1426 void gr8_dump_frame_stop()
1427 {
1428         if ( !Gr8_dump_frames ) {
1429                 Int3();         //  We're not dumping frames.  See John.
1430                 return;
1431         }       
1432
1433         // dump any remaining frames
1434         gr8_flush_frame_dump();
1435         
1436         Gr8_dump_frames = 0;
1437         if ( Gr8_dump_buffer )  {
1438                 free(Gr8_dump_buffer);
1439                 Gr8_dump_buffer = NULL;
1440         }
1441 }
1442
1443 void gr_soft_set_cull(int cull)
1444 {
1445 }
1446
1447 // cross fade
1448 void gr_soft_cross_fade(int bmap1, int bmap2, int x1, int y1, int x2, int y2, float pct)
1449 {
1450         if ( pct <= 50 )        {
1451                 gr_set_bitmap(bmap1);
1452                 gr_bitmap(x1, y1);
1453         } else {
1454                 gr_set_bitmap(bmap2);
1455                 gr_bitmap(x2, y2);
1456         }       
1457 }
1458
1459 // filter
1460 void gr_soft_filter_set(int filter)
1461 {
1462 }
1463
1464 // tcache
1465 int gr_soft_tcache_set(int bitmap_id, int bitmap_type, float *u_ratio, float *v_ratio, int fail_on_full = 0, int sx = -1, int sy = -1, int force = 0 )
1466 {
1467         return 1;
1468 }
1469
1470 // clear color
1471 void gr_soft_set_clear_color(int r, int g, int b)
1472 {
1473 }
1474
1475 extern uint Gr_signature;
1476
1477 //extern void gr_set_palette_internal(char *name, ubyte *pal);  
1478
1479 void gr8_set_gamma(float gamma)
1480 {
1481         Gr_gamma = gamma;
1482         Gr_gamma_int = int(Gr_gamma*100);
1483
1484         // Create the Gamma lookup table
1485         int i;
1486         for (i=0; i<256; i++ )  {
1487                 int v = fl2i(pow(i2fl(i)/255.0f, 1.0f/Gr_gamma)*255.0f);
1488                 if ( v > 255 ) {
1489                         v = 255;
1490                 } else if ( v < 0 )     {
1491                         v = 0;
1492                 }
1493                 Gr_gamma_lookup[i] = v;
1494         }
1495
1496 //      ubyte new_pal[768];
1497 //      if ( gr_screen.bits_per_pixel!=8 )      return;
1498 //
1499 //      for (i=0; i<768; i++ )  {
1500 //              new_pal[i] = ubyte(Gr_gamma_lookup[gr_palette[i]]);
1501 //      }
1502 //      grx_change_palette( new_pal );
1503
1504         gr_screen.signature = Gr_signature++;
1505 }
1506
1507 void gr_soft_init()
1508 {
1509 //      int i;
1510         HWND hwnd = (HWND)os_get_window();
1511         
1512         // software mode only supports 640x480
1513         Assert(gr_screen.res == GR_640);
1514         if(gr_screen.res != GR_640){
1515                 gr_screen.res = GR_640;
1516                 gr_screen.max_w = 640;
1517                 gr_screen.max_h = 480;
1518         }
1519
1520         // Prepare the window to go full screen
1521         if ( hwnd )     {
1522                 DWORD style, exstyle;
1523                 RECT            client_rect;
1524
1525                 exstyle = 0;
1526                 style = WS_CAPTION | WS_SYSMENU;
1527                 
1528                 //      Create Game Window
1529                 client_rect.left = client_rect.top = 0;
1530                 client_rect.right = gr_screen.max_w;
1531                 client_rect.bottom = gr_screen.max_h;
1532                 AdjustWindowRect(&client_rect,style,FALSE);
1533
1534                 RECT work_rect;
1535                 SystemParametersInfo( SPI_GETWORKAREA, 0, &work_rect, 0 );
1536                 int x = work_rect.left + (( work_rect.right - work_rect.left )-(client_rect.right - client_rect.left))/2;
1537                 int y = work_rect.top;
1538                 if ( x < work_rect.left ) {
1539                         x = work_rect.left;
1540                 }
1541                 int WinX = x;
1542                 int WinY = y;
1543                 int WinW = client_rect.right - client_rect.left;
1544                 int WinH = client_rect.bottom - client_rect.top;
1545
1546                 ShowWindow(hwnd, SW_SHOWNORMAL );
1547                 SetWindowLong( hwnd, GWL_STYLE, style );
1548                 SetWindowLong( hwnd, GWL_EXSTYLE, exstyle );
1549                 SetWindowPos( hwnd, HWND_NOTOPMOST, WinX, WinY, WinW, WinH, SWP_SHOWWINDOW );
1550                 SetActiveWindow(hwnd);
1551                 SetForegroundWindow(hwnd);
1552         }
1553
1554         Palette_flashed = 0;
1555         Palette_flashed_last_frame = 0;
1556
1557         gr_screen.bits_per_pixel = 8;
1558         gr_screen.bytes_per_pixel = 1;
1559
1560         gr_buffer_create( gr_screen.max_w, gr_screen.max_h, gr_screen.bits_per_pixel );
1561
1562         gr_screen.offscreen_buffer_base = lpDibBits;
1563
1564         gr_screen.rowsize = DibInfo.Header.biWidth*((gr_screen.bits_per_pixel+7)/8);
1565         Assert( DibInfo.Header.biWidth == gr_screen.max_w );
1566
1567         if (DibInfo.Header.biHeight > 0)        {
1568                 // top down 
1569                 gr_screen.offscreen_buffer = (void *)((uint)gr_screen.offscreen_buffer_base + (gr_screen.max_h - 1) * gr_screen.rowsize);
1570                 gr_screen.rowsize *= -1;
1571         } else {
1572                 // top up
1573                 gr_screen.offscreen_buffer = gr_screen.offscreen_buffer_base;
1574         }
1575
1576         grx_init_alphacolors();
1577
1578         gr_screen.gf_flip = grx_flip;
1579         gr_screen.gf_flip_window = grx_flip_window;
1580         gr_screen.gf_set_clip = grx_set_clip;
1581         gr_screen.gf_reset_clip = grx_reset_clip;
1582         gr_screen.gf_set_font = grx_set_font;
1583         gr_screen.gf_set_color = grx_set_color;
1584         gr_screen.gf_set_bitmap = grx_set_bitmap;
1585         gr_screen.gf_create_shader = grx_create_shader;
1586         gr_screen.gf_set_shader = grx_set_shader;
1587         gr_screen.gf_clear = grx_clear;
1588         // gr_screen.gf_bitmap = grx_bitmap;
1589         // ]gr_screen.gf_bitmap_ex = grx_bitmap_ex;
1590
1591         gr_screen.gf_aabitmap = grx_aabitmap;
1592         gr_screen.gf_aabitmap_ex = grx_aabitmap_ex;
1593
1594         gr_screen.gf_rect = grx_rect;
1595         gr_screen.gf_shade = gr8_shade;
1596         gr_screen.gf_string = gr8_string;
1597         gr_screen.gf_circle = gr8_circle;
1598
1599         gr_screen.gf_line = gr8_line;
1600         gr_screen.gf_aaline = gr8_aaline;
1601         gr_screen.gf_pixel = gr8_pixel;
1602         gr_screen.gf_scaler = gr8_scaler;
1603         gr_screen.gf_aascaler = gr8_aascaler;
1604         gr_screen.gf_tmapper = grx_tmapper;
1605
1606         gr_screen.gf_gradient = gr8_gradient;
1607
1608         gr_screen.gf_set_palette = grx_set_palette;
1609         gr_screen.gf_get_color = grx_get_color;
1610         gr_screen.gf_init_color = grx_init_color;
1611         gr_screen.gf_init_alphacolor = grx_init_alphacolor;
1612         gr_screen.gf_set_color_fast = grx_set_color_fast;
1613         gr_screen.gf_print_screen = grx_print_screen;
1614         gr_screen.gf_start_frame = grx_start_frame;
1615         gr_screen.gf_stop_frame = grx_stop_frame;
1616
1617         gr_screen.gf_fade_in = grx_fade_in;
1618         gr_screen.gf_fade_out = grx_fade_out;
1619         gr_screen.gf_flash = grx_flash;
1620
1621
1622         // Retrieves the zbuffer mode.
1623         gr_screen.gf_zbuffer_get = gr8_zbuffer_get;
1624         gr_screen.gf_zbuffer_set = gr8_zbuffer_set;
1625         gr_screen.gf_zbuffer_clear = gr8_zbuffer_clear;
1626
1627         gr_screen.gf_save_screen = gr8_save_screen;
1628         gr_screen.gf_restore_screen = gr8_restore_screen;
1629         gr_screen.gf_free_screen = gr8_free_screen;
1630
1631         // Screen dumping stuff
1632         gr_screen.gf_dump_frame_start = gr8_dump_frame_start;
1633         gr_screen.gf_dump_frame_stop = gr8_dump_frame_stop;
1634         gr_screen.gf_dump_frame = gr8_dump_frame;
1635
1636         // Gamma stuff
1637         gr_screen.gf_set_gamma = gr8_set_gamma;
1638
1639         // Lock/unlock stuff
1640         gr_screen.gf_lock = gr_soft_lock;
1641         gr_screen.gf_unlock = gr_soft_unlock;
1642
1643         // region
1644         gr_screen.gf_get_region = grx_get_region;
1645
1646         // fog stuff
1647         gr_screen.gf_fog_set = gr_soft_fog_set; 
1648
1649         // pixel get
1650         gr_screen.gf_get_pixel = gr_soft_get_pixel;
1651
1652         // poly culling
1653         gr_screen.gf_set_cull = gr_soft_set_cull;
1654
1655         // cross fade
1656         gr_screen.gf_cross_fade = gr_soft_cross_fade;
1657
1658         // filter
1659         gr_screen.gf_filter_set = gr_soft_filter_set;
1660
1661         // tcache set
1662         gr_screen.gf_tcache_set = gr_soft_tcache_set;
1663
1664         // set clear color
1665         gr_screen.gf_set_clear_color = gr_soft_set_clear_color;
1666
1667         gr_reset_clip();
1668         gr_clear();
1669         gr_flip();
1670 }
1671
1672 void gr_soft_force_windowed()
1673 {
1674 }
1675
1676 void gr_soft_cleanup()
1677 {
1678         if (Gr_soft_inited) {
1679                 gr_buffer_release();
1680                 Gr_soft_inited = 0;
1681         }
1682 }
1683
1684 void grx_change_palette( ubyte * new_pal )
1685 {
1686         if ( hPalette ) {
1687                 if (hDibDC)
1688                         SelectPalette( hDibDC, hOldPalette, FALSE );
1689                 if (!DeleteObject(hPalette))
1690                         Int3();
1691                 hPalette = NULL;
1692         }
1693
1694         hPalette = gr_create_palette_256(new_pal);      // All 256 mapped one-to-one, but BLT's are slow.
1695
1696         if ( hDibDC )   {
1697                 int i; 
1698                 for (i=0; i<256; i++ )  {
1699                         DibInfo.Colors.aColors[i].rgbRed = new_pal[i*3+0];
1700                         DibInfo.Colors.aColors[i].rgbGreen = new_pal[i*3+1];
1701                         DibInfo.Colors.aColors[i].rgbBlue = new_pal[i*3+2];
1702                         DibInfo.Colors.aColors[i].rgbReserved = 0;
1703                 }
1704
1705                 hOldPalette = SelectPalette( hDibDC, hPalette, FALSE );
1706                 SetDIBColorTable( hDibDC, 0, 256, DibInfo.Colors.aColors );
1707         }
1708 }
1709
1710 void grx_flash( int r, int g, int b )
1711 {
1712         int t,i;
1713         ubyte new_pal[768];
1714
1715         if ( (r==0) && (g==0) && (b==0) )       {
1716                 return;
1717         }
1718
1719         Palette_flashed++;
1720
1721         for (i=0; i<256; i++ )  {
1722                 t = gr_palette[i*3+0] + r;
1723                 if ( t < 0 ) t = 0; else if (t>255) t = 255;
1724                 new_pal[i*3+0] = (ubyte)t;
1725
1726                 t = gr_palette[i*3+1] + g;
1727                 if ( t < 0 ) t = 0; else if (t>255) t = 255;
1728                 new_pal[i*3+1] = (ubyte)t;
1729
1730                 t = gr_palette[i*3+2] + b;
1731                 if ( t < 0 ) t = 0; else if (t>255) t = 255;
1732                 new_pal[i*3+2] = (ubyte)t;
1733         }
1734
1735         grx_change_palette( new_pal );
1736 }
1737
1738
1739 static int gr_palette_faded_out = 0;
1740
1741 #define FADE_TIME (F1_0/4)              // How long to fade out
1742
1743 void grx_fade_out(int instantaneous)    
1744 {
1745 #ifndef HARDWARE_ONLY
1746         int i;
1747         ubyte new_pal[768];
1748
1749         if (!gr_palette_faded_out) {
1750
1751                 if ( !instantaneous )   {
1752         
1753                         int count = 0;
1754                         fix start_time, stop_time, t1;
1755
1756                         start_time = timer_get_fixed_seconds();
1757                         t1 = 0;
1758
1759                         do {
1760                                 for (i=0; i<768; i++ )  {               
1761                                         int c = (gr_palette[i]*(FADE_TIME-t1))/FADE_TIME;
1762                                         if (c < 0 )
1763                                                 c = 0;
1764                                         else if ( c > 255 )
1765                                                 c = 255;
1766                         
1767                                         new_pal[i] = (ubyte)c;
1768                                 }
1769                                 grx_change_palette( new_pal );
1770                                 gr_flip();
1771                                 count++;
1772
1773                                 t1 = timer_get_fixed_seconds() - start_time;
1774
1775                         } while ( (t1 < FADE_TIME) && (t1>=0) );                // Loop as long as time not up and timer hasn't rolled
1776
1777                         stop_time = timer_get_fixed_seconds();
1778
1779                         mprintf(( "Took %d frames (and %.1f secs) to fade out\n", count, f2fl(stop_time-start_time) ));
1780                 
1781                 }
1782                 gr_palette_faded_out = 1;
1783         }
1784
1785         gr_reset_clip();
1786         gr_clear();
1787         gr_flip();
1788         memset( new_pal, 0, 768 );
1789         grx_change_palette( new_pal );
1790 #else
1791         Int3();
1792 #endif
1793 }
1794
1795
1796 void grx_fade_in(int instantaneous)     
1797 {
1798 #ifndef HARDWARE_ONLY
1799         int i;
1800         ubyte new_pal[768];
1801
1802         if (gr_palette_faded_out)       {
1803
1804                 if ( !instantaneous )   {
1805                         int count = 0;
1806                         fix start_time, stop_time, t1;
1807
1808                         start_time = timer_get_fixed_seconds();
1809                         t1 = 0;
1810
1811                         do {
1812                                 for (i=0; i<768; i++ )  {               
1813                                         int c = (gr_palette[i]*t1)/FADE_TIME;
1814                                         if (c < 0 )
1815                                                 c = 0;
1816                                         else if ( c > 255 )
1817                                                 c = 255;
1818                         
1819                                         new_pal[i] = (ubyte)c;
1820                                 }
1821                                 grx_change_palette( new_pal );
1822                                 gr_flip();
1823                                 count++;
1824
1825                                 t1 = timer_get_fixed_seconds() - start_time;
1826
1827                         } while ( (t1 < FADE_TIME) && (t1>=0) );                // Loop as long as time not up and timer hasn't rolled
1828
1829                         stop_time = timer_get_fixed_seconds();
1830
1831                         mprintf(( "Took %d frames (and %.1f secs) to fade in\n", count, f2fl(stop_time-start_time) ));
1832                 }
1833                 gr_palette_faded_out = 0;
1834         }
1835
1836         memcpy( new_pal, gr_palette, 768 );
1837         grx_change_palette( new_pal );
1838 #else 
1839         Int3();
1840 #endif
1841 }
1842
1843