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