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