changeset 4049:e4e011384db9

RT-29542 Mesh Redo + RT-30961 + RT-31226
author Yao Wang <yao.w.wang@oracle.com>
date Mon, 24 Jun 2013 16:02:27 -0700
parents 35575fd554fd
children 87c39dfffa54
files javafx-geom/src/com/sun/javafx/geom/Matrix3f.java javafx-geom/src/com/sun/javafx/geom/Quat4f.java javafx-ui-common/src/javafx/scene/shape/Sphere.java prism-common/src/com/sun/prism/impl/BaseMesh.java prism-common/src/com/sun/prism/impl/MeshNTBVertex.java prism-common/src/com/sun/prism/impl/MeshNormal.java prism-common/src/com/sun/prism/impl/MeshQuat.java prism-common/src/com/sun/prism/impl/MeshTempState.java prism-common/src/com/sun/prism/impl/MeshUtil.java prism-common/src/com/sun/prism/impl/MeshVertex.java prism-d3d-native/src/D3DContext.cc prism-d3d/src/com/sun/prism/d3d/D3DContext.java prism-d3d/src/com/sun/prism/d3d/D3DMesh.java prism-es2-native/src/GLContext.c prism-es2/src/com/sun/prism/es2/ES2Context.java prism-es2/src/com/sun/prism/es2/ES2Mesh.java prism-es2/src/com/sun/prism/es2/GLContext.java
diffstat 17 files changed, 1268 insertions(+), 964 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-geom/src/com/sun/javafx/geom/Matrix3f.java	Mon Jun 24 16:02:27 2013 -0700
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.geom;
+
+/**
+ * A single precision floating point 3 by 3 matrix.
+ * Primarily to support 3D rotations.
+ */
+public class Matrix3f {
+
+    /**
+     * The first matrix element in the first row.
+     */
+    public float m00;
+    /**
+     * The second matrix element in the first row.
+     */
+    public float m01;
+    /**
+     * The third matrix element in the first row.
+     */
+    public float m02;
+    /**
+     * The first matrix element in the second row.
+     */
+    public float m10;
+    /**
+     * The second matrix element in the second row.
+     */
+    public float m11;
+    /**
+     * The third matrix element in the second row.
+     */
+    public float m12;
+    /**
+     * The first matrix element in the third row.
+     */
+    public float m20;
+    /**
+     * The second matrix element in the third row.
+     */
+    public float m21;
+    /**
+     * The third matrix element in the third row.
+     */
+    public float m22;
+
+    /**
+     * Constructs and initializes a Matrix3f from the specified nine values.
+     * @param m00 the [0][0] element
+     * @param m01 the [0][1] element
+     * @param m02 the [0][2] element
+     * @param m10 the [1][0] element
+     * @param m11 the [1][1] element
+     * @param m12 the [1][2] element
+     * @param m20 the [2][0] element
+     * @param m21 the [2][1] element
+     * @param m22 the [2][2] element
+     */
+    public Matrix3f(float m00, float m01, float m02,
+                    float m10, float m11, float m12,
+                    float m20, float m21, float m22) {
+        this.m00 = m00;
+        this.m01 = m01;
+        this.m02 = m02;
+
+        this.m10 = m10;
+        this.m11 = m11;
+        this.m12 = m12;
+
+        this.m20 = m20;
+        this.m21 = m21;
+        this.m22 = m22;
+
+    }
+
+    /**
+     * Constructs and initializes a Matrix3f from the specified
+     * nine-element array.   this.m00 =v[0], this.m01=v[1], etc.
+     * @param v the array of length 9 containing in order
+     */
+    public Matrix3f(float[] v) {
+        this.m00 = v[0];
+        this.m01 = v[1];
+        this.m02 = v[2];
+
+        this.m10 = v[3];
+        this.m11 = v[4];
+        this.m12 = v[5];
+
+        this.m20 = v[6];
+        this.m21 = v[7];
+        this.m22 = v[8];
+
+    }
+
+    /**
+     * Constructs and initializes a Matrix3f from the specified
+     * nine-element array.   this.m00 =v[0], this.m01=v[1], etc.
+     * @param v the array of length 9 containing in order
+     */
+    public Matrix3f(Vec3f[] v) {
+        this.m00 = v[0].x;
+        this.m01 = v[0].y;
+        this.m02 = v[0].z;
+
+        this.m10 = v[1].x;
+        this.m11 = v[1].x;
+        this.m12 = v[1].x;
+
+        this.m20 = v[2].x;
+        this.m21 = v[2].x;
+        this.m22 = v[2].x;
+
+    }
+
+    /**
+     *  Constructs a new matrix with the same values as the
+     *  Matrix3f parameter.
+     *  @param m1  the source matrix
+     */
+    public Matrix3f(Matrix3f m1) {
+        this.m00 = m1.m00;
+        this.m01 = m1.m01;
+        this.m02 = m1.m02;
+
+        this.m10 = m1.m10;
+        this.m11 = m1.m11;
+        this.m12 = m1.m12;
+
+        this.m20 = m1.m20;
+        this.m21 = m1.m21;
+        this.m22 = m1.m22;
+
+    }
+
+    /**
+     * Constructs and initializes a Matrix3f to all zeros.
+     */
+    public Matrix3f() {
+        this.m00 = (float) 1.0;
+        this.m01 = (float) 0.0;
+        this.m02 = (float) 0.0;
+
+        this.m10 = (float) 0.0;
+        this.m11 = (float) 1.0;
+        this.m12 = (float) 0.0;
+
+        this.m20 = (float) 0.0;
+        this.m21 = (float) 0.0;
+        this.m22 = (float) 1.0;
+
+    }
+
+    /**
+     * Returns a string that contains the values of this Matrix3f.
+     * @return the String representation
+     */
+    @Override
+    public String toString() {
+        return this.m00 + ", " + this.m01 + ", " + this.m02 + "\n"
+                + this.m10 + ", " + this.m11 + ", " + this.m12 + "\n"
+                + this.m20 + ", " + this.m21 + ", " + this.m22 + "\n";
+    }
+
+    /**
+     * Sets this Matrix3f to identity.
+     */
+    public final void setIdentity() {
+        this.m00 = (float) 1.0;
+        this.m01 = (float) 0.0;
+        this.m02 = (float) 0.0;
+
+        this.m10 = (float) 0.0;
+        this.m11 = (float) 1.0;
+        this.m12 = (float) 0.0;
+
+        this.m20 = (float) 0.0;
+        this.m21 = (float) 0.0;
+        this.m22 = (float) 1.0;
+    }
+
+    /**
+     * Sets the specified row of this matrix3f to the three values provided.
+     * @param row the row number to be modified (zero indexed)
+     * @param v the replacement row
+     */
+    public final void setRow(int row, float[] v) {
+        switch (row) {
+            case 0:
+                this.m00 = v[0];
+                this.m01 = v[1];
+                this.m02 = v[2];
+                break;
+
+            case 1:
+                this.m10 = v[0];
+                this.m11 = v[1];
+                this.m12 = v[2];
+                break;
+
+            case 2:
+                this.m20 = v[0];
+                this.m21 = v[1];
+                this.m22 = v[2];
+                break;
+
+            default:
+                throw new ArrayIndexOutOfBoundsException("Matrix3f");
+        }
+    }
+
+    /**
+     * Sets the specified row of this matrix3f to the Vector provided.
+     * @param row the row number to be modified (zero indexed)
+     * @param v the replacement row
+     */
+    public final void setRow(int row, Vec3f v) {
+        switch (row) {
+            case 0:
+                this.m00 = v.x;
+                this.m01 = v.y;
+                this.m02 = v.z;
+                break;
+
+            case 1:
+                this.m10 = v.x;
+                this.m11 = v.y;
+                this.m12 = v.z;
+                break;
+
+            case 2:
+                this.m20 = v.x;
+                this.m21 = v.y;
+                this.m22 = v.z;
+                break;
+
+            default:
+                throw new ArrayIndexOutOfBoundsException("Matrix3f");
+        }
+    }
+
+    /**
+     * Copies the matrix values in the specified row into the vector parameter.
+     * @param row  the matrix row
+     * @param v    the vector into which the matrix row values will be copied
+     */
+    public final void getRow(int row, Vec3f v) {
+        if (row == 0) {
+            v.x = m00;
+            v.y = m01;
+            v.z = m02;
+        } else if (row == 1) {
+            v.x = m10;
+            v.y = m11;
+            v.z = m12;
+        } else if (row == 2) {
+            v.x = m20;
+            v.y = m21;
+            v.z = m22;
+        } else {
+            throw new ArrayIndexOutOfBoundsException("Matrix3f");
+        }
+    }
+
+    /**
+     * Copies the matrix values in the specified row into the array parameter.
+     * @param row  the matrix row
+     * @param v    the array into which the matrix row values will be copied
+     */
+    public final void getRow(int row, float[] v) {
+        if (row == 0) {
+            v[0] = m00;
+            v[1] = m01;
+            v[2] = m02;
+        } else if (row == 1) {
+            v[0] = m10;
+            v[1] = m11;
+            v[2] = m12;
+        } else if (row == 2) {
+            v[0] = m20;
+            v[1] = m21;
+            v[2] = m22;
+        } else {
+            throw new ArrayIndexOutOfBoundsException("Matrix3f");
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-geom/src/com/sun/javafx/geom/Quat4f.java	Mon Jun 24 16:02:27 2013 -0700
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.geom;
+
+/**
+ * A 4 element unit quaternion represented by single precision floating point
+ * x,y,z,w coordinates. The quaternion is always normalized. 
+ */
+public class Quat4f {
+
+    final static double EPS2 = 1.0e-30;
+    
+    /**
+     * The x coordinate.
+     */
+    public float x;
+    /**
+     * The y coordinate.
+     */
+    public float y;
+    /**
+     * The z coordinate.
+     */
+    public float z;
+    /**
+     * The w coordinate.
+     */
+    public float w;
+
+    /**
+   * Constructs and initializes a Quat4f to (0,0,0,0).
+   */
+  public Quat4f()
+  {
+    this.x = 0.0f;
+    this.y = 0.0f;
+    this.z = 0.0f;
+    this.w = 0.0f;
+  }
+
+    /**
+     * Constructs and initializes a Quat4f from the specified xyzw coordinates.
+     * @param x the x coordinate
+     * @param y the y coordinate
+     * @param z the z coordinate
+     * @param w the w scalar component
+     */
+    public Quat4f(float x, float y, float z, float w) {
+        float mag;
+        mag = (float) (1.0 / Math.sqrt(x * x + y * y + z * z + w * w));
+        this.x = x * mag;
+        this.y = y * mag;
+        this.z = z * mag;
+        this.w = w * mag;
+
+    }
+
+    /**
+     * Constructs and initializes a Quat4f from the array of length 4.
+     * @param q the array of length 4 containing xyzw in order
+     */
+    public Quat4f(float[] q) {
+        float mag;
+        mag = (float) (1.0 / Math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]));
+        x = q[0] * mag;
+        y = q[1] * mag;
+        z = q[2] * mag;
+        w = q[3] * mag;
+
+    }
+
+    /**
+     * Constructs and initializes a Quat4f from the specified Quat4f.
+     * @param q1 the Quat4f containing the initialization x y z w data
+     */
+    public Quat4f(Quat4f q1) {
+        this.x = q1.x;
+        this.y = q1.y;
+        this.z = q1.z;
+        this.w = q1.w;
+    }
+
+    /**
+     * Normalizes the value of this quaternion in place.
+     */
+    public final void normalize() {
+        float norm;
+
+        norm = (this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
+
+        if (norm > 0.0f) {
+            norm = 1.0f / (float) Math.sqrt(norm);
+            this.x *= norm;
+            this.y *= norm;
+            this.z *= norm;
+            this.w *= norm;
+        } else {
+            this.x = (float) 0.0;
+            this.y = (float) 0.0;
+            this.z = (float) 0.0;
+            this.w = (float) 0.0;
+        }
+    }
+
+    /**
+     * Sets the value of this quaternion to the rotational component of
+     * the passed matrix.
+     * @param m1 the Matrix3f
+     */
+    public final void set(Matrix3f m1) {
+        float ww = 0.25f * (m1.m00 + m1.m11 + m1.m22 + 1.0f);
+
+        if (ww >= 0) {
+            if (ww >= EPS2) {
+                this.w = (float) Math.sqrt((double) ww);
+                ww = 0.25f / this.w;
+                this.x = (m1.m21 - m1.m12) * ww;
+                this.y = (m1.m02 - m1.m20) * ww;
+                this.z = (m1.m10 - m1.m01) * ww;
+                return;
+            }
+        } else {
+            this.w = 0;
+            this.x = 0;
+            this.y = 0;
+            this.z = 1;
+            return;
+        }
+
+        this.w = 0;
+        ww = -0.5f * (m1.m11 + m1.m22);
+        if (ww >= 0) {
+            if (ww >= EPS2) {
+                this.x = (float) Math.sqrt((double) ww);
+                ww = 0.5f / this.x;
+                this.y = m1.m10 * ww;
+                this.z = m1.m20 * ww;
+                return;
+            }
+        } else {
+            this.x = 0;
+            this.y = 0;
+            this.z = 1;
+            return;
+        }
+
+        this.x = 0;
+        ww = 0.5f * (1.0f - m1.m22);
+        if (ww >= EPS2) {
+            this.y = (float) Math.sqrt((double) ww);
+            this.z = m1.m21 / (2.0f * this.y);
+            return;
+        }
+
+        this.y = 0;
+        this.z = 1;
+    }
+
+    /**
+     * Sets the value of this quaternion to the rotational component of
+     * the passed float matrix.
+     * @param m1 the float[3][3] matrix
+     */
+    public final void set(float m1[][]) {
+        float ww = 0.25f * (m1[0][0] + m1[1][1] + m1[2][2] + 1.0f);
+
+        if (ww >= 0) {
+            if (ww >= EPS2) {
+                this.w = (float) Math.sqrt((double) ww);
+                ww = 0.25f / this.w;
+                this.x = (m1[2][1] - m1[1][2]) * ww;
+                this.y = (m1[0][2] - m1[2][0]) * ww;
+                this.z = (m1[1][0] - m1[0][1]) * ww;
+                return;
+            }
+        } else {
+            this.w = 0;
+            this.x = 0;
+            this.y = 0;
+            this.z = 1;
+            return;
+        }
+
+        this.w = 0;
+        ww = -0.5f * (m1[1][1] + m1[2][2]);
+        if (ww >= 0) {
+            if (ww >= EPS2) {
+                this.x = (float) Math.sqrt((double) ww);
+                ww = 0.5f / this.x;
+                this.y = m1[1][0] * ww;
+                this.z = m1[2][0] * ww;
+                return;
+            }
+        } else {
+            this.x = 0;
+            this.y = 0;
+            this.z = 1;
+            return;
+        }
+
+        this.x = 0;
+        ww = 0.5f * (1.0f - m1[2][2]);
+        if (ww >= EPS2) {
+            this.y = (float) Math.sqrt((double) ww);
+            this.z = m1[2][1] / (2.0f * this.y);
+            return;
+        }
+
+        this.y = 0;
+        this.z = 1;
+    }
+
+    /**
+   * Sets the value of this Quat4f to the scalar multiplication
+   * of the scale factor with this.
+   * @param s the scalar value
+   */
+  public final void scale(float s)
+  {
+    this.x *= s;
+    this.y *= s;
+    this.z *= s;
+    this.w *= s;
+  }
+}
+
--- a/javafx-ui-common/src/javafx/scene/shape/Sphere.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/javafx-ui-common/src/javafx/scene/shape/Sphere.java	Mon Jun 24 16:02:27 2013 -0700
@@ -303,7 +303,6 @@
         float points[] = new float[nPoints * 3];
         float tPoints[] = new float[nTPoints * 2];
         int faces[] = new int[nFaces * 6];
-        int smoothing[] = new int[nFaces];
 
         int pPos = 0, tPos = 0;
 
@@ -415,15 +414,10 @@
             fIndex += 6;
         }
 
-        for (int i = 0; i < nFaces; ++i) {
-            smoothing[i] = 1;
-        }
-
         TriangleMesh m = new TriangleMesh();
         m.getPoints().setAll(points);
         m.getTexCoords().setAll(tPoints);
         m.getFaces().setAll(faces);
-        m.getFaceSmoothingGroups().setAll(smoothing);
         return m;
     }
 
