ecere: Initial Emscripten support
[sdk] / ecere / src / gfx / Display.ec
index 560f4ed..b2af519 100644 (file)
@@ -1,5 +1,9 @@
 namespace gfx;
 
+#if (defined(ECERE_VANILLA) || defined(ECERE_ONEDRIVER)) && defined(__WIN32__)
+#define ECERE_NOTRUETYPE
+#endif
+
 import "System"
 
 import "Color"
@@ -12,6 +16,11 @@ import "BitmapResource"
 
 import "LFBDisplayDriver"
 
+// TOFIX: Temporary until we pass Display instead of DisplaySystem to FontExtent
+#if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
+import "GDIDisplayDriver"
+#endif
+
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
 import "Camera"
 import "Plane"
@@ -24,6 +33,8 @@ import "Vector3D"
 
 public enum RenderState { fillMode = 1, depthTest, depthWrite, fogDensity, fogColor, blend, ambient, alphaWrite, antiAlias, vSync };
 
+public union RenderStateFloat { float f; uint ui; };
+
 public enum FillModeValue { solid, wireframe };
 
 public class DisplayFlags
@@ -35,15 +46,17 @@ public class FontFlags
    public bool bold:1, italic:1, underline:1;
 };
 
-static void DummyFunction()
+__attribute__((unused)) static void DummyFunction()
 {
-   Mutex mutex { };
+#if !defined(__EMSCRIPTEN__)
+   Mutex { };
+#endif
 }
 
 public class DisplayDriver
 {
 public:
-   class_data char * name;
+   class_data const char * name;
    class_data bool textMode;
    class_data bool printer;
    class_data DisplaySystem displaySystem;
@@ -54,7 +67,7 @@ public:
       get { return class_data(displaySystem); }
    };
 
-   class_property char * name
+   class_property const char * name
    {
       set { class_data(name) = value; }
       get { return class_data(name); }
@@ -86,7 +99,7 @@ public:
    virtual void ::Scroll(Display, Box, int, int, Extent);
    virtual void ::Update(Display, Box);
    virtual void ::EndUpdate(Display);
-   
+
    // Allocate/free a bitmap
    virtual bool ::AllocateBitmap(DisplaySystem, Bitmap, int, int, int, PixelFormat, bool);
    virtual void ::FreeBitmap(DisplaySystem, Bitmap);
@@ -108,7 +121,7 @@ public:
 
    // Grab from the screen
    virtual bool ::GrabScreen(Display, Bitmap, int, int, unsigned int, unsigned int);
-   
+
    // Converts a bitmap format
    virtual bool ::ConvertBitmap(DisplaySystem, Bitmap, PixelFormat, ColorAlpha *);
 
@@ -116,7 +129,7 @@ public:
    virtual bool ::MakeDDBitmap(DisplaySystem, Bitmap, bool);
 
    // Font loading
-   virtual Font ::LoadFont(DisplaySystem displaySystem, char * faceName, float size, FontFlags flags);
+   virtual Font ::LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags);
    virtual void ::UnloadFont(DisplaySystem, Font);
 
    // 2D Drawing
@@ -137,9 +150,9 @@ public:
    virtual void ::FilterDI(Display, Surface, Bitmap, int, int, int, int, int, int, int,int);
    virtual void ::TextFont(Display, Surface, Font);
    virtual void ::TextOpacity(Display, Surface, bool);
-   virtual void ::WriteText(Display, Surface, int, int, char *, int);
-   virtual void ::TextExtent(Display, Surface, char *, int, int *, int *);
-   virtual void ::FontExtent(DisplaySystem, Font, char *, int, int *, int *);
+   virtual void ::WriteText(Display, Surface, int, int, const char *, int);
+   virtual void ::TextExtent(Display, Surface, const char *, int, int *, int *);
+   virtual void ::FontExtent(DisplaySystem, Font, const char *, int, int *, int *);
    virtual void ::DrawingChar(Display, Surface, char);
    virtual void ::NextPage(Display);
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
@@ -147,7 +160,7 @@ public:
    virtual void ::SetRenderState(Display, RenderState, uint);
    virtual void ::SetLight(Display, int, Light);
    virtual void ::SetCamera(Display, Surface, Camera);
