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