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