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