]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grglide.cpp
Screenshot function filled, will output into ~/.freespace(2)/Data
[taylor/freespace2.git] / src / graphics / grglide.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/GrGlide.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code that uses 3DFX's Glide graphics library
16  *
17  * $Log$
18  * Revision 1.2  2002/06/09 04:41:17  relnev
19  * added copyright header
20  *
21  * Revision 1.1.1.1  2002/05/03 03:28:09  root
22  * Initial import.
23  *
24  * 
25  * 39    9/14/99 5:14a Dave
26  * Fixed credits drawing in Glide.
27  * 
28  * 38    9/08/99 11:38p Dave
29  * Make V2 minimize/maximize the old way.
30  * 
31  * 37    9/04/99 8:00p Dave
32  * Fixed up 1024 and 32 bit movie support.
33  * 
34  * 36    9/01/99 10:49p Dave
35  * Added nice SquadWar checkbox to the client join wait screen.
36  * 
37  * 35    8/30/99 5:01p Dave
38  * Made d3d do less state changing in the nebula. Use new chat server for
39  * PXO.
40  * 
41  * 34    8/06/99 12:29a Dave
42  * Multiple bug fixes.
43  * 
44  * 33    8/04/99 5:36p Dave
45  * Make glide and D3D switch out properly.
46  * 
47  * 32    7/19/99 3:29p Dave
48  * Fixed gamma bitmap in the options screen.
49  * 
50  * 31    7/14/99 9:42a Dave
51  * Put in clear_color debug function. Put in base for 3dnow stuff / P3
52  * stuff
53  * 
54  * 30    7/13/99 1:15p Dave
55  * 32 bit support. Whee!
56  * 
57  * 29    6/29/99 10:35a Dave
58  * Interface polygon bitmaps! Whee!
59  * 
60  * 28    5/05/99 9:02p Dave
61  * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
62  * rotations, tweaked values, made bitmap selection more random). Fixed
63  * D3D beam weapon clipping problem. Added D3d frame dumping.
64  * 
65  * 27    2/21/99 1:48p Dave
66  * Some code for monitoring datarate for multiplayer in detail.
67  * 
68  * 26    2/11/99 3:08p Dave
69  * PXO refresh button. Very preliminary squad war support.
70  * 
71  * 25    2/05/99 12:52p Dave
72  * Fixed Glide nondarkening textures.
73  * 
74  * 24    2/04/99 6:29p Dave
75  * First full working rev of FS2 PXO support.  Fixed Glide lighting
76  * problems.
77  * 
78  * 23    2/03/99 11:44a Dave
79  * Fixed d3d transparent textures.
80  * 
81  * 22    1/30/99 1:29a Dave
82  * Fixed nebula thumbnail problem. Full support for 1024x768 choose pilot
83  * screen.  Fixed beam weapon death messages.
84  * 
85  * 21    1/24/99 11:37p Dave
86  * First full rev of beam weapons. Very customizable. Removed some bogus
87  * Int3()'s in low level net code.
88  * 
89  * 20    1/23/99 5:33p Dave
90  * Put in support for 1024x768 Glide.
91  * 
92  * 19    1/15/99 11:29a Neilk
93  * Fixed D3D screen/texture pixel formatting problem. 
94  * 
95  * 18    12/18/98 1:13a Dave
96  * Rough 1024x768 support for Direct3D. Proper detection and usage through
97  * the launcher.
98  * 
99  * 17    12/14/98 12:13p Dave
100  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
101  * Need to test now.
102  * 
103  * 16    12/09/98 7:34p Dave
104  * Cleanup up nebula effect. Tweaked many values.
105  * 
106  * 15    12/06/98 2:36p Dave
107  * Drastically improved nebula fogging.
108  * 
109  * 14    12/04/98 10:20a Dave
110  * Fixed up gr_glide_get_pixel(...)
111  * 
112  * 13    12/02/98 9:58a Dave
113  * Got fonttool working under Glide/Direct3d.
114  * 
115  * 12    12/01/98 5:54p Dave
116  * Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
117  * properly in D3D and Glide.
118  * 
119  * 11    12/01/98 10:32a Johnson
120  * Fixed direct3d font problems. Fixed sun bitmap problem. Fixed direct3d
121  * starfield problem.
122  * 
123  * 10    12/01/98 8:06a Dave
124  * Temporary checkin to fix some texture transparency problems in d3d.
125  * 
126  * 9     11/30/98 1:07p Dave
127  * 16 bit conversion, first run.
128  * 
129  * 8     11/24/98 4:43p Dave
130  * Make sure glide starts up in 640x480
131  * 
132  * 7     11/20/98 11:16a Dave
133  * Fixed up IPX support a bit. Making sure that switching modes and
134  * loading/saving pilot files maintains proper state.
135  * 
136  * 6     11/14/98 5:32p Dave
137  * Lots of nebula work. Put in ship contrails.
138  * 
139  * 5     11/12/98 12:19a Dave
140  * Removed compiler warning.
141  * 
142  * 4     11/11/98 5:37p Dave
143  * Checkin for multiplayer testing.
144  * 
145  * 3     11/09/98 2:11p Dave
146  * Nebula optimizations.
147  * 
148  * 2     10/07/98 10:52a Dave
149  * Initial checkin.
150  * 
151  * 1     10/07/98 10:49a Dave
152  * 
153  * 116   9/14/98 1:59p Allender
154  * allow for interlaced movies
155  * 
156  * 115   5/25/98 10:32a John
157  * Took out redundant code for font bitmap offsets that converted to a
158  * float, then later on converted back to an integer.  Quite unnecessary.
159  * 
160  * 114   5/22/98 9:09a John
161  * fixed type in previous
162  * 
163  * 113   5/22/98 9:07a John
164  * added in code that fixed Rush Glide startup problemmo.
165  * 
166  * 112   5/20/98 9:46p John
167  * added code so the places in code that change half the palette don't
168  * have to clear the screen.
169  * 
170  * 111   5/17/98 5:03p John
171  * Fixed some bugs that make the taskbar interfere with the DEBUG-only
172  * mouse cursor.
173  * 
174  * 110   5/17/98 3:23p John
175  * Took out capibility check for additive blending.  Made gr_bitmap_ex
176  * clip properly in glide and direct3d.
177  * 
178  * 109   5/15/98 9:34p John
179  * Removed the initial ugly little cursor part that drew right at program
180  * start.
181  * 
182  * 108   5/15/98 8:48a John
183  * Fixed bug where one-pixel line was getting left on right and bottom.
184  * 
185  * 107   5/14/98 5:42p John
186  * Revamped the whole window position/mouse code for the graphics windows.
187  * 
188  * 106   5/08/98 5:38p John
189  * Made Glide wait for retrace.
190  * 
191  * 105   5/08/98 5:37p John
192  * 
193  * 104   5/07/98 6:58p Hoffoss
194  * Made changes to mouse code to fix a number of problems.
195  * 
196  * 103   5/07/98 8:43a John
197  * Turned off 3dfx gamma correction.
198  * 
199  * 102   5/07/98 8:36a John
200  * Fixed Glide gradients
201  * 
202  * 101   5/06/98 8:41p John
203  * Fixed some font clipping bugs.   Moved texture handle set code for d3d
204  * into the texture module.
205  * 
206  * 100   5/06/98 5:30p John
207  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
208  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
209  * DirectX header files and libs that fixed the Direct3D alpha blending
210  * problems.
211  *
212  */
213
214 //#define USE_8BPP_TEXTURES 
215
216 #include <windows.h>
217 #include <windowsx.h>
218 #include "glide.h"
219 #include "glideutl.h"
220
221 #include "osapi.h"
222 #include "2d.h"
223 #include "bmpman.h"
224 #include "floating.h"
225 #include "palman.h"
226 #include "grinternal.h"
227 #include "grglide.h"
228 #include "line.h"
229 #include "font.h"
230 #include "mouse.h"
231 #include "key.h"
232 #include "systemvars.h"
233 #include "grglideinternal.h"
234 #include "cfile.h"
235 #include "timer.h"
236 // #include "movie.h"
237 #include "neb.h"
238
239 #define NEBULA_COLORS 20
240
241 GrFog_t Glide_linear_fogtable[GR_FOG_TABLE_SIZE];       
242
243 int Glide_textures_in = 0;
244
245 int Glide_voodoo3 = 0;
246
247 static int Inited = 0;
248
249 // voodoo3 is a little sensitive to getting deactivated
250 #define VOODOO3_DEACTIVATED                     -1
251 #define VOODOO3_INACTIVE()                              ( (Glide_voodoo3 == 1) && (Glide_deactivate == VOODOO3_DEACTIVATED) )
252
253 float Gr_gamma_lookup_float[256];
254
255 volatile int Glide_running = 0;
256 volatile int Glide_activate = 0;
257 volatile int Glide_deactivate = 0;
258
259 typedef enum gr_texture_source {
260         TEXTURE_SOURCE_NONE,
261         TEXTURE_SOURCE_DECAL,
262 } gr_texture_source;
263
264 typedef enum gr_color_source {
265         COLOR_SOURCE_VERTEX,
266         COLOR_SOURCE_TEXTURE,
267         COLOR_SOURCE_VERTEX_TIMES_TEXTURE,
268 } gr_color_source;
269
270 typedef enum gr_alpha_source {
271         ALPHA_SOURCE_VERTEX,
272         ALPHA_SOURCE_VERTEX_NONDARKENING,
273         ALPHA_SOURCE_TEXTURE,
274         ALPHA_SOURCE_VERTEX_TIMES_TEXTURE,
275 } gr_alpha_source;
276
277 typedef enum gr_alpha_blend {
278         ALPHA_BLEND_NONE,                                                       // 1*SrcPixel + 0*DestPixel
279         ALPHA_BLEND_ADDITIVE,                                   // 1*SrcPixel + 1*DestPixel
280         ALPHA_BLEND_ALPHA_ADDITIVE,                     // Alpha*SrcPixel + 1*DestPixel
281         ALPHA_BLEND_ALPHA_BLEND_ALPHA,          // Alpha*SrcPixel + (1-Alpha)*DestPixel
282         ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR,      // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
283 } gr_alpha_blend;
284
285 typedef enum gr_zbuffer_type {
286         ZBUFFER_TYPE_NONE,
287         ZBUFFER_TYPE_READ,
288         ZBUFFER_TYPE_WRITE,
289         ZBUFFER_TYPE_FULL,
290 } gr_zbuffer_type;
291
292 int Glide_last_state = -1;
293
294 void gr_glide_set_state( gr_texture_source ts, gr_color_source cs, gr_alpha_source as, gr_alpha_blend ab, gr_zbuffer_type zt )
295 {
296         int current_state = 0;
297
298         if(VOODOO3_INACTIVE()){
299                 return;
300         }
301
302         current_state = current_state | (ts<<0);
303         current_state = current_state | (cs<<5);
304         current_state = current_state | (as<<10);
305         current_state = current_state | (ab<<15);
306         current_state = current_state | (zt<<20);
307
308         if ( current_state == Glide_last_state ) {
309                 return;
310         }
311         Glide_last_state = current_state;
312
313         switch( ts )    {
314         case TEXTURE_SOURCE_NONE:
315                 grTexCombineFunction( GR_TMU0, GR_TEXTURECOMBINE_ONE );
316                 break;
317         case TEXTURE_SOURCE_DECAL:
318                 grTexCombineFunction( GR_TMU0, GR_TEXTURECOMBINE_DECAL );
319                 break;
320         default:
321                 Int3();
322         }
323
324         switch( cs )    {
325         case COLOR_SOURCE_VERTEX:
326                 grColorCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE );
327                 break;
328         
329         case COLOR_SOURCE_TEXTURE:
330                 grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE);
331                 break;
332
333         case COLOR_SOURCE_VERTEX_TIMES_TEXTURE:
334                 grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_LOCAL, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_TEXTURE, FXFALSE);
335                 break;
336
337         default:
338                 Int3();
339         }
340
341         switch( as )    {
342         case ALPHA_SOURCE_VERTEX:
343                 grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE );
344                 grAlphaControlsITRGBLighting(FXFALSE);
345                 break;
346
347         case ALPHA_SOURCE_VERTEX_NONDARKENING:
348                 grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE );
349                 grAlphaControlsITRGBLighting(FXTRUE);
350                 grConstantColorValue(0xFFFFFFFF);                       // Non-darkening colors will use this
351                 break;
352
353         case ALPHA_SOURCE_TEXTURE:
354                 grAlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE);
355                 grAlphaControlsITRGBLighting(FXFALSE);
356                 break;
357
358         case ALPHA_SOURCE_VERTEX_TIMES_TEXTURE:
359                 grAlphaCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_LOCAL, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_TEXTURE, FXFALSE );
360                 grAlphaControlsITRGBLighting(FXFALSE);
361                 break;
362
363         default:
364                 Int3();
365         }
366
367
368         switch( ab )    {
369         case ALPHA_BLEND_NONE:                                                  // 1*SrcPixel + 0*DestPixel
370                 grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO, GR_BLEND_ZERO );
371                 break;
372
373         case ALPHA_BLEND_ADDITIVE:                                              // 1*SrcPixel + 1*DestPixel
374                 grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO );
375                 break;
376
377         case ALPHA_BLEND_ALPHA_ADDITIVE:                                // Alpha*SrcPixel + 1*DestPixel
378                 grAlphaBlendFunction( GR_BLEND_SRC_ALPHA, GR_BLEND_ONE, GR_BLEND_ZERO, GR_BLEND_ZERO);
379                 break;
380
381         case ALPHA_BLEND_ALPHA_BLEND_ALPHA:                     // Alpha*SrcPixel + (1-Alpha)*DestPixel
382                 grAlphaBlendFunction( GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA, GR_BLEND_ZERO, GR_BLEND_ZERO );
383                 break;
384
385         case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
386                 grAlphaBlendFunction( GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_COLOR, GR_BLEND_ZERO, GR_BLEND_ZERO );
387                 break;
388
389         default:
390                 Int3();
391         }
392         
393         switch( zt )    {
394
395         case ZBUFFER_TYPE_NONE:
396                 grDepthBufferMode(GR_DEPTHBUFFER_DISABLE);
397                 grDepthMask( FXFALSE );
398                 break;
399
400         case ZBUFFER_TYPE_READ:
401                 grDepthBufferMode(GR_DEPTHBUFFER_WBUFFER);
402                 grDepthBufferFunction(GR_CMP_LEQUAL);
403                 grDepthMask( FXFALSE );
404                 break;
405
406         case ZBUFFER_TYPE_WRITE:
407                 grDepthBufferMode(GR_DEPTHBUFFER_WBUFFER);
408                 grDepthBufferFunction(GR_CMP_ALWAYS);
409                 grDepthMask( FXTRUE );
410                 break;
411
412         case ZBUFFER_TYPE_FULL:
413                 grDepthBufferMode(GR_DEPTHBUFFER_WBUFFER);
414                 grDepthBufferFunction(GR_CMP_LEQUAL);
415                 grDepthMask( FXTRUE );
416                 break;
417
418         default:
419                 Int3();
420         }
421
422 }
423
424 /*
425         gr_glide_set_state( 
426         TEXTURE_SOURCE_NONE, TEXTURE_SOURCE_DECAL,
427
428         COLOR_SOURCE_VERTEX, COLOR_SOURCE_TEXTURE, COLOR_SOURCE_VERTEX_TIMES_TEXTURE,
429
430         ALPHA_SOURCE_VERTEX, ALPHA_SOURCE_TEXTURE, ALPHA_SOURCE_VERTEX_TIMES_TEXTURE,
431
432         ALPHA_BLEND_NONE, ALPHA_BLEND_ADDITIVE, ALPHA_BLEND_ALPHA_ADDITIVE, ALPHA_BLEND_ALPHA_BLEND_ALPHA,      ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR,
433         
434         ZBUFFER_TYPE_NONE, ZBUFFER_TYPE_READ, ZBUFFER_TYPE_WRITE, ZBUFFER_TYPE_FULL,
435
436         );
437
438 */
439
440
441 // If mode is FALSE, turn zbuffer off the entire frame,
442 // no matter what people pass to gr_zbuffer_set.
443 void gr_glide_zbuffer_clear(int mode)
444 {
445         if(VOODOO3_INACTIVE()){
446                 return;
447         }
448
449         if ( mode )     {
450                 gr_zbuffering = 1;
451                 gr_zbuffering_mode = GR_ZBUFF_FULL;
452                 gr_global_zbuffering = 1;
453
454                 // Make sure zbuffering is on
455                 gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
456
457                 // Disable writes to color and alpha buffers
458                 grColorMask( FXFALSE, FXFALSE );        
459                 // Clear the zbuffer
460                 grBufferClear( 0x0, 0, GR_WDEPTHVALUE_FARTHEST );
461                 // Re-enable writes to the color buffer
462                 grColorMask( FXTRUE, FXFALSE ); 
463         } else {
464                 gr_zbuffering = 0;
465                 gr_zbuffering_mode = GR_ZBUFF_NONE;
466                 gr_global_zbuffering = 0;
467         }
468 }
469
470 int gr_glide_zbuffer_get()
471 {
472         if ( !gr_global_zbuffering )    {
473                 return GR_ZBUFF_NONE;
474         }
475         return gr_zbuffering_mode;
476 }
477
478 int gr_glide_zbuffer_set(int mode)
479 {
480         if ( !gr_global_zbuffering )    {
481                 gr_zbuffering = 0;
482                 return GR_ZBUFF_NONE;
483         }
484
485         int tmp = gr_zbuffering_mode;
486
487         gr_zbuffering_mode = mode;
488
489         if ( gr_zbuffering_mode == GR_ZBUFF_NONE )      {
490                 gr_zbuffering = 0;
491         } else {
492                 gr_zbuffering = 1;
493         }
494         return tmp;
495 }
496
497
498 void gr_glide_pixel(int x, int y)
499 {
500         if(VOODOO3_INACTIVE()){
501                 return;
502         }
503
504         gr_line(x,y,x,y);
505 /*
506         if ( x < gr_screen.clip_left ) return;
507         if ( x > gr_screen.clip_right ) return;
508         if ( y < gr_screen.clip_top ) return;
509         if ( y > gr_screen.clip_bottom ) return;
510
511         // Set up Render State - flat shading - alpha blending
512         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
513
514         GrVertex p;
515         p.x = 0.5f + i2fl(x + gr_screen.offset_x);
516         p.y = 0.5f + i2fl(y + gr_screen.offset_y);
517         p.a = 255.0f;
518         p.r = i2fl(gr_screen.current_color.red);
519         p.g = i2fl(gr_screen.current_color.green);
520         p.b = i2fl(gr_screen.current_color.blue);
521
522         grDrawPoint(&p);
523 */
524 }
525
526 float snap(float x)
527 {
528         int xi = fl2i(x*16.0f);
529         return i2fl(xi)/16.0f;
530 }
531
532 void gr_glide_clear()
533 {
534         GrColor_t clear_color;
535
536         if(VOODOO3_INACTIVE()){
537                 return;
538         }
539
540         // Turn off zbuffering so this doesn't clear the zbuffer
541         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
542
543         // Clear the screen     
544         clear_color = 0;
545         clear_color |= ((ubyte)gr_screen.current_clear_color.red);
546         clear_color |= ((ubyte)gr_screen.current_clear_color.green << 8);
547         clear_color |= ((ubyte)gr_screen.current_clear_color.blue << 16);
548         grBufferClear( clear_color, 0, GR_WDEPTHVALUE_FARTHEST );
549 }
550
551 static RECT Glide_cursor_clip_rect;
552
553 void gr_glide_clip_cursor(int active)
554 {
555         if ( active  )  {
556                 ClipCursor(&Glide_cursor_clip_rect);
557         } else {
558                 ClipCursor(NULL);
559         }
560 }
561
562
563 int Gr_glide_mouse_saved = 0;
564 int Gr_glide_mouse_saved_x1 = 0;
565 int Gr_glide_mouse_saved_y1 = 0;
566 int Gr_glide_mouse_saved_x2 = 0;
567 int Gr_glide_mouse_saved_y2 = 0;
568 int Gr_glide_mouse_saved_w = 0;
569 int Gr_glide_mouse_saved_h = 0;
570 #define MAX_SAVE_SIZE (32*32)
571 ushort Gr_glide_mouse_saved_data[MAX_SAVE_SIZE];
572
573 // Clamps X between R1 and R2
574 #define CLAMP(x,r1,r2) do { if ( (x) < (r1) ) (x) = (r1); else if ((x) > (r2)) (x) = (r2); } while(0)
575
576 void gr_glide_save_mouse_area(int x, int y, int w, int h )
577 {
578         if(VOODOO3_INACTIVE()){
579                 return;
580         }
581
582         Gr_glide_mouse_saved_x1 = x; 
583         Gr_glide_mouse_saved_y1 = y;
584         Gr_glide_mouse_saved_x2 = x+w-1;
585         Gr_glide_mouse_saved_y2 = y+h-1;
586          
587         CLAMP(Gr_glide_mouse_saved_x1, gr_screen.clip_left, gr_screen.clip_right );
588         CLAMP(Gr_glide_mouse_saved_x2, gr_screen.clip_left, gr_screen.clip_right );
589         CLAMP(Gr_glide_mouse_saved_y1, gr_screen.clip_top, gr_screen.clip_bottom );
590         CLAMP(Gr_glide_mouse_saved_y2, gr_screen.clip_top, gr_screen.clip_bottom );
591
592         Gr_glide_mouse_saved_w = Gr_glide_mouse_saved_x2 - Gr_glide_mouse_saved_x1 + 1;
593         Gr_glide_mouse_saved_h = Gr_glide_mouse_saved_y2 - Gr_glide_mouse_saved_y1 + 1;
594
595         if ( Gr_glide_mouse_saved_w < 1 ) return;
596         if ( Gr_glide_mouse_saved_h < 1 ) return;
597
598         // Make sure we're not saving too much!
599         Assert( (Gr_glide_mouse_saved_w*Gr_glide_mouse_saved_h) <= MAX_SAVE_SIZE );
600
601         GrLfbInfo_t info;
602
603         info.size=sizeof(GrLfbInfo_t);
604
605         // get a read pointer 
606         if ( grLfbLock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565,
607                                                         GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))          {
608
609                 ushort *rptr;
610                 int short_per_row=info.strideInBytes/2;
611
612                 rptr = (ushort *)info.lfbPtr;
613
614                 ushort *sptr, *dptr;
615
616                 dptr = Gr_glide_mouse_saved_data;
617
618                 for (int i=0; i<Gr_glide_mouse_saved_h; i++ )   {
619                         sptr = &rptr[(Gr_glide_mouse_saved_y1+i)*short_per_row+Gr_glide_mouse_saved_x1];
620
621                         for(int j=0; j<Gr_glide_mouse_saved_w; j++ )    {
622                                 *dptr++ = *sptr++;
623                         }
624                 }
625
626
627                 // Release the lock
628                 grLfbUnlock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER );
629
630                 Gr_glide_mouse_saved = 1;
631
632         }  else {
633                 mprintf(( "Couldn't get read-only lock to backbuffer for glide mouse save\n" ));
634         }
635
636 }
637
638 // lock the backbuffer and return a pointer
639 uint gr_glide_lock()
640 {
641         GrLfbInfo_t info;
642
643         if(VOODOO3_INACTIVE()){
644                 return NULL;
645         }
646
647         info.size=sizeof(GrLfbInfo_t);
648         if(grLfbLock(GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_1555, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)){              
649                 return (uint)info.lfbPtr;
650         } 
651
652         // fail
653         return NULL;
654 }
655
656 // unlock the backbuffer
657 void gr_glide_unlock()
658 {
659         if(VOODOO3_INACTIVE()){
660                 return;
661         }
662
663         // Release the lock
664         grLfbUnlock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER );
665 }
666
667 static int gr_palette_faded_out = 0;
668
669 void gr_glide_flip()
670 {
671         int cnt;        
672
673         if(VOODOO3_INACTIVE()){
674                 return;
675         }
676         
677         // voodoo3 ?    
678         if(!Glide_voodoo3){
679                 cnt = Glide_activate;
680                 if ( cnt )      {
681                         Glide_activate -= cnt;
682
683                         gr_glide_clip_cursor(1);
684                         grSstControl(GR_CONTROL_ACTIVATE);
685                 }
686
687                 cnt = Glide_deactivate;
688                 if ( cnt )      {
689                         Glide_deactivate -= cnt;
690
691                         gr_glide_clip_cursor(0);
692                         grSstControl(GR_CONTROL_DEACTIVATE);
693                 }
694         }       
695
696         gr_reset_clip();
697
698         if ( gr_palette_faded_out )     {
699                 return;
700         }
701
702         int mx, my;
703
704         Gr_glide_mouse_saved = 0;               // assume not saved
705
706         mouse_eval_deltas();
707         if ( mouse_is_visible() )       {
708                 gr_reset_clip();
709                 mouse_get_pos( &mx, &my );
710                 gr_glide_save_mouse_area(mx,my,32,32);
711                 if ( Gr_cursor == -1 )  {
712                         gr_set_color(255,255,255);
713                         gr_line( mx, my, mx+7, my + 7 );
714                         gr_line( mx, my, mx+5, my );
715                         gr_line( mx, my, mx, my+5 );
716                 } else {
717                         gr_set_bitmap(Gr_cursor);
718                         gr_bitmap( mx, my );
719                 }
720         } 
721
722 #ifndef NDEBUG
723         if(Interface_framerate){
724                 if(Interface_last_tick > 0){            
725                         int diff = timer_get_milliseconds() - Interface_last_tick;
726                         gr_printf(10, 10, "%f", 1000.0f / (float)diff);
727                 }
728                 Interface_last_tick = timer_get_milliseconds();
729         }
730 #endif
731
732 #ifndef NDEBUG
733         grBufferSwap( 0 );
734 #else
735         grBufferSwap( 1 );
736 #endif
737    grSstIdle();
738
739         glide_tcache_frame();
740 }
741
742 void gr_glide_flip_window(uint _hdc, int x, int y, int w, int h )
743 {
744 }
745
746 void gr_glide_set_clip(int x,int y,int w,int h)
747 {
748         gr_screen.offset_x = x;
749         gr_screen.offset_y = y;
750
751         gr_screen.clip_left = 0;
752         gr_screen.clip_right = w-1;
753
754         gr_screen.clip_top = 0;
755         gr_screen.clip_bottom = h-1;
756
757         if(VOODOO3_INACTIVE()){
758                 return;
759         }
760
761         // check for sanity of parameters
762         if ( gr_screen.clip_left+x < 0 ) {
763                 gr_screen.clip_left = -x;
764         } else if ( gr_screen.clip_left+x > gr_screen.max_w-1 ) {
765                 gr_screen.clip_left = gr_screen.max_w-1-x;
766         }
767         if ( gr_screen.clip_right+x < 0 ) {
768                 gr_screen.clip_right = -x;
769         } else if ( gr_screen.clip_right+x >= gr_screen.max_w-1 )       {
770                 gr_screen.clip_right = gr_screen.max_w-1-x;
771         }
772
773         if ( gr_screen.clip_top+y < 0 ) {
774                 gr_screen.clip_top = -y;
775         } else if ( gr_screen.clip_top+y > gr_screen.max_h-1 )  {
776                 gr_screen.clip_top = gr_screen.max_h-1-y;
777         }
778
779         if ( gr_screen.clip_bottom+y < 0 ) {
780                 gr_screen.clip_bottom = -y;
781         } else if ( gr_screen.clip_bottom+y > gr_screen.max_h-1 )       {
782                 gr_screen.clip_bottom = gr_screen.max_h-1-y;
783         }
784
785         gr_screen.clip_width = gr_screen.clip_right - gr_screen.clip_left + 1;
786         gr_screen.clip_height = gr_screen.clip_bottom - gr_screen.clip_top + 1;
787
788         grClipWindow( gr_screen.clip_left+x, gr_screen.clip_top+y, gr_screen.clip_right+1+x, gr_screen.clip_bottom+1+y );
789 }
790
791 void gr_glide_reset_clip()
792 {
793         if(VOODOO3_INACTIVE()){
794                 return;
795         }
796
797         gr_screen.offset_x = 0;
798         gr_screen.offset_y = 0;
799         gr_screen.clip_left = 0;
800         gr_screen.clip_top = 0;
801         gr_screen.clip_right = gr_screen.max_w - 1;
802         gr_screen.clip_bottom = gr_screen.max_h - 1;
803         gr_screen.clip_width = gr_screen.max_w;
804         gr_screen.clip_height = gr_screen.max_h;
805
806         grClipWindow( gr_screen.clip_left, gr_screen.clip_top, gr_screen.clip_right+1, gr_screen.clip_bottom+1 );
807 }
808
809
810 void gr_glide_set_bitmap( int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha, int sx, int sy )
811 {
812         if(VOODOO3_INACTIVE()){
813                 return;
814         }
815
816         gr_screen.current_alpha = alpha;
817         gr_screen.current_alphablend_mode = alphablend_mode;
818         gr_screen.current_bitblt_mode = bitblt_mode;
819         gr_screen.current_bitmap = bitmap_num;
820
821         gr_screen.current_bitmap_sx = sx;
822         gr_screen.current_bitmap_sy = sy;
823 }
824
825 void gr_glide_create_shader(shader * shade, float r, float g, float b, float c )
826 {
827         shade->screen_sig = gr_screen.signature;
828         
829         shade->r = r;
830         shade->g = g;
831         shade->b = b;
832         shade->c = c;
833 }
834
835 void gr_glide_set_shader( shader * shade )
836 {       
837         if ( shade )    {
838                 if (shade->screen_sig != gr_screen.signature)   {
839                         gr_create_shader( shade, shade->r, shade->g, shade->b, shade->c );
840                 }
841                 gr_screen.current_shader = *shade;
842         } else {
843                 gr_create_shader( &gr_screen.current_shader, 0.0f, 0.0f, 0.0f, 0.0f );
844         }
845 }
846
847 void gr_glide_bitmap_ex_internal(int x,int y,int w,int h,int sx,int sy)
848 {
849         int i,j;
850         bitmap * bmp;
851         ushort * sptr;
852
853         if(VOODOO3_INACTIVE()){
854                 return;
855         }
856
857         bmp = bm_lock( gr_screen.current_bitmap, 16, 0 );
858         sptr = (ushort *)( bmp->data + (sy*bmp->w*2) + (sx*2) );
859
860         if ( x < gr_screen.clip_left ) return;
861         if ( x > gr_screen.clip_right ) return;
862         if ( y < gr_screen.clip_top ) return;
863         if ( y > gr_screen.clip_bottom ) return;
864
865         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );  
866         
867         GrLfbInfo_t info;
868
869         if ( grLfbLock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_1555, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info) ) {
870
871                 ushort *vram = (ushort *)info.lfbPtr;
872                 int stride = info.strideInBytes / sizeof(ushort);
873                 
874                 for (i=0; i<h; i++ )    {
875                                 
876                         ushort *dptr = &vram[stride*(gr_screen.offset_y+i+y)+(gr_screen.offset_x+x)];                   
877                         
878                         for ( j=0; j<w; j++ )   {
879                                 if(sptr[j] & 0x8000){
880                                         *dptr = sptr[j];
881                                 }
882
883                                 dptr++;
884                         }                       
885                         sptr += bmp->w;
886                 }
887
888                 grLfbUnlock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER);
889         }       
890
891         bm_unlock(gr_screen.current_bitmap);
892 }
893
894
895 void gr_glide_bitmap_ex(int x,int y,int w,int h,int sx,int sy)
896 {
897         int reclip;
898         #ifndef NDEBUG
899         int count = 0;
900         #endif
901
902         int dx1=x, dx2=x+w-1;
903         int dy1=y, dy2=y+h-1;
904
905         int bw, bh;
906         bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
907
908         do {
909                 reclip = 0;
910                 #ifndef NDEBUG
911                         if ( count > 1 ) Int3();
912                         count++;
913                 #endif
914         
915                 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
916                 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
917                 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
918                 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
919                 if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
920                 if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
921
922                 if ( sx < 0 ) {
923                         dx1 -= sx;
924                         sx = 0;
925                         reclip = 1;
926                 }
927
928                 if ( sy < 0 ) {
929                         dy1 -= sy;
930                         sy = 0;
931                         reclip = 1;
932                 }
933
934                 w = dx2-dx1+1;
935                 h = dy2-dy1+1;
936
937                 if ( sx + w > bw ) {
938                         w = bw - sx;
939                         dx2 = dx1 + w - 1;
940                 }
941
942                 if ( sy + h > bh ) {
943                         h = bh - sy;
944                         dy2 = dy1 + h - 1;
945                 }
946
947                 if ( w < 1 ) return;            // clipped away!
948                 if ( h < 1 ) return;            // clipped away!
949
950         } while (reclip);
951
952         // Make sure clipping algorithm works
953         #ifndef NDEBUG
954                 Assert( w > 0 );
955                 Assert( h > 0 );
956                 Assert( w == (dx2-dx1+1) );
957                 Assert( h == (dy2-dy1+1) );
958                 Assert( sx >= 0 );
959                 Assert( sy >= 0 );
960                 Assert( sx+w <= bw );
961                 Assert( sy+h <= bh );
962                 Assert( dx2 >= dx1 );
963                 Assert( dy2 >= dy1 );
964                 Assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
965                 Assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
966                 Assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
967                 Assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
968         #endif
969
970         // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
971         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
972
973         gr_glide_bitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
974 }
975
976
977 void gr_glide_bitmap(int x, int y)
978 {
979         int w, h;
980
981         bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
982         int dx1=x, dx2=x+w-1;
983         int dy1=y, dy2=y+h-1;
984         int sx=0, sy=0;
985
986         if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
987         if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
988         if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
989         if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
990         if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
991         if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
992
993         if ( sx < 0 ) return;
994         if ( sy < 0 ) return;
995         if ( sx >= w ) return;
996         if ( sy >= h ) return;
997
998         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
999
1000         gr_glide_bitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1001 }
1002
1003
1004 static void glide_scanline( int x1, int x2, int y )
1005 {
1006         int w;
1007
1008         if(VOODOO3_INACTIVE()){
1009                 return;
1010         }
1011
1012         if ( x1 > x2 )  {
1013                 int tmp = x1;
1014                 x1 = x2;
1015                 x2 = tmp;
1016         }
1017
1018         if ( y < gr_screen.clip_top ) return;
1019         if ( y > gr_screen.clip_bottom ) return;
1020         
1021         if ( x1 < gr_screen.clip_left ) x1 = gr_screen.clip_left;
1022         if ( x2 > gr_screen.clip_right ) x2 = gr_screen.clip_right;
1023
1024         w = x2 - x1 + 1;
1025
1026         if ( w < 1 ) return;
1027
1028 //      for (i=0; i<w; i++)
1029 //              gr_pixel(x1+i,y);
1030
1031
1032         // Set up Render State - flat shading - alpha blending
1033         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1034         
1035         GrVertex a,b;
1036
1037         a.x = i2fl(x1 + gr_screen.offset_x);
1038         a.y = i2fl(y + gr_screen.offset_y);
1039         a.r = i2fl(gr_screen.current_color.red);
1040         a.g = i2fl(gr_screen.current_color.green);
1041         a.b = i2fl(gr_screen.current_color.blue);
1042         a.a = i2fl(gr_screen.current_color.alpha);
1043
1044         b.x = i2fl(x2 + gr_screen.offset_x);
1045         b.y = i2fl(y + gr_screen.offset_y);
1046         b.r = i2fl(gr_screen.current_color.red);
1047         b.g = i2fl(gr_screen.current_color.green);
1048         b.b = i2fl(gr_screen.current_color.blue);
1049         b.a = i2fl(gr_screen.current_color.alpha);
1050
1051         if (a.x<b.x) {
1052                 a.x+=0.5f;
1053                 b.x+=1.0f;
1054         } else {
1055                 b.x+=0.5f;
1056                 a.x+=1.0f;
1057         }
1058
1059         if (a.y<b.y)    {
1060                 a.y+=0.5f;
1061                 b.y+=1.0f;
1062         } else {
1063                 b.y+=0.5f;
1064                 a.y+=1.0f;
1065         }
1066
1067         grDrawLine(&a, &b);
1068 }
1069
1070
1071 void gr_glide_rect(int x,int y,int w,int h)
1072 {
1073         int swapped=0;
1074         int x1 = x, x2;
1075         int y1 = y, y2;
1076
1077         if ( w > 0 )
1078                  x2 = x + w - 1;
1079         else
1080                  x2 = x + w + 1;
1081
1082         if ( h > 0 )
1083                 y2 = y + h - 1;
1084         else
1085                 y2 = y + h + 1;
1086                 
1087         if ( x2 < x1 )  {
1088                 int tmp;        
1089                 tmp = x1;
1090                 x1 = x2;
1091                 x2 = tmp;
1092                 w = -w;
1093                 swapped = 1;
1094         }
1095
1096         if ( y2 < y1 )  {
1097                 int tmp;        
1098                 tmp = y1;
1099                 y1 = y2;
1100                 y2 = tmp;
1101                 h = -h;
1102                 swapped = 1;
1103         }
1104
1105         for (int i=0; i<h; i++ )
1106                 glide_scanline( x1, x2, y1+i );
1107 }
1108
1109
1110 static void glide_shade_scanline( int x1, int x2, int y, int r, int g, int b, int a )
1111 {
1112         int w;
1113
1114         if(VOODOO3_INACTIVE()){
1115                 return;
1116         }
1117
1118         if ( x1 > x2 )  {
1119                 int tmp = x1;
1120                 x1 = x2;
1121                 x2 = tmp;
1122         }
1123
1124         if ( y < gr_screen.clip_top ) return;
1125         if ( y > gr_screen.clip_bottom ) return;
1126         
1127         if ( x1 < gr_screen.clip_left ) x1 = gr_screen.clip_left;
1128         if ( x2 > gr_screen.clip_right ) x2 = gr_screen.clip_right;
1129
1130         w = x2 - x1 + 1;
1131
1132         if ( w < 1 ) return;
1133
1134
1135         // Set up Render State - flat shading - alpha blending
1136         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1137
1138         GrVertex v1,v2;
1139
1140         v1.x = i2fl(x1 + gr_screen.offset_x);
1141         v1.y = i2fl(y + gr_screen.offset_y);
1142         v1.r = i2fl(r);
1143         v1.g = i2fl(g);
1144         v1.b = i2fl(b);
1145         v1.a = i2fl(a);
1146
1147         v2.x = i2fl(x2 + gr_screen.offset_x);
1148         v2.y = i2fl(y + gr_screen.offset_y);
1149         v2.r = i2fl(r);
1150         v2.g = i2fl(g);
1151         v2.b = i2fl(b);
1152         v2.a = i2fl(a);
1153
1154         if (v1.x<v2.x) {
1155                 v1.x+=0.5f;
1156                 v2.x+=1.0f;
1157         } else {
1158                 v2.x+=0.5f;
1159                 v1.x+=1.0f;
1160         }
1161
1162         if (v1.y<v2.y)  {
1163                 v1.y+=0.5f;
1164                 v2.y+=1.0f;
1165         } else {
1166                 v2.y+=0.5f;
1167                 v1.y+=1.0f;
1168         }
1169
1170         grDrawLine(&v1, &v2);
1171
1172 }
1173
1174 float shade1 = 1.0f;
1175 float shade2 = 6.0f;
1176
1177 DCF(shade1,"Set shade1")
1178 {
1179         if ( Dc_command )       {
1180                 dc_get_arg(ARG_FLOAT|ARG_NONE);
1181                 if ( Dc_arg_type & ARG_FLOAT )  {
1182                         shade1 = Dc_arg_float;
1183                 }
1184         }
1185 }
1186
1187 DCF(shade2,"Set shade2")
1188 {
1189         if ( Dc_command )       {
1190                 dc_get_arg(ARG_FLOAT|ARG_NONE);
1191                 if ( Dc_arg_type & ARG_FLOAT )  {
1192                         shade2 = Dc_arg_float;
1193                 }
1194         }
1195 }
1196
1197
1198 void gr_glide_shade(int x,int y,int w,int h)
1199 {
1200         int swapped=0;
1201         int x1 = x, x2;
1202         int y1 = y, y2;
1203
1204         if ( w > 0 )
1205                  x2 = x + w - 1;
1206         else
1207                  x2 = x + w + 1;
1208
1209         if ( h > 0 )
1210                 y2 = y + h - 1;
1211         else
1212                 y2 = y + h + 1;
1213                 
1214         if ( x2 < x1 )  {
1215                 int tmp;        
1216                 tmp = x1;
1217                 x1 = x2;
1218                 x2 = tmp;
1219                 w = -w;
1220                 swapped = 1;
1221         }
1222
1223         if ( y2 < y1 )  {
1224                 int tmp;        
1225                 tmp = y1;
1226                 y1 = y2;
1227                 y2 = tmp;
1228                 h = -h;
1229                 swapped = 1;
1230         }
1231
1232         int r,g,b,a;
1233         r = fl2i(gr_screen.current_shader.r*255.0f*shade1);
1234         if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1235         g = fl2i(gr_screen.current_shader.g*255.0f*shade1);
1236         if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1237         b = fl2i(gr_screen.current_shader.b*255.0f*shade1);
1238         if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1239         a = fl2i(gr_screen.current_shader.c*255.0f*shade2);
1240         if ( a < 0 ) a = 0; else if ( a > 255 ) a = 255;
1241
1242         for (int i=0; i<h; i++ )        {
1243                 glide_shade_scanline( x1, x2, y1+i, r, g, b, a );
1244         }
1245 }
1246
1247
1248 void gr_glide_aabitmap_ex_new(int x,int y,int w,int h,int sx,int sy);
1249
1250 void gr_glide_char(int x,int y,int letter)
1251 {
1252         font_char *ch;
1253         
1254         ch = &Current_font->char_data[letter];
1255         
1256         int sx = Current_font->bm_u[letter];
1257         int sy = Current_font->bm_v[letter];
1258
1259         gr_glide_aabitmap_ex_new( x, y, ch->byte_width, Current_font->h, sx, sy );
1260
1261 //      mprintf(( "String = %s\n", text ));
1262 }
1263
1264
1265 void gr_glide_string( int sx, int sy, char *s )
1266 {
1267         int width, spacing, letter;
1268         int x, y;
1269
1270         if ( !Current_font )    {
1271                 return;
1272         }
1273
1274         gr_set_bitmap(Current_font->bitmap_id);
1275
1276         x = sx;
1277         y = sy;
1278
1279         if (sx==0x8000) {                       //centered
1280                 x = get_centered_x(s);
1281         } else {
1282                 x = sx;
1283         }
1284
1285         spacing = 0;
1286
1287         while (*s)      {
1288
1289                 x += spacing;
1290
1291                 while (*s== '\n' )      {
1292                         s++;
1293                         y += Current_font->h;
1294                         if (sx==0x8000) {                       //centered
1295                                 x = get_centered_x(s);
1296                         } else {
1297                                 x = sx;
1298                         }
1299                 }
1300                 if (*s == 0 ) break;
1301
1302                 letter = get_char_width(s[0],s[1],&width,&spacing);
1303                 s++;
1304
1305                 if (letter<0) { //not in font, draw as space
1306                         continue;
1307                 }
1308
1309                 gr_glide_char( x, y, letter );
1310         }
1311 }
1312
1313 void gr_glide_circle( int xc, int yc, int d )
1314 {
1315
1316         int p,x, y, r;
1317
1318         r = d/2;
1319         p=3-d;
1320         x=0;
1321         y=r;
1322
1323         // Big clip
1324         if ( (xc+r) < gr_screen.clip_left ) return;
1325         if ( (xc-r) > gr_screen.clip_right ) return;
1326         if ( (yc+r) < gr_screen.clip_top ) return;
1327         if ( (yc-r) > gr_screen.clip_bottom ) return;
1328
1329         while(x<y)      {
1330                 // Draw the first octant
1331                 glide_scanline( xc-y, xc+y, yc-x );
1332                 glide_scanline( xc-y, xc+y, yc+x );
1333
1334                 if (p<0) 
1335                         p=p+(x<<2)+6;
1336                 else    {
1337                         // Draw the second octant
1338                         glide_scanline( xc-x, xc+x, yc-y );
1339                         glide_scanline( xc-x, xc+x, yc+y );
1340                         p=p+((x-y)<<2)+10;
1341                         y--;
1342                 }
1343                 x++;
1344         }
1345         if(x==y)        {
1346                 glide_scanline( xc-x, xc+x, yc-y );
1347                 glide_scanline( xc-x, xc+x, yc+y );
1348         }
1349         return;
1350 }
1351
1352 void gr_glide_line(int x1,int y1,int x2,int y2)
1353 {
1354         int clipped = 0, swapped=0;
1355
1356         if(VOODOO3_INACTIVE()){
1357                 return;
1358         }
1359
1360         INT_CLIPLINE(x1,y1,x2,y2,gr_screen.clip_left,gr_screen.clip_top,gr_screen.clip_right,gr_screen.clip_bottom,return,clipped=1,swapped=1);
1361
1362         // Set up Render State - flat shading - alpha blending
1363         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1364
1365         GrVertex a,b;
1366
1367         a.x = i2fl(x1 + gr_screen.offset_x);
1368         a.y = i2fl(y1 + gr_screen.offset_y);
1369         a.r = i2fl(gr_screen.current_color.red);
1370         a.g = i2fl(gr_screen.current_color.green);
1371         a.b = i2fl(gr_screen.current_color.blue);
1372         a.a = i2fl(gr_screen.current_color.alpha);
1373
1374         b.x = i2fl(x2 + gr_screen.offset_x);
1375         b.y = i2fl(y2 + gr_screen.offset_y);
1376         b.r = i2fl(gr_screen.current_color.red);
1377         b.g = i2fl(gr_screen.current_color.green);
1378         b.b = i2fl(gr_screen.current_color.blue);
1379         b.a = i2fl(gr_screen.current_color.alpha);
1380
1381         if (a.x<b.x) {
1382                 a.x+=0.5f;
1383                 b.x+=1.0f;
1384         } else {
1385                 b.x+=0.5f;
1386                 a.x+=1.0f;
1387         }
1388
1389         if (a.y<b.y)    {
1390                 a.y+=0.5f;
1391                 b.y+=1.0f;
1392         } else {
1393                 b.y+=0.5f;
1394                 a.y+=1.0f;
1395         }
1396
1397         grDrawLine(&a, &b);
1398 }
1399
1400
1401 void gr_glide_aaline( vertex *v1, vertex *v2 )
1402 {
1403         float x1, y1, x2, y2;
1404         int clipped = 0, swapped = 0;
1405         float a1, b1, a2, b2;
1406
1407         if(VOODOO3_INACTIVE()){
1408                 return;
1409         }
1410
1411         x1 = v1->sx;
1412         y1 = v1->sy;
1413
1414         x2 = v2->sx;
1415         y2 = v2->sy;
1416
1417         a1 = (float)gr_screen.clip_left;
1418         b1 = (float)gr_screen.clip_top;
1419         a2 = (float)gr_screen.clip_right;
1420         b2 = (float)gr_screen.clip_bottom;
1421
1422         FL_CLIPLINE(x1,y1,x2,y2,a1,b1,a2,b2,return,clipped=1,swapped=1);
1423
1424         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1425
1426         GrVertex a,b;
1427
1428         a.x = i2fl(fl2i(x1)) + gr_screen.offset_x;
1429         a.y = i2fl(fl2i(y1)) + gr_screen.offset_y;
1430         a.r = i2fl(gr_screen.current_color.red);
1431         a.g = i2fl(gr_screen.current_color.green);
1432         a.b = i2fl(gr_screen.current_color.blue);
1433         a.a = i2fl(gr_screen.current_color.alpha);
1434
1435         b.x = i2fl(fl2i(x2)) + gr_screen.offset_x;
1436         b.y = i2fl(fl2i(y2)) + gr_screen.offset_y;
1437         b.r = i2fl(gr_screen.current_color.red);
1438         b.g = i2fl(gr_screen.current_color.green);
1439         b.b = i2fl(gr_screen.current_color.blue);
1440         b.a = i2fl(gr_screen.current_color.alpha);
1441
1442         if (a.x<b.x) {
1443                 a.x+=0.5f;
1444                 b.x+=1.0f;
1445         } else {
1446                 b.x+=0.5f;
1447                 a.x+=1.0f;
1448         }
1449
1450         if (a.y<b.y)    {
1451                 a.y+=0.5f;
1452                 b.y+=1.0f;
1453         } else {
1454                 b.y+=0.5f;
1455                 a.y+=1.0f;
1456         }
1457
1458         grAADrawLine(&a, &b);
1459 }
1460
1461 void gr_glide_tmapper_internal( int nv, vertex * verts[], uint flags, int is_scaler )
1462 {
1463         GrVertex GrVerts[25];
1464         int i;
1465         float Glide_u_ratio = 0.0f;
1466         float Glide_v_ratio = 0.0f;
1467
1468         if(VOODOO3_INACTIVE()){
1469                 return;
1470         }
1471
1472         // Make nebula use the texture mapper... this blends the colors better.
1473         if ( flags & TMAP_FLAG_NEBULA ) {
1474                 Int3();
1475                 /*
1476                 flags |= TMAP_FLAG_TEXTURED;
1477
1478                 static int test_bmp = -1;
1479                 static ushort data[16];         
1480                 if ( test_bmp == -1 ){
1481                         ushort pix;
1482                         ubyte a, r, g, b;
1483                         int idx;
1484                         
1485                         // stuff the fake bitmap
1486                         a = 1; r = 255; g = 255; b = 255;
1487                         pix = 0;
1488                         bm_set_components((ubyte*)&pix, &r, &g, &b, &a);                        
1489                         for(idx=0; idx<16; idx++){
1490                                 data[idx] = pix;
1491                         }                       
1492                         test_bmp = bm_create( 16, 4, 4, data );
1493                 }
1494                 gr_set_bitmap( test_bmp );
1495
1496                 for (i=0; i<nv; i++ )   {
1497                         verts[i]->u = verts[i]->v = 0.5f;
1498                 }
1499                 */
1500         }
1501
1502         gr_texture_source texture_source = (gr_texture_source)-1;
1503         gr_color_source color_source = (gr_color_source)-1;
1504         gr_alpha_source alpha_source = (gr_alpha_source)-1;
1505         gr_alpha_blend alpha_blend = (gr_alpha_blend)-1;
1506         gr_zbuffer_type zbuffer_type = (gr_zbuffer_type)-1;
1507
1508         if ( gr_zbuffering )    {
1509                 if ( is_scaler || (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER)   )       {
1510                         zbuffer_type = ZBUFFER_TYPE_READ;
1511                 } else {
1512                         zbuffer_type = ZBUFFER_TYPE_FULL;
1513                 }
1514         } else {
1515                 zbuffer_type = ZBUFFER_TYPE_NONE;
1516         }
1517
1518         float alpha;
1519
1520         alpha_source = ALPHA_SOURCE_VERTEX;
1521
1522         switch(gr_screen.current_alphablend_mode){
1523         case GR_ALPHABLEND_FILTER:
1524                 // Blend with screen pixel using src*alpha+dst                          
1525                 if ( gr_screen.current_alpha > 1.0f )   {
1526                         alpha_blend = ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR;
1527                         alpha = 255.0f;
1528                 } else {
1529                         alpha_blend = ALPHA_BLEND_ALPHA_ADDITIVE;
1530                         alpha = gr_screen.current_alpha*255.0f;
1531                 }
1532                 break;  
1533
1534         default :       
1535                 alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA;
1536                 alpha = 255.0f;
1537                 break;
1538         }
1539
1540         if ( flags & TMAP_FLAG_TEXTURED )       {
1541                 int texture_type = TCACHE_TYPE_NORMAL;
1542
1543                 if ( flags & TMAP_FLAG_NONDARKENING )   {
1544                         alpha_source = ALPHA_SOURCE_VERTEX_NONDARKENING;                        
1545                         //alpha_source = ALPHA_SOURCE_VERTEX_TIMES_TEXTURE;
1546                         texture_type = TCACHE_TYPE_NONDARKENING;
1547                 } else {                        
1548                         alpha_source = ALPHA_SOURCE_VERTEX_TIMES_TEXTURE;
1549                         texture_type = TCACHE_TYPE_XPARENT;
1550                 }
1551
1552                 // common settings
1553                 color_source = COLOR_SOURCE_VERTEX_TIMES_TEXTURE;
1554                 texture_source = TEXTURE_SOURCE_DECAL;
1555
1556                 // force texture type
1557                 if(flags & TMAP_FLAG_BITMAP_SECTION){
1558                         texture_type = TCACHE_TYPE_BITMAP_SECTION;
1559                 }
1560                 
1561                 if ( !gr_tcache_set( gr_screen.current_bitmap, texture_type, &Glide_u_ratio, &Glide_v_ratio, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy ))     {
1562                         // Error setting texture!
1563                         mprintf(( "GLIDE: Error setting texture!\n" ));
1564                         // Mark as no texturing
1565                         color_source = COLOR_SOURCE_VERTEX;
1566                         texture_source = TEXTURE_SOURCE_NONE;
1567                 }               
1568         } else {
1569                 color_source = COLOR_SOURCE_VERTEX;             
1570                 texture_source = TEXTURE_SOURCE_NONE;
1571                 if(flags & TMAP_FLAG_ALPHA){
1572                         alpha_source = ALPHA_SOURCE_VERTEX;
1573                 }
1574         }
1575
1576 //      zbuffer_type = ZBUFFER_TYPE_NONE;
1577 //      alpha_source = ALPHA_SOURCE_VERTEX;
1578 //      alpha_blend = ALPHA_BLEND_NONE;
1579 //      alpha = 255.0f;
1580 //      color_source = COLOR_SOURCE_VERTEX;
1581 //      texture_source = TEXTURE_SOURCE_NONE;   
1582         gr_glide_set_state( texture_source, color_source, alpha_source, alpha_blend, zbuffer_type );
1583
1584         int x1, y1, x2, y2;
1585         x1 = gr_screen.clip_left*16;
1586         x2 = gr_screen.clip_right*16+15;
1587         y1 = gr_screen.clip_top*16;
1588         y2 = gr_screen.clip_bottom*16+15;       
1589         
1590 //      memset( GrVerts, 0, sizeof(GrVertex) * 25 );
1591
1592         for (i=0; i<nv; i++ )   {
1593                 if ( flags & TMAP_FLAG_ALPHA )  {                       
1594                         GrVerts[i].a = i2fl(verts[i]->a);                                                       
1595                 } else {
1596                         GrVerts[i].a = alpha;
1597                 }
1598
1599                 if ( flags & TMAP_FLAG_NEBULA ) {
1600                         int pal = (verts[i]->b*(NEBULA_COLORS-1))/255;
1601                         GrVerts[i].r = i2fl(gr_palette[pal*3+0]);
1602                         GrVerts[i].g = i2fl(gr_palette[pal*3+1]);
1603                         GrVerts[i].b = i2fl(gr_palette[pal*3+2]);
1604                 } else if ( (flags & TMAP_FLAG_RAMP) && (flags & TMAP_FLAG_GOURAUD) )   {
1605                         GrVerts[i].r = Gr_gamma_lookup_float[verts[i]->b];
1606                         GrVerts[i].g = Gr_gamma_lookup_float[verts[i]->b];
1607                         GrVerts[i].b = Gr_gamma_lookup_float[verts[i]->b];
1608                 } else if ( (flags & TMAP_FLAG_RGB)  && (flags & TMAP_FLAG_GOURAUD) )   {                       
1609                         // Make 0.75 be 256.0f
1610                         GrVerts[i].r = Gr_gamma_lookup_float[verts[i]->r];
1611                         GrVerts[i].g = Gr_gamma_lookup_float[verts[i]->g];
1612                         GrVerts[i].b = Gr_gamma_lookup_float[verts[i]->b];
1613                 } else  {
1614                         if ( flags & TMAP_FLAG_TEXTURED )       {
1615                                 GrVerts[i].r = 255.0f;
1616                                 GrVerts[i].g = 255.0f;
1617                                 GrVerts[i].b = 255.0f;
1618                         } else {
1619                                 GrVerts[i].r = i2fl(gr_screen.current_color.red);
1620                                 GrVerts[i].g = i2fl(gr_screen.current_color.green);
1621                                 GrVerts[i].b = i2fl(gr_screen.current_color.blue);
1622                         }
1623                 }
1624
1625                 int x, y;
1626                 x = fl2i(verts[i]->sx*16.0f);
1627                 y = fl2i(verts[i]->sy*16.0f);
1628
1629                 if ( flags & TMAP_FLAG_CORRECT )        {
1630                         // "clip" it 
1631                         if ( x < x1 ) {
1632                                 x = x1;
1633                         } else if ( x > x2 )    {
1634                                 x = x2;
1635                         }
1636                         if ( y < y1 )   {
1637                                 y = y1;
1638                         } else if ( y > y2 )    {
1639                                 y = y2;
1640                         }
1641                 }
1642
1643                 x += gr_screen.offset_x*16;
1644                 y += gr_screen.offset_y*16;
1645                 
1646                 GrVerts[i].x = i2fl(x) / 16.0f;
1647                 GrVerts[i].y = i2fl(y) / 16.0f;
1648
1649                 //verts[i]->sw = 1.0f;
1650
1651                 GrVerts[i].oow=verts[i]->sw;
1652         
1653                 if ( flags & TMAP_FLAG_TEXTURED )       {
1654                         GrVerts[i].tmuvtx[GR_TMU0].oow=verts[i]->sw;
1655                         GrVerts[i].tmuvtx[GR_TMU0].sow=verts[i]->u * verts[i]->sw * Glide_u_ratio;
1656                         GrVerts[i].tmuvtx[GR_TMU0].tow=verts[i]->v * verts[i]->sw * Glide_v_ratio;
1657                 }
1658         }
1659
1660         // if we're rendering against a fullneb background
1661         if(flags & TMAP_FLAG_PIXEL_FOG){        
1662                 int r, g, b;
1663                 int ra, ga, ba;         
1664                 ra = ga = ba = 0;               
1665
1666                 // get the average pixel color behind the vertices
1667                 for(i=0; i<nv; i++){                    
1668                         neb2_get_pixel((int)GrVerts[i].x, (int)GrVerts[i].y, &r, &g, &b);
1669                         ra += r;
1670                         ga += g;
1671                         ba += b;
1672                 }               
1673                 
1674                 ra /= nv;
1675                 ga /= nv;
1676                 ba /= nv;               
1677
1678                 // set fog
1679                 gr_fog_set(GR_FOGMODE_FOG, ra, ga, ba);
1680         }
1681                                         
1682         if ( flags & TMAP_FLAG_CORRECT )        {
1683                 grDrawPolygonVertexList( nv, GrVerts );
1684         } else {
1685                 for (i=1; i<nv-1; i++ ) {
1686                         guDrawTriangleWithClip(&GrVerts[0],&GrVerts[i],&GrVerts[i+1]);
1687                 }
1688         } 
1689
1690         // turn off fog
1691         // if(flags & TMAP_FLAG_PIXEL_FOG){
1692                 // gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
1693         // }
1694 }
1695
1696 void gr_glide_tmapper( int nv, vertex * verts[], uint flags )
1697 {
1698         gr_glide_tmapper_internal( nv, verts, flags, 0 );
1699 }
1700
1701 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (((((x)-(x0))*((y1)-(y0)))/((x1)-(x0)))+(y0))
1702
1703 void gr_glide_aascaler(vertex *va, vertex *vb )
1704 {
1705                                         
1706 }
1707
1708 void gr_glide_scaler(vertex *va, vertex *vb )
1709 {
1710         float x0, y0, x1, y1;
1711         float u0, v0, u1, v1;
1712         float clipped_x0, clipped_y0, clipped_x1, clipped_y1;
1713         float clipped_u0, clipped_v0, clipped_u1, clipped_v1;
1714         float xmin, xmax, ymin, ymax;
1715         int dx0, dy0, dx1, dy1;
1716
1717         if(VOODOO3_INACTIVE()){
1718                 return;
1719         }
1720
1721         //============= CLIP IT =====================
1722
1723         x0 = va->sx; y0 = va->sy;
1724         x1 = vb->sx; y1 = vb->sy;
1725
1726         xmin = i2fl(gr_screen.clip_left); ymin = i2fl(gr_screen.clip_top);
1727         xmax = i2fl(gr_screen.clip_right); ymax = i2fl(gr_screen.clip_bottom);
1728
1729         u0 = va->u; v0 = va->v;
1730         u1 = vb->u; v1 = vb->v;
1731
1732         // Check for obviously offscreen bitmaps...
1733         if ( (y1<=y0) || (x1<=x0) ) return;
1734         if ( (x1<xmin ) || (x0>xmax) ) return;
1735         if ( (y1<ymin ) || (y0>ymax) ) return;
1736
1737         clipped_u0 = u0; clipped_v0 = v0;
1738         clipped_u1 = u1; clipped_v1 = v1;
1739
1740         clipped_x0 = x0; clipped_y0 = y0;
1741         clipped_x1 = x1; clipped_y1 = y1;
1742
1743         // Clip the left, moving u0 right as necessary
1744         if ( x0 < xmin )        {
1745                 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
1746                 clipped_x0 = xmin;
1747         }
1748
1749         // Clip the right, moving u1 left as necessary
1750         if ( x1 > xmax )        {
1751                 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
1752                 clipped_x1 = xmax;
1753         }
1754
1755         // Clip the top, moving v0 down as necessary
1756         if ( y0 < ymin )        {
1757                 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
1758                 clipped_y0 = ymin;
1759         }
1760
1761         // Clip the bottom, moving v1 up as necessary
1762         if ( y1 > ymax )        {
1763                 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
1764                 clipped_y1 = ymax;
1765         }
1766         
1767         dx0 = fl2i(clipped_x0); dx1 = fl2i(clipped_x1);
1768         dy0 = fl2i(clipped_y0); dy1 = fl2i(clipped_y1);
1769
1770         if (dx1<=dx0) return;
1771         if (dy1<=dy0) return;
1772
1773         //============= DRAW IT =====================
1774
1775         vertex v[4];
1776         vertex *vl[4];
1777
1778         vl[0] = &v[0];  
1779         v->sx = clipped_x0;
1780         v->sy = clipped_y0;
1781         v->sw = va->sw;
1782         v->z = va->z;
1783         v->u = clipped_u0;
1784         v->v = clipped_v0;
1785
1786         vl[1] = &v[1];  
1787         v[1].sx = clipped_x1;
1788         v[1].sy = clipped_y0;
1789         v[1].sw = va->sw;
1790         v[1].z = va->z;
1791         v[1].u = clipped_u1;
1792         v[1].v = clipped_v0;
1793
1794         vl[2] = &v[2];  
1795         v[2].sx = clipped_x1;
1796         v[2].sy = clipped_y1;
1797         v[2].sw = va->sw;
1798         v[2].z = va->z;
1799         v[2].u = clipped_u1;
1800         v[2].v = clipped_v1;
1801
1802         vl[3] = &v[3];  
1803         v[3].sx = clipped_x0;
1804         v[3].sy = clipped_y1;
1805         v[3].sw = va->sw;
1806         v[3].z = va->z;
1807         v[3].u = clipped_u0;
1808         v[3].v = clipped_v1;
1809
1810         //glide_zbuffering(0);
1811         gr_glide_tmapper_internal( 4, vl, TMAP_FLAG_TEXTURED, 1 );
1812 }
1813
1814
1815 void gr_glide_aabitmap_ex_new(int x,int y,int w,int h,int sx,int sy)
1816 {
1817         if ( w < 1 ) return;
1818         if ( h < 1 ) return;
1819
1820         if ( !gr_screen.current_color.is_alphacolor )   return;
1821
1822         if(VOODOO3_INACTIVE()){
1823                 return;
1824         }
1825
1826 //      mprintf(( "x=%d, y=%d, w=%d, h=%d\n", x, y, w, h ));
1827 //      mprintf(( "sx=%d, sy=%d, bw=%d, bh=%d\n", sx, sy, bmp->w, bmp->h ));
1828
1829         float Glide_u_ratio;
1830         float Glide_v_ratio;
1831
1832         // Set up Render State - flat shading - alpha blending
1833         gr_glide_set_state( TEXTURE_SOURCE_DECAL, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX_TIMES_TEXTURE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1834
1835         if ( !gr_tcache_set( gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP, &Glide_u_ratio, &Glide_v_ratio ) ) {
1836                 // Couldn't set texture
1837                 mprintf(( "GLIDE: Error setting aabitmap texture!\n" ));
1838                 return;
1839         }
1840
1841         GrVertex GrVerts[4];
1842
1843         float u0, u1, v0, v1;
1844         float r,g,b,a;
1845
1846         r = i2fl(gr_screen.current_color.red);
1847         g = i2fl(gr_screen.current_color.green);
1848         b = i2fl(gr_screen.current_color.blue);
1849         a = i2fl(gr_screen.current_color.alpha);
1850
1851         int bw, bh;
1852
1853         bm_get_info( gr_screen.current_bitmap, &bw, &bh );
1854         
1855         u0 = Glide_u_ratio*i2fl(sx)/i2fl(bw);
1856         v0 = Glide_v_ratio*i2fl(sy)/i2fl(bh);
1857
1858         u1 = Glide_u_ratio*i2fl(sx+w)/i2fl(bw);
1859         v1 = Glide_v_ratio*i2fl(sy+h)/i2fl(bh);
1860
1861         float x1, x2, y1, y2;
1862         x1 = i2fl(x+gr_screen.offset_x);
1863         y1 = i2fl(y+gr_screen.offset_y);
1864         x2 = i2fl(x+w+gr_screen.offset_x);
1865         y2 = i2fl(y+h+gr_screen.offset_y);
1866
1867         int i;
1868
1869         i = 0;
1870         GrVerts[i].x = x1;
1871         GrVerts[i].y = y1;
1872         GrVerts[i].oow = 1.0f;
1873         GrVerts[i].r = r;
1874         GrVerts[i].g = g;
1875         GrVerts[i].b = b;
1876         GrVerts[i].a = a;
1877         GrVerts[i].tmuvtx[GR_TMU0].sow=u0;
1878         GrVerts[i].tmuvtx[GR_TMU0].tow=v0;
1879
1880         i = 1;
1881         GrVerts[i].x = x2;
1882         GrVerts[i].y = y1;
1883         GrVerts[i].oow = 1.0f;
1884         GrVerts[i].r = r;
1885         GrVerts[i].g = g;
1886         GrVerts[i].b = b;
1887         GrVerts[i].a = a;
1888         GrVerts[i].tmuvtx[GR_TMU0].sow=u1;
1889         GrVerts[i].tmuvtx[GR_TMU0].tow=v0;
1890
1891         i = 2;
1892         GrVerts[i].x = x2;
1893         GrVerts[i].y = y2;
1894         GrVerts[i].oow = 1.0f;
1895         GrVerts[i].r = r;
1896         GrVerts[i].g = g;
1897         GrVerts[i].b = b;
1898         GrVerts[i].a = a;
1899         GrVerts[i].tmuvtx[GR_TMU0].sow=u1;
1900         GrVerts[i].tmuvtx[GR_TMU0].tow=v1;
1901
1902         i = 3;
1903         GrVerts[i].x = x1;
1904         GrVerts[i].y = y2;
1905         GrVerts[i].oow = 1.0f;
1906         GrVerts[i].r = r;
1907         GrVerts[i].g = g;
1908         GrVerts[i].b = b;
1909         GrVerts[i].a = a;
1910         GrVerts[i].tmuvtx[GR_TMU0].sow=u0;
1911         GrVerts[i].tmuvtx[GR_TMU0].tow=v1;
1912
1913         grDrawPolygonVertexList( 4, GrVerts );
1914 }
1915
1916
1917
1918 void gr_glide_aabitmap_ex(int x,int y,int w,int h,int sx,int sy)
1919 {
1920         int reclip;
1921         #ifndef NDEBUG
1922         int count = 0;
1923         #endif
1924
1925         int dx1=x, dx2=x+w-1;
1926         int dy1=y, dy2=y+h-1;
1927
1928         int bw, bh;
1929         bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
1930
1931         do {
1932                 reclip = 0;
1933                 #ifndef NDEBUG
1934                         if ( count > 1 ) Int3();
1935                         count++;
1936                 #endif
1937         
1938                 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1939                 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1940                 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1941                 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1942                 if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
1943                 if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
1944
1945                 if ( sx < 0 ) {
1946                         dx1 -= sx;
1947                         sx = 0;
1948                         reclip = 1;
1949                 }
1950
1951                 if ( sy < 0 ) {
1952                         dy1 -= sy;
1953                         sy = 0;
1954                         reclip = 1;
1955                 }
1956
1957                 w = dx2-dx1+1;
1958                 h = dy2-dy1+1;
1959
1960                 if ( sx + w > bw ) {
1961                         w = bw - sx;
1962                         dx2 = dx1 + w - 1;
1963                 }
1964
1965                 if ( sy + h > bh ) {
1966                         h = bh - sy;
1967                         dy2 = dy1 + h - 1;
1968                 }
1969
1970                 if ( w < 1 ) return;            // clipped away!
1971                 if ( h < 1 ) return;            // clipped away!
1972
1973         } while (reclip);
1974
1975         // Make sure clipping algorithm works
1976         #ifndef NDEBUG
1977                 Assert( w > 0 );
1978                 Assert( h > 0 );
1979                 Assert( w == (dx2-dx1+1) );
1980                 Assert( h == (dy2-dy1+1) );
1981                 Assert( sx >= 0 );
1982                 Assert( sy >= 0 );
1983                 Assert( sx+w <= bw );
1984                 Assert( sy+h <= bh );
1985                 Assert( dx2 >= dx1 );
1986                 Assert( dy2 >= dy1 );
1987                 Assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
1988                 Assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
1989                 Assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
1990                 Assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
1991         #endif
1992
1993         // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
1994
1995         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1996         gr_glide_aabitmap_ex_new(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1997 }
1998
1999 void gr_glide_string_hack( int sx, int sy, char *s )
2000 {
2001         int width, spacing, letter;
2002         int x, y;
2003
2004         if ( !Current_font )    {
2005                 return;
2006         }
2007
2008         gr_set_bitmap(Current_font->bitmap_id);
2009
2010         x = sx;
2011         y = sy;
2012
2013         if (sx==0x8000) {                       //centered
2014                 x = get_centered_x(s);
2015         } else {
2016                 x = sx;
2017         }
2018
2019         spacing = 0;
2020
2021         while (*s)      {
2022
2023                 x += spacing;
2024
2025                 while (*s== '\n' )      {
2026                         s++;
2027                         y += Current_font->h;
2028                         if (sx==0x8000) {                       //centered
2029                                 x = get_centered_x(s);
2030                         } else {
2031                                 x = sx;
2032                         }
2033                 }
2034                 if (*s == 0 ) break;
2035
2036                 letter = get_char_width(s[0],s[1],&width,&spacing);
2037                 s++;
2038
2039                 if (letter<0) { //not in font, draw as space
2040                         continue;
2041                 }
2042
2043                 // formerly a call to gr_glide_char(...)
2044                 {
2045                         font_char *ch;
2046         
2047                         ch = &Current_font->char_data[letter];
2048                         
2049                         int _sx = Current_font->bm_u[letter];
2050                         int _sy = Current_font->bm_v[letter];
2051
2052                         gr_glide_aabitmap_ex( x, y, ch->byte_width, Current_font->h, _sx, _sy );
2053                 }               
2054         }
2055 }
2056
2057 void gr_glide_aabitmap(int x, int y)
2058 {
2059         int w, h;
2060
2061         bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
2062         int dx1=x, dx2=x+w-1;
2063         int dy1=y, dy2=y+h-1;
2064         int sx=0, sy=0;
2065
2066         if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
2067         if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
2068         if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
2069         if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
2070         if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
2071         if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
2072
2073         if ( sx < 0 ) return;
2074         if ( sy < 0 ) return;
2075         if ( sx >= w ) return;
2076         if ( sy >= h ) return;
2077
2078         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
2079         gr_aabitmap_ex(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
2080 }
2081
2082
2083 void gr_glide_gradient(int x1,int y1,int x2,int y2)
2084 {
2085         int clipped = 0, swapped=0;
2086
2087         if(VOODOO3_INACTIVE()){
2088                 return;
2089         }
2090
2091         if ( !gr_screen.current_color.is_alphacolor )   {
2092                 gr_line( x1, y1, x2, y2 );
2093                 return;
2094         }
2095
2096         INT_CLIPLINE(x1,y1,x2,y2,gr_screen.clip_left,gr_screen.clip_top,gr_screen.clip_right,gr_screen.clip_bottom,return,clipped=1,swapped=1);   
2097
2098         // Set up Render State - flat shading - alpha blending
2099         gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
2100
2101         GrVertex a,b;
2102
2103         a.x = i2fl(x1 + gr_screen.offset_x);
2104         a.y = i2fl(y1 + gr_screen.offset_y);
2105         a.r = i2fl(gr_screen.current_color.red);
2106         a.g = i2fl(gr_screen.current_color.green);
2107         a.b = i2fl(gr_screen.current_color.blue);
2108
2109         b.x = i2fl(x2 + gr_screen.offset_x);
2110         b.y = i2fl(y2 + gr_screen.offset_y);
2111         b.r = i2fl(gr_screen.current_color.red);
2112         b.g = i2fl(gr_screen.current_color.green);
2113         b.b = i2fl(gr_screen.current_color.blue);
2114
2115         if ( swapped )  {
2116                 a.a = 0.0f;
2117                 b.a = i2fl(gr_screen.current_color.alpha);
2118         } else {
2119                 b.a = 0.0f;
2120                 a.a = i2fl(gr_screen.current_color.alpha);
2121         }
2122
2123         if (a.x<b.x) {
2124                 a.x+=0.5f;
2125                 b.x+=1.0f;
2126         } else {
2127                 b.x+=0.5f;
2128                 a.x+=1.0f;
2129         }
2130
2131         if (a.y<b.y)    {
2132                 a.y+=0.5f;
2133                 b.y+=1.0f;
2134         } else {
2135                 b.y+=0.5f;
2136                 a.y+=1.0f;
2137         }
2138
2139         grDrawLine(&a, &b);
2140 }
2141
2142 void gr_glide_set_palette(ubyte *new_palette, int force_flag )
2143 {
2144         gr_palette_faded_out = 0;
2145
2146         if(VOODOO3_INACTIVE()){
2147                 return;
2148         }
2149
2150 #ifdef USE_8BPP_TEXTURES
2151         GuTexPalette palette;
2152
2153         glide_free_textures();
2154
2155         int i;
2156
2157         for (i=0;i<256; i++ )   {
2158                 palette.data[i] = 0xFF000000;
2159                 palette.data[i] |= new_palette[i*3+2];
2160                 palette.data[i] |= new_palette[i*3+1]<<8;
2161                 palette.data[i] |= new_palette[i*3+0]<<16;
2162         }
2163
2164         grTexDownloadTable( GR_TMU0, GR_TEXTABLE_PALETTE, &palette );           
2165 #endif
2166         
2167 }
2168
2169 void gr_glide_init_color(color *c, int r, int g, int b)
2170 {
2171         c->screen_sig = gr_screen.signature;
2172         c->red = unsigned char(r);
2173         c->green = unsigned char(g);
2174         c->blue = unsigned char(b);
2175         c->alpha = 255;
2176         c->ac_type = AC_TYPE_NONE;
2177         c->alphacolor = -1;
2178         c->is_alphacolor = 0;
2179         c->magic = 0xAC01;
2180 }
2181
2182 void gr_glide_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type )
2183 {
2184         if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
2185         if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
2186         if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
2187         if ( alpha < 0 ) alpha = 0; else if ( alpha > 255 ) alpha = 255;
2188
2189         gr_glide_init_color( clr, r, g, b );
2190
2191         clr->alpha = unsigned char(alpha);
2192         clr->ac_type = (ubyte)type;
2193         clr->alphacolor = -1;
2194         clr->is_alphacolor = 1;
2195 }
2196
2197 void gr_glide_set_color( int r, int g, int b )
2198 {
2199         Assert((r >= 0) && (r < 256));
2200         Assert((g >= 0) && (g < 256));
2201         Assert((b >= 0) && (b < 256));
2202
2203         gr_glide_init_color( &gr_screen.current_color, r, g, b );
2204 }
2205
2206 void gr_glide_get_color( int * r, int * g, int * b )
2207 {
2208         if (r) *r = gr_screen.current_color.red;
2209         if (g) *g = gr_screen.current_color.green;
2210         if (b) *b = gr_screen.current_color.blue;
2211 }
2212
2213 void gr_glide_set_color_fast(color *dst)
2214 {
2215         if ( dst->screen_sig != gr_screen.signature )   {
2216                 if ( dst->is_alphacolor )       {
2217                         gr_glide_init_alphacolor( dst, dst->red, dst->green, dst->blue, dst->alpha, dst->ac_type );
2218                 } else {
2219                         gr_glide_init_color( dst, dst->red, dst->green, dst->blue );
2220                 }
2221         }
2222         gr_screen.current_color = *dst;
2223 }
2224
2225
2226
2227 void gr_glide_flash(int r, int g, int b)
2228 {
2229         int Flash_r = r;  
2230         int Flash_g = g;
2231         int Flash_b = b;
2232
2233         if(VOODOO3_INACTIVE()){
2234                 return;
2235         }
2236
2237         CAP(Flash_r,0,255);
2238         CAP(Flash_g,0,255);
2239         CAP(Flash_b,0,255);
2240
2241         if ( Flash_r || Flash_g || Flash_b )    {
2242                 gr_glide_set_state( TEXTURE_SOURCE_NONE, COLOR_SOURCE_VERTEX, ALPHA_SOURCE_VERTEX, ALPHA_BLEND_ALPHA_ADDITIVE, ZBUFFER_TYPE_NONE );
2243         
2244                 GrVertex GrVerts[4];
2245
2246                 float r,g,b,a;
2247
2248                 r = i2fl(Flash_r);
2249                 g = i2fl(Flash_g);
2250                 b = i2fl(Flash_b);
2251                 a = i2fl(255);
2252
2253                 float x1, x2, y1, y2;
2254                 x1 = i2fl(gr_screen.clip_left+gr_screen.offset_x);
2255                 y1 = i2fl(gr_screen.clip_top+gr_screen.offset_y);
2256                 x2 = i2fl(gr_screen.clip_right+gr_screen.offset_x);
2257                 y2 = i2fl(gr_screen.clip_bottom+gr_screen.offset_y);
2258         
2259                 int i;
2260
2261                 i = 0;
2262                 GrVerts[i].x = x1;
2263                 GrVerts[i].y = y1;
2264                 GrVerts[i].r = r;
2265                 GrVerts[i].g = g;
2266                 GrVerts[i].b = b;
2267                 GrVerts[i].a = a;
2268
2269                 i = 1;
2270                 GrVerts[i].x = x2;
2271                 GrVerts[i].y = y1;
2272                 GrVerts[i].r = r;
2273                 GrVerts[i].g = g;
2274                 GrVerts[i].b = b;
2275                 GrVerts[i].a = a;
2276
2277                 i = 2;
2278                 GrVerts[i].x = x2;
2279                 GrVerts[i].y = y2;
2280                 GrVerts[i].r = r;
2281                 GrVerts[i].g = g;
2282                 GrVerts[i].b = b;
2283                 GrVerts[i].a = a;
2284
2285                 i = 3;
2286                 GrVerts[i].x = x1;
2287                 GrVerts[i].y = y2;
2288                 GrVerts[i].r = r;
2289                 GrVerts[i].g = g;
2290                 GrVerts[i].b = b;
2291                 GrVerts[i].a = a;
2292
2293                 grDrawPolygonVertexList( 4, GrVerts );
2294         }
2295
2296 }
2297
2298
2299
2300 void gr_glide_activate(int active)
2301 {
2302         if (!Glide_running)     {
2303                 return;
2304         }       
2305
2306         mprintf(( "Glide activate: %d\n", active ));
2307
2308         // voodoo3
2309         if(Glide_voodoo3){              
2310                 // choose resolution
2311                 GrScreenResolution_t res_mode;
2312                 if((gr_screen.max_w == 1024) && (gr_screen.max_h == 768)){
2313                         res_mode = GR_RESOLUTION_1024x768;
2314                 } else {
2315                         res_mode = GR_RESOLUTION_640x480;
2316                 }       
2317
2318                 HWND hwnd = (HWND)os_get_window();      
2319                 
2320                 if ( active  )  {                       
2321                         // already active
2322                         if(Glide_deactivate == 0){
2323                                 return;
2324                         }
2325
2326                         Glide_deactivate = 0;
2327
2328                         if ( hwnd )     {                                               
2329                                 SetActiveWindow(hwnd);
2330                                 SetForegroundWindow(hwnd);
2331                                 grSstWinOpen( (DWORD)hwnd, res_mode, GR_REFRESH_60Hz, GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1 );
2332                                 ShowWindow(hwnd,SW_MAXIMIZE);
2333                                 gr_glide_clip_cursor(1);
2334                                 glide_tcache_init();
2335                                 grGammaCorrectionValue(1.0f);                                                           
2336                         }
2337                 } else {                        
2338                         // already deactivated
2339                         if(Glide_deactivate == VOODOO3_DEACTIVATED){
2340                                 return;
2341                         }
2342
2343                         Glide_deactivate = VOODOO3_DEACTIVATED;
2344
2345                         if ( hwnd )     {
2346                                 gr_glide_clip_cursor(0);
2347                                 ShowWindow(hwnd,SW_MINIMIZE);                   
2348                                 grSstWinClose();
2349                         }
2350                 }
2351         } else {
2352                 HWND hwnd = (HWND)os_get_window();
2353         
2354                 if ( active  )  {
2355                         Glide_activate++;                       
2356
2357                         if ( hwnd )     {
2358                                 // SetActiveWindow(hwnd);
2359                                 // SetForegroundWindow(hwnd);                           
2360                                 ShowWindow(hwnd,SW_RESTORE);
2361                                 // gr_glide_clip_cursor(1);
2362                                 // grSstControl(GR_CONTROL_ACTIVATE);                           
2363                         }
2364                 } else {
2365                         Glide_deactivate++;
2366         
2367                         if ( hwnd )     {
2368                                 // grSstControl(GR_CONTROL_DEACTIVATE);
2369                                 ClipCursor(NULL);
2370                                 ShowWindow(hwnd,SW_MINIMIZE);
2371                         }
2372                 }
2373         }       
2374 }
2375
2376
2377 // copy from one pixel buffer to another
2378 //
2379 //    from                      pointer to source buffer
2380 //    to                                pointer to dest. buffet
2381 //    pixels            number of pixels to copy
2382 //    fromsize          source pixel size
2383 //    tosize            dest. pixel size
2384
2385 static int tga_copy_data(char *to, char *from, int pixels, int fromsize, int tosize)
2386 {
2387         int rmask = 0xf800;
2388         int rshift = 11;
2389         int rscale = 8;;
2390         int gmask = 0x7e0;
2391         int gshift = 5;
2392         int gscale = 4;
2393         int bmask = 0x1f;
2394         int bshift = 0;
2395         int bscale = 8;;
2396
2397         if ( (fromsize == 2) && (tosize == 3) ) {
2398                 ushort *src = (ushort *)from;
2399                 ubyte *dst  = (ubyte *)to;
2400
2401                 int i;
2402                 for (i=0; i<pixels; i++ )       {
2403                         ushort pixel = *src++;
2404
2405                         int r,g,b;              
2406                         b = ((pixel & bmask)>>bshift)*bscale;
2407                         g = ((pixel & gmask)>>gshift)*gscale;
2408                         r = ((pixel & rmask)>>rshift)*rscale;
2409
2410                         // Adjust for gamma and output it
2411                         *dst++ = ubyte(b);
2412                         *dst++ = ubyte(g);
2413                         *dst++ = ubyte(r);
2414                 }
2415                 return tosize*pixels;
2416         } else {
2417                 Int3();
2418                 return tosize*pixels;
2419         }
2420 }
2421
2422
2423
2424 //
2425 //      tga_pixels_equal -- Test if two pixels are identical
2426 //
2427 //              Returns:
2428 //                      0 if No Match
2429 //                      1 if Match
2430
2431 static int tga_pixels_equal(char *pix1, char *pix2, int pixbytes)
2432 {
2433         do      {
2434                 if ( *pix1++ != *pix2++ ) {
2435                         return 0;
2436                 }
2437         } while ( --pixbytes > 0 );
2438
2439         return 1;
2440 }
2441
2442
2443 //      tga_compress - Do the Run Length Compression
2444 //
2445 //      Usage:
2446 //                              out                     Buffer to write it out to
2447 //                              in                              Buffer to compress
2448 //                              bytecount       Number of bytes input
2449 //                              pixsize         Number of bytes in input pixel
2450 //                              outsize         Number of bytes in output buffer
2451
2452 int tga_compress(char *out, char *in, int bytecount )
2453 {
2454 #define pixsize 2
2455 #define outsize 3
2456         int pixcount;           // number of pixels in the current packet
2457         char *inputpixel=NULL;  // current input pixel position
2458         char *matchpixel=NULL;  // pixel value to match for a run
2459         char *flagbyte=NULL;            // location of last flag byte to set
2460         int rlcount;            // current count in r.l. string 
2461         int rlthresh;           // minimum valid run length
2462         char *copyloc;          // location to begin copying at
2463
2464         // set the threshold -- the minimum valid run length
2465
2466         #if outsize == 1
2467                 rlthresh = 2;                                   // for 8bpp, require a 2 pixel span before rle'ing
2468         #else
2469                 rlthresh = 1;                   
2470         #endif
2471         
2472         // set the first pixel up
2473
2474         flagbyte = out; // place to put next flag if run
2475         inputpixel = in;
2476         pixcount = 1;
2477         rlcount = 0;
2478         copyloc = (char *)0;
2479
2480         // loop till data processing complete
2481         do      {
2482
2483                 // if we have accumulated a 128-byte packet, process it
2484                 if ( pixcount == 129 )  {
2485                         *flagbyte = 127;
2486
2487                         // set the run flag if this is a run
2488
2489                         if ( rlcount >= rlthresh )      {
2490                                         *flagbyte |= 0x80;
2491                                         pixcount = 2;
2492                         }
2493
2494                         // copy the data into place
2495                         ++flagbyte;
2496                         flagbyte += tga_copy_data(flagbyte, copyloc, pixcount-1, pixsize, outsize);
2497                         pixcount = 1;
2498
2499                         // set up for next packet
2500                         continue;
2501                 }
2502
2503                 // if zeroth byte, handle as special case
2504                 if ( pixcount == 1 )    {
2505                         rlcount = 0;
2506                         copyloc = inputpixel;           /* point to 1st guy in packet */
2507                         matchpixel = inputpixel;        /* set pointer to pix to match */
2508                         pixcount = 2;
2509                         inputpixel += pixsize;
2510                         continue;
2511                 }
2512
2513                 // assembling a packet -- look at next pixel
2514
2515                 // current pixel == match pixel?
2516                 if ( tga_pixels_equal(inputpixel, matchpixel, outsize) )        {
2517
2518                         //      establishing a run of enough length to
2519                         //      save space by doing it
2520                         //              -- write the non-run length packet
2521                         //              -- start run-length packet
2522
2523                         if ( ++rlcount == rlthresh )    {
2524                                 
2525                                 //      close a non-run packet
2526                                 
2527                                 if ( pixcount > (rlcount+1) )   {
2528                                         // write out length and do not set run flag
2529
2530                                         *flagbyte++ = (char)(pixcount - 2 - rlthresh);
2531
2532                                         flagbyte += tga_copy_data(flagbyte, copyloc, (pixcount-1-rlcount), pixsize, outsize);
2533
2534                                         copyloc = inputpixel;
2535                                         pixcount = rlcount + 1;
2536                                 }
2537                         }
2538                 } else {
2539
2540                         // no match -- either break a run or continue without one
2541                         //      if a run exists break it:
2542                         //              write the bytes in the string (outsize+1)
2543                         //              start the next string
2544
2545                         if ( rlcount >= rlthresh )      {
2546
2547                                 *flagbyte++ = (char)(0x80 | rlcount);
2548                                 flagbyte += tga_copy_data(flagbyte, copyloc, 1, pixsize, outsize);
2549                                 pixcount = 1;
2550                                 continue;
2551                         } else {
2552
2553                                 //      not a match and currently not a run
2554                                 //              - save the current pixel
2555                                 //              - reset the run-length flag
2556                                 rlcount = 0;
2557                                 matchpixel = inputpixel;
2558                         }
2559                 }
2560                 pixcount++;
2561                 inputpixel += pixsize;
2562         } while ( inputpixel < (in + bytecount));
2563
2564         // quit this buffer without loosing any data
2565
2566         if ( --pixcount >= 1 )  {
2567                 *flagbyte = (char)(pixcount - 1);
2568                 if ( rlcount >= rlthresh )      {
2569                         *flagbyte |= 0x80;
2570                         pixcount = 1;
2571                 }
2572
2573                 // copy the data into place
2574                 ++flagbyte;
2575                 flagbyte += tga_copy_data(flagbyte, copyloc, pixcount, pixsize, outsize);
2576         }
2577         return(flagbyte-out);
2578 }
2579
2580
2581
2582 void gr_glide_print_screen(char *filename)
2583 {
2584         GrLfbInfo_t info;
2585         int i;
2586         ubyte outrow[1024*3*4];
2587
2588         if(VOODOO3_INACTIVE()){
2589                 return;
2590         }
2591
2592         if ( gr_screen.max_w > 1024 )   {
2593                 mprintf(( "Screen too wide for print_screen\n" ));
2594                 return;
2595         }
2596
2597         info.size=sizeof(GrLfbInfo_t);
2598
2599         // get a read pointer 
2600         if ( grLfbLock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565,
2601                                                         GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))          {
2602                 int w=gr_screen.max_w,h=gr_screen.max_h;
2603                 ushort *rptr;
2604                 int short_per_row=info.strideInBytes/2;
2605
2606                 rptr = (ushort *)info.lfbPtr;
2607
2608
2609                 char tmp[1024];
2610
2611                 strcpy( tmp, NOX(".\\"));       // specify a path mean files goes in root
2612                 strcat( tmp, filename );
2613                 strcat( tmp, NOX(".tga"));
2614
2615                 CFILE *f = cfopen(tmp, "wb");
2616
2617                 // Write the TGA header
2618                 cfwrite_ubyte( 0, f );  //      IDLength;
2619                 cfwrite_ubyte( 0, f );  //      ColorMapType;
2620                 cfwrite_ubyte( 10, f ); //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
2621                 cfwrite_ushort( 0, f ); // CMapStart;
2622                 cfwrite_ushort( 0, f ); //      CMapLength;
2623                 cfwrite_ubyte( 0, f );  // CMapDepth;
2624                 cfwrite_ushort( 0, f ); //      XOffset;
2625                 cfwrite_ushort( 0, f ); //      YOffset;
2626                 cfwrite_ushort( (ushort)w, f ); //      Width;
2627                 cfwrite_ushort( (ushort)h, f ); //      Height;
2628                 cfwrite_ubyte( 24, f ); //PixelDepth;
2629                 cfwrite_ubyte( 0, f );  //ImageDesc;
2630
2631                 // Go through and read our pixels
2632                 for (i=0;i<h;i++)       {
2633                         int len = tga_compress( (char *)outrow, (char *)&rptr[(h-i-1)*short_per_row], w*sizeof(short) );
2634
2635                         cfwrite(outrow,len,1,f);
2636                 }
2637
2638                 cfclose(f);
2639
2640                 // Release the lock
2641                 grLfbUnlock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER );
2642         } else {
2643                 mprintf(( "Couldn't get a lock to glide's back buffer!\n" ));
2644                 Int3();
2645         }
2646
2647 }
2648
2649 int gr_glide_save_screen_internal(ushort *src_data)
2650 {
2651         GrLfbInfo_t info;
2652         int i;
2653
2654         if(VOODOO3_INACTIVE()){
2655                 return 0;
2656         }
2657
2658         info.size=sizeof(GrLfbInfo_t);
2659
2660         // get a read pointer 
2661         if ( grLfbLock( GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER, GR_LFBWRITEMODE_565,
2662                                                         GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))          {
2663                 int w=gr_screen.max_w,h=gr_screen.max_h;
2664                 ushort *rptr;
2665                 int short_per_row=info.strideInBytes/2;
2666
2667                 rptr = (ushort *)info.lfbPtr;
2668
2669                 // Go through and read our pixels
2670                 for (i=0;i<h;i++)       {
2671                         memcpy( &src_data[gr_screen.max_w*i], &rptr[i*short_per_row], w*sizeof(short) );
2672                 }
2673
2674                 // Release the lock
2675                 grLfbUnlock( GR_LFB_READ_ONLY, GR_BUFFER_FRONTBUFFER );
2676         } else {
2677                 mprintf(( "Couldn't get a read lock to glide's back buffer!\n" ));
2678                 return 0;
2679         }
2680         return 1;
2681 }
2682
2683
2684 static ushort *Gr_saved_screen = NULL;
2685
2686 int gr_glide_save_screen()
2687 {
2688         if(VOODOO3_INACTIVE()){
2689                 return -1;
2690         }       
2691
2692         if ( Gr_saved_screen )  {
2693                 mprintf(( "Screen alread saved!\n" ));
2694                 return -1;
2695         }
2696
2697         gr_reset_clip();
2698
2699         Gr_saved_screen = (ushort *)malloc( gr_screen.max_w*gr_screen.max_h*sizeof(ushort) );
2700         if (!Gr_saved_screen) {
2701                 mprintf(( "Couldn't get memory for saved screen!\n" ));
2702                 return -1;
2703         }
2704
2705         if ( !gr_glide_save_screen_internal(Gr_saved_screen) )  {
2706                 free(Gr_saved_screen);
2707                 Gr_saved_screen = NULL;
2708                 return -1;
2709         }
2710
2711         if ( Gr_glide_mouse_saved )     {
2712                 ushort *sptr, *dptr;
2713
2714                 sptr = Gr_glide_mouse_saved_data;
2715
2716                 for (int i=0; i<Gr_glide_mouse_saved_h; i++ )   {
2717                         dptr = &Gr_saved_screen[(Gr_glide_mouse_saved_y1+i)*gr_screen.max_w+Gr_glide_mouse_saved_x1];
2718
2719                         for(int j=0; j<Gr_glide_mouse_saved_w; j++ )    {
2720                                 *dptr++ = *sptr++;
2721                         }
2722                 }
2723         }
2724
2725         return 0;
2726 }
2727
2728 void gr_glide_restore_screen_internal(ushort *src_data)
2729 {
2730         GrLfbInfo_t info;
2731         int i;
2732
2733         if(VOODOO3_INACTIVE()){
2734                 return;
2735         }
2736
2737         info.size=sizeof(GrLfbInfo_t);
2738
2739         // get a read pointer 
2740         if ( grLfbLock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565,
2741                                                         GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))          {
2742                 int w=gr_screen.max_w,h=gr_screen.max_h;
2743                 ushort *rptr;
2744                 int short_per_row=info.strideInBytes/2;
2745
2746                 rptr = (ushort *)info.lfbPtr;
2747
2748                 // Go through and read our pixels
2749                 for (i=0;i<h;i++)       {
2750                         memcpy( &rptr[i*short_per_row], &src_data[gr_screen.max_w*i], w*sizeof(short) );
2751                 }
2752
2753                 // Release the lock
2754                 grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER );
2755         } else {
2756                 mprintf(( "Couldn't get a write lock to glide's back buffer!\n" ));
2757         }
2758 }
2759
2760
2761 void gr_glide_restore_screen(int id)
2762 {
2763         if(VOODOO3_INACTIVE()){
2764                 return;
2765         }
2766
2767         gr_reset_clip();
2768
2769         if ( !Gr_saved_screen ) {
2770                 gr_clear();
2771                 return;
2772         }
2773
2774         gr_glide_restore_screen_internal(Gr_saved_screen);
2775 }
2776
2777 void gr_glide_free_screen(int id)
2778 {
2779         if(VOODOO3_INACTIVE()){
2780                 return;
2781         }
2782
2783         if ( Gr_saved_screen )  {
2784                 free( Gr_saved_screen );
2785                 Gr_saved_screen = NULL;
2786         }
2787 }
2788
2789
2790 void gr_glide_force_windowed()
2791 {
2792         if(VOODOO3_INACTIVE()){
2793                 return;
2794         }
2795
2796         gr_glide_clip_cursor(0);
2797         grSstControl(GR_CONTROL_DEACTIVATE);
2798 }
2799
2800
2801
2802 static int Glide_dump_frames = 0;
2803 static ubyte *Glide_dump_buffer = NULL;
2804 static int Glide_dump_frame_number = 0;
2805 static int Glide_dump_frame_count = 0;
2806 static int Glide_dump_frame_count_max = 0;
2807 static int Glide_dump_frame_size = 0;
2808
2809 void gr_glide_dump_frame_start(int first_frame, int frames_between_dumps)
2810 {
2811         if(VOODOO3_INACTIVE()){
2812                 return;
2813         }
2814
2815         if ( Glide_dump_frames )        {
2816                 Int3();         //  We're already dumping frames.  See John.
2817                 return;
2818         }       
2819         Glide_dump_frames = 1;
2820         Glide_dump_frame_number = first_frame;
2821         Glide_dump_frame_count = 0;
2822         Glide_dump_frame_count_max = frames_between_dumps;
2823         Glide_dump_frame_size = gr_screen.max_w * gr_screen.max_h * 2;
2824         
2825         if ( !Glide_dump_buffer ) {
2826                 int size = Glide_dump_frame_count_max * Glide_dump_frame_size;
2827                 Glide_dump_buffer = (ubyte *)malloc(size);
2828                 if ( !Glide_dump_buffer )       {
2829                         Error(LOCATION, "Unable to malloc %d bytes for dump buffer", size );
2830                 }
2831         }
2832
2833 }
2834
2835 // A hacked function to dump the frame buffer contents
2836 void gr_glide_dump_screen_hack( ushort * dst )
2837 {
2838         GrLfbInfo_t info;
2839         int i;
2840
2841         if(VOODOO3_INACTIVE()){
2842                 return;
2843         }
2844
2845         info.size=sizeof(GrLfbInfo_t);  
2846
2847         // get a read pointer 
2848         if ( grLfbLock(GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))              {
2849                 int w=gr_screen.max_w,h=gr_screen.max_h;
2850                 ushort *rptr;
2851                 int short_per_row=info.strideInBytes/2;
2852
2853                 rptr = (ushort *)info.lfbPtr;
2854
2855                 // Go through and read our pixels
2856                 for (i=0;i<h;i++)       {
2857                         memcpy( &dst[gr_screen.max_w*i], &rptr[(h-i-1)*short_per_row], w*sizeof(short) );
2858                 }
2859
2860                 // Release the lock
2861                 grLfbUnlock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER );
2862         } else {
2863                 mprintf(( "Couldn't get a read lock to glide's back buffer for frame dump!\n" ));
2864         }
2865 }
2866
2867 void gr_glide_get_region(int front, int w, int h, ubyte *data)
2868 {
2869         GrLfbInfo_t info;
2870         ushort bit_16;
2871         ubyte r, g, b, a;
2872         a = 1;
2873
2874         if(VOODOO3_INACTIVE()){
2875                 return;
2876         }
2877
2878         info.size=sizeof(GrLfbInfo_t);
2879         // get a read pointer 
2880         if ( grLfbLock(GR_LFB_READ_ONLY, front ? GR_BUFFER_FRONTBUFFER : GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_1555, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info)){
2881                 ushort *rptr;
2882                 int short_per_row=info.strideInBytes/2;
2883
2884                 rptr = (ushort *)info.lfbPtr;
2885
2886                 ushort *sptr, *dptr;
2887
2888                 dptr = (ushort*)data;
2889
2890                 for (int i=0; i<h; i++ )        {
2891                         sptr = &rptr[i*short_per_row];
2892
2893                         // 565 data is what we always get, so we need to swizzle
2894                         for(int j=0; j<w; j++ ) {
2895                                 bit_16 = *sptr++;                       
2896                                 
2897                                 r = (ubyte)((bit_16 & 0xf800) >> 8);
2898                                 g = (ubyte)((bit_16 & 0x07e0) >> 3);
2899                                 b = (ubyte)((bit_16 & 0x001f) << 3);
2900                                 
2901                                 // swizzle the data to 1555 (BM_PIXEL_FORMAT_ARGB)
2902                                 *dptr = 0;
2903                                 bm_set_components((ubyte*)dptr++, &r, &g, &b, &a);                              
2904                         }
2905                 }
2906
2907                 // Release the lock
2908                 grLfbUnlock(GR_LFB_READ_ONLY, front ? GR_BUFFER_FRONTBUFFER : GR_BUFFER_BACKBUFFER);
2909         } 
2910 }
2911
2912 void gr_glide_flush_frame_dump()
2913 {
2914         int i,j;
2915         char filename[MAX_PATH_LEN], *movie_path = ".\\";
2916         ubyte outrow[1024*3*4];
2917
2918         if(VOODOO3_INACTIVE()){
2919                 return;
2920         }
2921
2922         if ( gr_screen.max_w > 1024)    {
2923                 mprintf(( "Screen too wide for frame_dump\n" ));
2924                 return;
2925         }
2926
2927         for (i = 0; i < Glide_dump_frame_count; i++) {
2928
2929                 int w = gr_screen.max_w;
2930                 int h = gr_screen.max_h;
2931
2932                 sprintf(filename, NOX("%sfrm%04d.tga"), movie_path, Glide_dump_frame_number );
2933                 Glide_dump_frame_number++;
2934
2935                 CFILE *f = cfopen(filename, "wb");
2936
2937                 // Write the TGA header
2938                 cfwrite_ubyte( 0, f );  //      IDLength;
2939                 cfwrite_ubyte( 0, f );  //      ColorMapType;
2940                 cfwrite_ubyte( 10, f ); //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
2941                 cfwrite_ushort( 0, f ); // CMapStart;
2942                 cfwrite_ushort( 0, f ); //      CMapLength;
2943                 cfwrite_ubyte( 0, f );  // CMapDepth;
2944                 cfwrite_ushort( 0, f ); //      XOffset;
2945                 cfwrite_ushort( 0, f ); //      YOffset;
2946                 cfwrite_ushort( (ushort)w, f ); //      Width;
2947                 cfwrite_ushort( (ushort)h, f ); //      Height;
2948                 cfwrite_ubyte( 24, f ); //PixelDepth;
2949                 cfwrite_ubyte( 0, f );  //ImageDesc;
2950
2951                 // Go through and write our pixels
2952                 for (j=0;j<h;j++)       {
2953                         ubyte *src_ptr = Glide_dump_buffer+(i*Glide_dump_frame_size)+(j*w*2);
2954
2955                         int len = tga_compress( (char *)outrow, (char *)src_ptr, w*sizeof(short) );
2956
2957                         cfwrite(outrow,len,1,f);
2958                 }
2959
2960                 cfclose(f);
2961
2962         }
2963
2964         Glide_dump_frame_count = 0;
2965 }
2966
2967 void gr_glide_dump_frame()
2968 {
2969         if(VOODOO3_INACTIVE()){
2970                 return;
2971         }
2972
2973         // A hacked function to dump the frame buffer contents
2974         gr_glide_dump_screen_hack( (ushort *)(Glide_dump_buffer+(Glide_dump_frame_count*Glide_dump_frame_size)) );
2975
2976         Glide_dump_frame_count++;
2977
2978         if ( Glide_dump_frame_count == Glide_dump_frame_count_max ) {
2979                 gr_glide_flush_frame_dump();
2980         }
2981 }
2982
2983 void gr_glide_dump_frame_stop()
2984 {
2985         if(VOODOO3_INACTIVE()){
2986                 return;
2987         }
2988
2989         if ( !Glide_dump_frames )       {
2990                 Int3();         //  We're not dumping frames.  See John.
2991                 return;
2992         }       
2993
2994         // dump any remaining frames
2995         gr_glide_flush_frame_dump();
2996         
2997         Glide_dump_frames = 0;
2998         if ( Glide_dump_buffer )        {
2999                 free(Glide_dump_buffer);
3000                 Glide_dump_buffer = NULL;
3001         }
3002 }
3003
3004 #define FADE_TIME (F1_0/4)              // How long to fade out
3005
3006 void gr_glide_fade_out(int instantaneous)       
3007 {
3008         ushort *tmp_data;
3009
3010         if(VOODOO3_INACTIVE()){
3011                 return;
3012         }
3013
3014         gr_reset_clip();
3015         Mouse_hidden++;
3016
3017         tmp_data = (ushort *)malloc( gr_screen.max_w*gr_screen.max_h*sizeof(ushort) );
3018
3019         if ( tmp_data ) {
3020                 gr_glide_save_screen_internal(tmp_data);
3021         }
3022
3023         if (!gr_palette_faded_out) {
3024
3025                 if ( !instantaneous )   {
3026
3027                         if ( tmp_data ) {
3028                                 int count = 0;
3029                                 fix start_time, stop_time, t1;
3030
3031
3032                                 start_time = timer_get_fixed_seconds();
3033                                 t1 = 0;
3034
3035                                 do {
3036                                         //int c = (255*(FADE_TIME-t1))/FADE_TIME;
3037                                         int c = (255*t1)/FADE_TIME;
3038                                         if (c < 0 )     {
3039                                                 c = 0;
3040                                         } else if ( c > 255 )   {
3041                                                 c = 255;
3042                                         }
3043
3044                                         gr_glide_restore_screen_internal(tmp_data);
3045                                 
3046                                         for (int i=0; i<gr_screen.max_h; i++ )  {
3047                                                 glide_shade_scanline( 0, gr_screen.max_w-1, i, 0, 0, 0, c );
3048                                         }
3049
3050                                         gr_flip();
3051                                         count++;
3052
3053                                         t1 = timer_get_fixed_seconds() - start_time;
3054
3055                                 } while ( (t1 < FADE_TIME) && (t1>=0) );                // Loop as long as time not up and timer hasn't rolled
3056
3057                                 stop_time = timer_get_fixed_seconds();
3058
3059                                 mprintf(( "Took %d frames (and %.1f secs) to fade out\n", count, f2fl(stop_time-start_time) ));
3060                 
3061                         }
3062                 }
3063         }
3064
3065         gr_clear();
3066         gr_flip();
3067         gr_palette_faded_out = 1;
3068         Mouse_hidden--;
3069
3070         if ( tmp_data ) {
3071                 free(tmp_data);
3072         }
3073 }
3074
3075 void gr_glide_fade_in(int instantaneous)        
3076 {
3077         ushort *tmp_data;
3078
3079         if(VOODOO3_INACTIVE()){
3080                 return;
3081         }
3082
3083         Mouse_hidden++;
3084         gr_reset_clip();
3085
3086         tmp_data = (ushort *)malloc( gr_screen.max_w*gr_screen.max_h*sizeof(ushort) );
3087
3088         if ( tmp_data ) {
3089                 gr_glide_save_screen_internal(tmp_data);
3090         }
3091
3092         if (gr_palette_faded_out) {
3093
3094                 gr_palette_faded_out = 0;
3095
3096                 if ( !instantaneous )   {
3097
3098                         if ( tmp_data ) {
3099                                 int count = 0;
3100                                 fix start_time, stop_time, t1;
3101
3102
3103                                 start_time = timer_get_fixed_seconds();
3104                                 t1 = 0;
3105
3106                                 do {
3107                                         int c = (255*(FADE_TIME-t1))/FADE_TIME;
3108                                         if (c < 0 )     {
3109                                                 c = 0;
3110                                         } else if ( c > 255 )   {
3111                                                 c = 255;
3112                                         }
3113
3114                                         gr_glide_restore_screen_internal(tmp_data);
3115                                         
3116                                         for (int i=0; i<gr_screen.max_h; i++ )  {
3117                                                 glide_shade_scanline( 0, gr_screen.max_w-1, i, 0, 0, 0, c );
3118                                         }
3119
3120                                         gr_flip();
3121                                         count++;
3122
3123                                         t1 = timer_get_fixed_seconds() - start_time;
3124
3125                                 } while ( (t1 < FADE_TIME) && (t1>=0) );                // Loop as long as time not up and timer hasn't rolled
3126
3127                                 stop_time = timer_get_fixed_seconds();
3128
3129                                 mprintf(( "Took %d frames (and %.1f secs) to fade out\n", count, f2fl(stop_time-start_time) ));
3130                 
3131                         }
3132                 }
3133         }
3134
3135
3136         if ( tmp_data ) {
3137                 gr_glide_restore_screen_internal(tmp_data);
3138         }
3139         gr_flip();
3140         Mouse_hidden--;
3141
3142         if ( tmp_data ) {
3143                 free(tmp_data);
3144         }
3145 }
3146
3147 void gr_glide_cleanup()
3148 {
3149         if ( !Inited )  return;
3150
3151
3152         grGlideShutdown();
3153
3154         vglide_close();
3155
3156         gr_glide_clip_cursor(0);
3157
3158         glide_tcache_cleanup();
3159
3160         Inited = 0;
3161 }
3162
3163 void gr_glide_set_gamma(float gamma)
3164 {
3165         Gr_gamma = gamma;
3166         Gr_gamma_int = int(Gr_gamma*100);
3167
3168         // Create the Gamma lookup table
3169         int i;
3170         for (i=0; i<256; i++ )  {
3171                 int v = fl2i(pow(i2fl(i)/255.0f, 1.0f/Gr_gamma)*255.0f);
3172                 if ( v > 255 ) {
3173                         v = 255;
3174                 } else if ( v < 0 )     {
3175                         v = 0;
3176                 }
3177                 Gr_gamma_lookup[i] = v;
3178         }
3179
3180         for (i=0; i<256; i++ )  {
3181                 float v = (float)pow(i2fl(i)/255.0f, 1.0f/Gr_gamma)*255.0f;
3182                 if ( v > 255.0f ) {
3183                         v = 255.0f;
3184                 } else if ( v < 0.0f )  {
3185                         v = 0.0f;
3186                 }
3187                 Gr_gamma_lookup_float[i] = v;
3188         }
3189
3190         // Flush any existing textures
3191         glide_tcache_flush();
3192
3193 }
3194
3195 void gr_glide_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
3196 {               
3197         GrColor_t color = 0;
3198
3199         if(VOODOO3_INACTIVE()){
3200                 return;
3201         }
3202         
3203         Assert((r >= 0) && (r < 256));
3204         Assert((g >= 0) && (g < 256));
3205         Assert((b >= 0) && (b < 256));
3206
3207         // store the values
3208         gr_glide_init_color( &gr_screen.current_fog_color, r, g, b );
3209         if(fog_near >= 0.0f){
3210                 gr_screen.fog_near = fog_near;
3211         }
3212         if(fog_far >= 0.0f){
3213                 gr_screen.fog_far = fog_far;
3214         }       
3215         gr_screen.current_fog_mode = fog_mode;
3216
3217         // enable/disable fog
3218         if(fog_mode == GR_FOGMODE_NONE){
3219                 grFogMode(GR_FOG_DISABLE);
3220
3221                 // always unset the global for value if we're disabling fog
3222                 gr_screen.fog_near = -1.0f;
3223                 gr_screen.fog_far = -1.0f;
3224
3225                 return;
3226         } 
3227         grFogMode(GR_FOG_WITH_TABLE);
3228         
3229         // set the fog color
3230         color |= ((ubyte)r);
3231         color |= ((ubyte)g << 8);
3232         color |= ((ubyte)b << 16);
3233         grFogColorValue(color);
3234
3235         // only generate a new fog table if we have to
3236         if((fog_near >= 0.0f) && (fog_far > fog_near)){
3237                 guFogGenerateLinear(Glide_linear_fogtable, fog_near, fog_far);
3238         }
3239
3240         // set the fog table            
3241         grFogTable(Glide_linear_fogtable);              
3242 }
3243
3244 void gr_glide_get_pixel(int x, int y, int *r, int *g, int *b)
3245 {
3246         ushort pixel;
3247         *r = 0;
3248         *g = 0;
3249         *b = 0;         
3250
3251         if(VOODOO3_INACTIVE()){
3252                 return;
3253         }
3254
3255         // returns data in 565 format
3256         grLfbReadRegion(GR_BUFFER_BACKBUFFER, (FxU32)x, (FxU32)y, 1, 1, 2, &pixel);
3257
3258         // unpack pixel color
3259         *r = (0xf800 & pixel) >> 8;
3260         *g = (0x07e0 & pixel) >> 3;
3261         *b = (0x001f & pixel) << 3;             
3262 }
3263
3264 // resolution checking
3265 int gr_glide_supports_res_ingame(int res)
3266 {
3267         return 1;
3268 }
3269
3270 int gr_glide_supports_res_interface(int res)
3271 {
3272         return 1;
3273 }
3274
3275 void gr_glide_set_cull(int cull)
3276 {
3277 }
3278
3279 void gr_glide_filter_set(int filter)
3280 {
3281         if(VOODOO3_INACTIVE()){
3282                 return;
3283         }
3284
3285         if(filter){
3286                 grTexFilterMode(GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR);
3287         } else {
3288                 grTexFilterMode(GR_TMU0, GR_TEXTUREFILTER_POINT_SAMPLED, GR_TEXTUREFILTER_POINT_SAMPLED);
3289         }
3290 }
3291
3292 // set clear color
3293 void gr_glide_set_clear_color(int r, int g, int b)
3294 {
3295         gr_init_color(&gr_screen.current_clear_color, r, g, b);
3296 }
3297
3298 extern int movie_rendered_flag;
3299 extern int movie_frame_count;
3300
3301 void __cdecl grglide_MovieShowFrame(void *buf,uint bufw,uint bufh, uint sx,uint sy,uint w,uint h,uint dstx,uint dsty, uint hi_color)
3302 {
3303         // no soup for you!
3304
3305         /*
3306         RECT srect, drect;
3307
3308         if(VOODOO3_INACTIVE()){
3309                 return;
3310         }       
3311
3312         gr_reset_clip();
3313         gr_clear();
3314
3315         ushort *src_data = (ushort *)buf;
3316
3317         movie_rendered_flag = 1;
3318         
3319         if ( hi_color ) {
3320                 bufw >>= 1;
3321                 sx >>= 1;
3322                 w >>= 1;
3323                 dstx >>= 1;
3324         }       
3325
3326         SetRect(&srect, sx, sy, sx+w-1, sy+h-1);
3327         //SetRect(&drect, dstx, dsty, dstx+w-1, dsty+h-1);
3328         dstx = (gr_screen.max_w - w)/2;
3329         dsty = (gr_screen.max_h - h)/2;
3330         SetRect(&drect, dstx, dsty, dstx+w-1, dsty+h-1);
3331
3332         GrLfbInfo_t info;
3333         int i;
3334
3335         info.size=sizeof(GrLfbInfo_t);
3336
3337         // get a read pointer 
3338         if ( grLfbLock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_1555,
3339                                                         GR_ORIGIN_UPPER_LEFT, FXFALSE, &info))          {
3340                 ushort *rptr;
3341                 int short_per_row=info.strideInBytes/2;
3342
3343                 rptr = (ushort *)info.lfbPtr;
3344
3345                 // if doing interlaced mode, then go through every other scanline
3346                 if ( Interlace_movies ) {
3347                         static int start_at = 0;
3348
3349                         for ( i = start_at; i < (int)h; i += 2 ) {
3350                                 memcpy( &rptr[(dsty+i)*short_per_row+dstx], &src_data[bufw*i], w*sizeof(short) );
3351                         }
3352                         //start_at = (start_at + 1) % 2;
3353                 } else { 
3354                         // Go through and read our pixels
3355                         for (i=0;i<(int)h;i++)  {
3356                                 memcpy( &rptr[(dsty+i)*short_per_row+dstx], &src_data[bufw*i], w*sizeof(short) );
3357                         }
3358                 }
3359
3360                 // Release the lock
3361                 grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER );
3362         } else {
3363                 mprintf(( "Couldn't get a write lock to glide's back buffer!\n" ));
3364         }
3365
3366         Mouse_hidden++;
3367         gr_flip();
3368         Mouse_hidden--;
3369         */
3370 }
3371
3372 // cross fade
3373 #define FETCH_A(i, j)   {                                                               \
3374         ubyte code = 0;                                                                         \
3375         code |= ((i+min_x<x1) << 0);                                            \
3376         code |= ((j+min_y<y1) << 1);                                            \
3377         code |= ((i+min_x<x1+bmp1->w) << 2);                    \
3378         code |= ((j+min_y<y1+bmp1->h) << 3);                    \
3379         if(code && (code < 4)){                                                         \
3380                 pixel_a = sptr1[i - (x1 - min_x)];                      \
3381         } else {                                                                                                        \
3382                 pixel_a = pixel_black;                                                  \
3383         }                                                                                                                       \
3384 }
3385 #define FETCH_B(i, j)   {                                                               \
3386         ubyte code = 0;                                                                         \
3387         code |= ((i+min_x<x2) << 0);                                            \
3388         code |= ((j+min_y<y2) << 1);                                            \
3389         code |= ((i+min_x<x2+bmp2->w) << 2);                    \
3390         code |= ((j+min_y<y2+bmp2->h) << 3);                    \
3391         if(code && (code < 4)){                                                         \
3392                 pixel_b = sptr2[i - (x2 - min_x)];                      \
3393         } else {                                                                                                        \
3394                 pixel_b = pixel_black;                                                  \
3395         }                                                                                                                       \
3396 }
3397 #define MIX(pout, p1, p2)                               { pout = p1; }
3398 void gr_glide_cross_fade(int bmap1, int bmap2, int x1, int y1, int x2, int y2, float pct)
3399 {
3400         if ( pct <= 50 )        {
3401                 gr_set_bitmap(bmap1);
3402                 gr_bitmap(x1, y1);
3403         } else {
3404                 gr_set_bitmap(bmap2);
3405                 gr_bitmap(x2, y2);
3406         }       
3407         /*
3408         int min_x = x1 < x2 ? x1 : x2;
3409         int min_y = y1 < y2 ? y1 : y2;
3410         int max_x = x2 > x1 ? x2 : x1;
3411         int max_y = y2 > y1 ? y2 : y1;
3412         int max_w, max_h;
3413         int i, j;
3414         ushort *sptr1;
3415         ushort *sptr2;
3416         bitmap *bmp1, *bmp2;                    
3417         ushort pixel_a, pixel_b;
3418         ushort pixel_black;
3419         ushort pixel_out;
3420         ubyte r, g, b, a;
3421
3422         // stuff the black pixel
3423         r = 0; g = 0; b = 0; a = 255;
3424         pixel_black = 0;
3425         bm_set_components(&pixel_black, &r, &g, &b, &a);
3426         
3427         // lock the first bitmap
3428         bmp1 = bm_lock( bmap1, 16, 0 );
3429         sptr1 = (ushort *)( bmp1->data );
3430
3431         // lock the second bitmap
3432         bmp2 = bm_lock( bmap2, 16, 0 );
3433         sptr2 = (ushort *)( bmp2->data );       
3434
3435         if(x1 > x2){
3436                 max_x = x1;
3437                 min_x = x2;
3438         } else {
3439                 min_x = x1;
3440                 max_x = x2;
3441         }
3442         if(y1 > y2){
3443                 max_y = y1;
3444                 min_y = y2;
3445         } else {
3446                 min_y = y1;
3447                 max_y = y2;
3448         }
3449         if(bmp1->w > bmp2->w){
3450                 max_w = bmp1->w;
3451         } else {
3452                 max_w = bmp2->w;
3453         }
3454         if(bmp1->h > bmp2->h){
3455                 max_h = bmp1->h;
3456         } else {
3457                 max_h = bmp2->h;
3458         }
3459         
3460         GrLfbInfo_t info;
3461
3462         // lock the framebuffer
3463         if ( grLfbLock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER, GR_LFBWRITEMODE_1555, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info) ) {
3464
3465                 // pointer into vram
3466                 ushort *vram = (ushort *)info.lfbPtr;
3467                 int stride = info.strideInBytes / sizeof(ushort);
3468                 
3469                 // for all scanlines
3470                 for (i=0; i<max_h; i++ ){
3471                         // this scanline in vram
3472                         ushort *dptr = &vram[stride*(gr_screen.offset_y+i+min_y)+(gr_screen.offset_x+min_x)];
3473                         
3474                         // for this scanline
3475                         for ( j=0; j<max_w; j++ ){                              
3476                                 // fetch the A and B pixels
3477                                 // FETCH_A(i, j);
3478                                 // FETCH_B(i, j);
3479                                 {                                                               
3480                                         ubyte code = 0;                                                                         
3481                                         code |= ((i+min_x>=x1) << 0);                                           
3482                                         code |= ((j+min_y>=y1) << 1);                                           
3483                                         code |= ((i+min_x>x1+bmp1->w) << 2);                    
3484                                         code |= ((j+min_y>y1+bmp1->h) << 3);                    
3485                                         if(code && (code < 4)){                                                         
3486                                                 pixel_a = sptr1[i - (x1 - min_x)];                      
3487                                         } else {                                                                                                        
3488                                                 pixel_a = pixel_black;                                                  
3489                                         }                                                                                                                       
3490                                 }
3491                                 {                                                               
3492                                         ubyte code = 0;                                                                         
3493                                         code |= ((i+min_x>=x2) << 0);                                           
3494                                         code |= ((j+min_y>=y2) << 1);                                           
3495                                         code |= ((i+min_x>x2+bmp2->w) << 2);                    
3496                                         code |= ((j+min_y>y2+bmp2->h) << 3);                    
3497                                         if(code && (code < 4)){                                                         
3498                                                 pixel_b = sptr2[i - (x2 - min_x)];                      
3499                                         } else {                                                                                                        
3500                                                 pixel_b = pixel_black;                                                  
3501                                         }                                                                                                                       
3502                                 }
3503
3504
3505                                 // mix them - for now just always pick pixel A
3506                                 MIX(pixel_out, pixel_a, pixel_b);
3507
3508                                 // write to vram
3509                                 *dptr = pixel_out;
3510
3511                                 // next pixel in vram
3512                                 dptr++;
3513                         }                       
3514                         
3515                         // increment if we need to
3516                         if((j+min_y >= y1) && (j+min_y < y1+bmp1->h)){
3517                                 sptr1 += bmp1->w;
3518                         }
3519                         // increment if we need to
3520                         if((j+min_y >= y2) && (j+min_y < y2+bmp2->h)){
3521                                 sptr2 += bmp2->w;                       
3522                         }
3523                 }
3524
3525                 grLfbUnlock(GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER);
3526         }       
3527
3528         bm_unlock(bmap1);
3529         bm_unlock(bmap2);
3530         */
3531 }
3532
3533 GrHwConfiguration hwconfig;
3534
3535 void gr_glide_init()
3536 {
3537         D3D_enabled = 1;
3538         Glide_running = 0;      
3539         int res_mode;
3540
3541         if ( Inited )   {
3542                 gr_glide_cleanup();
3543                 Inited = 0;
3544         }
3545
3546         // Turn off the 3Dfx splash screen
3547         SetEnvironmentVariable("FX_GLIDE_NO_SPLASH","1");
3548
3549         // Turn off the 3Dfx gamma correction
3550         SetEnvironmentVariable("SST_RGAMMA","1.0");
3551         SetEnvironmentVariable("SST_GGAMMA","1.0");
3552         SetEnvironmentVariable("SST_BGAMMA","1.0");
3553
3554         mprintf(( "Initializing glide graphics device...\n" ));
3555         Inited = 1;
3556
3557         if ( !vglide_init() )   {
3558                 mprintf(( "Glide DLL not found!\n" ));
3559                 exit(1);
3560         }
3561
3562 //      os_suspend();
3563
3564         // Find the extents of the window
3565         HWND hwnd = (HWND)os_get_window();
3566
3567         // Prepare the window to go full screen
3568 #ifndef NDEBUG
3569         mprintf(( "Window in debugging mode... mouse clicking may cause problems!\n" ));
3570         SetWindowLong( hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT );
3571         SetWindowLong( hwnd, GWL_STYLE, WS_POPUP );
3572         ShowWindow(hwnd, SW_SHOWNORMAL );
3573         RECT work_rect;
3574         SystemParametersInfo( SPI_GETWORKAREA, 0, &work_rect, 0 );
3575         SetWindowPos( hwnd, HWND_NOTOPMOST, work_rect.left, work_rect.top, gr_screen.max_w, gr_screen.max_h, 0 );       
3576         SetActiveWindow(hwnd);
3577         SetForegroundWindow(hwnd);
3578         Glide_cursor_clip_rect.left = work_rect.left;
3579         Glide_cursor_clip_rect.top = work_rect.top;
3580         Glide_cursor_clip_rect.right = work_rect.left + gr_screen.max_w - 1;
3581         Glide_cursor_clip_rect.bottom = work_rect.top + gr_screen.max_h - 1;
3582 #else
3583         SetWindowLong( hwnd, GWL_EXSTYLE, 0 );
3584         SetWindowLong( hwnd, GWL_STYLE, WS_POPUP );
3585         ShowWindow(hwnd, SW_SHOWNORMAL );
3586         SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ), 0 );  
3587         SetActiveWindow(hwnd);
3588         SetForegroundWindow(hwnd);
3589         Glide_cursor_clip_rect.left = 0;
3590         Glide_cursor_clip_rect.top = 0;
3591         Glide_cursor_clip_rect.right = gr_screen.max_w;
3592         Glide_cursor_clip_rect.bottom = gr_screen.max_h;
3593 #endif
3594
3595         // Let things catch up....
3596         Sleep(2000);
3597         
3598         grGlideInit();
3599
3600         gr_screen.bytes_per_pixel = 2;
3601         gr_screen.bits_per_pixel = 16;
3602
3603         char version[80];
3604         grGlideGetVersion(version);
3605         mprintf(( "Glide version: %s\n", version ));
3606
3607         if ( !grSstQueryHardware( &hwconfig ))  {
3608                 mprintf(( "Glide: Query hardaware failed!\n" ));
3609                 os_resume();
3610                 exit(1);
3611         }       
3612
3613         grSstSelect(0);
3614
3615         // voodoo 3
3616         Glide_voodoo3 = 0;
3617         if(hwconfig.SSTs[0].sstBoard.Voodoo2Config.fbRam >= 12){
3618                 Glide_voodoo3 = 1;
3619         }
3620
3621         // choose resolution
3622         if((gr_screen.max_w == 1024) && (gr_screen.max_h == 768)){
3623                 res_mode = GR_RESOLUTION_1024x768;
3624         } else {
3625                 res_mode = GR_RESOLUTION_640x480;
3626         }
3627
3628         int retval = grSstWinOpen( (DWORD)hwnd, res_mode, GR_REFRESH_60Hz, GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1 );
3629         if ( !retval )  {
3630                 mprintf(( "Glide: grSstOpen failed!\n" ));
3631                 os_resume();
3632                 exit(1);
3633         }
3634
3635         // pixel format
3636         Bm_pixel_format = BM_PIXEL_FORMAT_ARGB;
3637
3638 //      grChromakeyMode( GR_CHROMAKEY_ENABLE );
3639 //      grChromakeyValue( 0x00FF00 );
3640
3641 //      os_resume();
3642
3643         // Setup the surface format
3644         Gr_red.bits = 5;
3645         Gr_red.shift = 10;
3646         Gr_red.scale = 256/32;
3647         Gr_red.mask = 0x7C00;
3648         Gr_t_red = Gr_red;
3649         Gr_current_red = &Gr_red;       
3650
3651         Gr_green.bits = 5;
3652         Gr_green.shift = 5;
3653         Gr_green.scale = 256/32;
3654         Gr_green.mask = 0x03e0;
3655         Gr_t_green = Gr_green;
3656         Gr_current_green = &Gr_green;
3657
3658         Gr_blue.bits = 5;
3659         Gr_blue.shift = 0;
3660         Gr_blue.scale = 256/32;
3661         Gr_blue.mask = 0x1F;
3662         Gr_t_blue = Gr_blue;
3663         Gr_current_blue = &Gr_blue;
3664
3665         Gr_current_alpha = &Gr_alpha;
3666
3667         glide_tcache_init();
3668
3669         gr_glide_clip_cursor(1);
3670
3671         grGammaCorrectionValue(1.0f);
3672
3673         gr_screen.gf_flip = gr_glide_flip;
3674         gr_screen.gf_flip_window = gr_glide_flip_window;
3675         gr_screen.gf_set_clip = gr_glide_set_clip;
3676         gr_screen.gf_reset_clip = gr_glide_reset_clip;
3677         gr_screen.gf_set_font = grx_set_font;
3678         gr_screen.gf_set_color = gr_glide_set_color;
3679         gr_screen.gf_set_bitmap = gr_glide_set_bitmap;
3680         gr_screen.gf_create_shader = gr_glide_create_shader;
3681         gr_screen.gf_set_shader = gr_glide_set_shader;
3682         gr_screen.gf_clear = gr_glide_clear;
3683
3684         // gr_screen.gf_bitmap = gr_glide_bitmap;       
3685         // gr_screen.gf_bitmap_ex = gr_glide_bitmap_ex;
3686
3687         gr_screen.gf_rect = gr_glide_rect;
3688         gr_screen.gf_shade = gr_glide_shade;
3689         gr_screen.gf_string = gr_glide_string;
3690         gr_screen.gf_circle = gr_glide_circle;
3691
3692         gr_screen.gf_line = gr_glide_line;
3693         gr_screen.gf_aaline = gr_glide_aaline;
3694         gr_screen.gf_pixel = gr_glide_pixel;
3695         gr_screen.gf_scaler = gr_glide_scaler;
3696         gr_screen.gf_aascaler = gr_glide_aascaler;
3697         gr_screen.gf_tmapper = gr_glide_tmapper;
3698
3699         gr_screen.gf_gradient = gr_glide_gradient;
3700
3701         gr_screen.gf_set_palette = gr_glide_set_palette;
3702         gr_screen.gf_get_color = gr_glide_get_color;
3703         gr_screen.gf_init_color = gr_glide_init_color;
3704         gr_screen.gf_init_alphacolor = gr_glide_init_alphacolor;
3705         gr_screen.gf_set_color_fast = gr_glide_set_color_fast;
3706         gr_screen.gf_print_screen = gr_glide_print_screen;
3707
3708         gr_screen.gf_aabitmap = gr_glide_aabitmap;
3709         gr_screen.gf_aabitmap_ex = gr_glide_aabitmap_ex;
3710
3711         gr_screen.gf_fade_in = gr_glide_fade_in;
3712         gr_screen.gf_fade_out = gr_glide_fade_out;
3713         gr_screen.gf_flash = gr_glide_flash;
3714
3715         gr_screen.gf_zbuffer_get = gr_glide_zbuffer_get;
3716         gr_screen.gf_zbuffer_set = gr_glide_zbuffer_set;
3717         gr_screen.gf_zbuffer_clear = gr_glide_zbuffer_clear;
3718
3719         gr_screen.gf_save_screen = gr_glide_save_screen;
3720         gr_screen.gf_restore_screen = gr_glide_restore_screen;
3721         gr_screen.gf_free_screen = gr_glide_free_screen;
3722
3723         // Screen dumping stuff
3724         gr_screen.gf_dump_frame_start = gr_glide_dump_frame_start;
3725         gr_screen.gf_dump_frame_stop = gr_glide_dump_frame_stop;
3726         gr_screen.gf_dump_frame = gr_glide_dump_frame;
3727
3728         gr_screen.gf_set_gamma = gr_glide_set_gamma;
3729
3730         // Lock/unlock stuff
3731         gr_screen.gf_lock = gr_glide_lock;
3732         gr_screen.gf_unlock = gr_glide_unlock;
3733
3734         // region
3735         gr_screen.gf_get_region = gr_glide_get_region;
3736
3737         // fog stuff
3738         gr_screen.gf_fog_set = gr_glide_fog_set;        
3739
3740         // pixel get
3741         gr_screen.gf_get_pixel = gr_glide_get_pixel;
3742
3743         // poly culling
3744         gr_screen.gf_set_cull = gr_glide_set_cull;
3745
3746         // cross fade
3747         gr_screen.gf_cross_fade = gr_glide_cross_fade;
3748
3749         // filter
3750         gr_screen.gf_filter_set = gr_glide_filter_set;
3751
3752         // texture cache set
3753         gr_screen.gf_tcache_set = glide_tcache_set;
3754
3755         // set clear color
3756         gr_screen.gf_set_clear_color = gr_glide_set_clear_color;
3757
3758         Glide_running=1;
3759
3760         // default linear fog table
3761         guFogGenerateLinear(Glide_linear_fogtable, 1.0f, 1000.0f);
3762         
3763         Mouse_hidden++;
3764         gr_reset_clip();
3765         gr_clear();
3766         gr_flip();
3767         Mouse_hidden--;
3768 }
3769