ecere/gfx/3D: Updates to Direct3D driver to not crash on bump maps / cube maps
[sdk] / ecere / src / gfx / drivers / Direct3D8DisplayDriver.ec
index 362db21..567e81e 100644 (file)
@@ -62,7 +62,7 @@ static class D3D8System : struct
    IDirect3D8 * (WINAPI * direct3DCreate8)(UINT);
    uint usage;
    D3DPRESENT_PARAMETERS d3dpp;
-   uint shaders[NUM_VERTEX_SHADERS], shader2D;
+   DWORD shaders[NUM_VERTEX_SHADERS], shader2D;
    bool ready;
    HWND hwnd;
    int format;
@@ -76,6 +76,7 @@ static class D3D8Surface : struct
    bool opaqueText;
    int xOffset;
    bool writingText;
+   bool writingOutline;
 
    ColorAlpha background;
 };
@@ -130,15 +131,14 @@ class Direct3D8DisplayDriver : DisplayDriver
    bool ::LockDisplay(Display display, Surface surface, Bitmap lfbBitmap, Surface * lfbSurface)
    {
       bool result = false;
-      DisplaySystem displaySystem = display.displaySystem;
-      D3D8System d3dSystem = displaySystem.driverData;
       D3D8Display d3dDisplay = display.driverData;
-      
+
       //if(!IDirect3DDevice8_GetBackBuffer(d3dSystem.d3dDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dDisplay.backBuffer))
       {
          D3DLOCKED_RECT lockedRect;
          if(!IDirect3DSurface8_LockRect(d3dDisplay.backBuffer, &lockedRect, null, 0))
          {
+            result = true;
             switch(d3dDisplay.d3dpp.BackBufferFormat)
             {
                case D3DFMT_A8R8G8B8:
@@ -156,19 +156,23 @@ class Direct3D8DisplayDriver : DisplayDriver
                case D3DFMT_X4R4G4B4:
                   lfbBitmap.pixelFormat = pixelFormat444;
                   break;
+               default:
+                  result = false;
+            }
+            if(result)
+            {
+               lfbBitmap.driver = null;
+               lfbBitmap.displaySystem = null;
+               lfbBitmap.picture = (byte *)lockedRect.pBits;
+               lfbBitmap.transparent = false;
+               lfbBitmap.stride = lockedRect.Pitch >> GetColorDepthShifts(lfbBitmap.pixelFormat);
+               lfbBitmap.width = display.width;
+               lfbBitmap.height = display.height;
+
+               *lfbSurface = lfbBitmap.GetSurface(surface ? surface.offset.x : 0, surface ? surface.offset.y : 0, surface ? &surface.box : null);
             }
-            lfbBitmap.driver = null;
-            lfbBitmap.displaySystem = null;
-            lfbBitmap.picture = (byte *)lockedRect.pBits;
-            lfbBitmap.transparent = false;
-            lfbBitmap.stride = lockedRect.Pitch >> GetColorDepthShifts(lfbBitmap.pixelFormat);
-            lfbBitmap.width = display.width;
-            lfbBitmap.height = display.height;
-            
-            *lfbSurface = lfbBitmap.GetSurface(surface ? surface.offset.x : 0, surface ? surface.offset.y : 0, surface ? &surface.box : null);
-            result = true;
          }
-         else
+         if(!result)
             IDirect3DSurface8_Release(d3dDisplay.backBuffer);
       }
       return result;
@@ -176,8 +180,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void ::UnlockDisplay(Display display, Surface surface)
    {
-      DisplaySystem displaySystem = display.displaySystem;
-      D3D8System d3dSystem = displaySystem.driverData;
       D3D8Display d3dDisplay = display.driverData;
       if(d3dDisplay.backBuffer)
       {
@@ -239,7 +241,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       {
          displaySystem.flags.alpha = true;
          //if(displaySystem.flags.fullScreen)
-            displaySystem.flags.flipping = true; 
+            displaySystem.flags.flipping = true;
          displaySystem.pixelFormat = pixelFormat888;
 
          d3dSystem.d3dDll = LoadLibrary("d3d8.dll");
@@ -248,7 +250,7 @@ class Direct3D8DisplayDriver : DisplayDriver
             d3dSystem.direct3DCreate8 = (void *)GetProcAddress(d3dSystem.d3dDll, "Direct3DCreate8");
             if(d3dSystem.direct3DCreate8)
             {
-               if(d3dSystem.direct3D = d3dSystem.direct3DCreate8(D3D_SDK_VERSION))
+               if((d3dSystem.direct3D = d3dSystem.direct3DCreate8(D3D_SDK_VERSION)))
                {
                   D3DDISPLAYMODE d3ddm;
                   if(!IDirect3D8_GetAdapterDisplayMode(d3dSystem.direct3D, D3DADAPTER_DEFAULT, &d3ddm))
@@ -263,7 +265,7 @@ class Direct3D8DisplayDriver : DisplayDriver
                      }
                      else
                      {
-                        d3dSystem.d3dpp.hDeviceWindow = d3dSystem.hwnd = 
+                        d3dSystem.d3dpp.hDeviceWindow = d3dSystem.hwnd =
                            CreateWindow("static", null, 0,0,0,0,0,null,null,null,null);
                         d3dSystem.d3dpp.Windowed = TRUE;
                      }
@@ -272,7 +274,7 @@ class Direct3D8DisplayDriver : DisplayDriver
                      d3dSystem.format = d3dSystem.d3dpp.BackBufferFormat = d3ddm.Format;
                      d3dSystem.d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
 
-                     if(!IDirect3D8_CreateDevice(d3dSystem.direct3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
+                     if(!IDirect3D8_CreateDevice(d3dSystem.direct3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
                         d3dSystem.d3dpp.hDeviceWindow,
                                D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE|D3DCREATE_FPU_PRESERVE,
                                &d3dSystem.d3dpp, &d3dSystem.d3dDevice))
@@ -280,7 +282,7 @@ class Direct3D8DisplayDriver : DisplayDriver
                      else
                      {
                         d3dSystem.usage = D3DUSAGE_SOFTWAREPROCESSING;
-                        if(!IDirect3D8_CreateDevice(d3dSystem.direct3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
+                        if(!IDirect3D8_CreateDevice(d3dSystem.direct3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
                               d3dSystem.d3dpp.hDeviceWindow,
                                   D3DCREATE_SOFTWARE_VERTEXPROCESSING|D3DCREATE_FPU_PRESERVE,
                                   &d3dSystem.d3dpp, &d3dSystem.d3dDevice))
@@ -292,26 +294,26 @@ class Direct3D8DisplayDriver : DisplayDriver
                         DWORD vertexShaders[NUM_VERTEX_SHADERS][7] =
                         {
                            {
-                               D3DVSD_STREAM(0),   
+                               D3DVSD_STREAM(0),
                                D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
                                D3DVSD_END()
                            },
                            {
-                               D3DVSD_STREAM(0),   
+                               D3DVSD_STREAM(0),
                                D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
                                D3DVSD_STREAM(1),
                                D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
                                D3DVSD_END()
                            },
                            {
-                               D3DVSD_STREAM(0),   
+                               D3DVSD_STREAM(0),
                                D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
                                D3DVSD_STREAM(2),
                                D3DVSD_REG(D3DVSDE_TEXCOORD0, D3DVSDT_FLOAT2),
                                D3DVSD_END()
                            },
                            {
-                               D3DVSD_STREAM(0),   
+                               D3DVSD_STREAM(0),
                                D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
                                D3DVSD_STREAM(1),
                                D3DVSD_REG(D3DVSDE_NORMAL, D3DVSDT_FLOAT3),
@@ -409,7 +411,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       bool result = false;
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Display d3dDisplay = display.driverData = D3D8Display { };
+      display.driverData = D3D8Display { };
 
       d3dSystem.ready = false;
 
@@ -475,19 +477,19 @@ class Direct3D8DisplayDriver : DisplayDriver
             //d3dDisplay.d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
             //d3dDisplay.d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
 
-            result = !IDirect3DDevice8_CreateAdditionalSwapChain(d3dSystem.d3dDevice, 
+            result = !IDirect3DDevice8_CreateAdditionalSwapChain(d3dSystem.d3dDevice,
                &d3dDisplay.d3dpp, &d3dDisplay.swapChain);
 
             if(!result)
             {
                d3dDisplay.d3dpp.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
-               result = !IDirect3DDevice8_CreateAdditionalSwapChain(d3dSystem.d3dDevice, 
+               result = !IDirect3DDevice8_CreateAdditionalSwapChain(d3dSystem.d3dDevice,
                   &d3dDisplay.d3dpp, &d3dDisplay.swapChain);
             }
             if(!result)
             {
                d3dDisplay.d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
-               result = !IDirect3DDevice8_CreateAdditionalSwapChain(d3dSystem.d3dDevice, 
+               result = !IDirect3DDevice8_CreateAdditionalSwapChain(d3dSystem.d3dDevice,
                   &d3dDisplay.d3dpp, &d3dDisplay.swapChain);
             }
          }
@@ -495,10 +497,10 @@ class Direct3D8DisplayDriver : DisplayDriver
          if(result)
          {
             if(d3dDisplay.swapChain)
-               result = !IDirect3DSwapChain8_GetBackBuffer(d3dDisplay.swapChain, 
+               result = !IDirect3DSwapChain8_GetBackBuffer(d3dDisplay.swapChain,
                   0, D3DBACKBUFFER_TYPE_MONO, &d3dDisplay.backBuffer);
             else
-               result = !IDirect3DDevice8_GetBackBuffer(d3dSystem.d3dDevice, 
+               result = !IDirect3DDevice8_GetBackBuffer(d3dSystem.d3dDevice,
                   0, D3DBACKBUFFER_TYPE_MONO, &d3dDisplay.backBuffer);
             if(result)
             {
@@ -507,7 +509,7 @@ class Direct3D8DisplayDriver : DisplayDriver
                   d3dSystem.ready = true;
             }
          }
-            
+
          if(d3dSystem.ready)
          {
             float fogDensity = 0;
@@ -522,7 +524,7 @@ class Direct3D8DisplayDriver : DisplayDriver
             IDirect3DDevice8_SetRenderState(d3dDevice, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
             IDirect3DDevice8_SetRenderState(d3dDevice, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
             IDirect3DDevice8_SetRenderState(d3dDevice, D3DRS_FOGTABLEMODE, D3DFOG_EXP);
-            IDirect3DDevice8_SetRenderState(d3dDevice, D3DRS_FOGDENSITY, *(uint *)(void *)&fogDensity);
+            IDirect3DDevice8_SetRenderState(d3dDevice, D3DRS_FOGDENSITY, RenderStateFloat { fogDensity }.ui);
             display.ambient = Color { 50,50,50 };
             IDirect3DDevice8_SetRenderState(d3dDevice, D3DRS_NORMALIZENORMALS, TRUE);
             IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_MULTISAMPLEANTIALIAS, FALSE);
@@ -590,7 +592,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       {
          //eSystem_Sleep(0.05);
          IDirect3DDevice8_EndScene(d3dSystem.d3dDevice);
-         
+
          if(display.displaySystem.flags.flipping)
          {
             if(d3dDisplay.swapChain)
@@ -662,8 +664,8 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
    {
-      if(bitmap.picture)
-         IDirect3DTexture8_Release((IDirect3DTexture8 *)bitmap.picture);
+      if(bitmap.driverData)
+         IDirect3DTexture8_Release((IDirect3DTexture8 *)bitmap.driverData);
    }
 
    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
@@ -671,16 +673,16 @@ class Direct3D8DisplayDriver : DisplayDriver
       return false;
    }
 
-   bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps)
+   bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps, int cubeMapFace)
    {
       bool result = false;
       D3D8System d3dSystem = displaySystem.driverData;
-      if(bitmap.Convert(null, pixelFormat888, null))
+      if(cubeMapFace && bitmap.Convert(null, pixelFormat888, null))
       {
          IDirect3DTexture8 * texture;
          uint w = pow2i(Min(bitmap.width, 512)), h = pow2i(Min(bitmap.height, 512));
 
-         if(!IDirect3DDevice8_CreateTexture(d3dSystem.d3dDevice, w, h, mipMaps ? log2i(Max(w+1, h+1)) : 1, 0, 
+         if(!IDirect3DDevice8_CreateTexture(d3dSystem.d3dDevice, w, h, mipMaps ? log2i(Max(w+1, h+1)) : 1, 0,
                D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture))
          {
             int level;
@@ -706,34 +708,39 @@ class Direct3D8DisplayDriver : DisplayDriver
                      case D3DFMT_R5G6B5:   mipMap.pixelFormat = pixelFormat565; break;
                      case D3DFMT_A8R8G8B8: mipMap.pixelFormat = pixelFormat888; break;
                      case D3DFMT_A1R5G5B5: mipMap.pixelFormat = pixelFormat555; break;
+                     default:
+                        result = false;
                   }
-                  mipMap.stride = lockedRect.Pitch >> GetColorDepthShifts(mipMap.pixelFormat);
-               
-                  mipSurface = mipMap.GetSurface(0,0,null);
-                  if(mipSurface)
+                  if(result)
                   {
-                     if(mipMap.width != bitmap.width || mipMap.height != bitmap.height)
-                        mipSurface.Filter(bitmap, 0,0, 0,0, mipMap.width, mipMap.height, bitmap.width, bitmap.height);
-                     else
+                     mipMap.stride = lockedRect.Pitch >> GetColorDepthShifts(mipMap.pixelFormat);
+
+                     mipSurface = mipMap.GetSurface(0,0,null);
+                     if(mipSurface)
                      {
-                        //FillBytesBy4(mipMap.picture, bitmap.picture, mipMap.width * mipMap.height);
-                        mipSurface.Blit(bitmap, 0,0, 0,0, bitmap.width, bitmap.height);
-                     }
+                        if(mipMap.width != bitmap.width || mipMap.height != bitmap.height)
+                           mipSurface.Filter(bitmap, 0,0, 0,0, mipMap.width, mipMap.height, bitmap.width, bitmap.height);
+                        else
+                        {
+                           //FillBytesBy4(mipMap.picture, bitmap.picture, mipMap.width * mipMap.height);
+                           mipSurface.Blit(bitmap, 0,0, 0,0, bitmap.width, bitmap.height);
+                        }
 
-                     delete mipSurface;
+                        delete mipSurface;
+                     }
                   }
 
                   mipMap.picture = null;
                   delete mipMap;
 
-                  IDirect3DTexture8_UnlockRect(texture, level);            
+                  IDirect3DTexture8_UnlockRect(texture, level);
                }
                if(!mipMaps) break;
             }
 
             bitmap.driver.FreeBitmap(bitmap.displaySystem, bitmap);
             bitmap.driver = displaySystem.driver;
-            bitmap.picture = (void *)texture;
+            bitmap.driverData = (void *)texture;
 
             if(!result)
                FreeBitmap(displaySystem, bitmap);
@@ -781,7 +788,6 @@ class Direct3D8DisplayDriver : DisplayDriver
    void Clip(Display display, Surface surface, Box clip)
    {
       Box box;
-      D3D8Display d3dDisplay = display.driverData;
 
       if(clip != null)
       {
@@ -802,7 +808,7 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void SetBackground(Display display, Surface surface, ColorAlpha color)
    {
-      D3D8Surface d3dSurface = surface.driverData;  
+      D3D8Surface d3dSurface = surface.driverData;
       d3dSurface.background = color;
    }
 
@@ -813,8 +819,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void PutPixel(Display display, Surface surface,int x,int y)
    {
-      D3D8Display d3dDisplay = display.driverData;
-      D3D8Surface d3dSurface = surface.driverData;
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
       D3D8Vertex vertex = { (float)x, (float)y, 1.0f, surface.foreground, 0, 0 };
@@ -825,8 +829,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
    {
-      D3D8Surface d3dSurface = surface.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
       D3D8Vertex vertex[2] =
@@ -846,8 +848,6 @@ class Direct3D8DisplayDriver : DisplayDriver
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Surface d3dSurface = surface.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       D3D8Vertex vertex[5] =
       {
          { (float)x1, (float)y1, 1.0f, surface.foreground, 0, 0 },
@@ -857,7 +857,7 @@ class Direct3D8DisplayDriver : DisplayDriver
          { (float)x1, (float)y1, 1.0f, surface.foreground, 0, 0 }
       };
 
-      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_LINESTRIP, 4, 
+      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_LINESTRIP, 4,
          vertex, sizeof(D3D8Vertex));
 
    }
@@ -867,7 +867,6 @@ class Direct3D8DisplayDriver : DisplayDriver
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
       D3D8Surface d3dSurface = surface.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       D3D8Vertex vertex[4] =
       {
          { (float)x1, (float)y1, 1.0f, d3dSurface.background, 0, 0 },
@@ -876,7 +875,7 @@ class Direct3D8DisplayDriver : DisplayDriver
          { (float)x2 + 1.0f, (float)y2 + 1.0f, 1.0f, d3dSurface.background, 0, 0 }
       };
 
-      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2, 
+      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
          vertex, sizeof(D3D8Vertex));
 
    }
@@ -886,10 +885,9 @@ class Direct3D8DisplayDriver : DisplayDriver
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
       D3D8Surface d3dSurface = surface.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       IDirect3DDevice8_Clear(d3dSystem.d3dDevice, 0, null,
          ((type == depthBuffer) ? 0 : D3DCLEAR_TARGET) |
-         ((type == colorBuffer) ? 0 : D3DCLEAR_ZBUFFER), 
+         ((type == colorBuffer) ? 0 : D3DCLEAR_ZBUFFER),
          d3dSurface.background, 1,0);
    }
 
@@ -903,22 +901,21 @@ class Direct3D8DisplayDriver : DisplayDriver
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
       D3D8Surface d3dSurface = surface.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       Color foreground = d3dSurface.writingText ? surface.foreground : white;
       D3D8Vertex vertex[4] =
       {
-         { (float)dx, (float)dy, 1.0f, foreground, 
+         { (float)dx, (float)dy, 1.0f, foreground,
             (float)sx / (src.width-1), (float)sy/ (src.height-1) },
-         { (float)(dx+w), (float)dy, 1.0f, foreground, 
+         { (float)(dx+w), (float)dy, 1.0f, foreground,
             (float)(sx+w)/ (src.width-1), (float)sy/ (src.height-1) },
-         { (float)dx, (float)(dy+h), 1.0f, foreground, 
+         { (float)dx, (float)(dy+h), 1.0f, foreground,
             (float)sx/ (src.width-1), (float)(sy+h)/ (src.height-1) },
-         { (float)(dx+w), (float)(dy+h), 1.0f, foreground, 
+         { (float)(dx+w), (float)(dy+h), 1.0f, foreground,
             (float)(sx+w) / (src.width-1), (float)(sy+h)/ (src.height-1) }
       };
 
-      IDirect3DDevice8_SetTexture(d3dSystem.d3dDevice, 0, (IDirect3DBaseTexture8 *)src.picture);
-      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2, 
+      IDirect3DDevice8_SetTexture(d3dSystem.d3dDevice, 0, (IDirect3DBaseTexture8 *)src.driverData);
+      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
          vertex, sizeof(D3D8Vertex));
       IDirect3DDevice8_SetTexture(d3dSystem.d3dDevice, 0, null);
    }
@@ -927,22 +924,20 @@ class Direct3D8DisplayDriver : DisplayDriver
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Surface d3dSurface = surface.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       D3D8Vertex vertex[4] =
       {
-         { (float)dx, (float)dy, 1.0f, surface.foreground, 
+         { (float)dx, (float)dy, 1.0f, surface.foreground,
             (float)sx / (src.width-1), (float)sy/ (src.height-1) },
-         { (float)(dx+w), (float)dy, 1.0f, surface.foreground, 
+         { (float)(dx+w), (float)dy, 1.0f, surface.foreground,
             (float)(sx+sw)/ (src.width-1), (float)sy/ (src.height-1) },
-         { (float)dx, (float)(dy+h), 1.0f, surface.foreground, 
+         { (float)dx, (float)(dy+h), 1.0f, surface.foreground,
             (float)sx/ (src.width-1), (float)(sy+sh)/ (src.height-1) },
-         { (float)(dx+w), (float)(dy+h), 1.0f, surface.foreground, 
+         { (float)(dx+w), (float)(dy+h), 1.0f, surface.foreground,
             (float)(sx+sw) / (src.width-1), (float)(sy+sh)/ (src.height-1) }
       };
 
-      IDirect3DDevice8_SetTexture(d3dSystem.d3dDevice, 0, (IDirect3DBaseTexture8 *)src.picture);
-      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2, 
+      IDirect3DDevice8_SetTexture(d3dSystem.d3dDevice, 0, (IDirect3DBaseTexture8 *)src.driverData);
+      IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
          vertex, sizeof(D3D8Vertex));
       IDirect3DDevice8_SetTexture(d3dSystem.d3dDevice, 0, null);
    }
@@ -954,8 +949,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
    {
-      DisplaySystem displaySystem = display.displaySystem;
-      D3D8System d3dSystem = displaySystem.driverData;
       Surface lfbSurface;
       Bitmap lfbBitmap { };
       if(LockDisplay(display, surface, lfbBitmap, &lfbSurface))
@@ -969,8 +962,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
    {
-      DisplaySystem displaySystem = display.displaySystem;
-      D3D8System d3dSystem = displaySystem.driverData;
       Surface lfbSurface;
       Bitmap lfbBitmap { };
       if(LockDisplay(display, surface, lfbBitmap, &lfbSurface))
@@ -992,9 +983,9 @@ class Direct3D8DisplayDriver : DisplayDriver
       ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
    }
 
-   Font LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags)
+   Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade)
    {
-      return ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags);
+      return ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags, outlineSize, outlineFade);
    }
 
    void TextFont(Display display, Surface surface, Font font)
@@ -1008,22 +999,22 @@ class Direct3D8DisplayDriver : DisplayDriver
       d3dSurface.opaqueText = opaque;
    }
 
-   void FontExtent(DisplaySystem displaySystem, Font font, byte * text, int len, int * width, int * height)
+   void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
-   void WriteText(Display display, Surface surface, int x, int y, byte * text, int len)
+   void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       D3D8Surface d3dSurface = surface.driverData;
 
       if(surface.textOpacity)
       {
-         int w, h;
-         FontExtent(display.displaySystem, surface.font, text, len, &w, &h);
+         int w, h, adv;
+         FontExtent(display.displaySystem, surface.font, text, len, &w, &h, prevGlyph, rPrevGlyph, &adv);
+         w += adv;
 
          {
             int x1 = x, y1 = y, x2 = x+w-1, y2 = y+h-1;
@@ -1035,7 +1026,7 @@ class Direct3D8DisplayDriver : DisplayDriver
                { (float)x2 + 1.0f, (float)y2 /*+ 1.5f*/, 1.0f, d3dSurface.background, 0, 0 }
             };
 
-            IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2, 
+            IDirect3DDevice8_DrawPrimitiveUP(d3dSystem.d3dDevice, D3DPT_TRIANGLESTRIP, 2,
                vertex, sizeof(D3D8Vertex));
          }
          //display.displaySystem.driver.Area(display, surface, x, y, x+w-1, y+h-1);
@@ -1045,7 +1036,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       IDirect3DDevice8_SetTextureStageState(d3dSystem.d3dDevice, 0, D3DTSS_MIPFILTER, D3DTEXF_NONE);
       d3dSurface.writingText = true;
 
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
 
       d3dSurface.writingText = false;
       IDirect3DDevice8_SetTextureStageState(d3dSystem.d3dDevice, 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR);
@@ -1053,9 +1044,9 @@ class Direct3D8DisplayDriver : DisplayDriver
       IDirect3DDevice8_SetTextureStageState(d3dSystem.d3dDevice, 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); //NONE);
    }
 
-   void TextExtent(Display display, Surface surface, byte * text, int len, int * width, int * height)
+   void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
    {
-      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height);
+      ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, width, height, prevGlyph, rPrevGlyph, adv);
    }
 
    void DrawingChar(Display display, Surface surface, byte character)
@@ -1065,9 +1056,9 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void LineStipple(Display display, Surface surface, uint stipple)
    {
-      D3D8Display d3dDisplay = display.driverData;
       /*
-      IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_LINEPATTERN, 
+      D3D8Display d3dDisplay = display.driverData;
+      IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_LINEPATTERN,
          stipple?MDWORD(1,stipple):0);
       */
    }
@@ -1076,14 +1067,13 @@ class Direct3D8DisplayDriver : DisplayDriver
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       switch(state)
       {
          case antiAlias:
             IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_MULTISAMPLEANTIALIAS, value ? TRUE : FALSE);
             break;
          case fillMode:
-            IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_FILLMODE, 
+            IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_FILLMODE,
                ((FillModeValue)value == solid) ? D3DFILL_SOLID : D3DFILL_WIREFRAME);
             break;
          case depthTest:
@@ -1098,8 +1088,8 @@ class Direct3D8DisplayDriver : DisplayDriver
             break;
          case fogDensity:
          {
-            float fogDensity = *(float *)(void *)&value;
-            IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_FOGDENSITY, *(uint *)(void *)&fogDensity);
+            float fogDensity = RenderStateFloat { ui = value }.f;
+            IDirect3DDevice8_SetRenderState(d3dSystem.d3dDevice, D3DRS_FOGDENSITY, RenderStateFloat { fogDensity }.ui);
             break;
          }
          case blend:
@@ -1118,18 +1108,20 @@ class Direct3D8DisplayDriver : DisplayDriver
       D3D8Display d3dDisplay = display.driverData;
       if(light != null)
       {
-         D3DLIGHT8 d3dLight = 
+         D3DLIGHT8 d3dLight =
          {
-            D3DLIGHT_DIRECTIONAL, 
+            D3DLIGHT_DIRECTIONAL,
             // Opacity on the light?
             { light.diffuse.r, light.diffuse.g, light.diffuse.b,    1.0f },
             { light.specular.r, light.specular.g, light.specular.b, 1.0f },
-            { light.ambient.r, light.ambient.g, light.ambient.b,    1.0f },
+            { light.ambient.r, light.ambient.g, light.ambient.b,    1.0f }
          };
+         Vector3Df * lightDirection;
          Vector3Df vector {0,0,1};
          Vector3Df vectorPI {0,0,-1};
          Vector3Df direction;
          Matrix mat;
+         lightDirection = (Vector3Df *)&d3dLight.Direction;
 
          mat.RotationQuaternion(light.orientation);
 
@@ -1141,17 +1133,15 @@ class Direct3D8DisplayDriver : DisplayDriver
             d3dLight.Direction.z =-direction.z;
          }
          else
-         {
-            ((Vector3Df *)&d3dLight.Direction)->MultMatrix(direction, d3dDisplay.worldMatrix);
-         }
+            lightDirection->MultMatrix(direction, d3dDisplay.worldMatrix);
 
          d3dDisplay.lights[id] = d3dLight;
-         
+
          IDirect3DDevice8_LightEnable(d3dSystem.d3dDevice, id, TRUE);
          IDirect3DDevice8_SetLight(d3dSystem.d3dDevice, id, &d3dDisplay.lights[id]);
 
          direction.MultMatrix(vectorPI, mat);
-         ((Vector3Df *)&d3dLight.Direction)->MultMatrix(direction, d3dDisplay.worldMatrix);
+         lightDirection->MultMatrix(direction, d3dDisplay.worldMatrix);
 
          d3dDisplay.lightsPI[id] = d3dLight;
       }
@@ -1255,7 +1245,6 @@ class Direct3D8DisplayDriver : DisplayDriver
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       IDirect3DDevice8 * d3dDevice = d3dSystem.d3dDevice;
       D3D8Mesh d3dMesh = mesh.data;
 
@@ -1267,7 +1256,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       {
          Bitmap map = material.baseMap;
 
-         IDirect3DDevice8_SetTexture(d3dDevice, 0, (IDirect3DBaseTexture8 *)map.picture);
+         IDirect3DDevice8_SetTexture(d3dDevice, 0, (IDirect3DBaseTexture8 *)map.driverData);
 
          if(material.flags.tile)
          {
@@ -1317,7 +1306,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void FreeMesh(DisplaySystem displaySystem, Mesh mesh)
    {
-      D3D8System d3dSystem = displaySystem.driverData;
       D3D8Mesh d3dMesh = mesh.data;
       if(d3dMesh)
       {
@@ -1365,38 +1353,88 @@ class Direct3D8DisplayDriver : DisplayDriver
       }
    }
 
-   bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh)
+   bool AllocateMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags, int nVertices)
    {
       D3D8System d3dSystem = displaySystem.driverData;
       bool result = false;
       IDirect3DDevice8 * d3dDevice = d3dSystem.d3dDevice;
-      
+
       if(!mesh.data)
          mesh.data = D3D8Mesh { };
       if(mesh.data)
       {
          D3D8Mesh d3dMesh = mesh.data;
          result = true;
-         if((mesh.flags .vertices) && !d3dMesh.vertices)
+         if(mesh.nVertices == nVertices)
          {
-            mesh.vertices = new Vector3Df[mesh.nVertices];
-            if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * mesh.nVertices, 
-               d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.vertices))
-               result = false;
-         }
-         if((mesh.flags.normals) && !d3dMesh.normals)
-         {
-            mesh.normals = new Vector3Df[mesh.nVertices];
-            if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * mesh.nVertices, 
-               d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.normals))
-               result = false;
+            if(mesh.flags != flags)
+            {
+               // Same number of vertices, adding features (Leaves the other features pointers alone)
+               if(flags.vertices && !d3dMesh.vertices)
+               {
+                  mesh.vertices = new Vector3Df[nVertices];
+                  if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
+                     d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.vertices))
+                     result = false;
+               }
+               if(flags.normals && !d3dMesh.normals)
+               {
+                  mesh.normals = new Vector3Df[nVertices];
+                  if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
+                     d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.normals))
+                     result = false;
+               }
+               if(flags.texCoords1 && !d3dMesh.texCoords)
+               {
+                  mesh.texCoords = new Pointf[nVertices];
+                  if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Pointf) * nVertices,
+                     d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.texCoords))
+                     result = false;
+               }
+            }
          }
-         if((mesh.flags.texCoords1) && !d3dMesh.texCoords)
+         else
          {
-            mesh.texCoords = new Pointf[mesh.nVertices];
-            if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Pointf) * mesh.nVertices, 
-               d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.texCoords))
-               result = false;
+            // New number of vertices, reallocate all current and new features
+            flags |= mesh.flags;
+
+            // Same number of vertices, adding features (Leaves the other features pointers alone)
+            if(flags.vertices)
+            {
+               if(d3dMesh.vertices)
+               {
+                  IDirect3DVertexBuffer8_Release(d3dMesh.vertices);
+                  d3dMesh.vertices = null;
+               }
+               mesh.vertices = renew mesh.vertices Vector3Df[nVertices];
+               if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
+                  d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.vertices))
+                  result = false;
+            }
+            if(flags.normals)
+            {
+               if(d3dMesh.normals)
+               {
+                  IDirect3DVertexBuffer8_Release(d3dMesh.normals);
+                  d3dMesh.normals = null;
+               }
+               mesh.normals = renew mesh.normals Vector3Df[nVertices];
+               if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Vector3Df) * nVertices,
+                  d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.normals))
+                  result = false;
+            }
+            if(flags.texCoords1)
+            {
+               if(d3dMesh.texCoords)
+               {
+                  IDirect3DVertexBuffer8_Release(d3dMesh.texCoords);
+                  d3dMesh.texCoords = null;
+               }
+               mesh.texCoords = renew mesh.texCoords Pointf[nVertices];
+               if(IDirect3DDevice8_CreateVertexBuffer(d3dDevice, sizeof(Pointf) * nVertices,
+                  d3dSystem.usage, 0, D3DPOOL_MANAGED, &d3dMesh.texCoords))
+                  result = false;
+            }
          }
       }
       return result;
