b57cfa1ef568e8dbe930cfed43b4166db8ed6442
[sdk] / ecere / src / gfx / drivers / Direct3D9DisplayDriver.ec
1 namespace gfx::drivers;
2
3 import "instance"
4
5 #if defined(__WIN32__)
6
7 #ifndef D3DPRESENT_DONOTWAIT
8 #define D3DPRESENT_DONOTWAIT 0x00000001L
9 #endif
10
11 #define D3D_DEBUG_INFO  1
12
13 #define Method _Method
14 #define uint _uint
15 #define byte _byte
16 #define int64 _int64
17 #define String _String
18 #define Mutex _Mutex
19 #define Size _Size
20 #define Platform _Platform
21
22 #include <windows.h>
23
24 #if defined(__MINGW32__) && !defined(_W64)
25 #undef DECLARE_INTERFACE
26 #define DECLARE_INTERFACE(i) \
27    interface i { CONST_VTABLE struct i##Vtbl *lpVtbl; }; \
28    typedef CONST_VTABLE struct i##Vtbl i##Vtbl; \
29    CONST_VTABLE struct i##Vtbl
30 #endif
31
32 #include <d3d9.h>
33
34 #undef Method
35 #undef uint
36 #undef byte
37 #undef int64
38 #undef String
39 #undef Mutex
40 #undef Size
41 #undef Platform
42
43 import "Display"
44
45 #define MATRIX_STACK_SIZE  32
46
47 #define NUM_VERTEX_DECLS 4
48
49 static class D3DDisplay : struct
50 {
51    Box updateBox;
52    IDirect3DSwapChain9 * swapChain;
53    Matrix worldMatrixStack[MATRIX_STACK_SIZE];
54    Matrix * worldMatrix;
55    D3DMATRIX projMatrix;
56    D3DLIGHT9 lights[NumberOfLights], lightsPI[NumberOfLights];
57    D3DPRESENT_PARAMETERS d3dpp;
58    IDirect3DSurface9 * backBuffer, * depthSurface;
59    bool vSync;
60 };
61
62 static class D3DSystem : struct
63 {
64    HMODULE d3dDll;
65    IDirect3D9 * direct3D;
66    IDirect3DDevice9 * d3dDevice;
67    IDirect3D9 * (WINAPI * direct3DCreate9)(UINT);
68    uint usage;
69    D3DPRESENT_PARAMETERS d3dpp;
70
71    IDirect3DVertexDeclaration9 * decls[NUM_VERTEX_DECLS], * decl2D;
72    bool ready;
73    HWND hwnd;
74    int format;
75    bool inScene;
76 };
77
78 static class D3DSurface : struct
79 {
80    // For compatibility with LFB driver
81    Font font;
82    bool opaqueText;
83    int xOffset;
84    bool writingText;
85    bool writingOutline;
86
87    ColorAlpha background;
88 };
89
90 static class D3DMesh : struct
91 {
92    IDirect3DVertexBuffer9 * vertices;
93    IDirect3DVertexBuffer9 * normals;
94    IDirect3DVertexBuffer9 * texCoords;
95    IDirect3DVertexBuffer9 * texCoords2;
96 };
97
98 static struct Vertex
99 {
100    float x,y,z;
101    ColorAlpha color;
102    float u,v;
103 };
104
105 static class D3DIndices : struct
106 {
107    uint16 * indices;
108    IDirect3DIndexBuffer9 * buffer;
109    int nIndices;
110 };
111
112 static int primitiveTypes[RenderPrimitiveType] =
113 {
114    D3DPT_POINTLIST, D3DPT_LINELIST, D3DPT_TRIANGLELIST, D3DPT_TRIANGLESTRIP, D3DPT_TRIANGLEFAN, D3DPT_TRIANGLEFAN, 0, D3DPT_LINESTRIP
115 };
116
117 static void SetTransformMatrix(IDirect3DDevice9 * device, Matrix matrix)
118 {
119    D3DMATRIX d3dMat =
120    {
121       {
122          {
123             (float)matrix.m[0][0], (float)matrix.m[0][1], (float)matrix.m[0][2], (float)matrix.m[0][3],
124             (float)matrix.m[1][0], (float)matrix.m[1][1], (float)matrix.m[1][2], (float)matrix.m[1][3],
125             (float)matrix.m[2][0], (float)matrix.m[2][1], (float)matrix.m[2][2], (float)matrix.m[2][3],
126             (float)matrix.m[3][0], (float)matrix.m[3][1], (float)matrix.m[3][2], (float)matrix.m[3][3]
127          }
128       }
129    };
130    IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &d3dMat);
131 }
132
133 class Direct3D9DisplayDriver : DisplayDriver
134 {
135    class_property(name) = "Direct3D";
136
137    // Utility Functions
138    bool ::LockDisplay(Display display, Surface surface, Bitmap lfbBitmap, Surface * lfbSurface)
139    {
140       bool result = false;
141       D3DDisplay d3dDisplay = display.driverData;
142
143       //if(!IDirect3DDevice9_GetBackBuffer(d3dSystem.d3dDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dDisplay.backBuffer))
144       {
145          D3DLOCKED_RECT lockedRect;
146          if(!IDirect3DSurface9_LockRect(d3dDisplay.backBuffer, &lockedRect, null, 0))
147          {
148             result = true;
149             switch(d3dDisplay.d3dpp.BackBufferFormat)
150             {
151                case D3DFMT_A8R8G8B8:
152                case D3DFMT_X8R8G8B8:
153                   lfbBitmap.pixelFormat = pixelFormat888;
154                   break;
155                case D3DFMT_R5G6B5:
156                   lfbBitmap.pixelFormat = pixelFormat565;
157                   break;
158                case D3DFMT_X1R5G5B5:
159                case D3DFMT_A1R5G5B5:
160                   lfbBitmap.pixelFormat = pixelFormat555;
161                   break;
162                case D3DFMT_A4R4G4B4:
163                case D3DFMT_X4R4G4B4:
164                   lfbBitmap.pixelFormat = pixelFormat444;
165                   break;
166                default:
167                   result = false;
168             }
169             if(result)
170             {
171                lfbBitmap.driver = null;
172                lfbBitmap.displaySystem = null;
173                lfbBitmap.picture = (byte *)lockedRect.pBits;
174                lfbBitmap.transparent = false;
175                lfbBitmap.stride = lockedRect.Pitch >> GetColorDepthShifts(lfbBitmap.pixelFormat);
176                lfbBitmap.width = display.width;
177                lfbBitmap.height = display.height;
178
179                *lfbSurface = lfbBitmap.GetSurface(surface ? surface.offset.x : 0, surface ? surface.offset.y : 0, surface ? surface.box : null);
180             }
181          }
182          if(!result)
183             IDirect3DSurface9_Release(d3dDisplay.backBuffer);
184       }
185       return result;
186    }
187
188    void ::UnlockDisplay(Display display, Surface surface)
189    {
190       D3DDisplay d3dDisplay = display.driverData;
191       if(d3dDisplay.backBuffer)
192       {
193          IDirect3DSurface9_UnlockRect(d3dDisplay.backBuffer);
194          IDirect3DSurface9_Release(d3dDisplay.backBuffer);
195       }
196       delete surface;
197    }
198
199    void ::SetViewportAndMatrices(Display display, int x, int y, Box box)
200    {
201       D3DDisplay d3dDisplay = display.driverData;
202       DisplaySystem displaySystem = display.displaySystem;
203       D3DSystem d3dSystem = displaySystem.driverData;
204       if(d3dSystem.ready)
205       {
206          D3DVIEWPORT9 viewport;
207          viewport.MinZ = 0;
208          viewport.MaxZ = 1;
209          if(box.right < box.left || box.bottom < box.top)
210          {
211             viewport.Width = viewport.Height = 1;
212             viewport.X = viewport.Y = MAXDWORD;
213          }
214          else
215          {
216             viewport.X = x + box.left;
217             viewport.Y = y + box.top;
218             viewport.Width = box.right - box.left + 1;
219             viewport.Height = box.bottom - box.top + 1;
220          }
221          if(!IDirect3DDevice9_SetViewport(d3dSystem.d3dDevice, &viewport))
222          {
223             D3DMATRIX * matProj = &d3dDisplay.projMatrix;
224             Matrix * matWorld = d3dDisplay.worldMatrix = d3dDisplay.worldMatrixStack;
225
226             matProj->m[0][0] = 2.0f / viewport.Width;
227             matProj->m[1][1] =-2.0f / viewport.Height;
228             matProj->m[2][2] = matProj->m[3][1] = matProj->m[3][3] = 1;
229             matProj->m[3][0] = -1;
230
231             IDirect3DDevice9_SetTransform(d3dSystem.d3dDevice, D3DTS_PROJECTION, matProj);
232
233             matWorld->Identity();
234             matWorld->m[3][0] =-box.left;
235             matWorld->m[3][1] =-box.top;
236
237             SetTransformMatrix(d3dSystem.d3dDevice, matWorld);
238          }
239       }
240    }
241
242    // Implementation
243    bool CreateDisplaySystem(DisplaySystem displaySystem)
244    {
245       bool result = false;
246       D3DSystem d3dSystem = displaySystem.driverData = D3DSystem { };
247       if(d3dSystem)
248       {
249          displaySystem.flags.alpha = true;
250          //if(displaySystem.flags.fullScreen)
251             displaySystem.flags.flipping = true;
252          displaySystem.pixelFormat = pixelFormat888;
253
254          d3dSystem.d3dDll = LoadLibrary("d3d9.dll");
255          if(d3dSystem.d3dDll)
256          {
257             d3dSystem.direct3DCreate9 = (void *)GetProcAddress(d3dSystem.d3dDll, "Direct3DCreate9");
258             if(d3dSystem.direct3DCreate9)
259             {
260                if((d3dSystem.direct3D = d3dSystem.direct3DCreate9(D3D_SDK_VERSION)))
261                {
262                   D3DDISPLAYMODE d3ddm;
263                   if(!IDirect3D9_GetAdapterDisplayMode(d3dSystem.direct3D, D3DADAPTER_DEFAULT, &d3ddm))
264                   {
265                      d3dSystem.d3dpp.BackBufferCount = 1;
266
267                      if(displaySystem.flags.fullScreen)
268                      {
269                         d3dSystem.d3dpp.BackBufferWidth = d3ddm.Width;
270                         d3dSystem.d3dpp.BackBufferHeight = d3ddm.Height;
271                         d3dSystem.d3dpp.hDeviceWindow = displaySystem.window;
272                      }
273                      else
274                      {
275                         d3dSystem.d3dpp.hDeviceWindow = d3dSystem.hwnd =
276                            CreateWindow("static", null, 0,0,0,0,0,null,null,null,null);
277                         d3dSystem.d3dpp.Windowed = TRUE;
278                      }
279
280                      d3dSystem.d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
281                      d3dSystem.format = d3dSystem.d3dpp.BackBufferFormat = d3ddm.Format;
282                      d3dSystem.d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
283
284                      if(!IDirect3D9_CreateDevice(d3dSystem.direct3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
285                         d3dSystem.d3dpp.hDeviceWindow,
286                                D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE|D3DCREATE_FPU_PRESERVE,
287                                &d3dSystem.d3dpp, &d3dSystem.d3dDevice))
288                         result = true;
289                      else
290                      {
291                         d3dSystem.usage = D3DUSAGE_SOFTWAREPROCESSING;
292                         if(!IDirect3D9_CreateDevice(d3dSystem.direct3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
293                               d3dSystem.d3dpp.hDeviceWindow,
294                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE,
295                                   &d3dSystem.d3dpp, &d3dSystem.d3dDevice))
296                            result = true;
297                      }
298
299                      if(result)
300                      {
301                         D3DVERTEXELEMENT9 vertexDecls[NUM_VERTEX_DECLS][4] =
302                         {
303                            {
304                               { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
305                               D3DDECL_END( )
306                            },
307                            {
308                               { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
309                               { 1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 },
310                               D3DDECL_END( )
311                            },
312                            {
313                               { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
314                               { 2, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
315                               D3DDECL_END( )
316                            },
317                            {
318                               { 0, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_POSITION, 0 },
319                               { 1, 0, D3DDECLTYPE_FLOAT3, 0, D3DDECLUSAGE_NORMAL, 0 },
320                               { 2, 0, D3DDECLTYPE_FLOAT2, 0, D3DDECLUSAGE_TEXCOORD, 0 },
321                               D3DDECL_END( )
322                            }
323                         };
324
325                         D3DVERTEXELEMENT9 vertexDecl2D[] =
326                         {
327                            { 0, 0, D3DDECLTYPE_FLOAT3,   0, D3DDECLUSAGE_POSITION, 0 },
328                            { 0, (uint16)(3*sizeof(float)), D3DDECLTYPE_D3DCOLOR, 0, D3DDECLUSAGE_COLOR, 0 },
329                            { 0, (uint16)(3*sizeof(float) + sizeof(uint)), D3DDECLTYPE_FLOAT2,   0, D3DDECLUSAGE_TEXCOORD, 0 },
330                            D3DDECL_END( )
331                         };
332
333                         int c;
334                         for(c = 0; c<NUM_VERTEX_DECLS; c++)
335                            if(IDirect3DDevice9_CreateVertexDeclaration(d3dSystem.d3dDevice, vertexDecls[c], &d3dSystem.decls[c]))
336                               break;
337
338                         if(c < NUM_VERTEX_DECLS ||
339                            IDirect3DDevice9_CreateVertexDeclaration(d3dSystem.d3dDevice, vertexDecl2D, &d3dSystem.decl2D))
340                            result = false;
341                      }
342                      if(result)
343                         d3dSystem.ready = false;
344                   }
345                }
346             }
347          }
348          else
349             Log("Couldn't load library d3d9.dll\n");
350             //LogErrorCode(ERR_MISSING_LIBRARY, "d3d9.dll");
351       }
352       return result;
353    }
354
355    void DestroyDisplaySystem(DisplaySystem displaySystem)
356    {
357       D3DSystem d3dSystem = displaySystem.driverData;
358       int c;
359
360       if(d3dSystem.d3dDevice)
361          IDirect3DDevice9_Release(d3dSystem.d3dDevice);
362
363       if(d3dSystem.direct3D)
364          IDirect3D9_Release(d3dSystem.direct3D);
365
366       for(c = 0; c<NUM_VERTEX_DECLS; c++)
367       {
368          if(d3dSystem.decls[c])
369             IDirect3DVertexDeclaration9_Release(d3dSystem.decls[c]);
370       }
371
372       if(d3dSystem.decl2D)
373          IDirect3DVertexDeclaration9_Release(d3dSystem.decl2D);
374
375       FreeLibrary(d3dSystem.d3dDll);
376
377       delete d3dSystem;
378       displaySystem.driverData = null;
379
380    }
381
382    void DestroyDisplay(Display display)
383    {
384       DisplaySystem displaySystem = display.displaySystem;
385       D3DSystem d3dSystem = displaySystem.driverData;
386       D3DDisplay d3dDisplay = display.driverData;
387
388       if(d3dSystem.inScene)
389       {
390          IDirect3DDevice9_EndScene(d3dSystem.d3dDevice);
391          d3dSystem.inScene = false;
392       }
393
394       if(d3dDisplay.backBuffer)
395          IDirect3DSurface9_Release(d3dDisplay.backBuffer);
396
397       if(d3dDisplay.depthSurface)
398          IDirect3DSurface9_Release(d3dDisplay.depthSurface);
399
400       if(d3dDisplay.swapChain)
401          IDirect3DSwapChain9_Release(d3dDisplay.swapChain);
402
403       delete d3dDisplay;
404       display.driverData = null;
405    }
406
407    bool CreateDisplay(Display display)
408    {
409       bool result = false;
410       DisplaySystem displaySystem = display.displaySystem;
411       D3DSystem d3dSystem = displaySystem.driverData;
412       display.driverData = D3DDisplay { };
413
414       d3dSystem.ready = false;
415
416       result = true;
417
418       return result;
419    }
420
421    bool DisplaySize(Display display, int width, int height)
422    {
423       bool result = false;
424       DisplaySystem displaySystem = display.displaySystem;
425       D3DSystem d3dSystem = displaySystem.driverData;
426       D3DDisplay d3dDisplay = display.driverData;
427       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
428
429       d3dSystem.ready = false;
430
431       if(d3dDisplay.backBuffer)
432       {
433          IDirect3DSurface9_Release(d3dDisplay.backBuffer);
434          d3dDisplay.backBuffer = null;
435       }
436
437       if(d3dDisplay.depthSurface)
438       {
439          IDirect3DSurface9_Release(d3dDisplay.depthSurface);
440          d3dDisplay.depthSurface = null;
441       }
442
443       if(d3dDisplay.swapChain)
444       {
445          IDirect3DSwapChain9_Release(d3dDisplay.swapChain);
446          d3dDisplay.swapChain = null;
447       }
448
449       if(width && height)
450       {
451
452          if(displaySystem.flags.fullScreen)
453          {
454             d3dSystem.d3dpp.BackBufferWidth = width;
455             d3dSystem.d3dpp.BackBufferHeight = height;
456
457             result = !IDirect3DDevice9_Reset(d3dSystem.d3dDevice, &d3dSystem.d3dpp);
458
459             result = !IDirect3DDevice9_GetSwapChain(d3dSystem.d3dDevice, 0, &d3dDisplay.swapChain);
460          }
461          else
462          {
463             d3dDisplay.d3dpp.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
464             d3dDisplay.d3dpp.BackBufferWidth = width;
465             d3dDisplay.d3dpp.BackBufferHeight = height;
466             d3dDisplay.d3dpp.Windowed = TRUE;
467             //d3dDisplay.d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
468             //d3dDisplay.d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
469             d3dDisplay.d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
470
471             //d3dDisplay.d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
472             d3dDisplay.d3dpp.BackBufferFormat = d3dSystem.format;
473             d3dDisplay.d3dpp.BackBufferCount = 1;
474             d3dDisplay.d3dpp.hDeviceWindow = display.window;
475             d3dDisplay.d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
476             d3dDisplay.d3dpp.PresentationInterval = d3dDisplay.vSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_DONOTWAIT;
477             //d3dDisplay.d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
478             //d3dDisplay.d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
479
480             result = !IDirect3DDevice9_CreateAdditionalSwapChain(d3dSystem.d3dDevice,
481                &d3dDisplay.d3dpp, &d3dDisplay.swapChain);
482
483             if(!result)
484             {
485                d3dDisplay.d3dpp.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
486                result = !IDirect3DDevice9_CreateAdditionalSwapChain(d3dSystem.d3dDevice,
487                   &d3dDisplay.d3dpp, &d3dDisplay.swapChain);
488             }
489             if(!result)
490             {
491                d3dDisplay.d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
492                result = !IDirect3DDevice9_CreateAdditionalSwapChain(d3dSystem.d3dDevice,
493                   &d3dDisplay.d3dpp, &d3dDisplay.swapChain);
494             }
495          }
496
497          if(result)
498          {
499             if(!IDirect3DSwapChain9_GetBackBuffer(d3dDisplay.swapChain,
500                0, D3DBACKBUFFER_TYPE_MONO, &d3dDisplay.backBuffer))
501             {
502                if(!IDirect3DDevice9_CreateDepthStencilSurface(d3dSystem.d3dDevice, width, height,
503                      D3DFMT_D16, d3dDisplay.d3dpp.MultiSampleType,0,TRUE,&d3dDisplay.depthSurface, null))
504                {
505                   result = true;
506                   d3dSystem.ready = true;
507                }
508             }
509          }
510
511          if(d3dSystem.ready)
512          {
513             float fogDensity = 0;
514
515             IDirect3DDevice9_SetVertexDeclaration(d3dDevice, d3dSystem.decl2D);
516
517             //IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_SOFTWAREVERTEXPROCESSING, FALSE);
518             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_CULLMODE, D3DCULL_NONE);
519             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ZENABLE, FALSE);
520             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_LIGHTING, FALSE);
521             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ALPHABLENDENABLE, TRUE);
522             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
523             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
524             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_FOGTABLEMODE, D3DFOG_EXP);
525             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_FOGDENSITY, RenderStateFloat { fogDensity }.ui);
526             display.ambient = Color { 50,50,50 };
527             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_NORMALIZENORMALS, TRUE);
528             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_MULTISAMPLEANTIALIAS, FALSE);
529
530             IDirect3DDevice9_SetTextureStageState(d3dDevice, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);
531             IDirect3DDevice9_SetTextureStageState(d3dDevice, 0, D3DTSS_COLORARG1, D3DTA_CURRENT);
532             IDirect3DDevice9_SetTextureStageState(d3dDevice, 0, D3DTSS_COLORARG2, D3DTA_TEXTURE);
533             IDirect3DDevice9_SetTextureStageState(d3dDevice, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
534             IDirect3DDevice9_SetTextureStageState(d3dDevice, 0, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
535             IDirect3DDevice9_SetTextureStageState(d3dDevice, 0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE);
536
537             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
538             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
539             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
540
541             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
542             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
543
544             IDirect3DDevice9_SetTexture(d3dDevice, 0, null);
545
546             result = true;
547          }
548       }
549       display.width = width;
550       display.height = height;
551       d3dDisplay.updateBox.left = display.width;
552       d3dDisplay.updateBox.top = display.height;
553       d3dDisplay.updateBox.right = 0;
554       d3dDisplay.updateBox.bottom = 0;
555
556       return result;
557    }
558
559    void DisplayPosition(Display display, int x, int y)
560    {
561
562    }
563
564    void SetPalette(Display display, ColorAlpha * palette, bool colorMatch)
565    {
566    }
567
568    void RestorePalette(Display display)
569    {
570    }
571
572    void StartUpdate(Display display)
573    {
574    }
575
576    void EndUpdate(Display display)
577    {
578    }
579
580    void Scroll(Display display, Box scroll, int x, int y, Extent dirty)
581    {
582    }
583
584    void Update(Display display, Box updateBox)
585    {
586       DisplaySystem displaySystem = display.displaySystem;
587       D3DSystem d3dSystem = displaySystem.driverData;
588       D3DDisplay d3dDisplay = display.driverData;
589       if(d3dSystem.ready)
590       {
591          //eSystem_Sleep(0.05);
592          IDirect3DDevice9_EndScene(d3dSystem.d3dDevice);
593
594          if(display.displaySystem.flags.flipping)
595          {
596             // IDirect3DDevice9_Present(d3dSystem.d3dDevice, null, null, null, null);
597             IDirect3DSwapChain9_Present(d3dDisplay.swapChain, null, null, null, null, 0);
598          }
599          else
600          {
601             RECT source, dest;
602
603             if(updateBox != null)
604             {
605                source.left = dest.left = updateBox.left;
606                source.top = dest.top = updateBox.top;
607                source.right = dest.right = updateBox.right+1;
608                source.bottom = dest.bottom = updateBox.bottom+1;
609             }
610             else
611             {
612                source.left = dest.left = d3dDisplay.updateBox.left;
613                source.top = dest.top = d3dDisplay.updateBox.top;
614                source.right = dest.right = d3dDisplay.updateBox.right+1;
615                source.bottom = dest.bottom = d3dDisplay.updateBox.bottom+1;
616             }
617             if(dest.bottom > dest.top && dest.right > dest.left)
618                IDirect3DDevice9_Present(d3dSystem.d3dDevice, &source, &dest, null, null);
619             if(updateBox == null)
620             {
621                d3dDisplay.updateBox.left = display.width;
622                d3dDisplay.updateBox.top = display.height;
623                d3dDisplay.updateBox.right = 0;
624                d3dDisplay.updateBox.bottom = 0;
625             }
626          }
627          d3dSystem.inScene = false;
628       }
629    }
630
631    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
632    {
633       bool result = false;
634       Surface lfbSurface;
635       Bitmap lfbBitmap { };
636
637       if(LockDisplay(display, null, lfbBitmap, &lfbSurface))
638       {
639          Surface surface;
640          if(bitmap.pixelFormat != lfbBitmap.pixelFormat || bitmap.width < w || bitmap.height < h)
641          {
642             bitmap.Free();
643             bitmap.Allocate(null, w,h,w, lfbBitmap.pixelFormat, false);
644          }
645          surface = bitmap.GetSurface(0, 0, null);
646          if(surface)
647          {
648             ((subclass(DisplayDriver))class(LFBDisplayDriver)).Blit(null, surface, lfbBitmap, 0, 0, x, y, w, h);
649             result = true;
650          }
651          delete surface;
652          UnlockDisplay(display, lfbSurface);
653       }
654
655       lfbBitmap.picture = null;
656       delete lfbBitmap;
657
658       if(!result)
659          bitmap.Free();
660       return result;
661    }
662
663    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
664    {
665       if(bitmap.driverData)
666          IDirect3DTexture9_Release((IDirect3DTexture9 *)bitmap.driverData);
667    }
668
669    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
670    {
671       return false;
672    }
673
674    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps, int cubeMapFace)
675    {
676       bool result = false;
677       D3DSystem d3dSystem = displaySystem.driverData;
678       if(bitmap.Convert(null, pixelFormat888, null))
679       {
680          IDirect3DTexture9 * texture;
681          uint w = pow2i(Min(bitmap.width, 512)), h = pow2i(Min(bitmap.height, 512));
682
683          if(!IDirect3DDevice9_CreateTexture(d3dSystem.d3dDevice, w, h, mipMaps ? log2i(Max(w+1, h+1)) : 1, 0,
684                D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture, null))
685          {
686             int level;
687
688             result = true;
689
690             for(level = 0; result && (w >= 1 || h >= 1); level++, w >>= 1, h >>= 1)
691             {
692                D3DSURFACE_DESC desc;
693                D3DLOCKED_RECT lockedRect;
694
695                if(!IDirect3DTexture9_GetLevelDesc(texture, level, &desc) &&
696                   !IDirect3DTexture9_LockRect(texture, level, &lockedRect, null, 0))
697                {
698                   Bitmap mipMap { };
699                   Surface mipSurface;
700
701                   mipMap.width = desc.Width;
702                   mipMap.height = desc.Height;
703                   mipMap.picture = lockedRect.pBits;
704                   switch(desc.Format)
705                   {
706                      case D3DFMT_R5G6B5:   mipMap.pixelFormat = pixelFormat565; break;
707                      case D3DFMT_A8R8G8B8: mipMap.pixelFormat = pixelFormat888; break;
708                      case D3DFMT_A1R5G5B5: mipMap.pixelFormat = pixelFormat555; break;
709                      default:
710                         result = false;
711                   }
712                   if(result)
713                   {
714                      mipMap.stride = lockedRect.Pitch >> GetColorDepthShifts(mipMap.pixelFormat);
715
716                      mipSurface = mipMap.GetSurface(0,0,null);
717                      if(mipSurface)
718                      {
719                         if(mipMap.width != bitmap.width || mipMap.height != bitmap.height)
720                            mipSurface.Filter(bitmap, 0,0, 0,0, mipMap.width, mipMap.height, bitmap.width, bitmap.height);
721                         else
722                         {
723                            //FillBytesBy4(mipMap.picture, bitmap.picture, mipMap.width * mipMap.height);
724                            mipSurface.Blit(bitmap, 0,0, 0,0, bitmap.width, bitmap.height);
725                         }
726                         delete mipSurface;
727                      }
728                   }
729
730                   IDirect3DTexture9_UnlockRect(texture, level);
731
732                   mipMap.picture = null;
733                   delete mipMap;
734                }
735                if(!mipMaps) break;
736             }
737
738             bitmap.driver.FreeBitmap(bitmap.displaySystem, bitmap);
739             bitmap.driver = displaySystem.driver;
740             bitmap.driverData = (void *)texture;
741
742             if(!result)
743                FreeBitmap(displaySystem, bitmap);
744          }
745       }
746       return result;
747    }
748
749    bool GetSurface(Display display, Surface surface, int x,int y, Box clip)
750    {
751       bool result = false;
752       D3DDisplay d3dDisplay = display.driverData;
753       DisplaySystem displaySystem = display.displaySystem;
754       D3DSystem d3dSystem = displaySystem.driverData;
755       D3DSurface d3dSurface = surface.driverData = D3DSurface { };
756
757       if(d3dSurface && d3dSystem.ready)
758       {
759          surface.unclippedBox = surface.box = clip;
760          surface.offset.x = x;
761          surface.offset.y = y;
762
763          d3dDisplay.updateBox.left = Min(x + clip.left, d3dDisplay.updateBox.left);
764          d3dDisplay.updateBox.top = Min(y + clip.top, d3dDisplay.updateBox.top);
765          d3dDisplay.updateBox.right = Max(x + clip.right, d3dDisplay.updateBox.right);
766          d3dDisplay.updateBox.bottom = Max(y + clip.bottom, d3dDisplay.updateBox.bottom);
767
768          SetViewportAndMatrices(display, x,y, surface.box);
769
770          result = true;
771       }
772       return result;
773    }
774
775    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x, int y, Box clip)
776    {
777       return false;
778    }
779
780    void ReleaseSurface(Display display, Surface surface)
781    {
782       delete surface.driverData;
783    }
784
785    void Clip(Display display, Surface surface, Box clip)
786    {
787       Box box;
788
789       if(clip != null)
790       {
791          box = clip;
792          box.Clip(surface.unclippedBox);
793          surface.box = box;
794       }
795       else
796          box = surface.box = surface.unclippedBox;
797
798       SetViewportAndMatrices(display, surface.offset.x, surface.offset.y, box);
799    }
800
801    void SetForeground(Display display, Surface surface, ColorAlpha color)
802    {
803
804    }
805
806    void SetBackground(Display display, Surface surface, ColorAlpha color)
807    {
808       D3DSurface d3dSurface = surface.driverData;
809       d3dSurface.background = color;
810    }
811
812    ColorAlpha GetPixel(Display display, Surface surface,int x,int y)
813    {
814       return 0;
815    }
816
817    void PutPixel(Display display, Surface surface,int x, int y)
818    {
819       DisplaySystem displaySystem = display.displaySystem;
820       D3DSystem d3dSystem = displaySystem.driverData;
821       Vertex vertex { (float)x, (float)y, 1.0f, surface.foreground, 0, 0 };
822
823       IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_POINTLIST, 1,
824          &vertex, sizeof(Vertex));
825    }
826
827    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
828    {
829       DisplaySystem displaySystem = display.displaySystem;
830       D3DSystem d3dSystem = displaySystem.driverData;
831       Vertex vertex[2] =
832       {
833          { (float)x1, (float)y1, 1.0f, surface.foreground, 0, 0 },
834          { (float)x2, (float)y2, 1.0f, surface.foreground, 0, 0 }
835       };
836
837       if(x1 == x2)
838       {
839          /*
840          vertex[0].y-= 0.5f;
841          vertex[1].y+= 0.5f;
842          */
843          vertex[1].y+= 1.0f;
844       }
845       else if(y1 == y2)
846       {
847          /*
848          vertex[0].x-= 0.5f;
849          vertex[1].x+= 0.5f;
850          */
851          vertex[1].x+= 1.0f;
852       }
853
854       IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_LINESTRIP, 1,
855          vertex, sizeof(Vertex));
856    }
857
858    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
859    {
860       DisplaySystem displaySystem = display.displaySystem;
861       D3DSystem d3dSystem = displaySystem.driverData;
862       Vertex vertex[5] =
863       {
864          { (float)x1, (float)y1, 1.0f, surface.foreground, 0, 0 },
865          { (float)x2, (float)y1, 1.0f, surface.foreground, 0, 0 },
866          { (float)x2, (float)y2, 1.0f, surface.foreground, 0, 0 },
867          { (float)x1, (float)y2, 1.0f, surface.foreground, 0, 0 },
868          { (float)x1, (float)y1, 1.0f, surface.foreground, 0, 0 }
869       };
870
871       IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_LINESTRIP, 4,
872          vertex, sizeof(Vertex));
873
874    }
875
876    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
877    {
878       DisplaySystem displaySystem = display.displaySystem;
879       D3DSystem d3dSystem = displaySystem.driverData;
880       D3DSurface d3dSurface = surface.driverData;
881       Vertex vertex[4] =
882       {
883          /*
884          { (float)x1, (float)y1, 1.0f, d3dSurface.background, 0, 0 },
885          { (float)x2 + 1.0f, (float)y1, 1.0f, d3dSurface.background, 0, 0 },
886          { (float)x1, (float)y2, 1.0f, d3dSurface.background, 0, 0 },
887          { (float)x2 + 1.0f, (float)y2, 1.0f, d3dSurface.background, 0, 0 }
888          */
889          { (float)x1, (float)y1 - 0.5f, 1.0f, d3dSurface.background, 0, 0 },
890          { (float)x2 + 1.0f, (float)y1 - 0.5f, 1.0f, d3dSurface.background, 0, 0 },
891          { (float)x1, (float)y2 + 1.5f, 1.0f, d3dSurface.background, 0, 0 },
892          { (float)x2 + 1.0f, (float)y2 + 1.5f, 1.0f, d3dSurface.background, 0, 0 }
893       };
894
895       IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
896          vertex, sizeof(Vertex));
897    }
898
899    void Clear(Display display, Surface surface, ClearType type)
900    {
901       DisplaySystem displaySystem = display.displaySystem;
902       D3DSystem d3dSystem = displaySystem.driverData;
903       D3DSurface d3dSurface = surface.driverData;
904       IDirect3DDevice9_Clear(d3dSystem.d3dDevice, 0, null,
905          ((type == depthBuffer) ? 0 : D3DCLEAR_TARGET) |
906          ((type == colorBuffer) ? 0 : D3DCLEAR_ZBUFFER),
907          d3dSurface.background, 1,0);
908    }
909
910    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap bitmap, PixelFormat format, ColorAlpha * palette)
911    {
912       return true;
913    }
914
915    void Blit(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
916    {
917       DisplaySystem displaySystem = display.displaySystem;
918       D3DSystem d3dSystem = displaySystem.driverData;
919       D3DSurface d3dSurface = surface.driverData;
920       Color foreground = d3dSurface.writingText ? surface.foreground : white;
921       Vertex vertex[4] =
922       {
923          { (float)dx, (float)dy, 1.0f, foreground,
924             (float)sx / (src.width-1), (float)sy/ (src.height-1) },
925          { (float)(dx+w), (float)dy, 1.0f, foreground,
926             (float)(sx+w)/ (src.width-1), (float)sy/ (src.height-1) },
927          { (float)dx, (float)(dy+h), 1.0f, foreground,
928             (float)sx/ (src.width-1), (float)(sy+h)/ (src.height-1) },
929          { (float)(dx+w), (float)(dy+h), 1.0f, foreground,
930             (float)(sx+w) / (src.width-1), (float)(sy+h)/ (src.height-1) }
931       };
932
933       IDirect3DDevice9_SetTexture(d3dSystem.d3dDevice, 0, (IDirect3DBaseTexture9 *)src.driverData);
934       IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
935          vertex, sizeof(Vertex));
936       IDirect3DDevice9_SetTexture(d3dSystem.d3dDevice, 0, null);
937    }
938
939    void Stretch(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
940    {
941       DisplaySystem displaySystem = display.displaySystem;
942       D3DSystem d3dSystem = displaySystem.driverData;
943       Vertex vertex[4] =
944       {
945          { (float)dx, (float)dy, 1.0f, surface.foreground,
946             (float)sx / (src.width-1), (float)sy/ (src.height-1) },
947          { (float)(dx+w), (float)dy, 1.0f, surface.foreground,
948             (float)(sx+sw)/ (src.width-1), (float)sy/ (src.height-1) },
949          { (float)dx, (float)(dy+h), 1.0f, surface.foreground,
950             (float)sx/ (src.width-1), (float)(sy+sh)/ (src.height-1) },
951          { (float)(dx+w), (float)(dy+h), 1.0f, surface.foreground,
952             (float)(sx+sw) / (src.width-1), (float)(sy+sh)/ (src.height-1) }
953       };
954
955       IDirect3DDevice9_SetTexture(d3dSystem.d3dDevice, 0, (IDirect3DBaseTexture9 *)src.driverData);
956       IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
957          vertex, sizeof(Vertex));
958       IDirect3DDevice9_SetTexture(d3dSystem.d3dDevice, 0, null);
959    }
960
961    void Filter(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
962    {
963       Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
964    }
965
966    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
967    {
968       Surface lfbSurface;
969       Bitmap lfbBitmap { };
970       if(LockDisplay(display, surface, lfbBitmap, &lfbSurface))
971       {
972          ((subclass(DisplayDriver))class(LFBDisplayDriver)).Stretch(null, lfbSurface, src, dx, dy, sx, sy, w, h, sw, sh);
973          UnlockDisplay(display, lfbSurface);
974       }
975       lfbBitmap.picture = null;
976       delete lfbBitmap;
977    }
978
979    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
980    {
981       Surface lfbSurface;
982       Bitmap lfbBitmap { };
983       if(LockDisplay(display, surface, lfbBitmap, &lfbSurface))
984       {
985          ((subclass(DisplayDriver))class(LFBDisplayDriver)).Blit(null, lfbSurface, src, dx, dy, sx, sy, w, h);
986          UnlockDisplay(display, lfbSurface);
987       }
988       lfbBitmap.picture = null;
989       delete lfbBitmap;
990    }
991
992    void FilterDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
993    {
994       StretchDI(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
995    }
996
997    void UnloadFont(DisplaySystem displaySystem, Font font)
998    {
999       ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
1000    }
1001
1002    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade)
1003    {
1004       return ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags, outlineSize, outlineFade);
1005    }
1006
1007    void TextFont(Display display, Surface surface, Font font)
1008    {
1009       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextFont(display, surface, font);
1010    }
1011
1012    void TextOpacity(Display display, Surface surface, bool opaque)
1013    {
1014       D3DSurface d3dSurface = surface.driverData;
1015       d3dSurface.opaqueText = opaque;
1016    }
1017
1018    void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
1019    {
1020       ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
1021    }
1022
1023    void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
1024    {
1025       DisplaySystem displaySystem = display.displaySystem;
1026       D3DSystem d3dSystem = displaySystem.driverData;
1027       D3DSurface d3dSurface = surface.driverData;
1028
1029       if(surface.textOpacity)
1030       {
1031          int w, h, adv;
1032          FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
1033          w += adv;
1034          {
1035             int x1 = x, y1 = y, x2 = x+w-1, y2 = y+h-1;
1036             Vertex vertex[4] =
1037             {
1038                { (float)x1, (float)y1 /*- 0.5*/, 1.0f, d3dSurface.background, 0, 0 },
1039                { (float)x2 + 1.0f, (float)y1 /*- 0.5*/, 1.0f, d3dSurface.background, 0, 0 },
1040                { (float)x1, (float)y2 /*+ 1.5f*/, 1.0f, d3dSurface.background, 0, 0 },
1041                { (float)x2 + 1.0f, (float)y2 /*+ 1.5f*/, 1.0f, d3dSurface.background, 0, 0 }
1042             };
1043
1044             IDirect3DDevice9_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
1045                vertex, sizeof(Vertex));
1046          }
1047          //display.displaySystem.driver.Area(display, surface, x, y, x+w-1, y+h-1);
1048       }
1049
1050       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
1051       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
1052       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
1053       d3dSurface.writingText = true;
1054
1055       ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
1056
1057       d3dSurface.writingText = false;
1058       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
1059       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
1060       IDirect3DDevice9_SetSamplerState(d3dSystem.d3dDevice, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
1061    }
1062
1063    void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
1064    {
1065       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
1066    }
1067
1068    void DrawingChar(Display display, Surface surface, char character)
1069    {
1070
1071    }
1072
1073    void LineStipple(Display display, Surface surface, uint stipple)
1074    {
1075       /*
1076       IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_LINEPATTERN,
1077          stipple?Muint(1,stipple):0);
1078       */
1079    }
1080
1081
1082    void SetRenderState(Display display, RenderState state, uint value)
1083    {
1084       DisplaySystem displaySystem = display.displaySystem;
1085       D3DSystem d3dSystem = displaySystem.driverData;
1086       D3DDisplay d3dDisplay = display.driverData;
1087       switch(state)
1088       {
1089          case antiAlias:
1090             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_MULTISAMPLEANTIALIAS, value ? TRUE : FALSE);
1091             break;
1092          case fillMode:
1093             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_FILLMODE,
1094                ((FillModeValue)value == solid) ? D3DFILL_SOLID : D3DFILL_WIREFRAME);
1095             break;
1096          case depthTest:
1097             // IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_ZENABLE, value ? D3DZB_USEW : D3DZB_FALSE);
1098             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_ZENABLE, value ? D3DZB_TRUE : D3DZB_FALSE);
1099             break;
1100          case depthWrite:
1101             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_ZWRITEENABLE, value);
1102             break;
1103          case fogColor:
1104             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_FOGCOLOR, value);
1105             break;
1106          case fogDensity:
1107          {
1108             float fogDensity = RenderStateFloat { ui = value }.f;
1109             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_FOGDENSITY, RenderStateFloat { fogDensity }.ui);
1110             break;
1111          }
1112          case blend:
1113             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_ALPHABLENDENABLE, value);
1114             break;
1115          case ambient:
1116             IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_AMBIENT, value);
1117             break;
1118          case vSync:
1119          {
1120             if(d3dDisplay.vSync != (bool)value)
1121             {
1122                d3dDisplay.vSync = (bool)value;
1123                DisplaySize(display, display.width, display.height);
1124             }
1125             break;
1126          }
1127       }
1128    }
1129
1130    void SetLight(Display display, int id, Light light)
1131    {
1132       DisplaySystem displaySystem = display.displaySystem;
1133       D3DSystem d3dSystem = displaySystem.driverData;
1134       D3DDisplay d3dDisplay = display.driverData;
1135       if(light != null)
1136       {
1137          D3DLIGHT9 d3dLight =
1138          {
1139             // Opacity on the light?
1140             D3DLIGHT_DIRECTIONAL,
1141             { light.diffuse.r, light.diffuse.g, light.diffuse.b,     1.0f },
1142             { light.specular.r, light.specular.g, light.specular.b,  1.0f },
1143             { light.ambient.r, light.ambient.g, light.ambient.b,     1.0f }
1144          };
1145          Vector3Df vector {0,0,1};
1146          Vector3Df vectorPI {0,0,-1};
1147          Vector3Df direction;
1148          Matrix mat;
1149          Vector3Df * lightDirection = (Vector3Df *)&d3dLight.Direction;
1150
1151          mat.RotationQuaternion(light.orientation);
1152
1153          direction.MultMatrix(vector, mat);
1154          if(!display.display3D || !display.display3D.camera)
1155          {
1156             d3dLight.Direction.x = direction.x;
1157             d3dLight.Direction.y = direction.y;
1158             d3dLight.Direction.z =-direction.z;
1159          }
1160          else
1161             lightDirection->MultMatrix(direction, d3dDisplay.worldMatrix);
1162
1163          d3dDisplay.lights[id] = d3dLight;
1164
1165          IDirect3DDevice9_LightEnable(d3dSystem.d3dDevice, id, TRUE);
1166          IDirect3DDevice9_SetLight(d3dSystem.d3dDevice, id, &d3dDisplay.lights[id] /*d3dLight*/);
1167
1168          direction.MultMatrix(vectorPI, mat);
1169          lightDirection->MultMatrix(direction, d3dDisplay.worldMatrix);
1170
1171          d3dDisplay.lightsPI[id] = d3dLight;
1172       }
1173       else
1174       {
1175          IDirect3DDevice9_LightEnable(d3dSystem.d3dDevice, id, FALSE);
1176          d3dDisplay.lights[id].Type = 0;
1177       }
1178    }
1179
1180    void SetCamera(Display display, Surface surface, Camera camera)
1181    {
1182       DisplaySystem displaySystem = display.displaySystem;
1183       D3DSystem d3dSystem = displaySystem.driverData;
1184       D3DDisplay d3dDisplay = display.driverData;
1185       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1186       if(camera)
1187       {
1188          Point topLeft {surface.box.left + surface.offset.x, surface.box.top + surface.offset.y};
1189          Point downRight {surface.box.right + surface.offset.x, surface.box.bottom  + surface.offset.y};
1190          Point origin
1191          {
1192             surface.offset.x + camera.origin.x,
1193             surface.offset.y + camera.origin.y
1194          };
1195          D3DMATRIX matProj;
1196          Matrix matrix;
1197          float l = (topLeft.x - origin.x) * camera.zMin / camera.focalX;
1198          float r = (downRight.x - origin.x) * camera.zMin / camera.focalX;
1199          float b = (downRight.y - origin.y) * camera.zMin / camera.focalY;
1200          float t = (topLeft.y - origin.y) * camera.zMin / camera.focalY;
1201          float n = camera.zMin;
1202          float f = camera.zMax;
1203
1204          matProj.m[0][0] = 2 * n / (r - l);
1205          matProj.m[0][1] = 0;
1206          matProj.m[0][2] = 0;
1207          matProj.m[0][3] = 0;
1208
1209          matProj.m[1][0] = 0;
1210          matProj.m[1][1] = 2 * n / (t - b);
1211          matProj.m[1][2] = 0;
1212          matProj.m[1][3] = 0;
1213
1214          matProj.m[2][0] = (l + r) / (r - l);
1215          matProj.m[2][1] = (t + b) / (t - b);
1216          matProj.m[2][2] = f / (n - f);
1217          matProj.m[2][3] = -1;
1218
1219          matProj.m[3][0] = 0;
1220          matProj.m[3][1] = 0;
1221          matProj.m[3][2] = n * f / (n - f);
1222          matProj.m[3][3] = 0;
1223
1224          IDirect3DDevice9_SetTransform(d3dDevice, D3DTS_PROJECTION, &matProj);
1225
1226          // *** View Matrix ***
1227          if(!display.display3D.camera)
1228             d3dDisplay.worldMatrix++;
1229
1230          matrix.Identity();
1231          matrix.Scale(1.0f, 1.0f, -1.0f);
1232          d3dDisplay.worldMatrix->Multiply(camera.viewMatrix, matrix);
1233
1234          SetTransformMatrix(d3dDevice, d3dDisplay.worldMatrix);
1235
1236          IDirect3DDevice9_SetVertexDeclaration(d3dDevice, d3dSystem.decls[0]);
1237
1238          // IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ZENABLE, D3DZB_USEW);
1239          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ZENABLE, D3DZB_TRUE);
1240          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ZWRITEENABLE, TRUE);
1241          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ALPHABLENDENABLE, FALSE);
1242          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_LIGHTING, TRUE);
1243          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_SPECULARENABLE, TRUE);
1244
1245          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_CULLMODE, D3DCULL_CW);
1246
1247          IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_MULTISAMPLEANTIALIAS, TRUE);
1248       }
1249       else if(display.display3D.camera)
1250       {
1251          d3dDisplay.worldMatrix = d3dDisplay.worldMatrixStack;
1252          SetTransformMatrix(d3dDevice, d3dDisplay.worldMatrix);
1253          IDirect3DDevice9_SetTransform(d3dDevice, D3DTS_PROJECTION, &d3dDisplay.projMatrix);
1254
1255          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_CULLMODE, D3DCULL_NONE);
1256          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ZENABLE, FALSE);
1257          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_LIGHTING, FALSE);
1258          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_ALPHABLENDENABLE, TRUE);
1259          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_FOGENABLE, FALSE);
1260          IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_SPECULARENABLE, FALSE);
1261
1262          IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1263          IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1264
1265          IDirect3DDevice9_SetVertexDeclaration(d3dDevice, d3dSystem.decl2D);
1266
1267          IDirect3DDevice9_SetTexture(d3dDevice, 0, null);
1268
1269          IDirect3DDevice9_SetRenderState(d3dSystem.d3dDevice, D3DRS_MULTISAMPLEANTIALIAS, FALSE);
1270       }
1271    }
1272
1273    void ApplyMaterial(Display display, Material material, Mesh mesh)
1274    {
1275       DisplaySystem displaySystem = display.displaySystem;
1276       D3DSystem d3dSystem = displaySystem.driverData;
1277       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1278       D3DMesh d3dMesh = mesh.data;
1279
1280       // Fog
1281       IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_FOGENABLE, (material.flags.noFog) ? FALSE : TRUE);
1282
1283       // Maps
1284       if(material.baseMap && d3dMesh.texCoords && material.baseMap.driver.displaySystem == displaySystem)
1285       {
1286          Bitmap map = material.baseMap;
1287
1288          IDirect3DDevice9_SetTexture(d3dDevice, 0, (IDirect3DBaseTexture9 *)map.driverData);
1289
1290          if(material.flags.tile)
1291          {
1292             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
1293             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
1294          }
1295          else
1296          {
1297             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
1298             IDirect3DDevice9_SetSamplerState(d3dDevice, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
1299          }
1300       }
1301       else
1302          IDirect3DDevice9_SetTexture(d3dDevice, 0, null);
1303
1304       {
1305          D3DMATERIAL9 d3dMaterial;
1306
1307          d3dMaterial.Diffuse.r = material.diffuse.r;
1308          d3dMaterial.Diffuse.g = material.diffuse.g;
1309          d3dMaterial.Diffuse.b = material.diffuse.b;
1310          d3dMaterial.Diffuse.a = material.opacity;
1311
1312          d3dMaterial.Ambient.r = material.ambient.r;
1313          d3dMaterial.Ambient.g = material.ambient.g;
1314          d3dMaterial.Ambient.b = material.ambient.b;
1315          d3dMaterial.Ambient.a = 1;
1316
1317          d3dMaterial.Specular.r = material.specular.r;
1318          d3dMaterial.Specular.g = material.specular.g;
1319          d3dMaterial.Specular.b = material.specular.b;
1320          d3dMaterial.Specular.a = 1;
1321
1322          d3dMaterial.Emissive.r = material.emissive.r;
1323          d3dMaterial.Emissive.g = material.emissive.g;
1324          d3dMaterial.Emissive.b = material.emissive.b;
1325          d3dMaterial.Emissive.a = 1;
1326
1327          d3dMaterial.Power = material.power;
1328
1329          IDirect3DDevice9_SetMaterial(d3dDevice, &d3dMaterial);   //(D3DMATERIAL9 *)&material.diffuse
1330       }
1331    }
1332
1333    void FreeMesh(DisplaySystem displaySystem, Mesh mesh)
1334    {
1335       D3DMesh d3dMesh = mesh.data;
1336       if(d3dMesh)
1337       {
1338          if(!(mesh.flags.vertices))
1339          {
1340             if(d3dMesh.vertices)
1341             {
1342                IDirect3DVertexBuffer9_Release(d3dMesh.vertices);
1343                d3dMesh.vertices = null;
1344             }
1345             delete mesh.vertices;
1346          }
1347          if(!(mesh.flags.normals))
1348          {
1349             if(d3dMesh.normals)
1350             {
1351                IDirect3DVertexBuffer9_Release(d3dMesh.normals);
1352                d3dMesh.normals = null;
1353             }
1354             delete mesh.normals;
1355          }
1356          if(!(mesh.flags.texCoords1))
1357          {
1358             if(d3dMesh.texCoords)
1359             {
1360                IDirect3DVertexBuffer9_Release(d3dMesh.texCoords);
1361                d3dMesh.texCoords = null;
1362             }
1363             delete mesh.texCoords;
1364          }
1365          if(!(mesh.flags.texCoords2))
1366          {
1367             if(d3dMesh.texCoords2)
1368             {
1369                IDirect3DVertexBuffer9_Release(d3dMesh.texCoords2);
1370                d3dMesh.texCoords2 = null;
1371             }
1372             // delete mesh.texCoords2;
1373          }
1374          if(!mesh.flags)
1375          {
1376             delete d3dMesh;
1377             mesh.data = null;
1378          }
1379       }
1380    }
1381
1382    bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags, int nVertices)
1383    {
1384       D3DSystem d3dSystem = displaySystem.driverData;
1385       bool result = false;
1386       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1387
1388       if(!mesh.data)
1389          mesh.data = D3DMesh { };
1390       if(mesh.data)
1391       {
1392          D3DMesh d3dMesh = mesh.data;
1393          result = true;
1394          if(mesh.nVertices == nVertices)
1395          {
1396             if(mesh.flags != flags)
1397             {
1398                // Same number of vertices, adding features (Leaves the other features pointers alone)
1399                if(flags.vertices && !d3dMesh.vertices)
1400                {
1401                   mesh.vertices = new Vector3Df[nVertices];
1402                   if(IDirect3DDevice9_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
1403                      d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.vertices, null))
1404                      result = false;
1405                }
1406                if(flags.normals && !d3dMesh.normals)
1407                {
1408                   mesh.normals = new Vector3Df[nVertices];
1409                   if(IDirect3DDevice9_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
1410                      d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.normals, null))
1411                      result = false;
1412                }
1413                if(flags.texCoords1 && !d3dMesh.texCoords)
1414                {
1415                   mesh.texCoords = new Pointf[nVertices];
1416                   if(IDirect3DDevice9_CreateVertexBuffer(d3dDevice, sizeof(Pointf) * nVertices,
1417                      d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.texCoords, null))
1418                      result = false;
1419                }
1420             }
1421          }
1422          else
1423          {
1424             // New number of vertices, reallocate all current and new features
1425             flags |= mesh.flags;
1426
1427             // Same number of vertices, adding features (Leaves the other features pointers alone)
1428             if(flags.vertices)
1429             {
1430                if(d3dMesh.vertices)
1431                {
1432                   IDirect3DVertexBuffer9_Release(d3dMesh.vertices);
1433                   d3dMesh.vertices = null;
1434                }
1435                mesh.vertices = renew mesh.vertices Vector3Df[nVertices];
1436                if(IDirect3DDevice9_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
1437                   d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.vertices, null))
1438                   result = false;
1439             }
1440             if(flags.normals)
1441             {
1442                if(d3dMesh.normals)
1443                {
1444                   IDirect3DVertexBuffer9_Release(d3dMesh.normals);
1445                   d3dMesh.normals = null;
1446                }
1447                mesh.normals = renew mesh.normals Vector3Df[nVertices];
1448                if(IDirect3DDevice9_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
1449                   d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.normals, null))
1450                   result = false;
1451             }
1452             if(flags.texCoords1)
1453             {
1454                if(d3dMesh.texCoords)
1455                {
1456                   IDirect3DVertexBuffer9_Release(d3dMesh.texCoords);
1457                   d3dMesh.texCoords = null;
1458                }
1459                mesh.texCoords = renew mesh.texCoords Pointf[nVertices];
1460                if(IDirect3DDevice9_CreateVertexBuffer(d3dDevice, sizeof(Pointf) * nVertices,
1461                   d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.texCoords, null))
1462                   result = false;
1463             }
1464          }
1465       }
1466       return result;
1467    }
1468
1469    void UnlockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags)
1470    {
1471       D3DMesh d3dMesh = mesh.data;
1472       if(!flags) flags = mesh.flags;
1473
1474       if(flags.vertices && mesh.vertices)
1475       {
1476          Vector3Df * vertices;
1477          if(!IDirect3DVertexBuffer9_Lock(d3dMesh.vertices, 0, 0, (void **) &vertices, 0))
1478          {
1479             memcpy(vertices, mesh.vertices, mesh.nVertices * sizeof(Vector3Df));
1480             IDirect3DVertexBuffer9_Unlock(d3dMesh.vertices);
1481          }
1482       }
1483       if(flags.normals && mesh.normals)
1484       {
1485          Vector3Df * normals;
1486          if(!IDirect3DVertexBuffer9_Lock(d3dMesh.normals, 0, 0, (void **) &normals, 0))
1487          {
1488             memcpy(normals, mesh.normals, mesh.nVertices * sizeof(Vector3Df));
1489             IDirect3DVertexBuffer9_Unlock(d3dMesh.normals);
1490          }
1491       }
1492       if(flags.texCoords1 && mesh.texCoords)
1493       {
1494          Pointf * texCoords;
1495          if(!IDirect3DVertexBuffer9_Lock(d3dMesh.texCoords, 0, 0, (void **) &texCoords, 0))
1496          {
1497             memcpy(texCoords, mesh.texCoords, mesh.nVertices * sizeof(Pointf));
1498             IDirect3DVertexBuffer9_Unlock(d3dMesh.texCoords);
1499          }
1500       }
1501    }
1502
1503    bool LockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags)
1504    {
1505
1506       return true;
1507    }
1508
1509    void FreeIndices(DisplaySystem displaySystem, D3DIndices d3dIndices)
1510    {
1511       if(d3dIndices)
1512       {
1513          if(d3dIndices.buffer)
1514             IDirect3DIndexBuffer9_Release(d3dIndices.buffer);
1515          delete d3dIndices.indices;
1516          delete d3dIndices;
1517       }
1518    }
1519
1520    D3DIndices AllocateIndices(DisplaySystem displaySystem, int nIndices, bool indices32bit)
1521    {
1522       D3DSystem d3dSystem = displaySystem.driverData;
1523       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1524       D3DIndices d3dIndices { };
1525       if(d3dIndices && nIndices)
1526       {
1527          d3dIndices.indices = (void *)(indices32bit ? new uint32[nIndices] : new uint16[nIndices]);
1528          IDirect3DDevice9_CreateIndexBuffer(d3dDevice, (indices32bit ? sizeof(uint32) : sizeof(uint16)) * nIndices, 0, indices32bit ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
1529             D3DPOOL_MANAGED, &d3dIndices.buffer, null);
1530          d3dIndices.nIndices = nIndices;
1531       }
1532       return d3dIndices;
1533    }
1534
1535    void UnlockIndices(DisplaySystem displaySystem, D3DIndices d3dIndices, bool indices32bit, int nIndices)
1536    {
1537       uint16 * indexBuffer = null;
1538       if(!IDirect3DIndexBuffer9_Lock(d3dIndices.buffer, 0, 0, (void **)&indexBuffer, 0))
1539       {
1540          memcpy(indexBuffer, d3dIndices.indices, (indices32bit ? sizeof(uint32) : sizeof(uint16)) * d3dIndices.nIndices);
1541          IDirect3DIndexBuffer9_Unlock(d3dIndices.buffer);
1542       }
1543    }
1544
1545    uint16 * LockIndices(DisplaySystem displaySystem, D3DIndices d3dIndices)
1546    {
1547       return d3dIndices.indices;
1548    }
1549
1550    void SelectMesh(Display display, Mesh mesh)
1551    {
1552       DisplaySystem displaySystem = display.displaySystem;
1553       D3DSystem d3dSystem = displaySystem.driverData;
1554       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1555
1556       if(mesh && mesh.data)
1557       {
1558          int decl = 0;
1559          D3DMesh d3dMesh = mesh.data;
1560
1561          IDirect3DDevice9_SetStreamSource(d3dDevice, 0, d3dMesh.vertices, 0, sizeof(Vector3Df));
1562          if(d3dMesh.normals)
1563          {
1564             IDirect3DDevice9_SetStreamSource(d3dDevice, 1, d3dMesh.normals, 0, sizeof(Vector3Df));
1565             decl |= 1;
1566          }
1567          else
1568             IDirect3DDevice9_SetStreamSource(d3dDevice, 1, null, 0, sizeof(Vector3Df));
1569          if(d3dMesh.texCoords)
1570          {
1571             IDirect3DDevice9_SetStreamSource(d3dDevice, 2, d3dMesh.texCoords, 0, sizeof(Pointf));
1572             decl |= 2;
1573          }
1574          else
1575             IDirect3DDevice9_SetStreamSource(d3dDevice, 2, null, 0, sizeof(Pointf));
1576
1577          IDirect3DDevice9_SetVertexDeclaration(d3dDevice, d3dSystem.decls[decl]);
1578       }
1579    }
1580
1581    void DrawPrimitives(Display display, PrimitiveSingle * primitive, Mesh mesh)
1582    {
1583       DisplaySystem displaySystem = display.displaySystem;
1584       D3DSystem d3dSystem = displaySystem.driverData;
1585       D3DDisplay d3dDisplay = display.driverData;
1586       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1587
1588       if(primitiveTypes[primitive->type.primitiveType])
1589       {
1590          int numPrimitives = (primitive->type.vertexRange) ? primitive->nVertices : primitive->nIndices;
1591          int c;
1592
1593          switch(primitive->type.primitiveType)
1594          {
1595             case lines:     numPrimitives /= 2; break;
1596             case triangles: numPrimitives /= 3; break;
1597             case triStrip:
1598             case triFan:
1599                numPrimitives -= 2;
1600                break;
1601             case lineStrip:
1602                numPrimitives --;
1603                break;
1604             case quads:
1605                numPrimitives /= 4;
1606                break;
1607          }
1608          if(primitive->type.vertexRange)
1609          {
1610             if(primitive->type.primitiveType == quads)
1611             {
1612                for(c = 0; c<numPrimitives; c++)
1613                   IDirect3DDevice9_DrawPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], primitive->first+c*4, 2);
1614             }
1615             else
1616                IDirect3DDevice9_DrawPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], primitive->first, numPrimitives);
1617          }
1618          else
1619          {
1620             D3DIndices indices = primitive->data;
1621             IDirect3DDevice9_SetIndices(d3dDevice, indices.buffer);
1622             if(primitive->type.primitiveType == quads)
1623             {
1624                for(c = 0; c<numPrimitives; c++)
1625                   IDirect3DDevice9_DrawIndexedPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], 0, 0, mesh.nVertices, c*4, 2);
1626             }
1627             else
1628                IDirect3DDevice9_DrawIndexedPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], 0, 0, mesh.nVertices, 0, numPrimitives);
1629          }
1630
1631          if(display.display3D.material.flags.doubleSided)
1632          {
1633             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_CULLMODE, D3DCULL_CCW);
1634             if(!display.display3D.material.flags.singleSideLight)
1635             {
1636                for(c = 0; c<NumberOfLights; c++)
1637                   if(d3dDisplay.lights[c].Type)
1638                      IDirect3DDevice9_SetLight(d3dDevice, c, &d3dDisplay.lightsPI[c]);
1639             }
1640
1641             if(primitive->type.vertexRange)
1642             {
1643                if(primitive->type.primitiveType == quads)
1644                {
1645                   for(c = 0; c<numPrimitives; c++)
1646                      IDirect3DDevice9_DrawPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], primitive->first+c*4, 2);
1647                }
1648                else
1649                   IDirect3DDevice9_DrawPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], primitive->first, numPrimitives);
1650             }
1651             else
1652             {
1653                D3DIndices indices = primitive->data;
1654                IDirect3DDevice9_SetIndices(d3dDevice, indices.buffer);
1655                if(primitive->type.primitiveType == quads)
1656                {
1657                   for(c = 0; c<numPrimitives; c++)
1658                      IDirect3DDevice9_DrawIndexedPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], 0, 0, mesh.nVertices, c*4, 2);
1659                }
1660                else
1661                   IDirect3DDevice9_DrawIndexedPrimitive(d3dDevice, primitiveTypes[primitive->type.primitiveType], 0, 0, mesh.nVertices, 0, numPrimitives);
1662             }
1663             if(!display.display3D.material.flags.singleSideLight)
1664             {
1665                for(c = 0; c<NumberOfLights; c++)
1666                   if(d3dDisplay.lights[c].Type)
1667                      IDirect3DDevice9_SetLight(d3dDevice, c, &d3dDisplay.lights[c]);
1668             }
1669
1670             IDirect3DDevice9_SetRenderState(d3dDevice, D3DRS_CULLMODE, D3DCULL_CW);
1671          }
1672       }
1673    }
1674
1675    void PushMatrix(Display display)
1676    {
1677       D3DDisplay d3dDisplay = display.driverData;
1678       *(d3dDisplay.worldMatrix+1) = *(d3dDisplay.worldMatrix);
1679       d3dDisplay.worldMatrix++;
1680    }
1681
1682    void PopMatrix(Display display, bool setMatrix)
1683    {
1684       D3DDisplay d3dDisplay = display.driverData;
1685       DisplaySystem displaySystem = display.displaySystem;
1686       D3DSystem d3dSystem = displaySystem.driverData;
1687       d3dDisplay.worldMatrix--;
1688       if(setMatrix)
1689          SetTransformMatrix(d3dSystem.d3dDevice, d3dDisplay.worldMatrix);
1690    }
1691
1692    void SetTransform(Display display, Matrix transMatrix, bool viewSpace, bool useCamera)
1693    {
1694       DisplaySystem displaySystem = display.displaySystem;
1695       D3DSystem d3dSystem = displaySystem.driverData;
1696       Camera camera = useCamera ? display.display3D.camera : null;
1697       D3DDisplay d3dDisplay = display.driverData;
1698       IDirect3DDevice9 * d3dDevice = d3dSystem.d3dDevice;
1699
1700       Matrix matrix = transMatrix, temp;
1701
1702       if(viewSpace)
1703       {
1704          matrix.Scale(1.0f, 1.0f, -1.0f);
1705          *(d3dDisplay.worldMatrix) = matrix;
1706       }
1707       else
1708       {
1709          if(camera)
1710             matrix.Translate(
1711                - camera.cPosition.x,
1712                - camera.cPosition.y,
1713                - camera.cPosition.z);
1714          temp.Multiply(matrix, d3dDisplay.worldMatrix);
1715          *(d3dDisplay.worldMatrix) = temp;
1716       }
1717
1718       SetTransformMatrix(d3dDevice, d3dDisplay.worldMatrix);
1719    }
1720
1721    bool Lock(Display display)
1722    {
1723       DisplaySystem displaySystem = display.displaySystem;
1724       D3DSystem d3dSystem = displaySystem.driverData;
1725       D3DDisplay d3dDisplay = display.driverData;
1726
1727       if(d3dDisplay.backBuffer)
1728       {
1729          IDirect3DDevice9_SetDepthStencilSurface(d3dSystem.d3dDevice, d3dDisplay.depthSurface);
1730          IDirect3DDevice9_SetRenderTarget(d3dSystem.d3dDevice, 0, d3dDisplay.backBuffer);
1731          IDirect3DDevice9_BeginScene(d3dSystem.d3dDevice);
1732
1733          d3dSystem.inScene = true;
1734       }
1735       return true;
1736    }
1737
1738    void Unlock(Display display)
1739    {
1740       DisplaySystem displaySystem = display.displaySystem;
1741       D3DSystem d3dSystem = displaySystem.driverData;
1742
1743       if(d3dSystem.inScene)
1744       {
1745          IDirect3DDevice9_EndScene(d3dSystem.d3dDevice);
1746          d3dSystem.inScene = false;
1747       }
1748    }
1749 };
1750
1751 #endif