--- a/prism-common/src/com/sun/prism/impl/BaseMesh.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-common/src/com/sun/prism/impl/BaseMesh.java	Mon Jun 24 16:02:27 2013 -0700
@@ -25,31 +25,28 @@
 
 package com.sun.prism.impl;
 
+import com.sun.javafx.geom.Quat4f;
 import com.sun.javafx.geom.Vec2f;
 import com.sun.javafx.geom.Vec3f;
 import com.sun.prism.Mesh;
+import java.util.Arrays;
+import sun.util.logging.PlatformLogger;
 
 /**
  * TODO: 3D - Need documentation
- *  
- * TODO: 3D - This is a direct port of the 3D Mesh prototype.
- *       Need to rename members and methods.
- *       This code is poorly written and performance badly on Java.
- *       We should replace it with an implementation that is well suit for Java
- *       and is maintainable. 
- * JIRA ID: RT-29542 - FX 8 3D: Mesh computation code needs major clean up or redo
  */
 public abstract class BaseMesh extends BaseGraphicsResource implements Mesh {
 
     private int nVerts;
     private int nTVerts;
     private int nFaces;
-    private float pos[];
-    private float uv[];
-    private int faces[];
-    private int smoothing[];
-    private MeshNormal meshNormal;
-
+    private float[] pos;
+    private float[] uv;
+    private int[] faces;
+    private int[] smoothing;
+    private boolean allSameSmoothing;
+    private boolean allHardEdges;
+    
     //pos (3 floats), tex (2 floats) and norm (4 float)
     protected static final int VERTEX_SIZE = 9;
 
@@ -60,13 +57,17 @@
     public static enum FaceMembers {
         POINT0, TEXCOORD0, POINT1, TEXCOORD1, POINT2, TEXCOORD2, SMOOTHING_GROUP
     };
-    public static final int MAX_FACE_MEMBERS = 7;
+    public static final int FACE_MEMBERS_SIZE = 7;
 
     protected BaseMesh(Disposer.Record disposerRecord) {
         super(disposerRecord);
     }
 
-    public abstract boolean buildNativeGeometry();
+    public abstract boolean buildNativeGeometry(float[] vertexBuffer, 
+            int vertexBufferLength, int[] indexBufferInt, int indexBufferLength);
+
+     public abstract boolean buildNativeGeometry(float[] vertexBuffer,
+            int vertexBufferLength, short[] indexBufferShort, int indexBufferLength);
 
     @Override
     public boolean buildGeometry(float[] pos, float[] uv, int[] faces, int[] smoothing) {
@@ -79,87 +80,192 @@
         this.faces = faces;
         this.smoothing = smoothing != null && smoothing.length >= nFaces ? smoothing : null;
 
-        // System.err.println("*********** MeshBase.buildGeometry() .....");
-        // MeshData.cc
-        //(1) MeshNomralsReference tan = computeTangentBNormal(mesh);
-        meshNormal = new MeshNormal(this);
+        MeshTempState instance = MeshTempState.getInstance();
+        // big pool for all possible vertices
+        instance.pool = (instance.pool == null || instance.pool.length < nFaces * 3)
+                ? new MeshVertex[nFaces * 3] : instance.pool;
 
-        //(2) buildGeometry( FacetMeshWrapper<WORD>(mesh, tan.getPtr()) );
-        //    if (ok) setDrawCall();
-        //    return ok;
-        return buildNativeGeometry();
-    }
+        if (instance.indexBuffer == null || instance.indexBuffer.length < nFaces * 3) {
+            instance.indexBuffer = new int[nFaces * 3];
+        }
 
-    private static Vec2f tmp2f = new Vec2f();
-    private static Vec3f tmp3f = new Vec3f();
-    private int fillOVertex(float pv[], int index, MeshNTBVertex ntb) {
-        tmp3f = getVertex(ntb.pVert, tmp3f);
-        pv[index++] = tmp3f.x;
-        pv[index++] = tmp3f.y;
-        pv[index++] = tmp3f.z;
-        tmp2f = getTVertex(ntb.tVert, tmp2f);
-        pv[index++] = tmp2f.x;
-        pv[index++] = tmp2f.y;
-        pv[index++] = ntb.tbn.v.x;
-        pv[index++] = ntb.tbn.v.y;
-        pv[index++] = ntb.tbn.v.z;
-        pv[index++] = ntb.tbn.w;
-        return index;
-    }
+        if (instance.pVertex == null || instance.pVertex.length < nVerts) {
+            instance.pVertex = new MeshVertex[nVerts];
+        } else {
+            Arrays.fill(instance.pVertex, 0, instance.pVertex.length, null);
+        }
 
-    private void copyOVerts(float pv[]) {
-        int nv = meshNormal.getNumVerts();
-        int index = 0;
-        for (int i = 0; i != nv; ++i) {
-            index = fillOVertex(pv, index, meshNormal.getTangent(i));
+        // check if all hard edges or all smooth
+        checkSmoothingGroup();
+
+        // compute [N, T, B] for each face
+        computeTBNormal(instance.pool, instance.pVertex, instance.indexBuffer);
+
+        // process sm and weld points
+        int nNewVerts = MeshVertex.processVertices(instance.pVertex, nVerts,
+                allHardEdges, allSameSmoothing);
+
+        if (instance.vertexBuffer == null
+                || instance.vertexBuffer.length < nNewVerts * VERTEX_SIZE) {
+            instance.vertexBuffer = new float[nNewVerts * VERTEX_SIZE];
+        }
+        buildVertexBuffer(instance.pVertex, instance.vertexBuffer);
+        
+        if (nNewVerts > 0x10000) {
+            buildIndexBuffer(instance.pool, instance.indexBuffer, null);
+            return buildNativeGeometry(instance.vertexBuffer,
+                    nNewVerts * VERTEX_SIZE, instance.indexBuffer, nFaces * 3);
+        } else {
+            if (instance.indexBufferShort == null || instance.indexBufferShort.length < nFaces * 3) {
+                instance.indexBufferShort = new short[nFaces * 3];
+            }
+            buildIndexBuffer(instance.pool, instance.indexBuffer, instance.indexBufferShort);
+            return buildNativeGeometry(instance.vertexBuffer,
+                    nNewVerts * VERTEX_SIZE, instance.indexBufferShort, nFaces * 3);
         }
     }
 
-    private int getNVertsGM() {
-        return meshNormal.getNumVerts();
+    private void computeTBNormal(MeshVertex[] pool, MeshVertex[] pVertex, int[] indexBuffer) {
+        MeshTempState instance = MeshTempState.getInstance();
+        
+        // tmp variables
+        int[] smFace = instance.smFace;
+        int[] triVerts = instance.triVerts;
+        Vec3f[] triPoints = instance.triPoints;
+        Vec2f[] triTexCoords = instance.triTexCoords;
+        Vec3f[] n = instance.norm;
+        
+
+        for (int f = 0, nDeadFaces = 0, poolIndex = 0; f < nFaces; f++) {
+            int index = f * 3;
+
+            smFace = getFace(f, smFace); // copy from mesh to tmp smFace
+
+            // Get tex. point. index
+            triVerts[0] = smFace[BaseMesh.FaceMembers.POINT0.ordinal()];
+            triVerts[1] = smFace[BaseMesh.FaceMembers.POINT1.ordinal()];
+            triVerts[2] = smFace[BaseMesh.FaceMembers.POINT2.ordinal()];
+            
+            if (MeshUtil.isDeadFace(triVerts)) {
+                nDeadFaces++;
+                String logname = BaseMesh.class.getName();
+                PlatformLogger.getLogger(logname).warning("Dead face ["
+                        + triVerts[0] + ", " + triVerts[1] + ", " + triVerts[2]
+                        + "] @ face group " + f + "; nEmptyFaces = " + nDeadFaces);
+                indexBuffer[index] = MeshVertex.IDX_UNDEFINED;
+                continue;
+            }
+
+            for (int i = 0; i < 3; i++) {
+                triPoints[i] = getVertex(triVerts[i], triPoints[i]);
+            }
+
+            // Get tex. coord. index
+            triVerts[0] = smFace[BaseMesh.FaceMembers.TEXCOORD0.ordinal()];
+            triVerts[1] = smFace[BaseMesh.FaceMembers.TEXCOORD1.ordinal()];
+            triVerts[2] = smFace[BaseMesh.FaceMembers.TEXCOORD2.ordinal()];
+
+            for (int i = 0; i < 3; i++) {
+                triTexCoords[i] = getTVertex(triVerts[i], triTexCoords[i]);
+            }
+
+            MeshUtil.computeTBNNormalized(triPoints[0], triPoints[1], triPoints[2],
+                                          triTexCoords[0], triTexCoords[1], triTexCoords[2],
+                                          n);
+
+            for (int j = 0; j < 3; ++j) {
+                pool[poolIndex] = (pool[poolIndex] == null) ? new MeshVertex() : pool[poolIndex];
+
+                for (int i = 0; i < 3; ++i) {
+                    pool[poolIndex].norm[i].set(n[i]);
+                }
+                pool[poolIndex].smGroup = smFace[BaseMesh.FaceMembers.SMOOTHING_GROUP.ordinal()];
+                pool[poolIndex].fIdx = f;
+                pool[poolIndex].tVert = triVerts[j];
+                pool[poolIndex].index = MeshVertex.IDX_UNDEFINED;
+                int ii = j == 0 ? BaseMesh.FaceMembers.POINT0.ordinal()
+                        : j == 1 ? BaseMesh.FaceMembers.POINT1.ordinal()
+                        : BaseMesh.FaceMembers.POINT2.ordinal();
+                int pIdx = smFace[ii];
+                pool[poolIndex].pVert = pIdx;
+                indexBuffer[index + j] = pIdx;
+                pool[poolIndex].next = pVertex[pIdx];
+                pVertex[pIdx] = pool[poolIndex];
+                poolIndex++;
+            }
+        }
     }
 
-    private int getNIndicesGM() {
-        return meshNormal.getNumFaces() * 3;
+    private void buildVSQuat(Vec3f[] tm, Quat4f quat) {
+        Vec3f v = MeshTempState.getInstance().vec3f1;
+        v.cross(tm[1], tm[2]);
+        float d = tm[0].dot(v);
+        if (d < 0) {
+            tm[2].mul(-1);
+        }
+
+        MeshUtil.buildQuat(tm, quat);
+        assert (quat.w >= 0);
+
+        if (d < 0) {
+            if (quat.w == 0) {
+                quat.w = MeshUtil.MAGIC_SMALL;
+            }
+            quat.scale(-1);
+        }
     }
 
-    final protected float[] getVertsGM() {
-        int numVerts = getNVertsGM();
-        float vertexBuffer[] = new float[numVerts * VERTEX_SIZE];
-        copyOVerts(vertexBuffer);
-        return vertexBuffer;
+    private void buildVertexBuffer(MeshVertex[] pVerts, float[] vertexBuffer) {
+        Quat4f quat = MeshTempState.getInstance().quat;
+        int idLast = 0;
+
+        for (int i = 0, index = 0; i < nVerts; ++i) {
+            MeshVertex v = pVerts[i];
+            for (; v != null; v = v.next) {
+                if (v.index == idLast) {
+                    int ind = v.pVert * 3;
+                    vertexBuffer[index++] = pos[ind];
+                    vertexBuffer[index++] = pos[ind + 1];
+                    vertexBuffer[index++] = pos[ind + 2];
+                    ind = v.tVert * 2;
+                    vertexBuffer[index++] = uv[ind];
+                    vertexBuffer[index++] = uv[ind + 1];
+                    buildVSQuat(v.norm, quat);
+                    vertexBuffer[index++] = quat.x;
+                    vertexBuffer[index++] = quat.y;
+                    vertexBuffer[index++] = quat.z;
+                    vertexBuffer[index++] = quat.w;
+                    idLast++;
+                }
+            }
+        }
     }
 
-    final protected short[] getIndexGMShort() {
-        int numIndices = getNIndicesGM();
-        short indexBuffer[] = new short[numIndices];
-        int nf = meshNormal.getNumFaces();
-        int face[] = new int[3];
-        int index = 0;
-        for (int i = 0; i != nf; ++i) {
-            face = meshNormal.getFace(i, face);
-            indexBuffer[index++] = (short) face[0];
-            indexBuffer[index++] = (short) face[1];
-            indexBuffer[index++] = (short) face[2];
+    private void buildIndexBuffer(MeshVertex[] pool, int[] indexBuffer, short[] indexBufferShort) {
+        for (int i = 0; i < nFaces; ++i) {
+            int index = i * 3;
+            if (indexBuffer[index] != MeshVertex.IDX_UNDEFINED) {
+                for (int j = 0; j < 3; ++j) {
+                    assert (pool[index].fIdx == i);
+                    if (indexBufferShort != null) {
+                        indexBufferShort[index + j] = (short) pool[index + j].index;
+                    } else {
+                        indexBuffer[index + j] = pool[index + j].index;
+                    }
+                    pool[index + j].next = null; // release reference
+                }
+            } else {
+                for (int j = 0; j < 3; ++j) {
+                    if (indexBufferShort != null) {
+                        indexBufferShort[index + j] = 0;
+                    } else {
+                        indexBuffer[index + j] = 0;
+                    }
+                }
+            }
         }
-        return indexBuffer;
     }
-
-    final protected int[] getIndexGMInt() {
-        int numIndices = getNIndicesGM();
-        int indexBuffer[] = new int[numIndices];
-        int nf = meshNormal.getNumFaces();
-        int face[] = new int[3];
-        int index = 0;
-        for (int i = 0; i != nf; ++i) {
-            face = meshNormal.getFace(i, face);
-            indexBuffer[index++] = face[0];
-            indexBuffer[index++] = face[1];
-            indexBuffer[index++] = face[2];
-        }
-        return indexBuffer;
-    }
-
+    
     public int getNumVerts() {
         return nVerts;
     }
@@ -190,10 +296,35 @@
         return texCoord;
     }
 
-    public int[] getFace(int fIdx, int face[]) {
+    private void checkSmoothingGroup() {
+        if (smoothing == null || smoothing.length == 0) { // all smooth
+            allSameSmoothing = true;
+            allHardEdges = false;
+            return;
+        }
+
+        for (int i = 0; i + 1 < smoothing.length; i++) {
+            if (smoothing[i] != smoothing[i + 1]) {
+                // various SmGroup
+                allSameSmoothing = false;
+                allHardEdges = false;
+                return;
+            }
+        }
+
+        if (smoothing[0] == 0) { // all hard edges
+            allSameSmoothing = false;
+            allHardEdges = true;
+        } else { // all belongs to one group == all smooth
+            allSameSmoothing = true;
+            allHardEdges = false;
+        }
+    }
+
+    public int[] getFace(int fIdx, int[] face) {
         int index = fIdx * 6;
-        if ((face == null) && (face.length < MAX_FACE_MEMBERS)) {
-            face = new int[MAX_FACE_MEMBERS];
+        if ((face == null) || (face.length < FACE_MEMBERS_SIZE)) {
+            face = new int[FACE_MEMBERS_SIZE];
         }
         if (faces[index] < nVerts
                 && faces[index + 2] < nVerts
@@ -219,5 +350,4 @@
         }
         return face;
     }
-
 }
--- a/prism-common/src/com/sun/prism/impl/MeshNTBVertex.java	Mon Jun 24 18:03:10 2013 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.prism.impl;
-
-/**
- * TODO: 3D - Need documentation
- * TODO: This is a direct port of the 3D Mesh prototype.
- *       Need to rename members and methods
- * JIRA ID: RT-29542 - FX 8 3D: Mesh computation code needs major clean up or redo
- */
-class MeshNTBVertex {
-
-    MeshQuat tbn = new MeshQuat();
-    int pVert, tVert;
-
-    public MeshNTBVertex() {
-    }
-}
--- a/prism-common/src/com/sun/prism/impl/MeshNormal.java	Mon Jun 24 18:03:10 2013 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,322 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.prism.impl;
-
-import com.sun.javafx.geom.Vec2f;
-import com.sun.javafx.geom.Vec3f;
-import sun.util.logging.PlatformLogger;
-
-/**
- * TODO: 3D - Need documentation
- * Utility routines for dealing with mesh computation.
- * TODO: 3D - This is a direct port of the 3D Mesh prototype.
- *       Need to rename members and methods.
- *       This code is poorly written and performance badly on Java.
- *       We should replace it with an implementation that is well suit for Java
- *       and is maintainable.
- * JIRA ID: RT-29542 - FX 8 3D: Mesh computation code needs major clean up or redo
- */
-class MeshNormal {
-    private BaseMesh mesh;
-    private int nFaces, nVerts;
-    //Vec3iPtr  faces;
-    private int faces[]; // nFaces * 3
-    private MeshNTBVertex verts[];
-
-    private static Vec3f tmp1 = new Vec3f();
-    private static Vec3f tmp2 = new Vec3f();
-
-    MeshNormal(BaseMesh mesh) {
-        this.mesh = mesh;
-        compute();
-    }
-
-    int  getNumVerts() {
-        return nVerts;
-    }
-
-    int  getNumFaces() {
-        return nFaces;
-    }
-
-    MeshNTBVertex getTangent(int i) {
-        assert( i < nVerts );
-        return verts[i];
-    }
-
-    int[] getFace(int i, int[] face) {
-        assert( i < nFaces );
-        if (face == null) {
-            face = new int[3];
-        }
-        int index = i * 3;
-        face[0] = faces[index];
-        face[1] = faces[index + 1];
-        face[2] = faces[index + 2];
-        return face;
-    }
-
-    private void compute() {
-        int nOldVerts = mesh.getNumVerts();
-
-        nFaces = mesh.getNumFaces();
-
-        // big pool for all possible vertices
-        MeshVertex[] pool = new MeshVertex[nFaces * 3];
-        for (int i = 0; i < pool.length; i++) {
-            pool[i] = new MeshVertex();
-        }
-
-        // faces validity map
-        boolean[] validFaces = new boolean[nFaces];
-
-        // list of vertices for each point (use as pointer)
-        MeshVertex[] pVerts = new MeshVertex[nOldVerts];
-
-//        System.err.println("nOldVerts = " + nOldVerts + ", nFaces = " + nFaces);
-//        System.err.println("\n ************** Before ******************\n");
-//        for (int i = 0; i < nOldVerts; i++) {
-//            System.err.println("pVerts[" + i + "] = " + pVerts[i]);
-//        }
-//        for(int i = 0; i < nFaces; i++) {
-//            System.err.println("validFaces[" + i + "] = " + validFaces[i]);
-//        }
-//        for(int i = 0; i < (nFaces * 3); i++) {
-//            System.err.println("pool[" + i + "] = " + pool[i]);
-//        }
-//        System.err.println("\n ************** Enter ******************\n");
-
-        collect(pool, pVerts, validFaces);
-
-//        System.err.println("\n ************** After ******************\n");
-//        for (int i = 0; i < nOldVerts; i++) {
-//            System.err.println("pVerts[" + i + "] = " + pVerts[i]);
-//        }
-//        for(int i = 0; i < nFaces; i++) {
-//            System.err.println("validFaces[" + i + "] = " + validFaces[i]);
-//        }
-//        for(int i = 0; i < (nFaces * 3); i++) {
-//            System.err.println("pool[" + i + "] = " + pool[i]);
-//        }
-
-        int nU[] = new int[1];
-        int nNewVerts = 0;
-
-        for (int i=0; i!=nOldVerts; ++i) {
-            if (pVerts[i] != null) {
-//                System.err.println("Before ************ nU[0] = " + nU[0] + ", nNewVerts = " + nNewVerts);
-                nNewVerts = MeshVertex.processVertices(pVerts[i], nNewVerts, nU);
-//                System.err.println("After ************ nU[0] = " + nU[0] + ", nNewVerts = " + nNewVerts);
-            }
-        }
-
-        buildVetrices(nOldVerts, nNewVerts, pVerts);
-        buildFaces(pVerts, validFaces);
-
-        nVerts = nNewVerts;
-    }
-
-    // returns number of good faces
-    // does copy faces information into this->faces
-    private void collect(MeshVertex pool[], MeshVertex pVerts[],
-            boolean validFaces[])
-    {
-        Vec3f n[] = new Vec3f[3];
-        for (int i = 0; i < 3; i++) {
-            n[i] = new Vec3f();
-        }
-
-        int nEmptyFaces = 0;
-
-        // faces = new Vec3i[nFaces];
-        faces = new int[nFaces * 3];
-        int smFace[] = new int[BaseMesh.MAX_FACE_MEMBERS];
-        int triVerts[] = new int[3];
-        Vec3f triPoints[] = new Vec3f[3];
-        Vec2f triTexCoords[] = new Vec2f[3];
-        Vec3f N = new Vec3f();
-
-        int poolIndex = 0;
-        for (int f = 0; f < nFaces; f++) {
-            //faces[f].set(0,0,0);
-            int index = f * 3;
-            for (int i = 0; i < 3; i++) {
-                faces[index + i] = 0;
-            }
-            validFaces[f] = false;
-
-            //SmFace &smFace = mesh.getFace(f);
-            smFace = mesh.getFace(f, smFace);
-
-            triVerts[0] = smFace[BaseMesh.FaceMembers.POINT0.ordinal()];
-            triVerts[1] = smFace[BaseMesh.FaceMembers.POINT1.ordinal()];
-            triVerts[2] = smFace[BaseMesh.FaceMembers.POINT2.ordinal()];
-            if (MeshUtil.isDeadFace(triVerts)) {
-                nEmptyFaces++;
-                String logname = MeshNormal.class.getName();
-                PlatformLogger.getLogger(logname).warning("Dead face ["
-                        + triVerts[0] + ", " + triVerts[1] + ", " + triVerts[2]
-                        + "] @ face group " + f + "; nEmptyFaces = " + nEmptyFaces);
-                continue;
-            }
-            for (int i = 0; i < 3; i++) {
-                triPoints[i] = mesh.getVertex(triVerts[i], triPoints[i]);
-            }
-
-            // Vec3f N = (v1-v0)^(v2-v1);
-            tmp1.sub(triPoints[1], triPoints[0]);
-            tmp2.sub(triPoints[2], triPoints[1]);
-            N.cross(tmp1, tmp2);
-            float areaSquared = N.dot(N);
-//            System.err.println("areaSquared = " + areaSquared);
-
-            if (MeshUtil.isDeadFace(areaSquared)) {
-                nEmptyFaces++;
-                String logname = MeshNormal.class.getName();
-                PlatformLogger.getLogger(logname).warning("Face area exceeds the "
-                        + "minimum @ face group " + f + "; nEmptyFaces = "
-                        + nEmptyFaces);
-            }
-
-            for (int i = 0; i < 3; i++) {
-                faces[index + i] = triVerts[i];
-            }
-            validFaces[f] = true;
-
-            n[0].set(N);
-            n[0].normalize();
-
-            boolean valid;
-
-            // Get tex. coord. index
-            triVerts[0] = smFace[BaseMesh.FaceMembers.TEXCOORD0.ordinal()];
-            triVerts[1] = smFace[BaseMesh.FaceMembers.TEXCOORD1.ordinal()];
-            triVerts[2] = smFace[BaseMesh.FaceMembers.TEXCOORD2.ordinal()];
-
-            triTexCoords[0] = mesh.getTVertex(triVerts[0], triTexCoords[0]);
-            triTexCoords[1] = mesh.getTVertex(triVerts[1], triTexCoords[1]);
-            triTexCoords[2] = mesh.getTVertex(triVerts[2], triTexCoords[2]);
-
-            if (valid = MeshUtil.computeUVNormalized(triPoints[0], triPoints[1], triPoints[2],
-                    triTexCoords[0], triTexCoords[1], triTexCoords[2], n[1], n[2])) {
-
-                if (MeshUtil.fabs(n[1].dot(n[2])) > MeshUtil.gUVParralel) {
-                    // U and V go almost in parallel
-                    MeshUtil.fixParrallelTB(n);
-                }
-            } else {
-                MeshUtil.generateTB(triPoints[0], triPoints[1], triPoints[2], n);
-                // face has no valid mapping
-            }
-
-            for (int j=0; j!=3; ++j) {
-                MeshVertex vNew = pool[poolIndex++];
-
-                for (int i=0; i!=3; ++i) {
-                    vNew.norm[i].set(n[i]);
-                }
-                vNew.smGroup = smFace[BaseMesh.FaceMembers.SMOOTHING_GROUP.ordinal()];
-                vNew.initiazed = true;
-                vNew.fIndex = f;
-                vNew.valid = valid;
-                vNew.pIdx = MeshVertex.idxUndef;
-                int ii = j == 0 ? BaseMesh.FaceMembers.TEXCOORD0.ordinal() :
-                        j == 1 ? BaseMesh.FaceMembers.TEXCOORD1.ordinal() :
-                        BaseMesh.FaceMembers.TEXCOORD2.ordinal();
-                vNew.tIndex = smFace[ii];
-                ii = j == 0 ? BaseMesh.FaceMembers.POINT0.ordinal() :
-                        j == 1 ? BaseMesh.FaceMembers.POINT1.ordinal() :
-                        BaseMesh.FaceMembers.POINT2.ordinal();
-                int pIdx = smFace[ii];
-                vNew.next   = pVerts[pIdx];
-                pVerts[pIdx] = vNew;
-            }
-        }
-    }
-
-    private static void buildVSQuat(Vec3f tm[], MeshQuat quat) {
-
-        tmp1.cross(tm[1], tm[2]);
-        float d = tm[0].dot(tmp1);
-        if (d < 0) {
-            tm[2].mul(-1);
-        }
-
-        quat.buildQuat(tm);
-
-        assert( quat.w >= 0 );
-
-        if (d<0) {
-            if (quat.w == 0) {
-                quat.w = MeshUtil.magicSmall;
-            }
-            quat.scale(-1);
-        }
-    }
-
-    static int fillNewVertices(MeshVertex v, int idLast, int oldIndex, MeshNTBVertex vertices[]) {
-        for (; v != null; v = v.next) {
-            if (v.pIdx == idLast) {
-                MeshNTBVertex newVert = vertices[idLast];
-                newVert.pVert = oldIndex;
-                newVert.tVert = v.tIndex;
-                buildVSQuat(v.norm, newVert.tbn);
-                idLast++;
-            }
-        }
-        return idLast;
-    }
-
-    void buildVetrices( int nOldVerts, int nNewVerts, MeshVertex pVerts[]) {
-        verts = new MeshNTBVertex[nNewVerts];
-        for (int i = 0; i < nNewVerts; i++) {
-            verts[i] = new MeshNTBVertex();
-        }
-        MeshNTBVertex vertices[] = verts;
-
-        int idLast = 0;
-
-        for (int i=0; i != nOldVerts; ++i) {
-            MeshVertex v = pVerts[i];
-            idLast = fillNewVertices(v, idLast, i, vertices);
-            idLast = fillNewVertices(v, idLast, i, vertices);
-        }
-
-        assert ( idLast == nNewVerts );
-    }
-
-    void buildFaces(MeshVertex pVerts[], boolean validFaces[]) {
-        for (int i = 0; i != nFaces; ++i) {
-            if (validFaces[i]) {
-                int index = i * 3;
-                for (int j = 0; j != 3; ++j) {
-                    faces[index + j] = MeshVertex.getIndex(pVerts[faces[index + j]], i);
-                }
-            }
-        }
-    }
-
-}
--- a/prism-common/src/com/sun/prism/impl/MeshQuat.java	Mon Jun 24 18:03:10 2013 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.prism.impl;
-
-import com.sun.javafx.geom.Vec3f;
-
-/**
- * TODO: 3D - Need documentation
- * TODO: This is a direct port of the 3D Mesh prototype.
- *       Need to change to use proper quaternion class in the future
- * JIRA ID: RT-29542 - FX 8 3D: Mesh computation code needs major clean up or redo
- */
-class MeshQuat {
-
-
-    Vec3f v;
-    float w;
-
-    private static float m[][] = new float[3][3];
-    private static float tmp[] = new float[3];
-
-    MeshQuat() {
-        v = new Vec3f();
-        w = 0f;
-    }
-
-    MeshQuat(Vec3f v, float w) {
-        this.v = new Vec3f(v);
-        this.w = w;
-    }
-
-    void buildQuat(Vec3f tm[]) {
-
-        for (int i = 0; i < 3; i++) {
-            m[i][0] = tm[i].x;
-            m[i][1] = tm[i].y;
-            m[i][2] = tm[i].z;
-        }
-
-        float trace = m[0][0] + m[1][1] + m[2][2];
-
-        if (trace > 0) {
-
-            float s = (float) Math.sqrt(trace + 1.0f);
-            float t = 0.5f / s;
-            w = 0.5f * s;
-            v.x = (m[1][2] - m[2][1]) * t;
-            v.y = (m[2][0] - m[0][2]) * t;
-            v.z = (m[0][1] - m[1][0]) * t;
-
-        } else {
-
-            int next[] = {1, 2, 0};
-            int i = 0;
-
-            if (m[1][1] > m[0][0]) {
-                i = 1;
-            }
-            if (m[2][2] > m[i][i]) {
-                i = 2;
-            }
-
-            int j = next[i], k = next[j];
-
-            double s = Math.sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0f);
-
-            if (m[j][k] < m[k][j]) {
-                s = -s;
-            }
-
-            float t = (float) (0.5 / s);
-
-            tmp[i] = (float) (0.5f * s);
-            w = (m[j][k] - m[k][j]) * t;
-            tmp[j] = (m[i][j] + m[j][i]) * t;
-            tmp[k] = (m[i][k] + m[k][i]) * t;
-            v.x = tmp[0];
-            v.y = tmp[1];
-            v.z = tmp[2];
-        }
-    }
-
-    void scale(float s) {
-        v.mul(s);
-        w *= s;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/prism-common/src/com/sun/prism/impl/MeshTempState.java	Mon Jun 24 16:02:27 2013 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.prism.impl;
+
+import com.sun.javafx.geom.Quat4f;
+import com.sun.javafx.geom.Vec2f;
+import com.sun.javafx.geom.Vec3f;
+import static com.sun.prism.impl.BaseMesh.FACE_MEMBERS_SIZE;
+
+/**************************************************************************
+ *                                                                        *
+ * Temporary state, used to reduce the occurrence of temporary garbage    *
+ * while computing things such as Quat, Normal, Tangent or Bitangent.     *
+ * Since these operations happen extremely often and must be very fast,   *
+ * we need to reduce the load on the garbage collector.                   *
+ *                                                                        *
+ *************************************************************************/
+final class MeshTempState {
+    /**
+     * Temporary Vec3fs used by MeshUtil and BaseMesh to compute/adjust normals.
+     */
+    final Vec3f vec3f1 = new Vec3f();
+    final Vec3f vec3f2 = new Vec3f();
+    final Vec3f vec3f3 = new Vec3f();
+    final Vec3f vec3f4 = new Vec3f();
+    final Vec3f vec3f5 = new Vec3f();
+    final Vec3f vec3f6 = new Vec3f();
+
+    /**
+     * Temporary Vec2fs used by MeshUtil to fix tangent space.
+     */
+    final Vec2f vec2f1 = new Vec2f();
+    final Vec2f vec2f2 = new Vec2f();    
+
+    /**
+     * Temporary variables used by BaseMesh to compute TBN.
+     */
+    final int smFace[] = new int[FACE_MEMBERS_SIZE];
+    final int triVerts[] = new int[3];
+    final Vec3f triPoints[] = new Vec3f[3];
+    final Vec2f triTexCoords[] = new Vec2f[3];
+    final Vec3f norm[] = new Vec3f[3];
+
+    /**
+     * A temporary 3 by 3 float matrix used by BaseMesh to compute quat.
+     */
+    final float matrix[][] = new float[3][3];
+    /**
+     * A temporary float array used by BaseMesh to compute quat.
+     */
+    final float vector[] = new float[3];
+    /**
+     * A temporary Quat4f used by BaseMesh to build quat.
+     */
+    final Quat4f quat = new Quat4f();
+
+    /**
+     * A temporary MeshVertex array for all possible vertices.
+     * Length: nFaces * 3
+     */
+    MeshVertex[] pool;
+
+    /**
+     * A temporary MeshVertex array
+     * Length: nVerts
+     */
+    MeshVertex[] pVertex;
+
+    /**
+     * A temporary int indexBuffer array
+     * Length: nFaces * 3
+     */
+    int[] indexBuffer;
+    
+    /**
+     * A temporary short indexBuffer array
+     * Length: nFaces * 3
+     */
+    short[] indexBufferShort;
+
+    /**
+     * A temporary vertexBuffer array
+     * Length: nNewVerts * VERTEX_SIZE
+     */
+    float[] vertexBuffer;
+
+    private static final ThreadLocal<MeshTempState> tempStateRef =
+            new ThreadLocal<MeshTempState>() {
+                @Override
+                protected MeshTempState initialValue() {
+                    return new MeshTempState();
+                }
+            };
+
+    private MeshTempState() {
+        for (int i = 0; i < 3; i++) {
+            norm[i] = new Vec3f();
+        }
+    }
+
+    static MeshTempState getInstance() {
+        return tempStateRef.get();
+    }
+}
+
--- a/prism-common/src/com/sun/prism/impl/MeshUtil.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-common/src/com/sun/prism/impl/MeshUtil.java	Mon Jun 24 16:02:27 2013 -0700
@@ -25,29 +25,25 @@
 
 package com.sun.prism.impl;
 
+import com.sun.javafx.geom.Quat4f;
 import com.sun.javafx.geom.Vec2f;
 import com.sun.javafx.geom.Vec3f;
 
 /**
  * Utility routines for dealing with mesh computation.
- * TODO: 3D - This is a direct port of the 3D Mesh prototype.
- *       Need to rename members and methods.
- *       This code is poorly written and performance badly on Java.
- *       We should replace it with an implementation that is well suit for Java
- *       and is maintainable.
- * JIRA ID: RT-29542 - FX 8 3D: Mesh computation code needs major clean up or redo
  */
 class MeshUtil {
 
-    static final float normalWeldCos  = 0.9952f; // cos(5.6)
-    static final float tangentWeldCos = 0.866f; // cos(30)
-    static final float gUVParralel    = 0.9988f; // cos(2.8125);
-    static final float Cos1Degree     = 0.9998477f;
-    static final float bigEnoughNorma2 = 1.f/16;
+    static final float NORMAL_WELD_COS = 0.9952f; // cos(5.6)
+    static final float TANGENT_WELD_COS = 0.866f; // cos(30)
+    static final float G_UV_PARALLEL = 0.9988f; // cos(2.8125)
+    static final float COS_1_DEGREE = 0.9998477f;
+    static final float BIG_ENOUGH_NORMA2 = 0.0625f; // 1.f/16
     static final double PI = 3.1415926535897932384626433832795;
-    static final float invSqrt2 = 0.7071067812f;
-    static final float DEAD_FACE = 1.f/1024/1024/1024/1024;
-    static final float magicSmall = (float) 1E-10; // 0.000001;
+    static final float INV_SQRT2 = 0.7071067812f;
+    static final float DEAD_FACE = 9.094947E-13f; // 1.f/1024/1024/1024/1024
+    static final float MAGIC_SMALL = 1E-10f; // 0.000001
+    static final float COS110 = -0.33333334f; // -1.f / 3
 
     private MeshUtil() {
     }
@@ -56,55 +52,38 @@
         return areaSquared < DEAD_FACE;
     }
 
-    static boolean isDeadFace(int f[]) {
+    static boolean isDeadFace(int[] f) {
         return f[0] == f[1] || f[1] == f[2] || f[2] == f[0];
     }
 
     static boolean isNormalAlmostEqual(Vec3f n1, Vec3f n2) {
-        return n1.dot(n2) >= Cos1Degree;
+        return n1.dot(n2) >= COS_1_DEGREE;
     }
 
-    static boolean isTangentOkToWeld(Vec3f t1[], Vec3f t2[]) {
-        return t1[0].dot(t2[0]) >= normalWeldCos &&
-                t1[1].dot(t2[1]) >= tangentWeldCos &&
-                t1[2].dot(t2[2]) >= tangentWeldCos;
-    }
-
-    static boolean isTangetGoodAfterWeld(Vec3f t1[], Vec3f t2[]) {
-
-        return t1[0].dot(t2[0]) >= normalWeldCos &&
-                t1[1].dot(t2[1]) >= tangentWeldCos &&
-                t1[2].dot(t2[2]) >= tangentWeldCos;
+    static boolean isTangentOk(Vec3f[] t1, Vec3f[] t2) {
+        return t1[0].dot(t2[0]) >= NORMAL_WELD_COS
+                && t1[1].dot(t2[1]) >= TANGENT_WELD_COS
+                && t1[2].dot(t2[2]) >= TANGENT_WELD_COS;
     }
 
     static boolean isNormalOkAfterWeld(Vec3f normalSum) {
-        //return normalSum.Norma2() > bigEnoughNorma2;
-        return normalSum.dot(normalSum) > bigEnoughNorma2;
+        return normalSum.dot(normalSum) > BIG_ENOUGH_NORMA2;
     }
 
-    // we summ all tangets spaces inside sm group and test is if still ok ...
-    static boolean isTangetGoodAfterWeld(Vec3f nSum[]) {
-        return isNormalOkAfterWeld(nSum[0])
-                && isNormalOkAfterWeld(nSum[1])
-                && isNormalOkAfterWeld(nSum[2]);
+    /*
+     * Sum all tangets spaces inside sm group and test is if still ok
+     */
+    static boolean isTangentOK(Vec3f[] nSum) {
+        return isTangentOk(nSum, nSum);
     }
 
-    // check for normals in one smoothing group,
-    // and remove points from the group if they are opposite looking
-    // in order to prevent a normal to be zero in one SM group
-    // opposite looking = angle more then 110 degrees
-    static boolean isOppositeLookingNormals(Vec3f n1[], Vec3f n2[]) {
-        float cos110 = -1.f / 3;
+    static boolean isOppositeLookingNormals(Vec3f[] n1, Vec3f[] n2) {
         float cosPhi = n1[0].dot(n2[0]);
-        return cosPhi < cos110;
+        return cosPhi < COS110;
     }
 
     static float fabs(float x) {
-        return x >= 0 ? x : -x;
-    }
-
-    static boolean _AssertSmall(float x) {
-        return fabs(x) < (1 - Cos1Degree);
+        return x < 0 ? -x : x;
     }
 
     // Note: b will be modified to return the result and a remains unchanged.
@@ -114,7 +93,7 @@
         b.cross(b, a);
     }
 
-    static void orthogonalizeTB(Vec3f norm[]) {
+    static void orthogonalizeTB(Vec3f[] norm) {
         // N,T,B:  N preserved, T and B get orthogonalized to N
         // N = norm[0], T = norm[1] and B = norm[2]
         getOrt(norm[0], norm[1]);
@@ -123,166 +102,220 @@
         norm[2].normalize();
     }
 
-    static boolean computeUVNormalized( Vec3f pa, Vec3f pb, Vec3f pc,
-            Vec2f ta, Vec2f tb, Vec2f tc, Vec3f u, Vec3f v) {
-        if (MeshUtil.computeTangBinorm(pa, pb, pc, ta, tb, tc, u, v)) {
-            u.normalize();
-            v.normalize();
-            return true;
-        }
-        return false;
-    }
+    static void computeTBNNormalized(Vec3f pa, Vec3f pb, Vec3f pc,
+            Vec2f ta, Vec2f tb, Vec2f tc, Vec3f[] norm) {
+        MeshTempState instance = MeshTempState.getInstance();
+        Vec3f n = instance.vec3f1;
+        Vec3f v1 = instance.vec3f2;
+        Vec3f v2 = instance.vec3f3;
 
-    static boolean computeTangBinorm(Vec3f pa, Vec3f pb, Vec3f pc,
-            Vec2f ta, Vec2f tb, Vec2f tc, Vec3f t, Vec3f b) {
+        // compute Normal |(v1-v0)X(v2-v0)|
+        v1.sub(pb, pa);
+        v2.sub(pc, pa);
+        n.cross(v1, v2);
+        norm[0].set(n);
+        norm[0].normalize(); // TODO: make sure each triangle area (size) will be considered
 
-        Vec3f v1 = new Vec3f(0, tb.x - ta.x, tb.y - ta.y);
-        Vec3f v2 = new Vec3f(0, tc.x - ta.x, tc.y - ta.y);
+        v1.set(0, tb.x - ta.x, tb.y - ta.y);
+        v2.set(0, tc.x - ta.x, tc.y - ta.y);
 
         if (v1.y * v2.z == v1.z * v2.y) {
-            return false;
+            MeshUtil.generateTB(pa, pb, pc, norm);
+            return;
         }
 
-        Vec3f n = new Vec3f();
+        // compute Tangent and Binomal
         v1.x = pb.x - pa.x;
         v2.x = pc.x - pa.x;
         n.cross(v1, v2);
-        t.x = -n.y / n.x;
-        b.x = -n.z / n.x;
+        norm[1].x = -n.y / n.x;
+        norm[2].x = -n.z / n.x;
 
         v1.x = pb.y - pa.y;
         v2.x = pc.y - pa.y;
         n.cross(v1, v2);
-        t.y = -n.y / n.x;
-        b.y = -n.z / n.x;
+        norm[1].y = -n.y / n.x;
+        norm[2].y = -n.z / n.x;
 
         v1.x = pb.z - pa.z;
         v2.x = pc.z - pa.z;
         n.cross(v1, v2);
-        t.z = -n.y / n.x;
-        b.z = -n.z / n.x;
+        norm[1].z = -n.y / n.x;
+        norm[2].z = -n.z / n.x;
 
-        return true;
+        norm[1].normalize();
+        norm[2].normalize();
     }
 
-    // fix TB if T and B go almost in parralel
-    // T (ntb[1]) and B (ntb[2]) is almost parallel
-    // lets invent something artificial in NTB
-    // this function assumes that T and B are normalized
-    static void fixParrallelTB(Vec3f ntb[]) {
-        Vec3f median = new Vec3f(ntb[1]);
-        median.add(ntb[2]);
-        Vec3f ort = new Vec3f();
+    /*
+     * Fix TB if T and B go almost in parralel.
+     * If T (ntb[1]) and B (ntb[2]) is almost parallel, invent something
+     * artificial in NTB.
+     * 
+     * This method assumes that T and B are normalized.
+     */
+    static void fixParallelTB(Vec3f[] ntb) {
+        MeshTempState instance = MeshTempState.getInstance();
+        Vec3f median = instance.vec3f1;
+        median.add(ntb[1], ntb[2]);
+        Vec3f ort = instance.vec3f2;
         ort.cross(ntb[0], median);
         median.normalize();
         ort.normalize();
 
         //ntb[1] = (median + ort) * invSqrt2;
-        ntb[1].set(median);
-        ntb[1].add(ort);
-        ntb[1].mul(invSqrt2);
+        ntb[1].add(median, ort);
+        ntb[1].mul(INV_SQRT2);
 
         //ntb[2] = (median - ort) * invSqrt2;
-        ntb[2].set(median);
-        ntb[2].sub(ort);
-        ntb[2].mul(invSqrt2);
-//        testOrthoNorm(ntb[0], ntb[1], ntb[2]);
+        ntb[2].sub(median, ort);
+        ntb[2].mul(INV_SQRT2);
     }
 
-    // generate artificial tangent for un-textured face
-    static void generateTB(Vec3f v0, Vec3f v1, Vec3f v2, Vec3f ntb[]) {
-        // Vec3f a = v1-v0, b = v2-v0;
-        Vec3f a = new Vec3f(v1);
-        a.sub(v0);
-        Vec3f b = new Vec3f(v2);
-        b.sub(v0);
+    /*
+     * Generate artificial tangent for un-textured face
+     */
+    static void generateTB(Vec3f v0, Vec3f v1, Vec3f v2, Vec3f[] ntb) {
+        MeshTempState instance = MeshTempState.getInstance();
+        Vec3f a = instance.vec3f1;
+        a.sub(v1, v0);
+        Vec3f b = instance.vec3f2;
+        b.sub(v2, v0);
 
         if (a.dot(a) > b.dot(b)) {
             ntb[1] = a;
-            ntb[1].normalize();
+            ntb[1].normalize(); // TODO: make sure each triangle area (size) will be considered
             ntb[2].cross(ntb[0], ntb[1]);
         } else {
             ntb[2] = b;
-            ntb[2].normalize();
+            ntb[2].normalize(); // TODO: make sure each triangle area (size) will be considered
             ntb[1].cross(ntb[2], ntb[0]);
         }
     }
 
     static double clamp(double x, double min, double max) {
-        return x < max ? x > min ? x : min : max;
+        return x < max ? (x > min ? x : min) : max;
     }
 
-    static void fixTSpace(Vec3f norm[]) {
+    static void fixTSpace(Vec3f[] norm) {
+        float nNorm = norm[0].length();
 
-        float N_norma = norm[0].length();
-
-        Vec3f n1 = new Vec3f(norm[1]);
-        Vec3f n2 = new Vec3f(norm[2]);
+        MeshTempState instance = MeshTempState.getInstance();
+        Vec3f n1 = instance.vec3f1;
+        n1.set(norm[1]);
+        Vec3f n2 = instance.vec3f2;
+        n2.set(norm[2]);
         getOrt(norm[0], n1);
         getOrt(norm[0], n2);
 
-        float l1 = n1.length();
-        float l2 = n2.length();
+        float n1Length = n1.length();
+        float n2Length = n2.length();
 
-//        System.err.println("** norm[0] = " + norm[0]);
-//        System.err.println("** n1 = " + n1);
-//        System.err.println("** n2 = " + n2);
-
-        double cosPhi = (n1.dot(n2)) / (l1 * l2);
-
-        Vec3f e1, e2;
+        double cosPhi = (n1.dot(n2)) / (n1Length * n2Length);
+        Vec3f e1 = instance.vec3f3;
+        Vec3f e2 = instance.vec3f4;
 
         if (fabs((float) cosPhi) > 0.998) {
-            // Vec3f n2fix = (N^n1).Normalize();
-            Vec3f n2fix = new Vec3f();
+            Vec3f n2fix = instance.vec3f5;
             n2fix.cross(norm[0], n1);
             n2fix.normalize();
 
-            e2 = new Vec3f(n2fix);
+            e2.set(n2fix);
             if (n2fix.dot(n2) < 0) {
                 e2.mul(-1);
             }
-            e1 = new Vec3f(n1);
-            e1.mul(1f / l1);
-//            System.err.println("(1) e1 = " + e1);
-//            System.err.println("(1) e2 = " + e2);
+            e1.set(n1);
+            e1.mul(1f / n1Length);
         } else {
             double phi = Math.acos(clamp(cosPhi, -1, 1));
             double alpha = (PI * 0.5 - phi) * 0.5;
-            Vec2f e1_local = new Vec2f((float) Math.sin(alpha), (float) Math.cos(alpha));
-            Vec2f e2_local = new Vec2f((float) Math.sin(alpha + phi), (float) Math.cos(alpha + phi));
+            Vec2f e1Local = instance.vec2f1;
+            e1Local.set((float) Math.sin(alpha), (float) Math.cos(alpha));
+            Vec2f e2Local = instance.vec2f2;
+            e2Local.set((float) Math.sin(alpha + phi), (float) Math.cos(alpha + phi));
 
-            Vec3f n1T = new Vec3f(n2);
+            Vec3f n1T = instance.vec3f5;
+            n1T.set(n2);
             getOrt(n1, n1T);
-            float l_n1T = n1T.length();
+            float n1TLength = n1T.length();
 
             // e1 = float(e1_local.y/l1) * n1 - float(e1_local.x/l_n1T) * n1T;
-            e1 = new Vec3f(n1);
-            e1.mul(e1_local.y / l1);
+            e1.set(n1);
+            e1.mul(e1Local.y / n1Length);
 
-            Vec3f n1TT = new Vec3f(n1T);
-            n1TT.mul(e1_local.x / l_n1T);
+            Vec3f n1TT = instance.vec3f6;
+            n1TT.set(n1T);
+            n1TT.mul(e1Local.x / n1TLength);
             e1.sub(n1TT);
 
             // e2 = float(e2_local.y/l1) * n1 + float(e2_local.x/l_n1T) * n1T;
-            e2 = new Vec3f(n1);
-            e2.mul(e2_local.y / l1);
+            e2.set(n1);
+            e2.mul(e2Local.y / n1Length);
 
             // Recycle n1TT for temp computation
             n1TT.set(n1T);
-            n1TT.mul(e2_local.x / l_n1T);
+            n1TT.mul(e2Local.x / n1TLength);
             e2.add(n1TT);
 
-            float e1_dot_n1 = e1.dot(n1);
-            float e2_dot_n2 = e2.dot(n2);
-//            System.err.println("(2) e1 = " + e1);
-//            System.err.println("(2) e2 = " + e2);
-            assert ((e1_dot_n1 / l1 - e2_dot_n2 / l2) < 0.001);
+            float e1DotN1 = e1.dot(n1);
+            float e2DotN2 = e2.dot(n2);
+            assert ((e1DotN1 / n1Length - e2DotN2 / n2Length) < 0.001);
         }
 
         norm[1].set(e1);
         norm[2].set(e2);
-        norm[0].mul(1.f / N_norma);
+        norm[0].mul(1f / nNorm);
     }
 
+    static void buildQuat(Vec3f[] tm, Quat4f quat) {
+        MeshTempState instance = MeshTempState.getInstance();
+        float[][] m = instance.matrix;
+        float[] tmp = instance.vector;
+
+        for (int i = 0; i < 3; i++) {
+            m[i][0] = tm[i].x;
+            m[i][1] = tm[i].y;
+            m[i][2] = tm[i].z;
+        }
+
+        float trace = m[0][0] + m[1][1] + m[2][2];
+
+        if (trace > 0) {
+            float s = (float) Math.sqrt(trace + 1.0f);
+            float t = 0.5f / s;
+            quat.w = 0.5f * s;
+            quat.x = (m[1][2] - m[2][1]) * t;
+            quat.y = (m[2][0] - m[0][2]) * t;
+            quat.z = (m[0][1] - m[1][0]) * t;
+
+        } else {
+            int[] next = {1, 2, 0};
+            int i = 0;
+
+            if (m[1][1] > m[0][0]) {
+                i = 1;
+            }
+            if (m[2][2] > m[i][i]) {
+                i = 2;
+            }
+
+            int j = next[i], k = next[j];
+            float s = (float) Math.sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0f);
+
+            if (m[j][k] < m[k][j]) {
+                s = -s;
+            }
+
+            float t = 0.5f / s;
+
+            tmp[i] = 0.5f * s;
+            quat.w = (m[j][k] - m[k][j]) * t;
+            tmp[j] = (m[i][j] + m[j][i]) * t;
+            tmp[k] = (m[i][k] + m[k][i]) * t;
+            quat.x = tmp[0];
+            quat.y = tmp[1];
+            quat.z = tmp[2];
+        }
+    }
 }
+
--- a/prism-common/src/com/sun/prism/impl/MeshVertex.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-common/src/com/sun/prism/impl/MeshVertex.java	Mon Jun 24 16:02:27 2013 -0700
@@ -29,216 +29,140 @@
 
 /**
  * TODO: 3D - Need documentation
- * Part of MeshBuildTB.cc (see MVertex)
  * Utility routines for dealing with mesh computation.
- * TODO: 3D - This is a direct port of the 3D Mesh prototype.
- *       Need to rename members and methods.
- *       This code is poorly written and performance badly on Java.
- *       We should replace it with an implementation that is well suit for Java
- *       and is maintainable.
- * JIRA ID: RT-29542 - FX 8 3D: Mesh computation code needs major clean up or redo
  */
 class MeshVertex {
 
-    // TODO: This is a direct port of the 3D Mesh prototype.
-    //       Need to rename members and methods
-    static final int idxUndef = -1;
-    static final int idxSetSmooth = -2;
-    static final int idxUnite = -3;
-
-    boolean initiazed;
     int smGroup;
-    Vec3f norm[] = null;
-    boolean valid;
-    int tIndex;
-    int fIndex;
-    int pIdx;
+    int pVert; // vertexBuffer
+    int tVert; // vertexBuffer
+    int fIdx;
+    int index; // indexBuffer
+    Vec3f[] norm; // {N, T, B}
     MeshVertex next = null;
+    
+    static final int IDX_UNDEFINED = -1;
+    static final int IDX_SET_SMOOTH = -2;
+    static final int IDX_UNITE = -3;
 
     MeshVertex() {
-        pIdx = idxUndef;
-        norm = new Vec3f[3];  //N T B
+        norm = new Vec3f[3];
         for (int i = 0; i < norm.length; i++) {
             norm[i] = new Vec3f();
         }
-        next = null;
     }
 
-    private static boolean areNormalsUnique(MeshVertex v, MeshVertex head) {
-        for (int sm = v.smGroup; head != v; head = head.next) {
-            if ( head.smGroup == sm
-                    && MeshUtil.isNormalAlmostEqual(v.norm[0], head.norm[0])) {
-                return false;
-            }
-        }
-        return true;
-    }
+    static void avgSmNormals(MeshVertex v) {
+        Vec3f normalSum = MeshTempState.getInstance().vec3f1;
+        for (; v != null; v = v.next) {
+            if (v.index == IDX_UNDEFINED) {
+                normalSum.set(v.norm[0]);
+                int sm = v.smGroup;
 
-    // calculate average normal for one smoothing group
-    static void makeSmNormal(MeshVertex v) {
-        Vec3f normalSum = new Vec3f(v.norm[0]);
-        int sm = v.smGroup;
+                for (MeshVertex i = v.next; i != null; i = i.next) {
+                    if (i.smGroup == sm) {
+                        assert (i.index == IDX_UNDEFINED);
+                        i.index = IDX_SET_SMOOTH;
+                        normalSum.add(i.norm[0]);
+                    }
+                }
 
-        for (MeshVertex i = v.next; i != null; i = i.next) {
-            if (i.smGroup == sm && areNormalsUnique(i, v)) {
-                normalSum.add(i.norm[0]);
-            }
-        }
-
-        boolean normalOk = false;
-        if (MeshUtil.isNormalOkAfterWeld(normalSum)) {
-            normalSum.normalize();
-            normalOk = true;
-        } else {
-            normalOk = false;
-        }
-
-        for (MeshVertex i = v; i != null; i = i.next) {
-            if (i.smGroup == sm) {
-                assert( i.pIdx == idxUndef );
-                i.pIdx = idxSetSmooth;
-                if (normalOk) {
-                    i.norm[0].set(normalSum);
-                    // orthogonalize and normalize after normal ajustment
-                    MeshUtil.orthogonalizeTB(i.norm);
-                }
-            }
-        }
-    }
-
-    static void makeSmNormals(MeshVertex v) {
-        for (; v != null; v = v.next) {
-            if (v.pIdx == idxUndef) {
-                if (v.smGroup != 0) {
-                    makeSmNormal(v);
-                } else {
-                    v.pIdx = idxSetSmooth;
+                if (MeshUtil.isNormalOkAfterWeld(normalSum)) {
+                    normalSum.normalize();
+                    for (MeshVertex i = v; i != null; i = i.next) {
+                        if (i.smGroup == sm) {
+                            i.norm[0].set(normalSum);
+                        }
+                    }
                 }
             }
         }
     }
 
     static boolean okToWeldVertsTB(MeshVertex a, MeshVertex b) {
-        return a.tIndex == b.tIndex &&
-            MeshUtil.isTangentOkToWeld(a.norm, b.norm);
+        return a.tVert == b.tVert && MeshUtil.isTangentOk(a.norm, b.norm);
     }
 
-    // weld points and assigns new indexes
-    // calculate new TB
-    // return current number of points (last index +1)
-    static int weldWithTB(MeshVertex v, int index, int[] nUnited, boolean valid) {
-        int nU = 0;
-
-        for (;v != null; v = v.next) {
-            if (v.valid == valid && v.pIdx == idxSetSmooth) {
-//                System.err.println("@@@@@ v = ");
-//                dumpInfo(v);
+    /* 
+     * Weld points, assign new indexes and calculate new TB
+     * return current number of points (last index +1)
+     */
+    static int weldWithTB(MeshVertex v, int index) {
+        Vec3f[] nSum = MeshTempState.getInstance().norm;
+        for (; v != null; v = v.next) {
+            if (v.index < 0) {
                 int nuLocal = 0;
-
-                for (MeshVertex q = v; q.next != null; q = q.next) {
-                    for (MeshVertex i = q.next; i != null; i = i.next) {
-                        if (i.pIdx == idxSetSmooth) {
-                            if (okToWeldVertsTB(v, i)) {
-                                i.pIdx = idxUnite;
-                                nuLocal++;
-                            }
-                        }
-                    }
+                for (int i = 0; i < 3; i++) {
+                    nSum[i].set(v.norm[i]);
                 }
-                if (nuLocal != 0) {
-                    v.pIdx = index;
-                    Vec3f nSum[] = new Vec3f[3];
-                    for (int i = 0; i < 3; i++) {
-                        nSum[i] = new Vec3f(v.norm[i]);
-                    }
-
-                    for (MeshVertex i = v.next; i != null; i = i.next) {
-                        if (i.pIdx == idxUnite) {
-                            for (int n = 0; n < 3; ++n) {
-                                nSum[n].add(i.norm[n]);
-                            }
-                        }
-                    }
-
-                    boolean tbOk = MeshUtil.isTangetGoodAfterWeld(nSum);
-
-                    if (tbOk) {
-//                        System.err.println("** nSum[0] = " + nSum[0]);
-//                        System.err.println("** nSum[1] = " + nSum[1]);
-//                        System.err.println("** nSum[2] = " + nSum[2]);
-//                        System.err.println("X 1 X 1 X 1 X");
-                        MeshUtil.fixTSpace(nSum);
-//                        System.err.println("** nSum[0] = " + nSum[0]);
-//                        System.err.println("** nSum[1] = " + nSum[1]);
-//                        System.err.println("** nSum[2] = " + nSum[2]);
-                        v.pIdx = index;
-//                        System.err.println("^^^^^ (1) v = ");
-//                        dumpInfo(v);
-                        for (int n = 0; n != 3; ++n) {
-                            v.norm[n].set(nSum[n]);
-                        }
-//                        System.err.println("^^^^^ (2) v = ");
-//                        dumpInfo(v);
-                        for (MeshVertex i = v.next; i != null; i = i.next) {
-                            if (i.pIdx == idxUnite) {
-//                                System.err.println("%%%%%%%%%%%%% %%%%%%%% %%%%%%%%%%%%");
-                                i.pIdx = index;
-                                i.norm[0].set(0, 0, 0);
-                            }
-                        }
-//                        System.err.println("^^^^^ (3) v = ");
-//                        dumpInfo(v);
-                    } else {
-                        // roll all back, unite failed
-                        nuLocal = 0;
-                        for (MeshVertex i = v.next; i != null; i = i.next) {
-                            if (i.pIdx == idxUnite) {
-                                i.pIdx = idxSetSmooth;
+                for (MeshVertex i = v.next; i != null; i = i.next) {
+                    if (i.index < 0) {
+                        if (okToWeldVertsTB(v, i)) {
+                            i.index = IDX_UNITE;
+                            nuLocal++;
+                            for (int j = 0; j < 3; ++j) {
+                                nSum[j].add(i.norm[j]);
                             }
                         }
                     }
                 }
 
+                if (nuLocal != 0) {
+                    if (MeshUtil.isTangentOK(nSum)) {
+                        MeshUtil.fixTSpace(nSum);
+                        v.index = index;
+                        for (int i = 0; i < 3; ++i) {
+                            v.norm[i].set(nSum[i]);
+                        }
+                        for (MeshVertex i = v.next; i != null; i = i.next) {
+                            if (i.index == IDX_UNITE) {
+                                i.index = index;
+                                i.norm[0].set(0, 0, 0);
+                            }
+                        }
+                    } else {
+                        // roll all back, unite failed
+                        nuLocal = 0;
+                    }
+                }
+
                 if (nuLocal == 0) {
-//                    System.err.println("X 2 X 2 X 2 X");
                     // nothing to join, fix in-place
                     MeshUtil.fixTSpace(v.norm);
-                    v.pIdx = index;
+                    v.index = index;
                 }
-
                 index++;
-                nU += nuLocal;
             }
         }
-
-        nUnited[0] += nU;
         return index;
     }
 
-    static void correctSmIndex(MeshVertex n) {
-        for (MeshVertex l = n; l != null; l = l.next) {
+    static void mergeSmIndexes(MeshVertex n) {
+        for (MeshVertex l = n; l != null;) {
             boolean change = false;
-
             for (MeshVertex i = l.next; i != null; i = i.next) {
                 if (((l.smGroup & i.smGroup) != 0) && (l.smGroup != i.smGroup)) {
                     l.smGroup = i.smGroup | l.smGroup;
                     i.smGroup = l.smGroup;
                     change = true;
                 }
-                if (!change) {
-                    l = l.next;
-                }
+            }
+            if (!change) {
+                l = l.next;
             }
         }
     }
 
-    static void correctSmGroup(MeshVertex n) {
-        correctSmIndex(n);
-
+    /*
+     * Check for normals in one smoothing group and remove points from the group
+     * if they are opposite looking in order to prevent a normal to be zero in
+     * one SM group. Opposite looking normals are normals which angle is more
+     * than 110 degrees.
+     */
+    static void correctSmNormals(MeshVertex n) {
         // remove opposite looking normals from one smoothing group
-
-        for (MeshVertex l = n; l.next != null; l = l.next) {
-            if (l.smGroup == 0) {
+        for (MeshVertex l = n; l != null; l = l.next) {
+            if (l.smGroup != 0) {
                 for (MeshVertex i = l.next; i != null; i = i.next) {
                     if (((i.smGroup & l.smGroup) != 0)
                             && MeshUtil.isOppositeLookingNormals(i.norm, l.norm)) {
@@ -248,47 +172,40 @@
                     }
                 }
             }
-
         }
     }
 
-    // the entry point
-    // make all sm groups
-    static int processVertices(MeshVertex n, int nVerts,
-            int nUnited[]) {
-//        System.err.println("In processVertices (1):");
-//        dumpInfo(n);
-        // assign correct smGroups
-        correctSmGroup(n);
-//        System.err.println("In processVertices (2):");
-//        dumpInfo(n);
-        // assign common normals for smGroups
-        makeSmNormals(n);
-//        System.err.println("In processVertices (3):");
-//        dumpInfo(n);
+    static int processVertices(MeshVertex[] pVerts, int nVertex, 
+            boolean allHardEdges, boolean allSameSmoothing) {
+        int nNewVerts = 0;
+        Vec3f normalSum = MeshTempState.getInstance().vec3f1;
+        for (int i = 0; i < nVertex; ++i) {
+            if (pVerts[i] != null) {
+                if (!allHardEdges) {
+                    if (allSameSmoothing) {
+                        // calculate average normal for one smoothing group                        
+                        normalSum.set(pVerts[i].norm[0]);
+                        for (MeshVertex v = pVerts[i].next; v != null; v = v.next) {
+                            normalSum.add(v.norm[0]);
+                        }
 
-        // process textured faces
-        nVerts = weldWithTB(n, nVerts, nUnited, true);
-//        System.err.println("In processVertices (4) ************ nUnited[0] = " + nUnited[0] + ", nVerts = " + nVerts);
-//        dumpInfo(n);
-
-        // process untextured faces
-        nVerts = weldWithTB(n, nVerts, nUnited, false);
-//        System.err.println("In processVertices (5) ************ nUnited[0] = " + nUnited[0] + ", nVerts = " + nVerts);
-//        dumpInfo(n);
-        return nVerts;
-    }
-
-    // return new index of vertext for i-th face
-    static int getIndex(MeshVertex n, int fi) { // API Call
-        MeshVertex v = n;
-        while (v != null) {
-            if (fi == v.fIndex) {
-                return v.pIdx;
+                        if (MeshUtil.isNormalOkAfterWeld(normalSum)) {
+                            normalSum.normalize();
+                            for (MeshVertex v = pVerts[i]; v != null; v = v.next) {
+                                v.norm[0].set(normalSum);
+                            }
+                        }
+                    } else {
+                        // various Sm
+                        mergeSmIndexes(pVerts[i]);
+                        avgSmNormals(pVerts[i]);
+                    }
+                }
+                // weld points based on texture and assign new indexes
+                nNewVerts = weldWithTB(pVerts[i], nNewVerts);
             }
-            v = v.next;
         }
-        return 0;
+        return nNewVerts;
     }
 
     @Override
@@ -299,14 +216,14 @@
                 + "\tnorm[0] = " + norm[0] + "\n"
                 + "\tnorm[1] = " + norm[1] + "\n"
                 + "\tnorm[2] = " + norm[2] + "\n"
-                + "\tvalid = " + valid + ", tIndex = " + tIndex + ", fIndex = " + fIndex + "\n"
-                + "\tpIdx = " + pIdx + ", initized = " + initiazed + "\n"
+                + "\ttIndex = " + tVert + ", fIndex = " + fIdx + "\n"
+                + "\tpIdx = " + index + "\n"
                 + "\tnext = " + ((next == null) ? next : next.getClass().getName()
                 + "@0x" + Integer.toHexString(next.hashCode())) + "\n";
     }
 
     static void dumpInfo(MeshVertex v) {
-        System.err.println("** dumpInfo: " );
+        System.err.println("** dumpInfo: ");
         for (MeshVertex q = v; q != null; q = q.next) {
             System.err.println(q);
         }
--- a/prism-d3d-native/src/D3DContext.cc	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-d3d-native/src/D3DContext.cc	Mon Jun 24 16:02:27 2013 -0700
@@ -205,11 +205,11 @@
 
 /*
  * Class:     com_sun_prism_d3d_D3DContext
- * Method:    nBuildNativeGeometry
- * Signature: (JJ[F[S)Z
+ * Method:    nBuildNativeGeometryShort
+ * Signature: (JJ[FI[SI)Z
  */
 JNIEXPORT jboolean JNICALL Java_com_sun_prism_d3d_D3DContext_nBuildNativeGeometryShort
-  (JNIEnv *env, jclass, jlong ctx, jlong nativeMesh, jfloatArray vb, jshortArray ib)
+  (JNIEnv *env, jclass, jlong ctx, jlong nativeMesh, jfloatArray vb, jint vbSize, jshortArray ib, jint ibSize)
 {
     TraceLn(NWT_TRACE_INFO, "D3DContext_nBuildNativeGeometryShort");
     D3DMesh *mesh = (D3DMesh *) jlong_to_ptr(nativeMesh);
@@ -219,8 +219,13 @@
     UINT indexBufferSize = env->GetArrayLength(ib);
     USHORT *indexBuffer = (USHORT *) (env->GetPrimitiveArrayCritical(ib, NULL));
 
-    boolean result = mesh->buildBuffers(vertexBuffer, vertexBufferSize,
-            indexBuffer, indexBufferSize);
+    if (vertexBuffer == NULL || indexBuffer == NULL
+            || vbSize < 0 || vbSize > vertexBufferSize
+            || ibSize < 0 || ibSize > indexBufferSize) {
+        return JNI_FALSE;
+    }
+
+    boolean result = mesh->buildBuffers(vertexBuffer, vbSize, indexBuffer, ibSize);
     env->ReleasePrimitiveArrayCritical(ib, indexBuffer, 0);
     env->ReleasePrimitiveArrayCritical(vb, vertexBuffer, 0);
 
@@ -229,11 +234,11 @@
 
 /*
  * Class:     com_sun_prism_d3d_D3DContext
- * Method:    nBuildNativeGeometry
- * Signature: (JJ[F[I)Z
+ * Method:    nBuildNativeGeometryInt
+ * Signature: (JJ[FI[II)Z
  */
 JNIEXPORT jboolean JNICALL Java_com_sun_prism_d3d_D3DContext_nBuildNativeGeometryInt
-  (JNIEnv *env, jclass, jlong ctx, jlong nativeMesh, jfloatArray vb, jintArray ib)
+  (JNIEnv *env, jclass, jlong ctx, jlong nativeMesh, jfloatArray vb, jint vbSize, jintArray ib, jint ibSize)
 {
     TraceLn(NWT_TRACE_INFO, "D3DContext_nBuildNativeGeometryInt");
     D3DMesh *mesh = (D3DMesh *) jlong_to_ptr(nativeMesh);
@@ -243,8 +248,13 @@
     UINT indexBufferSize = env->GetArrayLength(ib);
     UINT *indexBuffer = (UINT *) (env->GetPrimitiveArrayCritical(ib, NULL));
 
-    boolean result = mesh->buildBuffers(vertexBuffer, vertexBufferSize,
-            indexBuffer, indexBufferSize);
+    if (vertexBuffer == NULL || indexBuffer == NULL
+            || vbSize < 0 || vbSize > vertexBufferSize
+            || ibSize < 0 || ibSize > indexBufferSize) {
+        return JNI_FALSE;
+    }
+
+    boolean result = mesh->buildBuffers(vertexBuffer, vbSize, indexBuffer, ibSize);
     env->ReleasePrimitiveArrayCritical(ib, indexBuffer, 0);
     env->ReleasePrimitiveArrayCritical(vb, vertexBuffer, 0);
 
--- a/prism-d3d/src/com/sun/prism/d3d/D3DContext.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-d3d/src/com/sun/prism/d3d/D3DContext.java	Mon Jun 24 16:02:27 2013 -0700
@@ -358,9 +358,9 @@
     private static native long nCreateD3DMesh(long pContext);
     private static native void nReleaseD3DMesh(long pContext, long nativeHandle);
     private static native boolean nBuildNativeGeometryShort(long pContext, long nativeHandle,
-            float vertexBuffer[], short indexBuffer[]);
+            float[] vertexBuffer, int vertexBufferLength, short[] indexBuffer, int indexBufferLength);
     private static native boolean nBuildNativeGeometryInt(long pContext, long nativeHandle,
-            float vertexBuffer[], int indexBuffer[]);
+            float[] vertexBuffer, int vertexBufferLength, int[] indexBuffer, int indexBufferLength);
     private static native long nCreateD3DPhongMaterial(long pContext);
     private static native void nReleaseD3DPhongMaterial(long pContext, long nativeHandle);
     private static native void nSetSolidColor(long pContext, long nativePhongMaterial,
@@ -425,14 +425,16 @@
         nReleaseD3DMesh(pContext, nativeHandle);
     }
 
-    boolean buildNativeGeometry(long nativeHandle, float vertexBuffer[],
-            short indexBuffer[]) {
-        return nBuildNativeGeometryShort(pContext, nativeHandle, vertexBuffer, indexBuffer);
+    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, int vertexBufferLength,
+            short[] indexBuffer, int indexBufferLength) {
+        return nBuildNativeGeometryShort(pContext, nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBuffer, indexBufferLength);
     }
 
-    boolean buildNativeGeometry(long nativeHandle, float vertexBuffer[],
-            int indexBuffer[]) {
-        return nBuildNativeGeometryInt(pContext, nativeHandle, vertexBuffer, indexBuffer);
+    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, int vertexBufferLength,
+            int[] indexBuffer, int indexBufferLength) {
+        return nBuildNativeGeometryInt(pContext, nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBuffer, indexBufferLength);
     }
 
     long createD3DPhongMaterial() {
--- a/prism-d3d/src/com/sun/prism/d3d/D3DMesh.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-d3d/src/com/sun/prism/d3d/D3DMesh.java	Mon Jun 24 16:02:27 2013 -0700
@@ -64,20 +64,17 @@
     }
 
     @Override
-    public boolean buildNativeGeometry() {
-        float vertexBuffer[] = getVertsGM();
-
-        boolean status;
-        if (vertexBuffer.length > (0x10000 * VERTEX_SIZE)) {
-//            System.err.println("** Use int[] for indexBuffer");
-            int indexBuffer[] = getIndexGMInt();
-            status = context.buildNativeGeometry(nativeHandle, vertexBuffer, indexBuffer);
-        } else {
-//            System.err.println("** Use short[] for indexBuffer");
-            short indexBuffer[] = getIndexGMShort();
-            status = context.buildNativeGeometry(nativeHandle, vertexBuffer, indexBuffer);
-        }
-        return status;
+    public boolean buildNativeGeometry(float[] vertexBuffer, int vertexBufferLength,
+            int[] indexBufferInt, int indexBufferLength) {
+        return context.buildNativeGeometry(nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBufferInt, indexBufferLength);
+    }
+    
+    @Override
+    public boolean buildNativeGeometry(float[] vertexBuffer, int vertexBufferLength,
+            short[] indexBufferShort, int indexBufferLength) {
+        return context.buildNativeGeometry(nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBufferShort, indexBufferLength);
     }
 
     static class D3DMeshDisposerRecord implements Disposer.Record {
--- a/prism-es2-native/src/GLContext.c	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-es2-native/src/GLContext.c	Mon Jun 24 16:02:27 2013 -0700
@@ -1698,11 +1698,11 @@
 /*
  * Class:     com_sun_prism_es2_GLContext
  * Method:    nBuildNativeGeometryShort
- * Signature: (JJ[F[S)Z
+ * Signature: (JJ[FI[SI)Z
  */
 JNIEXPORT jboolean JNICALL Java_com_sun_prism_es2_GLContext_nBuildNativeGeometryShort
   (JNIEnv *env, jclass class, jlong nativeCtxInfo, jlong nativeMeshInfo,
-        jfloatArray vbArray, jshortArray ibArray)
+        jfloatArray vbArray, jint vbSize, jshortArray ibArray, jint ibSize)
 {
     GLuint vertexBufferSize;
     GLuint indexBufferSize;
@@ -1727,22 +1727,23 @@
     indexBufferSize = (*env)->GetArrayLength(env, ibArray);
     indexBuffer = (GLushort *) ((*env)->GetPrimitiveArrayCritical(env, ibArray, NULL));
 
-    if ((vertexBuffer == NULL ) || (vertexBufferSize == 0)
-            || (indexBuffer == NULL) || (indexBufferSize == 0)) {
+    if (vertexBuffer == NULL || indexBuffer == NULL
+            || vbSize < 0 || vbSize > vertexBufferSize
+            || ibSize < 0 || ibSize > indexBufferSize) {
         status = JNI_FALSE;
     }
 
     if (status) {
         // Initialize vertex buffer
         ctxInfo->glBindBuffer(GL_ARRAY_BUFFER, meshInfo->vboIDArray[MESH_VERTEXBUFFER]);
-        ctxInfo->glBufferData(GL_ARRAY_BUFFER, vertexBufferSize * sizeof (GLfloat),
+        ctxInfo->glBufferData(GL_ARRAY_BUFFER, vbSize * sizeof (GLfloat),
                 vertexBuffer, GL_STATIC_DRAW);
 
         // Initialize index buffer
         ctxInfo->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshInfo->vboIDArray[MESH_INDEXBUFFER]);
-        ctxInfo->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize * sizeof (GLushort),
+        ctxInfo->glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibSize * sizeof (GLushort),
                 indexBuffer, GL_STATIC_DRAW);
-        meshInfo->indexBufferSize = indexBufferSize;
+        meshInfo->indexBufferSize = ibSize;
         meshInfo->indexBufferType = GL_UNSIGNED_SHORT;
 
         // Unbind VBOs
@@ -1763,11 +1764,11 @@
 /*
  * Class:     com_sun_prism_es2_GLContext
  * Method:    nBuildNativeGeometryInt
- * Signature: (JJ[F[I)Z
+ * Signature: (JJ[FI[II)Z
  */
 JNIEXPORT jboolean JNICALL Java_com_sun_prism_es2_GLContext_nBuildNativeGeometryInt
-  (JNIEnv *env, jclass class, jlong nativeCtxInfo, jlong nativeMeshInfo,
-        jfloatArray vbArray, jintArray ibArray)
+(JNIEnv *env, jclass class, jlong nativeCtxInfo, jlong nativeMeshInfo,
+        jfloatArray vbArray, jint vbSize, jintArray ibArray, jint ibSize)
 {
     GLuint vertexBufferSize;
     GLuint indexBufferSize;
@@ -1792,22 +1793,23 @@
     indexBufferSize = (*env)->GetArrayLength(env, ibArray);
     indexBuffer = (GLuint *) ((*env)->GetPrimitiveArrayCritical(env, ibArray, NULL));
 
-    if ((vertexBuffer == NULL ) || (vertexBufferSize == 0)
-            || (indexBuffer == NULL) || (indexBufferSize == 0)) {
+    if (vertexBuffer == NULL || indexBuffer == NULL
+            || vbSize < 0 || vbSize > vertexBufferSize
+            || ibSize < 0 || ibSize > indexBufferSize) {
         status = JNI_FALSE;
     }
 
     if (status) {
         // Initialize vertex buffer
         ctxInfo->glBindBuffer(GL_ARRAY_BUFFER, meshInfo->vboIDArray[MESH_VERTEXBUFFER]);
-        ctxInfo->glBufferData(GL_ARRAY_BUFFER, vertexBufferSize * sizeof (GLfloat),
+        ctxInfo->glBufferData(GL_ARRAY_BUFFER, vbSize * sizeof (GLfloat),
                 vertexBuffer, GL_STATIC_DRAW);
 
         // Initialize index buffer
         ctxInfo->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshInfo->vboIDArray[MESH_INDEXBUFFER]);
-        ctxInfo->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize * sizeof (GLuint),
+        ctxInfo->glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibSize * sizeof (GLuint),
                 indexBuffer, GL_STATIC_DRAW);
-        meshInfo->indexBufferSize = indexBufferSize;
+        meshInfo->indexBufferSize = ibSize;
         meshInfo->indexBufferType = GL_UNSIGNED_INT;
 
         // Unbind VBOs
--- a/prism-es2/src/com/sun/prism/es2/ES2Context.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-es2/src/com/sun/prism/es2/ES2Context.java	Mon Jun 24 16:02:27 2013 -0700
@@ -396,12 +396,16 @@
         glContext.releaseES2Mesh(nativeHandle);
     }
 
-    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, short[] indexBuffer) {
-        return glContext.buildNativeGeometry(nativeHandle, vertexBuffer, indexBuffer);
+    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer,
+            int vertexBufferLength, short[] indexBuffer, int indexBufferLength) {
+        return glContext.buildNativeGeometry(nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBuffer, indexBufferLength);
     }
 
-    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, int[] indexBuffer) {
-        return glContext.buildNativeGeometry(nativeHandle, vertexBuffer, indexBuffer);
+    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer,
+            int vertexBufferLength, int[] indexBuffer, int indexBufferLength) {
+        return glContext.buildNativeGeometry(nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBuffer, indexBufferLength);
     }
 
     long createES2PhongMaterial() {
--- a/prism-es2/src/com/sun/prism/es2/ES2Mesh.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-es2/src/com/sun/prism/es2/ES2Mesh.java	Mon Jun 24 16:02:27 2013 -0700
@@ -64,20 +64,17 @@
     }
 
     @Override
-    public boolean buildNativeGeometry() {
-        float vertexBuffer[] = getVertsGM();
+    public boolean buildNativeGeometry(float[] vertexBuffer, int vertexBufferLength,
+            int[] indexBufferInt, int indexBufferLength) {
+        return context.buildNativeGeometry(nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBufferInt, indexBufferLength);
+    }
 
-        boolean status;
-        if (vertexBuffer.length > (0x10000 * VERTEX_SIZE)) {
-//            System.err.println("** Use int[] for indexBuffer");
-            int indexBuffer[] = getIndexGMInt();
-            status = context.buildNativeGeometry(nativeHandle, vertexBuffer, indexBuffer);
-        } else {
-//            System.err.println("** Use short[] for indexBuffer");
-            short indexBuffer[] = getIndexGMShort();
-            status = context.buildNativeGeometry(nativeHandle, vertexBuffer, indexBuffer);
-        }
-        return status;
+    @Override
+    public boolean buildNativeGeometry(float[] vertexBuffer, int vertexBufferLength,
+            short[] indexBufferShort, int indexBufferLength) {
+        return context.buildNativeGeometry(nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBufferShort, indexBufferLength);
     }
 
     static class ES2MeshDisposerRecord implements Disposer.Record {
--- a/prism-es2/src/com/sun/prism/es2/GLContext.java	Mon Jun 24 18:03:10 2013 -0400
+++ b/prism-es2/src/com/sun/prism/es2/GLContext.java	Mon Jun 24 16:02:27 2013 -0700
@@ -207,9 +207,9 @@
     private static native long nCreateES2Mesh(long nativeCtxInfo);
     private static native void nReleaseES2Mesh(long nativeCtxInfo, long nativeHandle);
     private static native boolean nBuildNativeGeometryShort(long nativeCtxInfo, long nativeHandle,
-            float vertexBuffer[], short indexBuffer[]);
+            float[] vertexBuffer, int vertexBufferLength, short[] indexBuffer, int indexBufferLength);
     private static native boolean nBuildNativeGeometryInt(long nativeCtxInfo, long nativeHandle,
-            float vertexBuffer[], int indexBuffer[]);
+            float[] vertexBuffer, int vertexBufferLength, int[] indexBuffer, int indexBufferLength);
     private static native long nCreateES2PhongMaterial(long nativeCtxInfo);
     private static native void nReleaseES2PhongMaterial(long nativeCtxInfo, long nativeHandle);
     private static native void nSetSolidColor(long nativeCtxInfo, long nativePhongMaterial,
@@ -649,12 +649,16 @@
         nReleaseES2Mesh(nativeCtxInfo, nativeHandle);
     }
 
-    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, short[] indexBuffer) {
-        return nBuildNativeGeometryShort(nativeCtxInfo, nativeHandle, vertexBuffer, indexBuffer);
+    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer,
+            int vertexBufferLength, short[] indexBuffer, int indexBufferLength) {
+        return nBuildNativeGeometryShort(nativeCtxInfo, nativeHandle,
+                vertexBuffer, vertexBufferLength, indexBuffer, indexBufferLength);
     }
 
-    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer, int[] indexBuffer) {
-        return nBuildNativeGeometryInt(nativeCtxInfo, nativeHandle, vertexBuffer, indexBuffer);
+    boolean buildNativeGeometry(long nativeHandle, float[] vertexBuffer,
+            int vertexBufferLength, int[] indexBuffer, int indexBufferLength) {
+        return nBuildNativeGeometryInt(nativeCtxInfo, nativeHandle, vertexBuffer,
+                vertexBufferLength, indexBuffer, indexBufferLength);
     }
 
     long createES2PhongMaterial() {