Mesh replaces Polygon
[org.ibex.core.git] / src / org / ibex / core / Box.java
index 8c312de..ffec434 100644 (file)
@@ -39,7 +39,11 @@ import org.ibex.graphics.*;
  *  trigger a Surface.abort; if rendering were done in the same pass,
  *  rendering work done prior to the Surface.abort would be wasted.
  */
-public final class Box extends JS.Obj implements Callable {
+public final class Box extends JS.Obj implements Callable, Mesh.Chain {
+
+    public Mesh.Chain getMeshChainParent() { return parent; }
+    public Mesh       getMesh()            { return mesh; }
+    public Affine     getAffine()          { return transform; }
 
     // Macros //////////////////////////////////////////////////////////////////////
 
@@ -65,10 +69,11 @@ public final class Box extends JS.Obj implements Callable {
     private int          strokecolor  = 0xFF000000;
     public  float        flex         = 1;
     private Path         path         = null;
+    private Path         clippath     = null;
     private Affine       transform    = Affine.identity();
 
     // FEATURE: polygon caching
-    private Polygon      polygon      = null;
+    private Mesh      polygon      = null;
     private Mesh         mesh         = null;
 
     // specified directly by user
@@ -172,7 +177,8 @@ public final class Box extends JS.Obj implements Callable {
         transform.f = 0;
         a = a.copy().premultiply(transform);
 
-        boolean relevant = packed() || ((fillcolor&0xff000000)!=0x0) || path!=null;
+        //boolean relevant = packed() || ((fillcolor&0xff000000)!=0x0) || path!=null;
+        boolean relevant = true;
         int save_xmin = xmin, save_ymin = ymin, save_xmax = xmax, save_ymax = ymax;
         if (!relevant) {
             for(Box child = getChild(0); child != null; child = child.nextSibling()) {
@@ -219,45 +225,34 @@ public final class Box extends JS.Obj implements Callable {
     private static final boolean OPTIMIZE = false;
 
     /** Renders self and children within the specified region. All rendering operations are clipped to xIn,yIn,wIn,hIn */
-    public void render(PixelBuffer buf, Affine a) {
+    public void render(PixelBuffer buf, Affine a, Mesh clipFrom) { render(buf, a, clipFrom, Affine.identity()); }
+    public void render(PixelBuffer buf, Affine a, Mesh clipFrom, Affine clipa) {
         if (!test(VISIBLE)) return;
-        a = a.copy().premultiply(transform);
-
-        // FIXME: clipping
-        if (path == null) {
-            if (((fillcolor & 0xFF000000) != 0x00000000 || parent == null) && (text==null||"".equals(text))) {
-                if (OPTIMIZE && a.doesNotRotate()) {
-                    int x = (int)a.multiply_px(0, 0);
-                    int y = (int)a.multiply_py(0, 0);
-                    int x2 = (int)a.multiply_px(contentwidth, contentheight);
-                    int y2 = (int)a.multiply_py(contentwidth, contentheight);
-                    buf.fillTrapezoid(x, x, y, x2, x2, y2, (fillcolor & 0xFF000000) == 0 ? 0xffffffff : fillcolor);
-                } else {
-                    new Polygon().addrect(0, 0, contentwidth, contentheight, a).fill(buf, new Paint.SingleColorPaint(fillcolor));
-                }
+        a = a.copy().multiply(transform);
+        clipa = clipa.copy().multiply(transform);
+
+        if (mesh == null)
+            if (path != null) mesh = new Mesh(path, true);
+            else {
+                if (((fillcolor & 0xFF000000) != 0x00000000 || parent == null) && (text==null||"".equals(text)))
+                    mesh = new Mesh().addRect(0, 0, contentwidth, contentheight);
+                // long ret = font.rasterizeGlyphs(text, buf, a, null, 0x777777, 0);
+                // minwidth = maxwidth = font.textwidth(text);
+                // minheight = maxheight = font.textwidth(text);
+                // if (ret == 0) Platform.Scheduler.add(this);
+                // FIXME: texture
             }
-            if (text != null) {
-                long ret = font.rasterizeGlyphs(text, buf, a, null, 0x777777, 0);
-                minwidth = maxwidth = font.textwidth(text);
-                minheight = maxheight = font.textwidth(text);
-                if (ret == 0) Platform.Scheduler.add(this);
-            } 
-            // FIXME: texture
-        } else {
-            if (mesh == null) {
-                Log.warn(this, "generating mesh...");
-                mesh = new Mesh(new Polygon(path, Affine.identity()));
-                Log.warn(this, "  done generating mesh.");
-            }
-            mesh.fill(buf, a, fillcolor, true, false);
-            mesh.stroke(buf, a, strokecolor);
-            //mesh.fill(buf, a, fillcolor, true, true);
+        if (mesh==null) {
+            for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(buf, a, clipFrom, clipa);
+            return;
         }
 
-        for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(buf, a);
+        if (clipFrom != null) clipFrom.subtract(mesh, clipa);
+        Mesh mesh = treeSize() > 0 ? this.mesh.copy() : this.mesh;
+        for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(buf, a, mesh, Affine.identity());
+        mesh.fill(buf, a, null, fillcolor, true);
     }
     
-    
     // Methods to implement org.ibex.js.JS //////////////////////////////////////
   
     public JS call(JS method, JS[] args) throws JSExn {
@@ -383,6 +378,7 @@ public final class Box extends JS.Obj implements Callable {
         case "hshrink":     CHECKSET_FLAG(HSHRINK); RECONSTRAIN();
         case "vshrink":     CHECKSET_FLAG(VSHRINK); RECONSTRAIN();
         case "path":        {
+            mesh = null;
             path = new Path(JSU.toString(value));
             float tx = -1 * Encode.longToFloat2(path.horizontalBounds(Affine.identity()));
             float ty = -1 * Encode.longToFloat2(path.verticalBounds(Affine.identity()));
@@ -392,11 +388,22 @@ public final class Box extends JS.Obj implements Callable {
             dirty();
             polygon = null;
         }
+        case "clippath":        {
+            clippath = new Path(JSU.toString(value));
+            //float tx = -1 * Encode.longToFloat2(clippath.horizontalBounds(Affine.identity()));
+            //float ty = -1 * Encode.longToFloat2(clippath.verticalBounds(Affine.identity()));
+            //clippath.transform(Affine.translate(tx, ty), true);
+            REPLACE();
+            RECONSTRAIN();
+            dirty();
+            polygon = null;
+        }
         case "transform":   {
             transform = Affine.parse(JSU.toString(value));
             transform.e = 0;
             transform.f = 0;
-            if (getSurface() != null) getSurface().dirty(0, 0, 500, 500); // FIXME
+            if (getSurface() != null)  // FIXME
+                getSurface().dirty(0, 0, getSurface().root.contentwidth, getSurface().root.contentheight);
             REPLACE();
             RECONSTRAIN(); dirty(); polygon = null;
         }