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