-   virtual bool ::AllocateMesh(DisplaySystem, Mesh);
+   virtual bool ::AllocateMesh(DisplaySystem, Mesh, MeshFeatures, int nVertices);
    virtual void ::FreeMesh(DisplaySystem, Mesh);
    virtual bool ::LockMesh(DisplaySystem, Mesh, MeshFeatures flags);
    virtual void ::UnlockMesh(DisplaySystem, Mesh, MeshFeatures flags);
@@ -168,27 +181,6 @@ public:
 public enum Alignment { left, right, center };
 public enum ClearType { colorBuffer, depthBuffer, colorAndDepth };
 
-subclass(DisplayDriver) GetDisplayDriver(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(char * driverName)
-{
-   subclass(DisplayDriver) displayDriver = GetDisplayDriver(driverName);
-   return displayDriver ? displayDriver.displaySystem : null;
-}
-
 define textCellW = 8;
 define textCellH = 16;
 
@@ -198,7 +190,7 @@ public enum PixelFormat // : byte MESSES UP GuiApplication
 };
 public enum Resolution : int
 {
-   resText80x25, res320x200, res320x240, res320x400, res360x480, res400x256, res400x300, res512x256, res512x384, 
+   resText80x25, res320x200, res320x240, res320x400, res360x480, res400x256, res400x300, res512x256, res512x384,
    res640x200, res640x350, res640x400, res640x480,  res720x348, res800x600, res856x480, res960x720, res1024x768,
    res1152x864, res1280x1024, res1600x1200, res768x480
 };
@@ -309,7 +301,7 @@ struct SortPrimitive
       Mesh mesh = object.mesh;
       Matrix * matrix = &object.matrix;
       int v;
-      float a = poly2.plane.a, b = poly2.plane.b, c = poly2.plane.c, d = poly2.plane.d;
+      double a = poly2.plane.a, b = poly2.plane.b, c = poly2.plane.c, d = poly2.plane.d;
       if(d < 0)
       {
          a*=-1;
@@ -318,7 +310,7 @@ struct SortPrimitive
          d = - (a * poly2.middle.x + b * poly2.middle.y + c * poly2.middle.z);
       }
 
