ecere/gfx/3D/Object: computeLightVector flag to avoid always recomputing uselessly
[sdk] / ecere / src / gfx / Display.ec
index 4d296e2..217a181 100644 (file)
@@ -33,23 +33,38 @@ import "Vector3D"
 
 #if (!defined(ECERE_VANILLA) && !defined(ECERE_ONEDRIVER))
 import "OpenGLDisplayDriver"
+
+#define near _near
+#define far _far
+#include "gl123es.h"
+#undef near
+#undef far
 #endif
 
 public class GLCapabilities : uint
 {
 public:
-   bool legacy          :1;
-   bool shaders         :1;
-   bool nonPow2Textures :1;
+   // Expect reloading graphics
+   bool compatible      :1;
    bool vertexBuffer    :1;
-   bool frameBuffer     :1;
-
-   // To be able to disable these at runtime independently...
-   bool immediate       :1;
-   bool fixedFunction   :1;
    bool quads           :1;
    bool intAndDouble    :1;
+   bool legacyFormats   :1;
+   bool nonPow2Textures :1;
+   bool vertexPointer   :1;
+
+   // Should be able to toggle without reloading
+   bool legacy          :1;
+   bool shaders         :1;
+   bool fixedFunction   :1;
+   bool immediate       :1;
+   bool frameBuffer     :1;
+   bool pointSize       :1;
+   bool vao             :1;
+   bool select          :1;
    // bool mapBuffer       :1;
+
+   bool debug           :1;
 };
 
 public enum RenderState { fillMode = 1, depthTest, depthWrite, fogDensity, fogColor, blend, ambient, alphaWrite, antiAlias, vSync };
@@ -69,7 +84,9 @@ public class FontFlags
 
 __attribute__((unused)) static void DummyFunction()
 {
+#if !defined(__EMSCRIPTEN__)
    Mutex { };
+#endif
 }
 
 public class DisplayDriver
@@ -145,7 +162,7 @@ public:
    virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
 
    // Converts an LFB bitmap into an offscreen bitmap for this device
-   virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool);
+   virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool mipMaps, int cubeMapFace);
 
    // Font loading
    virtual Font ::LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags, float outlineSize, float outlineFade);
@@ -200,27 +217,6 @@ public:
 public enum Alignment { left, right, center };
 public enum ClearType { colorBuffer, depthBuffer, colorAndDepth };
 
-subclass(DisplayDriver) GetDisplayDriver(const char * driverName)
-{
-   if(driverName)
-   {
-      OldLink link;
-      for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
-      {
-         subclass(DisplayDriver) displayDriver = link.data;
-         if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
-            return displayDriver;
-      }
-   }
-   return null;
-}
-
-DisplaySystem GetDisplaySystem(const char * driverName)
-{
-   subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
-   return displayDriver ? displayDriver.displaySystem : null;
-}
-
 define textCellW = 8;
 define textCellH = 16;
 
@@ -261,7 +257,7 @@ public struct Light
    float multiplier;
 };
 
-define NumberOfLights = 8;
+public define NumberOfLights = 8;
 
 // Painter's algorithm
 
@@ -527,7 +523,7 @@ public:
 
    void FontExtent(Font font, const char * text, int len, int * width, int * height)
    {
-      int overHang;
+      int overHang = 0;
       FontExtent2(font, text, len, width, height, 0, null, &overHang);
       if(width) *width += overHang;
    }
@@ -577,7 +573,9 @@ public:
       result = displaySystem && displaySystem.Lock();
       if(result && render)
       {
+#if !defined(__EMSCRIPTEN__)
          mutex.Wait();
+#endif
 
          if(!current)
             result = displaySystem.driver.Lock(this);
@@ -603,7 +601,9 @@ public:
          */
          if(!current && displaySystem)
             displaySystem.driver.Unlock(this);
+#if !defined(__EMSCRIPTEN__)
          mutex.Release();
+#endif
       }
       if(displaySystem)
          displaySystem.Unlock();
