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