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