@@ -717,6 +717,10 @@ public:
    // --- Lights ---
    void SetLight(int id, Light light)
    {
+      if(!display3D)
+      {
+         display3D = Display3D { };
+      }
       displaySystem.driver.SetLight(this, id, light);
    }
 
@@ -942,6 +946,136 @@ public:
                if(!display3D.selection && displaySystem.driver.PushMatrix)
                   displaySystem.driver.PushMatrix(this);
 
+#if ENABLE_GL_FFP
+               if(object.mesh.tangents && object.mesh.normals && object.flags.computeLightVectors)
+               {
+                  Mesh mesh = object.mesh;
+                  if(!glCaps_shaders)
+                  {
+                     int count = mesh.nVertices;
+                     Vector3Df * normals = mesh.normals;
+                     Vector3Df * vertices = mesh.vertices;
+                     ColorRGB * lightVectors;
+                     Vector3Df * tangents = mesh.tangents;
+                     int i;
+                     float * l = display3D.light0Pos;
+                     Vector3Df light { l[0], l[1], l[2] };
+                     Matrix o = object.matrix;
+                     Matrix t, inv = camera.viewMatrix;
+                     Vector3D ot { };
+                     Vector3D cPos = camera.cPosition;
+                     Vector3D pos;
+                     bool positional = l[3] ? true : false;
+
+                     inv.Scale(1.0/nearPlane, -1.0/nearPlane,-1.0/nearPlane);
+
+                     pos.MultMatrix(cPos, camera.viewMatrix);
+
+                     ot.x = o.m[3][0] + pos.x;
+                     ot.y = o.m[3][1] + pos.y;
+                     ot.z = o.m[3][2] + pos.z;
+                     o.m[3][0] = 0;
+                     o.m[3][1] = 0;
+                     o.m[3][2] = 0;
+                     t.Multiply(o, inv);
+                     inv = t;
+                     t.Transpose(inv);
+                     inv.Inverse(t);
+
+                     mesh.Allocate({ lightVectors = true }, mesh.nVertices, displaySystem);
+                     mesh.Lock({ lightVectors = true });
+                     lightVectors = mesh.lightVectors;
+                     for(i = 0; i < count; i++)
+                     {
+                        Vector3Df tangent1 = tangents[i*2 + 0];
+                        Vector3Df tangent2 = tangents[i*2 + 1];
+                        Vector3Df normal = normals[i];
+                        Vector3Df tTangent1, tTangent2, tNormal;
+
+                        tTangent1.MultMatrix(tangent1, inv);
+                        tTangent2.MultMatrix(tangent2, inv);
+                        tNormal  .MultMatrix(normal,   inv);
+
+                        tTangent1.Normalize(tTangent1);
+                        tTangent2.Normalize(tTangent2);
+                        tNormal  .Normalize(tNormal);
+
+                        {
+                           Matrix tbn
+                           { {
+                               tTangent1.x, tTangent2.x, tNormal.x, 0,
+                               tTangent1.y, tTangent2.y, tNormal.y, 0,
+                               tTangent1.z, tTangent2.z, tNormal.z, 1
+                           } };
+                           Vector3Df n;
+                           if(positional)
+                           {
+                              Vector3Df tPos = vertices[i];
+                              tPos.x += ot.x, tPos.y += ot.y, tPos.z += ot.z;
+
+                              // Subtract vertex from light for positional lights
+                              light.x = l[0] - tPos.x;
+                              light.y = l[1] + tPos.y;
+                              light.z = l[2] - tPos.z;
+                           }
+                           n.MultMatrix(light, tbn);
+                           if(positional)
+                              n.Normalize(n);
+                           lightVectors[i] = { n.x / 2 + 0.5f, n.y / 2 + 0.5f, n.z / 2 + 0.5f };
+                        }
+                     }
+                     mesh.Unlock({ lightVectors = true });
+
+                     // Create normalization cube map
+                     /*
+                     if(!mesh.normMap)
+                        mesh.normMap = { };
+                     {
+                        int w = 256, h = 256, d = 256;
+                        Vector3Df min = mesh.min, max = mesh.max;
+                        Vector3Df delta
+                        {
+                           (max.x - min.x) / w,
+                           (max.y - min.y) / h,
+                           (max.z - min.z) / d
+                        };
+                        int i;
+                        for(i = 0; i < 6; i++)
+                        {
+                           Bitmap face = i > 0 ? { } : mesh.normMap;
+                           int x, y;
+                           ColorAlpha * p;
+                           face.Free();
+                           face.Allocate(null, w, h, 0, pixelFormat888, false);
+                           face.driverData = mesh.normMap.driverData;
+                           p = (ColorAlpha *)face.picture;
+                           for(y = 0; y < h; y++)
+                           {
+                              for(x = 0; x < w; x++, p++)
+                              {
+                                 Vector3Df v { min.x + x * delta.x, min.y + y * delta.y, min.z };
+                                 v.Normalize(v);
+                                 *p = ColorAlpha { 255, {
+                                       (byte)((v.x / 2.0 + 0.5) * 255),
+                                       (byte)((v.y / 2.0 + 0.5) * 255),
+                                       (byte)((v.z / 2.0 + 0.5) * 255) } };
+                             }
+                           }
+                           displaySystem.driver.MakeDDBitmap(displaySystem, face, true, (i + 1));
+                           if(i > 0)
+                           {
+                              face.driverData = 0;
+                              delete face;
+                           }
+                        }
+                     }
+                     */
+                  }
+                  else
+                     mesh.Free({ lightVectors = true });
+               }
+#endif
+
                SetTransform(object.matrix, object.flags.viewSpace);
                if(display3D.selection)
                {
@@ -1154,16 +1288,24 @@ public:
       set
       {
          glCapabilities = value;
-         if(driverData)
+         if(driverData && displaySystem.driver == class(OpenGLDisplayDriver))
          {
             OGLDisplay oglDisplay = driverData;
             if(!oglDisplay.originalCapabilities.fixedFunction)
                value.shaders = true;
             if(!oglDisplay.originalCapabilities.shaders)
                value.fixedFunction = true;
+            // Disable things that don't work with shaders
+            if(value.shaders)
+            {
+               value.fixedFunction = false;
+               value.legacy = false;
+               value.immediate = false;
+            }
             oglDisplay.capabilities = oglDisplay.originalCapabilities & value;
+
             Lock(true);
-            OpenGLDisplayDriver::initialDisplaySetup(this);
+            OpenGLDisplayDriver::initialDisplaySetup(this, true, false);
             Unlock();
          }
       }
@@ -1178,7 +1320,9 @@ private:
    DisplaySystem displaySystem;
    void * window;
 
+#if !defined(__EMSCRIPTEN__)
    Mutex mutex { };
+#endif
    int current;
 
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
@@ -1216,6 +1360,7 @@ private class Display3D : struct
 
    Line rayView, rayWorld, rayLocal;
    Vector3D rayIntersect;
+   float light0Pos[4];
 
    ~Display3D()
    {
@@ -1961,3 +2106,25 @@ public int BestColorMatch(ColorAlpha * palette, int start, int end, Color rgb)
    }
    return best;
 }
+
+// had to move this here due to compiler ordering issue for "get property" symbol
+subclass(DisplayDriver) GetDisplayDriver(const char * driverName)
+{
+   if(driverName)
+   {
+      OldLink link;
+      for(link = class(DisplayDriver).derivatives.first; link; link = link.next)
+      {
+         subclass(DisplayDriver) displayDriver = link.data;
+         if(displayDriver && displayDriver.name && !strcmp(displayDriver.name, driverName))
+            return displayDriver;
+      }
+   }
+   return null;
+}
+
+DisplaySystem GetDisplaySystem(const char * driverName)
+{
+   subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
+   return displayDriver ? displayDriver.displaySystem : null;
+}