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