]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grd3drender.cpp
get rid of some platform specific stuff
[taylor/freespace2.git] / src / graphics / grd3drender.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Graphics/GrD3DRender.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code to actually render stuff using Direct3D
16  *
17  * $Log$
18  * Revision 1.2  2002/06/09 04:41:17  relnev
19  * added copyright header
20  *
21  * Revision 1.1.1.1  2002/05/03 03:28:09  root
22  * Initial import.
23  *
24  * 
25  * 27    9/13/99 11:30a Dave
26  * Added checkboxes and functionality for disabling PXO banners as well as
27  * disabling d3d zbuffer biasing.
28  * 
29  * 26    9/08/99 12:03a Dave
30  * Make squad logos render properly in D3D all the time. Added intel anim
31  * directory.
32  * 
33  * 25    8/30/99 5:01p Dave
34  * Made d3d do less state changing in the nebula. Use new chat server for
35  * PXO.
36  * 
37  * 24    7/30/99 4:04p Anoop
38  * Fixed D3D shader.
39  * 
40  * 23    7/29/99 10:47p Dave
41  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
42  * 
43  * 22    7/27/99 3:09p Dave
44  * Made g400 work. Whee.
45  * 
46  * 21    7/24/99 4:19p Dave
47  * Fixed dumb code with briefing bitmaps. Made d3d zbuffer work much
48  * better. Made model code use zbuffer more intelligently.
49  * 
50  * 20    7/24/99 1:54p Dave
51  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
52  * missions.
53  * 
54  * 19    7/19/99 3:29p Dave
55  * Fixed gamma bitmap in the options screen.
56  * 
57  * 18    7/14/99 9:42a Dave
58  * Put in clear_color debug function. Put in base for 3dnow stuff / P3
59  * stuff
60  * 
61  * 17    7/13/99 1:15p Dave
62  * 32 bit support. Whee!
63  * 
64  * 16    7/12/99 11:42a Jefff
65  * Made rectangle drawing smarter in D3D. Made plines draw properly on Ati
66  * Rage Pro.
67  * 
68  * 15    6/29/99 10:35a Dave
69  * Interface polygon bitmaps! Whee!
70  * 
71  * 14    5/05/99 9:02p Dave
72  * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
73  * rotations, tweaked values, made bitmap selection more random). Fixed
74  * D3D beam weapon clipping problem. Added D3d frame dumping.
75  * 
76  * 13    2/03/99 11:44a Dave
77  * Fixed d3d transparent textures.
78  * 
79  * 12    1/30/99 5:08p Dave
80  * More new hi-res stuff.Support for nice D3D textures.
81  * 
82  * 11    12/18/98 1:13a Dave
83  * Rough 1024x768 support for Direct3D. Proper detection and usage through
84  * the launcher.
85  * 
86  * 10    12/08/98 7:03p Dave
87  * Much improved D3D fogging. Also put in vertex fogging for the cheesiest
88  * of 3d cards.
89  * 
90  * 9     12/08/98 2:47p Johnson
91  * Made D3D fog use eye-relative fog instead of z depth fog.
92  * 
93  * 8     12/08/98 9:36a Dave
94  * Almost done nebula effect for D3D. Looks 85% as good as Glide.
95  * 
96  * 7     12/07/98 5:51p Dave
97  * Finally got d3d fog working! Now we just need to tweak values.
98  * 
99  * 6     12/07/98 9:00a Dave
100  * Fixed d3d rendered. Still don't have fog working.
101  * 
102  * 5     12/06/98 6:53p Dave
103  * 
104  * 4     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  * 3     11/30/98 1:07p Dave
109  * 16 bit conversion, first run.
110  * 
111  * 2     10/07/98 10:52a Dave
112  * Initial checkin.
113  * 
114  * 1     10/07/98 10:49a Dave
115  * 
116  * 54    5/25/98 10:32a John
117  * Took out redundant code for font bitmap offsets that converted to a
118  * float, then later on converted back to an integer.  Quite unnecessary.
119  * 
120  * 53    5/24/98 6:45p John
121  * let direct3d do all clipping.
122  * 
123  * 52    5/24/98 3:42p John
124  * Let Direct3D do clipping on any linear textures, like lasers.
125  * 
126  * 51    5/23/98 7:18p John
127  * optimized the uv bashing a bit.
128  * 
129  * 50    5/22/98 1:11p John
130  * Added code to actually detect which offset a line needs
131  * 
132  * 49    5/22/98 12:54p John
133  * added .5 to each pixel of a line.  This seemed to make single pixel
134  * lines draw on all cards.
135  * 
136  * 48    5/22/98 9:00a John
137  * Fixed problem of no fading out of additive textures due to Permedia2
138  * fix.  Did this by dimming out the vertex RGB values.
139  * 
140  * 47    5/21/98 9:56p John
141  * Made Direct3D work with classic alpha-blending only devices, like the
142  * Virge.  Added a texture type XPARENT that fills the alpha in in the
143  * bitmap for Virge.   Added support for Permedia by making making
144  * additive alphablending be one/one instead of alpha/one, which didn't
145  * work, and there is no way to tell this from caps.
146  * 
147  * 46    5/20/98 9:45p John
148  * added code so the places in code that change half the palette don't
149  * have to clear the screen.
150  * 
151  * 45    5/20/98 3:10p John
152  * Made lines work even if no alphagouraud capabilities on the card.
153  * 
154  * 44    5/19/98 4:50p Lawrance
155  * JAS: Fixed some bugs on Alan's nVidia Riva128 PCI where some
156  * unitiallized fields, namely vertex->shw were causing glitches.
157  * 
158  * 43    5/19/98 1:46p John
159  * Fixed Rendition/Riva128 uv problems.
160  * 
161  * 42    5/19/98 12:34p John
162  * added code to fix uv's on rendition.  added code to fix zbuffering
163  * problem on rendition.
164  * 
165  * 41    5/18/98 8:26p John
166  * Made scanline be line.   Made lines work if no line alpha blending
167  * supported.   Made no alpha mode use alpha off.  
168  * 
169  * 40    5/17/98 4:13p John
170  * Made zbuffer clear only clear current clip region
171  * 
172  * 39    5/17/98 3:23p John
173  * Took out capibility check for additive blending.  Made gr_bitmap_ex
174  * clip properly in glide and direct3d.
175  * 
176  * 38    5/15/98 8:48a John
177  * Fixed bug where one-pixel line was getting left on right and bottom.
178  * 
179  * 37    5/12/98 8:43p John
180  * fixed particle zbuffering.
181  * 
182  * 36    5/12/98 10:34a John
183  * Added d3d_shade functionality.  Added d3d_flush function, since the
184  * shader seems to get reorganzed behind the overlay text stuff!
185  * 
186  * 35    5/12/98 10:06a John
187  * Made all tmaps "clamp-clip".  This fixed bug with offscreen hud
188  * indicators not rendering.
189  * 
190  * 34    5/12/98 8:18a John
191  * Put in code to use a different texture format for alpha textures and
192  * normal textures.   Turned off filtering for aabitmaps.  Took out
193  * destblend=invsrccolor alpha mode that doesn't work on riva128. 
194  * 
195  * 33    5/11/98 10:58a John
196  * Fixed pilot name cursor bug.  Started adding in code for alphachannel
197  * textures.
198  * 
199  * 32    5/09/98 12:37p John
200  * More texture caching
201  * 
202  * 31    5/09/98 12:16p John
203  * Even better texture caching.
204  * 
205  * 30    5/08/98 10:12a John
206  * took out an mprintf
207  * 
208  * 29    5/07/98 11:31a John
209  * Removed DEMO defines
210  * 
211  * 28    5/07/98 10:28a John
212  * Made texture format use 4444.   Made fonts use alpha to render.
213  * 
214  * 27    5/07/98 10:09a John
215  * Fixed some bugs with short lines in D3D.
216  * 
217  * 26    5/07/98 9:54a John
218  * Added in palette flash functionallity.
219  * 
220  * 25    5/07/98 9:40a John
221  * Fixed some bitmap transparency issues with Direct3D.
222  * 
223  * 24    5/06/98 11:21p John
224  * Fixed a bitmap bug with Direct3D.  Started adding new caching code into
225  * D3D.
226  * 
227  * 23    5/06/98 8:41p John
228  * Fixed some font clipping bugs.   Moved texture handle set code for d3d
229  * into the texture module.
230  * 
231  * 22    5/06/98 8:07p John
232  * made d3d clear work correctly.
233  * 
234  * 21    5/06/98 8:00p John
235  * Got stars working under D3D.
236  * 
237  * 20    5/06/98 5:30p John
238  * Removed unused cfilearchiver.  Removed/replaced some unused/little used
239  * graphics functions, namely gradient_h and _v and pixel_sp.   Put in new
240  * DirectX header files and libs that fixed the Direct3D alpha blending
241  * problems.
242  * 
243  * 19    5/05/98 10:37p John
244  * Added code to optionally use execute buffers.
245  * 
246  * 18    5/04/98 3:36p John
247  * Got zbuffering working with Direct3D.
248  * 
249  * 17    5/03/98 10:52a John
250  * Made D3D sort of work on 3dfx.
251  * 
252  * 16    5/03/98 10:43a John
253  * Working on Direct3D.
254  * 
255  * 15    4/14/98 12:15p John
256  * Made 16-bpp movies work.
257  * 
258  * 14    4/10/98 5:20p John
259  * Changed RGB in lighting structure to be ubytes.  Removed old
260  * not-necessary 24 bpp software stuff.
261  * 
262  * 13    4/09/98 11:05a John
263  * Removed all traces of Direct3D out of the demo version of Freespace and
264  * the launcher.
265  * 
266  * 12    3/12/98 5:36p John
267  * Took out any unused shaders.  Made shader code take rgbc instead of
268  * matrix and vector since noone used it like a matrix and it would have
269  * been impossible to do in hardware.   Made Glide implement a basic
270  * shader for online help.  
271  * 
272  * 11    3/11/98 1:55p John
273  * Fixed warnings
274  * 
275  * 10    3/10/98 4:18p John
276  * Cleaned up graphics lib.  Took out most unused gr functions.   Made D3D
277  * & Glide have popups and print screen.  Took out all >8bpp software
278  * support.  Made Fred zbuffer.  Made zbuffer allocate dynamically to
279  * support Fred.  Made zbuffering key off of functions rather than one
280  * global variable.
281  * 
282  * 9     3/08/98 12:33p John
283  * Added more lines, tris, and colored flat polys (lasers!) correctly.
284  * 
285  * 8     3/08/98 10:25a John
286  * Added in lines
287  * 
288  * 7     3/07/98 8:29p John
289  * Put in some Direct3D features.  Transparency on bitmaps.  Made fonts &
290  * aabitmaps render nice.
291  * 
292  * 6     3/06/98 5:39p John
293  * Started adding in aabitmaps
294  * 
295  * 5     3/02/98 5:42p John
296  * Removed WinAVI stuff from Freespace.  Made all HUD gauges wriggle from
297  * afterburner.  Made gr_set_clip work good with negative x &y.  Made
298  * model_caching be on by default.  Made each cached model have it's own
299  * bitmap id.  Made asteroids not rotate when model_caching is on.  
300  * 
301  * 4     2/26/98 3:24p John
302  * fixed optimized warning
303  * 
304  * 3     2/17/98 7:28p John
305  * Got fonts and texturing working in Direct3D
306  * 
307  * 2     2/07/98 7:50p John
308  * Added code so that we can use the old blending type of alphacolors if
309  * we want to.  Made the stars use them.
310  * 
311  * 1     2/03/98 9:24p John
312  *
313  * $NoKeywords: $
314  */
315
316 #include "grd3dinternal.h"
317 #include "2d.h"
318 #include "pstypes.h"
319 #include "bmpman.h"
320 #include "palman.h"
321 #include "line.h"
322 #include "cfile.h"
323 #include "neb.h"
324 #include "3d.h"
325
326 typedef enum gr_texture_source {
327         TEXTURE_SOURCE_NONE,
328         TEXTURE_SOURCE_DECAL,
329         TEXTURE_SOURCE_NO_FILTERING,
330 } gr_texture_source;
331
332 typedef enum gr_alpha_blend {
333         ALPHA_BLEND_NONE,                                                       // 1*SrcPixel + 0*DestPixel
334         ALPHA_BLEND_ALPHA_ADDITIVE,                     // Alpha*SrcPixel + 1*DestPixel
335         ALPHA_BLEND_ALPHA_BLEND_ALPHA,          // Alpha*SrcPixel + (1-Alpha)*DestPixel
336         ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR,      // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
337 } gr_alpha_blend;
338
339 typedef enum gr_zbuffer_type {
340         ZBUFFER_TYPE_NONE,
341         ZBUFFER_TYPE_READ,
342         ZBUFFER_TYPE_WRITE,
343         ZBUFFER_TYPE_FULL,
344 } gr_zbuffer_type;
345
346 int D3d_last_state = -1;
347
348 // Hack! move to another file!
349 extern int D3d_rendition_uvs;   
350
351 // Hack! move to another file!
352 extern int D3D_fog_mode;
353
354 void gr_d3d_set_state( gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt )
355 {
356         int current_state = 0;
357
358         current_state = current_state | (ts<<0);
359         current_state = current_state | (ab<<5);
360         current_state = current_state | (zt<<10);
361
362         if ( current_state == D3d_last_state ) {
363                 return;
364         }
365         D3d_last_state = current_state;
366
367         switch( ts )    {
368         case TEXTURE_SOURCE_NONE:
369                 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREHANDLE, NULL );
370                 // Let the texture cache system know whe set the handle to NULL
371                 gr_tcache_set(-1, -1, NULL, NULL );
372
373                 break;
374         case TEXTURE_SOURCE_DECAL:
375                 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEAR );
376                 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR );
377
378                 if ( lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA )  {
379                         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA );
380                 } else {
381                         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE );
382                 }
383                 break;
384
385         case TEXTURE_SOURCE_NO_FILTERING:
386                 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST );
387                 d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST );
388                 if ( lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA )  {
389                         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA );
390                 } else {
391                         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE );
392                 }
393                 break;
394
395         default:
396                 Int3();
397         }
398
399         switch( ab )    {
400         case ALPHA_BLEND_NONE:                                                  // 1*SrcPixel + 0*DestPixel
401                 d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE );
402                 break;
403
404         case ALPHA_BLEND_ALPHA_ADDITIVE:                                // Alpha*SrcPixel + 1*DestPixel
405         case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
406                 if ( lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE  )       {
407                         d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
408                         // Must use ONE:ONE as the Permedia2 can't do SRCALPHA:ONE.
409                         // But I lower RGB values so we don't loose anything.
410                         d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_ONE );
411                         //d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
412                         d3d_SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE );
413                         break;
414                 }
415                 // Fall through to normal alpha blending mode...
416
417         case ALPHA_BLEND_ALPHA_BLEND_ALPHA:                     // Alpha*SrcPixel + (1-Alpha)*DestPixel
418                 if ( lpDevDesc->dpcTriCaps.dwSrcBlendCaps & D3DPBLENDCAPS_SRCALPHA  )   {
419                         d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
420                         d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
421                         d3d_SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
422                 } else {
423                         d3d_SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
424                         d3d_SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_BOTHSRCALPHA );
425                 }
426                 break;
427
428
429         default:
430                 Int3();
431         }
432
433         switch( zt )    {
434
435         case ZBUFFER_TYPE_NONE:
436                 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,FALSE);
437                 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,FALSE);
438                 break;
439
440         case ZBUFFER_TYPE_READ:
441                 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,TRUE);
442                 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,FALSE);
443                 break;
444
445         case ZBUFFER_TYPE_WRITE:
446                 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,FALSE);
447                 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,TRUE);
448                 break;
449
450         case ZBUFFER_TYPE_FULL:
451                 d3d_SetRenderState(D3DRENDERSTATE_ZENABLE,TRUE);
452                 d3d_SetRenderState(D3DRENDERSTATE_ZWRITEENABLE,TRUE);
453                 break;
454
455         default:
456                 Int3();
457         }
458
459 }
460
461 extern int D3D_zbias;
462 void d3d_zbias(int bias)
463 {
464         if(D3D_zbias){
465                 d3d_SetRenderState(D3DRENDERSTATE_ZBIAS, bias);
466         }
467 }
468
469 // If mode is FALSE, turn zbuffer off the entire frame,
470 // no matter what people pass to gr_zbuffer_set.
471 void gr_d3d_zbuffer_clear(int mode)
472 {
473         if ( mode )     {
474                 gr_zbuffering = 1;
475                 gr_zbuffering_mode = GR_ZBUFF_FULL;
476                 gr_global_zbuffering = 1;
477
478                 // Make sure zbuffering is on
479                 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
480
481
482                 // An application can clear z-buffers by using the IDirectDrawSurface2::Blt method. 
483                 // The DDBLT_DEPTHFILL flag indicates that the blit clears z-buffers. If this flag 
484                 // is specified, the DDBLTFX structure passed to the IDirectDrawSurface2::Blt method 
485                 // should have its dwFillDepth member set to the required z-depth. If the DirectDraw device 
486                 // driver for a 3D-accelerated display card is designed to provide support for z-buffer 
487                 // clearing in hardware, it should export the DDCAPS_BLTDEPTHFILL flag and should 
488                 // handle DDBLT_DEPTHFILL blits. The destination surface of a depth-fill blit must 
489                 // be a z-buffer.
490                 // Note The actual interpretation of a depth value is specific to the 3D renderer.
491
492                 D3DRECT rect;
493
494                 rect.x1 = gr_screen.clip_left + gr_screen.offset_x;
495                 rect.y1 = gr_screen.clip_top + gr_screen.offset_y;
496                 rect.x2 = gr_screen.clip_right + gr_screen.offset_x;
497                 rect.y2 = gr_screen.clip_bottom + gr_screen.offset_y;
498
499                 if (lpViewport->Clear( 1, &rect, D3DCLEAR_ZBUFFER ) != D3D_OK ) {
500                         mprintf(( "Failed to clear zbuffer!\n" ));
501                         return;
502                 }
503
504
505         } else {
506                 gr_zbuffering = 0;
507                 gr_zbuffering_mode = GR_ZBUFF_NONE;
508                 gr_global_zbuffering = 0;
509         }
510 }
511
512 // internal d3d rect function
513 void gr_d3d_rect_internal(int x, int y, int w, int h, int r, int g, int b, int a)
514 {
515         int saved_zbuf;
516         vertex v[4];
517         vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
518
519         saved_zbuf = gr_zbuffer_get();
520         
521         // start the frame, no zbuffering, no culling
522         g3_start_frame(1);      
523         gr_zbuffer_set(GR_ZBUFF_NONE);          
524         gr_set_cull(0);         
525
526         // stuff coords         
527         v[0].sx = i2fl(x);
528         v[0].sy = i2fl(y);
529         v[0].sw = 0.0f;
530         v[0].u = 0.0f;
531         v[0].v = 0.0f;
532         v[0].flags = PF_PROJECTED;
533         v[0].codes = 0;
534         v[0].r = (ubyte)r;
535         v[0].g = (ubyte)g;
536         v[0].b = (ubyte)b;
537         v[0].a = (ubyte)a;
538
539         v[1].sx = i2fl(x + w);
540         v[1].sy = i2fl(y);      
541         v[1].sw = 0.0f;
542         v[1].u = 0.0f;
543         v[1].v = 0.0f;
544         v[1].flags = PF_PROJECTED;
545         v[1].codes = 0;
546         v[1].r = (ubyte)r;
547         v[1].g = (ubyte)g;
548         v[1].b = (ubyte)b;
549         v[1].a = (ubyte)a;
550
551         v[2].sx = i2fl(x + w);
552         v[2].sy = i2fl(y + h);
553         v[2].sw = 0.0f;
554         v[2].u = 0.0f;
555         v[2].v = 0.0f;
556         v[2].flags = PF_PROJECTED;
557         v[2].codes = 0;
558         v[2].r = (ubyte)r;
559         v[2].g = (ubyte)g;
560         v[2].b = (ubyte)b;
561         v[2].a = (ubyte)a;
562
563         v[3].sx = i2fl(x);
564         v[3].sy = i2fl(y + h);
565         v[3].sw = 0.0f;
566         v[3].u = 0.0f;
567         v[3].v = 0.0f;
568         v[3].flags = PF_PROJECTED;
569         v[3].codes = 0;                         
570         v[3].r = (ubyte)r;
571         v[3].g = (ubyte)g;
572         v[3].b = (ubyte)b;
573         v[3].a = (ubyte)a;
574
575         // draw the polys
576         g3_draw_poly_constant_sw(4, verts, TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB | TMAP_FLAG_ALPHA, 0.1f);          
577
578         g3_end_frame();
579
580         // restore zbuffer and culling
581         gr_zbuffer_set(saved_zbuf);
582         gr_set_cull(1); 
583 }
584
585 int gr_d3d_zbuffer_get()
586 {
587         if ( !gr_global_zbuffering )    {
588                 return GR_ZBUFF_NONE;
589         }
590         return gr_zbuffering_mode;
591 }
592
593 int gr_d3d_zbuffer_set(int mode)
594 {
595         /*
596         if ( !gr_global_zbuffering )    {
597                 gr_zbuffering = 0;
598                 return GR_ZBUFF_NONE;
599         }
600         */
601
602         int tmp = gr_zbuffering_mode;
603
604         gr_zbuffering_mode = mode;
605
606         if ( gr_zbuffering_mode == GR_ZBUFF_NONE )      {
607                 gr_zbuffering = 0;
608         } else {
609                 gr_zbuffering = 1;
610         }
611         return tmp;
612 }
613
614 float D3D_line_offset = 0.0f;
615
616 void d3d_make_rect( D3DTLVERTEX *a, D3DTLVERTEX *b, int x1, int y1, int x2, int y2 )
617 {
618         // Alan's nvidia riva128 PCI screws up targetting brackets if 
619         // rhw are uninitialized.
620         a->rhw = 1.0f;
621         b->rhw = 1.0f;
622
623         // just for completeness, initialize specular and sz.
624         a->specular = 0;
625         b->specular = 0;
626
627         a->sz = 0.99f;
628         b->sz = 0.99f;
629
630         a->sx = i2fl(x1 + gr_screen.offset_x)+D3D_line_offset;
631         a->sy = i2fl(y1 + gr_screen.offset_y)+D3D_line_offset;
632
633         b->sx = i2fl(x2 + gr_screen.offset_x)+D3D_line_offset;
634         b->sy = i2fl(y2 + gr_screen.offset_y)+D3D_line_offset;
635
636         if ( x1 == x2 ) {
637                 // Verticle line
638                 if ( a->sy < b->sy )    {
639                         b->sy += 0.5f;
640                 } else {
641                         a->sy += 0.5f;
642                 }
643         } else if ( y1 == y2 )  {
644                 // Horizontal line
645                 if ( a->sx < b->sx )    {
646                         b->sx += 0.5f;
647                 } else {
648                         a->sx += 0.5f;
649                 }
650         }
651
652 }
653
654 // basically just fills in the alpha component of the specular color. Hardware does the rest
655 // when rendering the poly
656 void gr_d3d_stuff_fog_value(float z, D3DCOLOR *spec)
657 {
658         float f_float;  
659         *spec = 0;
660
661         // linear fog formula
662         f_float = (gr_screen.fog_far - z) / (gr_screen.fog_far - gr_screen.fog_near);
663         if(f_float < 0.0f){
664                 f_float = 0.0f;
665         } else if(f_float > 1.0f){
666                 f_float = 1.0f;
667         }
668         *spec = D3DRGBA(0.0f, 0.0f, 0.0f, f_float);
669 }
670
671 float z_mult = 30000.0f;
672 DCF(zmult, "")
673 {
674         dc_get_arg(ARG_FLOAT);
675         z_mult = Dc_arg_float;
676 }
677
678 float flCAP( float x, float minx, float maxx)
679 {
680         if ( x < minx ) {
681                 return minx;
682         } else if ( x > maxx )  {
683                 return maxx;
684         }
685         return x;
686 }
687
688 #define NEBULA_COLORS 20
689
690 void gr_d3d_tmapper_internal( int nverts, vertex **verts, uint flags, int is_scaler )   
691 {
692         int i;
693         float u_scale = 1.0f, v_scale = 1.0f;
694         int bw = 1, bh = 1;             
695
696         // Make nebula use the texture mapper... this blends the colors better.
697         if ( flags & TMAP_FLAG_NEBULA ){
698                 Int3();
699                 /*
700                 flags |= TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT;
701
702                 static int test_bmp = -1;
703                 static ushort data[16];
704                 if ( test_bmp == -1 ){
705                         ushort pix;
706                         ubyte a, r, g, b;
707                         int idx;
708
709                         // stuff the fake bitmap
710                         a = 1; r = 255; g = 255; b = 255;
711                         pix = 0;
712                         bm_set_components((ubyte*)&pix, &r, &g, &b, &a);                        
713                         for(idx=0; idx<16; idx++){
714                                 data[idx] = pix;
715                         }                       
716                         test_bmp = bm_create( 16, 4, 4, data );
717                 }
718                 gr_set_bitmap( test_bmp );
719
720                 for (i=0; i<nverts; i++ )       {
721                         verts[i]->u = verts[i]->v = 0.5f;
722                 }
723                 */
724         }
725
726         gr_texture_source texture_source = (gr_texture_source)-1;
727         gr_alpha_blend alpha_blend = (gr_alpha_blend)-1;
728         gr_zbuffer_type zbuffer_type = (gr_zbuffer_type)-1;
729
730
731         if ( gr_zbuffering )    {
732                 if ( is_scaler || (gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER)   )       {
733                         zbuffer_type = ZBUFFER_TYPE_READ;
734                 } else {
735                         zbuffer_type = ZBUFFER_TYPE_FULL;
736                 }
737         } else {
738                 zbuffer_type = ZBUFFER_TYPE_NONE;
739         }
740
741         int alpha;
742
743         int tmap_type = TCACHE_TYPE_NORMAL;
744
745         int r, g, b;
746
747         if ( flags & TMAP_FLAG_TEXTURED )       {
748                 r = 255;
749                 g = 255;
750                 b = 255;
751         } else {
752                 r = gr_screen.current_color.red;
753                 g = gr_screen.current_color.green;
754                 b = gr_screen.current_color.blue;
755         }
756
757         if ( gr_screen.current_alphablend_mode == GR_ALPHABLEND_FILTER )        {
758
759                 if ( lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE  )       {
760                         tmap_type = TCACHE_TYPE_NORMAL;
761                         alpha_blend = ALPHA_BLEND_ALPHA_ADDITIVE;
762
763                         // Blend with screen pixel using src*alpha+dst
764                         float factor = gr_screen.current_alpha;
765
766                         alpha = 255;
767
768                         if ( factor <= 1.0f )   {
769                                 int tmp_alpha = fl2i(gr_screen.current_alpha*255.0f);
770                                 r = (r*tmp_alpha)/255;
771                                 g = (g*tmp_alpha)/255;
772                                 b = (b*tmp_alpha)/255;
773                         }
774                 } else {
775
776                         tmap_type = TCACHE_TYPE_XPARENT;
777
778                         alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA;
779
780                         // Blend with screen pixel using src*alpha+dst
781                         float factor = gr_screen.current_alpha;
782
783                         if ( factor > 1.0f )    {
784                                 alpha = 255;
785                         } else {
786                                 alpha = fl2i(gr_screen.current_alpha*255.0f);
787                         }
788                 }
789         } else {
790                 if(Bm_pixel_format == BM_PIXEL_FORMAT_ARGB_D3D){
791                         alpha_blend = ALPHA_BLEND_ALPHA_BLEND_ALPHA;
792                 } else {
793                         alpha_blend = ALPHA_BLEND_NONE;
794                 }
795                 alpha = 255;
796         }
797
798         if(flags & TMAP_FLAG_BITMAP_SECTION){
799                 tmap_type = TCACHE_TYPE_BITMAP_SECTION;
800         }
801
802         texture_source = TEXTURE_SOURCE_NONE;
803  
804         if ( flags & TMAP_FLAG_TEXTURED )       {
805                 if ( !gr_tcache_set(gr_screen.current_bitmap, tmap_type, &u_scale, &v_scale, 0, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy ))     {
806                         mprintf(( "Not rendering a texture because it didn't fit in VRAM!\n" ));
807                         return;
808                 }
809
810                 // use nonfiltered textures for bitmap sections
811                 if(flags & TMAP_FLAG_BITMAP_SECTION){
812                         texture_source = TEXTURE_SOURCE_NO_FILTERING;
813                 } else {
814                         texture_source = TEXTURE_SOURCE_DECAL;
815                 }
816         }
817         
818         gr_d3d_set_state( texture_source, alpha_blend, zbuffer_type );
819         
820         D3DTLVERTEX d3d_verts[32];
821         D3DTLVERTEX *src_v = d3d_verts;
822
823         int x1, y1, x2, y2;
824         x1 = gr_screen.clip_left*16;
825         x2 = gr_screen.clip_right*16+15;
826         y1 = gr_screen.clip_top*16;
827         y2 = gr_screen.clip_bottom*16+15;
828
829         float uoffset = 0.0f;
830         float voffset = 0.0f;
831
832         float minu=0.0f, minv=0.0f, maxu=1.0f, maxv=1.0f;
833
834         if ( flags & TMAP_FLAG_TEXTURED )       {                                                               
835                 if ( D3d_rendition_uvs )        {                               
836                         bm_get_info(gr_screen.current_bitmap, &bw, &bh);                        
837                                 
838                         uoffset = 2.0f/i2fl(bw);
839                         voffset = 2.0f/i2fl(bh);
840
841                         minu = uoffset;
842                         minv = voffset;
843
844                         maxu = 1.0f - uoffset;
845                         maxv = 1.0f - voffset;
846                 }                               
847         }       
848
849         // turn on pixel fog if we're rendering against a fullneb background
850         // if(flags & TMAP_FLAG_PIXEL_FOG){                                     
851                 // set fog
852         //      gr_fog_set(GR_FOGMODE_FOG, gr_screen.current_fog_color.red, gr_screen.current_fog_color.green, gr_screen.current_fog_color.blue);
853         // }                                    
854                 
855         for (i=0; i<nverts; i++ )       {
856                 vertex * va = verts[i];         
857                                 
858                 // store in case we're doing vertex fog.                
859                 if ( gr_zbuffering || (flags & TMAP_FLAG_NEBULA) )      {
860                         src_v->sz = va->z / z_mult;     // For zbuffering and fogging
861                         if ( src_v->sz > 0.98f )        {
862                                 src_v->sz = 0.98f;
863                         }               
864                 } else {
865                         src_v->sz = 0.99f;
866                 }                       
867
868                 if ( flags & TMAP_FLAG_CORRECT )        {
869                         src_v->rhw = va->sw;                            // For texture correction                                               
870                 } else {
871                         src_v->rhw = 1.0f;                              // For texture correction 
872                 }
873
874                 int a;
875
876                 if ( flags & TMAP_FLAG_ALPHA )  {
877                         a = verts[i]->a;
878                 } else {
879                         a = alpha;
880                 }
881
882                 if ( flags & TMAP_FLAG_NEBULA ) {
883                         int pal = (verts[i]->b*(NEBULA_COLORS-1))/255;
884                         r = gr_palette[pal*3+0];
885                         g = gr_palette[pal*3+1];
886                         b = gr_palette[pal*3+2];
887                 } else if ( (flags & TMAP_FLAG_RAMP) && (flags & TMAP_FLAG_GOURAUD) )   {
888                         r = Gr_gamma_lookup[verts[i]->b];
889                         g = Gr_gamma_lookup[verts[i]->b];
890                         b = Gr_gamma_lookup[verts[i]->b];
891                 } else if ( (flags & TMAP_FLAG_RGB)  && (flags & TMAP_FLAG_GOURAUD) )   {
892                         // Make 0.75 be 256.0f
893                         r = Gr_gamma_lookup[verts[i]->r];
894                         g = Gr_gamma_lookup[verts[i]->g];
895                         b = Gr_gamma_lookup[verts[i]->b];
896                 } else {
897                         // use constant RGB values...
898                 }
899
900                 src_v->color = RGBA_MAKE(r, g, b, a);
901
902                 // if we're fogging and we're doing vertex fog
903                 if((gr_screen.current_fog_mode != GR_FOGMODE_NONE) && (D3D_fog_mode == 1)){
904                         gr_d3d_stuff_fog_value(va->z, &src_v->specular);
905                 } else {
906                         src_v->specular = 0;
907                 }
908
909                 int x, y;
910                 x = fl2i(va->sx*16.0f);
911                 y = fl2i(va->sy*16.0f);
912
913                 x += gr_screen.offset_x*16;
914                 y += gr_screen.offset_y*16;
915                 
916                 src_v->sx = i2fl(x) / 16.0f;
917                 src_v->sy = i2fl(y) / 16.0f;
918
919                 if ( flags & TMAP_FLAG_TEXTURED )       {
920                         // argh. rendition
921                         if ( D3d_rendition_uvs ){                               
922                                 // tiled texture (ships, etc), bitmap sections
923                                 if(flags & TMAP_FLAG_TILED){                                    
924                                         src_v->tu = va->u*u_scale;
925                                         src_v->tv = va->v*v_scale;
926                                 }
927                                 // sectioned
928                                 else if(flags & TMAP_FLAG_BITMAP_SECTION){
929                                         int sw, sh;
930                                         bm_get_section_size(gr_screen.current_bitmap, gr_screen.current_bitmap_sx, gr_screen.current_bitmap_sy, &sw, &sh);
931
932                                         src_v->tu = (va->u + (0.5f / i2fl(sw))) * u_scale;
933                                         src_v->tv = (va->v + (0.5f / i2fl(sh))) * v_scale;
934                                 }
935                                 // all else.
936                                 else {                          
937                                         src_v->tu = flCAP(va->u, minu, maxu);
938                                         src_v->tv = flCAP(va->v, minv, maxv);
939                                 }                               
940                         }
941                         // yay. non-rendition
942                         else {
943                                 src_v->tu = va->u*u_scale;
944                                 src_v->tv = va->v*v_scale;
945                         }                                                       
946                 } else {
947                         src_v->tu = 0.0f;
948                         src_v->tv = 0.0f;
949                 }
950                 src_v++;
951         }
952
953         // if we're rendering against a fullneb background
954         if(flags & TMAP_FLAG_PIXEL_FOG){        
955                 int r, g, b;
956                 int ra, ga, ba;         
957                 ra = ga = ba = 0;               
958
959                 // get the average pixel color behind the vertices
960                 for(i=0; i<nverts; i++){                        
961                         neb2_get_pixel((int)d3d_verts[i].sx, (int)d3d_verts[i].sy, &r, &g, &b);
962                         ra += r;
963                         ga += g;
964                         ba += b;
965                 }                               
966                 ra /= nverts;
967                 ga /= nverts;
968                 ba /= nverts;           
969
970                 // set fog
971                 gr_fog_set(GR_FOGMODE_FOG, ra, ga, ba);
972         }                                       
973
974         d3d_DrawPrimitive(D3DPT_TRIANGLEFAN, D3DVT_TLVERTEX, (LPVOID)d3d_verts, nverts, NULL);
975
976         // turn off fog
977         // if(flags & TMAP_FLAG_PIXEL_FOG){
978                 // gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
979         // }
980 }
981
982 void gr_d3d_tmapper( int nverts, vertex **verts, uint flags )   
983 {
984         gr_d3d_tmapper_internal( nverts, verts, flags, 0 );
985 }
986
987 #define FIND_SCALED_NUM(x,x0,x1,y0,y1) (((((x)-(x0))*((y1)-(y0)))/((x1)-(x0)))+(y0))
988
989 void gr_d3d_scaler(vertex *va, vertex *vb )
990 {
991         float x0, y0, x1, y1;
992         float u0, v0, u1, v1;
993         float clipped_x0, clipped_y0, clipped_x1, clipped_y1;
994         float clipped_u0, clipped_v0, clipped_u1, clipped_v1;
995         float xmin, xmax, ymin, ymax;
996         int dx0, dy0, dx1, dy1;
997
998         //============= CLIP IT =====================
999
1000         x0 = va->sx; y0 = va->sy;
1001         x1 = vb->sx; y1 = vb->sy;
1002
1003         xmin = i2fl(gr_screen.clip_left); ymin = i2fl(gr_screen.clip_top);
1004         xmax = i2fl(gr_screen.clip_right); ymax = i2fl(gr_screen.clip_bottom);
1005
1006         u0 = va->u; v0 = va->v;
1007         u1 = vb->u; v1 = vb->v;
1008
1009         // Check for obviously offscreen bitmaps...
1010         if ( (y1<=y0) || (x1<=x0) ) return;
1011         if ( (x1<xmin ) || (x0>xmax) ) return;
1012         if ( (y1<ymin ) || (y0>ymax) ) return;
1013
1014         clipped_u0 = u0; clipped_v0 = v0;
1015         clipped_u1 = u1; clipped_v1 = v1;
1016
1017         clipped_x0 = x0; clipped_y0 = y0;
1018         clipped_x1 = x1; clipped_y1 = y1;
1019
1020         // Clip the left, moving u0 right as necessary
1021         if ( x0 < xmin )        {
1022                 clipped_u0 = FIND_SCALED_NUM(xmin,x0,x1,u0,u1);
1023                 clipped_x0 = xmin;
1024         }
1025
1026         // Clip the right, moving u1 left as necessary
1027         if ( x1 > xmax )        {
1028                 clipped_u1 = FIND_SCALED_NUM(xmax,x0,x1,u0,u1);
1029                 clipped_x1 = xmax;
1030         }
1031
1032         // Clip the top, moving v0 down as necessary
1033         if ( y0 < ymin )        {
1034                 clipped_v0 = FIND_SCALED_NUM(ymin,y0,y1,v0,v1);
1035                 clipped_y0 = ymin;
1036         }
1037
1038         // Clip the bottom, moving v1 up as necessary
1039         if ( y1 > ymax )        {
1040                 clipped_v1 = FIND_SCALED_NUM(ymax,y0,y1,v0,v1);
1041                 clipped_y1 = ymax;
1042         }
1043         
1044         dx0 = fl2i(clipped_x0); dx1 = fl2i(clipped_x1);
1045         dy0 = fl2i(clipped_y0); dy1 = fl2i(clipped_y1);
1046
1047         if (dx1<=dx0) return;
1048         if (dy1<=dy0) return;
1049
1050         //============= DRAW IT =====================
1051
1052         vertex v[4];
1053         vertex *vl[4];
1054
1055         vl[0] = &v[0];  
1056         v->sx = clipped_x0;
1057         v->sy = clipped_y0;
1058         v->sw = va->sw;
1059         v->z = va->z;
1060         v->u = clipped_u0;
1061         v->v = clipped_v0;
1062
1063         vl[1] = &v[1];  
1064         v[1].sx = clipped_x1;
1065         v[1].sy = clipped_y0;
1066         v[1].sw = va->sw;
1067         v[1].z = va->z;
1068         v[1].u = clipped_u1;
1069         v[1].v = clipped_v0;
1070
1071         vl[2] = &v[2];  
1072         v[2].sx = clipped_x1;
1073         v[2].sy = clipped_y1;
1074         v[2].sw = va->sw;
1075         v[2].z = va->z;
1076         v[2].u = clipped_u1;
1077         v[2].v = clipped_v1;
1078
1079         vl[3] = &v[3];  
1080         v[3].sx = clipped_x0;
1081         v[3].sy = clipped_y1;
1082         v[3].sw = va->sw;
1083         v[3].z = va->z;
1084         v[3].u = clipped_u0;
1085         v[3].v = clipped_v1;
1086
1087         gr_d3d_tmapper_internal( 4, vl, TMAP_FLAG_TEXTURED, 1 );
1088 }
1089
1090 void gr_d3d_aascaler(vertex *va, vertex *vb )
1091 {
1092 }
1093
1094
1095 void gr_d3d_pixel(int x, int y)
1096 {
1097         gr_line(x,y,x,y);
1098 }
1099
1100
1101 void gr_d3d_clear()
1102 {
1103         // Turn off zbuffering so this doesn't clear the zbuffer
1104         gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1105
1106         RECT dst;
1107         DDBLTFX ddbltfx;
1108         DDSURFACEDESC ddsd;     
1109
1110         // Get the surface desc
1111         ddsd.dwSize = sizeof(ddsd);
1112         lpBackBuffer->GetSurfaceDesc(&ddsd);   
1113
1114         memset(&ddbltfx, 0, sizeof(ddbltfx));
1115         ddbltfx.dwSize = sizeof(DDBLTFX);
1116
1117         ddbltfx.dwFillColor = RGB_MAKE(gr_screen.current_clear_color.red, gr_screen.current_clear_color.green, gr_screen.current_clear_color.blue);
1118
1119         dst.left = gr_screen.clip_left+gr_screen.offset_x;
1120         dst.top = gr_screen.clip_top+gr_screen.offset_y;
1121         dst.right = gr_screen.clip_right+1+gr_screen.offset_x;
1122         dst.bottom = gr_screen.clip_bottom+1+gr_screen.offset_y;        
1123
1124         if ( lpBackBuffer->Blt( &dst, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx ) != DD_OK )   {
1125                 return;
1126         }
1127 }
1128
1129
1130 // sets the clipping region & offset
1131 void gr_d3d_set_clip(int x,int y,int w,int h)
1132 {
1133         gr_screen.offset_x = x;
1134         gr_screen.offset_y = y;
1135
1136         gr_screen.clip_left = 0;
1137         gr_screen.clip_right = w-1;
1138
1139         gr_screen.clip_top = 0;
1140         gr_screen.clip_bottom = h-1;
1141
1142         // check for sanity of parameters
1143         if ( gr_screen.clip_left+x < 0 ) {
1144                 gr_screen.clip_left = -x;
1145         } else if ( gr_screen.clip_left+x > gr_screen.max_w-1 ) {
1146                 gr_screen.clip_left = gr_screen.max_w-1-x;
1147         }
1148         if ( gr_screen.clip_right+x < 0 ) {
1149                 gr_screen.clip_right = -x;
1150         } else if ( gr_screen.clip_right+x >= gr_screen.max_w-1 )       {
1151                 gr_screen.clip_right = gr_screen.max_w-1-x;
1152         }
1153
1154         if ( gr_screen.clip_top+y < 0 ) {
1155                 gr_screen.clip_top = -y;
1156         } else if ( gr_screen.clip_top+y > gr_screen.max_h-1 )  {
1157                 gr_screen.clip_top = gr_screen.max_h-1-y;
1158         }
1159
1160         if ( gr_screen.clip_bottom+y < 0 ) {
1161                 gr_screen.clip_bottom = -y;
1162         } else if ( gr_screen.clip_bottom+y > gr_screen.max_h-1 )       {
1163                 gr_screen.clip_bottom = gr_screen.max_h-1-y;
1164         }
1165
1166         gr_screen.clip_width = gr_screen.clip_right - gr_screen.clip_left + 1;
1167         gr_screen.clip_height = gr_screen.clip_bottom - gr_screen.clip_top + 1;
1168
1169         // Setup the viewport for a reasonable viewing area
1170         D3DVIEWPORT viewdata;
1171         DWORD       largest_side;
1172         HRESULT         ddrval;
1173
1174         // Compensate for aspect ratio
1175         if ( gr_screen.clip_width > gr_screen.clip_height )
1176                 largest_side = gr_screen.clip_width;
1177         else
1178                 largest_side = gr_screen.clip_height;
1179
1180         viewdata.dwSize = sizeof( viewdata );
1181         viewdata.dwX = gr_screen.clip_left+x;
1182         viewdata.dwY = gr_screen.clip_top+y;
1183         viewdata.dwWidth = gr_screen.clip_width;
1184         viewdata.dwHeight = gr_screen.clip_height;
1185         viewdata.dvScaleX = largest_side / 2.0F;
1186         viewdata.dvScaleY = largest_side / 2.0F;
1187         viewdata.dvMaxX = ( float ) ( viewdata.dwWidth / ( 2.0F * viewdata.dvScaleX ) );
1188         viewdata.dvMaxY = ( float ) ( viewdata.dwHeight / ( 2.0F * viewdata.dvScaleY ) );
1189         viewdata.dvMinZ = 0.0F;
1190         viewdata.dvMaxZ = 0.0F; // choose something appropriate here!
1191
1192         ddrval = lpViewport->SetViewport( &viewdata );
1193         if ( ddrval != DD_OK )  {
1194                 mprintf(( "GR_D3D_SET_CLIP: SetViewport failed.\n" ));
1195         }
1196
1197 }
1198
1199
1200 void gr_d3d_reset_clip()
1201 {
1202         gr_screen.offset_x = 0;
1203         gr_screen.offset_y = 0;
1204         gr_screen.clip_left = 0;
1205         gr_screen.clip_top = 0;
1206         gr_screen.clip_right = gr_screen.max_w - 1;
1207         gr_screen.clip_bottom = gr_screen.max_h - 1;
1208         gr_screen.clip_width = gr_screen.max_w;
1209         gr_screen.clip_height = gr_screen.max_h;
1210
1211         // Setup the viewport for a reasonable viewing area
1212         D3DVIEWPORT viewdata;
1213         DWORD       largest_side;
1214         HRESULT         ddrval;
1215
1216         // Compensate for aspect ratio
1217         if ( gr_screen.clip_width > gr_screen.clip_height )
1218                 largest_side = gr_screen.clip_width;
1219         else
1220                 largest_side = gr_screen.clip_height;
1221
1222         viewdata.dwSize = sizeof( viewdata );
1223         viewdata.dwX = gr_screen.clip_left;
1224         viewdata.dwY = gr_screen.clip_top;
1225         viewdata.dwWidth = gr_screen.clip_width;
1226         viewdata.dwHeight = gr_screen.clip_height;
1227         viewdata.dvScaleX = largest_side / 2.0F;
1228         viewdata.dvScaleY = largest_side / 2.0F;
1229         viewdata.dvMaxX = ( float ) ( viewdata.dwWidth / ( 2.0F * viewdata.dvScaleX ) );
1230         viewdata.dvMaxY = ( float ) ( viewdata.dwHeight / ( 2.0F * viewdata.dvScaleY ) );
1231         viewdata.dvMinZ = 0.0F;
1232         viewdata.dvMaxZ = 0.0F; // choose something appropriate here!
1233
1234         ddrval = lpViewport->SetViewport( &viewdata );
1235         if ( ddrval != DD_OK )  {
1236                 mprintf(( "GR_D3D_SET_CLIP: SetViewport failed.\n" ));
1237         }
1238
1239 }
1240
1241 void gr_d3d_init_color(color *c, int r, int g, int b)
1242 {
1243         c->screen_sig = gr_screen.signature;
1244         c->red = unsigned char(r);
1245         c->green = unsigned char(g);
1246         c->blue = unsigned char(b);
1247         c->alpha = 255;
1248         c->ac_type = AC_TYPE_NONE;
1249         c->alphacolor = -1;
1250         c->is_alphacolor = 0;
1251         c->magic = 0xAC01;
1252 }
1253
1254 void gr_d3d_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type )
1255 {
1256         if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1257         if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1258         if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1259         if ( alpha < 0 ) alpha = 0; else if ( alpha > 255 ) alpha = 255;
1260
1261         gr_d3d_init_color( clr, r, g, b );
1262
1263         clr->alpha = unsigned char(alpha);
1264         clr->ac_type = (ubyte)type;
1265         clr->alphacolor = -1;
1266         clr->is_alphacolor = 1;
1267 }
1268
1269 void gr_d3d_set_color( int r, int g, int b )
1270 {
1271         SDL_assert((r >= 0) && (r < 256));
1272         SDL_assert((g >= 0) && (g < 256));
1273         SDL_assert((b >= 0) && (b < 256));
1274
1275         gr_d3d_init_color( &gr_screen.current_color, r, g, b );
1276 }
1277
1278 void gr_d3d_get_color( int * r, int * g, int * b )
1279 {
1280         if (r) *r = gr_screen.current_color.red;
1281         if (g) *g = gr_screen.current_color.green;
1282         if (b) *b = gr_screen.current_color.blue;
1283 }
1284
1285 void gr_d3d_set_color_fast(color *dst)
1286 {
1287         if ( dst->screen_sig != gr_screen.signature )   {
1288                 if ( dst->is_alphacolor )       {
1289                         gr_d3d_init_alphacolor( dst, dst->red, dst->green, dst->blue, dst->alpha, dst->ac_type );
1290                 } else {
1291                         gr_d3d_init_color( dst, dst->red, dst->green, dst->blue );
1292                 }
1293         }
1294         gr_screen.current_color = *dst;
1295 }
1296
1297 void gr_d3d_set_bitmap( int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha, int sx, int sy )
1298 {
1299         gr_screen.current_alpha = alpha;
1300         gr_screen.current_alphablend_mode = alphablend_mode;
1301         gr_screen.current_bitblt_mode = bitblt_mode;
1302         gr_screen.current_bitmap = bitmap_num;
1303         gr_screen.current_bitmap_sx = sx;
1304         gr_screen.current_bitmap_sy = sy;
1305 }
1306
1307 void gr_d3d_bitmap_ex_internal(int x,int y,int w,int h,int sx,int sy)
1308 {
1309         int i,j;
1310         bitmap * bmp;
1311         ushort * sptr;
1312         ushort * dptr;
1313         HRESULT ddrval;
1314         DDSURFACEDESC ddsd;
1315
1316         memset( &ddsd, 0, sizeof( ddsd ) );
1317         ddsd.dwSize = sizeof( ddsd );
1318
1319         ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
1320         if ( ddrval != DD_OK )  {
1321                 mprintf(( "Error locking surface for bitmap_ex, %s\n", d3d_error_string(ddrval) ));
1322                 return;
1323         }
1324
1325         dptr = (ushort *)((int)ddsd.lpSurface+ddsd.lPitch*(y+gr_screen.offset_y)+(x+gr_screen.offset_x)*2);
1326
1327         bmp = bm_lock( gr_screen.current_bitmap, 16, 0 );
1328         sptr = (ushort *)( bmp->data + (sy*bmp->w + sx) );
1329
1330         // nice and speedy compared to the old way
1331         for (i=0; i<h; i++ )    {
1332                 for ( j=0; j<w; j++ )   {                               
1333                         // if its not transparent, blit it                      
1334                         if(sptr[j] != Gr_green.mask){
1335                                 dptr[j] = sptr[j];
1336                         }
1337                 }
1338                 
1339                 // next row on the screen
1340                 dptr = (ushort *)((uint)dptr + ddsd.lPitch);
1341
1342                 // next row in the bitmap
1343                 sptr += bmp->w;
1344         }       
1345
1346         bm_unlock(gr_screen.current_bitmap);
1347
1348         // Unlock the back buffer
1349         lpBackBuffer->Unlock( NULL );
1350 }
1351
1352 void gr_d3d_bitmap_ex(int x,int y,int w,int h,int sx,int sy)
1353 {
1354         int reclip;
1355         #ifndef NDEBUG
1356         int count = 0;
1357         #endif
1358
1359         int dx1=x, dx2=x+w-1;
1360         int dy1=y, dy2=y+h-1;
1361
1362         int bw, bh;
1363         bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
1364
1365         do {
1366                 reclip = 0;
1367                 #ifndef NDEBUG
1368                         if ( count > 1 ) Int3();
1369                         count++;
1370                 #endif
1371         
1372                 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1373                 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1374                 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1375                 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1376                 if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
1377                 if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
1378
1379                 if ( sx < 0 ) {
1380                         dx1 -= sx;
1381                         sx = 0;
1382                         reclip = 1;
1383                 }
1384
1385                 if ( sy < 0 ) {
1386                         dy1 -= sy;
1387                         sy = 0;
1388                         reclip = 1;
1389                 }
1390
1391                 w = dx2-dx1+1;
1392                 h = dy2-dy1+1;
1393
1394                 if ( sx + w > bw ) {
1395                         w = bw - sx;
1396                         dx2 = dx1 + w - 1;
1397                 }
1398
1399                 if ( sy + h > bh ) {
1400                         h = bh - sy;
1401                         dy2 = dy1 + h - 1;
1402                 }
1403
1404                 if ( w < 1 ) return;            // clipped away!
1405                 if ( h < 1 ) return;            // clipped away!
1406
1407         } while (reclip);
1408
1409         // Make sure clipping algorithm works
1410         #ifndef NDEBUG
1411                 SDL_assert( w > 0 );
1412                 SDL_assert( h > 0 );
1413                 SDL_assert( w == (dx2-dx1+1) );
1414                 SDL_assert( h == (dy2-dy1+1) );
1415                 SDL_assert( sx >= 0 );
1416                 SDL_assert( sy >= 0 );
1417                 SDL_assert( sx+w <= bw );
1418                 SDL_assert( sy+h <= bh );
1419                 SDL_assert( dx2 >= dx1 );
1420                 SDL_assert( dy2 >= dy1 );
1421                 SDL_assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
1422                 SDL_assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
1423                 SDL_assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
1424                 SDL_assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
1425         #endif
1426
1427         // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
1428         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1429
1430         gr_d3d_bitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1431 }
1432
1433 void gr_d3d_bitmap(int x, int y)
1434 {
1435         int w, h;
1436
1437
1438         bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
1439         int dx1=x, dx2=x+w-1;
1440         int dy1=y, dy2=y+h-1;
1441         int sx=0, sy=0;
1442
1443         if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1444         if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1445         if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1446         if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1447         if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
1448         if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
1449
1450         if ( sx < 0 ) return;
1451         if ( sy < 0 ) return;
1452         if ( sx >= w ) return;
1453         if ( sy >= h ) return;
1454
1455         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1456
1457         gr_d3d_bitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1458 }
1459
1460
1461
1462 void gr_d3d_aabitmap_ex_internal(int x,int y,int w,int h,int sx,int sy)
1463 {
1464         if ( w < 1 ) return;
1465         if ( h < 1 ) return;
1466
1467         if ( !gr_screen.current_color.is_alphacolor )   return;
1468
1469         float u_scale, v_scale;
1470
1471         gr_d3d_set_state( TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1472
1473         if ( !gr_tcache_set( gr_screen.current_bitmap, TCACHE_TYPE_AABITMAP, &u_scale, &v_scale ) )     {
1474                 // Couldn't set texture
1475                 //mprintf(( "GLIDE: Error setting aabitmap texture!\n" ));
1476                 return;
1477         }
1478
1479         LPD3DTLVERTEX src_v;
1480         D3DTLVERTEX d3d_verts[4];
1481
1482         float u0, u1, v0, v1;
1483         float x1, x2, y1, y2;
1484         int bw, bh;
1485
1486         bm_get_info( gr_screen.current_bitmap, &bw, &bh );
1487
1488         // Rendition
1489         if ( D3d_rendition_uvs )        {
1490                 u0 = u_scale*(i2fl(sx)+0.5f)/i2fl(bw);
1491                 v0 = v_scale*(i2fl(sy)+0.5f)/i2fl(bh);
1492
1493                 u1 = u_scale*(i2fl(sx+w)+0.5f)/i2fl(bw);
1494                 v1 = v_scale*(i2fl(sy+h)+0.5f)/i2fl(bh);
1495         } else {
1496                 u0 = u_scale*i2fl(sx)/i2fl(bw);
1497                 v0 = v_scale*i2fl(sy)/i2fl(bh);
1498
1499                 u1 = u_scale*i2fl(sx+w)/i2fl(bw);
1500                 v1 = v_scale*i2fl(sy+h)/i2fl(bh);
1501         }
1502
1503         x1 = i2fl(x+gr_screen.offset_x);
1504         y1 = i2fl(y+gr_screen.offset_y);
1505         x2 = i2fl(x+w+gr_screen.offset_x);
1506         y2 = i2fl(y+h+gr_screen.offset_y);
1507
1508         src_v = d3d_verts;
1509
1510         uint color;
1511
1512         if ( gr_screen.current_color.is_alphacolor )    {
1513                 if ( lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATEALPHA )  {
1514                         color = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue,gr_screen.current_color.alpha);
1515                 } else {
1516                         int r = (gr_screen.current_color.red*gr_screen.current_color.alpha)/255;
1517                         int g = (gr_screen.current_color.green*gr_screen.current_color.alpha)/255;
1518                         int b = (gr_screen.current_color.blue*gr_screen.current_color.alpha)/255;
1519                 
1520                         color = RGBA_MAKE(r,g,b, 255 );
1521                 }
1522         } else {
1523                 color = RGB_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue);
1524         }
1525
1526         src_v->sz = 0.99f;
1527         src_v->rhw = 1.0f;
1528         src_v->color = color;    
1529         src_v->specular = 0;
1530         src_v->sx = x1;
1531         src_v->sy = y1;
1532         src_v->tu = u0;
1533         src_v->tv = v0;
1534         src_v++;
1535
1536         src_v->sz = 0.99f;
1537         src_v->rhw = 1.0f;
1538         src_v->color = color;    
1539         src_v->specular = 0;
1540         src_v->sx = x2;
1541         src_v->sy = y1;
1542         src_v->tu = u1;
1543         src_v->tv = v0;
1544         src_v++;
1545
1546         src_v->sz = 0.99f;
1547         src_v->rhw = 1.0f;
1548         src_v->color = color;    
1549         src_v->specular = 0;
1550         src_v->sx = x2;
1551         src_v->sy = y2;
1552         src_v->tu = u1;
1553         src_v->tv = v1;
1554         src_v++;
1555
1556         src_v->sz = 0.99f;
1557         src_v->rhw = 1.0f;
1558         src_v->color = color;    
1559         src_v->specular = 0;
1560         src_v->sx = x1;
1561         src_v->sy = y2;
1562         src_v->tu = u0;
1563         src_v->tv = v1;
1564
1565         d3d_DrawPrimitive(D3DPT_TRIANGLEFAN,D3DVT_TLVERTEX,(LPVOID)d3d_verts,4,NULL);
1566 }
1567
1568 void gr_d3d_aabitmap_ex(int x,int y,int w,int h,int sx,int sy)
1569 {
1570         int reclip;
1571         #ifndef NDEBUG
1572         int count = 0;
1573         #endif
1574
1575         int dx1=x, dx2=x+w-1;
1576         int dy1=y, dy2=y+h-1;
1577
1578         int bw, bh;
1579         bm_get_info( gr_screen.current_bitmap, &bw, &bh, NULL );
1580
1581         do {
1582                 reclip = 0;
1583                 #ifndef NDEBUG
1584                         if ( count > 1 ) Int3();
1585                         count++;
1586                 #endif
1587         
1588                 if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1589                 if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1590                 if ( dx1 < gr_screen.clip_left ) { sx += gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1591                 if ( dy1 < gr_screen.clip_top ) { sy += gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1592                 if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
1593                 if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
1594
1595                 if ( sx < 0 ) {
1596                         dx1 -= sx;
1597                         sx = 0;
1598                         reclip = 1;
1599                 }
1600
1601                 if ( sy < 0 ) {
1602                         dy1 -= sy;
1603                         sy = 0;
1604                         reclip = 1;
1605                 }
1606
1607                 w = dx2-dx1+1;
1608                 h = dy2-dy1+1;
1609
1610                 if ( sx + w > bw ) {
1611                         w = bw - sx;
1612                         dx2 = dx1 + w - 1;
1613                 }
1614
1615                 if ( sy + h > bh ) {
1616                         h = bh - sy;
1617                         dy2 = dy1 + h - 1;
1618                 }
1619
1620                 if ( w < 1 ) return;            // clipped away!
1621                 if ( h < 1 ) return;            // clipped away!
1622
1623         } while (reclip);
1624
1625         // Make sure clipping algorithm works
1626         #ifndef NDEBUG
1627                 SDL_assert( w > 0 );
1628                 SDL_assert( h > 0 );
1629                 SDL_assert( w == (dx2-dx1+1) );
1630                 SDL_assert( h == (dy2-dy1+1) );
1631                 SDL_assert( sx >= 0 );
1632                 SDL_assert( sy >= 0 );
1633                 SDL_assert( sx+w <= bw );
1634                 SDL_assert( sy+h <= bh );
1635                 SDL_assert( dx2 >= dx1 );
1636                 SDL_assert( dy2 >= dy1 );
1637                 SDL_assert( (dx1 >= gr_screen.clip_left ) && (dx1 <= gr_screen.clip_right) );
1638                 SDL_assert( (dx2 >= gr_screen.clip_left ) && (dx2 <= gr_screen.clip_right) );
1639                 SDL_assert( (dy1 >= gr_screen.clip_top ) && (dy1 <= gr_screen.clip_bottom) );
1640                 SDL_assert( (dy2 >= gr_screen.clip_top ) && (dy2 <= gr_screen.clip_bottom) );
1641         #endif
1642
1643         // We now have dx1,dy1 and dx2,dy2 and sx, sy all set validly within clip regions.
1644         gr_d3d_aabitmap_ex_internal(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1645 }
1646
1647 void gr_d3d_aabitmap(int x, int y)
1648 {
1649         int w, h;
1650
1651         bm_get_info( gr_screen.current_bitmap, &w, &h, NULL );
1652         int dx1=x, dx2=x+w-1;
1653         int dy1=y, dy2=y+h-1;
1654         int sx=0, sy=0;
1655
1656         if ((dx1 > gr_screen.clip_right ) || (dx2 < gr_screen.clip_left)) return;
1657         if ((dy1 > gr_screen.clip_bottom ) || (dy2 < gr_screen.clip_top)) return;
1658         if ( dx1 < gr_screen.clip_left ) { sx = gr_screen.clip_left-dx1; dx1 = gr_screen.clip_left; }
1659         if ( dy1 < gr_screen.clip_top ) { sy = gr_screen.clip_top-dy1; dy1 = gr_screen.clip_top; }
1660         if ( dx2 > gr_screen.clip_right )       { dx2 = gr_screen.clip_right; }
1661         if ( dy2 > gr_screen.clip_bottom )      { dy2 = gr_screen.clip_bottom; }
1662
1663         if ( sx < 0 ) return;
1664         if ( sy < 0 ) return;
1665         if ( sx >= w ) return;
1666         if ( sy >= h ) return;
1667
1668         // Draw bitmap bm[sx,sy] into (dx1,dy1)-(dx2,dy2)
1669         gr_aabitmap_ex(dx1,dy1,dx2-dx1+1,dy2-dy1+1,sx,sy);
1670 }
1671
1672
1673 void gr_d3d_string( int sx, int sy, char *s )
1674 {
1675         int width, spacing, letter;
1676         int x, y;
1677
1678         if ( !Current_font )    {
1679                 return;
1680         }
1681
1682         gr_set_bitmap(Current_font->bitmap_id);
1683
1684         x = sx;
1685         y = sy;
1686
1687         if (sx==0x8000) {                       //centered
1688                 x = get_centered_x(s);
1689         } else {
1690                 x = sx;
1691         }
1692         
1693         spacing = 0;
1694
1695         while (*s)      {
1696                 x += spacing;
1697
1698                 while (*s== '\n' )      {
1699                         s++;
1700                         y += Current_font->h;
1701                         if (sx==0x8000) {                       //centered
1702                                 x = get_centered_x(s);
1703                         } else {
1704                                 x = sx;
1705                         }
1706                 }
1707                 if (*s == 0 ) break;
1708
1709                 letter = get_char_width(s[0],s[1],&width,&spacing);
1710                 s++;
1711
1712                 //not in font, draw as space
1713                 if (letter<0)   {
1714                         continue;
1715                 }
1716
1717                 int xd, yd, xc, yc;
1718                 int wc, hc;
1719
1720                 // Check if this character is totally clipped
1721                 if ( x + width < gr_screen.clip_left ) continue;
1722                 if ( y + Current_font->h < gr_screen.clip_top ) continue;
1723                 if ( x > gr_screen.clip_right ) continue;
1724                 if ( y > gr_screen.clip_bottom ) continue;
1725
1726                 xd = yd = 0;
1727                 if ( x < gr_screen.clip_left ) xd = gr_screen.clip_left - x;
1728                 if ( y < gr_screen.clip_top ) yd = gr_screen.clip_top - y;
1729                 xc = x+xd;
1730                 yc = y+yd;
1731
1732                 wc = width - xd; hc = Current_font->h - yd;
1733                 if ( xc + wc > gr_screen.clip_right ) wc = gr_screen.clip_right - xc;
1734                 if ( yc + hc > gr_screen.clip_bottom ) hc = gr_screen.clip_bottom - yc;
1735
1736                 if ( wc < 1 ) continue;
1737                 if ( hc < 1 ) continue;
1738
1739                 font_char *ch;
1740         
1741                 ch = &Current_font->char_data[letter];
1742
1743                 int u = Current_font->bm_u[letter];
1744                 int v = Current_font->bm_v[letter];
1745
1746                 gr_d3d_aabitmap_ex_internal( xc, yc, wc, hc, u+xd, v+yd );
1747         }
1748 }
1749
1750 void gr_d3d_rect(int x,int y,int w,int h)
1751 {
1752         gr_d3d_rect_internal(x, y, w, h, gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, gr_screen.current_color.alpha);      
1753 }
1754
1755 void gr_d3d_flash(int r, int g, int b)
1756 {
1757         CAP(r,0,255);
1758         CAP(g,0,255);
1759         CAP(b,0,255);
1760
1761         if ( r || g || b )      {
1762                 uint color;
1763                 if ( lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE  )       {
1764                         gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_ADDITIVE, ZBUFFER_TYPE_NONE );
1765                         color = RGBA_MAKE(r, g, b, 255);
1766                 } else {
1767                         gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1768         
1769                         int a = (r+g+b)/3;
1770                         color = RGBA_MAKE(r,g,b,a);
1771                 }
1772         
1773                 float x1, x2, y1, y2;
1774                 x1 = i2fl(gr_screen.clip_left+gr_screen.offset_x);
1775                 y1 = i2fl(gr_screen.clip_top+gr_screen.offset_y);
1776                 x2 = i2fl(gr_screen.clip_right+gr_screen.offset_x);
1777                 y2 = i2fl(gr_screen.clip_bottom+gr_screen.offset_y);
1778         
1779                 LPD3DTLVERTEX src_v;
1780                 D3DTLVERTEX d3d_verts[4];
1781
1782                 src_v = d3d_verts;
1783
1784                 src_v->sz = 0.99f;
1785                 src_v->rhw = 1.0f;
1786                 src_v->color = color;    
1787                 src_v->specular = 0;
1788                 src_v->sx = x1;
1789                 src_v->sy = y1;
1790                 src_v++;
1791
1792                 src_v->sz = 0.99f;
1793                 src_v->rhw = 1.0f;
1794                 src_v->color = color;    
1795                 src_v->specular = 0;
1796                 src_v->sx = x2;
1797                 src_v->sy = y1;
1798                 src_v++;
1799
1800                 src_v->sz = 0.99f;
1801                 src_v->rhw = 1.0f;
1802                 src_v->color = color;    
1803                 src_v->specular = 0;
1804                 src_v->sx = x2;
1805                 src_v->sy = y2;
1806                 src_v++;
1807
1808                 src_v->sz = 0.99f;
1809                 src_v->rhw = 1.0f;
1810                 src_v->color = color;    
1811                 src_v->specular = 0;
1812                 src_v->sx = x1;
1813                 src_v->sy = y2;
1814
1815                 d3d_DrawPrimitive(D3DPT_TRIANGLEFAN,D3DVT_TLVERTEX,(LPVOID)d3d_verts,4,NULL);
1816         }
1817 }
1818
1819
1820
1821 void gr_d3d_create_shader(shader * shade, float r, float g, float b, float c )
1822 {
1823         shade->screen_sig = gr_screen.signature;
1824         shade->r = r;
1825         shade->g = g;
1826         shade->b = b;
1827         shade->c = c;
1828 }
1829
1830 void gr_d3d_set_shader( shader * shade )
1831 {       
1832         if ( shade )    {
1833                 if (shade->screen_sig != gr_screen.signature)   {
1834                         gr_create_shader( shade, shade->r, shade->g, shade->b, shade->c );
1835                 }
1836                 gr_screen.current_shader = *shade;
1837         } else {
1838                 gr_create_shader( &gr_screen.current_shader, 0.0f, 0.0f, 0.0f, 0.0f );
1839         }
1840 }
1841
1842 void gr_d3d_shade(int x,int y,int w,int h)
1843 {       
1844         int r,g,b,a;
1845
1846         float shade1 = 1.0f;
1847         float shade2 = 6.0f;
1848
1849         r = fl2i(gr_screen.current_shader.r*255.0f*shade1);
1850         if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1851         g = fl2i(gr_screen.current_shader.g*255.0f*shade1);
1852         if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1853         b = fl2i(gr_screen.current_shader.b*255.0f*shade1);
1854         if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1855         a = fl2i(gr_screen.current_shader.c*255.0f*shade2);
1856         if ( a < 0 ) a = 0; else if ( a > 255 ) a = 255;
1857
1858         gr_d3d_rect_internal(x, y, w, h, r, g, b, a);   
1859 }
1860
1861 void gr_d3d_circle( int xc, int yc, int d )
1862 {
1863
1864         int p,x, y, r;
1865
1866         r = d/2;
1867         p=3-d;
1868         x=0;
1869         y=r;
1870
1871         // Big clip
1872         if ( (xc+r) < gr_screen.clip_left ) return;
1873         if ( (xc-r) > gr_screen.clip_right ) return;
1874         if ( (yc+r) < gr_screen.clip_top ) return;
1875         if ( (yc-r) > gr_screen.clip_bottom ) return;
1876
1877         while(x<y)      {
1878                 // Draw the first octant
1879                 gr_d3d_line( xc-y, yc-x, xc+y, yc-x );
1880                 gr_d3d_line( xc-y, yc+x, xc+y, yc+x );
1881
1882                 if (p<0) 
1883                         p=p+(x<<2)+6;
1884                 else    {
1885                         // Draw the second octant
1886                         gr_d3d_line( xc-x, yc-y, xc+x, yc-y );
1887                         gr_d3d_line( xc-x, yc+y, xc+x, yc+y );
1888                         p=p+((x-y)<<2)+10;
1889                         y--;
1890                 }
1891                 x++;
1892         }
1893         if(x==y)        {
1894                 gr_d3d_line( xc-x, yc-y, xc+x, yc-y );
1895                 gr_d3d_line( xc-x, yc+y, xc+x, yc+y );
1896         }
1897         return;
1898
1899 }
1900
1901
1902 void gr_d3d_line(int x1,int y1,int x2,int y2)
1903 {
1904         int clipped = 0, swapped=0;
1905         DWORD color;
1906
1907         // Set up Render State - flat shading - alpha blending
1908         if ( (lpDevDesc->dpcLineCaps.dwSrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) && (lpDevDesc->dpcLineCaps.dwDestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA)  )        {
1909                 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1910                 color = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, gr_screen.current_color.alpha );
1911         } else {
1912                 // Matrox MGA-G200 doesn't support alpha-blended lines.
1913                 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1914
1915                 int r = (gr_screen.current_color.red*gr_screen.current_color.alpha)/255;
1916                 int g = (gr_screen.current_color.green*gr_screen.current_color.alpha)/255;
1917                 int b = (gr_screen.current_color.blue*gr_screen.current_color.alpha)/255;
1918                 
1919                 color = RGBA_MAKE(r,g,b, 255 );
1920         }
1921
1922         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);
1923
1924         D3DTLVERTEX d3d_verts[2];
1925         D3DTLVERTEX *a = d3d_verts;
1926         D3DTLVERTEX *b = d3d_verts+1;
1927
1928         d3d_make_rect(a,b,x1,y1,x2,y2);
1929
1930         a->color = color;
1931         b->color = color;
1932
1933         d3d_DrawPrimitive(D3DPT_LINELIST,D3DVT_TLVERTEX,(LPVOID)d3d_verts,2,NULL);
1934 }
1935
1936 void gr_d3d_aaline(vertex *v1, vertex *v2)
1937 {
1938         gr_d3d_line( fl2i(v1->sx), fl2i(v1->sy), fl2i(v2->sx), fl2i(v2->sy) );
1939 }
1940
1941
1942 void gr_d3d_gradient(int x1,int y1,int x2,int y2)
1943 {
1944         int clipped = 0, swapped=0;
1945
1946         if ( !gr_screen.current_color.is_alphacolor )   {
1947                 gr_line( x1, y1, x2, y2 );
1948                 return;
1949         }
1950
1951         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);
1952
1953         uint color1, color2;
1954
1955         // Set up Render State - flat shading - alpha blending
1956         if ( (lpDevDesc->dpcLineCaps.dwSrcBlendCaps & D3DPBLENDCAPS_SRCALPHA) && (lpDevDesc->dpcLineCaps.dwDestBlendCaps & D3DPBLENDCAPS_INVSRCALPHA)  )        {
1957                 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE );
1958
1959                 if (lpDevDesc->dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_ALPHAGOURAUDBLEND )      {
1960                         color1 = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, gr_screen.current_color.alpha );
1961                         color2 = RGBA_MAKE(gr_screen.current_color.red, gr_screen.current_color.green, gr_screen.current_color.blue, 0 );
1962                 } else if (lpDevDesc->dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB ) {
1963                         color1 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,gr_screen.current_color.alpha);
1964                         color2 = RGBA_MAKE(0,0,0,gr_screen.current_color.alpha);
1965                 } else {
1966                         color1 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,gr_screen.current_color.alpha);
1967                         color2 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,gr_screen.current_color.alpha);
1968                 }
1969         } else {
1970                 // Matrox MGA-G200 doesn't support alpha-blended lines.
1971                 gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1972
1973                 int r = (gr_screen.current_color.red*gr_screen.current_color.alpha)/255;
1974                 int g = (gr_screen.current_color.green*gr_screen.current_color.alpha)/255;
1975                 int b = (gr_screen.current_color.blue*gr_screen.current_color.alpha)/255;
1976
1977                 if (lpDevDesc->dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_COLORGOURAUDRGB )        {
1978                         color1 = RGBA_MAKE(r,g,b, 255 );
1979                         color2 = RGBA_MAKE(0,0,0, 255 );
1980                 } else {
1981                         color1 = RGBA_MAKE(r,g,b, 255 );
1982                         color2 = RGBA_MAKE(r,g,b, 255 );
1983                 }
1984         }
1985
1986 //      gr_d3d_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE );
1987 //      color1 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,255);
1988 //      color2 = RGBA_MAKE(gr_screen.current_color.red,gr_screen.current_color.green,gr_screen.current_color.blue,255);
1989
1990         D3DTLVERTEX d3d_verts[2];
1991         D3DTLVERTEX *a = d3d_verts;
1992         D3DTLVERTEX *b = d3d_verts+1;
1993
1994         d3d_make_rect( a, b, x1, y1, x2, y2 );
1995
1996         if ( swapped )  {
1997                 b->color = color1;
1998                 a->color = color2;
1999         } else {
2000                 a->color = color1;
2001                 b->color = color2;
2002         }
2003         d3d_DrawPrimitive(D3DPT_LINELIST,D3DVT_TLVERTEX,(LPVOID)d3d_verts,2,NULL);
2004 }
2005
2006
2007 void gr_d3d_set_palette(ubyte *new_palette, int restrict_alphacolor)
2008 {
2009 }
2010
2011
2012 // copy from one pixel buffer to another
2013 //
2014 //    from                      pointer to source buffer
2015 //    to                                pointer to dest. buffet
2016 //    pixels            number of pixels to copy
2017 //    fromsize          source pixel size
2018 //    tosize            dest. pixel size
2019
2020 static int tga_copy_data(char *to, char *from, int pixels, int fromsize, int tosize)
2021 {
2022         if ( (fromsize == 2) && (tosize == 3) ) {
2023                 ushort *src = (ushort *)from;
2024                 ubyte *dst  = (ubyte *)to;
2025
2026                 int i;
2027                 for (i=0; i<pixels; i++ )       {
2028                         ushort pixel = *src++;
2029
2030                         *dst++ = ubyte(((pixel & Gr_blue.mask)>>Gr_blue.shift)*Gr_blue.scale);
2031                         *dst++ = ubyte(((pixel & Gr_green.mask)>>Gr_green.shift)*Gr_green.scale);
2032                         *dst++ = ubyte(((pixel & Gr_red.mask)>>Gr_red.shift)*Gr_red.scale);
2033                 }
2034                 return tosize*pixels;
2035         } else if( (fromsize == 4) && (tosize == 3) ){
2036                 uint *src = (uint *)from;
2037                 ubyte *dst  = (ubyte *)to;
2038
2039                 int i;
2040                 for (i=0; i<pixels; i++ )       {
2041                         uint pixel = *src++;
2042
2043                         *dst++ = ubyte(((pixel & Gr_blue.mask)>>Gr_blue.shift)*Gr_blue.scale);
2044                         *dst++ = ubyte(((pixel & Gr_green.mask)>>Gr_green.shift)*Gr_green.scale);
2045                         *dst++ = ubyte(((pixel & Gr_red.mask)>>Gr_red.shift)*Gr_red.scale);
2046                 }
2047                 return tosize*pixels;
2048         }       else {
2049                 Int3();
2050                 return tosize*pixels;
2051         }
2052 }
2053
2054 //
2055 //      tga_pixels_equal -- Test if two pixels are identical
2056 //
2057 //              Returns:
2058 //                      0 if No Match
2059 //                      1 if Match
2060
2061 static int tga_pixels_equal(char *pix1, char *pix2, int pixbytes)
2062 {
2063         do      {
2064                 if ( *pix1++ != *pix2++ ) {
2065                         return 0;
2066                 }
2067         } while ( --pixbytes > 0 );
2068
2069         return 1;
2070 }
2071
2072
2073 //      tga_compress - Do the Run Length Compression
2074 //
2075 //      Usage:
2076 //                              out                     Buffer to write it out to
2077 //                              in                              Buffer to compress
2078 //                              bytecount       Number of bytes input
2079 //                              pixsize         Number of bytes in input pixel
2080 //                              outsize         Number of bytes in output buffer
2081
2082 static int tga_compress(char *out, char *in, int bytecount, int pixsize )
2083 {       
2084         #define outsize 3
2085
2086         int pixcount;           // number of pixels in the current packet
2087         char *inputpixel=NULL;  // current input pixel position
2088         char *matchpixel=NULL;  // pixel value to match for a run
2089         char *flagbyte=NULL;            // location of last flag byte to set
2090         int rlcount;            // current count in r.l. string 
2091         int rlthresh;           // minimum valid run length
2092         char *copyloc;          // location to begin copying at
2093
2094         // set the threshold -- the minimum valid run length
2095
2096         #if outsize == 1
2097                 rlthresh = 2;                                   // for 8bpp, require a 2 pixel span before rle'ing
2098         #else
2099                 rlthresh = 1;                   
2100         #endif
2101
2102         // set the first pixel up
2103
2104         flagbyte = out; // place to put next flag if run
2105         inputpixel = in;
2106         pixcount = 1;
2107         rlcount = 0;
2108         copyloc = (char *)0;
2109
2110         // loop till data processing complete
2111         do      {
2112
2113                 // if we have accumulated a 128-byte packet, process it
2114                 if ( pixcount == 129 )  {
2115                         *flagbyte = 127;
2116
2117                         // set the run flag if this is a run
2118
2119                         if ( rlcount >= rlthresh )      {
2120                                         *flagbyte |= 0x80;
2121                                         pixcount = 2;
2122                         }
2123
2124                         // copy the data into place
2125                         ++flagbyte;
2126                         flagbyte += tga_copy_data(flagbyte, copyloc, pixcount-1, pixsize, outsize);
2127                         pixcount = 1;
2128
2129                         // set up for next packet
2130                         continue;
2131                 }
2132
2133                 // if zeroth byte, handle as special case
2134                 if ( pixcount == 1 )    {
2135                         rlcount = 0;
2136                         copyloc = inputpixel;           /* point to 1st guy in packet */
2137                         matchpixel = inputpixel;        /* set pointer to pix to match */
2138                         pixcount = 2;
2139                         inputpixel += pixsize;
2140                         continue;
2141                 }
2142
2143                 // assembling a packet -- look at next pixel
2144
2145                 // current pixel == match pixel?
2146                 if ( tga_pixels_equal(inputpixel, matchpixel, outsize) )        {
2147
2148                         //      establishing a run of enough length to
2149                         //      save space by doing it
2150                         //              -- write the non-run length packet
2151                         //              -- start run-length packet
2152
2153                         if ( ++rlcount == rlthresh )    {
2154                                 
2155                                 //      close a non-run packet
2156                                 
2157                                 if ( pixcount > (rlcount+1) )   {
2158                                         // write out length and do not set run flag
2159
2160                                         *flagbyte++ = (char)(pixcount - 2 - rlthresh);
2161
2162                                         flagbyte += tga_copy_data(flagbyte, copyloc, (pixcount-1-rlcount), pixsize, outsize);
2163
2164                                         copyloc = inputpixel;
2165                                         pixcount = rlcount + 1;
2166                                 }
2167                         }
2168                 } else {
2169
2170                         // no match -- either break a run or continue without one
2171                         //      if a run exists break it:
2172                         //              write the bytes in the string (outsize+1)
2173                         //              start the next string
2174
2175                         if ( rlcount >= rlthresh )      {
2176
2177                                 *flagbyte++ = (char)(0x80 | rlcount);
2178                                 flagbyte += tga_copy_data(flagbyte, copyloc, 1, pixsize, outsize);
2179                                 pixcount = 1;
2180                                 continue;
2181                         } else {
2182
2183                                 //      not a match and currently not a run
2184                                 //              - save the current pixel
2185                                 //              - reset the run-length flag
2186                                 rlcount = 0;
2187                                 matchpixel = inputpixel;
2188                         }
2189                 }
2190                 pixcount++;
2191                 inputpixel += pixsize;
2192         } while ( inputpixel < (in + bytecount));
2193
2194         // quit this buffer without loosing any data
2195
2196         if ( --pixcount >= 1 )  {
2197                 *flagbyte = (char)(pixcount - 1);
2198                 if ( rlcount >= rlthresh )      {
2199                         *flagbyte |= 0x80;
2200                         pixcount = 1;
2201                 }
2202
2203                 // copy the data into place
2204                 ++flagbyte;
2205                 flagbyte += tga_copy_data(flagbyte, copyloc, pixcount, pixsize, outsize);
2206         }
2207         return(flagbyte-out);
2208 }
2209
2210 void gr_d3d_print_screen(char *filename)
2211 {
2212         HRESULT ddrval;
2213         DDSURFACEDESC ddsd;
2214         ubyte outrow[1024*3*4];
2215
2216         if ( gr_screen.max_w > 1024 )   {
2217                 mprintf(( "Screen too wide for print_screen\n" ));
2218                 return;
2219         }
2220
2221         memset( &ddsd, 0, sizeof( ddsd ) );
2222         ddsd.dwSize = sizeof( ddsd );
2223
2224         ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
2225         if ( ddrval != DD_OK )  {
2226                 mprintf(( "Error locking surface for print_screen, %s\n", d3d_error_string(ddrval) ));
2227         } 
2228
2229         ubyte *dptr = (ubyte *)ddsd.lpSurface;
2230
2231         char tmp[1024];
2232
2233         strcpy( tmp, NOX(".\\"));       // specify a path mean files goes in root
2234         strcat( tmp, filename );
2235         strcat( tmp, NOX(".tga"));
2236
2237         CFILE *f = cfopen(tmp, "wb");
2238
2239         // Write the TGA header
2240         cfwrite_ubyte( 0, f );  //      IDLength;
2241         cfwrite_ubyte( 0, f );  //      ColorMapType;
2242         cfwrite_ubyte( 10, f ); //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
2243         cfwrite_ushort( 0, f ); // CMapStart;
2244         cfwrite_ushort( 0, f ); //      CMapLength;
2245         cfwrite_ubyte( 0, f );  // CMapDepth;
2246         cfwrite_ushort( 0, f ); //      XOffset;
2247         cfwrite_ushort( 0, f ); //      YOffset;
2248         cfwrite_ushort( (ushort)gr_screen.max_w, f );   //      Width;
2249         cfwrite_ushort( (ushort)gr_screen.max_h, f );   //      Height;
2250         cfwrite_ubyte( 24, f ); //PixelDepth;
2251         cfwrite_ubyte( 0, f );  //ImageDesc;    
2252
2253         // Go through and read our pixels
2254         int i;
2255         for (i=0;i<gr_screen.max_h;i++) {
2256                 int len = tga_compress( (char *)outrow, (char *)&dptr[(gr_screen.max_h-i-1)*ddsd.lPitch], gr_screen.max_w * gr_screen.bytes_per_pixel, gr_screen.bytes_per_pixel );
2257
2258                 cfwrite(outrow, len, 1, f);
2259         }
2260
2261         cfclose(f);
2262
2263         // Unlock the back buffer
2264         lpBackBuffer->Unlock( NULL );
2265
2266 }
2267
2268
2269