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