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