]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/2d.cpp
initial graphics system update
[taylor/freespace2.git] / src / graphics / 2d.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/2d.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Main file for 2d primitives.
16  *
17  * $Log$
18  * Revision 1.12  2004/07/04 11:31:43  taylor
19  * amd64 support, compiler warning fixes, don't use software rendering
20  *
21  * Revision 1.11  2002/08/31 01:39:13  theoddone33
22  * Speed up the renderer a tad
23  *
24  * Revision 1.10  2002/06/17 06:33:09  relnev
25  * ryan's struct patch for gcc 2.95
26  *
27  * Revision 1.9  2002/06/09 04:41:17  relnev
28  * added copyright header
29  *
30  * Revision 1.8  2002/06/05 04:03:32  relnev
31  * finished cfilesystem.
32  *
33  * removed some old code.
34  *
35  * fixed mouse save off-by-one.
36  *
37  * sound cleanups.
38  *
39  * Revision 1.7  2002/05/30 21:44:48  relnev
40  * implemented some missing texture stuff.
41  *
42  * enable bitmap polys for opengl.
43  *
44  * work around greenness in bitmaps.
45  *
46  * Revision 1.6  2002/05/28 21:36:10  relnev
47  * some more timer junk.
48  *
49  * tried to fix software mode.
50  *
51  * Revision 1.5  2002/05/28 04:18:08  theoddone33
52  * Fix some stuff and add -DFS2_DEMO
53  *
54  * Revision 1.4  2002/05/27 22:43:02  theoddone33
55  * Fix more glide symbols
56  *
57  * Revision 1.3  2002/05/27 22:39:21  theoddone33
58  * Remove glide symbols
59  *
60  * Revision 1.2  2002/05/07 03:16:45  theoddone33
61  * The Great Newline Fix
62  *
63  * Revision 1.1.1.1  2002/05/03 03:28:09  root
64  * Initial import.
65  *
66  * 
67  * 25    8/20/99 2:09p Dave
68  * PXO banner cycling.
69  * 
70  * 24    8/16/99 9:45a Jefff
71  * changes to cursor management to allow a 2nd temporary cursor
72  * 
73  * 23    7/27/99 3:52p Dave
74  * Make star drawing a bit more robust to help lame D3D cards.
75  * 
76  * 22    7/18/99 12:32p Dave
77  * Randomly oriented shockwaves.
78  * 
79  * 21    7/15/99 3:07p Dave
80  * 32 bit detection support. Mouse coord commandline.
81  * 
82  * 20    7/14/99 9:42a Dave
83  * Put in clear_color debug function. Put in base for 3dnow stuff / P3
84  * stuff
85  * 
86  * 19    7/13/99 1:15p Dave
87  * 32 bit support. Whee!
88  * 
89  * 18    7/12/99 11:42a Jefff
90  * Made rectangle drawing smarter in D3D. Made plines draw properly on Ati
91  * Rage Pro.
92  * 
93  * 17    7/09/99 9:51a Dave
94  * Added thick polyline code.
95  * 
96  * 16    7/02/99 3:05p Anoop
97  * Oops. Fixed g3_draw_2d_poly() so that it properly handles poly bitmap
98  * and LFB bitmap calls.
99  * 
100  * 15    6/29/99 10:35a Dave
101  * Interface polygon bitmaps! Whee!
102  * 
103  * 14    4/09/99 2:21p Dave
104  * Multiplayer beta stuff. CD checking.
105  * 
106  * 13    2/03/99 11:44a Dave
107  * Fixed d3d transparent textures.
108  * 
109  * 12    1/29/99 12:47a Dave
110  * Put in sounds for beam weapon. A bunch of interface screens (tech
111  * database stuff).
112  * 
113  * 11    1/15/99 11:29a Neilk
114  * Fixed D3D screen/texture pixel formatting problem. 
115  * 
116  * 10    1/08/99 2:08p Dave
117  * Fixed software rendering for pofview. Super early support for AWACS and
118  * beam weapons.
119  * 
120  * 9     1/06/99 2:24p Dave
121  * Stubs and release build fixes.
122  * 
123  * 8     12/18/98 1:49a Dave
124  * Fixed Fred initialization problem resulting from hi-res mode changes.
125  * 
126  * 7     12/18/98 1:13a Dave
127  * Rough 1024x768 support for Direct3D. Proper detection and usage through
128  * the launcher.
129  * 
130  * 6     12/01/98 10:32a Johnson
131  * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
132  * starfield problem.
133  * 
134  * 5     11/30/98 5:31p Dave
135  * Fixed up Fred support for software mode.
136  * 
137  * 4     11/30/98 1:07p Dave
138  * 16 bit conversion, first run.
139  * 
140  * 3     11/11/98 5:37p Dave
141  * Checkin for multiplayer testing.
142  * 
143  * 2     10/07/98 10:52a Dave
144  * Initial checkin.
145  * 
146  * 1     10/07/98 10:48a Dave
147  * 
148  * 122   6/13/98 3:18p Hoffoss
149  * NOX()ed out a bunch of strings that shouldn't be translated.
150  * 
151  * 121   5/23/98 11:26a Hoffoss
152  * Fixed bug where optimized code used EDX and my code trashed it.
153  * 
154  * 120   5/22/98 11:09p John
155  * put in code to hopefull not crash cyrix cpus
156  * 
157  * 119   5/20/98 9:45p John
158  * added code so the places in code that change half the palette don't
159  * have to clear the screen.
160  * 
161  * 118   5/20/98 12:59p Hoffoss
162  * Changed temporary crossfade code to just pop the image again.
163  * 
164  * 117   5/16/98 1:18p John
165  * Made softtware DirectDraw reset palette after Alt+TAB.
166  * 
167  * 116   5/14/98 5:42p John
168  * Revamped the whole window position/mouse code for the graphics windows.
169  * 
170  * 115   5/08/98 10:49a John
171  * Made 'gr d' go into direct3d mode.
172  * 
173  * 114   5/06/98 11:21p John
174  * Fixed a bitmap bug with Direct3D.  Started adding new caching code into
175  * D3D.
176  * 
177  * 113   4/21/98 9:28a John
178  * Added stub for cross-fade.
179  * 
180  * 112   4/10/98 5:20p John
181  * Changed RGB in lighting structure to be ubytes.  Removed old
182  * not-necessary 24 bpp software stuff.
183  * 
184  * 111   4/06/98 12:55p John
185  * Upped the gamma for Fred.
186  * 
187  * 110   3/25/98 8:07p John
188  * Restructured software rendering into two modules; One for windowed
189  * debug mode and one for DirectX fullscreen.   
190  * 
191  * 109   3/24/98 3:58p John
192  * Put in (hopefully) final gamma setting code.
193  * 
194  * 108   3/10/98 4:18p John
195  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
196  * & Glide have popups and print screen.  Took out all >8bpp software
197  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
198  * support Fred.  Made zbuffering key off of functions rather than one
199  * global variable.
200  * 
201  * 107   2/25/98 2:37p John
202  * Made afterburner shake 2x less noticable.  Made 'gr a' leave Glide mode
203  * properly.  Made model_caching never work in hardware mode.
204  * 
205  * 106   2/23/98 2:27p John
206  * Made int3,asserts, etc pass video through.
207  * 
208  * 105   2/20/98 3:13p John
209  * Made popup save code print an error an exit out if 3d accelerated.
210  * 
211  * 104   2/19/98 6:13p John
212  * Made Glide do texturing & zbuffering.
213  * 
214  * 103   1/26/98 5:12p John
215  * Added in code for Pentium Pro specific optimizations. Speed up
216  * zbuffered correct tmapper about 35%.   Speed up non-zbuffered scalers
217  * by about 25%.
218  * 
219  * 102   1/14/98 11:39a Dave
220  * Polished up a bunch of popup support items.
221  * 
222  * 101   1/10/98 1:14p John
223  * Added explanation to debug console commands
224  * 
225  * 100   12/21/97 4:33p John
226  * Made debug console functions a class that registers itself
227  * automatically, so you don't need to add the function to
228  * debugfunctions.cpp.  
229  * 
230  * 99    12/04/97 12:09p John
231  * Made glows use scaler instead of tmapper so they don't rotate.  Had to
232  * add a zbuffered scaler.
233  * 
234  * 98    12/03/97 10:47a John
235  * added functions to save/restore entire screens.
236  * 
237  * 97    12/02/97 3:59p John
238  * Added first rev of thruster glow, along with variable levels of
239  * translucency, which retquired some restructing of palman.
240  * 
241  * 96    11/30/97 12:18p John
242  * added more 24 & 32-bpp primitives
243  * 
244  * 95    11/24/97 11:20a John
245  * added new mode
246  * 
247  * 94    11/14/97 3:54p John
248  * Added triple buffering.
249  * 
250  * 93    11/14/97 12:30p John
251  * Fixed some DirectX bugs.  Moved the 8-16 xlat tables into Graphics
252  * libs.  Made 16-bpp DirectX modes know what bitmap format they're in.
253  * 
254  * 92    10/09/97 5:23p John
255  * Added support for more 16-bpp functions
256  * 
257  * 91    9/20/97 8:16a John
258  * Made .clr files go into the Cache directory. Replaced cfopen(name,NULL)
259  * to delete a file with cf_delete.
260  * 
261  * 90    9/09/97 11:01a Sandeep
262  * fixed warning level 4 bugs
263  * 
264  * 89    9/07/97 10:01p Lawrance
265  * add in support for animating mouse pointer
266  * 
267  * 88    9/03/97 4:32p John
268  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
269  * to bm_load functions not needed.   Made bmpman keep track of palettes
270  * for bitmaps not mapped into game palettes.
271  * 
272  * 87    8/20/97 4:19p John
273  * added delay to hopefully fix mike's problems when getting int3's in
274  * fullscreen.
275  * 
276  * 86    7/16/97 3:07p John
277  * 
278  * 85    6/18/97 12:07p John
279  * fixed some color bugs
280  * 
281  * 84    6/17/97 7:04p John
282  * added d3d support for gradients.
283  * fixed some color bugs by adding screen signatures instead of watching
284  * flags and palette changes.
285  * 
286  * 83    6/17/97 12:03p John
287  * Moved color/alphacolor functions into their own module.  Made all color
288  * functions be part of the low-level graphics drivers, not just the
289  * grsoft.
290  * 
291  * 82    6/12/97 5:04p John
292  * Initial rev of Glide support
293  * 
294  * 81    6/11/97 5:49p John
295  * Changed palette code to only recalculate alphacolors when needed, not
296  * when palette changes.
297  * 
298  * 80    6/11/97 1:12p John
299  * Started fixing all the text colors in the game.
300  * 
301  * 79    6/06/97 5:03p John
302  * fixed bug withalpha colors failing after gr_init
303  * 
304  * 78    6/06/97 4:53p John
305  * made gr_init not bash current color
306  * 
307  * 77    6/05/97 4:53p John
308  * First rev of new antialiased font stuff.
309  * 
310  * 76    5/20/97 10:36a John
311  * Fixed problem with user bitmaps and direct3d caching.
312  * 
313  * 75    5/16/97 9:11a John
314  * fixed bug that made Ctrl+Break in fullscreen hang
315  * 
316  * 74    5/14/97 4:38p John
317  * Fixed print_screen bug.
318  * 
319  * 73    5/14/97 2:10p John
320  * added rudimentary support for windowed direct3d.
321  * 
322  * 72    5/14/97 10:53a John
323  * fixed some discrepencies between d3d and software palette setting.
324  * 
325  * 71    5/13/97 4:39p John
326  * Added console function to set graphics modes.
327  * 
328  * 70    5/13/97 12:39p John
329  * Got fullscreen mode working.
330  * 
331  * 69    5/12/97 12:27p John
332  * Restructured Graphics Library to add support for multiple renderers.
333  * 
334  * 68    5/07/97 2:59p John
335  * Initial rev of D3D texturing.
336  * 
337  * 67    5/01/97 3:32p John
338  * oops... forced 2d to always be in 8bpp,
339  * 
340  * 66    5/01/97 3:23p John
341  * first hooks for some direct 3d setup stuff.
342  * 
343  * 65    4/28/97 5:33p John
344  * fixed a newly introduced bug with fullscreen toggle.
345  * 
346  * 64    4/28/97 4:46p John
347  * 
348  * 63    4/22/97 12:20p John
349  * fixed more resource leaks
350  * 
351  * 62    4/22/97 10:33a John
352  * fixed the 2d resource leaks that Alan found.
353  * 
354  * 61    3/31/97 9:45a Allender
355  * start of new font stuff
356  * 
357  * 60    3/26/97 10:52a Lawrance
358  * mouse always on in menus, disappears in gameplay after 1 second
359  * 
360  * 59    3/14/97 3:55p John
361  * Made tiled tmapper not always be zbuffered.
362  * 
363  * 58    3/13/97 9:09a Allender
364  * variable to allow trashing of the palette.  kind of temporary code
365  * right now...checking needed for undefined references
366  * 
367  * 57    3/12/97 2:51p John
368  * Added some test code for tmapper.  
369  * 
370  * 56    3/12/97 9:25a John
371  * fixed a bug with zbuffering.  Reenabled it by default.
372  * 
373  * 55    3/11/97 5:13p John
374  * made top up bitmaps work.
375  * 
376  * 54    2/26/97 11:59a Allender
377  * comment out warning about display settings not being optimal
378  * 
379  * 53    1/09/97 2:16p John
380  * took out the "Bing!" message
381  * 
382  * 52    1/09/97 11:35a John
383  * Added some 2d functions to get/put screen images.
384  * 
385  * 51    1/07/97 2:01p John
386  * Fairly fast zbuffering for object sorting.
387  * 
388  * 50    1/06/97 2:44p John
389  * Added in slow (but correct) zbuffering
390  * 
391  * 49    12/11/96 12:41p John
392  * Added new code to draw 3d laser using 2d ellipses.
393  * 
394  * 48    12/03/96 5:42p John
395  * took out debug code.
396  * 
397  * 47    12/03/96 5:42p John
398  * made gr_bitmap clip properly.
399  * 
400  * 46    12/03/96 5:06p John
401  * Added code to draw our own cursor.
402  * 
403  * 45    11/26/96 6:50p John
404  * Added some more hicolor primitives.  Made windowed mode run as current
405  * bpp, if bpp is 8,16,or 32.
406  * 
407  * 44    11/21/96 11:23a John
408  * fixed bug with previous.
409  * 
410  * 43    11/21/96 11:21a John
411  * Made gr_get_string_size handle multi line text.
412  * Took out gr_get_multiline_string_size
413  * 
414  * 42    11/21/96 11:06a John
415  * fixed warnings.
416  * 
417  * 41    11/20/96 10:01a Hoffoss
418  * A few minor improvements.
419  * 
420  * 40    11/19/96 2:47p Allender
421  * add support for xparent bitmaps in 32bpp
422  * 
423  * 39    11/18/96 4:46p Allender
424  * changed warning message about bit depth to appear when requested
425  * doesn't equal actual
426  * 
427  * 38    11/18/96 4:35p Allender
428  * new 16bpp gradient functions
429  * 
430  * 37    11/18/96 3:09p John
431  * made gr_clear always clear to black.
432  * 
433  * 36    11/18/96 1:48p Allender
434  * added 16 bit version of shader
435  * 
436  * 35    11/18/96 12:36p John
437  * Added code to dump screen to a PCX file.
438  * 
439  * 34    11/18/96 11:40a John
440  * Added faster gr_set_color method.
441  * 
442  * 33    11/15/96 11:26a John
443  * Added code to clip text to clipping region.
444  * 
445  * 32    11/15/96 11:26a Allender
446  * fixed up 16 bbp version of gr_bitmap
447  * 
448  * 31    11/14/96 9:11a John
449  * Fixed bug that didn't offset the gr_string text by the current clip
450  * region's offset.
451  * 
452  * 30    11/13/96 6:47p John
453  * Added gr_flip function.
454  * 
455  * 29    11/13/96 10:10a John
456  * Increases MAX_WIDTH & HEIGHT for Jasen's massive 1600x1200 display.
457  * 
458  * 28    11/07/96 6:19p John
459  * Added a bunch of 16bpp primitives so the game sort of runs in 16bpp
460  * mode.
461  * 
462  * 27    10/30/96 10:36a Lawrance
463  * added gr_diamond function
464  * 
465  * 26    10/26/96 1:40p John
466  * Added some now primitives to the 2d library and
467  * cleaned up some old ones.
468  *
469  * $NoKeywords: $
470  */
471
472 #ifndef PLAT_UNIX
473 #include <windows.h>
474 #include <windowsx.h>
475 #endif
476
477 #include "osapi.h"
478 #include "2d.h"
479 #include "3d.h"
480 #include "bmpman.h"
481 #include "palman.h"
482 #include "font.h"
483 #include "grinternal.h"
484 #include "systemvars.h"
485 #include "cmdline.h"
486
487 // 3dnow stuff
488 // #include "amd3d.h"
489
490 // Includes for different rendering systems
491 #include "grsoft.h"
492 #include "grd3d.h"
493 #ifndef PLAT_UNIX
494 #include "grglide.h"
495 #endif
496 #include "gropengl.h"
497 #include "grdirectdraw.h"
498
499 screen gr_screen;
500
501 color_gun Gr_red, Gr_green, Gr_blue, Gr_alpha;
502 color_gun Gr_t_red, Gr_t_green, Gr_t_blue, Gr_t_alpha;
503 color_gun Gr_ta_red, Gr_ta_green, Gr_ta_blue, Gr_ta_alpha;
504 color_gun *Gr_current_red, *Gr_current_green, *Gr_current_blue, *Gr_current_alpha;
505
506
507 ubyte Gr_original_palette[768];         // The palette 
508 ubyte Gr_current_palette[768];
509 char Gr_current_palette_name[128] = NOX("none");
510
511 // cursor stuff
512 int Gr_cursor = -1;
513 int Web_cursor_bitmap = -1;
514
515 int Gr_inited = 0;
516
517 // cpu types
518 int Gr_cpu = 0; 
519 int Gr_amd3d = 0;
520 int Gr_katmai = 0;
521 int Gr_mmx = 0;
522
523 uint Gr_signature = 0;
524
525 float Gr_gamma = 1.8f;
526 int Gr_gamma_int = 180;
527 int Gr_gamma_lookup[256];
528
529 void gr_close()
530 {
531         if ( !Gr_inited )       return;
532
533         palette_flush();
534
535         switch( gr_screen.mode )        {
536 #ifndef PLAT_UNIX
537         case GR_SOFTWARE:               
538                 gr_soft_cleanup();
539                 break;  
540         case GR_DIRECTDRAW:
541                 Int3();
542                 gr_directdraw_cleanup();
543                 break;
544         case GR_DIRECT3D:               
545                 gr_d3d_cleanup();
546                 break;
547         case GR_GLIDE:
548                 gr_glide_cleanup();
549                 break;
550 #endif          
551         case GR_OPENGL:
552                 gr_opengl_cleanup();
553                 break;
554         default:
555                 Int3();         // Invalid graphics mode
556         }
557
558         gr_font_close();
559
560         Gr_inited = 0;
561 }
562
563 //XSTR:OFF
564 DCF(gr,"Changes graphics mode")
565 {
566 #ifndef HARDWARE_ONLY
567         int mode = gr_screen.mode;
568
569         if ( Dc_command )       {
570                 dc_get_arg(ARG_STRING);
571                 
572                 if ( !strcmp( Dc_arg, "a"))     {
573                         Int3();
574                         mode = GR_SOFTWARE;
575                 } else if ( !strcmp( Dc_arg, "b"))      {
576                         Int3();
577                         mode = GR_DIRECTDRAW;
578                 } else if ( !strcmp( Dc_arg, "d"))      {
579                         mode = GR_DIRECT3D;
580                 } else if ( !strcmp( Dc_arg, "g"))      {
581 #ifndef PLAT_UNIX
582                         mode = GR_GLIDE;
583 #endif
584                 } else if ( !strcmp( Dc_arg, "o"))      {
585                         mode = GR_OPENGL;
586                 } else {
587                         // print usage, not stats
588                         Dc_help = 1;
589                 }
590
591                 /*
592                 if ( mode != gr_screen.mode )   {
593                         dc_printf( "Setting new video mode...\n" );
594                         int errcode = gr_init( gr_screen.max_w, gr_screen.max_h, mode );
595                         if (errcode)    {
596                                 dc_printf( "Error %d.  Graphics unchanged.\n", errcode );
597                         }
598                 }
599                 */
600         }
601
602         if ( Dc_help )  {
603                 dc_printf( "Usage: gr mode\n" );
604                 dc_printf( "The options can be:\n" );
605                 dc_printf( "Macros:  A=software win32 window (obsolete)\n" );
606                 dc_printf( "         B=software directdraw fullscreen (obsolete)\n" );
607                 dc_printf( "         D=Direct3d\n" );
608                 dc_printf( "         G=Glide\n" );
609                 dc_printf( "         O=OpenGl (obsolete)\n" );
610                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
611         }
612
613         if ( Dc_status )        {
614                 switch( gr_screen.mode )        {
615                 case GR_SOFTWARE:
616                         Int3();
617                         dc_printf( "Win32 software windowed\n" );
618                         break;
619                 case GR_DIRECTDRAW:
620                         Int3();
621                         dc_printf( "DirectDraw software windowed\n" );
622                         break;
623                 case GR_DIRECT3D:
624                         dc_printf( "Direct3D\n" );
625                         break;
626                 case GR_GLIDE:
627 #ifndef PLAT_UNIX
628                         dc_printf( "3Dfx Glide\n" );
629 #endif
630                         break;
631                 case GR_OPENGL:
632                         dc_printf( "OpenGl\n" );
633                         break;
634                 default:
635                         Int3();         // Invalid graphics mode
636                 }
637         }
638 #endif
639 }
640 //XSTR:ON
641
642 // set screen clear color
643 DCF(clear_color, "set clear color r, g, b")
644 {
645         int r, g, b;
646
647         dc_get_arg(ARG_INT);
648         r = Dc_arg_int;
649         dc_get_arg(ARG_INT);
650         g = Dc_arg_int;
651         dc_get_arg(ARG_INT);
652         b = Dc_arg_int;
653
654         // set the color
655         gr_set_clear_color(r, g, b);
656 }
657
658 void gr_set_palette_internal( const char *name, ubyte * palette, int restrict_font_to_128 )
659 {
660         if ( palette == NULL )  {
661                 // Create a default palette
662                 int r,g,b,i;
663                 i = 0;
664                                 
665                 for (r=0; r<6; r++ )    
666                         for (g=0; g<6; g++ )    
667                                 for (b=0; b<6; b++ )            {
668                                         Gr_current_palette[i*3+0] = (unsigned char)(r*51);
669                                         Gr_current_palette[i*3+1] = (unsigned char)(g*51);
670                                         Gr_current_palette[i*3+2] = (unsigned char)(b*51);
671                                         i++;
672                                 }
673                 for ( i=216;i<256; i++ )        {
674                         Gr_current_palette[i*3+0] = (unsigned char)((i-216)*6);
675                         Gr_current_palette[i*3+1] = (unsigned char)((i-216)*6);
676                         Gr_current_palette[i*3+2] = (unsigned char)((i-216)*6);
677                 }
678                 memmove( Gr_original_palette, Gr_current_palette, 768 );
679         } else {
680                 memmove( Gr_original_palette, palette, 768 );
681                 memmove( Gr_current_palette, palette, 768 );
682         }
683
684 //      mprintf(("Setting new palette\n" ));
685
686         if ( Gr_inited )        {
687                 if (gr_screen.gf_set_palette)   {
688                         (*gr_screen.gf_set_palette)(Gr_current_palette, restrict_font_to_128 );
689
690                         // Since the palette set code might shuffle the palette,
691                         // reload it into the source palette
692                         if ( palette )
693                                 memmove( palette, Gr_current_palette, 768 );
694                 }
695
696                 // Update Palette Manager tables
697                 memmove( gr_palette, Gr_current_palette, 768 );
698                 palette_update(name, restrict_font_to_128);
699         }
700 }
701
702
703 void gr_set_palette( const char *name, ubyte * palette, int restrict_font_to_128 )
704 {
705         char *p;
706         palette_flush();
707         strcpy( Gr_current_palette_name, name );
708         p = strchr( Gr_current_palette_name, '.' );
709         if ( p ) *p = 0;
710         gr_screen.signature = Gr_signature++;
711         gr_set_palette_internal( name, palette, restrict_font_to_128 );
712 }
713
714
715 //void gr_test();
716
717 #define CPUID _asm _emit 0fh _asm _emit 0a2h
718
719 // -----------------------------------------------------------------------
720 // Returns cpu type.
721 void gr_detect_cpu(int *cpu, int *mmx, int *amd3d, int *katmai )
722 {
723         // Set defaults
724         *cpu = 0;
725         *mmx = 0;
726         *amd3d = 0;
727         *katmai = 0;
728
729 #ifdef PLAT_UNIX
730         STUB_FUNCTION;
731 #else
732         DWORD RegEDX;
733         DWORD RegEAX;
734
735         char cpu_vender[16];
736         memset( cpu_vender, 0, sizeof(cpu_vender) );
737                 
738   _asm {
739
740                 // Check for prescence of 
741                 push    eax
742                 push    ebx
743                 push    ecx
744                 push    edx
745
746                 pushfd                  // get extended flags
747                 pop     eax
748                 mov     ebx, eax                // save current flags
749                 xor     eax, 200000h    // toggle bit 21
750                 push    eax                     // push new flags on stack
751                 popfd                                   // flags updated now in flags
752                 pushfd                  // get extended flags
753                 pop     eax             // store extended flags in eax
754                 xor     eax, ebx        // if bit 21 r/w then eax <> 0
755                 je              no_cpuid                
756
757                 mov     eax, 0          // setup CPUID to return vender id
758       CPUID           // code bytes = 0fh,  0a2h
759                 mov     DWORD PTR cpu_vender[0], ebx
760                 mov     DWORD PTR cpu_vender[4], edx
761                 mov     DWORD PTR cpu_vender[8], ecx
762                 
763       mov eax, 1      // setup CPUID to return features
764
765       CPUID           // code bytes = 0fh,  0a2h
766
767                 mov RegEAX, eax // family, etc returned in eax
768       mov RegEDX, edx   // features returned in edx
769                 jmp     done_checking_cpuid
770
771
772 no_cpuid:
773                 mov RegEAX, 4<<8        // family, etc returned in eax
774       mov RegEDX, 0             // features returned in edx
775
776 done_checking_cpuid:                                                            
777                 pop     edx
778                 pop     ecx
779                 pop     ebx
780                 pop     eax
781
782         }
783         
784
785
786         //RegEAX        .  Bits 11:8 is family
787         *cpu = (RegEAX >>8) & 0xF;
788
789         if ( *cpu < 5 ) {
790                 *cpu = 4;                                                               // processor does not support CPUID
791                 *mmx = 0;
792         }
793
794         //RegEAX        .  Bits 11:8 is family
795         *cpu = (RegEAX >>8) & 0xF;
796
797         // Check for MMX
798         BOOL retval = TRUE;
799    if (RegEDX & 0x800000)               // bit 23 is set for MMX technology
800    {
801
802            __try { _asm emms }          // try executing an MMX instruction "emms"
803
804            __except(EXCEPTION_EXECUTE_HANDLER) { retval = FALSE; }
805
806    } else {
807                 retval = FALSE;
808         }
809         if ( retval )   {
810                 *mmx = 1;                       // processor supports CPUID but does not support MMX technology
811         }
812
813         // Check for Katmai
814    if (RegEDX & (1<<25) )               // bit 25 is set for Katmai technology
815    {
816                 *katmai = 1;
817    }
818
819         // Check for Amd 3dnow
820         /*
821         if ( !SDL_strcasecmp( cpu_vender, NOX("AuthenticAMD")) )        {
822
823                 _asm {
824                         mov eax, 0x80000000      // setup CPUID to return extended number of functions
825
826                         CPUID           // code bytes = 0fh,  0a2h
827
828                         mov RegEAX, eax // highest extended function value
829                 }
830
831                 if ( RegEAX > 0x80000000 )      {
832
833                         _asm {
834                                 mov eax, 0x80000001      // setup CPUID to return extended flags
835
836                                 CPUID           // code bytes = 0fh,  0a2h
837
838                                 mov RegEAX, eax // family, etc returned in eax
839                                 mov RegEDX, edx // flags in edx
840                         }
841
842                         if (RegEDX & 0x80000000)               // bit 31 is set for AMD-3D technology
843                         {
844                                 // try executing some 3Dnow instructions
845                                 __try { 
846
847                                         float x = (float)1.25;            
848                                         float y = (float)1.25;            
849                                         float z;                      
850
851                                         _asm {
852                                                 movd            mm1, x
853                                                 movd            mm2, y                  
854                                                 PFMUL(AMD_M1, AMD_M2);               
855                                                 movd            z, mm1
856                                                 femms
857                                                 emms
858                                         }
859
860                                         int should_be_156 = int(z*100);
861
862                                         if ( should_be_156 == 156 )     {
863                                                 *amd3d = 1;
864                                         }
865
866                                 }          
867
868                                 __except(EXCEPTION_EXECUTE_HANDLER) { }
869                         }
870
871                 }               
872         }
873         */
874 #endif
875 }
876
877 // --------------------------------------------------------------------------
878
879 int gr_init(int res, int mode, int depth, int fred_x, int fred_y)
880 {
881         int first_time = 0;
882         int max_w, max_h;
883
884         gr_detect_cpu(&Gr_cpu, &Gr_mmx, &Gr_amd3d, &Gr_katmai );
885
886         mprintf(( "GR_CPU: Family %d, MMX=%s\n", Gr_cpu, (Gr_mmx?"Yes":"No") ));
887         
888 //      gr_test();
889
890         if ( !Gr_inited )       
891                 atexit(gr_close);
892
893         // If already inited, shutdown the previous graphics
894         if ( Gr_inited )        {
895                 switch( gr_screen.mode )        {
896 #ifndef PLAT_UNIX
897                 case GR_SOFTWARE:                       
898                         gr_soft_cleanup();
899                         break;
900                 case GR_DIRECTDRAW:
901                         Int3();
902                         gr_directdraw_cleanup();
903                         break;
904                 case GR_DIRECT3D:                       
905                         gr_d3d_cleanup();
906                         break;
907                 case GR_GLIDE:
908                         gr_glide_cleanup();
909                         break;
910 #endif                  
911                 case GR_OPENGL:
912                         gr_opengl_cleanup();
913                         break;
914                 default:
915                         Int3();         // Invalid graphics mode
916                 }
917         } else {
918                 first_time = 1;
919         }
920
921 #if defined(HARDWARE_ONLY)
922 #ifndef PLAT_UNIX
923         if(!Fred_running && !Pofview_running && !Nebedit_running && !Is_standalone){
924                 if((mode != GR_GLIDE) && (mode != GR_DIRECT3D) && (mode != GR_OPENGL)){
925                         mprintf(("Forcing glide startup!\n"));
926                         mode = GR_GLIDE;
927                 }       
928         }
929 #endif
930 #endif
931
932         D3D_enabled = 0;
933         Gr_inited = 1;
934
935         max_w = -1;
936         max_h = -1;
937         if(!Fred_running && !Pofview_running){
938                 // set resolution based on the res type
939                 switch(res){
940                 case GR_640:
941                         max_w = 640;
942                         max_h = 480;
943                         break;
944
945                 case GR_1024:
946                         max_w = 1024;
947                         max_h = 768;
948                         break;
949
950                 default :
951                         Int3();
952                 }
953         } else {                
954                 max_w = fred_x;
955                 max_h = fred_y;
956         }
957
958         // Make w a multiple of 8
959         max_w = ( max_w / 8 )*8;
960         if ( max_w < 8 ) max_w = 8;
961         if ( max_h < 8 ) max_h = 8;
962
963         memset( &gr_screen, 0, sizeof(screen) );
964
965         gr_screen.signature = Gr_signature++;
966         gr_screen.mode = mode;
967         gr_screen.res = res;    
968         gr_screen.max_w = max_w;
969         gr_screen.max_h = max_h;
970         gr_screen.use_sections = 1;
971         gr_screen.aspect = 1.0f;                        // Normal PC screen
972         gr_screen.offset_x = 0;
973         gr_screen.offset_y = 0;
974         gr_screen.clip_left = 0;
975         gr_screen.clip_top = 0;
976         gr_screen.clip_right = gr_screen.max_w - 1;
977         gr_screen.clip_bottom = gr_screen.max_h - 1;
978         gr_screen.clip_width = gr_screen.max_w;
979         gr_screen.clip_height = gr_screen.max_h;
980
981         switch( gr_screen.mode )        {
982 #ifndef PLAT_UNIX
983                 case GR_SOFTWARE:
984                         SDL_assert(Fred_running || Pofview_running || Is_standalone || Nebedit_running);
985                         gr_soft_init();
986                         break;
987                 case GR_DIRECTDRAW:
988                         Int3();
989                         gr_directdraw_init();
990                         break;
991                 case GR_DIRECT3D:
992                         // we only care about possible 32 bit stuff here
993                         Cmdline_force_32bit = 0;
994                         if(depth == 32){
995                                 Cmdline_force_32bit = 1;
996                         } 
997
998                         gr_d3d_init();
999
1000                         // bad startup - stupid D3D
1001                         extern int D3D_inited;
1002                         if(!D3D_inited){
1003                                 Gr_inited = 0;
1004                                 return 1;
1005                         }
1006
1007                         break;
1008                 case GR_GLIDE:
1009                         // if we're in high-res. force polygon interface
1010                         if(gr_screen.res == GR_1024){
1011                                 Gr_bitmap_poly = 1;
1012                         }
1013                         gr_glide_init();
1014                         break;
1015 #endif                  
1016                 case GR_OPENGL:
1017                         gr_opengl_init();
1018                         break;
1019                 default:
1020                         Int3();         // Invalid graphics mode
1021         }
1022
1023         memmove( Gr_current_palette, Gr_original_palette, 768 );
1024         gr_set_palette_internal(Gr_current_palette_name, Gr_current_palette,0); 
1025
1026         gr_set_gamma(Gr_gamma);
1027
1028         if ( Gr_cursor == -1 ){
1029                 Gr_cursor = bm_load( "cursor" );
1030         }
1031
1032         // load the web pointer cursor bitmap
1033         if (Web_cursor_bitmap < 0)      {
1034                 int nframes;                                            // used to pass, not really needed (should be 1)
1035                 Web_cursor_bitmap = bm_load_animation("cursorweb", &nframes);
1036                 SDL_assert(Web_cursor_bitmap >= 0);             // if bitmap didnt load, thats not good (this is protected for in release tho)
1037         }
1038
1039         gr_set_color(0,0,0);
1040
1041         gr_set_clear_color(0, 0, 0);
1042
1043         // Call some initialization functions
1044         gr_set_shader(NULL);
1045
1046         return 0;
1047 }
1048
1049 void gr_force_windowed()
1050 {
1051         if ( !Gr_inited ) {
1052                 return;
1053         }
1054
1055         if (gr_screen.gf_force_windowed) {
1056                 (*gr_screen.gf_force_windowed)();
1057         }
1058
1059         if (Os_debugger_running) {
1060                 SDL_Delay(1000);
1061         }
1062 }
1063
1064 void gr_activate(int active)
1065 {
1066         if ( !Gr_inited ) {
1067                 return;
1068         }
1069
1070         if (gr_screen.gf_activate) {
1071                 (*gr_screen.gf_activate)(active);
1072         }
1073 }
1074
1075 // -----------------------------------------------------------------------
1076 // gr_set_cursor_bitmap()
1077 //
1078 // Set the bitmap for the mouse pointer.  This is called by the animating mouse
1079 // pointer code.
1080 //
1081 // The lock parameter just locks basically disables the next call of this function that doesnt
1082 // have an unlock feature.  If adding in more cursor-changing situations, be aware of
1083 // unexpected results. You have been warned.
1084 //
1085 // TODO: investigate memory leak of original Gr_cursor bitmap when this is called
1086 void gr_set_cursor_bitmap(int n, int lock)
1087 {
1088         static int locked = 0;                  
1089         SDL_assert(n >= 0);
1090
1091         if (!locked || (lock == GR_CURSOR_UNLOCK)) {
1092                 Gr_cursor = n;
1093         } else {
1094                 locked = 0;
1095         }
1096
1097         if (lock == GR_CURSOR_LOCK) {
1098                 locked = 1;
1099         }
1100 }
1101
1102 // retrieves the current bitmap
1103 // used in UI_GADGET to save/restore current cursor state
1104 int gr_get_cursor_bitmap()
1105 {
1106         return Gr_cursor;
1107 }
1108
1109
1110 int Gr_bitmap_poly = 0;
1111 DCF(bmap, "")
1112 {
1113         Gr_bitmap_poly = !Gr_bitmap_poly;
1114
1115         if(Gr_bitmap_poly){
1116                 dc_printf("Using poly bitmaps\n");
1117         } else {
1118                 dc_printf("Using LFB bitmaps\n");
1119         }
1120 }
1121
1122 // new bitmap functions
1123 void gr_bitmap(int x, int y)
1124 {
1125         int section_x, section_y;       
1126         int x_line, y_line;
1127         int w, h;
1128
1129         // d3d and glide support texture poly shiz
1130         if((gr_screen.mode == GR_OPENGL) && Gr_bitmap_poly){
1131                 int idx, s_idx;
1132                 // float u_scale, v_scale;
1133                 bitmap_section_info *sections;                  
1134
1135                 // render all sections
1136                 bm_get_info(gr_screen.current_bitmap, &w, &h, NULL, NULL, NULL, &sections);
1137                 y_line = 0;
1138                 section_y = 0;
1139
1140                 if (gr_screen.use_sections) {
1141                         for(idx=0; idx<sections->num_y; idx++){
1142                                 x_line = 0;
1143                                 for(s_idx=0; s_idx<sections->num_x; s_idx++){
1144                                         // get the section as a texture in vram
1145                                         gr_set_bitmap(gr_screen.current_bitmap, gr_screen.current_alphablend_mode, gr_screen.current_bitblt_mode, gr_screen.current_alpha, s_idx, idx);
1146
1147                                         // determine the width and height of this section
1148                                         bm_get_section_size(gr_screen.current_bitmap, s_idx, idx, &section_x, &section_y);
1149
1150                                         // draw as a poly
1151                                         g3_draw_2d_poly_bitmap(x + x_line, y + y_line, section_x, section_y, TMAP_FLAG_BITMAP_SECTION);
1152                                         x_line += section_x;
1153                                 }
1154                                 y_line += section_y;
1155                         }
1156                 } else {
1157                         gr_set_bitmap(gr_screen.current_bitmap, gr_screen.current_alphablend_mode,
1158                                         gr_screen.current_bitblt_mode, gr_screen.current_alpha);
1159                         g3_draw_2d_poly_bitmap(x, y, w, h, TMAP_FLAG_BITMAP_INTERFACE);
1160
1161                 }
1162
1163                 // done. whee!
1164                 return;
1165         }                       
1166
1167         // old school bitmaps
1168         switch(gr_screen.mode){
1169 #ifndef PLAT_UNIX
1170         case GR_SOFTWARE:
1171         case GR_DIRECTDRAW:
1172                 grx_bitmap(x, y);
1173                 break;
1174
1175         case GR_DIRECT3D:
1176                 gr_d3d_bitmap(x, y);
1177                 break;
1178         
1179         case GR_GLIDE:          
1180                 gr_glide_bitmap(x, y);          
1181                 break;
1182 #endif
1183         /* don't want opengl bitmap to be called -- slow! */
1184         //case GR_OPENGL:
1185                 //gr_opengl_bitmap(x, y);
1186                 //break;
1187         default:
1188                 Int3();
1189         }
1190 }
1191
1192 void gr_bitmap_ex(int x, int y, int w, int h, int sx, int sy)
1193 {
1194         switch(gr_screen.mode){
1195 #ifndef PLAT_UNIX
1196         case GR_SOFTWARE:
1197         case GR_DIRECTDRAW:
1198                 grx_bitmap_ex(x, y, w, h, sx, sy);
1199                 break;
1200
1201         case GR_DIRECT3D:
1202                 gr_d3d_bitmap_ex(x, y, w, h, sx, sy);
1203                 break;
1204
1205         case GR_GLIDE:
1206                 gr_glide_bitmap_ex(x, y, w, h, sx, sy);
1207                 break;
1208 #endif
1209         /* slow! */
1210         //case GR_OPENGL:
1211         //      gr_opengl_bitmap_ex(x, y, w, h, sx, sy);
1212         //      break;
1213         default:
1214                 Int3();
1215                 break;
1216         }
1217 }
1218
1219 // given endpoints, and thickness, calculate coords of the endpoint
1220 void gr_pline_helper(vector *out, vector *in1, vector *in2, int thickness)
1221 {
1222         vector slope;   
1223
1224         // slope of the line    
1225         if(vm_vec_same(in1, in2)){
1226                 slope = vmd_zero_vector;
1227         } else {
1228                 vm_vec_sub(&slope, in2, in1);
1229                 float temp = -slope.xyz.x;
1230                 slope.xyz.x = slope.xyz.y;
1231                 slope.xyz.y = temp;
1232                 vm_vec_normalize(&slope);
1233         }
1234
1235         // get the points               
1236         vm_vec_scale_add(out, in1, &slope, (float)thickness);
1237 }
1238
1239 // special function for drawing polylines. this function is specifically intended for
1240 // polylines where each section is no more than 90 degrees away from a previous section.
1241 // Moreover, it is _really_ intended for use with 45 degree angles. 
1242 void gr_pline_special(vector **pts, int num_pts, int thickness)
1243 {                               
1244         vector s1, s2, e1, e2, dir;
1245         vector last_e1, last_e2;
1246         vertex v[4];
1247         vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
1248         int saved_zbuffer_mode, idx;            
1249         int started_frame = 0;
1250
1251         // SDL_assert(0);
1252
1253         // if we have less than 2 pts, bail
1254         if(num_pts < 2){
1255                 return;
1256         }       
1257
1258         extern int G3_count;
1259         if(G3_count == 0){
1260                 g3_start_frame(1);              
1261                 started_frame = 1;
1262         }
1263
1264         // turn off zbuffering  
1265         saved_zbuffer_mode = gr_zbuffer_get();
1266         gr_zbuffer_set(GR_ZBUFF_NONE);  
1267
1268         // turn off culling
1269         gr_set_cull(0);
1270
1271         // draw each section
1272         last_e1 = vmd_zero_vector;
1273         last_e2 = vmd_zero_vector;
1274         for(idx=0; idx<num_pts-1; idx++){               
1275                 // get the start and endpoints          
1276                 s1 = *pts[idx];                                                                                                         // start 1 (on the line)
1277                 gr_pline_helper(&s2, pts[idx], pts[idx+1], thickness);  // start 2
1278                 e1 = *pts[idx+1];                                                                                                               // end 1 (on the line)
1279                 vm_vec_sub(&dir, pts[idx+1], pts[idx]);         
1280                 vm_vec_add(&e2, &s2, &dir);                                                                             // end 2
1281                 
1282                 // stuff coords         
1283                 v[0].sx = (float)ceil(s1.xyz.x);
1284                 v[0].sy = (float)ceil(s1.xyz.y);        
1285                 v[0].sw = 0.0f;
1286                 v[0].u = 0.5f;
1287                 v[0].v = 0.5f;
1288                 v[0].flags = PF_PROJECTED;
1289                 v[0].codes = 0;
1290                 v[0].r = gr_screen.current_color.red;
1291                 v[0].g = gr_screen.current_color.green;
1292                 v[0].b = gr_screen.current_color.blue;
1293
1294                 v[1].sx = (float)ceil(s2.xyz.x);
1295                 v[1].sy = (float)ceil(s2.xyz.y);        
1296                 v[1].sw = 0.0f;
1297                 v[1].u = 0.5f;
1298                 v[1].v = 0.5f;
1299                 v[1].flags = PF_PROJECTED;
1300                 v[1].codes = 0;
1301                 v[1].r = gr_screen.current_color.red;
1302                 v[1].g = gr_screen.current_color.green;
1303                 v[1].b = gr_screen.current_color.blue;
1304
1305                 v[2].sx = (float)ceil(e2.xyz.x);
1306                 v[2].sy = (float)ceil(e2.xyz.y);
1307                 v[2].sw = 0.0f;
1308                 v[2].u = 0.5f;
1309                 v[2].v = 0.5f;
1310                 v[2].flags = PF_PROJECTED;
1311                 v[2].codes = 0;
1312                 v[2].r = gr_screen.current_color.red;
1313                 v[2].g = gr_screen.current_color.green;
1314                 v[2].b = gr_screen.current_color.blue;
1315
1316                 v[3].sx = (float)ceil(e1.xyz.x);
1317                 v[3].sy = (float)ceil(e1.xyz.y);
1318                 v[3].sw = 0.0f;
1319                 v[3].u = 0.5f;
1320                 v[3].v = 0.5f;
1321                 v[3].flags = PF_PROJECTED;
1322                 v[3].codes = 0;                         
1323                 v[3].r = gr_screen.current_color.red;
1324                 v[3].g = gr_screen.current_color.green;
1325                 v[3].b = gr_screen.current_color.blue;          
1326
1327                 // draw the polys
1328                 g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB, 0.1f);            
1329
1330                 // if we're past the first section, draw a "patch" triangle to fill any gaps
1331                 if(idx > 0){
1332                         // stuff coords         
1333                         v[0].sx = (float)ceil(s1.xyz.x);
1334                         v[0].sy = (float)ceil(s1.xyz.y);
1335                         v[0].sw = 0.0f;
1336                         v[0].u = 0.5f;
1337                         v[0].v = 0.5f;
1338                         v[0].flags = PF_PROJECTED;
1339                         v[0].codes = 0;
1340                         v[0].r = gr_screen.current_color.red;
1341                         v[0].g = gr_screen.current_color.green;
1342                         v[0].b = gr_screen.current_color.blue;
1343
1344                         v[1].sx = (float)ceil(s2.xyz.x);
1345                         v[1].sy = (float)ceil(s2.xyz.y);        
1346                         v[1].sw = 0.0f;
1347                         v[1].u = 0.5f;
1348                         v[1].v = 0.5f;
1349                         v[1].flags = PF_PROJECTED;
1350                         v[1].codes = 0;
1351                         v[1].r = gr_screen.current_color.red;
1352                         v[1].g = gr_screen.current_color.green;
1353                         v[1].b = gr_screen.current_color.blue;
1354
1355
1356                         v[2].sx = (float)ceil(last_e2.xyz.x);
1357                         v[2].sy = (float)ceil(last_e2.xyz.y);
1358                         v[2].sw = 0.0f;
1359                         v[2].u = 0.5f;
1360                         v[2].v = 0.5f;
1361                         v[2].flags = PF_PROJECTED;
1362                         v[2].codes = 0;
1363                         v[2].r = gr_screen.current_color.red;
1364                         v[2].g = gr_screen.current_color.green;
1365                         v[2].b = gr_screen.current_color.blue;
1366
1367                         g3_draw_poly_constant_sw(3, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB, 0.1f);            
1368                 }
1369
1370                 // store our endpoints
1371                 last_e1 = e1;
1372                 last_e2 = e2;
1373         }
1374
1375         if(started_frame){
1376                 g3_end_frame();
1377         }
1378
1379         // restore zbuffer mode
1380         gr_zbuffer_set(saved_zbuffer_mode);
1381
1382         // restore culling
1383         gr_set_cull(1);         
1384 }
1385