-       for(v = 0; v < primitive->nIndices; v++) 
+      for(v = 0; v < primitive->nIndices; v++)
       {
          double surface;
          Vector3Df * local = &mesh.vertices[primitive->indices[v]];
@@ -328,7 +320,7 @@ struct SortPrimitive
 
          surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
 
-               if(surface < EPSILON) 
+         if(surface < EPSILON)
          {
                        result = false;
             break;
@@ -341,7 +333,7 @@ struct SortPrimitive
          return result;
    }
 
-   int SurfaceInside(SortPrimitive poly2)
+   bool SurfaceInside(SortPrimitive poly2)
    {
       bool result = true;
 
@@ -349,7 +341,7 @@ struct SortPrimitive
       Mesh mesh = poly2.object.mesh;
       Matrix * matrix = &poly2.object.matrix;
       int v;
-      float a = plane.a, b = plane.b, c = plane.c, d = plane.d;
+      double a = plane.a, b = plane.b, c = plane.c, d = plane.d;
       if(d < 0)
       {
          a*=-1;
@@ -357,14 +349,14 @@ struct SortPrimitive
          c*=-1;
          d = - (a * middle.x + b * middle.y + c * middle.z);
       }
-      
-       for(v = 0; v < primitive->nIndices; v++) 
+
+      for(v = 0; v < primitive->nIndices; v++)
       {
          double surface;
          Vector3Df * local = &mesh.vertices[primitive->indices[v]];
          Vector3Df vertex;
 
-         vertex.Transform(local, matrix);
+         vertex.MultMatrix(local, matrix);
 
          surface = a * vertex.x + b * vertex.y + c * vertex.z + d;
                if(surface > -EPSILON)
@@ -493,19 +485,35 @@ public:
       return result;
    }
 
-   void FontExtent(Font font, char * text, int len, int * width, int * height)
+   void FontExtent(Font font, const char * text, int len, int * width, int * height)
    {
-      DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
+      // Fix for OnLoadGraphics time alpha blended window text extent on GDI
+#if defined(__WIN32__) && !defined(ECERE_NOTRUETYPE)
+      if(this && alphaBlend && pixelFormat == pixelFormat888 &&
+         displaySystem.driver == class(GDIDisplayDriver))
+      {
+         Surface s = GetSurface(0,0,null);
+         if(s)
+         {
+            s.font = font;
+            s.TextExtent(text, len, width, height);
+            delete s;
+         }
+      }
+      else
+#endif
+         // TODO: Should really pass display here...
+         DisplaySystem::FontExtent(this ? displaySystem : null, font, text, len, width, height);
    }
 
    void SetPalette(ColorAlpha * palette, bool colorMatch)
    {
        displaySystem.driver.SetPalette(this, palette, colorMatch);
    }
-   
+
    void RestorePalette(void)
    {
-      displaySystem.driver.RestorePalette(this);  
+      displaySystem.driver.RestorePalette(this);
    }
 
    bool Lock(bool render)
@@ -517,12 +525,14 @@ public:
          Log("   ");
       Logf("Locking (%d)\n", current+1);
       */
-      
+
       // TOCHECK: Why is displaySystem null with GISDesigner?
       result = displaySystem && displaySystem.Lock();
       if(result && render)
       {
+#if !defined(__EMSCRIPTEN__)
          mutex.Wait();
+#endif
 
          if(!current)
             result = displaySystem.driver.Lock(this);
@@ -540,7 +550,7 @@ public:
          current--;
          /*{
             int c;
-            
+
             for(c = 0; c<current; c++)
                Log("   ");
             Logf("Unlocking (%d)\n", current);
@@ -548,7 +558,9 @@ public:
          */
          if(!current && displaySystem)
             displaySystem.driver.Unlock(this);
+#if !defined(__EMSCRIPTEN__)
          mutex.Release();
+#endif
       }
       if(displaySystem)
          displaySystem.Unlock();
@@ -569,7 +581,7 @@ public:
       {
          if(!display3D.selection)
             displaySystem.driver.SelectMesh(this, null);
+
          display3D.material = null;
          display3D.mesh = null;
       }
@@ -602,12 +614,12 @@ public:
             double r = camera.origin.x - (display3D.pickX + display3D.pickWidth/2.0f);
             double t = (display3D.pickY - display3D.pickHeight/2.0f) - camera.origin.y;
             double b = (display3D.pickY + display3D.pickHeight/2.0f) - camera.origin.y;
-            
+
             fovLeft   = atan(l / camera.focalX);
             fovRight  = atan(r / camera.focalX);
             fovTop    = atan(t / camera.focalY);
             fovBottom = atan(b / camera.focalY);
-      
+
             // --- Left ---
             quat.Yaw(fovLeft - Pi/2);
             quat.ToDirection(normal);
@@ -778,11 +790,11 @@ public:
             Matrix matrix;
             Matrix inverse, inverseTranspose;
             int c;
-         
+
             if(object.flags.viewSpace)
                matrix = object.matrix;
             else
-            {  
+            {
                Camera camera = display3D.camera;
                Matrix temp = object.matrix;
                temp.m[3][0] -= camera.cPosition.x;
@@ -810,9 +822,9 @@ public:
                sort->middle.MultMatrix(triangle->middle, matrix);
                sort->middle.z *= -1;
                // sort->plane.MultMatrix(triangle->plane, inverseTranspose);
-               sort->plane.d = plane->a * inverseTranspose.m[0][3] + 
+               sort->plane.d = plane->a * inverseTranspose.m[0][3] +
                                plane->b * inverseTranspose.m[1][3] +
-                               plane->c * inverseTranspose.m[2][3] + 
+                               plane->c * inverseTranspose.m[2][3] +
                                plane->d * inverseTranspose.m[3][3];
             }
          }
@@ -867,7 +879,7 @@ public:
             planes = object.flags.viewSpace ? display3D.viewPickingPlanes : display3D.worldPickingPlanes;
          else
             planes = object.flags.viewSpace ? camera.viewClippingPlanes : camera.worldClippingPlanes;
-         
+
          visible = object.InsideFrustum(planes);
 
          if(visible || display3D.pickingPlanes)
@@ -1076,7 +1088,7 @@ public:
    property FillModeValue fillMode { set { displaySystem.driver.SetRenderState(this, fillMode, value); } };
    property bool depthTest    { set { displaySystem.driver.SetRenderState(this, depthTest, value); } };
    property bool depthWrite   { set { displaySystem.driver.SetRenderState(this, depthWrite, value); } };
-   property float fogDensity  { set { displaySystem.driver.SetRenderState(this, fogDensity, *(uint *)(void *)&value); } };
+   property float fogDensity  { set { displaySystem.driver.SetRenderState(this, fogDensity, RenderStateFloat { value }.ui); } };
    property Color fogColor    { set { displaySystem.driver.SetRenderState(this, fogColor, value); } };
    property bool blend        { set { displaySystem.driver.SetRenderState(this, blend, value); } };
    property Color ambient     { set { displaySystem.driver.SetRenderState(this, ambient, value); } };
@@ -1093,16 +1105,19 @@ public:
    property void * systemWindow { get { return window; } };
    property DisplaySystem displaySystem { get { return displaySystem; } };
 
+   int width, height;
+   void * driverData;
+
 private:
 
    DisplaySystem displaySystem;
    void * window;
-   public int width, height;
-   
+
+#if !defined(__EMSCRIPTEN__)
    Mutex mutex { };
+#endif
    int current;
 
-   public void * driverData;
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
    Display3D display3D;
 #endif
@@ -1112,7 +1127,7 @@ private:
 };
 
 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
-private class Display3D
+private class Display3D : struct
 {
    // 3D Display
    int nTriangles;
@@ -1150,11 +1165,11 @@ private class Display3D
 
          if(object.flags.light && !object.light.flags.off)
             display.SetLight(id++, object.light);
-         
+
          for(child = object.children.first; child; child = child.next)
          {
             id = _SetLights(display, child, id);
-         }   
+         }
       }
       return id;
    }