@@ -1404,7 +1442,6 @@ class Direct3D8DisplayDriver : DisplayDriver
 
    void UnlockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags)
    {
-      D3D8System d3dSystem = displaySystem.driverData;
       D3D8Mesh d3dMesh = mesh.data;
       if(!flags) flags = mesh.flags;
 
@@ -1424,7 +1461,7 @@ class Direct3D8DisplayDriver : DisplayDriver
          {
             memcpy(normals, mesh.normals, mesh.nVertices * sizeof(Vector3Df));
             IDirect3DVertexBuffer8_Unlock(d3dMesh.normals);
-         }      
+         }
       }
       if(flags.texCoords1 && mesh.texCoords)
       {
@@ -1433,7 +1470,7 @@ class Direct3D8DisplayDriver : DisplayDriver
          {
             memcpy(texCoords, mesh.texCoords, mesh.nVertices * sizeof(Pointf));
             IDirect3DVertexBuffer8_Unlock(d3dMesh.texCoords);
-         }      
+         }
       }
    }
 
@@ -1462,7 +1499,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       if(d3dIndices && nIndices)
       {
          d3dIndices.indices = (void *)(indices32bit ? new uint32[nIndices] : new uint16[nIndices]);
-         IDirect3DDevice8_CreateIndexBuffer(d3dDevice, (indices32bit ? sizeof(uint32) : sizeof(uint16)) * nIndices, 0, indices32bit ? D3DFMT_INDEX32 : D3DFMT_INDEX16, 
+         IDirect3DDevice8_CreateIndexBuffer(d3dDevice, (indices32bit ? sizeof(uint32) : sizeof(uint16)) * nIndices, 0, indices32bit ? D3DFMT_INDEX32 : D3DFMT_INDEX16,
             D3DPOOL_MANAGED, &d3dIndices.buffer);
          d3dIndices.nIndices = nIndices;
       }
@@ -1488,7 +1525,6 @@ class Direct3D8DisplayDriver : DisplayDriver
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Display d3dDisplay = display.driverData;
       IDirect3DDevice8 * d3dDevice = d3dSystem.d3dDevice;
 
       if(mesh && mesh.data)
@@ -1496,23 +1532,23 @@ class Direct3D8DisplayDriver : DisplayDriver
          int shader = 0;
          D3D8Mesh d3dMesh = mesh.data;
 
-         IDirect3DDevice8_SetStreamSource(d3dSystem.d3dDevice, 0, d3dMesh.vertices, sizeof(Vector3Df));
+         IDirect3DDevice8_SetStreamSource(d3dDevice, 0, d3dMesh.vertices, sizeof(Vector3Df));
          if(d3dMesh.normals)
          {
-            IDirect3DDevice8_SetStreamSource(d3dSystem.d3dDevice, 1, d3dMesh.normals, sizeof(Vector3Df));
+            IDirect3DDevice8_SetStreamSource(d3dDevice, 1, d3dMesh.normals, sizeof(Vector3Df));
             shader |= 1;
          }
          else
-            IDirect3DDevice8_SetStreamSource(d3dSystem.d3dDevice, 1, null, sizeof(Vector3Df));
+            IDirect3DDevice8_SetStreamSource(d3dDevice, 1, null, sizeof(Vector3Df));
          if(d3dMesh.texCoords)
          {
-            IDirect3DDevice8_SetStreamSource(d3dSystem.d3dDevice, 2, d3dMesh.texCoords, sizeof(Pointf));
+            IDirect3DDevice8_SetStreamSource(d3dDevice, 2, d3dMesh.texCoords, sizeof(Pointf));
             shader |= 2;
          }
          else
-            IDirect3DDevice8_SetStreamSource(d3dSystem.d3dDevice, 2, null, sizeof(Pointf));
+            IDirect3DDevice8_SetStreamSource(d3dDevice, 2, null, sizeof(Pointf));
 
-         IDirect3DDevice8_SetVertexShader(d3dSystem.d3dDevice, d3dSystem.shaders[shader]);
+         IDirect3DDevice8_SetVertexShader(d3dDevice, d3dSystem.shaders[shader]);
       }
    }
 
