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