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