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