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