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