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