]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grd3d.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / graphics / grd3d.cpp
1 /*
2  * $Logfile: /Freespace2/code/Graphics/GrD3D.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Code for our Direct3D renderer
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:45  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:09  root
14  * Initial import.
15  *
16  * 
17  * 42    10/13/99 3:49p Jefff
18  * fixed unnumbered XSTRs
19  * 
20  * 41    9/13/99 11:25p Dave
21  * Fixed problem with mode-switching and D3D movies.
22  * 
23  * 40    9/13/99 11:30a Dave
24  * Added checkboxes and functionality for disabling PXO banners as well as
25  * disabling d3d zbuffer biasing.
26  * 
27  * 39    9/10/99 11:53a Dave
28  * Shutdown graphics before sound to eliminate apparent lockups when
29  * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
30  * 
31  * 38    9/04/99 8:00p Dave
32  * Fixed up 1024 and 32 bit movie support.
33  * 
34  * 37    8/30/99 5:01p Dave
35  * Made d3d do less state changing in the nebula. Use new chat server for
36  * PXO.
37  * 
38  * 36    8/20/99 2:09p Dave
39  * PXO banner cycling.
40  * 
41  * 35    8/18/99 9:35a Dave
42  * Made d3d shutdown more stable.
43  * 
44  * 34    8/11/99 3:30p Dave
45  * Fixed window focus problems.
46  * 
47  * 33    8/04/99 5:36p Dave
48  * Make glide and D3D switch out properly.
49  * 
50  * 32    8/02/99 6:25p Dave
51  * Fixed d3d screen save/popup problem.
52  * 
53  * 31    7/30/99 7:01p Dave
54  * Dogfight escort gauge. Fixed up laser rendering in Glide.
55  * 
56  * 30    7/29/99 10:47p Dave
57  * Standardized D3D fogging using vertex fog. Shook out Savage 4 bugs.
58  * 
59  * 29    7/27/99 3:09p Dave
60  * Made g400 work. Whee.
61  * 
62  * 28    7/24/99 4:19p Dave
63  * Fixed dumb code with briefing bitmaps. Made d3d zbuffer work much
64  * better. Made model code use zbuffer more intelligently.
65  * 
66  * 27    7/16/99 1:49p Dave
67  * 8 bit aabitmaps. yay.
68  * 
69  * 26    7/14/99 9:42a Dave
70  * Put in clear_color debug function. Put in base for 3dnow stuff / P3
71  * stuff
72  * 
73  * 25    7/13/99 1:15p Dave
74  * 32 bit support. Whee!
75  * 
76  * 24    6/29/99 10:35a Dave
77  * Interface polygon bitmaps! Whee!
78  * 
79  * 23    6/03/99 6:37p Dave
80  * More TNT fun. Made perspective bitmaps more flexible.
81  * 
82  * 22    5/05/99 9:02p Dave
83  * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
84  * rotations, tweaked values, made bitmap selection more random). Fixed
85  * D3D beam weapon clipping problem. Added D3d frame dumping.
86  * 
87  * 21    2/03/99 11:44a Dave
88  * Fixed d3d transparent textures.
89  * 
90  * 20    1/24/99 11:36p Dave
91  * First full rev of beam weapons. Very customizable. Removed some bogus
92  * Int3()'s in low level net code.
93  * 
94  * 19    1/15/99 11:29a Neilk
95  * Fixed D3D screen/texture pixel formatting problem. 
96  * 
97  * 18    1/11/99 6:21p Neilk
98  * Fixed broken D3D card fog-capability check.
99  * 
100  * 17    1/06/99 2:24p Dave
101  * Stubs and release build fixes.
102  * 
103  * 16    12/18/98 1:13a Dave
104  * Rough 1024x768 support for Direct3D. Proper detection and usage through
105  * the launcher.
106  * 
107  * 15    12/09/98 7:34p Dave
108  * Cleanup up nebula effect. Tweaked many values.
109  * 
110  * 14    12/08/98 7:30p Dave
111  * Fixed broken compile.
112  * 
113  * 13    12/08/98 7:03p Dave
114  * Much improved D3D fogging. Also put in vertex fogging for the cheesiest
115  * of 3d cards.
116  * 
117  * 12    12/08/98 2:47p Johnson
118  * Made D3D fogging use eye-relative depth instead of z-depth. Works like
119  * Glide w-buffer now.
120  * 
121  * 11    12/08/98 9:36a Dave
122  * Almost done nebula effect for D3D. Looks 85% as good as Glide.
123  * 
124  * 10    12/07/98 5:51p Dave
125  * Finally got d3d fog working! Now we just need to tweak values.
126  * 
127  * 9     12/06/98 6:53p Dave
128  * 
129  * 8     12/06/98 3:08p Dave
130  * Fixed grx_tmapper to handle pixel fog flag. First run fog support for
131  * D3D.
132  * 
133  * 7     12/06/98 2:36p Dave
134  * Drastically improved nebula fogging.
135  * 
136  * 6     12/01/98 10:25a Johnson
137  * Fixed direct3d texture coord/font problems.
138  * 
139  * 5     11/30/98 1:07p Dave
140  * 16 bit conversion, first run.
141  * 
142  * 4     11/11/98 5:37p Dave
143  * Checkin for multiplayer testing.
144  * 
145  * 3     10/09/98 2:57p Dave
146  * Starting splitting up OS stuff.
147  * 
148  * 2     10/07/98 10:52a Dave
149  * Initial checkin.
150  * 
151  * 1     10/07/98 10:49a Dave
152  * 
153  * 110   6/13/98 6:01p Hoffoss
154  * Externalized all new (or forgot to be added) strings to all the code.
155  * 
156  * 109   6/13/98 3:18p Hoffoss
157  * NOX()ed out a bunch of strings that shouldn't be translated.
158  * 
159  * 108   5/24/98 9:41p John
160  * changed allender's previous fix to actually not draw the lines on
161  * NDEBUG.
162  * 
163  * 107   5/24/98 9:16p Allender
164  * put in previously non-NDEBUG code to draw bogus cursor when Gr_cursor
165  * wasn't defined.  Caused d3d to crash before playing movies
166  * 
167  * 106   5/22/98 10:29p John
168  * fixed some mode switching and line offset detection bugs.
169  * 
170  * 105   5/22/98 1:11p John
171  * Added code to actually detect which offset a line needs
172  * 
173  *
174  * $NoKeywords: $
175  */
176
177 #include <math.h>
178
179 #include "grd3dinternal.h"
180
181 #include "osapi.h"
182 #include "2d.h"
183 #include "bmpman.h"
184 #include "key.h"
185 #include "floating.h"
186 #include "palman.h"
187 #include "osregistry.h"
188 #include "grd3d.h"
189 #include "line.h"
190 #include "font.h"
191 #include "grinternal.h"
192 #include "mouse.h"
193 #include "alphacolors.h"
194 #include "systemvars.h"
195 #include "cfile.h"
196 #include "cmdline.h"
197
198
199 LPDIRECTDRAW                    lpDD1 = NULL;
200 LPDIRECTDRAW2                   lpDD = NULL;
201 LPDIRECT3D2                             lpD3D = NULL;
202 LPDIRECT3DDEVICE2               lpD3DDevice = NULL; 
203 // LPDIRECT3DDEVICE             lpD3DDeviceEB = NULL; 
204 LPDIRECTDRAWSURFACE     lpBackBuffer = NULL;
205 LPDIRECTDRAWSURFACE     lpFrontBuffer = NULL;
206 LPDIRECTDRAWSURFACE     lpZBuffer = NULL;
207
208 LPDIRECT3DVIEWPORT2     lpViewport;
209
210 DDPIXELFORMAT                   AlphaTextureFormat;
211 int Largest_alpha = 0;
212 DDPIXELFORMAT                   NonAlphaTextureFormat;
213 DDPIXELFORMAT                   NonAlphaTextureFormat_1555;
214 DDPIXELFORMAT                   NonAlphaTextureFormat_565;
215 int Largest_rgb = 0;
216 DDPIXELFORMAT                   ScreenFormat;
217
218 static RECT D3D_cursor_clip_rect;
219
220 D3DDEVICEDESC                   D3DHWDevDesc, D3DHELDevDesc;
221 LPD3DDEVICEDESC         lpDevDesc = NULL;
222
223 DDCAPS DD_driver_caps;
224 DDCAPS DD_hel_caps;
225
226 int D3D_texture_divider = 1;
227
228 int D3D_window = 0;
229
230 char Device_init_error[512] = "";
231
232 // -1 == no fog, bad bad bad
233 // 0 == vertex fog
234 // 1 == table fog
235 int D3D_fog_mode = -1;
236
237 static int In_frame = 0;
238
239 int D3D_inited = 0;
240
241 int DrawPrim = 0;
242
243 int D3d_rendition_uvs = 0;      
244
245 int D3D_32bit = 0;
246
247 int D3D_zbias = 1;
248 DCF(zbias, "")
249 {
250         D3D_zbias = !D3D_zbias;
251 }
252
253 #define MAX_D2D_DEVICES 8
254 #define MAX_D3D_DEVICES 16
255
256 typedef struct d3d_device {
257         GUID            guid_2d;
258         LPGUID  pguid_2d;
259
260         GUID            guid_3d;
261         LPGUID  pguid_3d;
262
263         char            name[1024];
264 } d3d_device;
265
266 d3d_device D2D_devices[MAX_D2D_DEVICES];
267 d3d_device D3D_devices[MAX_D3D_DEVICES];
268
269 int Num_d2d_devices = 0;
270 int Num_d3d_devices = 0;
271
272 d3d_device *D3D_device;
273
274 void mprint_guid( LPGUID lpGuid )
275 {
276         /*
277         if ( !lpGuid )          {
278                 mprintf(( "None\n" ));
279         } else {                                
280                 int i;
281                 for (i=0; i<sizeof(GUID); i++ ) {
282                         mprintf(( "%x ", *ptr++ ));
283                 }               
284                 mprintf(( "\n", *ptr++ ));
285         }
286         */
287 }
288
289 #define PUTD3DINSTRUCTION(op, sz, cnt, ptr) do {        \
290     ((LPD3DINSTRUCTION) ptr)->bOpcode = op; \
291     ((LPD3DINSTRUCTION) ptr)->bSize = sz; \
292     ((LPD3DINSTRUCTION) ptr)->wCount = cnt; \
293     ptr = (void *)(((LPD3DINSTRUCTION) ptr) + 1); } while (0)
294
295 #define VERTEX_DATA(loc, cnt, ptr) do { \
296     if ((ptr) != (loc)) memcpy((ptr), (loc), sizeof(D3DVERTEX) * (cnt)); \
297     ptr = (void *)(((LPD3DVERTEX) (ptr)) + (cnt)); } while (0)
298
299 // OP_MATRIX_MULTIPLY size: 4 (sizeof D3DINSTRUCTION)
300 #define OP_MATRIX_MULTIPLY(cnt, ptr) \
301     PUTD3DINSTRUCTION(D3DOP_MATRIXMULTIPLY, sizeof(D3DMATRIXMULTIPLY), cnt, ptr)
302
303 // MATRIX_MULTIPLY_DATA size: 12 (sizeof MATRIXMULTIPLY)
304 #define MATRIX_MULTIPLY_DATA(src1, src2, dest, ptr) do {        \
305     ((LPD3DMATRIXMULTIPLY) ptr)->hSrcMatrix1 = src1; \
306     ((LPD3DMATRIXMULTIPLY) ptr)->hSrcMatrix2 = src2; \
307     ((LPD3DMATRIXMULTIPLY) ptr)->hDestMatrix = dest; \
308     ptr = (void *)(((LPD3DMATRIXMULTIPLY) ptr) + 1); } while (0)
309
310 // OP_STATE_LIGHT size: 4 (sizeof D3DINSTRUCTION)
311 #define OP_STATE_LIGHT(cnt, ptr) \
312     PUTD3DINSTRUCTION(D3DOP_STATELIGHT, sizeof(D3DSTATE), cnt, ptr)
313
314 // OP_STATE_TRANSFORM size: 4 (sizeof D3DINSTRUCTION)
315 #define OP_STATE_TRANSFORM(cnt, ptr) \
316     PUTD3DINSTRUCTION(D3DOP_STATETRANSFORM, sizeof(D3DSTATE), cnt, ptr)
317
318 // OP_STATE_RENDER size: 4 (sizeof D3DINSTRUCTION)
319 #define OP_STATE_RENDER(cnt, ptr) \
320     PUTD3DINSTRUCTION(D3DOP_STATERENDER, sizeof(D3DSTATE), cnt, ptr)
321
322 // STATE_DATA size: 8 (sizeof D3DSTATE)
323 #define STATE_DATA(type, arg, ptr) do { \
324     ((LPD3DSTATE) ptr)->drstRenderStateType = (D3DRENDERSTATETYPE)type; \
325     ((LPD3DSTATE) ptr)->dwArg[0] = arg; \
326     ptr = (void *)(((LPD3DSTATE) ptr) + 1); } while (0)
327
328 // OP_PROCESS_VERTICES size: 4 (sizeof D3DINSTRUCTION)
329 #define OP_PROCESS_VERTICES(cnt, ptr) \
330     PUTD3DINSTRUCTION(D3DOP_PROCESSVERTICES, sizeof(D3DPROCESSVERTICES), cnt, ptr)
331
332 // PROCESSVERTICES_DATA size: 16 (sizeof D3DPROCESSVERTICES)
333 #define PROCESSVERTICES_DATA(flgs, strt, cnt, ptr) do { \
334     ((LPD3DPROCESSVERTICES) ptr)->dwFlags = flgs; \
335     ((LPD3DPROCESSVERTICES) ptr)->wStart = strt; \
336     ((LPD3DPROCESSVERTICES) ptr)->wDest = strt; \
337     ((LPD3DPROCESSVERTICES) ptr)->dwCount = cnt; \
338     ((LPD3DPROCESSVERTICES) ptr)->dwReserved = 0; \
339     ptr = (void *)(((LPD3DPROCESSVERTICES) ptr) + 1); } while (0)
340
341 // OP_TRIANGLE_LIST size: 4 (sizeof D3DINSTRUCTION)
342 #define OP_TRIANGLE_LIST(cnt, ptr) \
343     PUTD3DINSTRUCTION(D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), cnt, ptr)
344
345 #define TRIANGLE_LIST_DATA(loc, count, ptr) do { \
346     if ((ptr) != (loc)) memcpy((ptr), (loc), sizeof(D3DTRIANGLE) * (count)); \
347     ptr = (void *)(((LPD3DTRIANGLE) (ptr)) + (count)); } while (0)
348
349 // OP_LINE_LIST size: 4 (sizeof D3DINSTRUCTION)
350 #define OP_LINE_LIST(cnt, ptr) \
351     PUTD3DINSTRUCTION(D3DOP_LINE, sizeof(D3DLINE), cnt, ptr)
352
353 #define LINE_LIST_DATA(loc, count, ptr) do { \
354     if ((ptr) != (loc)) memcpy((ptr), (loc), sizeof(D3DLINE) * (count)); \
355     ptr = (void *)(((LPD3DLINE) (ptr)) + (count)); } while (0)
356
357 // OP_POINT_LIST size: 8 (sizeof D3DINSTRUCTION + sizeof D3DPOINT)
358 #define OP_POINT_LIST(first, cnt, ptr) do { \
359     PUTD3DINSTRUCTION(D3DOP_POINT, sizeof(D3DPOINT), 1, ptr); \
360     ((LPD3DPOINT)(ptr))->wCount = cnt; \
361     ((LPD3DPOINT)(ptr))->wFirst = first; \
362     ptr = (void*)(((LPD3DPOINT)(ptr)) + 1); } while(0)
363
364 // OP_SPAN_LIST size: 8 (sizeof D3DINSTRUCTION + sizeof D3DSPAN)
365 #define OP_SPAN_LIST(first, cnt, ptr) \
366     PUTD3DINSTRUCTION(D3DOP_SPAN, sizeof(D3DSPAN), 1, ptr); \
367     ((LPD3DSPAN)(ptr))->wCount = cnt; \
368     ((LPD3DSPAN)(ptr))->wFirst = first; \
369     ptr = (void*)(((LPD3DSPAN)(ptr)) + 1); } while(0)
370
371 // OP_BRANCH_FORWARD size: 18 (sizeof D3DINSTRUCTION + sizeof D3DBRANCH)
372 #define OP_BRANCH_FORWARD(tmask, tvalue, tnegate, toffset, ptr) \
373     PUTD3DINSTRUCTION(D3DOP_BRANCHFORWARD, sizeof(D3DBRANCH), 1, ptr); \
374     ((LPD3DBRANCH) ptr)->dwMask = tmask; \
375     ((LPD3DBRANCH) ptr)->dwValue = tvalue; \
376     ((LPD3DBRANCH) ptr)->bNegate = tnegate; \
377     ((LPD3DBRANCH) ptr)->dwOffset = toffset; \
378     ptr = (void *)(((LPD3DBRANCH) (ptr)) + 1); } while (0)
379
380 // OP_SET_STATUS size: 20 (sizeof D3DINSTRUCTION + sizeof D3DSTATUS)
381 #define OP_SET_STATUS(flags, status, _x1, _y1, _x2, _y2, ptr) \
382     PUTD3DINSTRUCTION(D3DOP_SETSTATUS, sizeof(D3DSTATUS), 1, ptr); \
383     ((LPD3DSTATUS)(ptr))->dwFlags = flags; \
384     ((LPD3DSTATUS)(ptr))->dwStatus = status; \
385     ((LPD3DSTATUS)(ptr))->drExtent.x1 = _x1; \
386     ((LPD3DSTATUS)(ptr))->drExtent.y1 = _y1; \
387     ((LPD3DSTATUS)(ptr))->drExtent.x2 = _x2; \
388     ((LPD3DSTATUS)(ptr))->drExtent.y2 = _y2; \
389     ptr = (void *)(((LPD3DSTATUS) (ptr)) + 1); } while (0)
390
391 // OP_NOP size: 4
392 #define OP_NOP(ptr) \
393     PUTD3DINSTRUCTION(D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), 0, ptr)
394
395 #define OP_EXIT(ptr) \
396     PUTD3DINSTRUCTION(D3DOP_EXIT, 0, 0, ptr)
397
398 #define QWORD_ALIGNED(ptr) \
399     (!(0x00000007L & (ULONG)(ptr)))
400
401 #define D3D_MAX_VERTS 512
402 #define D3D_EXBUFFER_SIZE 65536
403 static int D3D_num_verts;
404 //static D3DTLVERTEX D3D_vertices[D3D_MAX_VERTS];
405 static D3DTLVERTEX *D3D_vertices;
406 //static ubyte D3D_exbuffer[D3D_EXBUFFER_SIZE];
407 static void *D3D_ex_ptr, *D3D_ex_end;
408 LPDIRECT3DEXECUTEBUFFER lpExBuf = NULL;
409
410 LPVOID lpBufStart, lpPointer, lpInsStart;
411 int Exb_size;
412
413
414 void gr_d3d_exb_init()
415 {
416         /*
417         HRESULT ddrval;
418         D3DEXECUTEBUFFERDESC debDesc;
419
420         if ( DrawPrim ) {
421                 return;
422         }
423         
424         Exb_size = D3D_EXBUFFER_SIZE + sizeof(D3DTLVERTEX)*D3D_MAX_VERTS;
425
426    // create a D3DEXECUTEBUFFERDESC
427         memset( &debDesc, 0, sizeof( debDesc ) );
428         debDesc.dwSize       = sizeof( debDesc );
429         debDesc.dwFlags      = D3DDEB_BUFSIZE;
430         debDesc.dwBufferSize = Exb_size;
431
432         // create the buffer
433         ddrval = lpD3DDeviceEB->CreateExecuteBuffer( &debDesc, &lpExBuf, NULL );
434         if ( ddrval != DD_OK )  {
435                 mprintf(( "GR_D3D_INIT: CreateExecuteBuffer failed. size=%d, '%s'\n", Exb_size, d3d_error_string(ddrval) ));
436                 goto D3DError;
437         }
438
439         memset( &debDesc, 0, sizeof( debDesc ) );
440         debDesc.dwSize       = sizeof( debDesc );
441         ddrval = lpExBuf->Lock( &debDesc );
442         if ( ddrval != DD_OK )  {
443                 mprintf(( "Failed to lock the execute buffer!\n" ));
444                 goto D3DError;
445         }
446
447         lpPointer = lpBufStart = lpInsStart = debDesc.lpData;
448
449         lpPointer = (void *)((uint)lpPointer+sizeof(D3DTLVERTEX)*D3D_MAX_VERTS);
450         lpInsStart = lpPointer;
451
452         OP_PROCESS_VERTICES( 1, lpPointer );
453         PROCESSVERTICES_DATA( D3DPROCESSVERTICES_COPY, 0,  1, lpPointer );
454
455         D3D_num_verts = 0;
456         D3D_ex_ptr = lpPointer;
457         D3D_ex_end = (void *)((uint)lpBufStart + Exb_size - 1024);
458         D3D_vertices = (D3DTLVERTEX *)lpBufStart;
459         return;
460
461
462 D3DError:
463         // Reset everything
464         if ( lpExBuf )  {
465                 lpExBuf->Release();
466                 lpExBuf = NULL;
467         }
468         gr_d3d_cleanup();
469         exit(1);
470         */
471 }
472
473 HRESULT set_wbuffer_planes(LPDIRECT3DDEVICE2 lpDev, float dvWNear, float dvWFar)
474 {
475   HRESULT res;
476   D3DMATRIX matWorld;
477   D3DMATRIX matView;
478   D3DMATRIX matProj;
479
480   memset(&matWorld, 0, sizeof(matWorld));
481   memset(&matView, 0, sizeof(matWorld));
482   memset(&matProj, 0, sizeof(matWorld));
483   matWorld._11 = 1; matWorld._22 = 1; matWorld._33 = 1; matWorld._44 = 1;
484   matView._11 = 1; matView._22 = 1; matView._33 = 1; matView._44 = 1;
485   matProj._11 = 1; matProj._22 = 1; matProj._33 = 1; matProj._44 = 1;
486   
487   res = lpDev->SetTransform( D3DTRANSFORMSTATE_WORLD,      &matWorld );
488   if (res) return res;
489   res = lpDev->SetTransform( D3DTRANSFORMSTATE_VIEW,       &matView );
490   if (res) return res;
491   
492   matProj._43 = 0;
493   matProj._34 = 1;
494   matProj._44 = dvWNear; // not used
495   matProj._33 = dvWNear / (dvWFar - dvWNear) + 1;  
496
497   res = lpDev->SetTransform( D3DTRANSFORMSTATE_PROJECTION, &matProj );
498   return res;
499 }
500
501 DCF(wplanes, "")
502 {
503         dc_get_arg(ARG_FLOAT);
504         float n = Dc_arg_float;
505         dc_get_arg(ARG_FLOAT);
506         float f = Dc_arg_float;
507         set_wbuffer_planes(lpD3DDevice, n, f);
508 }
509
510 void gr_d3d_exb_flush(int end_of_frame)
511 {
512         /*
513         HRESULT ddrval;
514         D3DEXECUTEBUFFERDESC debDesc;
515         D3DEXECUTEDATA d3dExData;
516
517         if ( DrawPrim ) {
518                 return;
519         }
520
521         if (!lpExBuf) return;
522
523         OP_EXIT( D3D_ex_ptr );
524
525         lpPointer = lpInsStart;
526         OP_PROCESS_VERTICES( 1, lpPointer );
527         PROCESSVERTICES_DATA( D3DPROCESSVERTICES_COPY, 0,  D3D_num_verts, lpPointer );
528
529         ddrval = lpExBuf->Unlock();
530         if (ddrval != DD_OK )   {
531                 mprintf(( "Failed to unlock the execute buffer!\n" ));
532                 goto D3DError;
533         }
534
535         memset(&d3dExData, 0, sizeof(D3DEXECUTEDATA));
536         d3dExData.dwSize = sizeof(D3DEXECUTEDATA);
537         d3dExData.dwVertexCount = D3D_num_verts;
538         d3dExData.dwInstructionOffset = (ULONG)((char*)lpInsStart - (char*)lpBufStart);
539         d3dExData.dwInstructionLength = (ULONG)((char*)D3D_ex_ptr - (char*)lpInsStart);
540
541 //      if (end_of_frame==0)    {
542 //              mprintf(( "Flushing execute buffer in frame, %d verts, %d data size!\n", D3D_num_verts, d3dExData.dwInstructionLength ));
543 //      } else if (end_of_frame==2)     { 
544 //              mprintf(( "Flushing execute buffer in frame, because of VRAM flush!\n" ));
545 //      }
546
547         ddrval = lpExBuf->SetExecuteData(&d3dExData);
548         if (ddrval != DD_OK )   {
549                 mprintf(( "Failed to SetExecuteData!\n" ));
550                 goto D3DError;
551         }
552
553         ddrval = lpD3DDeviceEB->Execute( lpExBuf, lpViewport, D3DEXECUTE_UNCLIPPED );
554         if (ddrval != DD_OK )   {
555                 mprintf(( "Failed to Execute! nverts=%d\n", D3D_num_verts));
556                 mprintf(( "(%s)\n", d3d_error_string(ddrval) ));
557                 goto D3DError;
558         }
559
560
561         memset( &debDesc, 0, sizeof( debDesc ) );
562         debDesc.dwSize       = sizeof( debDesc );
563         ddrval = lpExBuf->Lock( &debDesc );
564         if ( ddrval != DD_OK )  {
565                 mprintf(( "Failed to lock the execute buffer!\n" ));
566                 goto D3DError;
567         }
568
569         lpPointer = lpBufStart = lpInsStart = debDesc.lpData;
570
571         lpPointer = (void *)((uint)lpPointer+sizeof(D3DTLVERTEX)*D3D_MAX_VERTS);
572         lpInsStart = lpPointer;
573
574         OP_PROCESS_VERTICES( 1, lpPointer );
575         PROCESSVERTICES_DATA( D3DPROCESSVERTICES_COPY, 0,  1, lpPointer );
576
577         D3D_num_verts = 0;
578         D3D_ex_ptr = lpPointer;
579         D3D_ex_end = (void *)((uint)lpBufStart + Exb_size - 1024);
580         D3D_vertices = (D3DTLVERTEX *)lpBufStart;
581         return;
582
583
584 D3DError:
585         // Reset everything
586
587         if ( lpExBuf )  {
588                 lpExBuf->Release();
589                 lpExBuf = NULL;
590         }
591 //      gr_d3d_cleanup();
592 //      exit(1);
593 */
594 }
595
596
597
598 HRESULT d3d_SetRenderState( D3DRENDERSTATETYPE dwRenderStateType,  DWORD dwRenderState )
599 {
600         if ( DrawPrim ) {
601                 return lpD3DDevice->SetRenderState(dwRenderStateType, dwRenderState );
602         } else {
603                 if ( (uint)D3D_ex_ptr > (uint)D3D_ex_end )  {
604                         gr_d3d_exb_flush(0);
605                 }
606                 OP_STATE_RENDER(1, D3D_ex_ptr);
607                 STATE_DATA(dwRenderStateType, dwRenderState, D3D_ex_ptr);
608                 return DD_OK;
609         }
610
611 }
612
613 HRESULT d3d_DrawPrimitive( D3DPRIMITIVETYPE dptPrimitiveType, D3DVERTEXTYPE dvtVertexType, LPVOID lpvVertices, DWORD dwVertexCount, DWORD dwFlags )
614 {
615         if ( DrawPrim ) {
616                 return lpD3DDevice->DrawPrimitive(dptPrimitiveType, dvtVertexType, lpvVertices, dwVertexCount, dwFlags );
617         } else {        
618
619                 switch( dptPrimitiveType )      {
620
621                 case D3DPT_TRIANGLEFAN: 
622                         if ( dvtVertexType == D3DVT_TLVERTEX )  {
623
624                                 D3DTLVERTEX *Verts = (D3DTLVERTEX *)lpvVertices;
625                                 
626                                 if ( D3D_num_verts + dwVertexCount > D3D_MAX_VERTS ) gr_d3d_exb_flush(0);
627                                 if ( (uint)D3D_ex_ptr > (uint)D3D_ex_end )  gr_d3d_exb_flush(0);
628
629                                 D3DTLVERTEX *src_v = &D3D_vertices[D3D_num_verts];
630
631                                 int i;
632                                 for (i=0; i<(int)dwVertexCount; i++ )   {
633                                         *src_v++ = Verts[i];
634                                 }
635
636                                 // triangle data must be QWORD aligned, so we need to make sure
637                                 // that the OP_TRIANGLE_LIST is unaligned!  Note that you MUST have
638                                 // the braces {} around the OP_NOP since the macro in D3DMACS.H will
639                                 // fail if you remove them.
640
641                                 if ( QWORD_ALIGNED( D3D_ex_ptr ) ) {
642                                         OP_NOP( D3D_ex_ptr );
643                                 }
644
645                                 OP_TRIANGLE_LIST( unsigned short(dwVertexCount-2), D3D_ex_ptr );
646
647                                 LPD3DTRIANGLE tri = ( LPD3DTRIANGLE )D3D_ex_ptr;
648
649                                 for (i=0; i<(int)dwVertexCount-2; i++ ) {
650                                         tri->v1 = unsigned short(D3D_num_verts+0);
651                                         tri->v2 = unsigned short(D3D_num_verts+i+1);
652                                         tri->v3 = unsigned short(D3D_num_verts+i+2);
653                                         tri->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE;
654                                         tri++;
655                                 
656                                 }
657                                 D3D_ex_ptr = ( LPVOID )tri;
658                                 D3D_num_verts += (int)dwVertexCount;
659                         }
660                         break;
661
662                 case D3DPT_LINELIST:
663                         if ( dvtVertexType == D3DVT_TLVERTEX )  {
664
665                                 D3DTLVERTEX *Verts = (D3DTLVERTEX *)lpvVertices;
666                                 
667                                 if ( D3D_num_verts + dwVertexCount > D3D_MAX_VERTS ) gr_d3d_exb_flush(0);
668                                 if ( (uint)D3D_ex_ptr > (uint)D3D_ex_end )  gr_d3d_exb_flush(0);
669
670                                 D3DTLVERTEX *src_v = &D3D_vertices[D3D_num_verts];
671
672                                 int i;
673                                 for (i=0; i<(int)dwVertexCount; i++ )   {
674                                         *src_v++ = Verts[i];
675                                 }
676
677                                 // triangle data must be QWORD aligned, so we need to make sure
678                                 // that the OP_TRIANGLE_LIST is unaligned!  Note that you MUST have
679                                 // the braces {} around the OP_NOP since the macro in D3DMACS.H will
680                                 // fail if you remove them.
681
682                                 if ( QWORD_ALIGNED( D3D_ex_ptr ) ) {
683                                         OP_NOP( D3D_ex_ptr );
684                                 }
685
686                                 ushort nlines = ushort(dwVertexCount/2);
687
688                                 OP_LINE_LIST( nlines, D3D_ex_ptr );
689         
690                                 for (i=0; i<(int)nlines; i++ )  {
691                                         LPD3DLINE line = (LPD3DLINE )D3D_ex_ptr;
692                                         line->v1 = unsigned short(D3D_num_verts);
693                                         line->v2 = unsigned short(D3D_num_verts+1);
694                                         D3D_ex_ptr = (void *)(((LPD3DLINE)D3D_ex_ptr) + 1);
695                                 }       
696
697                                 D3D_num_verts += (int)dwVertexCount;
698                         }
699                         break;
700                 }
701                 return DD_OK;
702         }
703 }
704
705 volatile int D3D_running = 0;
706 volatile int D3D_activate = 0;
707 volatile int D3D_deactivate = 0;
708
709 void gr_d3d_activate(int active)
710 {
711         if ( !D3D_running )     {
712                 return;
713         }
714         mprintf(( "Direct3D activate: %d\n", active ));
715
716         HWND hwnd = (HWND)os_get_window();
717         
718         if ( active  )  {
719                 D3D_activate++;
720
721                 if ( hwnd )     {
722                         ClipCursor(&D3D_cursor_clip_rect);
723                         ShowWindow(hwnd,SW_RESTORE);
724                 }
725         } else {
726                 D3D_deactivate++;
727
728                 if ( hwnd )     {
729                         ClipCursor(NULL);
730                         ShowWindow(hwnd,SW_MINIMIZE);
731                 }
732         }
733 }
734
735
736 void d3d_start_frame()
737 {
738         HRESULT ddrval;
739
740         if (!D3D_inited) return;
741
742         if ( In_frame < 0 || In_frame > 1 )     {
743                 mprintf(( "Start frame error! (%d)\n", In_frame ));
744                 return;
745         }
746         if ( In_frame == 1 ) return;
747
748 //      gr_d3d_clear_surface(lpBackBuffer, 0.0f, 0.0f, 0.0f);
749
750         In_frame++;
751
752         ddrval = lpD3DDevice->BeginScene();
753         if (ddrval != D3D_OK )  {
754                 //mprintf(( "Failed to begin scene!\n%s\n", d3d_error_string(ddrval) ));
755                 return;
756         }
757
758         
759 }
760
761
762 void d3d_stop_frame()
763 {
764         HRESULT ddrval;
765
766         if (!D3D_inited) return;
767
768         if ( In_frame < 0 || In_frame > 1 )     {
769                 mprintf(( "Stop frame error! (%d)\n", In_frame ));
770                 return;
771         }
772
773         if ( In_frame == 0 ) return;
774
775         gr_d3d_exb_flush(1);
776
777         In_frame--;
778         
779         ddrval = lpD3DDevice->EndScene();
780         if (ddrval != D3D_OK )  {
781                 //mprintf(( "Failed to end scene!\n%s\n", d3d_error_string(ddrval) ));
782                 return;
783         }
784
785 }
786
787 void d3d_flush()        
788 {
789         d3d_stop_frame();
790         d3d_start_frame();
791 }
792
793 static void d3d_dump_format(DDPIXELFORMAT *pf)
794 {
795         unsigned long m;
796         int r, g, b, a;
797         for (r = 0, m = pf->dwRBitMask; !(m & 1); r++, m >>= 1);
798         for (r = 0; m & 1; r++, m >>= 1);
799         for (g = 0, m = pf->dwGBitMask; !(m & 1); g++, m >>= 1);
800         for (g = 0; m & 1; g++, m >>= 1); 
801         for (b = 0, m = pf->dwBBitMask; !(m & 1); b++, m >>= 1);
802         for (b = 0; m & 1; b++, m >>= 1);
803         if ( pf->dwFlags & DDPF_ALPHAPIXELS ) {
804                 for (a = 0, m = pf->dwRGBAlphaBitMask; !(m & 1); a++, m >>= 1);
805                 for (a = 0; m & 1; a++, m >>= 1);
806                 mprintf(( "ARGB, %d:%d:%d:%d\n", a, r, g, b ));
807         } else {
808                 a = 0;
809                 mprintf(( "RGB, %d:%d:%d\n", r, g, b ));
810         }
811 }
812
813 int D3D_found_1555_tex = 0;
814 int D3D_found_565_tex = 0;
815 static HRESULT WINAPI EnumTextureFormatsCallback(LPDDSURFACEDESC lpDDSD, LPVOID lpContext)
816 {
817         if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXEDTO8) {
818                 mprintf(( "Palettized to an 8 bpp palette\n" ));
819         }
820
821         if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) {
822                 mprintf(( "Palettized 8 bpp\n" ));
823 //              TextureFormat = *lpDDSD;
824 //              mprintf(( " ^-- And I'm using this one!\n" ));
825         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) {
826                 mprintf(( "Palettized 4 bpp\n" ));
827                 return DDENUMRET_OK;
828         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) {
829                 mprintf(( "Palettized 2 bpp\n" ));
830                 return DDENUMRET_OK;
831         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1) {
832                 mprintf(( "Palettized 1 bpp\n" ));
833         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_ALPHA ) {
834                 mprintf(( "Alpha something or other\n" ));
835                 return DDENUMRET_OK;
836         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_YUV ) {
837                 mprintf(( "YUV?\n" ));
838                 return DDENUMRET_OK;
839         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_ZBUFFER ) {
840                 mprintf(( "ZBUFFER?\n" ));
841                 return DDENUMRET_OK;
842         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_COMPRESSED ) {
843                 mprintf(( "Compressed?\n" ));
844                 return DDENUMRET_OK;
845         } else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
846                 mprintf(( "FourCC?\n" ));
847                 return DDENUMRET_OK;
848         } else {
849                 unsigned long m;
850                 int r, g, b, a;
851                 for (r = 0, m = lpDDSD->ddpfPixelFormat.dwRBitMask; !(m & 1) && (r < 32); r++, m >>= 1);
852                 for (r = 0; m & 1; r++, m >>= 1);
853                 for (g = 0, m = lpDDSD->ddpfPixelFormat.dwGBitMask; !(m & 1) && (g < 32); g++, m >>= 1);
854                 for (g = 0; m & 1; g++, m >>= 1); 
855                 for (b = 0, m = lpDDSD->ddpfPixelFormat.dwBBitMask; !(m & 1) && (b < 32); b++, m >>= 1);
856                 for (b = 0; m & 1; b++, m >>= 1);
857                 if ( lpDDSD->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS ) {
858                         for (a = 0, m = lpDDSD->ddpfPixelFormat.dwRGBAlphaBitMask; !(m & 1) && (a < 32); a++, m >>= 1);
859                         for (a = 0; m & 1; a++, m >>= 1);
860                         mprintf(( "ARGB, %d:%d:%d:%d\n", a, r, g, b ));
861                 } else {
862                         a = 0;
863                         mprintf(( "RGB, %d:%d:%d\n", r, g, b ));
864                 }
865
866                 // if we found a nice 1555 texture format
867                 if( (r == 5) && (g == 5) && (b == 5) && (a == 1)){
868                         Largest_rgb = 15;
869                         NonAlphaTextureFormat_1555 = lpDDSD->ddpfPixelFormat;
870                         NonAlphaTextureFormat = lpDDSD->ddpfPixelFormat;
871                         D3D_found_1555_tex = 1;
872                 }
873                 // 565 textures
874                 else if ( (r == 5) && (g == 6) && (b == 5) ){
875                         NonAlphaTextureFormat_565 = lpDDSD->ddpfPixelFormat;
876                         D3D_found_565_tex = 1;
877                 } 
878                 // otherwise keep looking
879                 else if(!D3D_found_1555_tex) {
880                         //if ( (r==4) && (g==4) && (b==4) && (a==4) && (lpDDSD->ddpfPixelFormat.dwRGBBitCount==16) )    {
881                         if ( (r>0) && (g>0) && (b>0) && (lpDDSD->ddpfPixelFormat.dwRGBBitCount==16) )   {
882                                 if ( r+g+b > Largest_rgb )      {
883                                         Largest_rgb = r+g+b;
884                                         NonAlphaTextureFormat = lpDDSD->ddpfPixelFormat;
885                                 }
886                         }               
887                 }
888
889                 // HACK!!! Some 3dfx cards (Allender, Whiteside, Johnson) choose
890                 // ARGB=8:3:3:2 as a texture format but when you go to create a surface
891                 // in system RAM with this format, it fails, saying invalid surface format...
892                 // So I'll just force 4:4:4:4 which seems to work on all cards I've seen.
893                 if ( (a>0) && (a<8) && (lpDDSD->ddpfPixelFormat.dwRGBBitCount<=16) )    {
894                         if ( a > Largest_alpha )        {
895                                 Largest_alpha = a;
896                                 AlphaTextureFormat = lpDDSD->ddpfPixelFormat;
897                         }
898                 }
899
900         }
901     return DDENUMRET_OK;
902 }
903
904 HRESULT WINAPI gr_d3d_enum( LPGUID lpGUID,
905                                                         LPSTR lpDeviceDescription,
906                                                         LPSTR lpDeviceName,
907                                                         LPD3DDEVICEDESC lpHWDesc,
908                                                         LPD3DDEVICEDESC lpHELDesc, 
909                                                         LPVOID lpContext )
910 {
911         int use_it = 0;
912         
913 //      mprintf(( "Found 3d device %s: %s\n",  lpDeviceName, lpDeviceDescription ));
914
915         if ( lpHWDesc && lpHWDesc->dwFlags != 0 )       {
916                 use_it = 1;
917         } //else if ( lpHELDesc )       {
918
919         
920         if ( use_it )   {
921                 d3d_device *d2d = (d3d_device *)lpContext;
922                 d3d_device *d3d = (d3d_device *)&D3D_devices[Num_d3d_devices++];
923
924                 if ( lpGUID )   {
925                         memmove( &d3d->guid_3d, lpGUID, sizeof(GUID) );
926                         d3d->pguid_3d = &d3d->guid_3d;
927                 } else {
928                         memset( &d3d->guid_3d, 0, sizeof(GUID) );
929                         d3d->pguid_3d = NULL;
930                 }
931
932                 memmove( &d3d->guid_2d, &d2d->guid_2d, sizeof(GUID) );
933                 if ( d2d->pguid_2d )    {
934                         d3d->pguid_2d = &d3d->guid_2d;
935                 } else {
936                         d3d->pguid_2d = NULL;
937                 }
938
939                 //strcpy( d3d->name, lpDeviceName );
940                 //strcat( d3d->name, " - " );
941                 strcpy( d3d->name, NOX("Direct 3D - ") );
942                 strcat( d3d->name, d2d->name );
943                 //strcat( d3d->name, lpDeviceDescription );
944         }
945
946         return D3DENUMRET_OK;
947 }
948  
949 BOOL WINAPI gr_d2d_enum( LPGUID lpGUID,
950                                                         LPSTR lpDeviceDescription,
951                                                         LPSTR lpDeviceName,
952                                                         LPVOID lpContext )
953 {
954         d3d_device *d2d = (d3d_device *)&D2D_devices[Num_d2d_devices++];
955
956 //      mprintf(( "Found 2d device %s: %s\n",  lpDeviceName, lpDeviceDescription ));
957         
958         if ( lpGUID )   {
959                 memmove( &d2d->guid_2d, lpGUID, sizeof(GUID) );
960                 d2d->pguid_2d = &d2d->guid_2d;
961         } else {
962                 memset( &d2d->guid_2d, 0, sizeof(GUID) );
963                 d2d->pguid_2d = NULL;
964         }
965
966         strcpy( d2d->name, lpDeviceDescription );
967 //      strcat( d2d->name, lpDeviceName );
968
969         return D3DENUMRET_OK;
970 }
971
972 d3d_device *d3d_poll_devices()
973 {
974         int i;
975         HRESULT ddrval;
976
977         Num_d2d_devices = 0;
978         Num_d3d_devices = 0;
979                 
980         ddrval = DirectDrawEnumerate( gr_d2d_enum, NULL );
981         if ( ddrval != DD_OK ) {
982                 mprintf(( "GR_D3D_INIT: DirectDrawEnumerate failed.\n" ));
983                 goto D3DError;
984         }
985
986         for ( i=0; i<Num_d2d_devices; i++)      {
987                 d3d_device *d2d = (d3d_device *)&D2D_devices[i];
988
989                 ddrval = DirectDrawCreate( d2d->pguid_2d, &lpDD1, NULL );
990                 if ( ddrval != DD_OK ) {
991                         mprintf(( "GR_D3D_INIT: DirectDrawCreate failed.\n" ));
992                         goto D3DError;
993                 }
994
995                 ddrval = lpDD1->QueryInterface( IID_IDirect3D2, ( LPVOID *) &lpD3D );
996                 if ( ddrval != DD_OK ) {
997                         mprintf(( "GR_D3D_INIT: QueryInterface failed.\n" ));
998                         goto D3DError;
999                 }
1000
1001                 ddrval = lpD3D->EnumDevices(gr_d3d_enum, d2d );
1002                 if ( ddrval != DD_OK )  {
1003                         mprintf(( "WIN_DD32: D3D enum devices failed. (0x%x)\n", ddrval ));
1004                 }
1005
1006                 lpD3D->Release();
1007                 lpD3D = NULL;
1008
1009                 lpDD1->Release();
1010                 lpDD1 = NULL;
1011         }
1012
1013         for ( i=0; i<Num_d3d_devices; i++)      {
1014                 mprintf(( "D3D Device %d: %s\n", i, D3D_devices[i].name ));
1015                 //mprint_guid(D3D_devices[i].pguid_2d);
1016         }
1017
1018         if ( Num_d3d_devices <= 0 )     {
1019                 mprintf(( "No D3D device found!\n" ));
1020                 return NULL;
1021         } 
1022         
1023
1024         if ( Num_d3d_devices > 0 )      {
1025                 //mprintf(( "More than one D3D device found!\n" ));
1026
1027                 char *name = os_config_read_string( NULL, "VideoCard", NULL );
1028
1029                 if ( name && (strlen(name)>0) ) {
1030                         for ( i=0; i<Num_d3d_devices; i++)      {
1031                                 if ( strstr( name, D3D_devices[i].name ) )      {
1032                                         mprintf(( "Using one that matched Direct3D registry value '%s'.\n", name ));
1033                                         return &D3D_devices[i];
1034                                 }
1035                         }
1036                         mprintf(( "WARNING!!!! Couldn't find one that matched Direct3D registry value '%s'.\n", name ));
1037                 } 
1038
1039                 mprintf(( "But no Direct3D registry key or no match, so use the last one.\n" ));
1040
1041                 // Use the last device.
1042                 return &D3D_devices[Num_d3d_devices-1];
1043         }
1044
1045         return NULL;
1046
1047 D3DError:
1048         mprintf(( "Direct3D Polling failed.\n" ));
1049         return NULL;
1050 }
1051
1052
1053 LPDIRECTDRAW gr_d3d_get_dd()
1054 {
1055         return lpDD1;
1056 }
1057
1058
1059 LPDIRECTDRAWSURFACE gr_d3d_get_dd_surface()
1060 {
1061         return lpBackBuffer;
1062 }
1063
1064 void gr_d3d_clip_cursor(int active)
1065 {
1066         if ( active  )  {
1067                 ClipCursor(&D3D_cursor_clip_rect);
1068         } else {
1069                 ClipCursor(NULL);
1070         }
1071 }
1072
1073 // front buffer, backbuffer, d3d device, viewport
1074 int gr_d3d_create_rendering_objects(int clear)
1075 {
1076         HRESULT ddrval;
1077
1078         {
1079                 DDSURFACEDESC ddsd;
1080                 DDSCAPS ddscaps;
1081
1082                 memset( &ddsd, 0, sizeof( ddsd ));
1083
1084                 ddsd.dwSize = sizeof( ddsd );
1085
1086                 // windowed
1087                 if(D3D_window){         
1088                         ddsd.dwFlags = DDSD_CAPS;
1089                         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;                        
1090                 }
1091                 // fullscreen
1092                 else {
1093                         ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
1094                         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX;
1095                         ddsd.dwBackBufferCount = 1;
1096                 }
1097
1098                 ddrval = lpDD->CreateSurface( &ddsd, &lpFrontBuffer, NULL );
1099                 if ( ddrval != DD_OK )  {
1100                         // mprintf(( "GR_D3D_INIT: CreateSurface (Front) failed.\n" ));
1101                         strcpy(Device_init_error, "CreateSurface (Front) failed.");
1102                         return 0;
1103                 }
1104                 
1105                 // create a clipper and a backbuffer in windowed mode
1106                 if(D3D_window){
1107                         // create a clipper for windowed mode   
1108                         LPDIRECTDRAWCLIPPER pcClipper;
1109                         HRESULT hr = lpDD->CreateClipper(0, &pcClipper, NULL);
1110                         if(hr != DD_OK){
1111                                 return 0;
1112                         }
1113
1114                         // Associate the clipper with our window.
1115                         pcClipper->SetHWnd(0, (HWND)os_get_window());
1116                         lpFrontBuffer->SetClipper(pcClipper);
1117                         pcClipper->Release();   
1118
1119                         // backbuffer
1120                         ddsd.dwFlags        = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
1121                         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;                                
1122                         ddsd.dwWidth = gr_screen.max_w;
1123                         ddsd.dwHeight = gr_screen.max_h;                
1124                         hr = lpDD->CreateSurface(&ddsd, &lpBackBuffer, NULL);
1125                         if(hr != DD_OK){
1126                                 strcpy(Device_init_error, "Windowed backbuffer create failed.");
1127                                 return 0;
1128                         }
1129                 } 
1130                 // backbuffer is already created for us in fullscreen mode
1131                 else {
1132                         ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
1133                         ddrval = lpFrontBuffer->GetAttachedSurface( &ddscaps, &lpBackBuffer );
1134                         if ( ddrval != DD_OK )  {
1135                                 // mprintf(( "GR_D3D_INIT: GetAttachedSurface (Back) failed.\n" ));
1136                                 strcpy(Device_init_error, "GetAttachedSurface (Back) failed.");
1137                                 return 0;
1138                         }
1139                 }
1140         }
1141
1142         // Create a z-buffer and attach it to the backbuffer
1143         {
1144                 DDSURFACEDESC ddsd;
1145
1146                 memset( &ddsd, 0, sizeof( ddsd ) );
1147                 ddsd.dwSize = sizeof(ddsd);
1148                 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
1149                 ddsd.dwWidth = gr_screen.max_w;
1150                 ddsd.dwHeight = gr_screen.max_h;
1151                 ddsd.dwZBufferBitDepth = 16;
1152
1153                 ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
1154                 if (lpDD->CreateSurface(&ddsd, &lpZBuffer, NULL) != DD_OK)      {
1155                         // mprintf(( "GR_D3D_INIT: Create Zbuffer failed.\n" ));
1156                         strcpy(Device_init_error, "Create Zbuffer failed.");
1157                         return 0;
1158                 }
1159
1160                 if (lpBackBuffer->AddAttachedSurface(lpZBuffer) != DD_OK)       {
1161                         // mprintf(( "GR_D3D_INIT: Attach Zbuffer failed.\n" ));
1162                         strcpy(Device_init_error, "Attach Zbuffer failed.");
1163                         return 0;
1164                 }
1165         }       
1166
1167         // blit all the buffers clear
1168         if(clear){
1169                 // Clear the surface
1170                 DDBLTFX ddBltFx;                
1171                 ddBltFx.dwSize = sizeof(DDBLTFX);
1172                 ddBltFx.dwFillColor = 0;        
1173                 lpFrontBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddBltFx);                
1174                 lpBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL, &ddBltFx);         
1175         }
1176
1177         // Create the D3D device        
1178         lpD3DDevice = NULL;
1179    ddrval = lpD3D->CreateDevice( D3D_device->guid_3d, lpBackBuffer, &lpD3DDevice );
1180         if ( ddrval != DD_OK )  {
1181                 // mprintf(( "GR_D3D_INIT: Create D3D Device2 failed. %s\n", d3d_error_string(ddrval) ));
1182                 sprintf(Device_init_error, "Create D3D Device2 failed. %s\n", d3d_error_string(ddrval));
1183                 return 0;
1184         }       
1185
1186         // Create and add viewport
1187         ddrval = lpD3D->CreateViewport( &lpViewport, NULL );
1188         if ( ddrval != DD_OK )  {
1189                 // mprintf(( "GR_D3D_INIT: CreateViewport failed.\n" ));
1190                 strcpy(Device_init_error, "CreateViewport failed.");
1191                 return 0;
1192         }
1193
1194         ddrval = lpD3DDevice->AddViewport( lpViewport );
1195         if ( ddrval != DD_OK )  {
1196                 // mprintf(( "GR_D3D_INIT: AddViewport failed.\n" ));
1197                 strcpy(Device_init_error, "CreateViewport failed.");
1198                 return 0;
1199         }
1200
1201
1202         // Setup the viewport for a reasonable viewing area
1203         D3DVIEWPORT viewdata;
1204         DWORD       largest_side;
1205
1206         memset( &viewdata, 0, sizeof( viewdata ) );
1207
1208         // Compensate for aspect ratio  
1209         if ( gr_screen.max_w > gr_screen.max_h ){
1210                 largest_side = gr_screen.max_w;
1211         } else {
1212                 largest_side = gr_screen.max_h;
1213         }
1214
1215         // this sets up W data so the fogging can work
1216         extern float z_mult;
1217         set_wbuffer_planes(lpD3DDevice, 0.0f, z_mult);
1218
1219         viewdata.dwSize = sizeof( viewdata );
1220         viewdata.dwX = viewdata.dwY = 0;
1221         viewdata.dwWidth = gr_screen.max_w;
1222         viewdata.dwHeight = gr_screen.max_h;
1223         viewdata.dvScaleX = largest_side / 2.0F;
1224         viewdata.dvScaleY = largest_side / 2.0F;
1225         viewdata.dvMaxX = ( float ) ( viewdata.dwWidth / ( 2.0F * viewdata.dvScaleX ) );
1226         viewdata.dvMaxY = ( float ) ( viewdata.dwHeight / ( 2.0F * viewdata.dvScaleY ) );
1227         viewdata.dvMinZ = 0.0f;
1228         viewdata.dvMaxZ = 1.0f; // choose something appropriate here!
1229
1230         ddrval = lpViewport->SetViewport( &viewdata );
1231         if ( ddrval != DD_OK )  {
1232                 // mprintf(( "GR_D3D_INIT: SetViewport failed.\n" ));
1233                 strcpy(Device_init_error, "SetViewport failed.");
1234                 return 0;
1235         }
1236
1237         ddrval = lpD3DDevice->SetCurrentViewport(lpViewport );
1238         if ( ddrval != DD_OK )  {
1239                 // mprintf(( "GR_D3D_INIT: SetCurrentViewport failed.\n" ));
1240                 strcpy(Device_init_error, "SetCurrentViewport failed.");
1241                 return 0;
1242         }       
1243
1244         return 1;
1245 }
1246
1247 void gr_d3d_release_rendering_objects()
1248 {
1249         if ( lpViewport )       {
1250                 lpViewport->Release();
1251                 lpViewport = NULL;
1252         }       
1253         
1254         if ( lpD3DDevice )      {
1255                 lpD3DDevice->Release();
1256                 lpD3DDevice = NULL;
1257         }
1258         
1259         if (lpZBuffer)  {
1260                 lpZBuffer->Release();
1261                 lpZBuffer = NULL;
1262         }
1263
1264         if (lpBackBuffer)       {
1265                 lpBackBuffer->Release();
1266                 lpBackBuffer = NULL;
1267         }
1268
1269         if (lpFrontBuffer)      {
1270                 lpFrontBuffer->Release();
1271                 lpFrontBuffer = NULL;
1272         }
1273 }
1274
1275 void gr_d3d_set_initial_render_state()
1276 {
1277         d3d_SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE );
1278         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEAR );
1279         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR );
1280         d3d_SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD );
1281         d3d_SetRenderState(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE );
1282         d3d_SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE );                      
1283 }
1284
1285 void gr_d3d_init_device(int screen_width, int screen_height)
1286 {
1287         HRESULT ddrval;
1288         HWND hwnd;      
1289
1290         if ( os_config_read_uint( NULL, NOX("D3DUseExecuteBuffers"), 0 ))       {
1291                 DrawPrim = 0;
1292         } else {
1293                 DrawPrim = 1;
1294         }
1295
1296         os_suspend();
1297         d3d_device *dd = d3d_poll_devices();
1298         os_resume();
1299         if (!dd )       {
1300                 // Error( LOCATION, "No Direct3D devices found!\n" );
1301                 strcpy(Device_init_error, "No Direct3D devices found!");
1302                 goto D3DError;
1303         }
1304
1305         // Let things catch up....
1306 //      Sleep(1000);
1307         
1308         hwnd = (HWND)os_get_window();
1309         if ( !hwnd )    {
1310                 // mprintf(( "gr_d3d_init_device: No window handle.\n" ));
1311                 strcpy(Device_init_error, "Could not get application window handle");
1312                 return;
1313         }
1314
1315         // windowed
1316         if(D3D_window){
1317                 SetWindowPos(hwnd, HWND_TOP, 0, 0, gr_screen.max_w, gr_screen.max_h, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME);
1318                 SetForegroundWindow(hwnd);
1319                 SetActiveWindow(hwnd);  
1320                 
1321                 D3D_cursor_clip_rect.left = 0;
1322                 D3D_cursor_clip_rect.top = 0;
1323                 D3D_cursor_clip_rect.right = gr_screen.max_w-1;
1324                 D3D_cursor_clip_rect.bottom = gr_screen.max_h-1;
1325         } else {
1326                 // Prepare the window to go full screen
1327         #ifndef NDEBUG
1328                 mprintf(( "Window in debugging mode... mouse clicking may cause problems!\n" ));
1329                 SetWindowLong( hwnd, GWL_EXSTYLE, 0 );
1330                 SetWindowLong( hwnd, GWL_STYLE, WS_POPUP );
1331                 ShowWindow(hwnd, SW_SHOWNORMAL );
1332                 RECT work_rect;
1333                 SystemParametersInfo( SPI_GETWORKAREA, 0, &work_rect, 0 );
1334                 SetWindowPos( hwnd, HWND_TOPMOST, work_rect.left, work_rect.top, gr_screen.max_w, gr_screen.max_h, 0 ); 
1335                 SetActiveWindow(hwnd);
1336                 SetForegroundWindow(hwnd);
1337                 D3D_cursor_clip_rect.left = work_rect.left;
1338                 D3D_cursor_clip_rect.top = work_rect.top;
1339                 D3D_cursor_clip_rect.right = work_rect.left + gr_screen.max_w - 1;
1340                 D3D_cursor_clip_rect.bottom = work_rect.top + gr_screen.max_h - 1;
1341         #else
1342                 SetWindowLong( hwnd, GWL_EXSTYLE, 0 );
1343                 SetWindowLong( hwnd, GWL_STYLE, WS_POPUP );
1344                 ShowWindow(hwnd, SW_SHOWNORMAL );
1345                 // SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ), 0 );       
1346                 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, gr_screen.max_w, gr_screen.max_h, 0 );  
1347                 SetActiveWindow(hwnd);
1348                 SetForegroundWindow(hwnd);
1349                 D3D_cursor_clip_rect.left = 0;
1350                 D3D_cursor_clip_rect.top = 0;
1351                 D3D_cursor_clip_rect.right = gr_screen.max_w-1;
1352                 D3D_cursor_clip_rect.bottom = gr_screen.max_h-1;
1353         #endif
1354         }
1355
1356         // active d3d device
1357         D3D_device = dd;        
1358
1359         os_suspend();
1360         ddrval = DirectDrawCreate( dd->pguid_2d, &lpDD1, NULL );
1361         os_resume();
1362         if ( ddrval != DD_OK ) {
1363                 // mprintf(( "GR_D3D_INIT: DirectDrawCreate failed.\n" ));
1364                 strcpy(Device_init_error, "DirectDrawCreate failed");
1365                 goto D3DError;
1366         }
1367
1368         ddrval = lpDD1->QueryInterface(IID_IDirectDraw2,  (LPVOID *)&lpDD); 
1369         if(ddrval != DD_OK)     {
1370                 // mprintf(( "GR_D3D_INIT: DirectDrawCreate2 failed.\n" ));
1371                 strcpy(Device_init_error, "DirectDrawCreate2 failed");
1372                 goto D3DError;
1373         }       
1374  
1375         if(D3D_window){
1376                 ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL );
1377         } else {
1378                 ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES );
1379         }
1380         if ( ddrval != DD_OK )  {
1381                 // mprintf(( "GR_D3D_INIT: SetCooperativeLevel EXCLUSIVE failed.\n" ));
1382                 strcpy(Device_init_error, "SetCooperativeLevel EXCLUSIVE failed.");
1383                 goto D3DError;
1384         }
1385                 
1386         // Go to full screen!
1387         if(!D3D_window){
1388                 os_suspend();
1389                 ddrval = lpDD->SetDisplayMode( screen_width, screen_height, gr_screen.bits_per_pixel, 0, 0 );
1390                 os_resume();
1391                 if ( ddrval != DD_OK )  {
1392                         // mprintf(( "GR_D3D_INIT: SetDisplayMode failed.\n" ));
1393                         strcpy(Device_init_error, "SetDisplayMode failed.");
1394                         goto D3DError;
1395                 }
1396         }
1397
1398         gr_d3d_clip_cursor(1);
1399
1400         ddrval = lpDD->QueryInterface( IID_IDirect3D2, ( LPVOID *) &lpD3D );
1401         if ( ddrval != DD_OK ) {
1402                 // mprintf(( "GR_D3D_INIT: QueryInterface failed.\n" ));
1403                 strcpy(Device_init_error, "QueryInterface failed.");
1404                 goto D3DError;
1405         }
1406
1407         // create all surfaces here
1408         if(!gr_d3d_create_rendering_objects(1)){
1409                 goto D3DError;
1410         }
1411         
1412         {
1413                 extern void dd_get_shift_masks( DDSURFACEDESC *ddsd );
1414                 DDSURFACEDESC ddsd;
1415                 memset( &ddsd, 0, sizeof( ddsd ) );
1416                 ddsd.dwSize = sizeof(ddsd);
1417                 lpBackBuffer->GetSurfaceDesc(&ddsd);   
1418                 dd_get_shift_masks( &ddsd );
1419                 ScreenFormat = ddsd.ddpfPixelFormat;
1420         }
1421
1422         // if we're in windowed mode, fill in bits per pixel and bytes per pixel here
1423         if(D3D_window){
1424                 gr_screen.bits_per_pixel = ScreenFormat.dwRGBBitCount;
1425                 gr_screen.bytes_per_pixel = gr_screen.bits_per_pixel / 8;
1426         }
1427
1428         // Init values so we can choose the largest of each format
1429         Largest_alpha = 0;
1430         Largest_rgb = 0;
1431         D3D_found_1555_tex = 0;
1432         D3D_found_565_tex = 0;
1433         ddrval = lpD3DDevice->EnumTextureFormats(EnumTextureFormatsCallback, NULL );
1434         if ( ddrval != DD_OK )  {
1435                 // mprintf(( "GR_D3D_INIT: EnumTextureFormats failed.\n" ));
1436                 strcpy(Device_init_error, "EnumTextureFormats failed.");
1437                 goto D3DError;
1438         }
1439
1440         // if we found our ideal texture, set the global pixel format
1441         if(D3D_found_1555_tex){
1442                 Bm_pixel_format = BM_PIXEL_FORMAT_ARGB_D3D;
1443         }
1444
1445         if ( Largest_alpha == 0 )       {
1446                 gr_d3d_cleanup();
1447                 MessageBox( NULL, XSTR("Alpha channel textures",620), XSTR("Missing Features",621), MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
1448                 exit(1);
1449         }
1450         if ( Largest_rgb == 0 ) {
1451                 gr_d3d_cleanup();
1452                 MessageBox( NULL, XSTR("16-bpp RGB textures",622), XSTR("Missing Features",621), MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
1453                 exit(1);
1454         }
1455
1456         // setup texture pixel formats
1457         {
1458                 DDPIXELFORMAT *surface_desc;
1459                 int s;  
1460                 // RGB decoder
1461                 unsigned long m;                
1462                                         
1463                 // Determine the red, green and blue masks' shift and scale.
1464                 surface_desc = &NonAlphaTextureFormat;  
1465                 for (s = 0, m = surface_desc->dwRBitMask; !(m & 1); s++, m >>= 1);
1466                 Gr_t_red.mask = surface_desc->dwRBitMask;
1467                 Gr_t_red.shift = s;
1468                 Gr_t_red.scale = 255 / (surface_desc->dwRBitMask >> s);
1469                 for (s = 0, m = surface_desc->dwGBitMask; !(m & 1); s++, m >>= 1);
1470                 Gr_t_green.mask = surface_desc->dwRBitMask;
1471                 Gr_t_green.shift = s;
1472                 Gr_t_green.scale = 255 / (surface_desc->dwGBitMask >> s);
1473                 for (s = 0, m = surface_desc->dwBBitMask; !(m & 1); s++, m >>= 1);
1474                 Gr_t_blue.mask = surface_desc->dwRBitMask;
1475                 Gr_t_blue.shift = s;
1476                 Gr_t_blue.scale = 255 / (surface_desc->dwBBitMask >> s);
1477                 Gr_t_alpha.mask = surface_desc->dwRGBAlphaBitMask;
1478                 if ( surface_desc->dwFlags & DDPF_ALPHAPIXELS ) {                       
1479                         for (s = 0, m = surface_desc->dwRGBAlphaBitMask; !(m & 1); s++, m >>= 1);
1480                         Gr_t_alpha.shift = s;
1481                         Gr_t_alpha.scale = 255 / (surface_desc->dwRGBAlphaBitMask >> s);                        
1482                 } else {
1483                         Gr_t_alpha.shift = 0;
1484                         Gr_t_alpha.scale = 256;
1485                 }
1486
1487                 // Determine the red, green and blue masks' shift and scale.
1488                 surface_desc = &AlphaTextureFormat;     
1489                 for (s = 0, m = surface_desc->dwRBitMask; !(m & 1); s++, m >>= 1);
1490                 Gr_ta_red.mask = surface_desc->dwRBitMask;
1491                 Gr_ta_red.shift = s;
1492                 Gr_ta_red.scale = 255 / (surface_desc->dwRBitMask >> s);
1493                 for (s = 0, m = surface_desc->dwGBitMask; !(m & 1); s++, m >>= 1);
1494                 Gr_ta_green.mask = surface_desc->dwRBitMask;
1495                 Gr_ta_green.shift = s;
1496                 Gr_ta_green.scale = 255 / (surface_desc->dwGBitMask >> s);
1497                 for (s = 0, m = surface_desc->dwBBitMask; !(m & 1); s++, m >>= 1);
1498                 Gr_ta_blue.mask = surface_desc->dwRBitMask;
1499                 Gr_ta_blue.shift = s;
1500                 Gr_ta_blue.scale = 255 / (surface_desc->dwBBitMask >> s);
1501                 Gr_ta_alpha.mask = surface_desc->dwRGBAlphaBitMask;
1502                 if ( surface_desc->dwFlags & DDPF_ALPHAPIXELS ) {
1503                         for (s = 0, m = surface_desc->dwRGBAlphaBitMask; !(m & 1); s++, m >>= 1);
1504                         Gr_ta_alpha.shift = s;
1505                         Gr_ta_alpha.scale = 255 / (surface_desc->dwRGBAlphaBitMask >> s);
1506                 } else {
1507                         Gr_ta_alpha.shift = 0;
1508                         Gr_ta_alpha.scale = 256;
1509                 }               
1510         }
1511
1512         mprintf(( "Alpha texture format = " ));
1513         d3d_dump_format(&AlphaTextureFormat);
1514
1515         mprintf(( "Non-alpha texture format = " ));
1516         d3d_dump_format(&NonAlphaTextureFormat);
1517
1518         mprintf(( "Screen format = " ));
1519         d3d_dump_format(&ScreenFormat);
1520
1521 //      key_getch();
1522
1523         // gr_d3d_exb_init();
1524
1525         memset( &D3DHWDevDesc, 0, sizeof( D3DHWDevDesc ) );
1526         D3DHWDevDesc.dwSize = sizeof(D3DHELDevDesc);
1527
1528         memset( &D3DHELDevDesc, 0, sizeof( D3DHELDevDesc ) );
1529         D3DHELDevDesc.dwSize = sizeof(D3DHELDevDesc);
1530
1531         ddrval = lpD3DDevice->GetCaps( &D3DHWDevDesc, &D3DHELDevDesc );
1532         if ( ddrval != DD_OK )  {
1533                 mprintf(( "GR_D3D_INIT: 3DDevice->GetCaps failed.\n" ));
1534                 goto D3DError;
1535         }
1536         lpDevDesc = &D3DHWDevDesc;
1537
1538         lpDD->GetCaps(&DD_driver_caps,&DD_hel_caps);
1539
1540         {
1541                 int not_good = 0;
1542
1543                 char missing_features[128*1024];
1544
1545                 strcpy( missing_features, XSTR("Your video card is missing the following features required by FreeSpace:\r\n\r\n",623) );
1546
1547                 // fog
1548                 if ( !(lpDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGVERTEX) && !(lpDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGTABLE)){
1549                         strcat( missing_features, XSTR("Vertex fog or Table fog\r\n", 1499) );
1550                         not_good++;                     
1551                 }               
1552                                 
1553                 // Texture blending values
1554                 if ( !(lpDevDesc->dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_MODULATE ))    {
1555                         strcat( missing_features, XSTR("Texture blending mode = Modulate\r\n", 624) );
1556                         not_good++;
1557                 }
1558
1559                 // Source blending values
1560 //              if ( !(lpDevDesc->dpcTriCaps.dwSrcBlendCaps & D3DPBLENDCAPS_ONE) )      {
1561 //                      strcat( missing_features, "Source blending mode = ONE\r\n" );
1562 //                      not_good++;
1563 //              }
1564
1565                 if ( !(lpDevDesc->dpcTriCaps.dwSrcBlendCaps & (D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_BOTHSRCALPHA)) )    {
1566                         strcat( missing_features, XSTR("Source blending mode = SRCALPHA or BOTHSRCALPHA\r\n", 625) );
1567                         not_good++;
1568                 }
1569
1570 //              if ( !(lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ZERO ) )   {
1571 //                      strcat( missing_features, "Destination blending mode = ZERO\r\n" );
1572 //                      not_good++;
1573 //              }
1574
1575 //              if ( !(lpDevDesc->dpcTriCaps.dwDestBlendCaps & D3DPBLENDCAPS_ONE ) )    {
1576 //                      strcat( missing_features, "Destination blending mode = ONE\r\n" );
1577 //                      not_good++;
1578 //              }
1579
1580                 // Dest blending values
1581                 if ( !(lpDevDesc->dpcTriCaps.dwDestBlendCaps & (D3DPBLENDCAPS_INVSRCALPHA|D3DPBLENDCAPS_BOTHINVSRCALPHA)) )     {
1582                         strcat( missing_features, XSTR("Destination blending mode = INVSRCALPHA or BOTHINVSRCALPHA\r\n",626) );
1583                         not_good++;
1584                 }
1585         
1586                 // If card is Mystique 220, turn off modulaalpha since it doesn't work...
1587                 if ( Largest_alpha < 4 )        {
1588                         lpDevDesc->dpcTriCaps.dwTextureBlendCaps &= (~D3DPTBLENDCAPS_MODULATEALPHA);
1589                 }
1590
1591                 if ( not_good ) {
1592                         gr_d3d_cleanup();
1593                         MessageBox( NULL, missing_features, XSTR("Missing Features",621), MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
1594                         exit(1);
1595                 }       
1596         }
1597
1598         // fog info - for now we'll prefer table fog over vertex fog
1599         D3D_fog_mode = 1;       
1600         // if the user wants to force w-fog, maybe do it        
1601         if(os_config_read_uint(NULL, "ForceWFOG", 0) && (lpDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGTABLE)){
1602                 D3D_fog_mode = 2;
1603         }       
1604         // if the card does not have vertex fog, but has table fog, let it go
1605         if(!(lpDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGVERTEX) && (lpDevDesc->dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGTABLE)){
1606                 D3D_fog_mode = 2;
1607         }
1608
1609         {
1610                 DDSCAPS ddsCaps;
1611                 DWORD dwFree, dwTotal;
1612
1613                 memset(&ddsCaps,0,sizeof(ddsCaps) );
1614                 ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1615                 HRESULT ddrval = lpDD->GetAvailableVidMem(&ddsCaps, &dwTotal, &dwFree);
1616                 if ( ddrval != DD_OK )  {
1617                         mprintf(( "GR_D3D_INIT: GetAvailableVidMem failed.\n" ));
1618                         dwFree = 0;
1619                 }
1620
1621                 if ( dwFree < (1024*1024) )     {
1622                         gr_d3d_cleanup();
1623                         MessageBox( NULL, XSTR("At least 1 MB of available video memory required.",627), XSTR("Missing Features",621), MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
1624                         exit(1);
1625                 }
1626         }
1627
1628         // setup proper render state
1629         gr_d3d_set_initial_render_state();      
1630
1631         mprintf(( "Direct3D Initialized OK!\n" ));
1632
1633         D3D_inited = 1; 
1634         return;
1635
1636 D3DError:
1637         mprintf(( "Direct3D Initialization failed.\n" ));
1638
1639         gr_d3d_cleanup();
1640 }
1641
1642
1643 int Gr_d3d_mouse_saved = 0;
1644 int Gr_d3d_mouse_saved_x1 = 0;
1645 int Gr_d3d_mouse_saved_y1 = 0;
1646 int Gr_d3d_mouse_saved_x2 = 0;
1647 int Gr_d3d_mouse_saved_y2 = 0;
1648 int Gr_d3d_mouse_saved_w = 0;
1649 int Gr_d3d_mouse_saved_h = 0;
1650 #define MAX_SAVE_SIZE (32*32)
1651 ushort Gr_d3d_mouse_saved_data[MAX_SAVE_SIZE];
1652
1653 // Clamps X between R1 and R2
1654 #define CLAMP(x,r1,r2) do { if ( (x) < (r1) ) (x) = (r1); else if ((x) > (r2)) (x) = (r2); } while(0)
1655
1656 void gr_d3d_save_mouse_area(int x, int y, int w, int h )
1657 {
1658         // bail in 32 bit
1659         if(D3D_32bit){
1660                 return;
1661         }
1662
1663         Gr_d3d_mouse_saved_x1 = x; 
1664         Gr_d3d_mouse_saved_y1 = y;
1665         Gr_d3d_mouse_saved_x2 = x+w-1;
1666         Gr_d3d_mouse_saved_y2 = y+h-1;
1667          
1668         CLAMP(Gr_d3d_mouse_saved_x1, gr_screen.clip_left, gr_screen.clip_right );
1669         CLAMP(Gr_d3d_mouse_saved_x2, gr_screen.clip_left, gr_screen.clip_right );
1670         CLAMP(Gr_d3d_mouse_saved_y1, gr_screen.clip_top, gr_screen.clip_bottom );
1671         CLAMP(Gr_d3d_mouse_saved_y2, gr_screen.clip_top, gr_screen.clip_bottom );
1672
1673         Gr_d3d_mouse_saved_w = Gr_d3d_mouse_saved_x2 - Gr_d3d_mouse_saved_x1 + 1;
1674         Gr_d3d_mouse_saved_h = Gr_d3d_mouse_saved_y2 - Gr_d3d_mouse_saved_y1 + 1;
1675
1676         if ( Gr_d3d_mouse_saved_w < 1 ) return;
1677         if ( Gr_d3d_mouse_saved_h < 1 ) return;
1678
1679         // Make sure we're not saving too much!
1680         Assert( (Gr_d3d_mouse_saved_w*Gr_d3d_mouse_saved_h) <= MAX_SAVE_SIZE );
1681
1682         HRESULT ddrval;
1683         DDSURFACEDESC ddsd;
1684
1685         memset( &ddsd, 0, sizeof( ddsd ) );
1686         ddsd.dwSize = sizeof( ddsd );
1687
1688         ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
1689         if ( ddrval == DD_OK )  {
1690
1691                 ushort *rptr;
1692                 int short_per_row=ddsd.lPitch/2;
1693
1694                 rptr = (ushort *)ddsd.lpSurface;
1695
1696                 ushort *sptr, *dptr;
1697
1698                 dptr = Gr_d3d_mouse_saved_data;
1699
1700                 for (int i=0; i<Gr_d3d_mouse_saved_h; i++ )     {
1701                         sptr = &rptr[(Gr_d3d_mouse_saved_y1+i)*short_per_row+Gr_d3d_mouse_saved_x1];
1702
1703                         for(int j=0; j<Gr_d3d_mouse_saved_w; j++ )      {
1704                                 *dptr++ = *sptr++;
1705                         }
1706                 }
1707
1708                 // Unlock it
1709                 lpBackBuffer->Unlock( NULL );
1710
1711                 Gr_d3d_mouse_saved = 1;
1712
1713         } else {
1714                 mprintf(( "Couldn't get read-only lock to backbuffer for d3d mouse save\n" ));
1715         }
1716
1717 }
1718
1719
1720 void gr_d3d_flip()
1721 {
1722         int mx, my;
1723         HRESULT ddrval; 
1724         
1725         
1726         gr_reset_clip();        
1727
1728         mouse_eval_deltas();
1729
1730         Gr_d3d_mouse_saved = 0;         // assume not saved             
1731
1732         if(!Gr_bitmap_poly){
1733                 d3d_stop_frame();
1734         }
1735
1736         if ( mouse_is_visible() )       {                               
1737                 gr_reset_clip();
1738                 mouse_get_pos( &mx, &my );
1739                 
1740                 gr_d3d_save_mouse_area(mx,my,32,32);    
1741                 if ( Gr_cursor == -1 )  {
1742                         #ifndef NDEBUG
1743                                 gr_set_color(255,255,255);
1744                                 gr_line( mx, my, mx+7, my + 7 );
1745                                 gr_line( mx, my, mx+5, my );
1746                                 gr_line( mx, my, mx, my+5 );
1747                         #endif
1748                 } else {        
1749                         gr_set_bitmap(Gr_cursor);                               
1750                         gr_bitmap( mx, my );
1751                 }               
1752         }       
1753
1754         // Move stop frame before drawing cursor so cursor always appears on PowerVR.
1755         if(Gr_bitmap_poly){
1756                 d3d_stop_frame();
1757         }
1758
1759 //      ddrval = lpFrontBuffer->Flip( NULL, 1 );
1760 //      if (ddrval != DD_OK )   {
1761 //              mprintf(( "Fullscreen flip failed!\n" ));
1762 //              return;
1763 //      }
1764
1765         if(D3D_window){
1766                 // blt region
1767                 RECT rect, view_rect;
1768                 GetClientRect( (HWND)os_get_window(), &rect);
1769                 ClientToScreen( (HWND)os_get_window(), (POINT*)&rect.left );
1770                 ClientToScreen( (HWND)os_get_window(), (POINT*)&rect.right );           
1771                 view_rect.left = 0;
1772                 view_rect.top = 0;
1773                 view_rect.right = gr_screen.max_w - 1;
1774                 view_rect.bottom = gr_screen.max_h - 1;
1775
1776                 // do the blit
1777                 lpFrontBuffer->Blt(&rect, lpBackBuffer, &view_rect, 0, NULL );
1778                 while(lpFrontBuffer->GetBltStatus(DDGBS_ISBLTDONE) != DD_OK){}  
1779         } else {
1780         TryFlipAgain:
1781                 if ( lpFrontBuffer->IsLost() == DDERR_SURFACELOST )     {
1782                         lpFrontBuffer->Restore();
1783                 }
1784                 if ( lpBackBuffer->IsLost() == DDERR_SURFACELOST )      {
1785                         lpBackBuffer->Restore();
1786                 }
1787                 if ( lpZBuffer->IsLost() == DDERR_SURFACELOST ) {
1788                         lpZBuffer->Restore();
1789                 }
1790                 ddrval = lpFrontBuffer->Flip( NULL, DDFLIP_WAIT  );
1791                 if ( ddrval == DDERR_SURFACELOST )      {
1792                         mprintf(( "Front surface lost... attempting to restore...\n" ));
1793                         os_sleep(1000); // Wait a second
1794
1795                         // os poll?
1796         #ifndef THREADED
1797                         os_poll();
1798         #endif
1799
1800                         goto TryFlipAgain;
1801                 } else if (ddrval != DD_OK )    {
1802                         mprintf(( "Fullscreen flip failed!\n" ));
1803                 }
1804         }
1805
1806         d3d_tcache_frame();
1807
1808         int cnt = D3D_activate;
1809         if ( cnt )      {
1810                 D3D_activate-=cnt;
1811                 d3d_tcache_flush();
1812                 gr_d3d_clip_cursor(1);
1813         }
1814
1815         cnt = D3D_deactivate; 
1816         if ( cnt )      {
1817                 D3D_deactivate-=cnt;
1818                 gr_d3d_clip_cursor(0);
1819         }
1820
1821         d3d_start_frame();
1822 }
1823
1824 void gr_d3d_flip_cleanup()
1825 {
1826         d3d_stop_frame();
1827
1828         if (lpFrontBuffer->Flip( NULL, 1 ) != DD_OK )   {
1829                 mprintf(( "Flip failed!\n" ));
1830                 return;
1831         }
1832 }
1833
1834
1835 void gr_d3d_flip_window(uint _hdc, int x, int y, int w, int h )
1836 {
1837 }
1838
1839 void gr_d3d_cleanup()
1840 {
1841         if (!D3D_inited) return;
1842
1843         d3d_tcache_cleanup();   
1844
1845         // release surfaces
1846         gr_d3d_release_rendering_objects();
1847
1848         if ( lpD3D ) {
1849                 lpD3D->Release();
1850                 lpD3D = NULL; 
1851         }
1852
1853         if ( lpDD1 ) {
1854
1855                 HRESULT ddrval;
1856                 HWND hwnd = (HWND)os_get_window();
1857
1858                 ddrval = lpDD->RestoreDisplayMode();
1859                 if( ddrval != DD_OK )   {
1860                         mprintf(( "WIN_DD32: RestoreDisplayMode failed (0x%x)\n", ddrval ));
1861                 }
1862
1863                 ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL );
1864                 if( ddrval != DD_OK )   {
1865                         mprintf(( "WIN_DD32: SetCooperativeLevel W Failed (0x%x)\n", ddrval ));
1866                 }
1867
1868                 // restore windows clipping rectangle
1869                 ClipCursor(NULL);
1870
1871 //              SetWindowLong( hwnd, GWL_STYLE, WS_CAPTION | WS_SYSMENU );
1872 //              SetWindowLong( hwnd, GWL_EXSTYLE, 0 );
1873 //              SetWindowPos( hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE );
1874
1875                 // gr_d3d_clip_cursor(0);
1876                 
1877                 os_suspend();
1878                 lpDD1->Release();
1879                 os_resume();
1880                 lpDD1 = NULL; 
1881         }
1882
1883         D3D_inited = 0;
1884 }
1885
1886
1887 void gr_d3d_fade_in(int instantaneous)
1888 {
1889 }
1890
1891 void gr_d3d_fade_out(int instantaneous)
1892 {
1893 }
1894
1895
1896
1897 void gr_d3d_force_windowed()
1898 {
1899         HWND hwnd = (HWND)os_get_window();
1900
1901         // Simulate Alt+Tab
1902         PostMessage(hwnd,WM_SYSKEYUP, 0x9, 0xa00f0001 );
1903         PostMessage(hwnd,WM_SYSKEYUP, 0x12, 0xc0380001 );
1904
1905         gr_d3d_clip_cursor(0);
1906
1907         // Wait a second to give things a change to settle down.                                
1908         Sleep(1000);
1909 }
1910
1911 static char *Gr_saved_screen = NULL;
1912
1913 int gr_d3d_save_screen()
1914 {
1915         gr_reset_clip();
1916
1917         if ( Gr_saved_screen )  {
1918                 mprintf(( "Screen alread saved!\n" ));
1919                 return -1;
1920         }
1921
1922         Gr_saved_screen = (char*)malloc( gr_screen.max_w * gr_screen.max_h * gr_screen.bytes_per_pixel );
1923         if (!Gr_saved_screen) {
1924                 mprintf(( "Couldn't get memory for saved screen!\n" ));
1925                 return -1;
1926         }
1927
1928         HRESULT ddrval;
1929         DDSURFACEDESC ddsd;
1930
1931         memset( &ddsd, 0, sizeof( ddsd ) );
1932         ddsd.dwSize = sizeof( ddsd );
1933
1934         ddrval = lpFrontBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
1935         if ( ddrval != DD_OK )  {
1936                 free(Gr_saved_screen);
1937                 Gr_saved_screen = NULL;
1938                 mprintf(( "Error locking surface for save_screen, %s\n", d3d_error_string(ddrval) ));
1939                 return -1;
1940         } 
1941
1942         // 32 bit
1943         if(D3D_32bit){
1944                 uint *dptr = (uint*)ddsd.lpSurface;     
1945                 int i;
1946                 for (i=0; i<gr_screen.max_h; i++ )      {
1947                         memcpy( &Gr_saved_screen[gr_screen.max_w * i * gr_screen.bytes_per_pixel], dptr, gr_screen.max_w * gr_screen.bytes_per_pixel );
1948                 
1949                         dptr = (uint *)((uint)dptr + ddsd.lPitch);
1950                 }
1951         } else {
1952                 ushort *dptr = (ushort *)ddsd.lpSurface;        
1953                 int i;
1954                 for (i=0; i<gr_screen.max_h; i++ )      {
1955                         memcpy( &Gr_saved_screen[gr_screen.max_w * i * gr_screen.bytes_per_pixel], dptr, gr_screen.max_w * gr_screen.bytes_per_pixel );
1956                 
1957                         dptr = (ushort *)((uint)dptr + ddsd.lPitch);
1958                 }
1959         }
1960
1961         // Unlock the front buffer
1962         lpFrontBuffer->Unlock( NULL );
1963         
1964         if ( Gr_d3d_mouse_saved && !D3D_32bit)  {
1965                 ushort *sptr, *dptr;
1966
1967                 sptr = Gr_d3d_mouse_saved_data;
1968
1969                 for (int i=0; i<Gr_d3d_mouse_saved_h; i++ )     {
1970                         dptr = &((ushort*)Gr_saved_screen)[(Gr_d3d_mouse_saved_y1 + i) * gr_screen.max_w + Gr_d3d_mouse_saved_x1];
1971
1972                         for(int j=0; j<Gr_d3d_mouse_saved_w; j++ )      {
1973                                 *dptr++ = *sptr++;
1974                         }
1975                 }
1976         }       
1977
1978         return 0;
1979 }
1980
1981 void gr_d3d_restore_screen(int id)
1982 {
1983         gr_reset_clip();
1984
1985         if ( !Gr_saved_screen ) {
1986                 gr_clear();
1987                 return;
1988         }
1989
1990         HRESULT ddrval;
1991         DDSURFACEDESC ddsd;
1992
1993         memset( &ddsd, 0, sizeof( ddsd ) );
1994         ddsd.dwSize = sizeof( ddsd );
1995
1996         ddrval = lpBackBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
1997         if ( ddrval != DD_OK )  {
1998                 free(Gr_saved_screen);
1999                 Gr_saved_screen = NULL;
2000                 mprintf(( "Error locking surface for restore_screen, %s\n", d3d_error_string(ddrval) ));
2001                 return;
2002         } 
2003
2004         // restore
2005         if(D3D_32bit){
2006                 uint *dptr = (uint *)ddsd.lpSurface;    
2007                 int i;
2008                 for (i=0; i<gr_screen.max_h; i++ )      {
2009                         memcpy( dptr, &Gr_saved_screen[gr_screen.max_w * i * gr_screen.bytes_per_pixel], gr_screen.max_w * gr_screen.bytes_per_pixel );
2010                 
2011                         dptr = (uint *)((uint)dptr + ddsd.lPitch);
2012                 }
2013         } else {
2014                 ushort *dptr = (ushort *)ddsd.lpSurface;        
2015                 int i;
2016                 for (i=0; i<gr_screen.max_h; i++ )      {
2017                         memcpy( dptr, &Gr_saved_screen[gr_screen.max_w * i * gr_screen.bytes_per_pixel], gr_screen.max_w * gr_screen.bytes_per_pixel );
2018                 
2019                         dptr = (ushort *)((uint)dptr + ddsd.lPitch);
2020                 }
2021         }
2022
2023         // Unlock the back buffer
2024         lpBackBuffer->Unlock( NULL );
2025 }
2026
2027 void gr_d3d_free_screen(int id)
2028 {
2029         if ( Gr_saved_screen )  {
2030                 free( Gr_saved_screen );
2031                 Gr_saved_screen = NULL;
2032         }
2033 }
2034
2035 static int D3d_dump_frames = 0;
2036 static ubyte *D3d_dump_buffer = NULL;
2037 static int D3d_dump_frame_number = 0;
2038 static int D3d_dump_frame_count = 0;
2039 static int D3d_dump_frame_count_max = 0;
2040 static int D3d_dump_frame_size = 0;
2041 void gr_d3d_dump_frame_start(int first_frame, int frames_between_dumps)
2042 {
2043         if ( D3d_dump_frames )  {
2044                 Int3();         //  We're already dumping frames.  See John.
2045                 return;
2046         }       
2047         D3d_dump_frames = 1;
2048         D3d_dump_frame_number = first_frame;
2049         D3d_dump_frame_count = 0;
2050         D3d_dump_frame_count_max = frames_between_dumps;
2051         D3d_dump_frame_size = gr_screen.max_w * gr_screen.max_h * 2;
2052         
2053         if ( !D3d_dump_buffer ) {
2054                 int size = D3d_dump_frame_count_max * D3d_dump_frame_size;
2055                 D3d_dump_buffer = (ubyte *)malloc(size);
2056                 if ( !D3d_dump_buffer ) {
2057                         Error(LOCATION, "Unable to malloc %d bytes for dump buffer", size );
2058                 }
2059         }
2060 }
2061
2062 extern int tga_compress(char *out, char *in, int bytecount);
2063 void gr_d3d_flush_frame_dump()
2064 {
2065         int i,j;
2066         char filename[MAX_PATH_LEN], *movie_path = ".\\";
2067         ubyte outrow[1024*3*4];
2068
2069         if ( gr_screen.max_w > 1024)    {
2070                 mprintf(( "Screen too wide for frame_dump\n" ));
2071                 return;
2072         }
2073
2074         for (i = 0; i < D3d_dump_frame_count; i++) {
2075
2076                 int w = gr_screen.max_w;
2077                 int h = gr_screen.max_h;
2078
2079                 sprintf(filename, NOX("%sfrm%04d.tga"), movie_path, D3d_dump_frame_number );
2080                 D3d_dump_frame_number++;
2081
2082                 CFILE *f = cfopen(filename, "wb");
2083
2084                 // Write the TGA header
2085                 cfwrite_ubyte( 0, f );  //      IDLength;
2086                 cfwrite_ubyte( 0, f );  //      ColorMapType;
2087                 cfwrite_ubyte( 10, f ); //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
2088                 cfwrite_ushort( 0, f ); // CMapStart;
2089                 cfwrite_ushort( 0, f ); //      CMapLength;
2090                 cfwrite_ubyte( 0, f );  // CMapDepth;
2091                 cfwrite_ushort( 0, f ); //      XOffset;
2092                 cfwrite_ushort( 0, f ); //      YOffset;
2093                 cfwrite_ushort( (ushort)w, f ); //      Width;
2094                 cfwrite_ushort( (ushort)h, f ); //      Height;
2095                 cfwrite_ubyte( 24, f ); //PixelDepth;
2096                 cfwrite_ubyte( 0, f );  //ImageDesc;
2097
2098                 // Go through and write our pixels
2099                 for (j=0;j<h;j++)       {
2100                         ubyte *src_ptr = D3d_dump_buffer+(i*D3d_dump_frame_size)+(j*w*2);
2101
2102                         int len = tga_compress( (char *)outrow, (char *)src_ptr, w*sizeof(short) );
2103
2104                         cfwrite(outrow,len,1,f);
2105                 }
2106
2107                 cfclose(f);
2108
2109         }
2110
2111         D3d_dump_frame_count = 0;
2112 }
2113
2114 void gr_d3d_dump_frame_stop()
2115 {
2116
2117         if ( !D3d_dump_frames ) {
2118                 Int3();         //  We're not dumping frames.  See John.
2119                 return;
2120         }       
2121
2122         // dump any remaining frames
2123         gr_d3d_flush_frame_dump();
2124         
2125         D3d_dump_frames = 0;
2126         if ( D3d_dump_buffer )  {
2127                 free(D3d_dump_buffer);
2128                 D3d_dump_buffer = NULL;
2129         }
2130 }
2131
2132 void gr_d3d_dump_screen_hack( ushort * dst )
2133 {
2134         HRESULT ddrval;
2135         DDSURFACEDESC ddsd;     
2136         LPDIRECTDRAWSURFACE surf = lpBackBuffer;
2137         ushort pixel;
2138         ubyte r, g, b;
2139
2140         // don't dump in 32 bit
2141         if(D3D_32bit){
2142                 return;
2143         }
2144         
2145         // screen format
2146         BM_SELECT_SCREEN_FORMAT();
2147         memset( &ddsd, 0, sizeof( ddsd ) );
2148         ddsd.dwSize = sizeof( ddsd );
2149
2150         // try and lock the buffer
2151         ddrval = surf->Lock( NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY, NULL );
2152         if ( ddrval != DD_OK )  {
2153                 mprintf(( "Error locking surface for get_region, %s\n", d3d_error_string(ddrval) ));
2154                 return;
2155         }
2156
2157         ushort *sptr;           
2158         ubyte *rptr = (ubyte*)ddsd.lpSurface;   
2159
2160         for (int i=0; i<gr_screen.max_h; i++ )  {
2161                 sptr = (ushort*)&rptr[(gr_screen.max_h-i-1)*ddsd.lPitch];
2162                 
2163                 for(int j=0; j<gr_screen.max_w; j++ )   {
2164                         pixel = *sptr++;                        
2165
2166                         bm_get_components((ubyte*)pixel, &r, &g, &b, NULL);
2167
2168                         // bash to 565, hackity hack
2169                         pixel = 0;
2170                         pixel |= ((r >> 3) << 11);
2171                         pixel |= ((g >> 2) << 5);
2172                         pixel |= (b >> 3);
2173
2174                         *dst++ = pixel;
2175                 }
2176         }       
2177         
2178         // Unlock the buffer
2179         surf->Unlock( NULL );   
2180 }
2181
2182 void gr_d3d_dump_frame()
2183 {
2184         // A hacked function to dump the frame buffer contents
2185         gr_d3d_dump_screen_hack( (ushort *)(D3d_dump_buffer+(D3d_dump_frame_count*D3d_dump_frame_size)) );
2186
2187         D3d_dump_frame_count++;
2188
2189         if ( D3d_dump_frame_count == D3d_dump_frame_count_max ) {
2190                 gr_d3d_flush_frame_dump();
2191         }
2192 }       
2193
2194 uint gr_d3d_lock()
2195 {
2196         return 1;
2197 }
2198
2199 void gr_d3d_unlock()
2200 {
2201 }
2202
2203 void gr_d3d_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
2204 {
2205         D3DCOLOR color = 0;     
2206           
2207         Assert((r >= 0) && (r < 256));
2208         Assert((g >= 0) && (g < 256));
2209         Assert((b >= 0) && (b < 256));  
2210
2211         // turning fog off
2212         if(fog_mode == GR_FOGMODE_NONE){
2213                 // only change state if we need to
2214                 if(gr_screen.current_fog_mode != fog_mode){
2215                         d3d_SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE );           
2216                 }
2217                 gr_screen.current_fog_mode = fog_mode;
2218
2219                 // to prevent further state changes
2220                 return;
2221         }
2222
2223         // maybe switch fogging on
2224         if(gr_screen.current_fog_mode != fog_mode){             
2225                 d3d_SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);     
2226
2227                 // if we're using table fog, enable table fogging
2228                 if(D3D_fog_mode == 2){
2229                         d3d_SetRenderState( D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_LINEAR );                       
2230                 }
2231
2232                 gr_screen.current_fog_mode = fog_mode;  
2233         }       
2234
2235         // is color changing?
2236         if( (gr_screen.current_fog_color.red != r) || (gr_screen.current_fog_color.green != g) || (gr_screen.current_fog_color.blue != b) ){
2237                 // store the values
2238                 gr_d3d_init_color( &gr_screen.current_fog_color, r, g, b );
2239
2240                 color = RGB_MAKE(r, g, b);
2241                 d3d_SetRenderState(D3DRENDERSTATE_FOGCOLOR, color);     
2242         }               
2243
2244         // planes changing?
2245         if( (fog_near >= 0.0f) && (fog_far >= 0.0f) && ((fog_near != gr_screen.fog_near) || (fog_far != gr_screen.fog_far)) ){          
2246                 gr_screen.fog_near = fog_near;          
2247                 gr_screen.fog_far = fog_far;                                    
2248
2249                 // only generate a new fog table if we have to (wfog/table fog mode)
2250                 if(D3D_fog_mode == 2){  
2251                         d3d_SetRenderState( D3DRENDERSTATE_FOGTABLESTART, *((DWORD *)(&fog_near)));             
2252                         d3d_SetRenderState( D3DRENDERSTATE_FOGTABLEEND, *((DWORD *)(&fog_far)));
2253                 }                               
2254         }       
2255 }
2256
2257 void gr_d3d_set_gamma(float gamma)
2258 {
2259         Gr_gamma = gamma;
2260         Gr_gamma_int = int(Gr_gamma*100);
2261
2262         // Create the Gamma lookup table
2263         int i;
2264         for (i=0; i<256; i++ )  {
2265                 int v = fl2i(pow(i2fl(i)/255.0f, 1.0f/Gr_gamma)*255.0f);
2266                 if ( v > 255 ) {
2267                         v = 255;
2268                 } else if ( v < 0 )     {
2269                         v = 0;
2270                 }
2271                 Gr_gamma_lookup[i] = v;
2272         }
2273
2274         // Flush any existing textures
2275         d3d_tcache_flush();
2276 }
2277
2278 void d3d_get_pixel(int x, int y, ubyte *pixel)
2279 {
2280         HRESULT ddrval;
2281         DDSURFACEDESC ddsd;
2282
2283         memset( &ddsd, 0, sizeof( ddsd ) );
2284         ddsd.dwSize = sizeof( ddsd );
2285
2286         ddrval = lpFrontBuffer->Lock( NULL, &ddsd, DDLOCK_WAIT, NULL );
2287         if ( ddrval != DD_OK )  {
2288                 mprintf(( "Error locking surface for uv test, %s\n", d3d_error_string(ddrval) ));
2289                 return;
2290         } 
2291
2292         ubyte *dptr = (ubyte *)((uint)ddsd.lpSurface + y*ddsd.lPitch + (x * gr_screen.bytes_per_pixel));
2293         memcpy(pixel, dptr, gr_screen.bytes_per_pixel); 
2294
2295         // Unlock the buffer
2296         lpFrontBuffer->Unlock( NULL );  
2297 }
2298
2299 void gr_d3d_get_pixel(int x, int y, int *r, int *g, int *b)
2300 {
2301 }
2302
2303 // resolution checking
2304 int gr_d3d_supports_res_interface(int res)
2305 {
2306         return 1;
2307 }
2308
2309 int gr_d3d_supports_res_ingame(int res)
2310 {
2311         return 1;
2312 }
2313
2314 void gr_d3d_set_cull(int cull)
2315 {
2316         // switch culling on or off
2317         if(cull){
2318                 d3d_SetRenderState( D3DRENDERSTATE_CULLMODE, D3DCULL_CCW );             
2319         } else {
2320                 d3d_SetRenderState( D3DRENDERSTATE_CULLMODE, D3DCULL_NONE );                            
2321         }
2322 }
2323
2324 // cross fade
2325 void gr_d3d_cross_fade(int bmap1, int bmap2, int x1, int y1, int x2, int y2, float pct)
2326 {
2327         if ( pct <= 50 )        {
2328                 gr_set_bitmap(bmap1);
2329                 gr_bitmap(x1, y1);
2330         } else {
2331                 gr_set_bitmap(bmap2);
2332                 gr_bitmap(x2, y2);
2333         }       
2334 }
2335
2336 // filtering
2337 void gr_d3d_filter_set(int filter)
2338 {
2339 }
2340
2341 // set clear color
2342 void gr_d3d_set_clear_color(int r, int g, int b)
2343 {
2344         gr_init_color(&gr_screen.current_clear_color, r, g, b);
2345 }
2346
2347 // JAS: Need to turn optimizations off or Alan's machine, with 3dfx direct3d hangs...
2348 #pragma optimize("",off)                
2349
2350 void d3d_detect_texture_origin_32()
2351 {
2352         int test_bmp = -1;
2353         ubyte data[32*32];
2354         color ac;
2355         uint pix1a, pix2a;
2356         uint pix1b, pix2b;
2357
2358         mprintf(( "Detecting uv type...\n" ));
2359
2360         gr_set_gamma(1.0f);
2361         gr_init_alphacolor(&ac,255,255,255,255);
2362                 
2363         memset( data, 0, 32*32 );
2364         data[15*32+15] = 14;
2365         
2366         test_bmp = bm_create( 8, 32, 32, data, BMP_AABITMAP );
2367         
2368         mprintf(( "Trial #1\n" ));
2369         D3d_rendition_uvs = 0;
2370         gr_reset_clip();
2371         gr_clear();
2372         gr_set_color_fast(&ac);
2373         gr_set_bitmap( test_bmp );
2374         gr_aabitmap_ex(0, 0, 32, 32, 15, 15);
2375         Mouse_hidden++;
2376         gr_flip();
2377         d3d_get_pixel(0, 0, (ubyte*)&pix1a);
2378         d3d_get_pixel(1, 1, (ubyte*)&pix1b);
2379         gr_reset_clip();
2380         gr_clear();
2381         gr_flip();
2382         Mouse_hidden--;
2383
2384         mprintf(( "Trial #2\n" ));
2385         D3d_rendition_uvs = 1;
2386         gr_reset_clip();
2387         gr_clear();
2388         gr_set_color_fast(&ac);
2389         gr_set_bitmap( test_bmp );
2390         gr_aabitmap_ex(0, 0, 32, 32, 15, 15);
2391         Mouse_hidden++;
2392         gr_flip();
2393         d3d_get_pixel(0, 0, (ubyte*)&pix2a);
2394         d3d_get_pixel(1, 1, (ubyte*)&pix2b);
2395         gr_reset_clip();
2396         gr_clear();
2397         gr_flip();
2398         Mouse_hidden--;
2399
2400         bm_release(test_bmp);
2401
2402         mprintf(( "Pixel 1 = %x , %x\n", pix1a, pix1b ));
2403         mprintf(( "Pixel 2 = %x , %x\n", pix2a, pix2b ));
2404
2405         if ( (pix1b!=0) || (pix2b!=0)  )        {
2406                 D3d_rendition_uvs = 1;
2407         } else {
2408                 D3d_rendition_uvs = 0;
2409         }
2410
2411         mprintf(( "Rendition uvs: %d\n", D3d_rendition_uvs ));
2412 }
2413         
2414 void d3d_detect_texture_origin_16()
2415 {
2416         int test_bmp = -1;
2417         ubyte data[32*32];
2418         color ac;
2419         ushort pix1a, pix2a;
2420         ushort pix1b, pix2b;
2421
2422         mprintf(( "Detecting uv type...\n" ));
2423
2424         gr_set_gamma(1.0f);
2425         gr_init_alphacolor(&ac,255,255,255,255);
2426                 
2427         memset( data, 0, 32*32 );
2428         data[15*32+15] = 14;
2429         
2430         test_bmp = bm_create( 8, 32, 32, data, BMP_AABITMAP );
2431         
2432         mprintf(( "Trial #1\n" ));
2433         D3d_rendition_uvs = 0;
2434         gr_reset_clip();
2435         gr_clear();
2436         gr_set_color_fast(&ac);
2437         gr_set_bitmap( test_bmp );
2438         gr_aabitmap_ex(0, 0, 32, 32, 15, 15);
2439         Mouse_hidden++;
2440         gr_flip();
2441         d3d_get_pixel(0, 0, (ubyte*)&pix1a);
2442         d3d_get_pixel(1, 1, (ubyte*)&pix1b);
2443         gr_reset_clip();
2444         gr_clear();
2445         gr_flip();
2446         Mouse_hidden--;
2447
2448         mprintf(( "Trial #2\n" ));
2449         D3d_rendition_uvs = 1;
2450         gr_reset_clip();
2451         gr_clear();
2452         gr_set_color_fast(&ac);
2453         gr_set_bitmap( test_bmp );
2454         gr_aabitmap_ex(0, 0, 32, 32, 15, 15);
2455         Mouse_hidden++;
2456         gr_flip();
2457         d3d_get_pixel(0, 0, (ubyte*)&pix2a);
2458         d3d_get_pixel(1, 1, (ubyte*)&pix2b);
2459         gr_reset_clip();
2460         gr_clear();
2461         gr_flip();
2462         Mouse_hidden--;
2463
2464         bm_release(test_bmp);
2465
2466         mprintf(( "Pixel 1 = %x , %x\n", pix1a, pix1b ));
2467         mprintf(( "Pixel 2 = %x , %x\n", pix2a, pix2b ));
2468
2469         if ( (pix1b!=0) || (pix2b!=0)  )        {
2470                 D3d_rendition_uvs = 1;
2471         } else {
2472                 D3d_rendition_uvs = 0;
2473         }
2474
2475         mprintf(( "Rendition uvs: %d\n", D3d_rendition_uvs ));
2476 }
2477
2478 void gr_d3d_get_region(int front, int w, int h, ubyte *data)
2479 {       
2480         HRESULT ddrval;
2481         DDSURFACEDESC ddsd;     
2482         LPDIRECTDRAWSURFACE surf = front ? lpFrontBuffer : lpBackBuffer;
2483         
2484         memset( &ddsd, 0, sizeof( ddsd ) );
2485         ddsd.dwSize = sizeof( ddsd );
2486
2487         // try and lock the buffer
2488         ddrval = surf->Lock( NULL, &ddsd, DDLOCK_WAIT | DDLOCK_READONLY, NULL );
2489         if ( ddrval != DD_OK )  {
2490                 mprintf(( "Error locking surface for get_region, %s\n", d3d_error_string(ddrval) ));
2491                 return;
2492         }
2493
2494         ubyte *sptr;    
2495         ubyte *dptr = data;     
2496         ubyte *rptr = (ubyte*)ddsd.lpSurface;   
2497
2498         for (int i=0; i<h; i++ )        {
2499                 sptr = (ubyte*)&rptr[ i * ddsd.lPitch ];
2500
2501                 // don't think we need to swizzle here ...
2502                 for(int j=0; j<w; j++ ) {
2503                         memcpy(dptr, sptr, gr_screen.bytes_per_pixel);
2504                         dptr += gr_screen.bytes_per_pixel;
2505                         sptr += gr_screen.bytes_per_pixel;
2506                 }
2507         }       
2508         
2509         // Unlock the buffer
2510         surf->Unlock( NULL );   
2511 }
2512
2513 extern float D3D_line_offset;
2514
2515 void d3d_detect_line_offset_32()
2516 {
2517         color ac;
2518         uint pix1a, pix2a;
2519         uint pix1b, pix2b;
2520
2521         mprintf(( "Detecting line offset...\n" ));
2522
2523         gr_set_gamma(1.0f);
2524         gr_init_alphacolor(&ac, 255,255, 255, 255);
2525         
2526         mprintf(( "Trial #1\n" ));
2527         D3D_line_offset = 0.0f;
2528         gr_reset_clip();
2529         gr_clear();
2530         gr_set_color_fast(&ac);
2531         gr_line( 0,0,0,0 );
2532         Mouse_hidden++;
2533         gr_flip();
2534         d3d_get_pixel(0, 0, (ubyte*)&pix1a);
2535         d3d_get_pixel(1, 1, (ubyte*)&pix1b);
2536         gr_reset_clip();
2537         gr_clear();
2538         gr_flip();
2539         Mouse_hidden--;
2540
2541         mprintf(( "Trial #2\n" ));
2542         D3D_line_offset = 0.5f;
2543         gr_reset_clip();
2544         gr_clear();
2545         gr_set_color_fast(&ac);
2546         gr_line( 0,0,0,0 );
2547         Mouse_hidden++;
2548         gr_flip();
2549         d3d_get_pixel(0, 0, (ubyte*)&pix2a);
2550         d3d_get_pixel(1, 1, (ubyte*)&pix2b);
2551         gr_reset_clip();
2552         gr_clear();
2553         gr_flip();
2554         Mouse_hidden--;
2555
2556         mprintf(( "Pixel 1 = %x , %x\n", pix1a, pix1b ));
2557         mprintf(( "Pixel 2 = %x , %x\n", pix2a, pix2b ));
2558
2559         if ( (pix1a!=0) && (pix2a==0)  )        {
2560                 D3D_line_offset = 0.0f;
2561         } else if ( (pix1a==0) && (pix2a!=0)  ) {
2562                 D3D_line_offset = 0.5f;
2563         } else {
2564                 D3D_line_offset = 0.0f;
2565         }
2566
2567         mprintf(( "Line offset: %.1f\n", D3D_line_offset ));
2568 }
2569
2570 void d3d_detect_line_offset_16()
2571 {
2572         color ac;
2573         ushort pix1a, pix2a;
2574         ushort pix1b, pix2b;
2575
2576         mprintf(( "Detecting line offset...\n" ));
2577
2578         gr_set_gamma(1.0f);
2579         gr_init_alphacolor(&ac, 255,255, 255, 255);
2580         
2581         mprintf(( "Trial #1\n" ));
2582         D3D_line_offset = 0.0f;
2583         gr_reset_clip();
2584         gr_clear();
2585         gr_set_color_fast(&ac);
2586         gr_line( 0,0,0,0 );
2587         Mouse_hidden++;
2588         gr_flip();
2589         d3d_get_pixel(0, 0, (ubyte*)&pix1a);
2590         d3d_get_pixel(1, 1, (ubyte*)&pix1b);
2591         gr_reset_clip();
2592         gr_clear();
2593         gr_flip();
2594         Mouse_hidden--;
2595
2596         mprintf(( "Trial #2\n" ));
2597         D3D_line_offset = 0.5f;
2598         gr_reset_clip();
2599         gr_clear();
2600         gr_set_color_fast(&ac);
2601         gr_line( 0,0,0,0 );
2602         Mouse_hidden++;
2603         gr_flip();
2604         d3d_get_pixel(0, 0, (ubyte*)&pix2a);
2605         d3d_get_pixel(1, 1, (ubyte*)&pix2b);
2606         gr_reset_clip();
2607         gr_clear();
2608         gr_flip();
2609         Mouse_hidden--;
2610
2611         mprintf(( "Pixel 1 = %x , %x\n", pix1a, pix1b ));
2612         mprintf(( "Pixel 2 = %x , %x\n", pix2a, pix2b ));
2613
2614         if ( (pix1a!=0) && (pix2a==0)  )        {
2615                 D3D_line_offset = 0.0f;
2616         } else if ( (pix1a==0) && (pix2a!=0)  ) {
2617                 D3D_line_offset = 0.5f;
2618         } else {
2619                 D3D_line_offset = 0.0f;
2620         }
2621
2622         mprintf(( "Line offset: %.1f\n", D3D_line_offset ));
2623 }
2624
2625 #pragma optimize("",on)         
2626
2627 void gr_d3d_init()
2628 {
2629         D3D_enabled = 1;                // Tell Freespace code that we're using Direct3D.
2630         D3D_running = 0;        
2631
2632         Assert( !D3D_inited );
2633
2634         // pixel format
2635         Bm_pixel_format = BM_PIXEL_FORMAT_D3D;  
2636         
2637         D3D_32bit = 0;
2638         D3D_window = Cmdline_window;
2639
2640         // windowed?
2641         if(D3D_window){
2642                 gr_d3d_init_device(gr_screen.max_w, gr_screen.max_h);
2643         } else {
2644                 // 32 bit mode          
2645                 if(Cmdline_force_32bit){
2646                         gr_screen.bits_per_pixel = 32;
2647                         gr_screen.bytes_per_pixel = 4;
2648                         gr_d3d_init_device(gr_screen.max_w, gr_screen.max_h);                                           
2649                 } else {
2650                         // 16 bit mode                  
2651                         gr_screen.bits_per_pixel = 16;
2652                         gr_screen.bytes_per_pixel = 2;
2653                         gr_d3d_init_device(gr_screen.max_w, gr_screen.max_h);                                           
2654                 }
2655         }
2656
2657         // determine 32 bit status
2658         D3D_32bit = gr_screen.bits_per_pixel == 32 ? 1 : 0;
2659         d3d_tcache_init(D3D_32bit ? 1 : 0);
2660         Gr_bitmap_poly = D3D_32bit ? 1 : 0;     
2661
2662         // did we initialize properly?
2663         if(!D3D_inited){
2664                 return;
2665         }
2666
2667         // zbiasing?
2668         if(os_config_read_uint(NULL, "DisableZbias", 0)){
2669                 D3D_zbias = 0;
2670         }
2671         
2672         d3d_start_frame();      
2673
2674         Gr_current_red = &Gr_red;
2675         Gr_current_blue = &Gr_blue;
2676         Gr_current_green = &Gr_green;
2677         Gr_current_alpha = &Gr_alpha;
2678
2679         gr_screen.gf_flip = gr_d3d_flip;
2680         gr_screen.gf_flip_window = gr_d3d_flip_window;
2681         gr_screen.gf_set_clip = gr_d3d_set_clip;
2682         gr_screen.gf_reset_clip = gr_d3d_reset_clip;
2683         gr_screen.gf_set_font = grx_set_font;
2684
2685         gr_screen.gf_get_color = gr_d3d_get_color;
2686         gr_screen.gf_init_color = gr_d3d_init_color;
2687         gr_screen.gf_set_color_fast = gr_d3d_set_color_fast;
2688         gr_screen.gf_set_color = gr_d3d_set_color;
2689         gr_screen.gf_init_color = gr_d3d_init_color;
2690         gr_screen.gf_init_alphacolor = gr_d3d_init_alphacolor;
2691
2692         gr_screen.gf_set_bitmap = gr_d3d_set_bitmap;
2693         gr_screen.gf_create_shader = gr_d3d_create_shader;
2694         gr_screen.gf_set_shader = gr_d3d_set_shader;
2695         gr_screen.gf_clear = gr_d3d_clear;
2696         // gr_screen.gf_bitmap = gr_d3d_bitmap;
2697         // gr_screen.gf_bitmap_ex = gr_d3d_bitmap_ex;
2698         gr_screen.gf_aabitmap = gr_d3d_aabitmap;
2699         gr_screen.gf_aabitmap_ex = gr_d3d_aabitmap_ex;
2700
2701         gr_screen.gf_rect = gr_d3d_rect;
2702         gr_screen.gf_shade = gr_d3d_shade;
2703         gr_screen.gf_string = gr_d3d_string;
2704         gr_screen.gf_circle = gr_d3d_circle;
2705
2706         gr_screen.gf_line = gr_d3d_line;
2707         gr_screen.gf_aaline = gr_d3d_aaline;
2708         gr_screen.gf_pixel = gr_d3d_pixel;
2709         gr_screen.gf_scaler = gr_d3d_scaler;
2710         gr_screen.gf_aascaler = gr_d3d_aascaler;
2711         gr_screen.gf_tmapper = gr_d3d_tmapper;
2712
2713         gr_screen.gf_gradient = gr_d3d_gradient;
2714
2715         gr_screen.gf_set_palette = gr_d3d_set_palette;
2716         gr_screen.gf_print_screen = gr_d3d_print_screen;
2717
2718         gr_screen.gf_fade_in = gr_d3d_fade_in;
2719         gr_screen.gf_fade_out = gr_d3d_fade_out;
2720         gr_screen.gf_flash = gr_d3d_flash;
2721
2722         gr_screen.gf_zbuffer_get = gr_d3d_zbuffer_get;
2723         gr_screen.gf_zbuffer_set = gr_d3d_zbuffer_set;
2724         gr_screen.gf_zbuffer_clear = gr_d3d_zbuffer_clear;
2725
2726         gr_screen.gf_save_screen = gr_d3d_save_screen;
2727         gr_screen.gf_restore_screen = gr_d3d_restore_screen;
2728         gr_screen.gf_free_screen = gr_d3d_free_screen;
2729
2730         // Screen dumping stuff
2731         gr_screen.gf_dump_frame_start = gr_d3d_dump_frame_start;
2732         gr_screen.gf_dump_frame_stop = gr_d3d_dump_frame_stop;
2733         gr_screen.gf_dump_frame = gr_d3d_dump_frame;
2734
2735         gr_screen.gf_set_gamma = gr_d3d_set_gamma;
2736
2737         // Lock/unlock stuff
2738         gr_screen.gf_lock = gr_d3d_lock;
2739         gr_screen.gf_unlock = gr_d3d_unlock;
2740
2741         // screen region
2742         gr_screen.gf_get_region = gr_d3d_get_region;
2743
2744         // fog stuff
2745         gr_screen.gf_fog_set = gr_d3d_fog_set;
2746
2747         // pixel get
2748         gr_screen.gf_get_pixel = gr_d3d_get_pixel;
2749
2750         // poly culling
2751         gr_screen.gf_set_cull = gr_d3d_set_cull;
2752
2753         // cross fade
2754         gr_screen.gf_cross_fade = gr_d3d_cross_fade;
2755
2756         // filtering
2757         gr_screen.gf_filter_set = gr_d3d_filter_set;
2758
2759         // texture cache
2760         gr_screen.gf_tcache_set = d3d_tcache_set;
2761
2762         // set clear color
2763         gr_screen.gf_set_clear_color = gr_d3d_set_clear_color;
2764         
2765         uint tmp = os_config_read_uint( NULL, "D3DTextureOrigin", 0xFFFF );
2766
2767         if ( tmp != 0xFFFF )    {
2768                 if ( tmp )      {
2769                         D3d_rendition_uvs = 1;
2770                 } else {
2771                         D3d_rendition_uvs = 0;
2772                 }
2773         } else {
2774                 if(D3D_32bit){
2775                         d3d_detect_texture_origin_32();
2776                 } else {
2777                         d3d_detect_texture_origin_16();
2778                 }
2779         }
2780
2781         tmp = os_config_read_uint( NULL, "D3DLineOffset", 0xFFFF );
2782
2783         if ( tmp != 0xFFFF )    {
2784                 if ( tmp )      {
2785                         D3D_line_offset = 0.5f;
2786                 } else {
2787                         D3D_line_offset = 0.0f;
2788                 }
2789         } else {
2790                 if(D3D_32bit){
2791                         d3d_detect_line_offset_32();
2792                 } else {
2793                         d3d_detect_line_offset_16();
2794                 }
2795         }
2796
2797         D3D_running = 1;        
2798
2799         Mouse_hidden++;
2800         gr_reset_clip();
2801         gr_clear();
2802         gr_flip();
2803         Mouse_hidden--;
2804 }
2805
2806 char* d3d_error_string(HRESULT error)
2807 {
2808 //XSTR:OFF
2809     switch(error) {
2810         case DD_OK:
2811             return "No error.\0";
2812         case DDERR_ALREADYINITIALIZED:
2813             return "This object is already initialized.\0";
2814         case DDERR_BLTFASTCANTCLIP:
2815             return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0";
2816         case DDERR_CANNOTATTACHSURFACE:
2817             return "This surface can not be attached to the requested surface.\0";
2818         case DDERR_CANNOTDETACHSURFACE:
2819             return "This surface can not be detached from the requested surface.\0";
2820         case DDERR_CANTCREATEDC:
2821             return "Windows can not create any more DCs.\0";
2822         case DDERR_CANTDUPLICATE:
2823             return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0";
2824         case DDERR_CLIPPERISUSINGHWND:
2825             return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0";
2826         case DDERR_COLORKEYNOTSET:
2827             return "No src color key specified for this operation.\0";
2828         case DDERR_CURRENTLYNOTAVAIL:
2829             return "Support is currently not available.\0";
2830         case DDERR_DIRECTDRAWALREADYCREATED:
2831             return "A DirectDraw object representing this driver has already been created for this process.\0";
2832         case DDERR_EXCEPTION:
2833             return "An exception was encountered while performing the requested operation.\0";
2834         case DDERR_EXCLUSIVEMODEALREADYSET:
2835             return "An attempt was made to set the cooperative level when it was already set to exclusive.\0";
2836         case DDERR_GENERIC:
2837             return "Generic failure.\0";
2838         case DDERR_HEIGHTALIGN:
2839             return "Height of rectangle provided is not a multiple of reqd alignment.\0";
2840         case DDERR_HWNDALREADYSET:
2841             return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0";
2842         case DDERR_HWNDSUBCLASSED:
2843             return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0";
2844         case DDERR_IMPLICITLYCREATED:
2845             return "This surface can not be restored because it is an implicitly created surface.\0";
2846         case DDERR_INCOMPATIBLEPRIMARY:
2847             return "Unable to match primary surface creation request with existing primary surface.\0";
2848         case DDERR_INVALIDCAPS:
2849             return "One or more of the caps bits passed to the callback are incorrect.\0";
2850         case DDERR_INVALIDCLIPLIST:
2851             return "DirectDraw does not support the provided cliplist.\0";
2852         case DDERR_INVALIDDIRECTDRAWGUID:
2853             return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0";
2854         case DDERR_INVALIDMODE:
2855             return "DirectDraw does not support the requested mode.\0";
2856         case DDERR_INVALIDOBJECT:
2857             return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0";
2858         case DDERR_INVALIDPARAMS:
2859             return "One or more of the parameters passed to the function are incorrect.\0";
2860         case DDERR_INVALIDPIXELFORMAT:
2861             return "The pixel format was invalid as specified.\0";
2862         case DDERR_INVALIDPOSITION:
2863             return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0";
2864         case DDERR_INVALIDRECT:
2865             return "Rectangle provided was invalid.\0";
2866         case DDERR_LOCKEDSURFACES:
2867             return "Operation could not be carried out because one or more surfaces are locked.\0";
2868         case DDERR_NO3D:
2869             return "There is no 3D present.\0";
2870         case DDERR_NOALPHAHW:
2871             return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0";
2872         case DDERR_NOBLTHW:
2873             return "No blitter hardware present.\0";
2874         case DDERR_NOCLIPLIST:
2875             return "No cliplist available.\0";
2876         case DDERR_NOCLIPPERATTACHED:
2877             return "No clipper object attached to surface object.\0";
2878         case DDERR_NOCOLORCONVHW:
2879             return "Operation could not be carried out because there is no color conversion hardware present or available.\0";
2880         case DDERR_NOCOLORKEY:
2881             return "Surface doesn't currently have a color key\0";
2882         case DDERR_NOCOLORKEYHW:
2883             return "Operation could not be carried out because there is no hardware support of the destination color key.\0";
2884         case DDERR_NOCOOPERATIVELEVELSET:
2885             return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0";
2886         case DDERR_NODC:
2887             return "No DC was ever created for this surface.\0";
2888         case DDERR_NODDROPSHW:
2889             return "No DirectDraw ROP hardware.\0";
2890         case DDERR_NODIRECTDRAWHW:
2891             return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0";
2892         case DDERR_NOEMULATION:
2893             return "Software emulation not available.\0";
2894         case DDERR_NOEXCLUSIVEMODE:
2895             return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0";
2896         case DDERR_NOFLIPHW:
2897             return "Flipping visible surfaces is not supported.\0";
2898         case DDERR_NOGDI:
2899             return "There is no GDI present.\0";
2900         case DDERR_NOHWND:
2901             return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0";
2902         case DDERR_NOMIRRORHW:
2903             return "Operation could not be carried out because there is no hardware present or available.\0";
2904         case DDERR_NOOVERLAYDEST:
2905             return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0";
2906         case DDERR_NOOVERLAYHW:
2907             return "Operation could not be carried out because there is no overlay hardware present or available.\0";
2908         case DDERR_NOPALETTEATTACHED:
2909             return "No palette object attached to this surface.\0";
2910         case DDERR_NOPALETTEHW:
2911             return "No hardware support for 16 or 256 color palettes.\0";
2912         case DDERR_NORASTEROPHW:
2913             return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0";
2914         case DDERR_NOROTATIONHW:
2915             return "Operation could not be carried out because there is no rotation hardware present or available.\0";
2916         case DDERR_NOSTRETCHHW:
2917             return "Operation could not be carried out because there is no hardware support for stretching.\0";
2918         case DDERR_NOT4BITCOLOR:
2919             return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0";
2920         case DDERR_NOT4BITCOLORINDEX:
2921             return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0";
2922         case DDERR_NOT8BITCOLOR:
2923             return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0";
2924         case DDERR_NOTAOVERLAYSURFACE:
2925             return "Returned when an overlay member is called for a non-overlay surface.\0";
2926         case DDERR_NOTEXTUREHW:
2927             return "Operation could not be carried out because there is no texture mapping hardware present or available.\0";
2928         case DDERR_NOTFLIPPABLE:
2929             return "An attempt has been made to flip a surface that is not flippable.\0";
2930         case DDERR_NOTFOUND:
2931             return "Requested item was not found.\0";
2932         case DDERR_NOTLOCKED:
2933             return "Surface was not locked.  An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0";
2934         case DDERR_NOTPALETTIZED:
2935             return "The surface being used is not a palette-based surface.\0";
2936         case DDERR_NOVSYNCHW:
2937             return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0";
2938         case DDERR_NOZBUFFERHW:
2939             return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0";
2940         case DDERR_NOZOVERLAYHW:
2941             return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0";
2942         case DDERR_OUTOFCAPS:
2943             return "The hardware needed for the requested operation has already been allocated.\0";
2944         case DDERR_OUTOFMEMORY:
2945             return "DirectDraw does not have enough memory to perform the operation.\0";
2946         case DDERR_OUTOFVIDEOMEMORY:
2947             return "DirectDraw does not have enough memory to perform the operation.\0";
2948         case DDERR_OVERLAYCANTCLIP:
2949             return "The hardware does not support clipped overlays.\0";
2950         case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
2951             return "Can only have ony color key active at one time for overlays.\0";
2952         case DDERR_OVERLAYNOTVISIBLE:
2953             return "Returned when GetOverlayPosition is called on a hidden overlay.\0";
2954         case DDERR_PALETTEBUSY:
2955             return "Access to this palette is being refused because the palette is already locked by another thread.\0";
2956         case DDERR_PRIMARYSURFACEALREADYEXISTS:
2957             return "This process already has created a primary surface.\0";
2958         case DDERR_REGIONTOOSMALL:
2959             return "Region passed to Clipper::GetClipList is too small.\0";
2960         case DDERR_SURFACEALREADYATTACHED:
2961             return "This surface is already attached to the surface it is being attached to.\0";
2962         case DDERR_SURFACEALREADYDEPENDENT:
2963             return "This surface is already a dependency of the surface it is being made a dependency of.\0";
2964         case DDERR_SURFACEBUSY:
2965             return "Access to this surface is being refused because the surface is already locked by another thread.\0";
2966         case DDERR_SURFACEISOBSCURED:
2967             return "Access to surface refused because the surface is obscured.\0";
2968         case DDERR_SURFACELOST:
2969             return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0";
2970         case DDERR_SURFACENOTATTACHED:
2971             return "The requested surface is not attached.\0";
2972         case DDERR_TOOBIGHEIGHT:
2973             return "Height requested by DirectDraw is too large.\0";
2974         case DDERR_TOOBIGSIZE:
2975             return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0";
2976         case DDERR_TOOBIGWIDTH:
2977             return "Width requested by DirectDraw is too large.\0";
2978         case DDERR_UNSUPPORTED:
2979             return "Action not supported.\0";
2980         case DDERR_UNSUPPORTEDFORMAT:
2981             return "FOURCC format requested is unsupported by DirectDraw.\0";
2982         case DDERR_UNSUPPORTEDMASK:
2983             return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0";
2984         case DDERR_VERTICALBLANKINPROGRESS:
2985             return "Vertical blank is in progress.\0";
2986         case DDERR_WASSTILLDRAWING:
2987             return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0";
2988         case DDERR_WRONGMODE:
2989             return "This surface can not be restored because it was created in a different mode.\0";
2990         case DDERR_XALIGN:
2991             return "Rectangle provided was not horizontally aligned on required boundary.\0";
2992         case D3DERR_BADMAJORVERSION:
2993             return "D3DERR_BADMAJORVERSION\0";
2994         case D3DERR_BADMINORVERSION:
2995             return "D3DERR_BADMINORVERSION\0";
2996         case D3DERR_EXECUTE_LOCKED:
2997             return "D3DERR_EXECUTE_LOCKED\0";
2998         case D3DERR_EXECUTE_NOT_LOCKED:
2999             return "D3DERR_EXECUTE_NOT_LOCKED\0";
3000         case D3DERR_EXECUTE_CREATE_FAILED:
3001             return "D3DERR_EXECUTE_CREATE_FAILED\0";
3002         case D3DERR_EXECUTE_DESTROY_FAILED:
3003             return "D3DERR_EXECUTE_DESTROY_FAILED\0";
3004         case D3DERR_EXECUTE_LOCK_FAILED:
3005             return "D3DERR_EXECUTE_LOCK_FAILED\0";
3006         case D3DERR_EXECUTE_UNLOCK_FAILED:
3007             return "D3DERR_EXECUTE_UNLOCK_FAILED\0";
3008         case D3DERR_EXECUTE_FAILED:
3009             return "D3DERR_EXECUTE_FAILED\0";
3010         case D3DERR_EXECUTE_CLIPPED_FAILED:
3011             return "D3DERR_EXECUTE_CLIPPED_FAILED\0";
3012         case D3DERR_TEXTURE_NO_SUPPORT:
3013             return "D3DERR_TEXTURE_NO_SUPPORT\0";
3014         case D3DERR_TEXTURE_NOT_LOCKED:
3015             return "D3DERR_TEXTURE_NOT_LOCKED\0";
3016         case D3DERR_TEXTURE_LOCKED:
3017             return "D3DERR_TEXTURELOCKED\0";
3018         case D3DERR_TEXTURE_CREATE_FAILED:
3019             return "D3DERR_TEXTURE_CREATE_FAILED\0";
3020         case D3DERR_TEXTURE_DESTROY_FAILED:
3021             return "D3DERR_TEXTURE_DESTROY_FAILED\0";
3022         case D3DERR_TEXTURE_LOCK_FAILED:
3023             return "D3DERR_TEXTURE_LOCK_FAILED\0";
3024         case D3DERR_TEXTURE_UNLOCK_FAILED:
3025             return "D3DERR_TEXTURE_UNLOCK_FAILED\0";
3026         case D3DERR_TEXTURE_LOAD_FAILED:
3027             return "D3DERR_TEXTURE_LOAD_FAILED\0";
3028         case D3DERR_MATRIX_CREATE_FAILED:
3029             return "D3DERR_MATRIX_CREATE_FAILED\0";
3030         case D3DERR_MATRIX_DESTROY_FAILED:
3031             return "D3DERR_MATRIX_DESTROY_FAILED\0";
3032         case D3DERR_MATRIX_SETDATA_FAILED:
3033             return "D3DERR_MATRIX_SETDATA_FAILED\0";
3034         case D3DERR_SETVIEWPORTDATA_FAILED:
3035             return "D3DERR_SETVIEWPORTDATA_FAILED\0";
3036         case D3DERR_MATERIAL_CREATE_FAILED:
3037             return "D3DERR_MATERIAL_CREATE_FAILED\0";
3038         case D3DERR_MATERIAL_DESTROY_FAILED:
3039             return "D3DERR_MATERIAL_DESTROY_FAILED\0";
3040         case D3DERR_MATERIAL_SETDATA_FAILED:
3041             return "D3DERR_MATERIAL_SETDATA_FAILED\0";
3042         case D3DERR_LIGHT_SET_FAILED:
3043             return "D3DERR_LIGHT_SET_FAILED\0";
3044         default:
3045             return "Unrecognized error value.\0";
3046     }
3047 //XSTR:ON
3048 }
3049