@@ -1531,12 +1567,12 @@ class Direct3D8DisplayDriver : DisplayDriver
          {
             case lines:     numPrimitives /= 2; break;
             case triangles: numPrimitives /= 3; break;
-            case triStrip: 
+            case triStrip:
             case triFan:
-               numPrimitives -= 2; 
+               numPrimitives -= 2;
                break;
             case lineStrip:
-               numPrimitives --; 
+               numPrimitives --;
                break;
             case quads:
                numPrimitives /= 4;
@@ -1620,7 +1656,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       D3D8Display d3dDisplay = display.driverData;
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      
+
       d3dDisplay.worldMatrix--;
       if(setMatrix)
          SetTransformMatrix(d3dSystem.d3dDevice, d3dDisplay.worldMatrix);
@@ -1632,7 +1668,6 @@ class Direct3D8DisplayDriver : DisplayDriver
       D3D8System d3dSystem = displaySystem.driverData;
       Camera camera = useCamera ? display.display3D.camera : null;
       D3D8Display d3dDisplay = display.driverData;
-      IDirect3DDevice8 * d3dDevice = d3dSystem.d3dDevice;
 
       Matrix matrix = transMatrix, temp;
 
@@ -1644,7 +1679,7 @@ class Direct3D8DisplayDriver : DisplayDriver
       else
       {
          if(camera)
-            matrix.Translate( 
+            matrix.Translate(
                - camera.cPosition.x,
                - camera.cPosition.y,
                - camera.cPosition.z);
@@ -1675,7 +1710,6 @@ class Direct3D8DisplayDriver : DisplayDriver
    {
       DisplaySystem displaySystem = display.displaySystem;
       D3D8System d3dSystem = displaySystem.driverData;
-      D3D8Display d3dDisplay = display.driverData;
 
       if(d3dSystem.inScene)
       {