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