@@ -1169,7 +1184,7 @@ private class Display3D
       int c = 0;
       int nIndex = 1, nPoints = 1;
       int offset = 0;
-      bool result = false;      
+      bool result = false;
       Vector3D * points = this.points;
       Vector3D * newPoints = this.newPoints;
       byte * goodPoints = this.goodPoints;
@@ -1177,9 +1192,9 @@ private class Display3D
       int strip = 1;
       Vector3Df tmp;
       bool i32bit = primitive.type.indices32bit;
-      uint32 * indices32 = primitive.indices;
+      uint32 * indices32 = primitive.indices32;
       uint16 * indices16 = primitive.indices;
-      
+
       switch(primitive.type.primitiveType)
       {
          case triangles: nIndex = 3; nPoints = 3; break;
@@ -1194,7 +1209,7 @@ private class Display3D
             points[1] = { (double)tmp.x, (double)tmp.y, (double)tmp.z };
             break;
       }
-      
+
       for(c = offset; c<nVertices; c += nIndex)
       {
          bool outside = false;
@@ -1252,14 +1267,14 @@ private class Display3D
                }
             }
 
-             for(p = 0; p < 6; p++) 
+            for(p = 0; p < 6; p++)
             {
                Plane * plane = &planes[p];
                int i;
                int numGoodPoints = 0;
-       
+
                memset(goodPoints, 0, n);
-                     for(i = 0; i < n; i++) 
+               for(i = 0; i < n; i++)
                {
                   double dot = plane->normal.DotProduct(points[i]);
                   double distance = dot + plane->d;
@@ -1290,7 +1305,7 @@ private class Display3D
                      }
                      else
                      {
-                        Line edge; 
+                        Line edge;
                         int next;
 
                         if(lastGood == -1)
@@ -1442,13 +1457,14 @@ private class Display3D
                Vector3Df min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
          Vector3Df max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
          int v;
+         bool ix32 = primitive->type.indices32bit;
          if(object != sort->object)
          {
             object = sort->object;
             if(object.flags.viewSpace)
                matrix = object.matrix;
             else
-            {  
+            {
                Camera camera = this.camera;
                Matrix temp = object.matrix;
                temp.m[3][0] -= camera.cPosition.x;
@@ -1458,9 +1474,9 @@ private class Display3D
             }
          }
 
-          for(v = 0; v<primitive->nIndices; v++) 
+         for(v = 0; v<primitive->nIndices; v++)
          {
-            Vector3Df * local = &mesh.vertices[primitive->indices[v]];
+            Vector3Df * local = &mesh.vertices[ix32 ? primitive->indices32[v] : primitive->indices[v]];
             Vector3Df vertex;
 
             vertex.MultMatrix(local, &matrix);
@@ -1490,7 +1506,7 @@ private class Display3D
 
          Logf("Triangle %d (%s):\n", c, primitive->material->name);
 
-          for(v = 0; v<primitive->nIndices; v++) 
+         for(v = 0; v<primitive->nIndices; v++)
          {
             Vector3Df * local = &mesh.vertices[primitive->indices[v]];
             Vector3Df vertex;
@@ -1523,7 +1539,7 @@ private class Display3D
 
          Logf("Triangle %d (%s):\n", c, primitive->material->name);
 
-          for(v = 0; v<primitive->nIndices; v++) 
+         for(v = 0; v<primitive->nIndices; v++)
          {
             Vector3Df * local = &mesh.vertices[primitive->indices[v]];
             Vector3Df vertex;
@@ -1546,17 +1562,17 @@ private class Display3D
       //exit(0);
 
    /*
-   If all five tests fail for a particular Q, 
-   then P might obscure Q. Now Q must be tested. 
-   First, the algorithm checks if Q has been "marked." 
-   If Q is marked, then Q was "moved around" in the list 
-   during a previous iteration of the loop. The algorithm 
-   only allows a polygon to be moved once, to avoid the possibility 
-   of infinite loops. If Q is not marked, it is tested to see 
-   if it might obscure P. If Q cannot obscure P, then Q is possibly 
-   behind P and so it is good candidate to be drawn next. 
-   Therefore, the algorithm "abandons" the current P (that is, it 
-   stops testing Q's against the current P) and moves the current 
+   If all five tests fail for a particular Q,
+   then P might obscure Q. Now Q must be tested.
+   First, the algorithm checks if Q has been "marked."
+   If Q is marked, then Q was "moved around" in the list
+   during a previous iteration of the loop. The algorithm
+   only allows a polygon to be moved once, to avoid the possibility
+   of infinite loops. If Q is not marked, it is tested to see
+   if it might obscure P. If Q cannot obscure P, then Q is possibly
+   behind P and so it is good candidate to be drawn next.
+   Therefore, the algorithm "abandons" the current P (that is, it
+   stops testing Q's against the current P) and moves the current
    Q to the end of the list to become the next P.
    */
    /*
@@ -1591,8 +1607,7 @@ private class Display3D
             }
          }
       }
-      */
-   /*
+
       {
          int p;
          for(p = 0; p<nTriangles; p++)
@@ -1624,8 +1639,8 @@ private class Display3D
                }
             }
          }
-      }*/
-      /*
+      }
+
       {
          int p;
          for(p = nTriangles-1; p>=0; p--)
@@ -1656,17 +1671,17 @@ private class Display3D
                }
             }
          }
-      }*/
+      }
+
 
-   /*
       {
-          for(c=0; c<nTriangles; c++) 
+         for(c=0; c<nTriangles; c++)
          {
             int b;
             SortPrimitive * poly1 = &triangles[c];
 
-            // for(b=0; b<nTriangles; b++) 
-            //for(b=c+1; b<nTriangles; b++) 
+            // for(b=0; b<nTriangles; b++)
+            //for(b=c+1; b<nTriangles; b++)
             b = c+1;
             if(b<this.nTriangles)
             {
@@ -1681,18 +1696,19 @@ private class Display3D
             }
           }
       }
-   */
+      */
+
    }
 };
 #endif
 
-bool IsDriverTextMode(char * driverName)
+bool IsDriverTextMode(const char * driverName)
 {
    subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
    return driver ? driver.textMode : false;
 }
 
-bool IsDriverPrinter(char * driverName)
+bool IsDriverPrinter(const char * driverName)
 {
    subclass(DisplayDriver) driver = GetDisplayDriver(driverName);
    return driver ? driver.printer : false;
@@ -1880,3 +1896,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;
+}