aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/GeometryArrayRetained.java
diff options
context:
space:
mode:
authorJulien Gouesse <[email protected]>2015-11-19 20:45:53 +0100
committerJulien Gouesse <[email protected]>2015-11-19 20:45:53 +0100
commita18c3b0789bfc24b49dbaf41c2390159bc683afc (patch)
treeb5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/GeometryArrayRetained.java
parent264608060948a634b53a13ee96ed07527eb07340 (diff)
parent7a2e20caac9db6f789a7b3fab344b9758af45335 (diff)
Gets Harvey's changes
Diffstat (limited to 'src/javax/media/j3d/GeometryArrayRetained.java')
-rw-r--r--src/javax/media/j3d/GeometryArrayRetained.java11213
1 files changed, 11213 insertions, 0 deletions
diff --git a/src/javax/media/j3d/GeometryArrayRetained.java b/src/javax/media/j3d/GeometryArrayRetained.java
new file mode 100644
index 0000000..53a691a
--- /dev/null
+++ b/src/javax/media/j3d/GeometryArrayRetained.java
@@ -0,0 +1,11213 @@
+/*
+ * Copyright 1996-2008 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package javax.media.j3d;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import javax.vecmath.Color3b;
+import javax.vecmath.Color3f;
+import javax.vecmath.Color4b;
+import javax.vecmath.Color4f;
+import javax.vecmath.Point2d;
+import javax.vecmath.Point2f;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point3f;
+import javax.vecmath.Point4d;
+import javax.vecmath.Point4f;
+import javax.vecmath.TexCoord2f;
+import javax.vecmath.TexCoord3f;
+import javax.vecmath.TexCoord4f;
+import javax.vecmath.Vector3d;
+import javax.vecmath.Vector3f;
+
+
+/**
+ * The GeometryArray object contains arrays of positional coordinates,
+ * colors, normals and/or texture coordinates that describe
+ * point, line, or surface geometry. It is extended to create
+ * the various primitive types (e.g., lines, triangle_strips, etc.)
+ */
+
+abstract class GeometryArrayRetained extends GeometryRetained{
+
+ // XXXX: Memory footprint reduction. Should have separate object to
+ // to contain specific data such as a ByRef object for
+ // all ByRef related data. So that incases where no
+ // ByRef is needed, the ByRef object reference is
+ // set to null. Hence saving memory!
+ // Need object such as Texture, D3d and ByRef ...
+ //
+
+
+ // Contains a bitset indicating which components are present
+ int vertexFormat;
+
+ // Whether this geometry was ever rendered as transparent
+ int c4fAllocated = 0;
+
+ // Total Number of vertices
+ int vertexCount;
+
+ // number of vertices used in rendering
+ int validVertexCount;
+
+ // The vertex data in packed format
+ float vertexData[];
+
+ // vertex data in packed format for each screen in multi-screen situation
+ // if alpha values of each vertex are to be updated
+ private float mvertexData[][];
+
+ //
+ // The following offset/stride values are internally computed
+ // from the format
+ //
+
+ // Stride (in words) from one vertex to the next
+ int stride;
+
+ // Stride (in words) from one texture coordinate to the next
+ int texCoordStride;
+
+ // Offset (in words) within each vertex of the coordinate position
+ int coordinateOffset;
+
+ // Offset (in words) within each vertex of the normal
+ int normalOffset;
+
+ // Offset (in words) within each vertex of the color
+ int colorOffset;
+
+ // Offset (in words) within each vertex of the texture coordinate
+ int textureOffset;
+
+ // Offset (in words) within each vertex of each vertex attribute
+ int[] vertexAttrOffsets;
+
+ // Stride (size) of all vertex attributes
+ int vertexAttrStride;
+
+ // alpha value for transparency and texture blending
+ private float[] lastAlpha = new float[1];
+ float lastScreenAlpha = -1;
+
+ int colorChanged = 0;
+
+ // byte to float scale factor
+ static final float ByteToFloatScale = 1.0f/255.0f;
+
+ // float to byte scale factor
+ static final float FloatToByteScale = 255.0f;
+
+ // Set flag indicating that we are in the updater. This flag
+ // can be used by the various setRef methods to inhibit any
+ // update messages
+ boolean inUpdater = false;
+
+// Array List used for messages
+ArrayList<GeometryAtom> gaList = new ArrayList<GeometryAtom>(1);
+
+ // Target threads to be notified when morph changes
+ static final int targetThreads = (J3dThread.UPDATE_RENDER |
+ J3dThread.UPDATE_GEOMETRY);
+
+ // used for byReference geometry
+ float[] floatRefCoords = null;
+ double[] doubleRefCoords = null;
+ Point3d[] p3dRefCoords = null;
+ Point3f[] p3fRefCoords = null;
+
+ // Used for NIO buffer geometry
+ J3DBuffer coordRefBuffer = null;
+ FloatBuffer floatBufferRefCoords = null;
+ DoubleBuffer doubleBufferRefCoords = null;
+
+ // Initial index to use for rendering
+ int initialCoordIndex = 0;
+ int initialColorIndex = 0;
+ int initialNormalIndex = 0;
+ int[] initialTexCoordIndex = null;
+ int[] initialVertexAttrIndex = null;
+ int initialVertexIndex = 0;
+
+
+ // used for byReference colors
+ float[] floatRefColors = null;
+ byte[] byteRefColors = null;
+ Color3f[] c3fRefColors = null;
+ Color4f[] c4fRefColors = null;
+ Color3b[] c3bRefColors = null;
+ Color4b[] c4bRefColors = null;
+
+ // Used for NIO buffer colors
+ J3DBuffer colorRefBuffer = null;
+ FloatBuffer floatBufferRefColors = null;
+ ByteBuffer byteBufferRefColors = null;
+
+ // flag to indicate if the "by reference" component is already set
+ int vertexType = 0;
+ static final int PF = 0x1;
+ static final int PD = 0x2;
+ static final int P3F = 0x4;
+ static final int P3D = 0x8;
+ static final int VERTEX_DEFINED = PF | PD | P3F | P3D;
+
+ static final int CF = 0x10;
+ static final int CUB = 0x20;
+ static final int C3F = 0x40;
+ static final int C4F = 0x80;
+ static final int C3UB = 0x100;
+ static final int C4UB = 0x200;
+ static final int COLOR_DEFINED = CF | CUB | C3F | C4F| C3UB | C4UB;
+
+ static final int NF = 0x400;
+ static final int N3F = 0x800;
+ static final int NORMAL_DEFINED = NF | N3F;
+
+ static final int TF = 0x1000;
+ static final int T2F = 0x2000;
+ static final int T3F = 0x4000;
+ static final int TEXCOORD_DEFINED = TF | T2F | T3F;
+
+ static final int AF = 0x8000;
+ static final int VATTR_DEFINED = AF;
+
+ // Flag word indicating the type of by-ref texCoord. We will copy this to
+ // the vertexType field only when the references for all texture coordinate
+ // sets are set to non-null values.
+ private int texCoordType = 0;
+
+ // Flag word indicating the type of by-ref vertex attr. We will copy this to
+ // the vertexType field only when the references for all vertex attrs
+ // are set to non-null values.
+ private int vertexAttrType = 0;
+
+ // flag for execute geometry array when by reference
+ static final int COORD_FLOAT = 0x01;
+ static final int COORD_DOUBLE = 0x02;
+ static final int COLOR_FLOAT = 0x04;
+ static final int COLOR_BYTE = 0x08;
+ static final int NORMAL_FLOAT = 0x10;
+ static final int TEXCOORD_FLOAT = 0x20;
+ static final int VATTR_FLOAT = 0x40;
+
+
+ // used by "by reference" normals
+ float[] floatRefNormals = null;
+ Vector3f[] v3fRefNormals = null;
+
+ // Used for NIO buffer normals
+ J3DBuffer normalRefBuffer = null;
+ FloatBuffer floatBufferRefNormals = null;
+
+ // used for "by reference" vertex attrs
+ float[][] floatRefVertexAttrs = null;
+
+ // Used for NIO buffer vertex attrs
+ J3DBuffer[] vertexAttrsRefBuffer = null;
+ FloatBuffer[] floatBufferRefVertexAttrs = null;
+
+ // used by "by reference" tex coords
+ Object[] refTexCoords = null;
+ TexCoord2f[] t2fRefTexCoords = null;
+ TexCoord3f[] t3fRefTexCoords = null;
+
+ // Used for NIO buffer tex coords
+ J3DBuffer[] refTexCoordsBuffer = null;
+ //FloatBufferWrapper[] floatBufferRefTexCoords = null;
+
+
+ // used by interleaved array
+ float[] interLeavedVertexData = null;
+
+ // used by interleaved NIO buffer
+ J3DBuffer interleavedVertexBuffer = null;
+ FloatBuffer interleavedFloatBufferImpl = null;
+
+ // pointers used, when transparency is turned on
+ // or when its an object such as C3F, P3F etc ..
+ float[] mirrorFloatRefCoords = null;
+ double[] mirrorDoubleRefCoords = null;
+ float[] mirrorFloatRefNormals = null;
+ float[][] mirrorFloatRefVertexAttrs = null;
+ float[] mirrorFloatRefTexCoords = null;
+ Object[] mirrorRefTexCoords = null;
+
+ float[][] mirrorFloatRefColors = new float[1][];
+ byte[][] mirrorUnsignedByteRefColors= new byte[1][];
+ float[][] mirrorInterleavedColorPointer = null;
+
+ // boolean to determine if a mirror was allocated
+ int mirrorVertexAllocated = 0;
+ int mirrorColorAllocated = 0;
+ boolean mirrorNormalAllocated = false;
+
+ // Some dirty bits for GeometryArrays
+ static final int COORDINATE_CHANGED = 0x01;
+ static final int NORMAL_CHANGED = 0x02;
+ static final int COLOR_CHANGED = 0x04;
+ static final int TEXTURE_CHANGED = 0x08;
+ static final int BOUNDS_CHANGED = 0x10;
+ static final int INDEX_CHANGED = 0x20;
+ static final int STRIPCOUNT_CHANGED = 0x40;
+ static final int VATTR_CHANGED = 0x80;
+ static final int VERTEX_CHANGED = COORDINATE_CHANGED |
+ NORMAL_CHANGED |
+ COLOR_CHANGED |
+ TEXTURE_CHANGED |
+ VATTR_CHANGED;
+
+ static final int defaultTexCoordSetMap[] = {0};
+ int texCoordSetCount = 0;
+ int [] texCoordSetMap = null;
+
+ // this array contains offset to the texCoord data for each
+ // texture unit. -1 means no corresponding texCoord data offset
+ int [] texCoordSetMapOffset = null;
+
+ // Vertex attribute information
+ int vertexAttrCount = 0;
+ int[] vertexAttrSizes = null;
+
+
+ // This point to a list of VertexBuffers in a Vector structure
+ // Each element correspond to a D3D context that create this VB.
+ // Note that this GeometryArray can be used by multiple ctx.
+ int dirtyFlag;
+
+ // each bit corresponds to a unique renderer if shared context
+ // or a unique canvas otherwise
+ int resourceCreationMask = 0x0;
+
+ // Fix for Issue 5
+ //
+ // Replace the per-canvas reference count with a per-RenderBin set
+ // of users. The per-RenderBin set of users of this display list
+ // is defined as a HashMap where:
+ //
+ // key = the RenderBin
+ // value = a set of RenderAtomListInfo objects using this
+ // geometry array for display list purposes
+private HashMap<RenderBin, HashSet<RenderAtomListInfo>> dlistUsers = null;
+
+ // timestamp used to create display list. This is either
+ // one per renderer for useSharedCtx, or one per Canvas for non-shared
+ // ctx
+ private long[] timeStampPerDlist = new long[2];
+
+ // Unique display list Id, if this geometry is shared
+ int dlistId = -1;
+ Integer dlistObj = null;
+
+ // A list of pre-defined bits to indicate which component
+ // in this Texture object changed.
+ // static final int DLIST_CREATE_CHANGED = 0x01;
+ static final int INIT_MIRROR_GEOMETRY = 0x02;
+
+
+// A list of Universes that this Geometry is referenced in Morph from
+ArrayList<VirtualUniverse> morphUniverseList = null;
+
+// A list of ArrayLists which contain all the MorphRetained objects
+// refering to this geometry. Each list corresponds to the universe
+// above.
+ArrayList<ArrayList<MorphRetained>> morphUserLists = null;
+
+ // The following variables are only used in compile mode
+
+ // Offset of a geometry array into the merged array
+ int[] geoOffset;
+
+ // vertexcount of a geometry array in a merge array
+ int[] compileVcount;
+
+ boolean isCompiled = false;
+
+ boolean isShared = false;
+
+ IndexedGeometryArrayRetained cloneSourceArray = null;
+
+ static final double EPS = 1.0e-13;
+
+ GeometryArrayRetained() {
+ dirtyFlag = INDEX_CHANGED|VERTEX_CHANGED;
+ lastAlpha[0] = 1.0f;
+ }
+
+
+ @Override
+ void setLive(boolean inBackgroundGroup, int refCount) {
+ dirtyFlag = VERTEX_CHANGED|INDEX_CHANGED;
+ isEditable = !isWriteStatic();
+ super.doSetLive(inBackgroundGroup, refCount);
+ super.markAsLive();
+ // Send message to RenderingAttribute structure to obtain a dlistId
+ // System.err.println("Geometry - "+this+"refCount = "+this.refCount);
+ if (this.refCount > 1) {
+ // Send to rendering attribute structure,
+ /*
+ J3dMessage createMessage = new J3dMessage();
+ createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES;
+ createMessage.type = J3dMessage.GEOMETRYARRAY_CHANGED;
+ createMessage.universe = null;
+ createMessage.args[0] = this;
+ createMessage.args[1]= new Integer(DLIST_CREATE_CHANGED);
+ VirtualUniverse.mc.processMessage(createMessage);
+ */
+ isShared = true;
+ } // Clone geometry only for the first setLive
+ else {
+ // If geometry is indexed and use_index_coord is false, unindexify
+ // otherwise, set mirrorGeometry to null (from previous clearLive)
+ if (this instanceof IndexedGeometryArrayRetained) {
+ // Send to rendering attribute structure,
+ J3dMessage createMessage = new J3dMessage();
+ createMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES;
+ createMessage.type = J3dMessage.GEOMETRY_CHANGED;
+ createMessage.universe = null;
+ createMessage.args[0] = null;
+ createMessage.args[1]= this;
+ createMessage.args[2]= new Integer(INIT_MIRROR_GEOMETRY);
+ VirtualUniverse.mc.processMessage(createMessage);
+ }
+ }
+
+ }
+
+ @Override
+ void clearLive(int refCount) {
+ super.clearLive(refCount);
+
+ if (this.refCount <= 0) {
+ isShared = false;
+ }
+ }
+
+ @Override
+ void computeBoundingBox() {
+
+ // System.err.println("computeBoundingBox ....");
+
+ if (boundsDirty && VirtualUniverse.mc.cacheAutoComputedBounds) {
+ for(ArrayList<Shape3DRetained> users : userLists) {
+ for(Shape3DRetained shape : users)
+ shape.dirtyBoundsCache();
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ // by copy
+ computeBoundingBox(initialVertexIndex, vertexData);
+
+ } else if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) { // USE_NIO_BUFFER
+ //System.err.println("vertexFormat & GeometryArray.USE_NIO_BUFFER");
+ if((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ computeBoundingBox(initialCoordIndex, interleavedFloatBufferImpl);
+ } else if((vertexType & PF) != 0) {
+ computeBoundingBox(floatBufferRefCoords);
+ } else if((vertexType & PD) != 0) {
+ computeBoundingBox(doubleBufferRefCoords);
+ }
+
+ } else if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ //System.err.println("vertexFormat & GeometryArray.INTERLEAVED");
+ computeBoundingBox(initialCoordIndex, interLeavedVertexData);
+ } else if ((vertexType & PF) != 0) {
+ //System.err.println("vertexType & PF");
+ computeBoundingBox(floatRefCoords);
+ } else if ((vertexType & P3F) != 0) {
+ //System.err.println("vertexType & P3F");
+ computeBoundingBox(p3fRefCoords);
+ } else if ((vertexType & P3D) != 0) {
+ //System.err.println("vertexType & P3D");
+ computeBoundingBox(p3dRefCoords);
+ } else if ((vertexType & PD) != 0) {
+ //System.err.println("vertexType & PD");
+ computeBoundingBox(doubleRefCoords);
+ }
+
+ }
+
+
+ // NullGeometry is true only for byRef case
+ void processCoordsChanged(boolean nullGeo) {
+
+ /*
+ System.err.println("processCoordsChanged : nullGeo " + nullGeo);
+ System.err.println("Before :processCoordsChanged : geoBounds ");
+ System.err.println(geoBounds);
+ */
+ if (nullGeo) {
+ synchronized(geoBounds) {
+ geoBounds.setLower(-1.0, -1.0, -1.0);
+ geoBounds.setUpper(1.0, 1.0, 1.0);
+ boundsDirty = false;
+ }
+ synchronized(centroid) {
+ recompCentroid = false;
+ geoBounds.getCenter(this.centroid);
+ }
+
+ }
+ else {
+ // re-compute centroid if used
+ synchronized(centroid) {
+ recompCentroid = true;
+ }
+
+ synchronized(geoBounds) {
+ boundsDirty = true;
+ computeBoundingBox();
+ }
+
+ /*
+ System.err.println("After :processCoordsChanged : geoBounds ");
+ System.err.println(geoBounds);
+ */
+ }
+ }
+
+
+ void computeBoundingBox(int vIndex, float[] vdata) {
+ int i, offset;
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+
+
+ //System.err.println("Before : computeBoundingBox : geoBounds ");
+ // System.err.println(geoBounds);
+
+ synchronized(geoBounds) {
+
+ // If autobounds compute is false then return
+ // It is possible that user call getBounds() before
+ // this Geometry add to live scene graph.
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+ if (!boundsDirty)
+ return;
+
+ // Initial offset
+ offset = vIndex * stride+coordinateOffset;
+ // Compute the bounding box
+ xmin = xmax = vdata[offset];
+ ymin = ymax = vdata[offset+1];
+ zmin = zmax = vdata[offset+2];
+ offset += stride;
+ for (i=1; i<validVertexCount; i++) {
+ if (vdata[offset] > xmax)
+ xmax = vdata[offset];
+ if (vdata[offset] < xmin)
+ xmin = vdata[offset];
+
+ if (vdata[offset+1] > ymax)
+ ymax = vdata[offset+1];
+ if (vdata[offset+1] < ymin)
+ ymin = vdata[offset+1];
+
+ if (vdata[offset+2] > zmax)
+ zmax = vdata[offset+2];
+ if (vdata[offset+2] < zmin)
+ zmin = vdata[offset+2];
+
+ offset += stride;
+ }
+
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+ /*
+ System.err.println("After : computeBoundingBox : geoBounds ");
+ System.err.println(geoBounds);
+ */
+ }
+
+ // Compute boundingbox for interleaved nio buffer
+ void computeBoundingBox(int vIndex, FloatBuffer vdata) {
+ int i, offset;
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+ // Initial offset
+ offset = vIndex * stride+coordinateOffset;
+ // Compute the bounding box
+ xmin = xmax = vdata.get(offset);
+ ymin = ymax = vdata.get(offset+1);
+ zmin = zmax = vdata.get(offset+2);
+ offset += stride;
+ for (i=1; i<validVertexCount; i++) {
+ if (vdata.get(offset) > xmax)
+ xmax = vdata.get(offset);
+ if (vdata.get(offset) < xmin)
+ xmin = vdata.get(offset);
+
+ if (vdata.get(offset+1) > ymax)
+ ymax = vdata.get(offset+1);
+ if (vdata.get(offset+1) < ymin)
+ ymin = vdata.get(offset+1);
+
+ if (vdata.get(offset+2) > zmax)
+ zmax = vdata.get(offset+2);
+ if (vdata.get(offset+2) < zmin)
+ zmin = vdata.get(offset+2);
+
+ offset += stride;
+ }
+
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+ }
+
+
+ // compute bounding box for coord with nio buffer
+ void computeBoundingBox( DoubleBuffer buffer) {
+ int i, j, k, sIndex;
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+ sIndex = initialCoordIndex;
+ int maxIndex = 3*validVertexCount;
+
+ // Compute the bounding box
+ xmin = xmax = buffer.get(sIndex++);
+ ymin = ymax = buffer.get(sIndex++);
+ zmin = zmax = buffer.get(sIndex++);
+
+ for (i=sIndex; i<maxIndex; i+=3) {
+ j = i + 1;
+ k = i + 2;
+
+ if (buffer.get(i) > xmax)
+ xmax = buffer.get(i);
+ if (buffer.get(i) < xmin)
+ xmin = buffer.get(i);
+
+ if (buffer.get(j) > ymax)
+ ymax = buffer.get(j);
+ if (buffer.get(j) < ymin)
+ ymin = buffer.get(j);
+
+ if (buffer.get(k) > zmax)
+ zmax = buffer.get(k);
+ if (buffer.get(k) < zmin)
+ zmin = buffer.get(k);
+
+ }
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+ }
+
+ // compute bounding box for coord with nio buffer
+ void computeBoundingBox( FloatBuffer buffer) {
+ int i, j, k, sIndex;
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+
+ sIndex = initialCoordIndex;
+ int maxIndex = 3*validVertexCount;
+
+ // Compute the bounding box
+ xmin = xmax = buffer.get(sIndex++);
+ ymin = ymax = buffer.get(sIndex++);
+ zmin = zmax = buffer.get(sIndex++);
+
+ for (i=sIndex; i<maxIndex; i+=3) {
+ j = i + 1;
+ k = i + 2;
+
+ if (buffer.get(i) > xmax)
+ xmax = buffer.get(i);
+ if (buffer.get(i) < xmin)
+ xmin = buffer.get(i);
+
+ if (buffer.get(j) > ymax)
+ ymax = buffer.get(j);
+ if (buffer.get(j) < ymin)
+ ymin = buffer.get(j);
+
+ if (buffer.get(k) > zmax)
+ zmax = buffer.get(k);
+ if (buffer.get(k) < zmin)
+ zmin = buffer.get(k);
+
+ }
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+ }
+
+ void computeBoundingBox(float[] coords) {
+ // System.err.println("GeometryArrayRetained : computeBoundingBox(float[] coords)");
+ int i, j, k, sIndex;
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+ sIndex = initialCoordIndex;
+ int maxIndex = 3*validVertexCount;
+
+ // Compute the bounding box
+ xmin = xmax = coords[sIndex++];
+ ymin = ymax = coords[sIndex++];
+ zmin = zmax = coords[sIndex++];
+
+ for (i=sIndex; i<maxIndex; i+=3) {
+ j = i + 1;
+ k = i + 2;
+
+ if (coords[i] > xmax)
+ xmax = coords[i];
+ if (coords[i] < xmin)
+ xmin = coords[i];
+
+ if (coords[j] > ymax)
+ ymax = coords[j];
+ if (coords[j] < ymin)
+ ymin = coords[j];
+
+ if (coords[k] > zmax)
+ zmax = coords[k];
+ if (coords[k] < zmin)
+ zmin = coords[k];
+
+ }
+ geoBounds.setUpper(xmax, ymax, zmax);
+ // System.err.println("max(" + xmax + ", " + ymax + ", " + zmax + ")");
+ geoBounds.setLower(xmin, ymin, zmin);
+ // System.err.println("min(" + xmin + ", " + ymin + ", " + zmin + ")");
+
+ boundsDirty = false;
+ }
+
+ }
+
+ void computeBoundingBox(double[] coords) {
+ int i, j, k, sIndex;
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+
+ sIndex = initialCoordIndex;
+ int maxIndex = 3*validVertexCount;
+
+ // Compute the bounding box
+ xmin = xmax = coords[sIndex++];
+ ymin = ymax = coords[sIndex++];
+ zmin = zmax = coords[sIndex++];
+
+ for (i=sIndex; i<maxIndex; i+=3) {
+ j = i + 1;
+ k = i + 2;
+
+ if (coords[i] > xmax)
+ xmax = coords[i];
+ if (coords[i] < xmin)
+ xmin = coords[i];
+
+ if (coords[j] > ymax)
+ ymax = coords[j];
+ if (coords[j] < ymin)
+ ymin = coords[j];
+
+ if (coords[k] > zmax)
+ zmax = coords[k];
+ if (coords[k] < zmin)
+ zmin = coords[k];
+
+ }
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+
+ }
+
+ void computeBoundingBox(Point3f[] coords) {
+
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+ Point3f p;
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+
+
+ // Compute the bounding box
+ xmin = xmax = coords[initialCoordIndex].x;
+ ymin = ymax = coords[initialCoordIndex].y;
+ zmin = zmax = coords[initialCoordIndex].z;
+
+ for (int i=initialCoordIndex+1; i<validVertexCount; i++) {
+ p = coords[i];
+ if (p.x > xmax) xmax = p.x;
+ if (p.x < xmin) xmin = p.x;
+
+ if (p.y > ymax) ymax = p.y;
+ if (p.y < ymin) ymin = p.y;
+
+ if (p.z > zmax) zmax = p.z;
+ if (p.z < zmin) zmin = p.z;
+
+ }
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+
+ }
+
+ void computeBoundingBox(Point3d[] coords) {
+
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+ Point3d p;
+
+ synchronized(geoBounds) {
+ // If autobounds compute is false then return
+ if ((computeGeoBounds == 0) && (refCount > 0)) {
+ return;
+ }
+
+ if (!boundsDirty)
+ return;
+
+
+ // Compute the bounding box
+ xmin = xmax = coords[initialCoordIndex].x;
+ ymin = ymax = coords[initialCoordIndex].y;
+ zmin = zmax = coords[initialCoordIndex].z;
+
+ for (int i=initialCoordIndex+1; i<validVertexCount; i++) {
+ p = coords[i];
+ if (p.x > xmax) xmax = p.x;
+ if (p.x < xmin) xmin = p.x;
+
+ if (p.y > ymax) ymax = p.y;
+ if (p.y < ymin) ymin = p.y;
+
+ if (p.z > zmax) zmax = p.z;
+ if (p.z < zmin) zmin = p.z;
+
+ }
+ geoBounds.setUpper(xmax, ymax, zmax);
+ geoBounds.setLower(xmin, ymin, zmin);
+ boundsDirty = false;
+ }
+
+ }
+
+
+ @Override
+ synchronized void update() {
+ }
+
+ void setupMirrorVertexPointer(int vType) {
+ int i, index;
+
+ switch (vType) {
+ case PF:
+ if (floatRefCoords == null) {
+ if ((vertexType & VERTEX_DEFINED) == PF) {
+ vertexType &= ~PF;
+ mirrorFloatRefCoords = null;
+ mirrorVertexAllocated &= ~PF;
+ }
+ }
+ else {
+ vertexType |= PF;
+ mirrorFloatRefCoords = floatRefCoords;
+ mirrorVertexAllocated &= ~PF;
+ }
+
+ break;
+ case PD:
+ if (doubleRefCoords == null) {
+ if ((vertexType & VERTEX_DEFINED) == PD) {
+ mirrorDoubleRefCoords = null;
+ mirrorVertexAllocated &= ~PD;
+ vertexType &= ~PD;
+ }
+ vertexType &= ~PD;
+ }
+ else {
+ vertexType |= PD;
+ mirrorDoubleRefCoords = doubleRefCoords;
+ mirrorVertexAllocated &= ~PD;
+ }
+
+ break;
+ case P3F:
+ if (p3fRefCoords == null) {
+ vertexType &= ~P3F;
+ // Don't set the mirrorFloatRefCoords to null,
+ // may be able to re-use
+ // mirrorFloatRefCoords = null;
+ }
+ else {
+ vertexType |= P3F;
+
+ if ((mirrorVertexAllocated & PF) == 0) {
+ mirrorFloatRefCoords = new float[vertexCount * 3];
+ mirrorVertexAllocated |= PF;
+ }
+
+ index = initialCoordIndex * 3;
+ for ( i=initialCoordIndex; i<validVertexCount; i++) {
+ mirrorFloatRefCoords[index++] = p3fRefCoords[i].x;
+ mirrorFloatRefCoords[index++] = p3fRefCoords[i].y;
+ mirrorFloatRefCoords[index++] = p3fRefCoords[i].z;
+ }
+ }
+ break;
+ case P3D:
+ if (p3dRefCoords == null) {
+ vertexType &= ~P3D;
+ // Don't set the mirrorDoubleRefCoords to null,
+ // may be able to re-use
+ // mirrorDoubleRefCoords = null;
+ }
+ else {
+ vertexType |= P3D;
+
+ if ((mirrorVertexAllocated & PD) == 0) {
+ mirrorDoubleRefCoords = new double[vertexCount * 3];
+ mirrorVertexAllocated |= PD;
+ }
+
+ index = initialCoordIndex * 3;
+ for ( i=initialCoordIndex; i<validVertexCount; i++) {
+ mirrorDoubleRefCoords[index++] = p3dRefCoords[i].x;
+ mirrorDoubleRefCoords[index++] = p3dRefCoords[i].y;
+ mirrorDoubleRefCoords[index++] = p3dRefCoords[i].z;
+ }
+ }
+ break;
+ default:
+ break;
+
+ }
+
+ }
+
+ // If turned transparent the first time, then force it to allocate
+ void setupMirrorInterleavedColorPointer(boolean force) {
+ int index, length, offset;
+ int i;
+
+ if (force || (c4fAllocated != 0)) { // Color is present
+
+ length = 4 * vertexCount;
+
+ if (mirrorInterleavedColorPointer == null) {
+ mirrorInterleavedColorPointer = new float[1][length];
+ }
+
+ index = 4 * initialVertexIndex;
+ offset = stride * initialVertexIndex + colorOffset;
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0 &&
+ interLeavedVertexData != null ) { // java array
+ if ((vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+
+ for (i = initialVertexIndex; i < validVertexCount; i++) {
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset];
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset+1];
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset+2];
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset+3];
+ offset += stride;
+ }
+ }
+ else {
+ for (i = initialVertexIndex; i < validVertexCount; i++) {
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset];
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset+1];
+ mirrorInterleavedColorPointer[0][index++] =
+ interLeavedVertexData[offset+2];
+ mirrorInterleavedColorPointer[0][index++] = 1.0f;
+ offset += stride;
+ }
+ }
+
+ } else { // NIO BUFFER
+ if ((vertexFormat & GeometryArray.WITH_ALPHA) != 0 &&
+ interleavedFloatBufferImpl != null) {
+ for (i = initialVertexIndex; i < validVertexCount; i++) {
+ interleavedFloatBufferImpl.position(offset);
+ interleavedFloatBufferImpl.get(mirrorInterleavedColorPointer[0],
+ index , 4);
+ index += 4;
+ offset += stride;
+ }
+ }
+ else {
+ for (i = initialVertexIndex; i < validVertexCount; i++) {
+ interleavedFloatBufferImpl.position(offset);
+ interleavedFloatBufferImpl.get(mirrorInterleavedColorPointer[0],
+ index, 3);
+ mirrorInterleavedColorPointer[0][index+3] = 1.0f;
+ index += 4;
+ offset += stride;
+
+ }
+ }
+ }
+ c4fAllocated = GeometryArray.WITH_ALPHA;
+ }
+ }
+
+ // If turned transparent the first time, then force it to allocate
+ void setupMirrorColorPointer(int ctype, boolean force) {
+ int i, srcIndex = 0, dstIndex = 0;
+ int multiplier;
+
+ if (c4fAllocated == 0 && !force) {
+ multiplier = 3;
+ } else {
+
+ // If the first time, we are forced to allocate 4f, then
+ // we need to force the allocation of the colors again
+ // for the case when allocation has previously occurred
+ // only for RGB
+ if (force && (c4fAllocated == 0) &&
+ (vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+ mirrorColorAllocated = 0;
+ }
+ c4fAllocated = GeometryArray.WITH_ALPHA;
+ multiplier = 4;
+ }
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) { // java array
+ switch (ctype) {
+ case CF:
+ if (floatRefColors == null) {
+ if ((c4fAllocated == 0) && !force &&
+ (vertexType & COLOR_DEFINED) == CF) {
+ mirrorFloatRefColors[0] = null;
+ mirrorColorAllocated &= ~CF;
+ }
+ vertexType &= ~CF;
+ return;
+ }
+
+ vertexType |= CF;
+ if (c4fAllocated == 0 && !force) {
+ mirrorFloatRefColors[0] = floatRefColors;
+ mirrorColorAllocated &= ~CF;
+ }
+ else {
+ if ((mirrorColorAllocated & CF) == 0) {
+ mirrorFloatRefColors[0] = new float[4 * vertexCount];
+ mirrorColorAllocated |= CF;
+ }
+
+ if ((vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+
+ srcIndex = initialColorIndex * 3;
+ dstIndex = initialColorIndex * 4;
+
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorFloatRefColors[0][dstIndex++] =
+ floatRefColors[srcIndex++];
+ mirrorFloatRefColors[0][dstIndex++] =
+ floatRefColors[srcIndex++];
+ mirrorFloatRefColors[0][dstIndex++] =
+ floatRefColors[srcIndex++];
+ mirrorFloatRefColors[0][dstIndex++] = 1.0f;
+ }
+
+ }
+ else {
+ srcIndex = initialColorIndex * 4;
+ System.arraycopy(floatRefColors, srcIndex,
+ mirrorFloatRefColors[0], srcIndex,
+ (4*validVertexCount));
+ }
+ }
+ break;
+ case CUB:
+ if (byteRefColors == null) {
+ if (c4fAllocated == 0 && !force &&
+ ((vertexType & COLOR_DEFINED) == CUB) ) {
+ mirrorUnsignedByteRefColors[0] = null;
+ mirrorColorAllocated &= ~CUB;
+ }
+ vertexType &= ~CUB;
+ return;
+ }
+ vertexType |= CUB;
+ if (c4fAllocated == 0 && !force) {
+ mirrorUnsignedByteRefColors[0] = byteRefColors;
+ mirrorColorAllocated &= ~CUB;;
+ }
+ else {
+ if ((mirrorColorAllocated & CUB) == 0) {
+ mirrorUnsignedByteRefColors[0] = new byte[4 * vertexCount];
+ mirrorColorAllocated |= CUB;
+ }
+ if ((vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+
+ srcIndex = initialColorIndex * 3;
+ dstIndex = initialColorIndex * 4;
+
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorUnsignedByteRefColors[0][dstIndex++] =
+ byteRefColors[srcIndex++];
+ mirrorUnsignedByteRefColors[0][dstIndex++] =
+ byteRefColors[srcIndex++];
+ mirrorUnsignedByteRefColors[0][dstIndex++] =
+ byteRefColors[srcIndex++];
+ mirrorUnsignedByteRefColors[0][dstIndex++] =
+ (byte)(255.0);
+ }
+ }
+ else {
+ srcIndex = initialColorIndex * 4;
+ System.arraycopy(byteRefColors, srcIndex,
+ mirrorUnsignedByteRefColors[0], srcIndex,
+ (4*validVertexCount));
+ }
+ }
+
+ break;
+ case C3F:
+ if (c3fRefColors == null) {
+ vertexType &= ~C3F;
+ return;
+ }
+ vertexType |=C3F ;
+
+ if ((mirrorColorAllocated & CF) == 0) {
+ mirrorFloatRefColors[0] = new float[vertexCount * multiplier];
+ mirrorColorAllocated |= CF;
+ }
+ if ((c4fAllocated & GeometryArray.WITH_ALPHA) == 0) {
+
+ dstIndex = initialColorIndex * 3;
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorFloatRefColors[0][dstIndex++] = c3fRefColors[i].x;
+ mirrorFloatRefColors[0][dstIndex++] = c3fRefColors[i].y;
+ mirrorFloatRefColors[0][dstIndex++] = c3fRefColors[i].z;
+ }
+ } else {
+
+ dstIndex = initialColorIndex * 4;
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorFloatRefColors[0][dstIndex++] = c3fRefColors[i].x;
+ mirrorFloatRefColors[0][dstIndex++] = c3fRefColors[i].y;
+ mirrorFloatRefColors[0][dstIndex++] = c3fRefColors[i].z;
+ mirrorFloatRefColors[0][dstIndex++] = 1.0f;
+ }
+ }
+
+ break;
+ case C4F:
+ if (c4fRefColors == null) {
+ vertexType &= ~C4F;
+ return;
+ }
+ vertexType |=C4F ;
+
+ if ((mirrorColorAllocated & CF) == 0) {
+ mirrorFloatRefColors[0] = new float[vertexCount << 2];
+ mirrorColorAllocated |= CF;
+ }
+
+ dstIndex = initialColorIndex * 4;
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorFloatRefColors[0][dstIndex++] = c4fRefColors[i].x;
+ mirrorFloatRefColors[0][dstIndex++] = c4fRefColors[i].y;
+ mirrorFloatRefColors[0][dstIndex++] = c4fRefColors[i].z;
+ mirrorFloatRefColors[0][dstIndex++] = c4fRefColors[i].w;
+ }
+ break;
+ case C3UB:
+ if (c3bRefColors == null) {
+ vertexType &= ~C3UB;
+ return;
+ }
+ vertexType |=C3UB ;
+
+ if ((mirrorColorAllocated & CUB) == 0) {
+ mirrorUnsignedByteRefColors[0] =
+ new byte[vertexCount * multiplier];
+ mirrorColorAllocated |= CUB;
+ }
+ if ((c4fAllocated & GeometryArray.WITH_ALPHA) == 0) {
+ dstIndex = initialColorIndex * 3;
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c3bRefColors[i].x;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c3bRefColors[i].y;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c3bRefColors[i].z;
+ }
+ } else {
+ dstIndex = initialColorIndex * 4;
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c3bRefColors[i].x;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c3bRefColors[i].y;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c3bRefColors[i].z;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = (byte)255;
+ }
+ }
+ break;
+ case C4UB:
+ if (c4bRefColors == null) {
+ vertexType &= ~C4UB;
+ return;
+ }
+ vertexType |=C4UB ;
+ if ((mirrorColorAllocated & CUB) == 0) {
+ mirrorUnsignedByteRefColors[0] = new byte[vertexCount << 2];
+ mirrorColorAllocated |= CUB;
+ }
+
+ dstIndex = initialColorIndex * 4;
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c4bRefColors[i].x;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c4bRefColors[i].y;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c4bRefColors[i].z;
+ mirrorUnsignedByteRefColors[0][dstIndex++] = c4bRefColors[i].w;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ else { //USE_NIO_BUFFER is set
+ if( colorRefBuffer == null) {
+ if (c4fAllocated == 0 && !force &&
+ (vertexType & COLOR_DEFINED) == CF) {
+ mirrorFloatRefColors[0] = null;
+ mirrorColorAllocated &= ~CF;
+ }
+ vertexType &= ~CF;
+
+ if (c4fAllocated == 0 && !force &&
+ ((vertexType & COLOR_DEFINED) == CUB) ) {
+ mirrorUnsignedByteRefColors[0] = null;
+ mirrorColorAllocated &= ~CUB;
+ }
+ vertexType &= ~CUB;
+ return;
+
+ } else if( floatBufferRefColors != null) {
+ vertexType |= CF;
+ vertexType &= ~CUB;
+ if (c4fAllocated == 0 && !force) {
+ // NOTE: make suren mirrorFloatRefColors[0] is set right
+ mirrorFloatRefColors[0] = null;
+ mirrorColorAllocated &= ~CF;
+ }
+ else {
+ if ((mirrorColorAllocated & CF) == 0) {
+ mirrorFloatRefColors[0] = new float[4 * vertexCount];
+ mirrorColorAllocated |= CF;
+ }
+ floatBufferRefColors.rewind();
+ if ((vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+ srcIndex = initialColorIndex * 3;
+ dstIndex = initialColorIndex * 4;
+ floatBufferRefColors.position(srcIndex);
+
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ floatBufferRefColors.get(mirrorFloatRefColors[0], dstIndex, 3);
+ mirrorFloatRefColors[0][dstIndex+3] = 1.0f;
+ dstIndex += 4;
+ }
+ }
+ else {
+
+ srcIndex = initialColorIndex * 4;
+ dstIndex = initialColorIndex * 4;
+ floatBufferRefColors.position(srcIndex);
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ floatBufferRefColors.get(mirrorFloatRefColors[0], dstIndex, 4);
+ dstIndex+= 4;
+ }
+ }
+ }
+ } else if ( byteBufferRefColors != null) {
+ vertexType |= CUB;
+ vertexType &= ~CF;
+ if (c4fAllocated == 0 && !force) {
+ // NOTE: make sure mirrorUnsignedByteRefColors[0] is set right
+ mirrorUnsignedByteRefColors[0] = null;
+ mirrorColorAllocated &= ~CUB;;
+ }
+ else {
+ if ((mirrorColorAllocated & CUB) == 0) {
+ mirrorUnsignedByteRefColors[0] = new byte[4 * vertexCount];
+ mirrorColorAllocated |= CUB;
+ }
+
+ byteBufferRefColors.rewind();
+ if ((vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+ srcIndex = initialColorIndex * 3;
+ dstIndex = initialColorIndex * 4;
+ byteBufferRefColors.position(srcIndex);
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ byteBufferRefColors.get(mirrorUnsignedByteRefColors[0],
+ dstIndex, 3);
+ mirrorUnsignedByteRefColors[0][dstIndex+3] = (byte)(255.0);
+ dstIndex += 4;
+ }
+ }
+ else {
+ srcIndex = initialColorIndex * 4;
+ dstIndex = initialColorIndex * 4;
+ byteBufferRefColors.position(srcIndex);
+ for (i = initialColorIndex; i < validVertexCount; i++) {
+ byteBufferRefColors.get(mirrorUnsignedByteRefColors[0], dstIndex, 4);
+ dstIndex+= 4;
+ }
+ }
+ } // end of else
+ }//end of else if ( byteBufferRefColors != null)
+ }//end of NIO BUFFER case
+
+ colorChanged = 0xffff;
+ }
+
+
+ void setupMirrorNormalPointer(int ntype) {
+ int i, index;
+
+ switch (ntype) {
+ case NF:
+ if (floatRefNormals == null) {
+ if ((vertexType & NORMAL_DEFINED) == NF) {
+ vertexType &= ~NF;
+ mirrorFloatRefNormals = null;
+ mirrorNormalAllocated = false;
+ }
+ }
+ else {
+ vertexType |= NF;
+ mirrorFloatRefNormals = floatRefNormals;
+ mirrorNormalAllocated = false;
+ }
+ break;
+ case N3F:
+ if (v3fRefNormals == null) {
+ if ((vertexType & NORMAL_DEFINED) == N3F) {
+ vertexType &= ~N3F;
+ }
+ return;
+ }
+ else {
+ vertexType |= N3F;
+ }
+ if (!mirrorNormalAllocated) {
+ mirrorFloatRefNormals = new float[vertexCount * 3];
+ mirrorNormalAllocated = true;
+ }
+
+ index = initialNormalIndex * 3;
+ for (i = initialNormalIndex; i < validVertexCount; i++) {
+ mirrorFloatRefNormals[index++] = v3fRefNormals[i].x;
+ mirrorFloatRefNormals[index++] = v3fRefNormals[i].y;
+ mirrorFloatRefNormals[index++] = v3fRefNormals[i].z;
+ }
+ break;
+ default:
+ break; }
+ }
+
+ void setupMirrorTexCoordPointer(int type) {
+ for (int i = 0; i < texCoordSetCount; i++) {
+ doSetupMirrorTexCoordPointer(i, type);
+ }
+
+ validateTexCoordPointerType();
+ }
+
+ void setupMirrorTexCoordPointer(int texCoordSet, int type) {
+ doSetupMirrorTexCoordPointer(texCoordSet, type);
+ validateTexCoordPointerType();
+ }
+
+ // If all texCoord pointers are set to a non-null value, then set the
+ // texcoord type in the vertexType flag word, else clear the texcoord type
+ private void validateTexCoordPointerType() {
+ boolean allNonNull = true;
+ boolean allNull = true;
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if (refTexCoords[i] == null) {
+ allNonNull = false;
+ } else {
+ allNull = false;
+ }
+ }
+
+ // Reset texCoordType if all references are null
+ if (allNull) {
+ texCoordType = 0;
+ }
+
+ // Copy texCoordType to vertexType if all references are non-null
+ vertexType &= ~TEXCOORD_DEFINED;
+ if (allNonNull) {
+ vertexType |= texCoordType;
+ }
+ }
+
+ private void doSetupMirrorTexCoordPointer(int texCoordSet, int type) {
+ int i, index;
+
+ switch (type) {
+ case TF:
+ texCoordType = TF;
+ mirrorRefTexCoords[texCoordSet] = refTexCoords[texCoordSet];
+ break;
+
+ case T2F:
+ texCoordType = T2F;
+ t2fRefTexCoords = (TexCoord2f[])refTexCoords[texCoordSet];
+
+ if (t2fRefTexCoords == null) {
+ mirrorRefTexCoords[texCoordSet] = null;
+ break;
+ }
+
+ mirrorFloatRefTexCoords = (float[])mirrorRefTexCoords[texCoordSet];
+ if (mirrorFloatRefTexCoords != null) {
+ if (mirrorFloatRefTexCoords.length < (vertexCount * 2))
+ mirrorRefTexCoords[texCoordSet] =
+ mirrorFloatRefTexCoords = new float[vertexCount * 2];
+ }
+ else {
+ mirrorRefTexCoords[texCoordSet] =
+ mirrorFloatRefTexCoords = new float[vertexCount * 2];
+ }
+
+ index = initialTexCoordIndex[texCoordSet] * 2;
+ for (i = initialTexCoordIndex[texCoordSet]; i < validVertexCount; i++) {
+ mirrorFloatRefTexCoords[index++] = t2fRefTexCoords[i].x;
+ mirrorFloatRefTexCoords[index++] = t2fRefTexCoords[i].y;
+ }
+ break;
+
+ case T3F:
+ texCoordType = T3F;
+ t3fRefTexCoords = (TexCoord3f[])refTexCoords[texCoordSet];
+
+ if (t3fRefTexCoords == null) {
+ mirrorRefTexCoords[texCoordSet] = null;
+ break;
+ }
+
+ mirrorFloatRefTexCoords = (float[])mirrorRefTexCoords[texCoordSet];
+ if (mirrorFloatRefTexCoords != null) {
+ if (mirrorFloatRefTexCoords.length < (vertexCount * 3))
+ mirrorRefTexCoords[texCoordSet] =
+ mirrorFloatRefTexCoords = new float[vertexCount * 3];
+ }
+ else {
+ mirrorRefTexCoords[texCoordSet] =
+ mirrorFloatRefTexCoords = new float[vertexCount * 3];
+ }
+
+ index = initialTexCoordIndex[texCoordSet] * 3;
+ for (i = initialTexCoordIndex[texCoordSet]; i < validVertexCount; i++) {
+ mirrorFloatRefTexCoords[index++] = t3fRefTexCoords[i].x;
+ mirrorFloatRefTexCoords[index++] = t3fRefTexCoords[i].y;
+ mirrorFloatRefTexCoords[index++] = t3fRefTexCoords[i].z;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ void setupMirrorVertexAttrPointer(int type) {
+ for (int i = 0; i < vertexAttrCount; i++) {
+ doSetupMirrorVertexAttrPointer(i, type);
+ }
+
+ validateVertexAttrPointerType();
+ }
+
+ void setupMirrorVertexAttrPointer(int vertexAttrNum, int type) {
+ doSetupMirrorVertexAttrPointer(vertexAttrNum, type);
+ validateVertexAttrPointerType();
+ }
+
+ // If all vertex attr pointers are set to a non-null value, then set the
+ // vertex attr type in the vertexType flag word, else clear the
+ // vertex attr type
+ private void validateVertexAttrPointerType() {
+ boolean allNonNull = true;
+ boolean allNull = true;
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ for (int i = 0; i < vertexAttrCount; i++) {
+ if (floatRefVertexAttrs[i] == null) {
+ allNonNull = false;
+ } else {
+ allNull = false;
+ }
+ }
+ } else {
+ for (int i = 0; i < vertexAttrCount; i++) {
+ if (floatBufferRefVertexAttrs[i] == null) {
+ allNonNull = false;
+ } else {
+ allNull = false;
+ }
+ }
+ }
+
+ // Reset vertexAttrType if all references are null
+ if (allNull) {
+ vertexAttrType = 0;
+ }
+
+ // Copy vertexAttrType to vertexType if all references are non-null
+ vertexType &= ~VATTR_DEFINED;
+ if (allNonNull) {
+ vertexType |= vertexAttrType;
+ }
+ }
+
+ private void doSetupMirrorVertexAttrPointer(int vertexAttrNum, int type) {
+ switch (type) {
+ case AF:
+ vertexAttrType = AF;
+ mirrorFloatRefVertexAttrs[vertexAttrNum] =
+ floatRefVertexAttrs[vertexAttrNum];
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ void createGeometryArrayData(int vertexCount, int vertexFormat) {
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ createGeometryArrayData(vertexCount, vertexFormat, 1,
+ defaultTexCoordSetMap);
+ } else {
+ createGeometryArrayData(vertexCount, vertexFormat, 0, null);
+ }
+ }
+
+ void createGeometryArrayData(int vertexCount, int vertexFormat,
+ int texCoordSetCount, int[] texCoordSetMap) {
+
+ createGeometryArrayData(vertexCount, vertexFormat,
+ texCoordSetCount, texCoordSetMap,
+ 0, null);
+ }
+
+ void createGeometryArrayData(int vertexCount, int vertexFormat,
+ int texCoordSetCount, int[] texCoordSetMap,
+ int vertexAttrCount, int[] vertexAttrSizes) {
+ this.vertexFormat = vertexFormat;
+ this.vertexCount = vertexCount;
+ this.validVertexCount = vertexCount;
+
+ this.texCoordSetCount = texCoordSetCount;
+ if (texCoordSetMap == null) {
+ this.texCoordSetMap = null;
+ }
+ else {
+ this.texCoordSetMap = Arrays.copyOf(texCoordSetMap, texCoordSetMap.length);
+ }
+
+ this.vertexAttrCount = vertexAttrCount;
+ if (vertexAttrSizes == null) {
+ this.vertexAttrSizes = null;
+ }
+ else {
+ this.vertexAttrSizes = Arrays.copyOf(vertexAttrSizes, vertexAttrSizes.length);
+ }
+
+ this.vertexAttrStride = this.vertexAttrStride();
+ this.stride = this.stride();
+
+ this.vertexAttrOffsets = this.vertexAttrOffsets();
+ this.texCoordSetMapOffset = this.texCoordSetMapOffset();
+ this.textureOffset = this.textureOffset();
+ this.colorOffset = this.colorOffset();
+ this.normalOffset = this.normalOffset();
+ this.coordinateOffset = this.coordinateOffset();
+
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ this.vertexData = new float[this.vertexCount * this.stride];
+ }
+ else { // By reference geometry
+ this.vertexData = null;
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ this.mirrorRefTexCoords = new Object[texCoordSetCount];
+ this.refTexCoords = new Object[texCoordSetCount]; // keep J3DBufferImp object in nio buffer case
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 )
+ this.refTexCoordsBuffer = new J3DBuffer[texCoordSetCount]; // keep J3DBuffer object
+ }
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ this.floatRefVertexAttrs = new float[vertexAttrCount][];
+ this.mirrorFloatRefVertexAttrs = new float[vertexAttrCount][];
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
+ this.vertexAttrsRefBuffer = new J3DBuffer[vertexAttrCount];
+ this.floatBufferRefVertexAttrs = new FloatBuffer[vertexAttrCount];
+ }
+ }
+ }
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ this.initialTexCoordIndex = new int[texCoordSetCount];
+ }
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ this.initialVertexAttrIndex = new int[vertexAttrCount];
+ }
+ noAlpha = ((vertexFormat & GeometryArray.WITH_ALPHA) == 0);
+ lastAlpha[0] = 1.0f;
+
+ }
+
+ void setVertexFormat(boolean useAlpha, boolean ignoreVC, Context ctx) {
+ Pipeline.getPipeline().setVertexFormat(ctx,
+ this, vertexFormat, useAlpha, ignoreVC);
+ }
+
+ float[] updateAlphaInFloatRefColors(Canvas3D cv, int screen, float alpha) {
+
+ //System.err.println("updateAlphaInFloatRefColors screen = " + screen +
+ // " alpha " + alpha );
+
+ // update alpha only if vertex format includes alpha
+ if (((vertexFormat | c4fAllocated) & GeometryArray.WITH_ALPHA) == 0)
+ return mirrorFloatRefColors[0];
+
+ // if alpha is smaller than EPSILON, set it to EPSILON, so that
+ // even if alpha is equal to 0, we will not completely lose
+ // the original alpha value
+ if (alpha <= EPSILON) {
+ alpha = (float)EPSILON;
+ }
+
+ assert lastAlpha != null;
+ assert mirrorFloatRefColors != null;
+ assert mirrorFloatRefColors.length == lastAlpha.length;
+
+ // Issue 113 - reallocate lastAlpha array if needed, but no need to
+ // update the values here
+ if (lastAlpha.length <= screen) {
+ float[] la = new float[screen + 1];
+ for (int i = 0; i < lastAlpha.length; i++) {
+ la[i] = lastAlpha[i];
+ }
+ lastAlpha = la;
+ }
+
+ //System.err.println("updateAlphaInFloatRefColors screen is " + screen
+ // + " mirrorFloatRefColors.length " +
+ // mirrorFloatRefColors.length);
+
+ // allocate a copy of the color data for the screen if needed.
+ // this piece of code is only for multi-screens case
+ if (mirrorFloatRefColors.length <= screen) {
+ float[][] cfData = new float[screen + 1][];
+
+ for (int i = 0; i < mirrorFloatRefColors.length; i++) {
+ cfData[i] = mirrorFloatRefColors[i];
+ }
+
+ // Issue 113 - allocate entries for [oldSize..screen];
+ // copy cfData[0] to cfData[oldsize..screen-1] and
+ // lastAlpha[0] to lastAlpha[oldsize..screen-1].
+ for (int i = mirrorFloatRefColors.length; i < screen+1; i++) {
+ cfData[i] = new float[4 * vertexCount];
+ System.arraycopy(cfData[0], 0, cfData[i], 0, 4 * vertexCount);
+ lastAlpha[i] = lastAlpha[0];
+ }
+
+ mirrorFloatRefColors = cfData;
+
+ // Issue 113 - since we copied the data from screen 0, we don't need
+ // to do any further special processing.
+ }
+
+ assert lastAlpha[screen] >= 0.0;
+ /*
+ System.err.println("updateAlphaInFloatRefColors ** : lastAlpha[screen] " +
+ lastAlpha[screen]);
+
+ System.err.println("((colorChanged & (1<<screen)) == 0) " +
+ ((colorChanged & (1<<screen)) == 0));
+ */
+
+ if ((colorChanged & (1<<screen)) == 0) {
+ // color data is not modified
+ if (Math.abs(lastAlpha[screen] - alpha) <= EPSILON) {
+ // and if alpha is the same as the last one,
+ // just return the data
+ //System.err.println("updateAlphaInFloatRefColors 0 : alpha is the same as the last one " + alpha);
+
+ return mirrorFloatRefColors[screen];
+ } else {
+
+ // if alpha is different, update the alpha values
+ //System.err.println("updateAlphaInFloatRefColors 1 : alpha is different, update the alpha values " + alpha);
+
+ float m = alpha / lastAlpha[screen];
+
+ float[] cdata = mirrorFloatRefColors[screen];
+
+ // We've to traverse the whole due to BugId : 4676483
+ for (int i = 0, j = 0; i < vertexCount; i++, j+=4) {
+ cdata[j+3] = cdata[j+3] * m;
+ }
+ }
+ } else {
+ // color data is modified
+ if (screen == 0) {
+
+ // just update alpha values since screen 0 data is
+ // already updated in setupMirrorColorPointer
+
+ //System.err.println("updateAlphaInFloatRefColors 2 : just update alpha = " + alpha);
+
+ float[] cdata = mirrorFloatRefColors[screen];
+
+
+ // This part is also incorrect due to BugId : 4676483
+ // But traversing the whole array doesn't help either, as there
+ // isn't a mechanism to indicate the the alpha component has
+ // not changed by user.
+ int j = initialColorIndex * 4;
+ for (int i = initialColorIndex; i < validVertexCount; i++, j+=4) {
+ cdata[j+3] = cdata[j+3] * alpha;
+ }
+ } else {
+ // update color values from screen 0 data
+ //System.err.println("updateAlphaInFloatRefColors 3 : update color values from screen 0 data " + alpha);
+
+ float m;
+
+ if ((colorChanged & 1) == 0) {
+ // alpha is up to date in screen 0
+ m = alpha / lastAlpha[0];
+ } else {
+ m = alpha;
+ }
+
+ float[] sdata = mirrorFloatRefColors[0];
+ float[] cdata = mirrorFloatRefColors[screen];
+
+ int j = initialColorIndex * 4;
+ for (int i = initialColorIndex; i < validVertexCount; i++) {
+ cdata[j] = sdata[j++];
+ cdata[j] = sdata[j++];
+ cdata[j] = sdata[j++];
+ cdata[j] = sdata[j++] * m;
+ }
+ }
+ }
+
+ lastAlpha[screen] = alpha;
+ colorChanged &= ~(1 << screen);
+ dirtyFlag |= COLOR_CHANGED;
+ return mirrorFloatRefColors[screen];
+ }
+
+
+ byte[] updateAlphaInByteRefColors(Canvas3D cv, int screen, float alpha) {
+
+ /*
+ System.err.println("updateAlphaInByteRefColors screen = " + screen +
+ " alpha " + alpha );
+ */
+
+ // update alpha only if vertex format includes alpha
+ if (((vertexFormat | c4fAllocated) & GeometryArray.WITH_ALPHA) == 0)
+ return mirrorUnsignedByteRefColors[0];
+
+ // if alpha is smaller than EPSILON, set it to EPSILON, so that
+ // even if alpha is equal to 0, we will not completely lose
+ // the original alpha value
+ if (alpha <= EPSILON) {
+ alpha = (float)EPSILON;
+ }
+
+ assert lastAlpha != null;
+ assert mirrorUnsignedByteRefColors != null;
+ assert mirrorUnsignedByteRefColors.length == lastAlpha.length;
+
+ // Issue 113 - reallocate lastAlpha array if needed, but no need to
+ // update the values here
+ if (lastAlpha.length <= screen) {
+ float[] la = new float[screen + 1];
+ for (int i = 0; i < lastAlpha.length; i++) {
+ la[i] = lastAlpha[i];
+ }
+ lastAlpha = la;
+ }
+
+ // allocate a copy of the color data for the screen if needed.
+ // this piece of code is only for multi-screens case
+ if (mirrorUnsignedByteRefColors.length <= screen) {
+ byte[][] cbData = new byte[screen + 1][];
+ for (int i = 0; i < mirrorUnsignedByteRefColors.length; i++) {
+ cbData[i] = mirrorUnsignedByteRefColors[i];
+ }
+
+ // Issue 113 - allocate entries for [oldSize..screen];
+ // copy cbData[0] to cbData[oldsize..screen-1] and
+ // lastAlpha[0] to lastAlpha[oldsize..screen-1].
+ for (int i = mirrorUnsignedByteRefColors.length; i < screen+1; i++) {
+ cbData[i] = new byte[4 * vertexCount];
+ System.arraycopy(cbData[0], 0, cbData[i], 0, 4 * vertexCount);
+ lastAlpha[i] = lastAlpha[0];
+ }
+
+ mirrorUnsignedByteRefColors = cbData;
+
+ // Issue 113 - since we copied the data from screen 0, we don't need
+ // to do any further special processing.
+ }
+
+ assert lastAlpha[screen] >= 0.0;
+ /*
+ System.err.println("updateAlphaInByteRefColors ## : lastAlpha[screen] " +
+ lastAlpha[screen]);
+
+ System.err.println("((colorChanged & (1<<screen)) == 0) " +
+ ((colorChanged & (1<<screen)) == 0));
+ */
+
+ if ((colorChanged & (1<<screen)) == 0) {
+ // color data is not modified
+ if (Math.abs(lastAlpha[screen] - alpha) <= EPSILON) {
+ // and if alpha is the same as the last one,
+ // just return the data
+ //System.err.println("updateAlphaInByteRefColors 0 : alpha is the same as the last one " + alpha);
+
+ return mirrorUnsignedByteRefColors[screen];
+ } else {
+ // if alpha is different, update the alpha values
+
+ //System.err.println("updateAlphaInByteRefColors 1 : alpha is different, update the alpha values " + alpha);
+
+ float m = alpha / lastAlpha[screen];
+
+ byte[] cdata = mirrorUnsignedByteRefColors[screen];
+
+ // We've to traverse the whole due to BugId : 4676483
+ for (int i = 0, j = 0; i < vertexCount; i++, j+=4) {
+ cdata[j+3] = (byte)( ((int)cdata[j+3] & 0xff) * m);
+ }
+ }
+ } else {
+ // color data is modified
+ if (screen == 0) {
+ //System.err.println("updateAlphaInByteRefColors 2 : just update alpha =" + alpha);
+
+ // just update alpha values since screen 0 data is
+ // already updated in setupMirrorColorPointer
+
+ byte[] cdata = mirrorUnsignedByteRefColors[screen];
+
+ // This part is also incorrect due to BugId : 4676483
+ // But traversing the whole array doesn't help either, as there
+ // isn't a mechanism to indicate the the alpha component has
+ // not changed by user.
+ int j = initialColorIndex * 4;
+ for (int i = initialColorIndex; i < validVertexCount; i++, j+=4) {
+ cdata[j+3] = (byte)(((int)cdata[j+3] & 0xff) * alpha);
+ }
+ } else {
+ // update color values from screen 0 data
+ float m;
+
+ //System.err.println("updateAlphaInByteRefColors 3 : update color values from screen 0 data " + alpha);
+
+ if ((colorChanged & 1) == 0) {
+ // alpha is up to date in screen 0
+ m = alpha / lastAlpha[0];
+ } else {
+ m = alpha;
+ }
+ byte[] sdata = mirrorUnsignedByteRefColors[0];
+ byte[] cdata = mirrorUnsignedByteRefColors[screen];
+
+ int j = initialColorIndex * 4;
+ for (int i = initialColorIndex; i < validVertexCount; i++) {
+ cdata[j] = sdata[j++];
+ cdata[j] = sdata[j++];
+ cdata[j] = sdata[j++];
+ cdata[j] = (byte)(((int)sdata[j++]& 0xff) * m);
+ }
+ }
+ }
+
+ lastAlpha[screen] = alpha;
+ colorChanged &= ~(1 << screen);
+ dirtyFlag |= COLOR_CHANGED;
+ return mirrorUnsignedByteRefColors[screen];
+ }
+
+
+ Object[] updateAlphaInVertexData(Canvas3D cv, int screen, float alpha) {
+
+ Object[] retVal = new Object[2];
+ retVal[0] = Boolean.FALSE;
+
+ // update alpha only if vertex format includes alpha
+ if ((vertexFormat & GeometryArray.COLOR) == 0) {
+ retVal[1] = vertexData;
+ return retVal;
+ }
+
+ // if alpha is smaller than EPSILON, set it to EPSILON, so that
+ // even if alpha is equal to 0, we will not completely lose
+ // the original alpha value
+ if (alpha <= EPSILON) {
+ alpha = (float)EPSILON;
+ }
+ retVal[0] = Boolean.TRUE;
+
+ assert lastAlpha != null;
+ assert mvertexData == null || mvertexData.length == lastAlpha.length;
+
+ // Issue 113 - reallocate lastAlpha array if needed, but no need to
+ // update the values here
+ if (lastAlpha.length <= screen) {
+ float[] la = new float[screen + 1];
+ for (int i = 0; i < lastAlpha.length; i++) {
+ la[i] = lastAlpha[i];
+ }
+ lastAlpha = la;
+ }
+
+ // allocate a copy of the vertex data for the screen if needed.
+ // Note that a copy operation only happens in the multi-screens case.
+ // We always use the existing vertexData for screen 0.
+ if (mvertexData == null || mvertexData.length <= screen) {
+
+ float[][] cfData = new float[screen + 1][];
+ int oldSize = 1;
+
+ if (mvertexData != null) {
+ oldSize = mvertexData.length;
+ for (int i = 0; i < mvertexData.length; i++) {
+ cfData[i] = mvertexData[i];
+ }
+ }
+
+ if (cfData[0] == null) {
+ cfData[0] = vertexData;
+ }
+
+ // Issue 113 - allocate entries for [oldSize..screen];
+ // copy cfData[0] to cfData[oldsize..screen-1] and
+ // lastAlpha[0] to lastAlpha[oldsize..screen-1].
+ if (screen > 0) {
+ for (int i = oldSize; i < screen+1; i++) {
+ cfData[i] = new float[stride * vertexCount];
+ System.arraycopy(cfData[0], 0, cfData[i], 0,
+ stride * vertexCount);
+ lastAlpha[i] = lastAlpha[0];
+ }
+ }
+
+ mvertexData = cfData;
+
+ // Issue 113 - since we copied the data from screen 0, we don't need
+ // to do any further special processing.
+ }
+
+ assert lastAlpha[screen] >= 0.0;
+
+ if ((colorChanged & (1<<screen)) == 0) {
+ // color data is not modified
+ if (Math.abs(lastAlpha[screen] - alpha) <= EPSILON) {
+ // and if alpha is the same as the last one,
+ // just return the data
+ retVal[1] = mvertexData[screen];
+ return retVal;
+ } else {
+ // if alpha is different, update the alpha values
+ float m = alpha / lastAlpha[screen];
+
+ float[] cdata = mvertexData[screen];
+ for (int i = 0, j = colorOffset; i < vertexCount;
+ i++, j+=stride) {
+ cdata[j+3] *= m;
+ }
+ }
+ } else {
+ // color data is modified
+ if (screen == 0) {
+ // just update alpha values since screen 0 data is
+ // already updated in setupMirrorColorPointer
+
+ float[] cdata = mvertexData[screen];
+ double m = alpha / lastAlpha[0];
+
+ for (int i = 0, j = colorOffset; i < vertexCount;
+ i++, j+=stride) {
+ cdata[j+3] *= m;
+ }
+ } else {
+ // update color values from screen 0 data
+
+ float m = alpha / lastAlpha[0];
+ float[] sdata = mvertexData[0];
+ float[] cdata = mvertexData[screen];
+
+ for (int i = 0, j = colorOffset; i < vertexCount;
+ i++, j+=stride) {
+ System.arraycopy(sdata, j, cdata, j, 3);
+ cdata[j+3] = sdata[j+3] * m;
+ }
+ }
+ }
+
+ lastAlpha[screen] = alpha;
+ colorChanged &= ~(1 << screen);
+ dirtyFlag |= COLOR_CHANGED;
+ retVal[1] = mvertexData[screen];
+ return retVal;
+ }
+
+ Object[] updateAlphaInInterLeavedData(Canvas3D cv, int screen, float alpha) {
+
+ Object[] retVal = new Object[2];
+ retVal[0] = Boolean.FALSE;
+
+ // update alpha only if vertex format includes alpha
+ if (((vertexFormat | c4fAllocated) & GeometryArray.WITH_ALPHA) == 0) {
+ retVal[1] = mirrorInterleavedColorPointer[0];
+ return retVal;
+ }
+ int coffset = initialColorIndex << 2; // Each color is 4 floats
+
+ // if alpha is smaller than EPSILON, set it to EPSILON, so that
+ // even if alpha is equal to 0, we will not completely lose
+ // the original alpha value
+ if (alpha <= EPSILON) {
+ alpha = (float)EPSILON;
+ }
+ retVal[0] = Boolean.TRUE;
+
+ assert lastAlpha != null;
+ assert mirrorInterleavedColorPointer != null;
+ assert mirrorInterleavedColorPointer.length == lastAlpha.length;
+
+ // Issue 113 - reallocate lastAlpha array if needed, but no need to
+ // update the values here
+ if (lastAlpha.length <= screen) {
+ float[] la = new float[screen + 1];
+ for (int i = 0; i < lastAlpha.length; i++) {
+ la[i] = lastAlpha[i];
+ }
+ lastAlpha = la;
+ }
+
+ // allocate a copy of the vertex data for the screen if needed.
+ // this piece of code is only for multi-screens case
+ if (mirrorInterleavedColorPointer.length <= screen) {
+
+ float[][] cfData = new float[screen + 1][];
+
+ for (int i = 0; i < mirrorInterleavedColorPointer.length; i++) {
+ cfData[i] = mirrorInterleavedColorPointer[i];
+ }
+
+ // Issue 113 - allocate entries for [oldSize..screen];
+ // copy cfData[0] to cfData[oldsize..screen-1] and
+ // lastAlpha[0] to lastAlpha[oldsize..screen-1].
+ for (int i = mirrorInterleavedColorPointer.length; i < screen+1; i++) {
+ cfData[i] = new float[4 * vertexCount];
+ System.arraycopy(cfData[0], 0, cfData[i], 0, 4 * vertexCount);
+ lastAlpha[i] = lastAlpha[0];
+ }
+
+ mirrorInterleavedColorPointer = cfData;
+
+ // Issue 113 - since we copied the data from screen 0, we don't need
+ // to do any further special processing.
+ }
+
+ assert lastAlpha[screen] >= 0.0;
+
+ if ((colorChanged & (1<<screen)) == 0) {
+ // color data is not modified
+ if (Math.abs(lastAlpha[screen] - alpha) <= EPSILON) {
+ // and if alpha is the same as the last one,
+ // just return the data
+ retVal[1] = mirrorInterleavedColorPointer[screen];
+ return retVal;
+ } else {
+
+ // if alpha is different, update the alpha values
+
+ float m = alpha / lastAlpha[screen];
+
+ float[] cdata = mirrorInterleavedColorPointer[screen];
+
+ coffset = initialColorIndex << 2;
+ for (int i = coffset; i < coffset + (vertexCount << 2); i+=4) {
+ cdata[i+3] = cdata[i+3] * m;
+ }
+ }
+ } else {
+ // color data is modified
+ if (screen == 0) {
+
+ // just update alpha values since screen 0 data is
+ // already updated in setupMirrorInterleavedColorPointer
+
+ float[] cdata = mirrorInterleavedColorPointer[screen];
+
+ for (int i = coffset; i < coffset + (vertexCount << 2); i+=4) {
+ cdata[i+3] = cdata[i+3] * alpha;
+ }
+ } else {
+ // update color values from screen 0 data
+
+ float m;
+
+ if ((colorChanged & 1) == 0) {
+ // alpha is up to date in screen 0
+ m = alpha / lastAlpha[0];
+ } else {
+ m = alpha;
+ }
+
+ float[] sdata = mirrorInterleavedColorPointer[0];
+ float[] cdata = mirrorInterleavedColorPointer[screen];
+
+ for (int i = coffset; i < coffset + (vertexCount << 2);) {
+ // System.arraycopy(sdata, i, cdata, i, 3);
+ cdata[i] = sdata[i++];
+ cdata[i] = sdata[i++];
+ cdata[i] = sdata[i++];
+ cdata[i] = sdata[i++] * m;
+ }
+ }
+ }
+
+ lastAlpha[screen] = alpha;
+ colorChanged &= ~(1 << screen);
+ dirtyFlag |= COLOR_CHANGED;
+ retVal[1] = mirrorInterleavedColorPointer[screen];
+ return retVal;
+ }
+
+
+ // pass < 0 implies underlying library supports multiTexture, so
+ // use the multiTexture extension to send all texture units
+ // data in one pass
+ // pass >= 0 implies one pass for one texture unit state
+
+ @Override
+ void execute(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale,
+ boolean updateAlpha, float alpha,
+ int screen,
+ boolean ignoreVertexColors) {
+
+ int cdirty;
+ boolean useAlpha = false;
+ Object[] retVal;
+
+ // Check for by-copy case
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ float[] vdata;
+
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ // update the alpha values
+ retVal = updateAlphaInVertexData(cv, screen, alpha);
+ useAlpha = (retVal[0] == Boolean.TRUE);
+ vdata = (float[])retVal[1];
+
+ // D3D only
+ if (alpha != lastScreenAlpha) {
+ // handle multiple screen case
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ vdata = vertexData;
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+ }
+ // geomLock is get in MasterControl when
+ // RenderBin render the geometry. So it is safe
+ // just to set the dirty flag here
+ dirtyFlag = 0;
+ }
+
+ Pipeline.getPipeline().execute(cv.ctx,
+ this, geoType, isNonUniformScale,
+ useAlpha,
+ ignoreVertexColors,
+ initialVertexIndex,
+ validVertexCount,
+ ((vertexFormat & GeometryArray.COLOR) != 0)?(vertexFormat|GeometryArray.COLOR_4):vertexFormat,
+ texCoordSetCount, texCoordSetMap,
+ (texCoordSetMap == null) ? 0 : texCoordSetMap.length,
+ texCoordSetMapOffset,
+ cv.numActiveTexUnit,
+ vertexAttrCount, vertexAttrSizes,
+ vdata, null,
+ cdirty);
+ }
+
+ //By reference with java array
+ else if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ // interleaved data
+ if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ if(interLeavedVertexData == null)
+ return;
+
+ float[] cdata = null;
+
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ // update the alpha values
+ retVal = updateAlphaInInterLeavedData(cv, screen, alpha);
+ useAlpha = (retVal[0] == Boolean.TRUE);
+ cdata = (float[])retVal[1];
+ if (alpha != lastScreenAlpha) {
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+ }
+ dirtyFlag = 0;
+ }
+
+ Pipeline.getPipeline().execute(cv.ctx,
+ this, geoType, isNonUniformScale,
+ useAlpha,
+ ignoreVertexColors,
+ initialVertexIndex,
+ validVertexCount,
+ vertexFormat,
+ texCoordSetCount, texCoordSetMap,
+ (texCoordSetMap == null) ? 0 : texCoordSetMap.length,
+ texCoordSetMapOffset,
+ cv.numActiveTexUnit,
+ vertexAttrCount, vertexAttrSizes,
+ interLeavedVertexData, cdata,
+ cdirty);
+
+ } // end of interleaved case
+
+ // non interleaved data
+ else {
+
+ // Check if a vertexformat is set, but the array is null
+ // if yes, don't draw anything
+ if ((vertexType == 0) ||
+ ((vertexType & VERTEX_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.COLOR) != 0) &&
+ (vertexType & COLOR_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.NORMALS) != 0) &&
+ (vertexType & NORMAL_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) &&
+ (vertexType & VATTR_DEFINED) == 0) ||
+ (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) &&
+ (vertexType & TEXCOORD_DEFINED) == 0)) {
+ return;
+ } else {
+ byte[] cbdata = null;
+ float[] cfdata = null;
+
+ if ((vertexType & (CF | C3F | C4F )) != 0) {
+
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ cfdata = updateAlphaInFloatRefColors(cv, screen, alpha);
+ if (alpha != lastScreenAlpha) {
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ cfdata = mirrorFloatRefColors[0];
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+
+ }
+ dirtyFlag = 0;
+ }
+ } // end of color in float format
+ else if ((vertexType & (CUB| C3UB | C4UB)) != 0) {
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ cbdata = updateAlphaInByteRefColors(cv, screen, alpha);
+ if (alpha != lastScreenAlpha) {
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ cbdata = mirrorUnsignedByteRefColors[0];
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+ }
+ dirtyFlag = 0;
+ }
+ } // end of color in byte format
+ else {
+ cdirty = dirtyFlag;
+ }
+ // setup vdefined to passed to native code
+ int vdefined = 0;
+ if((vertexType & (PF | P3F)) != 0)
+ vdefined |= COORD_FLOAT;
+ if((vertexType & (PD | P3D)) != 0)
+ vdefined |= COORD_DOUBLE;
+ if((vertexType & (CF | C3F | C4F)) != 0)
+ vdefined |= COLOR_FLOAT;
+ if((vertexType & (CUB| C3UB | C4UB)) != 0)
+ vdefined |= COLOR_BYTE;
+ if((vertexType & NORMAL_DEFINED) != 0)
+ vdefined |= NORMAL_FLOAT;
+ if((vertexType & VATTR_DEFINED) != 0)
+ vdefined |= VATTR_FLOAT;
+ if((vertexType & TEXCOORD_DEFINED) != 0)
+ vdefined |= TEXCOORD_FLOAT;
+
+ Pipeline.getPipeline().executeVA(cv.ctx,
+ this, geoType, isNonUniformScale,
+ ignoreVertexColors,
+ validVertexCount,
+ (vertexFormat | c4fAllocated),
+ vdefined,
+ initialCoordIndex,
+ mirrorFloatRefCoords, mirrorDoubleRefCoords,
+ initialColorIndex, cfdata, cbdata,
+ initialNormalIndex, mirrorFloatRefNormals,
+ vertexAttrCount, vertexAttrSizes,
+ initialVertexAttrIndex, mirrorFloatRefVertexAttrs,
+ ((texCoordSetMap == null) ? 0:texCoordSetMap.length),
+ texCoordSetMap,
+ cv.numActiveTexUnit,
+ initialTexCoordIndex,texCoordStride,
+ mirrorRefTexCoords, cdirty);
+ }// end of all vertex data being set
+ }// end of non interleaved case
+ }// end of by reference with java array
+
+ //By reference with nio buffer
+ else {
+ // interleaved data
+ if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+
+ if ( interleavedFloatBufferImpl == null)
+ return;
+
+ float[] cdata = null;
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ // update the alpha values
+ // XXXX: to handle alpha case
+ retVal = updateAlphaInInterLeavedData(cv, screen, alpha);
+ useAlpha = (retVal[0] == Boolean.TRUE);
+ cdata = (float[])retVal[1];
+
+ if (alpha != lastScreenAlpha) {
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ // XXXX: to handle alpha case
+ cdata = null;
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+ }
+ dirtyFlag = 0;
+ }
+
+ Pipeline.getPipeline().executeInterleavedBuffer(cv.ctx,
+ this, geoType, isNonUniformScale,
+ useAlpha,
+ ignoreVertexColors,
+ initialVertexIndex,
+ validVertexCount,
+ vertexFormat,
+ texCoordSetCount, texCoordSetMap,
+ (texCoordSetMap == null) ? 0 : texCoordSetMap.length,
+ texCoordSetMapOffset,
+ cv.numActiveTexUnit,
+ interleavedFloatBufferImpl, cdata,
+ cdirty);
+
+ } // end of interleaved case
+
+ // non interleaved data
+ else {
+
+ // Check if a vertexformat is set, but the array is null
+ // if yes, don't draw anything
+ if ((vertexType == 0) ||
+ ((vertexType & VERTEX_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.COLOR) != 0) &&
+ (vertexType & COLOR_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.NORMALS) != 0) &&
+ (vertexType & NORMAL_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) &&
+ (vertexType & VATTR_DEFINED) == 0) ||
+ (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) &&
+ (vertexType & TEXCOORD_DEFINED) == 0)) {
+ return;
+ } else {
+ byte[] cbdata = null;
+ float[] cfdata = null;
+
+ if ((vertexType & CF ) != 0) {
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ cfdata = updateAlphaInFloatRefColors(cv,
+ screen, alpha);
+ if (alpha != lastScreenAlpha) {
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ // XXXX: handle transparency case
+ //cfdata = null;
+ cfdata = mirrorFloatRefColors[0];
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+
+ }
+ dirtyFlag = 0;
+ }
+ } // end of color in float format
+ else if ((vertexType & CUB) != 0) {
+ synchronized (this) {
+ cdirty = dirtyFlag;
+ if (updateAlpha && !ignoreVertexColors) {
+ cbdata = updateAlphaInByteRefColors(
+ cv, screen, alpha);
+ if (alpha != lastScreenAlpha) {
+ lastScreenAlpha = alpha;
+ cdirty |= COLOR_CHANGED;
+ }
+ } else {
+ // XXXX: handle transparency case
+ //cbdata = null;
+ cbdata = mirrorUnsignedByteRefColors[0];
+ // if transparency switch between on/off
+ if (lastScreenAlpha != -1) {
+ lastScreenAlpha = -1;
+ cdirty |= COLOR_CHANGED;
+ }
+ }
+ dirtyFlag = 0;
+ }
+ } // end of color in byte format
+ else {
+ cdirty = dirtyFlag;
+ }
+
+ Buffer vcoord = null;
+ Buffer cdataBuffer = null;
+ FloatBuffer normal=null;
+
+ int vdefined = 0;
+ if((vertexType & PF) != 0) {
+ vdefined |= COORD_FLOAT;
+ vcoord = floatBufferRefCoords;
+ } else if((vertexType & PD ) != 0) {
+ vdefined |= COORD_DOUBLE;
+ vcoord = doubleBufferRefCoords;
+ }
+
+ if((vertexType & CF ) != 0) {
+ vdefined |= COLOR_FLOAT;
+ cdataBuffer = floatBufferRefColors;
+ } else if((vertexType & CUB) != 0) {
+ vdefined |= COLOR_BYTE;
+ cdataBuffer = byteBufferRefColors;
+ }
+
+ if((vertexType & NORMAL_DEFINED) != 0) {
+ vdefined |= NORMAL_FLOAT;
+ normal = floatBufferRefNormals;
+ }
+
+ if ((vertexType & VATTR_DEFINED) != 0) {
+ vdefined |= VATTR_FLOAT;
+ }
+
+ if((vertexType & TEXCOORD_DEFINED) != 0)
+ vdefined |= TEXCOORD_FLOAT;
+
+ Pipeline.getPipeline().executeVABuffer(cv.ctx,
+ this, geoType, isNonUniformScale,
+ ignoreVertexColors,
+ validVertexCount,
+ (vertexFormat | c4fAllocated),
+ vdefined,
+ initialCoordIndex,
+ vcoord,
+ initialColorIndex,
+ cdataBuffer,
+ cfdata, cbdata,
+ initialNormalIndex,
+ normal,
+ vertexAttrCount, vertexAttrSizes,
+ initialVertexAttrIndex,
+ floatBufferRefVertexAttrs,
+ ((texCoordSetMap == null) ? 0:texCoordSetMap.length),
+ texCoordSetMap,
+ cv.numActiveTexUnit,
+ initialTexCoordIndex,texCoordStride,
+ refTexCoords, cdirty);
+ }// end of all vertex data being set
+ }// end of non interleaved case
+ }// end of by reference with nio-buffer case
+ }
+
+ void buildGA(Canvas3D cv, RenderAtom ra, boolean isNonUniformScale,
+ boolean updateAlpha, float alpha, boolean ignoreVertexColors,
+ Transform3D xform, Transform3D nxform) {
+
+ float[] vdata = null;
+
+ // NIO buffers are no longer supported in display lists
+ assert (vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0;
+
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ vdata = vertexData;
+ }
+ else if ((vertexFormat & GeometryArray.INTERLEAVED) != 0 &&
+ ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0)) {
+ vdata = interLeavedVertexData;
+ }
+ if (vdata != null) {
+ /*
+ System.err.println("calling native buildGA()");
+ System.err.println("geoType = "+geoType+" initialVertexIndex = "+initialVertexIndex+" validVertexCount = "+validVertexCount+" vertexFormat = "+vertexFormat+" vertexData = "+vertexData);
+ */
+ Pipeline.getPipeline().buildGA(cv.ctx,
+ this, geoType, isNonUniformScale,
+ updateAlpha, alpha, ignoreVertexColors,
+ initialVertexIndex,
+ validVertexCount, vertexFormat,
+ texCoordSetCount, texCoordSetMap,
+ (texCoordSetMap == null) ? 0 : texCoordSetMap.length,
+ texCoordSetMapOffset,
+ vertexAttrCount, vertexAttrSizes,
+ (xform == null) ? null : xform.mat,
+ (nxform == null) ? null : nxform.mat,
+ vdata);
+ }
+ else {
+ // Check if a vertexformat is set, but the array is null
+ // if yes, don't draw anything
+ if ((vertexType == 0) ||
+ ((vertexType & VERTEX_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.COLOR) != 0) &&
+ (vertexType & COLOR_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.NORMALS) != 0) &&
+ (vertexType & NORMAL_DEFINED) == 0) ||
+ (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) &&
+ (vertexType & VATTR_DEFINED) == 0) ||
+ (((vertexFormat& GeometryArray.TEXTURE_COORDINATE) != 0) &&
+ (vertexType & TEXCOORD_DEFINED) == 0)) {
+
+ return;
+ }
+
+ // Either non-interleaved, by-ref or nio buffer
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ // Java array case
+ // setup vdefined to passed to native code
+ int vdefined = 0;
+ if((vertexType & (PF | P3F)) != 0)
+ vdefined |= COORD_FLOAT;
+ if((vertexType & (PD | P3D)) != 0)
+ vdefined |= COORD_DOUBLE;
+ if((vertexType & (CF | C3F | C4F)) != 0)
+ vdefined |= COLOR_FLOAT;
+ if((vertexType & (CUB| C3UB | C4UB)) != 0)
+ vdefined |= COLOR_BYTE;
+ if((vertexType & NORMAL_DEFINED) != 0)
+ vdefined |= NORMAL_FLOAT;
+ if((vertexType & VATTR_DEFINED) != 0)
+ vdefined |= VATTR_FLOAT;
+ if((vertexType & TEXCOORD_DEFINED) != 0)
+ vdefined |= TEXCOORD_FLOAT;
+
+ Pipeline.getPipeline().buildGAForByRef(cv.ctx,
+ this, geoType, isNonUniformScale,
+ updateAlpha, alpha,
+ ignoreVertexColors,
+ validVertexCount,
+ vertexFormat,
+ vdefined,
+ initialCoordIndex,
+ mirrorFloatRefCoords, mirrorDoubleRefCoords,
+ initialColorIndex, mirrorFloatRefColors[0], mirrorUnsignedByteRefColors[0],
+ initialNormalIndex, mirrorFloatRefNormals,
+ vertexAttrCount, vertexAttrSizes,
+ initialVertexAttrIndex, mirrorFloatRefVertexAttrs,
+ ((texCoordSetMap == null) ? 0:texCoordSetMap.length),
+ texCoordSetMap,
+ initialTexCoordIndex,texCoordStride,
+ mirrorRefTexCoords,
+ (xform == null) ? null : xform.mat,
+ (nxform == null) ? null : nxform.mat);
+ }
+ /*
+ // NOTE: NIO buffers are no longer supported in display lists.
+ // This was never enabled by default anyway (only when the
+ // optimizeForSpace property was set to false), so it wasn't
+ // well-tested. If future support is desired, we will need to
+ // add vertex attributes to buildGAForBuffer. There are no plans
+ // to ever do this.
+ else {
+ // NIO Buffer case
+ Object vcoord = null, cdataBuffer=null, normal=null;
+
+ int vdefined = 0;
+ if((vertexType & PF) != 0) {
+ vdefined |= COORD_FLOAT;
+ vcoord = floatBufferRefCoords.getBufferAsObject();
+ } else if((vertexType & PD ) != 0) {
+ vdefined |= COORD_DOUBLE;
+ vcoord = doubleBufferRefCoords.getBufferAsObject();
+ }
+
+ if((vertexType & CF ) != 0) {
+ vdefined |= COLOR_FLOAT;
+ cdataBuffer = floatBufferRefColors.getBufferAsObject();
+ } else if((vertexType & CUB) != 0) {
+ vdefined |= COLOR_BYTE;
+ cdataBuffer = byteBufferRefColors.getBufferAsObject();
+ }
+
+ if((vertexType & NORMAL_DEFINED) != 0) {
+ vdefined |= NORMAL_FLOAT;
+ normal = floatBufferRefNormals.getBufferAsObject();
+ }
+
+ if((vertexType & TEXCOORD_DEFINED) != 0)
+ vdefined |= TEXCOORD_FLOAT;
+ // NOTE : need to add vertex attrs
+ Pipeline.getPipeline().buildGAForBuffer(cv.ctx,
+ this, geoType, isNonUniformScale,
+ updateAlpha, alpha,
+ ignoreVertexColors,
+ validVertexCount,
+ vertexFormat,
+ vdefined,
+ initialCoordIndex,
+ vcoord,
+ initialColorIndex,cdataBuffer,
+ initialNormalIndex, normal,
+ ((texCoordSetMap == null) ? 0:texCoordSetMap.length),
+ texCoordSetMap,
+ initialTexCoordIndex,texCoordStride,
+ refTexCoords,
+ (xform == null) ? null : xform.mat,
+ (nxform == null) ? null : nxform.mat);
+ }
+ */
+
+ }
+
+ }
+
+ void unIndexify(IndexedGeometryArrayRetained src) {
+ if ((src.vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ unIndexifyJavaArray(src);
+ }
+ else {
+ unIndexifyNIOBuffer(src);
+ }
+ }
+
+ private void unIndexifyJavaArray(IndexedGeometryArrayRetained src) {
+// System.err.println("unIndexifyJavaArray");
+
+ int vOffset = 0, srcOffset, tOffset = 0;
+ int index, colorStride = 0;
+ float[] vdata = null;
+ int i;
+ int start, end;
+ start = src.initialIndexIndex;
+ end = src.initialIndexIndex + src.validIndexCount;
+ // If its either "normal" data or interleaved data then ..
+ if (((src.vertexFormat & GeometryArray.BY_REFERENCE) == 0) ||
+ ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0)) {
+
+ if ((src.vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ vdata = src.vertexData;
+ if ((src.vertexFormat & GeometryArray.COLOR) != 0)
+ colorStride = 4;
+ }
+ else if ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ vdata = src.interLeavedVertexData;
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ colorStride = 4;
+ else if ((src.vertexFormat & GeometryArray.COLOR) != 0)
+ colorStride = 3;
+ }
+
+ // System.err.println("===> start = "+start+" end = "+end);
+ for (index= start; index < end; index++) {
+ if ((vertexFormat & GeometryArray.NORMALS) != 0){
+ System.arraycopy(vdata,
+ src.indexNormal[index]*src.stride + src.normalOffset,
+ vertexData, vOffset + normalOffset, 3);
+ }
+ if (colorStride == 4){
+ // System.err.println("===> copying color3");
+ System.arraycopy(vdata,
+ src.indexColor[index]*src.stride + src.colorOffset,
+ vertexData, vOffset + colorOffset, colorStride);
+ } else if (colorStride == 3) {
+ // System.err.println("===> copying color4");
+ System.arraycopy(vdata,
+ src.indexColor[index]*src.stride + src.colorOffset,
+ vertexData, vOffset + colorOffset, colorStride);
+ vertexData[vOffset + colorOffset + 3] = 1.0f;
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ int tcOffset = vOffset + textureOffset;
+ int interleavedOffset = 0;
+
+ for (i = 0; i < texCoordSetCount;
+ i++, tcOffset += texCoordStride) {
+
+ if ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ interleavedOffset = i * texCoordStride;
+ }
+
+ System.arraycopy(vdata,
+ (src.indexTexCoord[i][index])*src.stride + src.textureOffset + interleavedOffset,
+ vertexData, tcOffset, texCoordStride);
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ // vertex attributes can't be interleaved
+ assert (src.vertexFormat & GeometryArray.INTERLEAVED) == 0;
+
+ for (i = 0; i < vertexAttrCount; i++) {
+ int vaOffset = vOffset + vertexAttrOffsets[i];
+
+ System.arraycopy(vdata,
+ (src.indexVertexAttr[i][index])*src.stride + src.vertexAttrOffsets[i],
+ vertexData, vaOffset, vertexAttrSizes[i]);
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.COORDINATES) != 0){
+ // System.err.println("===> copying coords");
+ System.arraycopy(vdata,
+ src.indexCoord[index]*src.stride
+ + src.coordinateOffset,
+ vertexData,
+ vOffset + coordinateOffset, 3);
+ }
+ vOffset += stride;
+ }
+
+ } else {
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ vOffset = normalOffset;
+ switch ((src.vertexType & NORMAL_DEFINED)) {
+ case NF:
+ for (index=start; index < end; index++) {
+ System.arraycopy(src.floatRefNormals,
+ src.indexNormal[index]*3,
+ vertexData,
+ vOffset, 3);
+ vOffset += stride;
+ }
+ break;
+ case N3F:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexNormal[index];
+ vertexData[vOffset] = src.v3fRefNormals[srcOffset].x;
+ vertexData[vOffset+1] = src.v3fRefNormals[srcOffset].y;
+ vertexData[vOffset+2] = src.v3fRefNormals[srcOffset].z;
+ vOffset += stride;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR) != 0) {
+ vOffset = colorOffset;
+ int multiplier = 3;
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ multiplier = 4;
+
+ switch ((src.vertexType & COLOR_DEFINED)) {
+ case CF:
+ for (index=start; index < end; index++) {
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+ System.arraycopy(src.floatRefColors,
+ src.indexColor[index]*multiplier,
+ vertexData,
+ vOffset, 4);
+ }
+ else {
+ System.arraycopy(src.floatRefColors,
+ src.indexColor[index]*multiplier,
+ vertexData,
+ vOffset, 3);
+ vertexData[vOffset+3] = 1.0f;
+ }
+ vOffset += stride;
+ }
+ break;
+ case CUB:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexColor[index] * multiplier;
+ vertexData[vOffset] = (src.byteRefColors[srcOffset] & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+1] = (src.byteRefColors[srcOffset+1] & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+2] = (src.byteRefColors[srcOffset+2] & 0xff) * ByteToFloatScale;
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+ vertexData[vOffset+3] = (src.byteRefColors[srcOffset+3] & 0xff) * ByteToFloatScale;
+ }
+ else {
+ vertexData[vOffset+3] = 1.0f;
+ }
+ vOffset += stride;
+ }
+ break;
+ case C3F:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexColor[index];
+ vertexData[vOffset] = src.c3fRefColors[srcOffset].x;
+ vertexData[vOffset+1] = src.c3fRefColors[srcOffset].y;
+ vertexData[vOffset+2] = src.c3fRefColors[srcOffset].z;
+ vertexData[vOffset+3] = 1.0f;
+ vOffset += stride;
+ }
+ break;
+ case C4F:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexColor[index];
+ vertexData[vOffset] = src.c4fRefColors[srcOffset].x;
+ vertexData[vOffset+1] = src.c4fRefColors[srcOffset].y;
+ vertexData[vOffset+2] = src.c4fRefColors[srcOffset].z;
+ vertexData[vOffset+3] = src.c4fRefColors[srcOffset].w;
+ vOffset += stride;
+ }
+ break;
+ case C3UB:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexColor[index];
+ vertexData[vOffset] = (src.c3bRefColors[srcOffset].x & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+1] = (src.c3bRefColors[srcOffset].y & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+2] = (src.c3bRefColors[srcOffset].z & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+3] = 1.0f;
+ vOffset += stride;
+ }
+ break;
+ case C4UB:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexColor[index];
+ vertexData[vOffset] = (src.c4bRefColors[srcOffset].x & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+1] = (src.c4bRefColors[srcOffset].y & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+2] = (src.c4bRefColors[srcOffset].z & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+3] = (src.c4bRefColors[srcOffset].w & 0xff) * ByteToFloatScale;
+ vOffset += stride;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ vOffset = textureOffset;
+ switch ((src.vertexType & TEXCOORD_DEFINED)) {
+ case TF:
+ for (index=start; index < end; index++) {
+ for (i = 0, tOffset = vOffset;
+ i < texCoordSetCount; i++) {
+ System.arraycopy(src.refTexCoords[i],
+ src.indexTexCoord[i][index]*texCoordStride,
+ vertexData, tOffset, texCoordStride);
+ tOffset += texCoordStride;
+ }
+ vOffset += stride;
+ }
+ break;
+ case T2F:
+ for (index=start; index < end; index++) {
+ for (i = 0, tOffset = vOffset;
+ i < texCoordSetCount; i++) {
+ srcOffset = src.indexTexCoord[i][index];
+ vertexData[tOffset] =
+ ((TexCoord2f[])src.refTexCoords[i])[srcOffset].x;
+ vertexData[tOffset+1] =
+ ((TexCoord2f[])src.refTexCoords[i])[srcOffset].y;
+ tOffset += texCoordStride;
+ }
+ vOffset += stride;
+ }
+ break;
+ case T3F:
+ for (index=start; index < end; index++) {
+ for (i = 0, tOffset = vOffset;
+ i < texCoordSetCount; i++) {
+ srcOffset = src.indexTexCoord[i][index];
+ vertexData[tOffset] =
+ ((TexCoord3f[])src.refTexCoords[i])[srcOffset].x;
+ vertexData[tOffset+1] =
+ ((TexCoord3f[])src.refTexCoords[i])[srcOffset].y;
+ vertexData[tOffset+2] =
+ ((TexCoord3f[])src.refTexCoords[i])[srcOffset].z;
+ tOffset += texCoordStride;
+ }
+ vOffset += stride;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ vOffset = 0;
+ switch (src.vertexType & VATTR_DEFINED) {
+ case AF:
+ for (index=start; index < end; index++) {
+ for (i = 0; i < vertexAttrCount; i++) {
+ int vaOffset = vOffset + vertexAttrOffsets[i];
+ System.arraycopy(src.floatRefVertexAttrs[i],
+ src.indexVertexAttr[i][index]*vertexAttrSizes[i],
+ vertexData, vaOffset, vertexAttrSizes[i]);
+ }
+ vOffset += stride;
+ }
+ break;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.COORDINATES) != 0) {
+ vOffset = coordinateOffset;
+ switch ((src.vertexType & VERTEX_DEFINED)) {
+ case PF:
+ for (index=start; index < end; index++) {
+ System.arraycopy(src.floatRefCoords,
+ src.indexCoord[index]*3,
+ vertexData,
+ vOffset, 3);
+ vOffset += stride;
+ }
+ break;
+ case PD:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexCoord[index] * 3;
+ vertexData[vOffset] = (float)src.doubleRefCoords[srcOffset];
+ vertexData[vOffset+1] = (float)src.doubleRefCoords[srcOffset+1];
+ vertexData[vOffset+2] = (float)src.doubleRefCoords[srcOffset+2];
+ vOffset += stride;
+ }
+ break;
+ case P3F:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexCoord[index];
+ vertexData[vOffset] = src.p3fRefCoords[srcOffset].x;
+ vertexData[vOffset+1] = src.p3fRefCoords[srcOffset].y;
+ vertexData[vOffset+2] = src.p3fRefCoords[srcOffset].z;
+ vOffset += stride;
+ }
+ break;
+ case P3D:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexCoord[index];
+ vertexData[vOffset] = (float)src.p3dRefCoords[srcOffset].x;
+ vertexData[vOffset+1] = (float)src.p3dRefCoords[srcOffset].y;
+ vertexData[vOffset+2] = (float)src.p3dRefCoords[srcOffset].z;
+ vOffset += stride;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+ }
+
+
+ private void unIndexifyNIOBuffer(IndexedGeometryArrayRetained src) {
+// System.err.println("unIndexifyNIOBuffer");
+
+ int vOffset = 0, srcOffset, tOffset = 0;
+ int index, colorStride = 0;
+ int i;
+ int start, end;
+ start = src.initialIndexIndex;
+ end = src.initialIndexIndex + src.validIndexCount;
+ // If its interleaved data then ..
+ if ((src.vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ colorStride = 4;
+ else if ((src.vertexFormat & GeometryArray.COLOR) != 0)
+ colorStride = 3;
+
+ // System.err.println("===> start = "+start+" end = "+end);
+ for (index= start; index < end; index++) {
+ if ((vertexFormat & GeometryArray.NORMALS) != 0){
+ src.interleavedFloatBufferImpl.position(src.indexNormal[index]*src.stride + src.normalOffset);
+ src.interleavedFloatBufferImpl.get(vertexData, vOffset + normalOffset, 3);
+ }
+
+ if (colorStride == 4){
+ src.interleavedFloatBufferImpl.position(src.indexColor[index]*src.stride + src.colorOffset);
+ src.interleavedFloatBufferImpl.get(vertexData, vOffset + colorOffset, colorStride);
+ } else if (colorStride == 3) {
+ src.interleavedFloatBufferImpl.position(src.indexColor[index]*src.stride + src.colorOffset);
+ src.interleavedFloatBufferImpl.get(vertexData, vOffset + colorOffset, colorStride);
+ vertexData[vOffset + colorOffset + 3] = 1.0f;
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ int tcOffset = vOffset + textureOffset;
+ for (i = 0; i < texCoordSetCount;
+ i++, tcOffset += texCoordStride) {
+
+ src.interleavedFloatBufferImpl.position((src.indexTexCoord[i][index])*src.stride +
+ src.textureOffset);
+ src.interleavedFloatBufferImpl.get(vertexData, tcOffset, texCoordStride);
+ }
+ }
+ if ((vertexFormat & GeometryArray.COORDINATES) != 0){
+ src.interleavedFloatBufferImpl.position(src.indexCoord[index]*src.stride + src.coordinateOffset );
+ src.interleavedFloatBufferImpl.get(vertexData, vOffset + coordinateOffset, 3);
+ }
+ vOffset += stride;
+ }
+
+ } else {
+ if ((vertexFormat & GeometryArray.NORMALS) != 0){
+ vOffset = normalOffset;
+ if ((src.vertexType & NORMAL_DEFINED) != 0) {
+ for (index=start; index < end; index++) {
+ src.floatBufferRefNormals.position(src.indexNormal[index]*3);
+ src.floatBufferRefNormals.get(vertexData, vOffset, 3);
+ vOffset += stride;
+ }
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR) != 0){
+ vOffset = colorOffset;
+ int multiplier = 3;
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ multiplier = 4;
+
+ switch ((src.vertexType & COLOR_DEFINED)) {
+ case CF:
+ for (index=start; index < end; index++) {
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+ src.floatBufferRefColors.position(src.indexColor[index]*multiplier);
+ src.floatBufferRefColors.get(vertexData, vOffset, 4);
+ }
+ else {
+ src.floatBufferRefColors.position(src.indexColor[index]*multiplier);
+ src.floatBufferRefColors.get(vertexData, vOffset, 3);
+ vertexData[vOffset+3] = 1.0f;
+ }
+ vOffset += stride;
+ }
+ break;
+ case CUB:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexColor[index] * multiplier;
+ vertexData[vOffset] = (src.byteBufferRefColors.get(srcOffset) & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+1] = (src.byteBufferRefColors.get(srcOffset+1) & 0xff) * ByteToFloatScale;
+ vertexData[vOffset+2] = (src.byteBufferRefColors.get(srcOffset+2) & 0xff) * ByteToFloatScale;
+
+ if ((src.vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+ vertexData[vOffset+3] = (src.byteBufferRefColors.get(srcOffset+3) & 0xff) * ByteToFloatScale;
+ }
+ else {
+ vertexData[vOffset+3] = 1.0f;
+ }
+ vOffset += stride;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ vOffset = textureOffset;
+ if ((src.vertexType & TEXCOORD_DEFINED) != 0) {
+ for (index=start; index < end; index++) {
+ for (i = 0, tOffset = vOffset;
+ i < texCoordSetCount; i++) {
+ FloatBuffer texBuffer = (FloatBuffer)src.refTexCoordsBuffer[i].getROBuffer();
+ texBuffer.position(src.indexTexCoord[i][index]*texCoordStride);
+ texBuffer.get(vertexData, tOffset, texCoordStride);
+ tOffset += texCoordStride;
+ }
+ vOffset += stride;
+ }
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ vOffset = 0;
+ if ((src.vertexType & VATTR_DEFINED) == AF) {
+ for (index=start; index < end; index++) {
+ for (i = 0; i < vertexAttrCount; i++) {
+ int vaOffset = vOffset + vertexAttrOffsets[i];
+ FloatBuffer vaBuffer = src.floatBufferRefVertexAttrs[i];
+ vaBuffer.position(src.indexVertexAttr[i][index]*vertexAttrSizes[i]);
+ vaBuffer.get(vertexData, vaOffset, vertexAttrSizes[i]);
+ }
+ vOffset += stride;
+ }
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.COORDINATES) != 0){
+ vOffset = coordinateOffset;
+ switch ((src.vertexType & VERTEX_DEFINED)) {
+ case PF:
+ for (index=start; index < end; index++) {
+ src.floatBufferRefCoords.position(src.indexCoord[index]*3);
+ src.floatBufferRefCoords.get(vertexData, vOffset, 3);
+ vOffset += stride;
+ }
+ break;
+ case PD:
+ for (index=start; index < end; index++) {
+ srcOffset = src.indexCoord[index] * 3;
+ vertexData[vOffset] = (float)src.doubleBufferRefCoords.get(srcOffset);
+ vertexData[vOffset+1] = (float)src.doubleBufferRefCoords.get(srcOffset+1);
+ vertexData[vOffset+2] = (float)src.doubleBufferRefCoords.get(srcOffset+2);
+ vOffset += stride;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+ }
+
+
+ /**
+ * Returns the vertex stride in numbers of floats as a function
+ * of the vertexFormat.
+ * @return the stride in floats for this vertex array
+ */
+ int stride()
+ {
+ int stride = 0;
+
+ if((this.vertexFormat & GeometryArray.COORDINATES) != 0) stride += 3;
+ if((this.vertexFormat & GeometryArray.NORMALS) != 0) stride += 3;
+
+ if ((this.vertexFormat & GeometryArray.COLOR) != 0) {
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ // By copy
+ stride += 4;
+ } else {
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+ stride += 3;
+ }
+ else {
+ stride += 4;
+ }
+ }
+ }
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+
+ if ((this.vertexFormat &
+ GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ texCoordStride = 2;
+ } else if ((this.vertexFormat &
+ GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ texCoordStride = 3;
+ } else if ((this.vertexFormat &
+ GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ texCoordStride = 4;
+ }
+
+ stride += texCoordStride * texCoordSetCount;
+ }
+
+ if ((this.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ stride += vertexAttrStride;
+ }
+
+ //System.err.println("stride() = " + stride);
+ return stride;
+ }
+
+ int[] texCoordSetMapOffset()
+ {
+ if (texCoordSetMap == null)
+ return null;
+
+ texCoordSetMapOffset = new int[texCoordSetMap.length];
+ for (int i = 0; i < texCoordSetMap.length; i++) {
+ if (texCoordSetMap[i] == -1) {
+ texCoordSetMapOffset[i] = -1;
+ } else {
+ texCoordSetMapOffset[i] = texCoordSetMap[i] * texCoordStride;
+ }
+ }
+ return texCoordSetMapOffset;
+ }
+
+ /**
+ * Returns the stride of the set of vertex attributes. This is the
+ * sum of the sizes of each vertex attribute.
+ * @return the stride of the vertex attribute data
+ */
+ int vertexAttrStride() {
+ int sum = 0;
+ for (int i = 0; i < vertexAttrCount; i++) {
+ sum += vertexAttrSizes[i];
+ }
+ return sum;
+ }
+
+ /**
+ * Returns the offset in number of floats from the start of a vertex to
+ * each per-vertex vertex attribute.
+ * @return array of offsets in floats vertex start to the vertex attribute data
+ */
+ int[] vertexAttrOffsets() {
+ int[] offsets;
+
+ // Create array of offsets to the start of each vertex attribute.
+ // The offset of the first attribute is always 0. If no vertex attributes exist,
+ // then we will allocate an array of length 1 to avoid some checking elsewhere.
+ if (vertexAttrCount > 0) {
+ offsets = new int[vertexAttrCount];
+ }
+ else {
+ offsets = new int[1];
+ }
+ offsets[0] = 0;
+ for (int i = 1; i < vertexAttrCount; i++) {
+ offsets[i] = offsets[i-1] + vertexAttrSizes[i-1];
+ }
+
+ return offsets;
+ }
+
+ /**
+ * Returns the offset in number of floats from the start of a vertex to
+ * the per-vertex texture coordinate data.
+ * texture coordinate data always follows vertex attribute data
+ * @return the offset in floats vertex start to the tetxure data
+ */
+ int textureOffset()
+ {
+ int offset = vertexAttrOffsets[0];
+
+ if ((this.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ offset += vertexAttrStride;
+ }
+
+ return offset;
+ }
+
+ /**
+ * Returns the offset in number of floats from the start of a vertex to
+ * the per-vertex color data.
+ * color data always follows texture data
+ * @param vertexFormat the vertex format for this array
+ * @return the offset in floats vertex start to the color data
+ */
+ int colorOffset()
+ {
+ int offset = textureOffset;
+
+ if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
+ offset += 2 * texCoordSetCount;
+ else if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)
+ offset += 3 * texCoordSetCount;
+ else if((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0)
+ offset += 4 * texCoordSetCount;
+
+ return offset;
+ }
+
+ /**
+ * Returns the offset in number of floats from the start of a vertex to
+ * the per-vertex normal data.
+ * normal data always follows color data
+ * @return the offset in floats from the start of a vertex to the normal
+ */
+ int normalOffset()
+ {
+ int offset = colorOffset;
+
+ if ((this.vertexFormat & GeometryArray.COLOR) != 0) {
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ offset += 4;
+ } else {
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) == 0) {
+ offset += 3;
+ }
+ else {
+ offset += 4;
+ }
+ }
+ }
+ return offset;
+ }
+
+ /**
+ * Returns the offset in number of floats from the start of a vertex to
+ * the per vertex coordinate data.
+ * @return the offset in floats vertex start to the coordinate data
+ */
+ int coordinateOffset()
+ {
+ int offset = normalOffset;
+
+ if ((this.vertexFormat & GeometryArray.NORMALS) != 0) offset += 3;
+ return offset;
+ }
+
+ /**
+ * Returns number of vertices in the GeometryArray
+ * @return vertexCount number of vertices in the GeometryArray
+ */
+ int getVertexCount(){
+ return vertexCount;
+ }
+
+ /**
+ * Returns vertexFormat in the GeometryArray
+ * @return vertexFormat format of vertices in the GeometryArray
+ */
+ @Override
+ int getVertexFormat(){
+ return vertexFormat;
+ }
+
+ /**
+ * Retrieves the number of vertex attributes in this GeometryArray
+ * object.
+ *
+ * @return the number of vertex attributes in this GeometryArray
+ * object
+ */
+ int getVertexAttrCount() {
+ return vertexAttrCount;
+ }
+
+
+ /**
+ * Retrieves the vertex attribute sizes array from this
+ * GeometryArray object.
+ *
+ * @param vertexAttrSizes an array that will receive a copy of
+ * the vertex attribute sizes array. The array must hold at least
+ * <code>vertexAttrCount</code> elements.
+ */
+ void getVertexAttrSizes(int[] vertexAttrSizes) {
+ for (int i = 0; i < vertexAttrCount; i++) {
+ vertexAttrSizes[i] = this.vertexAttrSizes[i];
+ }
+ }
+
+
+
+ void sendDataChangedMessage(boolean coordinatesChanged) {
+ J3dMessage[] m;
+ int i, j, k, numShapeMessages, numMorphMessages;
+
+ synchronized(liveStateLock) {
+ if (source != null && source.isLive()) {
+ // System.err.println("In GeometryArrayRetained - ");
+
+ // Send a message to renderBin to rebuild the display list or
+ // process the vertex array accordingly
+ // XXXX: Should I send one per universe, isn't display list
+ // shared by all context/universes?
+ int threads = J3dThread.UPDATE_RENDER;
+ // If the geometry type is Indexed then we need to clone the geometry
+ // We also need to update the cachedChangedFrequent flag
+ threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES;
+
+ synchronized (universeList) {
+ numShapeMessages = universeList.size();
+ m = new J3dMessage[numShapeMessages];
+
+ k = 0;
+
+ for (i = 0; i < numShapeMessages; i++, k++) {
+ gaList.clear();
+
+ ArrayList<Shape3DRetained> shapeList = userLists.get(i);
+ for (j = 0; j < shapeList.size(); j++) {
+ Shape3DRetained s = shapeList.get(j);
+ LeafRetained src = (LeafRetained)s.sourceNode;
+ // Should only need to update distinct localBounds.
+ if (coordinatesChanged && src.boundsAutoCompute) {
+ src.boundsDirty = true;
+ }
+ }
+
+ for (j = 0; j < shapeList.size(); j++) {
+ Shape3DRetained s = shapeList.get(j);
+ LeafRetained src = (LeafRetained)s.sourceNode;
+ if (src.boundsDirty) {
+ // update combine bounds of mirrorShape3Ds. So we need to
+ // use its bounds and not localBounds.
+ // bounds is actually a reference to
+ // mirrorShape3D.source.localBounds.
+ src.updateBounds();
+ src.boundsDirty = false;
+ }
+ gaList.add(Shape3DRetained.getGeomAtom(s));
+ }
+
+ m[k] = new J3dMessage();
+
+ m[k].type = J3dMessage.GEOMETRY_CHANGED;
+ // Who to send this message to ?
+ m[k].threads = threads;
+ m[k].args[0] = gaList.toArray();
+ m[k].args[1] = this;
+ m[k].args[2]= null;
+ m[k].args[3] = new Integer(changedFrequent);
+ m[k].universe = universeList.get(i);
+ }
+ VirtualUniverse.mc.processMessage(m);
+ }
+
+ if (morphUniverseList != null) {
+ synchronized (morphUniverseList) {
+ numMorphMessages = morphUniverseList.size();
+
+ // take care of morph that is referencing this geometry
+ if (numMorphMessages > 0) {
+ synchronized (morphUniverseList) {
+ for (i = 0; i < numMorphMessages; i++, k++) {
+ ArrayList<MorphRetained> morphList = morphUserLists.get(i);
+ for (j = 0; j < morphList.size(); j++) {
+ morphList.get(j).updateMorphedGeometryArray(this, coordinatesChanged);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ /**
+ * Sets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate an array of 3 values containing the new coordinate
+ */
+ void setCoordinate(int index, float coordinate[]) {
+ int offset = this.stride * index + coordinateOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ this.vertexData[offset] = coordinate[0];
+ this.vertexData[offset+1]= coordinate[1];
+ this.vertexData[offset+2]= coordinate[2];
+
+ if (isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater || (source == null)) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+ sendDataChangedMessage(true);
+
+ }
+
+ /**
+ * Sets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate an array of 3 values containing the new coordinate
+ */
+ void setCoordinate(int index, double coordinate[]) {
+ int offset = this.stride * index + coordinateOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ this.vertexData[offset] = (float)coordinate[0];
+ this.vertexData[offset+1]= (float)coordinate[1];
+ this.vertexData[offset+2]= (float)coordinate[2];
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (inUpdater || (source == null)) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate a vector containing the new coordinate
+ */
+ void setCoordinate(int index, Point3f coordinate) {
+ int offset = this.stride * index + coordinateOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ this.vertexData[offset] = coordinate.x;
+ this.vertexData[offset+1]= coordinate.y;
+ this.vertexData[offset+2]= coordinate.z;
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater || (source == null)) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate a vector containing the new coordinate
+ */
+ void setCoordinate(int index, Point3d coordinate) {
+ int offset = this.stride * index + coordinateOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ this.vertexData[offset] = (float)coordinate.x;
+ this.vertexData[offset+1]= (float)coordinate.y;
+ this.vertexData[offset+2]= (float)coordinate.z;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater || source == null ) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+ // Compute geo's bounds
+ processCoordsChanged(false);
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of 3*n values containing n new coordinates
+ */
+ void setCoordinates(int index, float coordinates[]) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j, num = coordinates.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i=0, j= offset;i < num; i+=3, j+= this.stride)
+ {
+ this.vertexData[j] = coordinates[i];
+ this.vertexData[j+1]= coordinates[i+1];
+ this.vertexData[j+2]= coordinates[i+2];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater ||source == null ) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of 3*n values containing n new coordinates
+ */
+ void setCoordinates(int index, double coordinates[]) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j, num = coordinates.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i=0, j= offset;i < num; i+=3, j+= this.stride)
+ {
+ this.vertexData[j] = (float)coordinates[i];
+ this.vertexData[j+1]= (float)coordinates[i+1];
+ this.vertexData[j+2]= (float)coordinates[i+2];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (inUpdater ||source == null ) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of vectors containing new coordinates
+ */
+ void setCoordinates(int index, Point3f coordinates[]) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j, num = coordinates.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ this.vertexData[j] = coordinates[i].x;
+ this.vertexData[j+1]= coordinates[i].y;
+ this.vertexData[j+2]= coordinates[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (inUpdater ||source == null ) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of vectors containing new coordinates
+ */
+ void setCoordinates(int index, Point3d coordinates[]) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j, num = coordinates.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ this.vertexData[j] = (float)coordinates[i].x;
+ this.vertexData[j+1]= (float)coordinates[i].y;
+ this.vertexData[j+2]= (float)coordinates[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (inUpdater ||source == null ) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+ }
+
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index for this object using coordinate data starting
+ * from vertex index <code>start</code> for <code>length</code> vertices.
+ * @param index the vertex index
+ * @param coordinates an array of vectors containing new coordinates
+ * @param start starting vertex index of data in <code>coordinates</code> .
+ * @param length number of vertices to be copied.
+ */
+ void setCoordinates(int index, float coordinates[], int start, int length) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ for (i= start * 3, j= offset; i < (start+length) * 3;
+ i+=3, j+= this.stride) {
+ this.vertexData[j] = coordinates[i];
+ this.vertexData[j+1]= coordinates[i+1];
+ this.vertexData[j+2]= coordinates[i+2];
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater ||source == null ) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index for this object using coordinate data starting
+ * from vertex index <code>start</code> for <code>length</code> vertices.
+ * @param index the vertex index
+ * @param coordinates an array of 3*n values containing n new coordinates
+ * @param start starting vertex index of data in <code>coordinates</code> .
+ * @param length number of vertices to be copied.
+ */
+ void setCoordinates(int index, double coordinates[], int start, int length) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i= start*3, j= offset; i < (start+length)*3;
+ i+=3, j+= this.stride) {
+ this.vertexData[j] = (float)coordinates[i];
+ this.vertexData[j+1]= (float)coordinates[i+1];
+ this.vertexData[j+2]= (float)coordinates[i+2];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater || (source == null)) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index for this object using coordinate data starting
+ * from vertex index <code>start</code> for <code>length</code> vertices.
+ * @param index the vertex index
+ * @param coordinates an array of vectors containing new coordinates
+ * @param start starting vertex index of data in <code>coordinates</code> .
+ * @param length number of vertices to be copied.
+ */
+ void setCoordinates(int index, Point3f coordinates[], int start,
+ int length) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i=start, j= offset;i < start + length; i++, j+= this.stride) {
+ this.vertexData[j] = coordinates[i].x;
+ this.vertexData[j+1]= coordinates[i].y;
+ this.vertexData[j+2]= coordinates[i].z;
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (inUpdater || (source == null)) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the coordinates associated with the vertices starting at
+ * the specified index for this object using coordinate data starting
+ * from vertex index <code>start</code> for <code>length</code> vertices.
+ * @param index the vertex index
+ * @param coordinates an array of vectors containing new coordinates
+ * @param start starting vertex index of data in <code>coordinates</code> .
+ * @param length number of vertices to be copied.
+ */
+ void setCoordinates(int index, Point3d coordinates[], int start,
+ int length) {
+ int offset = this.stride * index + coordinateOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ for (i=start, j= offset;i < start + length; i++, j+= this.stride) {
+ this.vertexData[j] = (float)coordinates[i].x;
+ this.vertexData[j+1]= (float)coordinates[i].y;
+ this.vertexData[j+2]= (float)coordinates[i].z;
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (inUpdater || (source == null)) {
+ return;
+ }
+ if (!isLive) {
+ boundsDirty = true;
+ return;
+ }
+
+ // Compute geo's bounds
+ processCoordsChanged(false);
+
+ sendDataChangedMessage(true);
+ }
+
+ /**
+ * Sets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color an array of 3 or 4 values containing the new color
+ */
+ void setColor(int index, float color[]) {
+ int offset = this.stride*index + colorOffset;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.vertexData[offset] = color[0];
+ this.vertexData[offset+1] = color[1];
+ this.vertexData[offset+2] = color[2];
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ this.vertexData[offset+3] = color[3]*lastAlpha[0];
+ else
+ this.vertexData[offset+3] = lastAlpha[0];
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color an array of 3 or 4 values containing the new color
+ */
+ void setColor(int index, byte color[]) {
+ int offset = this.stride*index + colorOffset;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive) {
+ geomLock.getLock();
+ }
+
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.vertexData[offset] = (color[0] & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+1] = (color[1] & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+2] = (color[2] & 0xff) * ByteToFloatScale;
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ this.vertexData[offset+3] = ((color[3] & 0xff)* ByteToFloatScale)*lastAlpha[0];
+ else
+ this.vertexData[offset+3] = lastAlpha[0];
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector containing the new color
+ */
+ void setColor(int index, Color3f color) {
+ int offset = this.stride*index + colorOffset;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.vertexData[offset] = color.x;
+ this.vertexData[offset+1] = color.y;
+ this.vertexData[offset+2] = color.z;
+ this.vertexData[offset+3] = lastAlpha[0];
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+
+ }
+
+ /**
+ * Sets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector containing the new color
+ */
+ void setColor(int index, Color4f color) {
+ int offset = this.stride*index + colorOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.vertexData[offset] = color.x;
+ this.vertexData[offset+1] = color.y;
+ this.vertexData[offset+2] = color.z;
+ this.vertexData[offset+3] = color.w*lastAlpha[0];
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector containing the new color
+ */
+ void setColor(int index, Color3b color) {
+ int offset = this.stride*index + colorOffset;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.vertexData[offset] = (color.x & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+1] = (color.y & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+2] = (color.z & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+3] = lastAlpha[0];
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector containing the new color
+ */
+ void setColor(int index, Color4b color) {
+ int offset = this.stride*index + colorOffset;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.vertexData[offset] = (color.x & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+1] = (color.y & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+2] = (color.z & 0xff) * ByteToFloatScale;
+ this.vertexData[offset+3] = ((color.w & 0xff) * ByteToFloatScale)*lastAlpha[0];
+
+ if(isLive){
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ */
+ void setColors(int index, float colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ {
+ for (i=0, j= offset;i < num; i+= 4, j+= this.stride)
+ {
+ this.vertexData[j] = colors[i];
+ this.vertexData[j+1] = colors[i+1];
+ this.vertexData[j+2] = colors[i+2];
+ this.vertexData[j+3] = colors[i+3]*lastAlpha[0];
+ }
+ }
+ else
+ {
+ for (i=0, j= offset;i < num; i+= 3, j+= this.stride)
+ {
+ this.vertexData[j] = colors[i];
+ this.vertexData[j+1] = colors[i+1];
+ this.vertexData[j+2] = colors[i+2];
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ */
+ void setColors(int index, byte colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ {
+ for (i=0, j= offset;i < num; i+= 4, j+= this.stride)
+ {
+ this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = ((colors[i+3] & 0xff) * ByteToFloatScale)*lastAlpha[0];
+ }
+ }
+ else
+ {
+ for (i=0, j= offset;i < num; i+= 3, j+= this.stride)
+ {
+ this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+ }
+
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors containing new colors
+ */
+ void setColors(int index, Color3f colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ this.vertexData[j] = colors[i].x;
+ this.vertexData[j+1] = colors[i].y;
+ this.vertexData[j+2] = colors[i].z;
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors containing new colors
+ */
+ void setColors(int index, Color4f colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ this.vertexData[j] = colors[i].x;
+ this.vertexData[j+1] = colors[i].y;
+ this.vertexData[j+2] = colors[i].z;
+ this.vertexData[j+3] = colors[i].w*lastAlpha[0];
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors containing new colors
+ */
+ void setColors(int index, Color3b colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors containing new colors
+ */
+ void setColors(int index, Color4b colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = ((colors[i].w & 0xff) * ByteToFloatScale)*lastAlpha[0];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index for this object using data in <code>color</code>s
+ * starting at index <code>start</code> for <code>length</code> colors.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ * @param start starting color index of data in <code>colors</code>.
+ * @param length number of colors to be copied.
+ */
+ void setColors(int index, float colors[], int start, int length) {
+ int offset = this.stride*index + colorOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+ for (i = start * 4, j = offset; i < (start + length) * 4;
+ i += 4, j += this.stride) {
+ this.vertexData[j] = colors[i];
+ this.vertexData[j+1] = colors[i+1];
+ this.vertexData[j+2] = colors[i+2];
+ this.vertexData[j+3] = colors[i+3]*lastAlpha[0];
+ }
+ } else {
+ for (i = start * 3, j = offset; i < (start + length) * 3;
+ i += 3, j += this.stride) {
+ this.vertexData[j] = colors[i];
+ this.vertexData[j+1] = colors[i+1];
+ this.vertexData[j+2] = colors[i+2];
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index for this object using data in <code>color</code>s
+ * starting at index <code>start</code> for <code>length</code> colors.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ * @param start starting color index of data in <code>colors</code>.
+ * @param length number of colors to be copied.
+ */
+ void setColors(int index, byte colors[], int start, int length) {
+ int offset = this.stride*index + colorOffset;
+ int i, j;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0) {
+ for (i = start * 4, j = offset; i < (start + length) * 4;
+ i += 4, j += this.stride) {
+ this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = ((colors[i+3] & 0xff) * ByteToFloatScale)*lastAlpha[0];
+ }
+ } else {
+ for (i = start * 3, j = offset; i < (start + length) * 3;
+ i += 3, j += this.stride) {
+ this.vertexData[j] = (colors[i] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i+1] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i+2] & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index for this object using data in <code>color</code>s
+ * starting at index <code>start</code> for <code>length</code> colors.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ * @param start starting color index of data in <code>colors</code>.
+ * @param length number of colors to be copied.
+ */
+ void setColors(int index, Color3f colors[], int start, int length) {
+ int offset = this.stride*index + colorOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = colors[i].x;
+ this.vertexData[j+1] = colors[i].y;
+ this.vertexData[j+2] = colors[i].z;
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index for this object using data in <code>color</code>s
+ * starting at index <code>start</code> for <code>length</code> colors.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ * @param start starting color index of data in <code>colors</code>.
+ * @param length number of colors to be copied.
+ */
+ void setColors(int index, Color4f colors[], int start, int length) {
+ int offset = this.stride*index + colorOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = colors[i].x;
+ this.vertexData[j+1] = colors[i].y;
+ this.vertexData[j+2] = colors[i].z;
+ this.vertexData[j+3] = colors[i].w*lastAlpha[0];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index for this object using data in <code>color</code>s
+ * starting at index <code>start</code> for <code>length</code> colors.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ * @param start starting color index of data in <code>colors</code>.
+ * @param length number of colors to be copied.
+ */
+ void setColors(int index, Color3b colors[], int start, int length) {
+ int offset = this.stride*index + colorOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = lastAlpha[0];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the colors associated with the vertices starting at
+ * the specified index for this object using data in <code>color</code>s
+ * starting at index <code>start</code> for <code>length</code> colors.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values containing n new colors
+ * @param start starting color index of data in <code>colors</code>.
+ * @param length number of colors to be copied.
+ */
+ void setColors(int index, Color4b colors[], int start, int length) {
+ int offset = this.stride*index + colorOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = (colors[i].x & 0xff) * ByteToFloatScale;
+ this.vertexData[j+1] = (colors[i].y & 0xff) * ByteToFloatScale;
+ this.vertexData[j+2] = (colors[i].z & 0xff) * ByteToFloatScale;
+ this.vertexData[j+3] = ((colors[i].w & 0xff) * ByteToFloatScale)*lastAlpha[0];
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the normal associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param normal the new normal
+ */
+ void setNormal(int index, float normal[]) {
+ int offset = this.stride*index + normalOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ this.vertexData[offset] = normal[0];
+ this.vertexData[offset+1] = normal[1];
+ this.vertexData[offset+2] = normal[2];
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the normal associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param normal the vector containing the new normal
+ */
+ void setNormal(int index, Vector3f normal) {
+ int offset = this.stride*index + normalOffset;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ this.vertexData[offset] = normal.x;
+ this.vertexData[offset+1] = normal.y;
+ this.vertexData[offset+2] = normal.z;
+
+ if(isLive){
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the normals associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param normals the new normals
+ */
+ void setNormals(int index, float normals[]) {
+ int offset = this.stride*index + normalOffset;
+ int i, j, num = normals.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ for (i=0, j= offset;i < num;i += 3, j+= this.stride)
+ {
+ this.vertexData[j] = normals[i];
+ this.vertexData[j+1] = normals[i+1];
+ this.vertexData[j+2] = normals[i+2];
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the normals associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param normals the vector containing the new normals
+ */
+ void setNormals(int index, Vector3f normals[]) {
+ int offset = this.stride*index + normalOffset;
+ int i, j, num = normals.length;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ this.vertexData[j] = normals[i].x;
+ this.vertexData[j+1] = normals[i].y;
+ this.vertexData[j+2] = normals[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the normals associated with the vertices starting at
+ * the specified index for this object using data in <code>normals</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param normals the new normals
+ * @param start starting normal index of data in <code>colors</code> .
+ * @param length number of normals to be copied.
+ */
+ void setNormals(int index, float normals[], int start, int length) {
+ int offset = this.stride*index + normalOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ for (i = start * 3, j = offset; i < (start + length) * 3;
+ i+=3, j += this.stride) {
+ this.vertexData[j] = normals[i];
+ this.vertexData[j+1] = normals[i+1];
+ this.vertexData[j+2] = normals[i+2];
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the normals associated with the vertices starting at
+ * the specified index for this object using data in <code>normals</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param normals the new normals
+ * @param start starting normal index of data in <code>colors</code> .
+ * @param length number of normals to be copied.
+ */
+ void setNormals(int index, Vector3f normals[], int start, int length) {
+ int offset = this.stride*index + normalOffset;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = normals[i].x;
+ this.vertexData[j+1] = normals[i].y;
+ this.vertexData[j+2] = normals[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+
+ /**
+ * Sets the texture coordinates associated with the vertices starting at
+ * the specified index for this object using data in <code>texCoords</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param texCoords the new texture coordinates
+ * @param start starting texture coordinate index of data in <code>texCoords</code> .
+ * @param length number of texture Coordinates to be copied.
+ */
+ void setTextureCoordinates(int texCoordSet, int index, float texCoords[],
+ int start, int length) {
+
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray82"));
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0)
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79"));
+
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, k;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ for (i = start * 4, j = offset, k = 0; k < length;
+ j += this.stride, k++) {
+ this.vertexData[j] = texCoords[i++];
+ this.vertexData[j+1] = texCoords[i++];
+ this.vertexData[j+2] = texCoords[i++];
+ this.vertexData[j+3] = texCoords[i++];
+ }
+ } else if ((this.vertexFormat &
+ GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ for (i = start * 3, j = offset, k = 0; k < length;
+ j += this.stride, k++) {
+ this.vertexData[j] = texCoords[i++];
+ this.vertexData[j+1] = texCoords[i++];
+ this.vertexData[j+2] = texCoords[i++];
+ }
+ } else {
+ for (i = start * 2, j = offset, k = 0; k < length;
+ j += this.stride, k++) {
+ this.vertexData[j] = texCoords[i++];
+ this.vertexData[j+1] = texCoords[i++];
+ }
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the texture coordinates associated with the vertices starting at
+ * the specified index for this object using data in <code>texCoords</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param texCoords the new texture coordinates
+ * @param start starting texture coordinate index of data in <code>texCoords</code> .
+ * @param length number of texture Coordinates to be copied.
+ */
+ void setTextureCoordinates(int texCoordSet, int index, Point2f texCoords[],
+ int start, int length) {
+
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray82"));
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0)
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79"));
+
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = texCoords[i].x;
+ this.vertexData[j+1] = texCoords[i].y;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the texture coordinates associated with the vertices starting at
+ * the specified index for this object using data in <code>texCoords</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param texCoords the new texture coordinates
+ * @param start starting texture coordinate index of data in <code>texCoords</code> .
+ * @param length number of texture Coordinates to be copied.
+ */
+ void setTextureCoordinates(int texCoordSet, int index, Point3f texCoords[],
+ int start, int length) {
+
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray82"));
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0)
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79"));
+
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = texCoords[i].x;
+ this.vertexData[j+1] = texCoords[i].y;
+ this.vertexData[j+2] = texCoords[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the texture coordinates associated with the vertices starting at
+ * the specified index for this object using data in <code>texCoords</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param texCoords the new texture coordinates
+ * @param start starting texture coordinate index of data in <code>texCoords</code> .
+ * @param length number of texture Coordinates to be copied.
+ */
+ void setTextureCoordinates(int texCoordSet, int index, TexCoord2f texCoords[],
+ int start, int length) {
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray82"));
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0)
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79"));
+
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = texCoords[i].x;
+ this.vertexData[j+1] = texCoords[i].y;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Sets the texture coordinates associated with the vertices starting at
+ * the specified index for this object using data in <code>texCoords</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param texCoords the new texture coordinates
+ * @param start starting texture coordinate index of data in <code>texCoords</code> .
+ * @param length number of texture Coordinates to be copied.
+ */
+ void setTextureCoordinates(int texCoordSet, int index,
+ TexCoord3f texCoords[],
+ int start, int length) {
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray82"));
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0)
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79"));
+
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = texCoords[i].x;
+ this.vertexData[j+1] = texCoords[i].y;
+ this.vertexData[j+2] = texCoords[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the texture coordinates associated with the vertices starting at
+ * the specified index for this object using data in <code>texCoords</code>
+ * starting at index <code>start</code> and ending at index <code>start+length</code>.
+ * @param index the vertex index
+ * @param texCoords the new texture coordinates
+ * @param start starting texture coordinate index of data in <code>texCoords</code> .
+ * @param length number of texture Coordinates to be copied.
+ */
+ void setTextureCoordinates(int texCoordSet, int index,
+ TexCoord4f texCoords[],
+ int start, int length) {
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+
+ if ((this.vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray82"));
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE ) == 0)
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray79"));
+
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j;
+
+ for (i = start, j = offset; i < start+length; i++, j += this.stride) {
+ this.vertexData[j] = texCoords[i].x;
+ this.vertexData[j+1] = texCoords[i].y;
+ this.vertexData[j+2] = texCoords[i].z;
+ this.vertexData[j+3] = texCoords[i].w;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ /**
+ * Sets the vertex attribute associated with the vertex at the
+ * specified index in the specified vertex attribute number for
+ * this object.
+ *
+ * @param vertexAttrNum vertex attribute number in this geometry array
+ * @param index destination vertex index in this geometry array
+ * @param vertexAttr the Point2f containing the new vertex attribute
+ */
+ void setVertexAttr(int vertexAttrNum, int index,
+ Point2f vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ this.vertexData[offset] = vertexAttr.x;
+ this.vertexData[offset+1] = vertexAttr.y;
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the vertex attribute associated with the vertex at the
+ * specified index in the specified vertex attribute number for
+ * this object.
+ *
+ * @param vertexAttrNum vertex attribute number in this geometry array
+ * @param index destination vertex index in this geometry array
+ * @param vertexAttr the Point3f containing the new vertex attribute
+ */
+ void setVertexAttr(int vertexAttrNum, int index,
+ Point3f vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ this.vertexData[offset] = vertexAttr.x;
+ this.vertexData[offset+1] = vertexAttr.y;
+ this.vertexData[offset+2] = vertexAttr.z;
+
+ if (isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the vertex attribute associated with the vertex at the
+ * specified index in the specified vertex attribute number for
+ * this object.
+ *
+ * @param vertexAttrNum vertex attribute number in this geometry array
+ * @param index destination vertex index in this geometry array
+ * @param vertexAttr the Point4f containing the new vertex attribute
+ */
+ void setVertexAttr(int vertexAttrNum, int index,
+ Point4f vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ this.vertexData[offset] = vertexAttr.x;
+ this.vertexData[offset+1] = vertexAttr.y;
+ this.vertexData[offset+2] = vertexAttr.z;
+ this.vertexData[offset+3] = vertexAttr.w;
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the vertex attributes associated with the vertices
+ * starting at the specified index in the specified vertex
+ * attribute number for this object using data in
+ * <code>vertexAttrs</code> starting at index <code>start</code> and
+ * ending at index <code>start+length</code>.
+ *
+ * @param index starting destination vertex index in this geometry array
+ * @param vertexAttrs source array of 1*n, 2*n, 3*n, or 4*n values
+ * containing n new vertex attributes
+ * @param start starting source vertex index in <code>vertexAttrs</code>
+ * array.
+ * @param length number of vertex attributes to be copied.
+ */
+ void setVertexAttrs(int vertexAttrNum, int index,
+ float[] vertexAttrs,
+ int start, int length) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int size = vertexAttrSizes[vertexAttrNum];
+ int i, j, k;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ for (i = start * size, j = offset, k = 0; k < length; i += size, j += this.stride, k++) {
+ for (int ii = 0; ii < size; ii++) {
+ this.vertexData[j+ii] = vertexAttrs[i+ii];
+ }
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the vertex attributes associated with the vertices
+ * starting at the specified index in the specified vertex
+ * attribute number for this object using data in
+ * <code>vertexAttrs</code> starting at index <code>start</code> and
+ * ending at index <code>start+length</code>.
+ *
+ * @param vertexAttrNum vertex attribute number in this geometry array
+ * @param index starting destination vertex index in this geometry array
+ * @param vertexAttrs source array of Point2f objects containing new
+ * vertex attributes
+ * @param start starting source vertex index in <code>vertexAttrs</code>
+ * array.
+ * @param length number of vertex attributes to be copied.
+ */
+ void setVertexAttrs(int vertexAttrNum, int index,
+ Point2f[] vertexAttrs,
+ int start, int length) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int i, j, k;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ for (i = start, j = offset, k = 0; k < length; i++, j += this.stride, k++) {
+ this.vertexData[j] = vertexAttrs[i].x;
+ this.vertexData[j+1] = vertexAttrs[i].y;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the vertex attributes associated with the vertices
+ * starting at the specified index in the specified vertex
+ * attribute number for this object using data in
+ * <code>vertexAttrs</code> starting at index <code>start</code> and
+ * ending at index <code>start+length</code>.
+ *
+ * @param vertexAttrNum vertex attribute number in this geometry array
+ * @param index starting destination vertex index in this geometry array
+ * @param vertexAttrs source array of Point3f objects containing new
+ * vertex attributes
+ * @param start starting source vertex index in <code>vertexAttrs</code>
+ * array.
+ * @param length number of vertex attributes to be copied.
+ */
+ void setVertexAttrs(int vertexAttrNum, int index,
+ Point3f[] vertexAttrs,
+ int start, int length) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int i, j, k;
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ for (i = start, j = offset, k = 0; k < length; i++, j += this.stride, k++) {
+ this.vertexData[j] = vertexAttrs[i].x;
+ this.vertexData[j+1] = vertexAttrs[i].y;
+ this.vertexData[j+2] = vertexAttrs[i].z;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Sets the vertex attributes associated with the vertices
+ * starting at the specified index in the specified vertex
+ * attribute number for this object using data in
+ * <code>vertexAttrs</code> starting at index <code>start</code> and
+ * ending at index <code>start+length</code>.
+ *
+ * @param vertexAttrNum vertex attribute number in this geometry array
+ * @param index starting destination vertex index in this geometry array
+ * @param vertexAttrs source array of Point4f objects containing new
+ * vertex attributes
+ * @param start starting source vertex index in <code>vertexAttrs</code>
+ * array.
+ * @param length number of vertex attributes to be copied.
+ */
+ void setVertexAttrs(int vertexAttrNum, int index,
+ Point4f[] vertexAttrs,
+ int start, int length) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int i, j, k;
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+
+ for (i = start, j = offset, k = 0; k < length; i++, j += this.stride, k++) {
+ this.vertexData[j] = vertexAttrs[i].x;
+ this.vertexData[j+1] = vertexAttrs[i].y;
+ this.vertexData[j+2] = vertexAttrs[i].z;
+ this.vertexData[j+3] = vertexAttrs[i].w;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ /**
+ * Gets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate an array of 3 values that will receive the new coordinate
+ */
+ void getCoordinate(int index, float coordinate[]) {
+ int offset = this.stride*index + coordinateOffset;
+
+ coordinate[0]= this.vertexData[offset];
+ coordinate[1]= this.vertexData[offset+1];
+ coordinate[2]= this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate an array of 3 values that will receive the new coordinate
+ */
+ void getCoordinate(int index, double coordinate[]) {
+ int offset = this.stride*index + coordinateOffset;
+
+ coordinate[0]= (double)this.vertexData[offset];
+ coordinate[1]= (double)this.vertexData[offset+1];
+ coordinate[2]= (double)this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate a vector that will receive the new coordinate
+ */
+ void getCoordinate(int index, Point3f coordinate) {
+ int offset = this.stride*index + coordinateOffset;
+
+ coordinate.x = this.vertexData[offset];
+ coordinate.y = this.vertexData[offset+1];
+ coordinate.z = this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the coordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinate a vector that will receive the new coordinate
+ */
+ void getCoordinate(int index, Point3d coordinate) {
+ int offset = this.stride*index + coordinateOffset;
+
+ coordinate.x = (double)this.vertexData[offset];
+ coordinate.y = (double)this.vertexData[offset+1];
+ coordinate.z = (double)this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of 3*n values that will receive new coordinates
+ */
+ void getCoordinates(int index, float coordinates[]) {
+ int offset = this.stride*index + coordinateOffset;
+ int i, j, num = coordinates.length;
+
+ for (i=0,j= offset;i < num;i +=3, j += this.stride)
+ {
+ coordinates[i] = this.vertexData[j];
+ coordinates[i+1]= this.vertexData[j+1];
+ coordinates[i+2]= this.vertexData[j+2];
+ }
+ }
+
+
+ /**
+ * Gets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of 3*n values that will receive new coordinates
+ */
+ void getCoordinates(int index, double coordinates[]) {
+ int offset = this.stride*index + coordinateOffset;
+ int i, j, num = coordinates.length;
+
+ for (i=0,j= offset;i < num;i +=3, j += this.stride)
+ {
+ coordinates[i] = (double)this.vertexData[j];
+ coordinates[i+1]= (double)this.vertexData[j+1];
+ coordinates[i+2]= (double)this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of vectors that will receive new coordinates
+ */
+ void getCoordinates(int index, Point3f coordinates[]) {
+ int offset = this.stride*index + coordinateOffset;
+ int i, j, num = coordinates.length;
+
+ for (i=0,j= offset;i < num;i++, j += this.stride)
+ {
+ coordinates[i].x = this.vertexData[j];
+ coordinates[i].y = this.vertexData[j+1];
+ coordinates[i].z = this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the coordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param coordinates an array of vectors that will receive new coordinates
+ */
+ void getCoordinates(int index, Point3d coordinates[]) {
+ int offset = this.stride*index + coordinateOffset;
+ int i, j, num = coordinates.length;
+
+ for (i=0,j= offset;i < num;i++, j += this.stride)
+ {
+ coordinates[i].x = (double)this.vertexData[j];
+ coordinates[i].y = (double)this.vertexData[j+1];
+ coordinates[i].z = (double)this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color an array of 3 or 4 values that will receive the new color
+ */
+ void getColor(int index, float color[]) {
+ int offset = this.stride*index + colorOffset;
+
+ color[0]= this.vertexData[offset];
+ color[1]= this.vertexData[offset+1];
+ color[2]= this.vertexData[offset+2];
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ color[3]= this.vertexData[offset+3]/lastAlpha[0];
+ }
+
+ /**
+ * Gets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color an array of 3 or 4 values that will receive the new color
+ */
+ void getColor(int index, byte color[]) {
+ int offset = this.stride*index + colorOffset;
+
+ color[0]= (byte)(this.vertexData[offset] * FloatToByteScale);
+ color[1]= (byte)(this.vertexData[offset+1] * FloatToByteScale);
+ color[2]= (byte)(this.vertexData[offset+2] * FloatToByteScale);
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ color[3]= (byte)((this.vertexData[offset+3]/lastAlpha[0]) * FloatToByteScale);
+ }
+
+ /**
+ * Gets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector that will receive the new color
+ */
+ void getColor(int index, Color3f color) {
+ int offset = this.stride*index + colorOffset;
+
+ color.x = this.vertexData[offset];
+ color.y = this.vertexData[offset+1];
+ color.z = this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector that will receive the new color
+ */
+ void getColor(int index, Color4f color) {
+ int offset = this.stride*index + colorOffset;
+
+ color.x = this.vertexData[offset];
+ color.y = this.vertexData[offset+1];
+ color.z = this.vertexData[offset+2];
+ color.w= this.vertexData[offset+3]/lastAlpha[0];
+ }
+
+ /**
+ * Gets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector that will receive the new color
+ */
+ void getColor(int index, Color3b color) {
+ int offset = this.stride*index + colorOffset;
+
+ color.x = (byte)(this.vertexData[offset] * FloatToByteScale);
+ color.y = (byte)(this.vertexData[offset+1] * FloatToByteScale);
+ color.z = (byte)(this.vertexData[offset+2] * FloatToByteScale);
+ }
+
+ /**
+ * Gets the color associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param color a vector that will receive the new color
+ */
+ void getColor(int index, Color4b color) {
+ int offset = this.stride*index + colorOffset;
+
+ color.x = (byte)(this.vertexData[offset] * FloatToByteScale);
+ color.y = (byte)(this.vertexData[offset+1] * FloatToByteScale);
+ color.z = (byte)(this.vertexData[offset+2] * FloatToByteScale);
+ color.w = (byte)((this.vertexData[offset+3]/lastAlpha[0]) * FloatToByteScale);
+ }
+
+ /**
+ * Gets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values that will receive n new colors
+ */
+ void getColors(int index, float colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+ float val = 1.0f/lastAlpha[0];
+
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ {
+ for (i=0, j= offset;i < num; i+= 4, j+= this.stride)
+ {
+ colors[i] = this.vertexData[j];
+ colors[i+1]= this.vertexData[j+1];
+ colors[i+2]= this.vertexData[j+2];
+ colors[i+3]= this.vertexData[j+3] * val;
+ }
+ }
+ else
+ {
+ for (i=0, j= offset;i < num; i+= 3, j+= this.stride)
+ {
+ colors[i] = this.vertexData[j];
+ colors[i+1]= this.vertexData[j+1];
+ colors[i+2]= this.vertexData[j+2];
+ }
+ }
+ }
+
+ /**
+ * Gets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of 3*n or 4*n values that will receive new colors
+ */
+ void getColors(int index, byte colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+ float val = 1.0f/lastAlpha[0];
+
+
+ if ((this.vertexFormat & GeometryArray.WITH_ALPHA) != 0)
+ {
+ for (i=0, j= offset;i < num; i+= 4, j+= this.stride)
+ {
+ colors[i] = (byte)(this.vertexData[j] * FloatToByteScale);
+ colors[i+1]= (byte)(this.vertexData[j+1] * FloatToByteScale);
+ colors[i+2]= (byte)(this.vertexData[j+2] * FloatToByteScale);
+ colors[i+3]= (byte)((this.vertexData[j+3] * val) * FloatToByteScale);
+ }
+ }
+ else
+ {
+ for (i=0, j= offset;i < num; i+= 3, j+= this.stride)
+ {
+ colors[i] = (byte)(this.vertexData[j] * FloatToByteScale);
+ colors[i+1]= (byte)(this.vertexData[j+1] * FloatToByteScale);
+ colors[i+2]= (byte)(this.vertexData[j+2] * FloatToByteScale);
+ }
+ }
+ }
+
+ /**
+ * Gets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors that will receive new colors
+ */
+ void getColors(int index, Color3f colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ colors[i].x = this.vertexData[j];
+ colors[i].y = this.vertexData[j+1];
+ colors[i].z = this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors that will receive new colors
+ */
+ void getColors(int index, Color4f colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+ float val = 1.0f/lastAlpha[0];
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ colors[i].x = this.vertexData[j];
+ colors[i].y = this.vertexData[j+1];
+ colors[i].z = this.vertexData[j+2];
+ colors[i].w = this.vertexData[j+3] * val;
+ }
+ }
+
+ /**
+ * Gets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors that will receive new colors
+ */
+ void getColors(int index, Color3b colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ colors[i].x = (byte)(this.vertexData[j] * FloatToByteScale);
+ colors[i].y = (byte)(this.vertexData[j+1] * FloatToByteScale);
+ colors[i].z = (byte)(this.vertexData[j+2] * FloatToByteScale);
+ }
+ }
+
+ /**
+ * Gets the colors associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param colors an array of vectors that will receive new colors
+ */
+ void getColors(int index, Color4b colors[]) {
+ int offset = this.stride*index + colorOffset;
+ int i, j, num = colors.length;
+ float val = 1.0f/lastAlpha[0];
+
+ for (i=0, j= offset;i < num; i++, j+= this.stride)
+ {
+ colors[i].x = (byte)(this.vertexData[j] * FloatToByteScale);
+ colors[i].y = (byte)(this.vertexData[j+1] * FloatToByteScale);
+ colors[i].z = (byte)(this.vertexData[j+2] * FloatToByteScale);
+ colors[i].w = (byte)(this.vertexData[j+3] * val * FloatToByteScale);
+ }
+ }
+
+ /**
+ * Gets the normal associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param normal array that will receive the new normal
+ */
+ void getNormal(int index, float normal[]) {
+ int offset = this.stride*index + normalOffset;
+
+ normal[0]= this.vertexData[offset];
+ normal[1]= this.vertexData[offset+1];
+ normal[2]= this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the normal associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param normal the vector that will receive the new normal
+ */
+ void getNormal(int index, Vector3f normal) {
+ int offset = this.stride*index + normalOffset;
+
+ normal.x= this.vertexData[offset];
+ normal.y= this.vertexData[offset+1];
+ normal.z= this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the normals associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param normals array that will receive the new normals
+ */
+ void getNormals(int index, float normals[]) {
+ int offset = this.stride*index + normalOffset;
+ int i, j, num = normals.length;
+
+ for (i=0, j= offset;i < num;i+=3, j+= this.stride)
+ {
+ normals[i] = this.vertexData[j];
+ normals[i+1]= this.vertexData[j+1];
+ normals[i+2]= this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the normals associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param normals the vector that will receive the new normals
+ */
+ void getNormals(int index, Vector3f normals[]) {
+ int offset = this.stride*index + normalOffset;
+ int i, j, num = normals.length;
+
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ normals[i].x= this.vertexData[j];
+ normals[i].y= this.vertexData[j+1];
+ normals[i].z= this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the texture co-ordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoord array that will receive the new texture co-ordinate
+ */
+ void getTextureCoordinate(int texCoordSet, int index, float texCoord[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+
+ texCoord[0]= this.vertexData[offset];
+ texCoord[1]= this.vertexData[offset+1];
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ texCoord[2]= this.vertexData[offset+2];
+
+ } else if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4)
+ != 0) {
+ texCoord[2]= this.vertexData[offset+2];
+ texCoord[3]= this.vertexData[offset+3];
+ }
+ }
+
+ /**
+ * Gets the texture co-ordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoord the vector that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinate(int texCoordSet, int index, TexCoord2f texCoord) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+
+ texCoord.x= this.vertexData[offset];
+ texCoord.y= this.vertexData[offset+1];
+ }
+
+ /**
+ * Gets the texture co-ordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoord the vector that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinate(int texCoordSet, int index, TexCoord3f texCoord) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+
+ texCoord.x= this.vertexData[offset];
+ texCoord.y= this.vertexData[offset+1];
+ texCoord.z= this.vertexData[offset+2];
+ }
+
+ /**
+ * Gets the texture co-ordinate associated with the vertex at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoord the vector that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinate(int texCoordSet, int index, TexCoord4f texCoord) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+
+ texCoord.x= this.vertexData[offset];
+ texCoord.y= this.vertexData[offset+1];
+ texCoord.z= this.vertexData[offset+2];
+ texCoord.w= this.vertexData[offset+3];
+ }
+
+ /**
+ * Gets the texture co-ordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoords array that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinates(int texCoordSet, int index, float texCoords[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, num = texCoords.length;
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ for (i=0, j= offset;i < num;i+=4, j+= this.stride)
+ {
+ texCoords[i]= this.vertexData[j];
+ texCoords[i+1]= this.vertexData[j+1];
+ texCoords[i+2]= this.vertexData[j+2];
+ texCoords[i+3]= this.vertexData[j+3];
+ }
+ } else if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE_3)
+ != 0) {
+ for (i=0, j= offset;i < num;i+=3, j+= this.stride)
+ {
+ texCoords[i]= this.vertexData[j];
+ texCoords[i+1]= this.vertexData[j+1];
+ texCoords[i+2]= this.vertexData[j+2];
+ }
+ } else {
+ for (i=0, j= offset;i < num;i+=2, j+= this.stride)
+ {
+ texCoords[i]= this.vertexData[j];
+ texCoords[i+1]= this.vertexData[j+1];
+ }
+ }
+ }
+
+ /**
+ * Gets the texture co-ordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoords the vector that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinates(int texCoordSet, int index,
+ TexCoord2f texCoords[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, num = texCoords.length;
+
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ texCoords[i].x= this.vertexData[j];
+ texCoords[i].y= this.vertexData[j+1];
+ }
+ }
+
+ /**
+ * Gets the texture co-ordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoords the vector that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinates(int texCoordSet, int index, TexCoord3f texCoords[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, num = texCoords.length;
+
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ texCoords[i].x= this.vertexData[j];
+ texCoords[i].y= this.vertexData[j+1];
+ texCoords[i].z= this.vertexData[j+2];
+ }
+ }
+
+ /**
+ * Gets the texture co-ordinates associated with the vertices starting at
+ * the specified index.
+ * @param index the vertex index
+ * @param texCoords the vector that will receive the new texture co-ordinates
+ */
+ void getTextureCoordinates(int texCoordSet, int index, TexCoord4f texCoords[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, num = texCoords.length;
+
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ texCoords[i].x= this.vertexData[j];
+ texCoords[i].y= this.vertexData[j+1];
+ texCoords[i].z= this.vertexData[j+2];
+ texCoords[i].w= this.vertexData[j+3];
+ }
+ }
+
+ void getTextureCoordinates(int texCoordSet, int index,
+ Point2f texCoords[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, num = texCoords.length;
+
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ texCoords[i].x= this.vertexData[j];
+ texCoords[i].y= this.vertexData[j+1];
+ }
+ }
+
+ void getTextureCoordinates(int texCoordSet, int index, Point3f texCoords[]) {
+ int offset = this.stride*index + textureOffset +
+ texCoordSet * texCoordStride;
+ int i, j, num = texCoords.length;
+
+ for (i=0, j= offset;i < num;i++, j+= this.stride)
+ {
+ texCoords[i].x= this.vertexData[j];
+ texCoords[i].y= this.vertexData[j+1];
+ texCoords[i].z= this.vertexData[j+2];
+ }
+ }
+
+
+ /**
+ * Gets the vertex attribute associated with the vertex at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttr(int vertexAttrNum, int index,
+ float[] vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int size = vertexAttrSizes[vertexAttrNum];
+
+ for (int i = 0; i < size; i++) {
+ vertexAttr[i] = this.vertexData[offset+i];
+
+ }
+
+ }
+
+ /**
+ * Gets the vertex attribute associated with the vertex at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttr(int vertexAttrNum, int index,
+ Point2f vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+
+ vertexAttr.x = this.vertexData[offset];
+ vertexAttr.y = this.vertexData[offset+1];
+
+ }
+
+ /**
+ * Gets the vertex attribute associated with the vertex at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttr(int vertexAttrNum, int index,
+ Point3f vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+
+ vertexAttr.x = this.vertexData[offset];
+ vertexAttr.y = this.vertexData[offset+1];
+ vertexAttr.z = this.vertexData[offset+2];
+
+ }
+
+ /**
+ * Gets the vertex attribute associated with the vertex at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttr(int vertexAttrNum, int index,
+ Point4f vertexAttr) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+
+ vertexAttr.x = this.vertexData[offset];
+ vertexAttr.y = this.vertexData[offset+1];
+ vertexAttr.z = this.vertexData[offset+2];
+ vertexAttr.w = this.vertexData[offset+3];
+
+ }
+
+ /**
+ * Gets the vertex attributes associated with the vertices starting at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttrs(int vertexAttrNum, int index,
+ float[] vertexAttrs) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int size = vertexAttrSizes[vertexAttrNum];
+ int i, j, k;
+
+ for (i = 0, j = offset;
+ ((i < vertexAttrs.length) && (j < this.vertexData.length)) ;
+ i += size, j += this.stride) {
+ for (k = 0; k < size; k++) {
+ vertexAttrs[i+k] = this.vertexData[j+k];
+ }
+ }
+
+ }
+
+ /**
+ * Gets the vertex attributes associated with the vertices starting at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttrs(int vertexAttrNum, int index,
+ Point2f[] vertexAttrs) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int i, j;
+
+ for (i = 0, j = offset;
+ ((i < vertexAttrs.length) && (j < this.vertexData.length)) ;
+ i++, j += this.stride) {
+ vertexAttrs[i].x = this.vertexData[j];
+ vertexAttrs[i].y = this.vertexData[j+1];
+ }
+
+ }
+
+ /**
+ * Gets the vertex attributes associated with the vertices starting at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttrs(int vertexAttrNum, int index,
+ Point3f[] vertexAttrs) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int i, j;
+
+ for (i = 0, j = offset;
+ ((i < vertexAttrs.length) && (j < this.vertexData.length)) ;
+ i++, j += this.stride) {
+ vertexAttrs[i].x = this.vertexData[j];
+ vertexAttrs[i].y = this.vertexData[j+1];
+ vertexAttrs[i].z = this.vertexData[j+2];
+ }
+
+ }
+
+ /**
+ * Gets the vertex attributes associated with the vertices starting at
+ * the specified index in the specified vertex attribute number
+ * for this object.
+ */
+ public void getVertexAttrs(int vertexAttrNum, int index,
+ Point4f[] vertexAttrs) {
+
+ int offset = this.stride*index + vertexAttrOffsets[vertexAttrNum];
+ int i, j;
+
+ for (i = 0, j = offset;
+ ((i < vertexAttrs.length) && (j < this.vertexData.length)) ;
+ i++, j += this.stride) {
+ vertexAttrs[i].x = this.vertexData[j];
+ vertexAttrs[i].y = this.vertexData[j+1];
+ vertexAttrs[i].z = this.vertexData[j+2];
+ vertexAttrs[i].w = this.vertexData[j+3];
+ }
+
+ }
+
+
+ /**
+ * Updates geometry array data.
+ */
+ void updateData(GeometryUpdater updater) {
+ boolean nullGeo = false;
+
+ // Add yourself to obtain the geometry lock
+ // and Thread.currentThread().sleep until you get the lock
+ geomLock.getLock();
+
+ inUpdater = true;
+ updater.updateData((Geometry)source);
+ inUpdater = false;
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) != 0) {
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
+ // XXXX: handle the nio buffer
+ if (!(this instanceof IndexedGeometryArrayRetained) ||
+ (vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
+ if (((vertexFormat & GeometryArray.INTERLEAVED) != 0)) {
+ setupMirrorInterleavedColorPointer(false);
+ nullGeo = (interleavedFloatBufferImpl == null);
+ }
+ else {
+ setupMirrorColorPointer((vertexType & COLOR_DEFINED), false);
+ nullGeo = ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0);
+ }
+ }
+ }
+ else {
+ if (!(this instanceof IndexedGeometryArrayRetained) ||
+ (vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
+ if (((vertexFormat & GeometryArray.INTERLEAVED) != 0)) {
+ setupMirrorInterleavedColorPointer(false);
+ nullGeo = (interLeavedVertexData == null);
+ }
+ else {
+ setupMirrorVertexPointer(vertexType & VERTEX_DEFINED);
+ setupMirrorColorPointer((vertexType & COLOR_DEFINED), false);
+ setupMirrorNormalPointer(vertexType & NORMAL_DEFINED);
+ setupMirrorTexCoordPointer(texCoordType);
+ setupMirrorVertexAttrPointer(vertexAttrType);
+ nullGeo = ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0);
+ }
+ }
+ }
+
+ //NVaidya
+ // User may or may not have changed indices in updater callback.
+ // We need to presume that the user may indeed have and, thus, will
+ // need to recompute maxCoordIndex unconditionally while
+ // geomLock is still locked.
+ if ((vertexFormat & GeometryArray.BY_REFERENCE_INDICES) != 0) {
+ assert (this instanceof IndexedGeometryArrayRetained);
+
+ if (((IndexedGeometryArrayRetained)this).getCoordIndicesRef() == null) {
+ nullGeo = true;
+ }
+ ((IndexedGeometryArrayRetained)this).doPostUpdaterUpdate();
+ }
+ }
+
+ dirtyFlag |= VERTEX_CHANGED;
+ colorChanged = 0xffff;
+ geomLock.unLock();
+
+ if (source != null && source.isLive()) {
+ processCoordsChanged(nullGeo);
+ sendDataChangedMessage(true);
+ }
+ }
+
+ boolean intersectBoundingBox( Point3d coordinates[],
+ BoundingBox box,
+ double dist[],
+ Point3d iPnt) {
+ int i;
+ int out[] = new int[6];
+
+ //Do trivial vertex test.
+ for(i=0; i<6; i++)
+ out[i] = 0;
+ for(i=0; i<coordinates.length; i++) {
+ if((coordinates[i].x >= box.lower.x) && (coordinates[i].x <= box.upper.x) &&
+ (coordinates[i].y >= box.lower.y) && (coordinates[i].y <= box.upper.y) &&
+ (coordinates[i].z >= box.lower.z) && (coordinates[i].z <= box.upper.z))
+ // We're done! It's inside the boundingbox.
+ return true;
+ else {
+ if(coordinates[i].x < box.lower.x)
+ out[0]++; // left
+ if(coordinates[i].y < box.lower.y)
+ out[1]++; // bottom
+ if(coordinates[i].z < box.lower.z)
+ out[2]++; // back
+ if(coordinates[i].x > box.upper.x)
+ out[3]++; // right
+ if(coordinates[i].y > box.upper.y)
+ out[4]++; // top
+ if(coordinates[i].z > box.upper.z)
+ out[5]++; // front
+ }
+
+ }
+
+ if((out[0] == coordinates.length) || (out[1] == coordinates.length) ||
+ (out[2] == coordinates.length) || (out[3] == coordinates.length) ||
+ (out[4] == coordinates.length) || (out[5] == coordinates.length))
+ // we're done. primitive is outside of boundingbox.
+ return false;
+
+ // Setup bounding planes.
+ Point3d pCoor[] = new Point3d[4];
+ for(i=0; i<4; i++)
+ pCoor[i] = new Point3d();
+
+ Point3d boxCenter = new Point3d();
+ box.getCenter(boxCenter);
+
+ // left plane.
+ pCoor[0].set(box.lower.x, box.lower.y, box.lower.z);
+ pCoor[1].set(box.lower.x, box.lower.y, box.upper.z);
+ pCoor[2].set(box.lower.x, box.upper.y, box.upper.z);
+ pCoor[3].set(box.lower.x, box.upper.y, box.lower.z);
+
+
+ if (intersectPolygon(pCoor, coordinates)) {
+ if (dist != null) {
+ computeMinDistance(pCoor, boxCenter, null, dist, iPnt);
+ }
+ return true;
+ }
+
+ // right plane.
+ pCoor[0].set(box.upper.x, box.lower.y, box.lower.z);
+ pCoor[1].set(box.upper.x, box.upper.y, box.lower.z);
+ pCoor[2].set(box.upper.x, box.upper.y, box.upper.z);
+ pCoor[3].set(box.upper.x, box.lower.y, box.upper.z);
+ if (intersectPolygon(pCoor, coordinates)) {
+ if (dist != null) {
+ computeMinDistance(pCoor, boxCenter, null, dist, iPnt);
+ }
+ return true;
+ }
+
+ // bottom plane.
+ pCoor[0].set(box.upper.x, box.lower.y, box.upper.z);
+ pCoor[1].set(box.lower.x, box.lower.y, box.upper.z);
+ pCoor[2].set(box.lower.x, box.lower.y, box.lower.z);
+ pCoor[3].set(box.upper.x, box.lower.y, box.lower.z);
+ if (intersectPolygon(pCoor, coordinates)) {
+ if (dist != null) {
+ computeMinDistance(pCoor, boxCenter, null, dist, iPnt);
+ }
+ return true;
+ }
+ // top plane.
+ pCoor[0].set(box.upper.x, box.upper.y, box.upper.z);
+ pCoor[1].set(box.upper.x, box.upper.y, box.lower.z);
+ pCoor[2].set(box.lower.x, box.upper.y, box.lower.z);
+ pCoor[3].set(box.lower.x, box.upper.y, box.upper.z);
+ if (intersectPolygon(pCoor, coordinates)) {
+ if (dist != null) {
+ computeMinDistance(pCoor, boxCenter, null, dist, iPnt);
+ }
+ return true;
+ }
+
+ // front plane.
+ pCoor[0].set(box.upper.x, box.upper.y, box.upper.z);
+ pCoor[1].set(box.lower.x, box.upper.y, box.upper.z);
+ pCoor[2].set(box.lower.x, box.lower.y, box.upper.z);
+ pCoor[3].set(box.upper.x, box.lower.y, box.upper.z);
+ if (intersectPolygon(pCoor, coordinates)) {
+ if (dist != null) {
+ computeMinDistance(pCoor, boxCenter, null, dist, iPnt);
+ }
+ return true;
+ }
+
+ // back plane.
+ pCoor[0].set(box.upper.x, box.upper.y, box.lower.z);
+ pCoor[1].set(box.upper.x, box.lower.y, box.lower.z);
+ pCoor[2].set(box.lower.x, box.lower.y, box.lower.z);
+ pCoor[3].set(box.lower.x, box.upper.y, box.lower.z);
+ if (intersectPolygon(pCoor, coordinates)) {
+ if (dist != null) {
+ computeMinDistance(pCoor, boxCenter, null, dist, iPnt);
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ boolean intersectBoundingSphere(Point3d coordinates[],
+ BoundingSphere sphere,
+ double dist[],
+ Point3d iPnt)
+ {
+ int i, j;
+ Vector3d tempV3D = new Vector3d();
+ boolean esFlag;
+
+ //Do trivial vertex test.
+
+ for (i=0; i<coordinates.length; i++) {
+ tempV3D.x = coordinates[i].x - sphere.center.x;
+ tempV3D.y = coordinates[i].y - sphere.center.y;
+ tempV3D.z = coordinates[i].z - sphere.center.z;
+
+ if (tempV3D.length() <= sphere.radius) {
+ // We're done! It's inside the boundingSphere.
+ if (dist != null) {
+ computeMinDistance(coordinates,
+ sphere.getCenter(),
+ null, dist, iPnt);
+ }
+
+ return true;
+ }
+ }
+
+ for (i=0; i<coordinates.length; i++) {
+ if (i < (coordinates.length-1))
+ esFlag = edgeIntersectSphere(sphere, coordinates[i],
+ coordinates[i+1]);
+ else
+ esFlag = edgeIntersectSphere(sphere, coordinates[i],
+ coordinates[0]);
+ if (esFlag == true) {
+ if (dist != null) {
+ computeMinDistance(coordinates,
+ sphere.getCenter(),
+ null,
+ dist, iPnt);
+ }
+
+ return true;
+ }
+ }
+
+
+ if (coordinates.length < 3) {
+ return false; // We're done with line.
+ }
+
+ // Find rho.
+ // Compute plane normal.
+ Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1;
+ Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3;
+ Vector3d pNrm = new Vector3d();
+ Vector3d pa = new Vector3d();
+ Point3d q = new Point3d();
+ double nLenSq, pqLen, pNrmDotPa, tq;
+
+ // compute plane normal for coordinates.
+ for(i=0; i<coordinates.length-1;) {
+ vec0.x = coordinates[i+1].x - coordinates[i].x;
+ vec0.y = coordinates[i+1].y - coordinates[i].y;
+ vec0.z = coordinates[i+1].z - coordinates[i++].z;
+ if(vec0.length() > 0.0)
+ break;
+ }
+
+ for(j=i; j<coordinates.length-1; j++) {
+ vec1.x = coordinates[j+1].x - coordinates[j].x;
+ vec1.y = coordinates[j+1].y - coordinates[j].y;
+ vec1.z = coordinates[j+1].z - coordinates[j].z;
+ if(vec1.length() > 0.0)
+ break;
+ }
+
+ if(j == (coordinates.length-1)) {
+ // System.err.println("(1) Degenerate polygon.");
+ return false; // Degenerate polygon.
+ }
+
+ /*
+ for(i=0; i<coordinates.length; i++)
+ System.err.println("coordinates P" + i + " " + coordinates[i]);
+ for(i=0; i<coord2.length; i++)
+ System.err.println("coord2 P" + i + " " + coord2[i]);
+ */
+
+ pNrm.cross(vec0,vec1);
+
+ nLenSq = pNrm.lengthSquared();
+ if( nLenSq == 0.0) {
+ // System.err.println("(2) Degenerate polygon.");
+ return false; // Degenerate polygon.
+ }
+
+ pa.x = coordinates[0].x - sphere.center.x;
+ pa.y = coordinates[0].y - sphere.center.y;
+ pa.z = coordinates[0].z - sphere.center.z;
+
+ pNrmDotPa = pNrm.dot(pa);
+
+ pqLen = Math.sqrt(pNrmDotPa * pNrmDotPa/ nLenSq);
+
+ if(pqLen > sphere.radius) {
+ return false;
+ }
+
+ tq = pNrmDotPa / nLenSq;
+
+ q.x = sphere.center.x + tq * pNrm.x;
+ q.y = sphere.center.y + tq * pNrm.y;
+ q.z = sphere.center.z + tq * pNrm.z;
+
+ // PolyPnt2D Test.
+ if (pointIntersectPolygon2D( pNrm, coordinates, q)) {
+ if (dist != null) {
+ computeMinDistance(coordinates,
+ sphere.getCenter(),
+ pNrm,
+ dist, iPnt);
+ }
+ return true;
+ }
+ return false;
+
+ }
+
+
+ boolean intersectBoundingPolytope(Point3d coordinates[],
+ BoundingPolytope polytope,
+ double dist[],
+ Point3d iPnt)
+ {
+ boolean debug = false;
+
+ Point4d tP4d = new Point4d();
+
+ // this is a multiplier to the halfplane distance coefficients
+ double distanceSign = -1.0;
+
+ if(coordinates.length == 2) {
+ // we'll handle line separately.
+ if (polytope.intersect( coordinates[0],
+ coordinates[1], tP4d)) {
+ if (dist != null) {
+ polytope.getCenter(iPnt);
+
+ double x = tP4d.x - iPnt.x;
+ double y = tP4d.y - iPnt.y;
+ double z = tP4d.z - iPnt.z;
+ dist[0] = Math.sqrt(x * x + y * y + z * z);
+ iPnt.x = tP4d.x;
+ iPnt.y = tP4d.y;
+ iPnt.z = tP4d.z;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // It is a triangle or a quad.
+
+ // first test to see if any of the coordinates are all inside of the
+ // intersection polytope's half planes
+ // essentially do a matrix multiply of the constraintMatrix K*3 with
+ // the input coordinates 3*1 = K*1 vector
+
+ if (debug) {
+ System.err.println("The value of the input vertices are: ");
+ for(int i=0; i < coordinates.length; i++) {
+ System.err.println("The " +i+ " th vertex is: " + coordinates[i]);
+ }
+
+ System.err.println("The value of the input bounding Polytope's planes =");
+ for(int i=0; i < polytope.planes.length; i++) {
+ System.err.println("The " +i+ " th plane is: " + polytope.planes[i]);
+ }
+
+ }
+
+ // the direction for the intersection cost function
+ double centers[] = new double[4];
+ centers[0] = 0.8; centers[1] = 0.9; centers[2] = 1.1; centers[3] = 1.2;
+
+ boolean intersection = true;
+ boolean PreTest = false;
+
+ if(PreTest) {
+ // for each coordinate, test it with each half plane
+ for( int i=0; i < coordinates.length; i++) {
+ for (int j=0; j < polytope.planes.length; j++) {
+ if ( ( polytope.planes[j].x * coordinates[i].x +
+ polytope.planes[j].y * coordinates[i].y +
+ polytope.planes[j].z*coordinates[i].z) <=
+ (distanceSign)*polytope.planes[j].w){
+ // the point satisfies this particular hyperplane
+ intersection = true;
+ } else {
+ // the point fails this hyper plane try with a new hyper plane
+ intersection = false;
+ break;
+ }
+ }
+ if(intersection) {
+ // a point was found to be completely inside the bounding hull
+ if (dist != null) {
+ computeMinDistance(coordinates,
+ polytope.getCenter(),
+ null,
+ dist, iPnt);
+ }
+ return true;
+ }
+ }
+ } // end of pretest
+
+ // at this point all points are outside of the bounding hull
+ // build the problem tableau for the linear program
+
+ int numberCols = polytope.planes.length + 2 + coordinates.length + 1;
+ int numberRows = 1 + coordinates.length;
+
+ double problemTableau[][] = new double[numberRows][numberCols];
+
+ // compute -Mtrans = -A*P
+
+ for( int i = 0; i < polytope.planes.length; i++) {
+ for( int j=0; j < coordinates.length; j++) {
+ problemTableau[j][i] = (-1.0)* (polytope.planes[i].x*coordinates[j].x+
+ polytope.planes[i].y*coordinates[j].y+
+ polytope.planes[i].z*coordinates[j].z);
+ }
+ }
+
+ // add the other rows
+ for(int i = 0; i < coordinates.length; i++) {
+ problemTableau[i][polytope.planes.length] = -1.0;
+ problemTableau[i][polytope.planes.length + 1] = 1.0;
+
+ for(int j=0; j < coordinates.length; j++) {
+ if ( i==j ) {
+ problemTableau[i][j + polytope.planes.length + 2] = 1.0;
+ } else {
+ problemTableau[i][j + polytope.planes.length + 2] = 0.0;
+ }
+
+ // place the last column elements the Ci's
+ problemTableau[i][numberCols - 1] = centers[i];
+ }
+ }
+
+ // place the final rows value
+ for(int j = 0; j < polytope.planes.length; j++) {
+ problemTableau[numberRows - 1][j] =
+ (distanceSign)*polytope.planes[j].w;
+ }
+ problemTableau[numberRows - 1][polytope.planes.length] = 1.0;
+ problemTableau[numberRows - 1][polytope.planes.length+1] = -1.0;
+ for(int j = 0; j < coordinates.length; j++) {
+ problemTableau[numberRows - 1][polytope.planes.length+2+j] = 0.0;
+ }
+
+ if(debug) {
+ System.err.println("The value of the problem tableau is: " );
+ for(int i=0; i < problemTableau.length; i++) {
+ for(int j=0; j < problemTableau[0].length; j++) {
+ System.err.print(problemTableau[i][j] + " ");
+ }
+ System.err.println();
+ }
+ }
+
+ double distance = generalStandardSimplexSolver(problemTableau,
+ Float.NEGATIVE_INFINITY);
+ if(debug) {
+ System.err.println("The value returned by the general standard simplex = " +
+ distance);
+ }
+ if (distance == Float.POSITIVE_INFINITY) {
+ return false;
+ }
+ if (dist != null) {
+ computeMinDistance(coordinates,
+ polytope.getCenter(),
+ null,
+ dist, iPnt);
+ }
+ return true;
+
+ }
+
+
+ // optimized version using arrays of doubles, but using the standard simplex
+ // method to solve the LP tableau. This version has not been optimized to
+ // work with a particular size input tableau and is much slower than some
+ // of the other variants...supposedly
+ double generalStandardSimplexSolver(double problemTableau[][],
+ double stopingValue) {
+ boolean debug = false;
+ int numRow = problemTableau.length;
+ int numCol = problemTableau[0].length;
+ boolean optimal = false;
+ int i, pivotRowIndex, pivotColIndex;
+ double maxElement, element, endElement, ratio, prevRatio;
+ double multiplier;
+
+ if(debug) {
+ System.err.println("The number of rows is : " + numRow);
+ System.err.println("The number of columns is : " + numCol);
+ }
+
+ // until the optimal solution is found continue to do
+ // iterations of the simplex method
+ while(!optimal) {
+
+ if(debug) {
+ System.err.println("input problem tableau is:");
+ for(int k=0; k < numRow; k++) {
+ for(int j=0; j < numCol; j++) {
+ System.err.println("kth, jth value is:" +k+" "+j+" : " +
+ problemTableau[k][j]);
+ }
+ }
+ }
+
+ // test to see if the current solution is optimal
+ // check all bottom row elements except the right most one and
+ // if all positive or zero its optimal
+ for(i = 0, maxElement = 0, pivotColIndex = -1; i < numCol - 1; i++) {
+ // a bottom row element
+ element = problemTableau[numRow - 1][i];
+ if( element < maxElement) {
+ maxElement = element;
+ pivotColIndex = i;
+ }
+ }
+
+ // if there is no negative non-zero element then we
+ // have found an optimal solution (the last row of the tableau)
+ if(pivotColIndex == -1) {
+ // found an optimal solution
+ //System.err.println("Found an optimal solution");
+ optimal = true;
+ }
+
+ //System.err.println("The value of maxElement is:" + maxElement);
+
+ if(!optimal) {
+ // Case when the solution is not optimal but not known to be
+ // either unbounded or infeasable
+
+ // from the above we have found the maximum negative element in
+ // bottom row, we have also found the column for this value
+ // the pivotColIndex represents this
+
+ // initialize the values for the algorithm, -1 for pivotRowIndex
+ // indicates no solution
+
+ prevRatio = Float.POSITIVE_INFINITY;
+ ratio = 0.0;
+ pivotRowIndex = -1;
+
+ // note if all of the elements in the pivot column are zero or
+ // negative the problem is unbounded.
+ for(i = 0; i < numRow - 1; i++) {
+ element = problemTableau[i][pivotColIndex]; // r value
+ endElement = problemTableau[i][numCol-1]; // s value
+
+ // pivot according to the rule that we want to choose the row
+ // with smallest s/r ratio see third case
+ // currently we ignore valuse of r==0 (case 1) and cases where the
+ // ratio is negative, i.e. either r or s are negative (case 2)
+ if(element == 0) {
+ if(debug) {
+ System.err.println("Division by zero has occurred");
+ System.err.println("Within the linear program solver");
+ System.err.println("Ignoring the zero as a potential pivot");
+ }
+ } else if ( (element < 0.0) || (endElement < 0.0) ){
+ if(debug) {
+ System.err.println("Ignoring cases where element is negative");
+ System.err.println("The value of element is: " + element);
+ System.err.println("The value of end Element is: " + endElement);
+ }
+ } else {
+ ratio = endElement/element; // should be s/r
+ if(debug) {
+ System.err.println("The value of element is: " + element);
+ System.err.println("The value of endElement is: " + endElement);
+ System.err.println("The value of ratio is: " + ratio);
+ System.err.println("The value of prevRatio is: " + prevRatio);
+ System.err.println("Value of ratio <= prevRatio is :" +
+ (ratio <= prevRatio));
+ }
+ if(ratio <= prevRatio) {
+ if(debug) {
+ System.err.println("updating prevRatio with ratio");
+ }
+ prevRatio = ratio;
+ pivotRowIndex = i;
+ }
+ }
+ }
+
+ // if the pivotRowIndex is still -1 then we know the pivotColumn
+ // has no viable pivot points and the solution is unbounded or
+ // infeasable (all pivot elements were either zero or negative or
+ // the right most value was negative (the later shouldn't happen?)
+ if(pivotRowIndex == -1) {
+ if(debug) {
+ System.err.println("UNABLE TO FIND SOLUTION");
+ System.err.println("The system is infeasable or unbounded");
+ }
+ return(Float.POSITIVE_INFINITY);
+ }
+
+ // we now have the pivot row and col all that remains is
+ // to divide through by this value and subtract the appropriate
+ // multiple of the pivot row from all other rows to obtain
+ // a tableau which has a column of all zeros and one 1 in the
+ // intersection of pivot row and col
+
+ // divide through by the pivot value
+ double pivotValue = problemTableau[pivotRowIndex][pivotColIndex];
+
+ if(debug) {
+ System.err.println("The value of row index is: " + pivotRowIndex);
+ System.err.println("The value of col index is: " + pivotColIndex);
+ System.err.println("The value of pivotValue is: " + pivotValue);
+ }
+ // divide through by s on the pivot row to obtain a 1 in pivot col
+ for(i = 0; i < numCol; i++) {
+ problemTableau[pivotRowIndex][i] =
+ problemTableau[pivotRowIndex][i] / pivotValue;
+ }
+
+ // subtract appropriate multiple of pivot row from all other rows
+ // to zero out all rows except the final row and the pivot row
+ for(i = 0; i < numRow; i++) {
+ if(i != pivotRowIndex) {
+ multiplier = problemTableau[i][pivotColIndex];
+ for(int j=0; j < numCol; j++) {
+ problemTableau[i][j] = problemTableau[i][j] -
+ multiplier * problemTableau[pivotRowIndex][j];
+ }
+ }
+ }
+ }
+ // case when the element is optimal
+ }
+ return(problemTableau[numRow - 1][numCol - 1]);
+ }
+
+
+
+ boolean edgeIntersectSphere(BoundingSphere sphere, Point3d start,
+ Point3d end)
+ {
+ double abLenSq, acLenSq, apLenSq, abDotAp, radiusSq;
+ Vector3d ab = new Vector3d();
+ Vector3d ap = new Vector3d();
+
+ ab.x = end.x - start.x;
+ ab.y = end.y - start.y;
+ ab.z = end.z - start.z;
+
+ ap.x = sphere.center.x - start.x;
+ ap.y = sphere.center.y - start.y;
+ ap.z = sphere.center.z - start.z;
+
+ abDotAp = ab.dot(ap);
+
+ if(abDotAp < 0.0) {
+ return false; // line segment points away from sphere.
+ }
+
+ abLenSq = ab.lengthSquared();
+ acLenSq = abDotAp * abDotAp / abLenSq;
+
+ if(acLenSq < abLenSq) {
+ return false; // C doesn't lies between end points of edge.
+ }
+
+ radiusSq = sphere.radius * sphere.radius;
+ apLenSq = ap.lengthSquared();
+
+ if((apLenSq - acLenSq) <= radiusSq) {
+ return true;
+ }
+
+ return false;
+
+ }
+
+
+ double det2D(Point2d a, Point2d b, Point2d p)
+ {
+ return (((p).x - (a).x) * ((a).y - (b).y) +
+ ((a).y - (p).y) * ((a).x - (b).x));
+ }
+
+ // Assume coord is CCW.
+ boolean pointIntersectPolygon2D(Vector3d normal, Point3d[] coord,
+ Point3d point)
+ {
+
+ double absNrmX, absNrmY, absNrmZ;
+ Point2d coord2D[] = new Point2d[coord.length];
+ Point2d pnt = new Point2d();
+
+ int i, j, axis;
+
+ // Project 3d points onto 2d plane.
+ // Note : Area of polygon is not preserve in this projection, but
+ // it doesn't matter here.
+
+ // Find the axis of projection.
+ absNrmX = Math.abs(normal.x);
+ absNrmY = Math.abs(normal.y);
+ absNrmZ = Math.abs(normal.z);
+
+ if(absNrmX > absNrmY)
+ axis = 0;
+ else
+ axis = 1;
+
+ if(axis == 0) {
+ if(absNrmX < absNrmZ)
+ axis = 2;
+ }
+ else if(axis == 1) {
+ if(absNrmY < absNrmZ)
+ axis = 2;
+ }
+
+ // System.err.println("Normal " + normal + " axis " + axis );
+
+ for(i=0; i<coord.length; i++) {
+ coord2D[i] = new Point2d();
+
+ switch (axis) {
+ case 0:
+ coord2D[i].x = coord[i].y;
+ coord2D[i].y = coord[i].z;
+ break;
+
+ case 1:
+ coord2D[i].x = coord[i].x;
+ coord2D[i].y = coord[i].z;
+ break;
+
+ case 2:
+ coord2D[i].x = coord[i].x;
+ coord2D[i].y = coord[i].y;
+ break;
+ }
+
+ // System.err.println("i " + i + " u " + uCoor[i] + " v " + vCoor[i]);
+ }
+
+
+ switch (axis) {
+ case 0:
+ pnt.x = point.y;
+ pnt.y = point.z;
+ break;
+
+ case 1:
+ pnt.x = point.x;
+ pnt.y = point.z;
+ break;
+
+ case 2:
+ pnt.x = point.x;
+ pnt.y = point.y;
+ break;
+ }
+
+ // Do determinant test.
+ for(j=0; j<coord.length; j++) {
+ if(j<(coord.length-1))
+ if(det2D(coord2D[j], coord2D[j+1], pnt)>0.0)
+ ;
+ else
+ return false;
+ else
+ if(det2D(coord2D[j], coord2D[0], pnt)>0.0)
+ ;
+ else
+ return false;
+ }
+
+ return true;
+
+ }
+
+
+ boolean edgeIntersectPlane(Vector3d normal, Point3d pnt, Point3d start,
+ Point3d end, Point3d iPnt)
+ {
+
+ Vector3d tempV3d = new Vector3d();
+ Vector3d direction = new Vector3d();
+ double pD, pNrmDotrDir, tr;
+
+ // Compute plane D.
+ tempV3d.set(pnt);
+ pD = normal.dot(tempV3d);
+
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+
+ pNrmDotrDir = normal.dot(direction);
+
+ // edge is parallel to plane.
+ if(pNrmDotrDir== 0.0) {
+ // System.err.println("Edge is parallel to plane.");
+ return false;
+ }
+
+ tempV3d.set(start);
+
+ tr = (pD - normal.dot(tempV3d))/ pNrmDotrDir;
+
+ // Edge intersects the plane behind the edge's start.
+ // or exceed the edge's length.
+ if((tr < 0.0 ) || (tr > 1.0 )) {
+ // System.err.println("Edge intersects the plane behind the start or exceed end.");
+ return false;
+ }
+
+ iPnt.x = start.x + tr * direction.x;
+ iPnt.y = start.y + tr * direction.y;
+ iPnt.z = start.z + tr * direction.z;
+
+ return true;
+
+ }
+
+ // Assume coord is CCW.
+ boolean edgeIntersectPolygon2D(Vector3d normal, Point3d[] coord,
+ Point3d[] seg)
+ {
+
+ double absNrmX, absNrmY, absNrmZ;
+ Point2d coord2D[] = new Point2d[coord.length];
+ Point2d seg2D[] = new Point2d[2];
+
+ int i, j, axis;
+
+ // Project 3d points onto 2d plane.
+ // Note : Area of polygon is not preserve in this projection, but
+ // it doesn't matter here.
+
+ // Find the axis of projection.
+ absNrmX = Math.abs(normal.x);
+ absNrmY = Math.abs(normal.y);
+ absNrmZ = Math.abs(normal.z);
+
+ if(absNrmX > absNrmY)
+ axis = 0;
+ else
+ axis = 1;
+
+ if(axis == 0) {
+ if(absNrmX < absNrmZ)
+ axis = 2;
+ }
+ else if(axis == 1) {
+ if(absNrmY < absNrmZ)
+ axis = 2;
+ }
+
+ // System.err.println("Normal " + normal + " axis " + axis );
+
+ for(i=0; i<coord.length; i++) {
+ coord2D[i] = new Point2d();
+
+ switch (axis) {
+ case 0:
+ coord2D[i].x = coord[i].y;
+ coord2D[i].y = coord[i].z;
+ break;
+
+ case 1:
+ coord2D[i].x = coord[i].x;
+ coord2D[i].y = coord[i].z;
+ break;
+
+ case 2:
+ coord2D[i].x = coord[i].x;
+ coord2D[i].y = coord[i].y;
+ break;
+ }
+
+ // System.err.println("i " + i + " u " + uCoor[i] + " v " + vCoor[i]);
+ }
+
+ for(i=0; i<2; i++) {
+ seg2D[i] = new Point2d();
+ switch (axis) {
+ case 0:
+ seg2D[i].x = seg[i].y;
+ seg2D[i].y = seg[i].z;
+ break;
+
+ case 1:
+ seg2D[i].x = seg[i].x;
+ seg2D[i].y = seg[i].z;
+ break;
+
+ case 2:
+ seg2D[i].x = seg[i].x;
+ seg2D[i].y = seg[i].y;
+ break;
+ }
+
+ // System.err.println("i " + i + " u " + uSeg[i] + " v " + vSeg[i]);
+ }
+
+ // Do determinant test.
+ boolean pntTest[][] = new boolean[2][coord.length];
+ boolean testFlag;
+
+ for(j=0; j<coord.length; j++) {
+ for(i=0; i<2; i++) {
+ if(j<(coord.length-1))
+ pntTest[i][j] = (det2D(coord2D[j], coord2D[j+1], seg2D[i])<0.0);
+ else
+ pntTest[i][j] = (det2D(coord2D[j], coord2D[0], seg2D[i])<0.0);
+ }
+
+ if((pntTest[0][j]==false) && (pntTest[1][j]==false))
+ return false;
+ }
+
+ testFlag = true;
+ for(i=0; i<coord.length; i++) {
+ if(pntTest[0][i]==false) {
+ testFlag = false;
+ break;
+ }
+ }
+
+ if(testFlag == true)
+ return true; // start point is inside polygon.
+
+ testFlag = true;
+ for(i=0; i<coord.length; i++) {
+ if(pntTest[1][i]==false) {
+ testFlag = false;
+ break;
+ }
+ }
+
+ if(testFlag == true)
+ return true; // end point is inside polygon.
+
+
+ int cnt = 0;
+ for(i=0; i<coord.length; i++) {
+ if(det2D(seg2D[0], seg2D[1], coord2D[i])<0.0)
+ cnt++;
+ }
+
+ if((cnt==0)||(cnt==coord.length))
+ return false;
+
+ return true;
+
+ }
+
+
+ // New stuffs .....
+ double getCompValue(Point3d v, int i) {
+ switch (i) {
+ case 0: return v.x;
+ case 1: return v.y;
+ }
+ // Has to return something, so set the default to z component.
+ return v.z;
+ }
+
+ double getCompValue(Point3d v0, Point3d v1, int i) {
+ switch (i) {
+ case 0: return (v0.x - v1.x);
+ case 1: return (v0.y - v1.y);
+ }
+ // Has to return some, so set the default to z component.
+ return (v0.z - v1.z);
+ }
+
+
+ boolean pointInTri(Point3d v0, Point3d u0, Point3d u1, Point3d u2,
+ Vector3d normal) {
+
+ double nAbsX, nAbsY, nAbsZ;
+ int i0, i1;
+
+ // first project onto an axis-aligned plane, that maximizes the area
+ // of the triangles, compute indices i0, i1.
+ nAbsX = Math.abs(normal.x);
+ nAbsY = Math.abs(normal.y);
+ nAbsZ = Math.abs(normal.z);
+
+ if (nAbsX > nAbsY) {
+ if(nAbsX > nAbsZ) {
+ i0 = 1; // nAbsX is greatest.
+ i1 = 2;
+ }
+ else {
+ i0 = 0; // nAbsZ is greatest.
+ i1 = 1;
+ }
+ } else { // nAbsX <= nAbsY
+ if(nAbsZ > nAbsY) {
+ i0 = 0; // nAbsZ is greatest.
+ i1 = 1;
+ }
+ else {
+ i0 = 0; // nAbsY is greatest.
+ i1 = 2;
+ }
+ }
+ return pointInTri(v0, u0, u1, u2, i0, i1);
+ }
+
+ boolean pointInTri(Point3d v0, Point3d u0, Point3d u1, Point3d u2,
+ int i0, int i1) {
+
+ double a, b, c, d0, d1, d2;
+ // is T1 completely inside T2 ?
+ // check if v0 is inside tri(u0,u1,u2)
+
+ a = getCompValue(u1, u0, i1);
+ b = -(getCompValue(u1, u0, i0));
+ c = -a * getCompValue(u0, i0) - b * getCompValue(u0, i1);
+ d0 = a * getCompValue(v0, i0) + b * getCompValue(v0, i1) + c;
+
+ a = getCompValue(u2, u1, i1);
+ b = -(getCompValue(u2, u1, i0));
+ c = -a * getCompValue(u1, i0) - b * getCompValue(u1, i1);
+ d1 = a * getCompValue(v0, i0) + b * getCompValue(v0, i1) + c;
+
+ a = getCompValue(u0, u2, i1);
+ b = -(getCompValue(u0, u2, i0));
+ c = -a * getCompValue(u2, i0) - b * getCompValue(u2, i1);
+ d2 = a * getCompValue(v0, i0) + b * getCompValue(v0, i1) + c;
+
+ if(d0*d1>0.0) {
+ if(d0*d2>0.0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ // this edge to edge test is based on Franlin Antonio's gem:
+ // "Faster line segment intersection", in Graphics Gems III, pp 199-202
+ boolean edgeAgainstEdge(Point3d v0, Point3d u0, Point3d u1, double aX, double aY,
+ int i0, int i1) {
+ double bX, bY, cX, cY, e, d, f;
+
+ bX = getCompValue(u0, u1,i0);
+ bY = getCompValue(u0, u1, i1);
+ cX = getCompValue(v0, u0, i0);
+ cY = getCompValue(v0, u0, i1);
+
+ f = aY * bX - aX * bY;
+ d = bY * cX - bX * cY;
+ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) {
+ e = aX * cY - aY * cX;
+ if(f>0) {
+ if(e>=0 && e<=f)
+ return true;
+ }
+ else {
+ if(e<=0 && e>=f)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ boolean edgeAgainstTriEdges(Point3d v0, Point3d v1, Point3d u0,
+ Point3d u1, Point3d u2, int i0, int i1) {
+ double aX, aY;
+
+ // aX = v1[i0] - v0[i0];
+ // aY = v1[i1] - v0[i1];
+ aX = getCompValue(v1, v0, i0);
+ aY = getCompValue(v1, v0, i1);
+
+ // test edge u0, u1 against v0, v1
+ if(edgeAgainstEdge(v0, u0, u1, aX, aY, i0, i1))
+ return true;
+ // test edge u1, u2 against v0, v1
+ if(edgeAgainstEdge(v0, u1, u2, aX, aY, i0, i1))
+ return true;
+ // test edge u2, u0 against v0, v1
+ if(edgeAgainstEdge(v0, u2, u0, aX, aY, i0, i1))
+ return true;
+
+ return false;
+
+ }
+
+ boolean coplanarTriTri(Vector3d normal, Point3d v0, Point3d v1, Point3d v2,
+ Point3d u0, Point3d u1, Point3d u2) {
+
+ double nAbsX, nAbsY, nAbsZ;
+ int i0, i1;
+
+ // first project onto an axis-aligned plane, that maximizes the area
+ // of the triangles, compute indices i0, i1.
+ nAbsX = Math.abs(normal.x);
+ nAbsY = Math.abs(normal.y);
+ nAbsZ = Math.abs(normal.z);
+
+ if(nAbsX > nAbsY) {
+ if(nAbsX > nAbsZ) {
+ i0 = 1; // nAbsX is greatest.
+ i1 = 2;
+ }
+ else {
+ i0 = 0; // nAbsZ is greatest.
+ i1 = 1;
+ }
+ }
+ else { // nAbsX <= nAbsY
+ if(nAbsZ > nAbsY) {
+ i0 = 0; // nAbsZ is greatest.
+ i1 = 1;
+ }
+ else {
+ i0 = 0; // nAbsY is greatest.
+ i1 = 2;
+ }
+ }
+
+ // test all edges of triangle 1 against the edges of triangle 2
+ if(edgeAgainstTriEdges(v0, v1, u0, u1, u2, i0, i1))
+ return true;
+
+ if(edgeAgainstTriEdges(v1, v2, u0, u1, u2, i0, i1))
+ return true;
+
+ if(edgeAgainstTriEdges(v2, v0, u0, u1, u2, i0, i1))
+ return true;
+
+ // finally, test if tri1 is totally contained in tri2 or vice versa.
+ if(pointInTri(v0, u0, u1, u2, i0, i1))
+ return true;
+
+ if(pointInTri(u0, v0, v1, v2, i0, i1))
+ return true;
+
+ return false;
+ }
+
+
+
+
+
+ boolean intersectTriPnt(Point3d v0, Point3d v1, Point3d v2, Point3d u) {
+
+ Vector3d e1 = new Vector3d();
+ Vector3d e2 = new Vector3d();
+ Vector3d n1 = new Vector3d();
+ Vector3d tempV3d = new Vector3d();
+
+ double d1, du;
+
+ // compute plane equation of triange(coord1)
+ e1.x = v1.x - v0.x;
+ e1.y = v1.y - v0.y;
+ e1.z = v1.z - v0.z;
+
+ e2.x = v2.x - v0.x;
+ e2.y = v2.y - v0.y;
+ e2.z = v2.z - v0.z;
+
+ n1.cross(e1,e2);
+
+ if(n1.length() == 0.0) {
+ // System.err.println("(1) Degenerate triangle.");
+ return false; // Degenerate triangle.
+ }
+
+ tempV3d.set(v0);
+ d1 = - n1.dot(tempV3d); // plane equation 1: n1.x + d1 = 0
+
+ // put u to compute signed distance to the plane.
+ tempV3d.set(u);
+ du = n1.dot(tempV3d) + d1;
+
+ // coplanarity robustness check
+ if(Math.abs(du)<EPS) du = 0.0;
+
+ // no intersection occurs
+ if(du != 0.0) {
+ return false;
+ }
+
+ double nAbsX, nAbsY, nAbsZ;
+ int i0, i1;
+
+ // first project onto an axis-aligned plane, that maximizes the area
+ // of the triangles, compute indices i0, i1.
+ nAbsX = Math.abs(n1.x);
+ nAbsY = Math.abs(n1.y);
+ nAbsZ = Math.abs(n1.z);
+
+ if(nAbsX > nAbsY) {
+ if(nAbsX > nAbsZ) {
+ i0 = 1; // nAbsX is greatest.
+ i1 = 2;
+ }
+ else {
+ i0 = 0; // nAbsZ is greatest.
+ i1 = 1;
+ }
+ }
+ else { // nAbsX <= nAbsY
+ if(nAbsZ > nAbsY) {
+ i0 = 0; // nAbsZ is greatest.
+ i1 = 1;
+ }
+ else {
+ i0 = 0; // nAbsY is greatest.
+ i1 = 2;
+ }
+ }
+
+
+ // finally, test if u is totally contained in tri.
+ if(pointInTri(u, v0, v1, v2, i0, i1)) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Return flag indicating whether two triangles intersect. This
+ * uses Tomas Moller's code for fast triangle-triangle
+ * intersection from his "Real-Time Rendering" book.
+ *
+ * The code is now divisionless. It tests for separating by planes
+ * parallel to either triangle. If neither separate the
+ * triangles, then two cases are considered. First case is if the
+ * normals to the triangles are parallel. In that case, the
+ * triangles are coplanar and a sequence of tests are made to see
+ * if edges of each triangle intersect the other triangle. If the
+ * normals are not parallel, then the two triangles can intersect
+ * only on the line of intersection of the two planes. The
+ * intervals of intersection of the triangles with the line of
+ * intersection of the two planes are computed and tested for
+ * overlap.
+ */
+ boolean intersectTriTri(Point3d v0, Point3d v1, Point3d v2,
+ Point3d u0, Point3d u1, Point3d u2) {
+
+ // System.err.println("In intersectTriTri ...");
+ Vector3d e1 = new Vector3d();
+ Vector3d e2 = new Vector3d();
+ Vector3d n1 = new Vector3d();
+ Vector3d n2 = new Vector3d();
+ Vector3d tempV3d = new Vector3d();
+
+ double d1, d2;
+ double du0, du1, du2, dv0, dv1, dv2;
+ double du0du1, du0du2, dv0dv1, dv0dv2;
+ int index;
+ double vp0=0.0, vp1=0.0, vp2=0.0;
+ double up0=0.0, up1=0.0, up2=0.0;
+ double bb, cc, max;
+
+ // compute plane equation of triange(coord1)
+ e1.x = v1.x - v0.x;
+ e1.y = v1.y - v0.y;
+ e1.z = v1.z - v0.z;
+
+ e2.x = v2.x - v0.x;
+ e2.y = v2.y - v0.y;
+ e2.z = v2.z - v0.z;
+
+ n1.cross(e1,e2);
+
+ if(n1.length() == 0.0) {
+ // System.err.println("(1) Degenerate triangle.");
+ return false; // Degenerate triangle.
+ }
+
+ tempV3d.set(v0);
+ d1 = - n1.dot(tempV3d); // plane equation 1: n1.x + d1 = 0
+
+ // put u0, u1, and u2 into plane equation 1
+ // to compute signed distance to the plane.
+ tempV3d.set(u0);
+ du0 = n1.dot(tempV3d) + d1;
+ tempV3d.set(u1);
+ du1 = n1.dot(tempV3d) + d1;
+ tempV3d.set(u2);
+ du2 = n1.dot(tempV3d) + d1;
+
+ // coplanarity robustness check
+ if(Math.abs(du0)<EPS) du0 = 0.0;
+ if(Math.abs(du1)<EPS) du1 = 0.0;
+ if(Math.abs(du2)<EPS) du2 = 0.0;
+
+ du0du1 = du0 * du1;
+ du0du2 = du0 * du2;
+
+ // same sign on all of them + not equal 0 ?
+ // no intersection occurs
+ if(du0du1>0.0 && du0du2>0.0) {
+ // System.err.println("In intersectTriTri : du0du1>0.0 && du0du2>0.0");
+ return false;
+ }
+
+ // compute plane of triangle(coord2)
+ e1.x = u1.x - u0.x;
+ e1.y = u1.y - u0.y;
+ e1.z = u1.z - u0.z;
+
+ e2.x = u2.x - u0.x;
+ e2.y = u2.y - u0.y;
+ e2.z = u2.z - u0.z;
+
+ n2.cross(e1,e2);
+
+ if(n2.length() == 0.0) {
+ // System.err.println("(2) Degenerate triangle.");
+ return false; // Degenerate triangle.
+ }
+
+ tempV3d.set(u0);
+ d2 = - n2.dot(tempV3d); // plane equation 2: n2.x + d2 = 0
+
+ // put v0, v1, and v2 into plane equation 2
+ // to compute signed distance to the plane.
+ tempV3d.set(v0);
+ dv0 = n2.dot(tempV3d) + d2;
+ tempV3d.set(v1);
+ dv1 = n2.dot(tempV3d) + d2;
+ tempV3d.set(v2);
+ dv2 = n2.dot(tempV3d) + d2;
+
+ // coplanarity robustness check
+ if(Math.abs(dv0)<EPS) dv0 = 0.0;
+ if(Math.abs(dv1)<EPS) dv1 = 0.0;
+ if(Math.abs(dv2)<EPS) dv2 = 0.0;
+
+ dv0dv1 = dv0 * dv1;
+ dv0dv2 = dv0 * dv2;
+
+ // same sign on all of them + not equal 0 ?
+ // no intersection occurs
+ if(dv0dv1>0.0 && dv0dv2>0.0) {
+ // System.err.println("In intersectTriTri : dv0dv1>0.0 && dv0dv2>0.0");
+ return false;
+ }
+ // compute direction of intersection line.
+ tempV3d.cross(n1, n2);
+
+ // compute and index to the largest component of tempV3d.
+ max = Math.abs(tempV3d.x);
+ index = 0;
+ bb = Math.abs(tempV3d.y);
+ cc = Math.abs(tempV3d.z);
+ if(bb>max) {
+ max=bb;
+ index=1;
+ }
+ if(cc>max) {
+ max=cc;
+ index=2;
+ }
+
+ // this is the simplified projection onto L.
+
+ switch (index) {
+ case 0:
+ vp0 = v0.x;
+ vp1 = v1.x;
+ vp2 = v2.x;
+
+ up0 = u0.x;
+ up1 = u1.x;
+ up2 = u2.x;
+ break;
+ case 1:
+ vp0 = v0.y;
+ vp1 = v1.y;
+ vp2 = v2.y;
+
+ up0 = u0.y;
+ up1 = u1.y;
+ up2 = u2.y;
+ break;
+ case 2:
+ vp0 = v0.z;
+ vp1 = v1.z;
+ vp2 = v2.z;
+
+ up0 = u0.z;
+ up1 = u1.z;
+ up2 = u2.z;
+ break;
+ }
+
+ // compute intereval for triangle 1.
+ double a=0.0, b=0.0, c=0.0, x0=0.0, x1=0.0;
+ if(dv0dv1>0.0) {
+ // here we know that dv0dv2 <= 0.0 that is dv0 and dv1 are on the same side,
+ // dv2 on the other side or on the plane.
+ a = vp2; b = (vp0 - vp2) * dv2; c = (vp1 - vp2) * dv2;
+ x0 = dv2 - dv0; x1 = dv2 - dv1;
+ }
+ else if(dv0dv2>0.0) {
+ // here we know that dv0dv1<=0.0
+ a = vp1; b = (vp0 - vp1) * dv1; c = (vp2 - vp1) * dv1;
+ x0 = dv1 - dv0; x1 = dv1 - dv2;
+ }
+ else if((dv1*dv2>0.0) || (dv0 != 0.0)) {
+ // here we know that dv0vd1<=0.0 or that dv0!=0.0
+ a = vp0; b = (vp1 - vp0) * dv0; c = (vp2 - vp0) * dv0;
+ x0 = dv0 - dv1; x1 = dv0 - dv2;
+ }
+ else if(dv1 != 0.0) {
+ a = vp1; b = (vp0 - vp1) * dv1; c = (vp2 - vp1) * dv1;
+ x0 = dv1 - dv0; x1 = dv1 - dv2;
+ }
+ else if(dv2 != 0.0) {
+ a = vp2; b = (vp0 - vp2) * dv2; c = (vp1 - vp2) * dv2;
+ x0 = dv2 - dv0; x1 = dv2 - dv1;
+ }
+ else {
+ // triangles are coplanar
+ boolean toreturn = coplanarTriTri(n1, v0, v1, v2, u0, u1, u2);
+ return toreturn;
+ }
+
+
+ // compute intereval for triangle 2.
+ double d=0.0, e=0.0, f=0.0, y0=0.0, y1=0.0;
+ if(du0du1>0.0) {
+ // here we know that du0du2 <= 0.0 that is du0 and du1 are on the same side,
+ // du2 on the other side or on the plane.
+ d = up2; e = (up0 - up2) * du2; f = (up1 - up2) * du2;
+ y0 = du2 - du0; y1 = du2 - du1;
+ }
+ else if(du0du2>0.0) {
+ // here we know that du0du1<=0.0
+ d = up1; e = (up0 - up1) * du1; f = (up2 - up1) * du1;
+ y0 = du1 - du0; y1 = du1 - du2;
+ }
+ else if((du1*du2>0.0) || (du0 != 0.0)) {
+ // here we know that du0du1<=0.0 or that D0!=0.0
+ d = up0; e = (up1 - up0) * du0; f = (up2 - up0) * du0;
+ y0 = du0 - du1; y1 = du0 - du2;
+ }
+ else if(du1 != 0.0) {
+ d = up1; e = (up0 - up1) * du1; f = (up2 - up1) * du1;
+ y0 = du1 - du0; y1 = du1 - du2;
+ }
+ else if(du2 != 0.0) {
+ d = up2; e = (up0 - up2) * du2; f = (up1 - up2) * du2;
+ y0 = du2 - du0; y1 = du2 - du1;
+ }
+ else {
+ // triangles are coplanar
+ // System.err.println("In intersectTriTri : coplanarTriTri test 2");
+ boolean toreturn = coplanarTriTri(n2, v0, v1, v2, u0, u1, u2);
+ return toreturn;
+ }
+
+ double xx, yy, xxyy, tmp, isect1S, isect1E, isect2S, isect2E;
+ xx = x0 * x1;
+ yy = y0 * y1;
+ xxyy = xx * yy;
+
+ tmp = a * xxyy;
+ isect1S = tmp + b * x1 * yy;
+ isect1E = tmp + c * x0 * yy;
+
+ tmp = d * xxyy;
+ isect2S = tmp + e * y1 * xx;
+ isect2E = tmp + f * y0 * xx;
+
+ // sort so that isect1S <= isect1E
+ if(isect1S > isect1E) {
+ tmp = isect1S;
+ isect1S = isect1E;
+ isect1E = tmp;
+ }
+
+ // sort so that isect2S <= isect2E
+ if(isect2S > isect2E) {
+ tmp = isect2S;
+ isect2S = isect2E;
+ isect2E = tmp;
+ }
+
+ if(isect1E<isect2S || isect2E<isect1S) {
+ // System.err.println("In intersectTriTri :isect1E<isect2S || isect2E<isect1S");
+ // System.err.println("In intersectTriTri : return false");
+ return false;
+ }
+
+ // System.err.println("In intersectTriTri : return true");
+ return true;
+
+ }
+
+
+
+ boolean intersectPolygon(Point3d coord1[], Point3d coord2[]) {
+ int i, j;
+ Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1;
+ Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3;
+ Vector3d pNrm = new Vector3d();
+ boolean epFlag;
+
+
+ // compute plane normal for coord1.
+ for(i=0; i<coord1.length-1;) {
+ vec0.x = coord1[i+1].x - coord1[i].x;
+ vec0.y = coord1[i+1].y - coord1[i].y;
+ vec0.z = coord1[i+1].z - coord1[i++].z;
+ if(vec0.length() > 0.0)
+ break;
+ }
+
+ for(j=i; j<coord1.length-1; j++) {
+ vec1.x = coord1[j+1].x - coord1[j].x;
+ vec1.y = coord1[j+1].y - coord1[j].y;
+ vec1.z = coord1[j+1].z - coord1[j].z;
+ if(vec1.length() > 0.0)
+ break;
+ }
+
+ if(j == (coord1.length-1)) {
+ // System.err.println("(1) Degenerate polygon.");
+ return false; // Degenerate polygon.
+ }
+
+ /*
+ for(i=0; i<coord1.length; i++)
+ System.err.println("coord1 P" + i + " " + coord1[i]);
+ for(i=0; i<coord2.length; i++)
+ System.err.println("coord2 P" + i + " " + coord2[i]);
+ */
+
+ pNrm.cross(vec0,vec1);
+
+ if(pNrm.length() == 0.0) {
+ // System.err.println("(2) Degenerate polygon.");
+ return false; // Degenerate polygon.
+ }
+
+ j = 0;
+ Point3d seg[] = new Point3d[2];
+ seg[0] = new Point3d();
+ seg[1] = new Point3d();
+
+ for(i=0; i<coord2.length; i++) {
+ if(i < (coord2.length-1))
+ epFlag = edgeIntersectPlane(pNrm, coord1[0], coord2[i],
+ coord2[i+1], seg[j]);
+ else
+ epFlag = edgeIntersectPlane(pNrm, coord1[0], coord2[i],
+ coord2[0], seg[j]);
+ if (epFlag) {
+ if(++j>1) {
+ break;
+ }
+ }
+ }
+
+ if (j==0) {
+ return false;
+ }
+
+ if (coord2.length < 3) {
+ boolean toreturn = pointIntersectPolygon2D(pNrm, coord1, seg[0]);
+ return toreturn;
+ } else {
+ boolean toreturn = edgeIntersectPolygon2D(pNrm, coord1, seg);
+ return toreturn;
+ }
+ }
+
+
+ /**
+ * Return true if triangle or quad intersects with ray and the
+ * distance is stored in dist[0] and the intersect point in iPnt
+ * (if iPnt is not null).
+ */
+ boolean intersectRay(Point3d coordinates[], PickRay ray, double dist[],
+ Point3d iPnt) {
+
+ return intersectRayOrSegment(coordinates, ray.direction, ray.origin,
+ dist, iPnt, false);
+
+ }
+
+ /**
+ * Return true if triangle or quad intersects with segment and
+ * the distance is stored in dist[0].
+ */
+ boolean intersectSegment( Point3d coordinates[], Point3d start, Point3d end,
+ double dist[], Point3d iPnt ) {
+ boolean result;
+ Vector3d direction = new Vector3d();
+ direction.x = end.x - start.x;
+ direction.y = end.y - start.y;
+ direction.z = end.z - start.z;
+ result = intersectRayOrSegment(coordinates, direction, start, dist, iPnt, true);
+ return result;
+ }
+
+
+
+ /**
+ * Return true if triangle or quad intersects with ray and the distance is
+ * stored in pr.
+ */
+ boolean intersectRayOrSegment(Point3d coordinates[],
+ Vector3d direction, Point3d origin,
+ double dist[], Point3d iPnt, boolean isSegment) {
+ Vector3d vec0, vec1, pNrm, tempV3d;
+ vec0 = new Vector3d();
+ vec1 = new Vector3d();
+ pNrm = new Vector3d();
+
+ double absNrmX, absNrmY, absNrmZ, pD = 0.0;
+ double pNrmDotrDir = 0.0;
+
+ boolean isIntersect = false;
+ int i, j, k=0, l = 0;
+
+ // Compute plane normal.
+ for (i=0; i<coordinates.length; i++) {
+ if (i != coordinates.length-1) {
+ l = i+1;
+ } else {
+ l = 0;
+ }
+ vec0.x = coordinates[l].x - coordinates[i].x;
+ vec0.y = coordinates[l].y - coordinates[i].y;
+ vec0.z = coordinates[l].z - coordinates[i].z;
+ if (vec0.length() > 0.0) {
+ break;
+ }
+ }
+
+
+ for (j=l; j<coordinates.length; j++) {
+ if (j != coordinates.length-1) {
+ k = j+1;
+ } else {
+ k = 0;
+ }
+ vec1.x = coordinates[k].x - coordinates[j].x;
+ vec1.y = coordinates[k].y - coordinates[j].y;
+ vec1.z = coordinates[k].z - coordinates[j].z;
+ if (vec1.length() > 0.0) {
+ break;
+ }
+ }
+
+ pNrm.cross(vec0,vec1);
+
+ if ((vec1.length() == 0) || (pNrm.length() == 0)) {
+ // degenerate to line if vec0.length() == 0
+ // or vec0.length > 0 and vec0 parallel to vec1
+ k = (l == 0 ? coordinates.length-1: l-1);
+ isIntersect = intersectLineAndRay(coordinates[l],
+ coordinates[k],
+ origin,
+ direction,
+ dist,
+ iPnt);
+
+ // put the Vectors on the freelist
+ return isIntersect;
+ }
+
+ // It is possible that Quad is degenerate to Triangle
+ // at this point
+
+ pNrmDotrDir = pNrm.dot(direction);
+
+ // Ray is parallel to plane.
+ if (pNrmDotrDir == 0.0) {
+ // Ray is parallel to plane
+ // Check line/triangle intersection on plane.
+ for (i=0; i < coordinates.length ;i++) {
+ if (i != coordinates.length-1) {
+ k = i+1;
+ } else {
+ k = 0;
+ }
+ if (intersectLineAndRay(coordinates[i],
+ coordinates[k],
+ origin,
+ direction,
+ dist,
+ iPnt)) {
+ isIntersect = true;
+ break;
+ }
+ }
+ return isIntersect;
+ }
+
+ // Plane equation: (p - p0)*pNrm = 0 or p*pNrm = pD;
+ tempV3d = new Vector3d();
+ tempV3d.set(coordinates[0]);
+ pD = pNrm.dot(tempV3d);
+ tempV3d.set(origin);
+
+ // Substitute Ray equation:
+ // p = origin + pi.distance*direction
+ // into the above Plane equation
+
+ dist[0] = (pD - pNrm.dot(tempV3d))/ pNrmDotrDir;
+
+ // Ray intersects the plane behind the ray's origin.
+ if ((dist[0] < -EPS ) ||
+ (isSegment && (dist[0] > 1.0+EPS))) {
+ // Ray intersects the plane behind the ray's origin
+ // or intersect point not fall in Segment
+ return false;
+ }
+
+ // Now, one thing for sure the ray intersect the plane.
+ // Find the intersection point.
+ if (iPnt == null) {
+ iPnt = new Point3d();
+ }
+ iPnt.x = origin.x + direction.x * dist[0];
+ iPnt.y = origin.y + direction.y * dist[0];
+ iPnt.z = origin.z + direction.z * dist[0];
+
+ // Project 3d points onto 2d plane
+ // Find the axis so that area of projection is maximize.
+ absNrmX = Math.abs(pNrm.x);
+ absNrmY = Math.abs(pNrm.y);
+ absNrmZ = Math.abs(pNrm.z);
+
+ // All sign of (y - y0) (x1 - x0) - (x - x0) (y1 - y0)
+ // must agree.
+ double sign, t, lastSign = 0;
+ Point3d p0 = coordinates[coordinates.length-1];
+ Point3d p1 = coordinates[0];
+
+ isIntersect = true;
+
+ if (absNrmX > absNrmY) {
+ if (absNrmX < absNrmZ) {
+ for (i=0; i < coordinates.length; i++) {
+ p0 = coordinates[i];
+ p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]);
+ sign = (iPnt.y - p0.y)*(p1.x - p0.x) -
+ (iPnt.x - p0.x)*(p1.y - p0.y);
+ if (isNonZero(sign)) {
+ if (sign*lastSign < 0) {
+ isIntersect = false;
+ break;
+ }
+ lastSign = sign;
+ } else { // point on line, check inside interval
+ t = p1.y - p0.y;
+ if (isNonZero(t)) {
+ t = (iPnt.y - p0.y)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ t = p1.x - p0.x;
+ if (isNonZero(t)) {
+ t = (iPnt.x - p0.x)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ // Ignore degenerate line=>point happen when Quad => Triangle.
+ // Note that by next round sign*lastSign = 0 so it will
+ // not pass the interest test. This should only happen once in the
+ // loop because we already check for degenerate geometry before.
+ }
+ }
+ }
+ }
+ } else {
+ for (i=0; i<coordinates.length; i++) {
+ p0 = coordinates[i];
+ p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]);
+ sign = (iPnt.y - p0.y)*(p1.z - p0.z) -
+ (iPnt.z - p0.z)*(p1.y - p0.y);
+ if (isNonZero(sign)) {
+ if (sign*lastSign < 0) {
+ isIntersect = false;
+ break;
+ }
+ lastSign = sign;
+ } else { // point on line, check inside interval
+ t = p1.y - p0.y;
+
+ if (isNonZero(t)) {
+ t = (iPnt.y - p0.y)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+
+ } else {
+ t = p1.z - p0.z;
+ if (isNonZero(t)) {
+ t = (iPnt.z - p0.z)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ //degenerate line=>point
+ }
+ }
+ }
+ }
+ }
+ } else {
+ if (absNrmY < absNrmZ) {
+ for (i=0; i<coordinates.length; i++) {
+ p0 = coordinates[i];
+ p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]);
+ sign = (iPnt.y - p0.y)*(p1.x - p0.x) -
+ (iPnt.x - p0.x)*(p1.y - p0.y);
+ if (isNonZero(sign)) {
+ if (sign*lastSign < 0) {
+ isIntersect = false;
+ break;
+ }
+ lastSign = sign;
+ } else { // point on line, check inside interval
+ t = p1.y - p0.y;
+ if (isNonZero(t)) {
+ t = (iPnt.y - p0.y)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ t = p1.x - p0.x;
+ if (isNonZero(t)) {
+ t = (iPnt.x - p0.x)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ //degenerate line=>point
+ }
+ }
+ }
+ }
+ } else {
+ for (i=0; i<coordinates.length; i++) {
+ p0 = coordinates[i];
+ p1 = (i != coordinates.length-1 ? coordinates[i+1]: coordinates[0]);
+ sign = (iPnt.x - p0.x)*(p1.z - p0.z) -
+ (iPnt.z - p0.z)*(p1.x - p0.x);
+ if (isNonZero(sign)) {
+ if (sign*lastSign < 0) {
+ isIntersect = false;
+ break;
+ }
+ lastSign = sign;
+ } else { // point on line, check inside interval
+ t = p1.x - p0.x;
+ if (isNonZero(t)) {
+ t = (iPnt.x - p0.x)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ t = p1.z - p0.z;
+ if (isNonZero(t)) {
+ t = (iPnt.z - p0.z)/t;
+ isIntersect = ((t > -EPS) && (t < 1+EPS));
+ break;
+ } else {
+ //degenerate line=>point
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (isIntersect) {
+ dist[0] *= direction.length();
+ }
+ return isIntersect;
+ }
+
+
+
+ static final boolean isNonZero(double v) {
+ return ((v > EPS) || (v < -EPS));
+
+ }
+
+ /**
+ * Return true if point is on the inside of halfspace test. The
+ * halfspace is partition by the plane of triangle or quad.
+ */
+ boolean inside( Point3d coordinates[], PickPoint point, int ccw ) {
+
+ Vector3d vec0 = new Vector3d(); // Edge vector from point 0 to point 1;
+ Vector3d vec1 = new Vector3d(); // Edge vector from point 0 to point 2 or 3;
+ Vector3d pNrm = new Vector3d();
+ double pD = 0.0;
+ Vector3d tempV3d = new Vector3d();
+
+ int i, j;
+
+ // Compute plane normal.
+ for(i=0; i<coordinates.length-1;) {
+ vec0.x = coordinates[i+1].x - coordinates[i].x;
+ vec0.y = coordinates[i+1].y - coordinates[i].y;
+ vec0.z = coordinates[i+1].z - coordinates[i++].z;
+ if(vec0.length() > 0.0)
+ break;
+ }
+
+ for(j=i; j<coordinates.length-1; j++) {
+ vec1.x = coordinates[j+1].x - coordinates[j].x;
+ vec1.y = coordinates[j+1].y - coordinates[j].y;
+ vec1.z = coordinates[j+1].z - coordinates[j].z;
+ if(vec1.length() > 0.0)
+ break;
+ }
+
+ if(j == (coordinates.length-1)) {
+ // System.err.println("(1) Degenerate polygon.");
+ return false; // Degenerate polygon.
+ }
+
+ /*
+ System.err.println("Ray orgin : " + ray.origin + " dir " + ray.direction);
+ System.err.println("Triangle/Quad :");
+ for(i=0; i<coordinates.length; i++)
+ System.err.println("P" + i + " " + coordinates[i]);
+ */
+
+ if( ccw == 0x1)
+ pNrm.cross(vec0,vec1);
+ else
+ pNrm.cross(vec1,vec0);
+
+ if(pNrm.length() == 0.0) {
+ // System.err.println("(2) Degenerate polygon.");
+ return false; // Degenerate polygon.
+ }
+ // Compute plane D.
+ tempV3d.set(coordinates[0]);
+ pD = pNrm.dot(tempV3d);
+ tempV3d.set(point.location);
+
+ return ((pD - pNrm.dot(tempV3d)) <= 0);
+ }
+
+ boolean intersectPntAndPnt( Point3d pnt1, Point3d pnt2 ) {
+ return ((pnt1.x == pnt2.x) &&
+ (pnt1.y == pnt2.y) &&
+ (pnt1.z == pnt2.z));
+ }
+
+ boolean intersectPntAndRay(Point3d pnt, Point3d ori, Vector3d dir,
+ double dist[]) {
+ int flag = 0;
+ double temp;
+
+ if(dir.x != 0.0) {
+ flag = 0;
+ dist[0] = (pnt.x - ori.x)/dir.x;
+ }
+ else if(dir.y != 0.0) {
+ if(pnt.x != ori.x)
+ return false;
+ flag = 1;
+ dist[0] = (pnt.y - ori.y)/dir.y;
+ }
+ else if(dir.z != 0.0) {
+ if((pnt.x != ori.x)||(pnt.y != ori.y))
+ return false;
+ flag = 2;
+ dist[0] = (pnt.z - ori.z)/dir.z;
+
+ }
+ else
+ return false;
+
+ if(dist[0] < 0.0)
+ return false;
+
+ if(flag == 0) {
+ temp = ori.y + dist[0] * dir.y;
+ if((pnt.y < (temp - EPS)) || (pnt.y > (temp + EPS)))
+ return false;
+ }
+
+ if(flag < 2) {
+ temp = ori.z + dist[0] * dir.z;
+ if((pnt.z < (temp - EPS)) || (pnt.z > (temp + EPS)))
+ return false;
+ }
+
+ return true;
+
+ }
+
+ boolean intersectLineAndRay(Point3d start, Point3d end,
+ Point3d ori, Vector3d dir, double dist[],
+ Point3d iPnt) {
+
+ double m00, m01, m10, m11;
+ double mInv00, mInv01, mInv10, mInv11;
+ double dmt, t, s, tmp1, tmp2;
+ Vector3d lDir;
+
+ // System.err.println("GeometryArrayRetained : intersectLineAndRay");
+ // System.err.println("start " + start + " end " + end );
+ // System.err.println("ori " + ori + " dir " + dir);
+
+ lDir = new Vector3d();
+ lDir.x = (end.x - start.x);
+ lDir.y = (end.y - start.y);
+ lDir.z = (end.z - start.z);
+
+ m00 = lDir.x;
+ m01 = -dir.x;
+ m10 = lDir.y;
+ m11 = -dir.y;
+
+ // Get the determinant.
+ dmt = (m00 * m11) - (m10 * m01);
+
+ if (dmt==0.0) { // No solution, check degenerate line
+ boolean isIntersect = false;
+ if ((lDir.x == 0) && (lDir.y == 0) && (lDir.z == 0)) {
+ isIntersect = intersectPntAndRay(start, ori, dir, dist);
+ if (isIntersect && (iPnt != null)) {
+ iPnt.set(start);
+ }
+ }
+ return isIntersect;
+ }
+ // Find the inverse.
+ tmp1 = 1/dmt;
+
+ mInv00 = tmp1 * m11;
+ mInv01 = tmp1 * (-m01);
+ mInv10 = tmp1 * (-m10);
+ mInv11 = tmp1 * m00;
+
+ tmp1 = ori.x - start.x;
+ tmp2 = ori.y - start.y;
+
+ t = mInv00 * tmp1 + mInv01 * tmp2;
+ s = mInv10 * tmp1 + mInv11 * tmp2;
+
+ if(s<0.0) { // Before the origin of ray.
+ // System.err.println("Before the origin of ray " + s);
+ return false;
+ }
+ if((t<0)||(t>1.0)) {// Before or after the end points of line.
+ // System.err.println("Before or after the end points of line. " + t);
+ return false;
+ }
+
+ tmp1 = ori.z + s * dir.z;
+ tmp2 = start.z + t * lDir.z;
+
+ if((tmp1 < (tmp2 - EPS)) || (tmp1 > (tmp2 + EPS))) {
+ // System.err.println("No intersection : tmp1 " + tmp1 + " tmp2 " + tmp2);
+ return false;
+ }
+
+ dist[0] = s;
+
+ if (iPnt != null) {
+ // compute point of intersection.
+ iPnt.x = ori.x + dir.x * dist[0];
+ iPnt.y = ori.y + dir.y * dist[0];
+ iPnt.z = ori.z + dir.z * dist[0];
+ }
+
+ // System.err.println("Intersected : tmp1 " + tmp1 + " tmp2 " + tmp2);
+ return true;
+ }
+
+ /**
+ Return true if triangle or quad intersects with cylinder. The
+ distance is stored in dist.
+ */
+ boolean intersectCylinder(Point3d coordinates[], PickCylinder cyl,
+ double dist[], Point3d iPnt) {
+
+ Point3d origin = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+ Point3d iPnt1 = new Point3d();
+ Vector3d originToIpnt = new Vector3d();
+
+ if (iPnt == null) {
+ iPnt = new Point3d();
+ }
+
+ // Get cylinder information
+ cyl.getOrigin (origin);
+ cyl.getDirection (direction);
+ double radius = cyl.getRadius ();
+
+ if (cyl instanceof PickCylinderSegment) {
+ ((PickCylinderSegment)cyl).getEnd (end);
+ }
+
+ // If the ray intersects, we're good (do not do this if we only have
+ // a segment
+ if (coordinates.length > 2) {
+ if (cyl instanceof PickCylinderRay) {
+ if (intersectRay(coordinates,
+ new PickRay(origin, direction),
+ dist, iPnt)) {
+ return true;
+ }
+ }
+ else {
+ if (intersectSegment(coordinates, origin, end, dist, iPnt)) {
+ return true;
+ }
+ }
+ }
+
+ // Ray doesn't intersect, check distance to edges
+ double sqDistToEdge;
+ int j;
+ for (int i=0; i<coordinates.length;i++) {
+ j = (i < coordinates.length-1 ? i+1: 0);
+ if (cyl instanceof PickCylinderSegment) {
+ sqDistToEdge =
+ Utils.segmentToSegment(origin, end,
+ coordinates[i], coordinates[j],
+ iPnt1, iPnt, null);
+ }
+ else {
+ sqDistToEdge =
+ Utils.rayToSegment(origin, direction,
+ coordinates[i], coordinates[j],
+ iPnt1, iPnt, null);
+ }
+ if (sqDistToEdge <= radius*radius) {
+ originToIpnt.sub (iPnt1, origin);
+ dist[0] = originToIpnt.length();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ Return true if triangle or quad intersects with cone. The
+ distance is stored in dist.
+ */
+ boolean intersectCone(Point3d coordinates[], PickCone cone,
+ double[] dist, Point3d iPnt) {
+
+ Point3d origin = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+ Vector3d originToIpnt = new Vector3d();
+ double distance;
+
+ Point3d iPnt1 = new Point3d();
+
+ if (iPnt == null) {
+ iPnt = new Point3d();
+ }
+ // Get cone information
+ cone.getOrigin (origin);
+ cone.getDirection (direction);
+ double radius;
+
+ if (cone instanceof PickConeSegment) {
+ ((PickConeSegment)cone).getEnd (end);
+ }
+
+ // If the ray intersects, we're good (do not do this if we only have
+ // a segment
+ if (coordinates.length > 2) {
+ if (cone instanceof PickConeRay) {
+ if (intersectRay(coordinates,
+ new PickRay (origin, direction),
+ dist, iPnt)) {
+ return true;
+ }
+ }
+ else {
+ if (intersectSegment(coordinates, origin, end, dist, iPnt)) {
+ return true;
+ }
+ }
+ }
+
+ // Ray doesn't intersect, check distance to edges
+ double sqDistToEdge;
+ int j = 0;
+ for (int i=0; i<coordinates.length;i++) {
+ j = (i < coordinates.length-1 ? i+1: 0);
+ if (cone instanceof PickConeSegment) {
+ sqDistToEdge =
+ Utils.segmentToSegment (origin, end,
+ coordinates[i], coordinates[j],
+ iPnt1, iPnt, null);
+ }
+ else {
+ sqDistToEdge =
+ Utils.rayToSegment (origin, direction,
+ coordinates[i], coordinates[j],
+ iPnt1, iPnt, null);
+ }
+ originToIpnt.sub(iPnt1, origin);
+ distance = originToIpnt.length();
+ radius = Math.tan (cone.getSpreadAngle()) * distance;
+ if (sqDistToEdge <= radius*radius) {
+ // System.err.println ("intersectCone: edge "+i+" intersected");
+ dist[0] = distance;
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ Return true if point intersects with cylinder and the distance is
+ stored in dist.
+ */
+ boolean intersectCylinder(Point3d pt, PickCylinder cyl,
+ double[] dist) {
+
+ Point3d origin = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+ Point3d iPnt = new Point3d();
+ Vector3d originToIpnt = new Vector3d();
+
+ // Get cylinder information
+ cyl.getOrigin (origin);
+ cyl.getDirection (direction);
+ double radius = cyl.getRadius ();
+ double sqDist;
+
+ if (cyl instanceof PickCylinderSegment) {
+ ((PickCylinderSegment)cyl).getEnd (end);
+ sqDist = Utils.ptToSegSquare(pt, origin, end, iPnt);
+ }
+ else {
+ sqDist = Utils.ptToRaySquare(pt, origin, direction, iPnt);
+ }
+ if (sqDist <= radius*radius) {
+ originToIpnt.sub (iPnt, origin);
+ dist[0] = originToIpnt.length();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ Return true if point intersects with cone and the
+ distance is stored in pi.
+ */
+ boolean intersectCone(Point3d pt, PickCone cone, double[] dist)
+ {
+ Point3d origin = new Point3d();
+ Point3d end = new Point3d();
+ Vector3d direction = new Vector3d();
+ Point3d iPnt = new Point3d();
+ Vector3d originToIpnt = new Vector3d();
+
+ // Get cone information
+ cone.getOrigin (origin);
+ cone.getDirection (direction);
+ double radius;
+ double distance;
+ double sqDist;
+
+ if (cone instanceof PickConeSegment) {
+ ((PickConeSegment)cone).getEnd (end);
+ sqDist = Utils.ptToSegSquare(pt, origin, end, iPnt);
+ }
+ else {
+ sqDist = Utils.ptToRaySquare(pt, origin, direction, iPnt);
+ }
+ originToIpnt.sub(iPnt, origin);
+ distance = originToIpnt.length();
+ radius = Math.tan (cone.getSpreadAngle()) * distance;
+ if (sqDist <= radius*radius) {
+ dist[0] = distance;
+ return true;
+ }
+ return false;
+ }
+
+
+ void setCoordRefBuffer(J3DBuffer coords) {
+ if (coords != null) {
+ switch (coords.bufferType) {
+ case FLOAT:
+ assert ((FloatBuffer)coords.getROBuffer()).isDirect();
+ break;
+ case DOUBLE:
+ assert ((DoubleBuffer)coords.getROBuffer()).isDirect();
+ break;
+ case NULL:
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray115"));
+
+ default:
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (3 * idx.maxCoordIndex >= coords.getROBuffer().limit()) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+ } else if (coords.getROBuffer().limit() < (3*(initialCoordIndex+validVertexCount))) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ }
+
+ // lock the geometry and start to do real work
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ coordRefBuffer = coords;
+ if(coords == null) {
+ floatBufferRefCoords = null;
+ doubleBufferRefCoords = null;
+ // XXXX: if not mix java array with nio buffer
+ // vertexType can be used as vertexTypeBuffer
+ vertexType &= ~PD;
+ vertexType &= ~PF;
+ }else {
+ switch (coords.bufferType) {
+ case FLOAT:
+ floatBufferRefCoords = (FloatBuffer)coords.getROBuffer();
+ doubleBufferRefCoords = null;
+ vertexType |= PF;
+ vertexType &= ~PD;
+ break;
+ case DOUBLE:
+ floatBufferRefCoords = null;
+ doubleBufferRefCoords = (DoubleBuffer)coords.getROBuffer();
+ vertexType |= PD;
+ vertexType &= ~PF;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // need not call setupMirrorVertexPointer() since
+ // we are not going to set mirror in NIO buffer case
+ // XXXX: if we need to mix java array with buffer,
+ // we may need to consider setupMirrorVertexPointer()
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && source != null) {
+ if (isLive) {
+ processCoordsChanged((coords == null));
+ sendDataChangedMessage(true);
+ } else {
+ boundsDirty = true;
+ }
+ }
+
+ }
+
+
+ J3DBuffer getCoordRefBuffer() {
+ return coordRefBuffer;
+ }
+
+
+ void setCoordRefFloat(float[] coords) {
+
+ // If non-null coordinate and vertType is either defined
+ // to be something other than PF, then issue an error
+ if (coords != null) {
+ if ((vertexType & VERTEX_DEFINED) != 0 &&
+ (vertexType & VERTEX_DEFINED) != PF) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (3 * idx.maxCoordIndex >= coords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+ } else if (coords.length < 3 * (initialCoordIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+
+ floatRefCoords = coords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (coords == null)
+ vertexType &= ~PF;
+ else
+ vertexType |= PF;
+ }
+ else {
+ setupMirrorVertexPointer(PF);
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && source != null) {
+ if (isLive) {
+ processCoordsChanged(coords == null);
+ sendDataChangedMessage(true);
+ } else {
+ boundsDirty = true;
+ }
+ }
+ }
+
+
+ float[] getCoordRefFloat() {
+ return floatRefCoords;
+ }
+
+
+ void setCoordRefDouble(double[] coords) {
+
+ if (coords != null) {
+ if ((vertexType & VERTEX_DEFINED) != 0 &&
+ (vertexType & VERTEX_DEFINED) != PD) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (3 * idx.maxCoordIndex >= coords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+ } else if (coords.length < 3 * (initialCoordIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ doubleRefCoords = coords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (coords == null)
+ vertexType &= ~PD;
+ else
+ vertexType |= PD;
+ }
+ else {
+ setupMirrorVertexPointer(PD);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && source != null) {
+ if (isLive) {
+ processCoordsChanged(coords == null);
+ sendDataChangedMessage(true);
+ } else {
+ boundsDirty = true;
+ }
+ }
+ }
+
+ double[] getCoordRefDouble() {
+ return doubleRefCoords;
+ }
+
+ void setCoordRef3f(Point3f[] coords) {
+
+ if (coords != null) {
+ if ((vertexType & VERTEX_DEFINED) != 0 &&
+ (vertexType & VERTEX_DEFINED) != P3F) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxCoordIndex >= coords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+ } else if (coords.length < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ p3fRefCoords = coords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (coords == null)
+ vertexType &= ~P3F;
+ else
+ vertexType |= P3F;
+ }
+ else {
+ setupMirrorVertexPointer(P3F);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && source != null) {
+ if (isLive) {
+ processCoordsChanged(coords == null);
+ sendDataChangedMessage(true);
+ } else {
+ boundsDirty = true;
+ }
+ }
+ }
+
+ Point3f[] getCoordRef3f() {
+ return p3fRefCoords;
+
+ }
+
+ void setCoordRef3d(Point3d[] coords) {
+
+ if (coords != null) {
+ if ((vertexType & VERTEX_DEFINED) != 0 &&
+ (vertexType & VERTEX_DEFINED) != P3D) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxCoordIndex >= coords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+ } else if (coords.length < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ p3dRefCoords = coords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (coords == null)
+ vertexType &= ~P3D;
+ else
+ vertexType |= P3D;
+ } else {
+ setupMirrorVertexPointer(P3D);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && source != null) {
+ if (isLive) {
+ processCoordsChanged(coords == null);
+ sendDataChangedMessage(true);
+ } else {
+ boundsDirty = true;
+ }
+ }
+ }
+
+ Point3d[] getCoordRef3d() {
+ return p3dRefCoords;
+ }
+
+ void setColorRefFloat(float[] colors) {
+
+ if (colors != null) {
+ if ((vertexType & COLOR_DEFINED) != 0 &&
+ (vertexType & COLOR_DEFINED) != CF) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray123"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (getColorStride() * idx.maxColorIndex >= colors.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.length < getColorStride() * (initialColorIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ floatRefColors = colors;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (colors == null)
+ vertexType &= ~CF;
+ else
+ vertexType |= CF;
+ }
+ else {
+ setupMirrorColorPointer(CF, false);
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ float[] getColorRefFloat() {
+ return floatRefColors;
+ }
+
+
+ // set the color with nio buffer
+ void setColorRefBuffer(J3DBuffer colors) {
+ if (colors != null) {
+ switch(colors.bufferType) {
+ case FLOAT:
+ assert ((FloatBuffer)colors.getROBuffer()).isDirect();
+ break;
+ case BYTE:
+ assert ((ByteBuffer)colors.getROBuffer()).isDirect();
+ break;
+ case NULL:
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray115"));
+
+ default:
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116"));
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray123"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (getColorStride() * idx.maxColorIndex >= colors.getROBuffer().limit()) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.getROBuffer().limit() <
+ getColorStride() * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ colorRefBuffer = colors;
+ if(colors == null) {
+ floatBufferRefColors = null;
+ byteBufferRefColors = null;
+ } else {
+ switch (colors.bufferType) {
+ case FLOAT:
+ floatBufferRefColors = (FloatBuffer)colors.getROBuffer();
+ byteBufferRefColors = null;
+ break;
+
+ case BYTE:
+ byteBufferRefColors = (ByteBuffer)colors.getROBuffer();
+ floatBufferRefColors = null;
+ break;
+ default:
+ break;
+ }
+ }
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if(colors == null) {
+ vertexType &= ~CF;
+ vertexType &= ~CUB;
+ } else {
+ switch (colors.bufferType) {
+ case FLOAT:
+ vertexType |= CF;
+ vertexType &= ~CUB;
+ break;
+
+ case BYTE:
+ vertexType |= CUB;
+ vertexType &= ~CF;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else {
+ setupMirrorColorPointer(CF|CUB, false);
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+ // return the color data in nio buffer format
+ J3DBuffer getColorRefBuffer() {
+ return colorRefBuffer;
+ }
+
+ void setColorRefByte(byte[] colors) {
+
+ if (colors != null) {
+ if ((vertexType & COLOR_DEFINED) != 0 &&
+ (vertexType & COLOR_DEFINED) != CUB) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray123"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (getColorStride() * idx.maxColorIndex >= colors.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.length < getColorStride() * (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ byteRefColors = colors;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (colors == null)
+ vertexType &= ~CUB;
+ else
+ vertexType |= CUB;
+ }
+ else {
+ setupMirrorColorPointer(CUB, false);
+ }
+ if(isLive){
+ geomLock.unLock();
+ }
+
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ byte[] getColorRefByte() {
+ return byteRefColors;
+ }
+
+ void setColorRef3f(Color3f[] colors) {
+
+ if (colors != null) {
+ if ((vertexType & COLOR_DEFINED) != 0 &&
+ (vertexType & COLOR_DEFINED) != C3F) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_3) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray92"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (idx.maxColorIndex >= colors.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ c3fRefColors = colors;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (colors == null)
+ vertexType &= ~C3F;
+ else
+ vertexType |= C3F;
+ }
+ else {
+ setupMirrorColorPointer(C3F, false);
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ Color3f[] getColorRef3f() {
+ return c3fRefColors;
+ }
+
+
+ void setColorRef4f(Color4f[] colors) {
+
+ if (colors != null) {
+ if ((vertexType & COLOR_DEFINED) != 0 &&
+ (vertexType & COLOR_DEFINED) != C4F) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+ if ((vertexFormat & GeometryArray.COLOR_4) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray93"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (idx.maxColorIndex >= colors.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ c4fRefColors = colors;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (colors == null)
+ vertexType &= ~C4F;
+ else
+ vertexType |= C4F;
+ }
+ else {
+ setupMirrorColorPointer(C4F, false);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+ Color4f[] getColorRef4f() {
+ return c4fRefColors;
+ }
+
+
+ void setColorRef3b(Color3b[] colors) {
+
+ if (colors != null) {
+
+ if ((vertexType & COLOR_DEFINED) != 0 &&
+ (vertexType & COLOR_DEFINED) != C3UB) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_3) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray92"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxColorIndex >= colors.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.length < (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ c3bRefColors = colors;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (colors == null)
+ vertexType &= ~C3UB;
+ else
+ vertexType |= C3UB;
+ }
+ else {
+ setupMirrorColorPointer(C3UB, false);
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ Color3b[] getColorRef3b() {
+ return c3bRefColors;
+ }
+
+ void setColorRef4b(Color4b[] colors) {
+
+ if (colors != null) {
+ if ((vertexType & COLOR_DEFINED) != 0 &&
+ (vertexType & COLOR_DEFINED) != C4UB) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.COLOR_4) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray93"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained) this;
+
+ if (idx.maxColorIndex >= colors.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+ } else if (colors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ c4bRefColors = colors;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (colors == null)
+ vertexType &= ~C4UB;
+ else
+ vertexType |= C4UB;
+ }
+ else {
+ setupMirrorColorPointer(C4UB, false);
+ }
+
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ Color4b[] getColorRef4b() {
+ return c4bRefColors;
+ }
+
+ void setNormalRefFloat(float[] normals) {
+
+ if (normals != null) {
+ if ((vertexType & NORMAL_DEFINED) != 0 &&
+ (vertexType & NORMAL_DEFINED) != NF) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.NORMALS) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray122"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxNormalIndex*3 >= normals.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26"));
+ }
+ } else if (normals.length < 3 * (initialNormalIndex + validVertexCount )) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ floatRefNormals = normals;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (normals == null)
+ vertexType &= ~NF;
+ else
+ vertexType |= NF;
+ }
+ else {
+ setupMirrorNormalPointer(NF);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ float[] getNormalRefFloat() {
+ return floatRefNormals;
+ }
+
+ // setup the normal with nio buffer
+ void setNormalRefBuffer(J3DBuffer normals) {
+
+ FloatBuffer bufferImpl = null;
+
+ if (normals != null) {
+ if(normals.bufferType != J3DBuffer.Type.FLOAT)
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116"));
+
+ bufferImpl = (FloatBuffer)normals.getROBuffer();
+
+ assert bufferImpl.isDirect();
+
+ if ((vertexFormat & GeometryArray.NORMALS) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray122"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (idx.maxNormalIndex * 3 >=
+ ((FloatBuffer)normals.getROBuffer()).limit()) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26"));
+ }
+ } else if (bufferImpl.limit() < 3 * (initialNormalIndex + validVertexCount )) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ normalRefBuffer = normals;
+
+ if (normals == null) {
+ vertexType &= ~NF;
+ floatBufferRefNormals = null;
+ }
+ else {
+ vertexType |= NF;
+ floatBufferRefNormals = bufferImpl;
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+ J3DBuffer getNormalRefBuffer() {
+ return normalRefBuffer;
+ }
+
+ void setNormalRef3f(Vector3f[] normals) {
+
+ if (normals != null) {
+ if ((vertexType & NORMAL_DEFINED) != 0 &&
+ (vertexType & NORMAL_DEFINED) != N3F) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray98"));
+ }
+
+ if ((vertexFormat & GeometryArray.NORMALS) == 0) {
+ throw new IllegalStateException(J3dI18N.getString("GeometryArray122"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (idx.maxNormalIndex >= normals.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26"));
+ }
+ } else if (normals.length < (initialNormalIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ v3fRefNormals = normals;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ if (normals == null)
+ vertexType &= ~N3F;
+ else
+ vertexType |= N3F;
+ }
+ else {
+ setupMirrorNormalPointer(N3F);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+ Vector3f[] getNormalRef3f() {
+ return v3fRefNormals;
+ }
+
+ final int getColorStride() {
+ return ((vertexFormat & GeometryArray.WITH_ALPHA) != 0 ? 4 : 3);
+ }
+
+ final int getTexStride() {
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ return 2;
+ }
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ return 3;
+ }
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ return 4;
+ }
+
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray121"));
+ }
+
+ void setTexCoordRefFloat(int texCoordSet, float[] texCoords) {
+
+ if (texCoordType != 0 && texCoordType != TF) {
+ if (texCoords != null) {
+ throw new IllegalArgumentException(
+ J3dI18N.getString("GeometryArray98"));
+ }
+ return;
+ }
+
+ if (texCoords != null) {
+
+ int ts = getTexStride();
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxTexCoordIndices[texCoordSet]*ts >= texCoords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25"));
+ }
+ } else if (texCoords.length < ts*(initialTexCoordIndex[texCoordSet]+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+ refTexCoords[texCoordSet] = texCoords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ texCoordType = TF;
+ validateTexCoordPointerType();
+ }
+ else {
+ setupMirrorTexCoordPointer(texCoordSet, TF);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ float[] getTexCoordRefFloat(int texCoordSet) {
+ return ((float[])refTexCoords[texCoordSet]);
+ }
+
+ // set the tex coord with nio buffer
+ void setTexCoordRefBuffer(int texCoordSet, J3DBuffer texCoords) {
+
+ FloatBuffer bufferImpl = null;
+
+ if (texCoords != null) {
+ if(texCoords.bufferType != J3DBuffer.Type.FLOAT)
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116"));
+
+ bufferImpl = (FloatBuffer)texCoords.getROBuffer();
+ int bufferSize = bufferImpl.limit();
+
+ assert bufferImpl.isDirect();
+
+ int ts = getTexStride();
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+ if (idx.maxTexCoordIndices[texCoordSet] * ts >= bufferSize) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25"));
+ }
+ } else if (bufferSize < ts*(initialTexCoordIndex[texCoordSet] + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+ // refTexCoordsBuffer contains J3DBuffer object for tex coord
+ refTexCoordsBuffer[texCoordSet] = texCoords;
+ if (texCoords == null) {
+ refTexCoords[texCoordSet] = null;
+ }
+ else {
+ // refTexCoords contains NIOBuffer object for tex coord
+ refTexCoords[texCoordSet] = bufferImpl;
+ }
+ texCoordType = TF;
+ validateTexCoordPointerType();
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+ J3DBuffer getTexCoordRefBuffer(int texCoordSet) {
+ return refTexCoordsBuffer[texCoordSet];
+ }
+
+ void setTexCoordRef2f(int texCoordSet, TexCoord2f[] texCoords) {
+
+ if (texCoordType != 0 && texCoordType != T2F) {
+ if (texCoords != null) {
+ throw new IllegalArgumentException(
+ J3dI18N.getString("GeometryArray98"));
+ }
+ return;
+ }
+
+ if (texCoords != null) {
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) == 0) {
+ throw new IllegalStateException(
+ J3dI18N.getString("GeometryArray94"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxTexCoordIndices[texCoordSet] >= texCoords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25"));
+ }
+ } else if (texCoords.length < (initialTexCoordIndex[texCoordSet] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113"));
+ }
+
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+ refTexCoords[texCoordSet] = texCoords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ texCoordType = T2F;
+ validateTexCoordPointerType();
+ }
+ else {
+ setupMirrorTexCoordPointer(texCoordSet, T2F);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ TexCoord2f[] getTexCoordRef2f(int texCoordSet) {
+ if (refTexCoords != null && refTexCoords[texCoordSet] != null &&
+ refTexCoords[texCoordSet] instanceof TexCoord2f[]) {
+ return ((TexCoord2f[])refTexCoords[texCoordSet]);
+ } else {
+ return null;
+ }
+ }
+
+
+ void setTexCoordRef3f(int texCoordSet, TexCoord3f[] texCoords) {
+
+ if (texCoordType != 0 && texCoordType != T3F) {
+ if (texCoords != null) {
+ throw new IllegalArgumentException(
+ J3dI18N.getString("GeometryArray98"));
+ }
+ return;
+ }
+
+ if (texCoords != null) {
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) == 0) {
+ throw new IllegalStateException(
+ J3dI18N.getString("GeometryArray95"));
+ }
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxTexCoordIndices[texCoordSet] >= texCoords.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray25"));
+ }
+
+ } else if (texCoords.length < (initialTexCoordIndex[texCoordSet] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray113"));
+ }
+
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+ refTexCoords[texCoordSet] = texCoords;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ texCoordType = T3F;
+ validateTexCoordPointerType();
+ }
+ else {
+ setupMirrorTexCoordPointer(texCoordSet, T3F);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+
+ TexCoord3f[] getTexCoordRef3f(int texCoordSet) {
+ if (refTexCoords != null && refTexCoords[texCoordSet] != null &&
+ refTexCoords[texCoordSet] instanceof TexCoord3f[]) {
+ return ((TexCoord3f[])refTexCoords[texCoordSet]);
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Sets the float vertex attribute array reference for the
+ * specified vertex attribute number to the specified array.
+ */
+ void setVertexAttrRefFloat(int vertexAttrNum, float[] vertexAttrs) {
+
+ // XXXX: Add the following test if we ever add double-precision types
+ /*
+ if (vertexAttrType != 0 && vertexAttrType != AF) {
+ if (vertexAttrs != null) {
+ // XXXX: new exception string
+ throw new IllegalArgumentException(
+ J3dI18N.getString("GeometryArray98-XXX"));
+ }
+ return;
+ }
+ */
+
+ if (vertexAttrs != null) {
+ int sz = vertexAttrSizes[vertexAttrNum];
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (sz*idx.maxVertexAttrIndices[vertexAttrNum] >= vertexAttrs.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30"));
+ }
+
+ } else if (vertexAttrs.length < sz*(initialVertexAttrIndex[vertexAttrNum] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray129"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+ floatRefVertexAttrs[vertexAttrNum] = vertexAttrs;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ vertexAttrType = AF;
+ validateVertexAttrPointerType();
+ }
+ else {
+ setupMirrorVertexAttrPointer(vertexAttrNum, AF);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+ }
+
+ /**
+ * Gets the float vertex attribute array reference for the specified
+ * vertex attribute number.
+ */
+ float[] getVertexAttrRefFloat(int vertexAttrNum) {
+ return floatRefVertexAttrs[vertexAttrNum];
+ }
+
+
+ /**
+ * Sets the vertex attribute buffer reference for the specified
+ * vertex attribute number to the specified buffer object.
+ */
+ void setVertexAttrRefBuffer(int vertexAttrNum, J3DBuffer vertexAttrs) {
+
+ FloatBuffer bufferImpl = null;
+
+ if (vertexAttrs != null) {
+ if(vertexAttrs.bufferType != J3DBuffer.Type.FLOAT)
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116"));
+
+ bufferImpl = (FloatBuffer)vertexAttrs.getROBuffer();
+ int bufferSize = bufferImpl.limit();
+
+ assert bufferImpl.isDirect();
+
+ int sz = vertexAttrSizes[vertexAttrNum];
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (idx.maxVertexAttrIndices[vertexAttrNum] * sz >= bufferSize) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray30"));
+ }
+ } else if (bufferSize < sz*(initialVertexAttrIndex[vertexAttrNum] + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray129"));
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+ vertexAttrsRefBuffer[vertexAttrNum] = vertexAttrs;
+ if (vertexAttrs == null) {
+ floatBufferRefVertexAttrs[vertexAttrNum] = null;
+ }
+ else {
+ floatBufferRefVertexAttrs[vertexAttrNum] = bufferImpl;
+ }
+ vertexAttrType = AF;
+ validateVertexAttrPointerType();
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ sendDataChangedMessage(false);
+ }
+
+ }
+
+ /**
+ * Gets the vertex attribute array buffer reference for the specified
+ * vertex attribute number.
+ */
+ J3DBuffer getVertexAttrRefBuffer(int vertexAttrNum) {
+ return vertexAttrsRefBuffer[vertexAttrNum];
+ }
+
+
+ void setInterleavedVertices(float[] vertexData) {
+ if (vertexData != null) {
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (stride * idx.maxCoordIndex >= vertexData.length) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if (stride * idx.maxTexCoordIndices[i] >= vertexData.length) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("IndexedGeometryArray25"));
+ }
+ }
+ }
+
+ if (((this.vertexFormat & GeometryArray.COLOR) != 0) &&
+ (stride * idx.maxColorIndex >= vertexData.length)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+
+ if (((this.vertexFormat & GeometryArray.NORMALS) != 0) &&
+ (stride * idx.maxNormalIndex >= vertexData.length)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray26"));
+ }
+ } else {
+ if (vertexData.length < (stride * (initialVertexIndex+validVertexCount)))
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114"));
+ }
+ }
+
+ // If the geometry has been rendered transparent, then make a copy
+ // of the color pointer with 4f
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VERTEX_CHANGED;
+ colorChanged = 0xffff;
+ interLeavedVertexData = vertexData;
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ setupMirrorInterleavedColorPointer(false);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ processCoordsChanged(vertexData == null);
+ sendDataChangedMessage(true);
+ }
+ }
+
+ // set the interleaved vertex with NIO buffer
+ void setInterleavedVertexBuffer(J3DBuffer vertexData) {
+
+ FloatBuffer bufferImpl = null;
+
+ if (vertexData != null ){
+
+ if (vertexData.bufferType != J3DBuffer.Type.FLOAT)
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray116"));
+
+ bufferImpl = (FloatBuffer)vertexData.getROBuffer();
+
+ assert bufferImpl.isDirect();
+
+ int bufferSize = bufferImpl.limit();
+
+ if (this instanceof IndexedGeometryArrayRetained) {
+ IndexedGeometryArrayRetained idx = (IndexedGeometryArrayRetained)this;
+
+ if (stride * idx.maxCoordIndex >= bufferSize) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+
+ if ((this.vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if (stride * idx.maxTexCoordIndices[i] >= bufferSize) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("IndexedGeometryArray25"));
+ }
+ }
+ }
+
+ if (((this.vertexFormat & GeometryArray.COLOR) != 0) &&
+ (stride * idx.maxColorIndex >= bufferSize)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray24"));
+ }
+
+ if (((this.vertexFormat & GeometryArray.NORMALS) != 0) &&
+ (stride * idx.maxNormalIndex >= bufferSize)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("IndexedGeometryArray23"));
+ }
+ } else {
+ if (bufferSize < (stride * (initialVertexIndex+validVertexCount)))
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114"));
+ }
+ }
+ // If the geometry has been rendered transparent, then make a copy
+ // of the color pointer with 4f
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VERTEX_CHANGED;
+ colorChanged = 0xffff;
+ interleavedVertexBuffer = vertexData;
+
+ if(vertexData == null)
+ interleavedFloatBufferImpl = null;
+ else
+ interleavedFloatBufferImpl = bufferImpl;
+
+ if (inUpdater || (this instanceof IndexedGeometryArrayRetained &&
+ ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0))) {
+ setupMirrorInterleavedColorPointer(false);
+ }
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ processCoordsChanged(vertexData == null);
+ sendDataChangedMessage(true);
+ }
+ }
+
+ float[] getInterleavedVertices() {
+ return interLeavedVertexData;
+ }
+
+ J3DBuffer getInterleavedVertexBuffer() {
+ return interleavedVertexBuffer;
+ }
+
+ void setValidVertexCount(int validVertexCount) {
+
+ boolean nullGeo = false;
+ if (validVertexCount < 0) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray110"));
+ }
+
+ if ((initialVertexIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray100"));
+ }
+
+ if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ // Interleaved, by-ref
+
+ // use nio buffer for interleaved data
+ if(( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 && interleavedFloatBufferImpl != null){
+ if(interleavedFloatBufferImpl.limit() < stride * (initialVertexIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114"));
+ }
+ }
+ //use java array for interleaved data
+ else if( interLeavedVertexData != null) {
+ if(interLeavedVertexData.length < stride * (initialVertexIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114"));
+ }
+ }
+ else {
+ nullGeo = true;
+ }
+ } else if ((vertexFormat & GeometryArray.BY_REFERENCE) != 0) {
+ // Non-interleaved, by-ref
+
+ if ((initialCoordIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray104"));
+ }
+ if ((initialColorIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray101"));
+ }
+ if ((initialNormalIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray102"));
+ }
+
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if ((initialTexCoordIndex[i] + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString(
+ "GeometryArray103"));
+ }
+ }
+ }
+
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ for (int i = 0; i < vertexAttrCount; i++) {
+ if ((initialVertexAttrIndex[i] + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString(
+ "GeometryArray130"));
+ }
+ }
+ }
+
+ if ((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0) {
+ nullGeo = true;
+ }
+
+ if (( vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
+ // by reference with nio buffer
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case PF:
+ if(floatBufferRefCoords.limit() < 3 * (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case PD:
+ if(doubleBufferRefCoords.limit() < 3 * (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ }
+
+ switch ((vertexType & COLOR_DEFINED)) {
+ case CF:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (floatBufferRefColors.limit() < 3 * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (floatBufferRefColors.limit() < 4 * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ case CUB:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (byteBufferRefColors.limit() < 3 * (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (byteBufferRefColors.limit() < 4 * (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ }
+ switch ((vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) {
+ case TF:
+ FloatBuffer texBuffer;
+ for (int i = 0; i < texCoordSetCount; i++) {
+ texBuffer = (FloatBuffer)refTexCoordsBuffer[i].getROBuffer();
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ if (texBuffer.limit() < 2 * (initialTexCoordIndex[i] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ if (texBuffer.limit() < 3 * (initialTexCoordIndex[i] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ if (texBuffer.limit() < 4 * (initialTexCoordIndex[i] + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ }
+ break;
+ }
+ switch ((vertexType & GeometryArrayRetained.NORMAL_DEFINED)) {
+ case NF:
+ if (floatBufferRefNormals.limit() < 3 * (initialNormalIndex + validVertexCount )) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ break;
+ }
+ switch ((vertexType & GeometryArrayRetained.VATTR_DEFINED)) {
+ case AF:
+ for (int i = 0; i < vertexAttrCount; i++) {
+ int sz = vertexAttrSizes[i];
+ if (floatBufferRefVertexAttrs[i].limit() <
+ (sz * (initialVertexAttrIndex[i] + validVertexCount)) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray129"));
+ }
+ }
+ break;
+ }
+ }
+ // By reference with java array
+ else {
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case PF:
+ if (floatRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case PD:
+ if (doubleRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case P3F:
+ if (p3fRefCoords.length < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case P3D:
+ if (p3dRefCoords.length < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ }
+ switch ((vertexType & COLOR_DEFINED)) {
+ case CF:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (floatRefColors.length < 3 * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (floatRefColors.length < 4 * (initialColorIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ case CUB:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (byteRefColors.length < 3 * (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (byteRefColors.length < 4 * (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ case C3F:
+ if (c3fRefColors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ case C4F:
+ if (c4fRefColors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ case C3UB:
+ if (c3bRefColors.length < (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ case C4UB:
+ if (c4bRefColors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ }
+ switch ((vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) {
+ case TF:
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ if (((float[])refTexCoords[i]).length < 2 * (initialTexCoordIndex[i] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ if (((float[])refTexCoords[i]).length < 3 * (initialTexCoordIndex[i] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ if (((float[])refTexCoords[i]).length < 4 * (initialTexCoordIndex[i] + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ }
+ }
+ break;
+ case T2F:
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if (((TexCoord2f[])refTexCoords[i]).length < (initialTexCoordIndex[i] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ break;
+ case T3F:
+ for (int i = 0; i < texCoordSetCount; i++) {
+ if (((TexCoord3f[])refTexCoords[i]).length < (initialTexCoordIndex[i] + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ break;
+ }
+ switch ((vertexType & GeometryArrayRetained.NORMAL_DEFINED)) {
+ case NF:
+ if (floatRefNormals.length < 3 * (initialNormalIndex + validVertexCount )) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ break;
+ case N3F:
+ if (v3fRefNormals.length < (initialNormalIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ }
+ switch ((vertexType & GeometryArrayRetained.VATTR_DEFINED)) {
+ case AF:
+ for (int i = 0; i < vertexAttrCount; i++) {
+ int sz = vertexAttrSizes[i];
+ if (floatRefVertexAttrs[i].length <
+ (sz * (initialVertexAttrIndex[i] + validVertexCount)) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray129"));
+ }
+ }
+ break;
+ }
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VERTEX_CHANGED;
+ this.validVertexCount = validVertexCount;
+
+ if(isLive){
+ geomLock.unLock();
+ }
+
+ if (!inUpdater && isLive) {
+ processCoordsChanged(nullGeo);
+ sendDataChangedMessage(true);
+ }
+ }
+
+
+ int getValidVertexCount() {
+ return validVertexCount;
+ }
+
+ //Used for interleaved data (array or nio buffer)
+ void setInitialVertexIndex(int initialVertexIndex) {
+ boolean nullGeo = false;
+
+ if ((initialVertexIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray100"));
+ }
+
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0 && interleavedFloatBufferImpl != null) {
+ if(interleavedFloatBufferImpl.limit() < stride * (initialVertexIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114"));
+ }
+ }
+ // interleaved data using java array
+ else if(interLeavedVertexData != null) {
+ if (interLeavedVertexData.length < stride * (initialVertexIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray114"));
+ }
+ }
+ else {
+ nullGeo = (vertexFormat & GeometryArray.INTERLEAVED) != 0; // Only for byRef
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VERTEX_CHANGED;
+ this.initialVertexIndex = initialVertexIndex;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ if (!inUpdater && isLive) {
+ processCoordsChanged(nullGeo);
+ sendDataChangedMessage(true);
+ }
+ }
+
+ int getInitialVertexIndex() {
+ return initialVertexIndex;
+ }
+
+ void setInitialCoordIndex(int initialCoordIndex) {
+ if ((initialCoordIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray104"));
+ }
+ // use NIO buffer
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case PF:
+ if(floatBufferRefCoords.limit() < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case PD:
+ if(doubleBufferRefCoords.limit() < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ }
+ } else {
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case PF:
+ if (floatRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case PD:
+ if (doubleRefCoords.length < 3 * (initialCoordIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case P3F:
+ if (p3fRefCoords.length < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ case P3D:
+ if (p3dRefCoords.length < (initialCoordIndex+validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray99"));
+ }
+ break;
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COORDINATE_CHANGED;
+ this.initialCoordIndex = initialCoordIndex;
+ dirtyFlag |= COORDINATE_CHANGED;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ // Send a message, since bounds changed
+ if (!inUpdater && isLive) {
+ processCoordsChanged((vertexType & GeometryArrayRetained.VERTEX_DEFINED) == 0);
+ sendDataChangedMessage(true);
+ }
+ }
+
+ int getInitialCoordIndex() {
+ return initialCoordIndex;
+ }
+
+ void setInitialColorIndex(int initialColorIndex) {
+ if ((initialColorIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray101"));
+ }
+ // NIO BUFFER CASE
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){
+ switch ((vertexType & COLOR_DEFINED)) {
+ case CF:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (floatBufferRefColors.limit() < 3 * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (floatBufferRefColors.limit() < 4 * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+
+ case CUB:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (byteBufferRefColors.limit() < 3 * (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (byteBufferRefColors.limit() < 4 * (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ }
+ }
+ // Java ARRAY CASE
+ else {
+ switch ((vertexType & COLOR_DEFINED)) {
+ case CF:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (floatRefColors.length < 3 * (initialColorIndex+validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (floatRefColors.length < 4 * (initialColorIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ case CUB:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ if (byteRefColors.length < 3 * (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
+ if (byteRefColors.length < 4 * (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ }
+ break;
+ case C3F:
+ if (c3fRefColors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ case C4F:
+ if (c4fRefColors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ case C3UB:
+ if (c3bRefColors.length < (initialColorIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ case C4UB:
+ if (c4bRefColors.length < (initialColorIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray112"));
+ }
+ break;
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= COLOR_CHANGED;
+ colorChanged = 0xffff;
+ this.initialColorIndex = initialColorIndex;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ // There is no need to send message for by reference, since we
+ // use VA
+
+ }
+
+ int getInitialColorIndex() {
+ return initialColorIndex;
+ }
+
+ void setInitialNormalIndex(int initialNormalIndex) {
+ if ((initialNormalIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray102"));
+ }
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){
+ if((vertexType & NORMAL_DEFINED) == NF){
+ if (floatBufferRefNormals.limit() < 3 * (initialNormalIndex + validVertexCount )) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ }
+ } else {
+ switch((vertexType & NORMAL_DEFINED)){
+ case NF:
+ if (floatRefNormals.length < 3 * (initialNormalIndex + validVertexCount )) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ break;
+ case N3F:
+ if (v3fRefNormals.length < (initialNormalIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(J3dI18N.getString("GeometryArray111"));
+ }
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= NORMAL_CHANGED;
+ this.initialNormalIndex = initialNormalIndex;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ // There is no need to send message for by reference, since we
+ // use VA
+ }
+
+ int getInitialNormalIndex() {
+ return initialNormalIndex;
+ }
+
+ /**
+ * Sets the initial vertex attribute index for the specified
+ * vertex attribute number for this GeometryArray object.
+ */
+ void setInitialVertexAttrIndex(int vertexAttrNum,
+ int initialVertexAttrIndex) {
+
+ if ((initialVertexAttrIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray130"));
+ }
+
+ int sz = vertexAttrSizes[vertexAttrNum];
+ int minLength = sz * (initialVertexAttrIndex + validVertexCount);
+ if ((vertexType & VATTR_DEFINED) == AF) {
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0) {
+ if (floatBufferRefVertexAttrs[vertexAttrNum].limit() < minLength) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray129"));
+ }
+ } else {
+ if (floatRefVertexAttrs[vertexAttrNum].length < minLength ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray129"));
+ }
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= VATTR_CHANGED;
+ this.initialVertexAttrIndex[vertexAttrNum] = initialVertexAttrIndex;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ // There is no need to send message for by reference, since we
+ // use VA
+ }
+
+
+ /**
+ * Gets the initial vertex attribute index for the specified
+ * vertex attribute number for this GeometryArray object.
+ */
+ int getInitialVertexAttrIndex(int vertexAttrNum) {
+ return initialVertexAttrIndex[vertexAttrNum];
+ }
+
+ void setInitialTexCoordIndex(int texCoordSet, int initialTexCoordIndex) {
+ if ((initialTexCoordIndex + validVertexCount) > vertexCount) {
+ throw new IllegalArgumentException(J3dI18N.getString("GeometryArray103"));
+ }
+
+ if((vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0){
+ if((vertexType & TEXCOORD_DEFINED) == TF) {
+ FloatBuffer texBuffer = (FloatBuffer)refTexCoordsBuffer[texCoordSet].getROBuffer();
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ if (texBuffer.limit() < 2 * (initialTexCoordIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ if (texBuffer.limit() < 3 * (initialTexCoordIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ if (texBuffer.limit() < 4 * (initialTexCoordIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ }
+ } else {
+ switch ((vertexType & TEXCOORD_DEFINED)) {
+ case TF:
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ if (((float[])refTexCoords[texCoordSet]).length < 2 * (initialTexCoordIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ if (((float[])refTexCoords[texCoordSet]).length < 3 * (initialTexCoordIndex + validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ if (((float[])refTexCoords[texCoordSet]).length < 4 * (initialTexCoordIndex + validVertexCount)) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ }
+ break;
+ case T2F:
+ if (((TexCoord2f[])refTexCoords[texCoordSet]).length < (initialTexCoordIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ break;
+ case T3F:
+ if (((TexCoord3f[])refTexCoords[texCoordSet]).length < (initialTexCoordIndex+ validVertexCount) ) {
+ throw new ArrayIndexOutOfBoundsException(
+ J3dI18N.getString("GeometryArray113"));
+ }
+ break;
+ }
+ }
+ boolean isLive = source!=null && source.isLive();
+ if(isLive){
+ geomLock.getLock();
+ }
+ dirtyFlag |= TEXTURE_CHANGED;
+ this.initialTexCoordIndex[texCoordSet] = initialTexCoordIndex;
+ if(isLive) {
+ geomLock.unLock();
+ }
+ // There is no need to send message for by reference, since we
+ // use VA
+ }
+
+ int getInitialTexCoordIndex(int texCoordSet) {
+ return initialTexCoordIndex[texCoordSet];
+ }
+
+
+ int getTexCoordSetCount() {
+ return this.texCoordSetCount;
+ }
+
+ int getTexCoordSetMapLength() {
+ if (this.texCoordSetMap != null)
+ return this.texCoordSetMap.length;
+ else
+ return 0;
+ }
+
+ void getTexCoordSetMap(int [] texCoordSetMap) {
+
+ if (this.texCoordSetMap!=null) {
+ for (int i = 0; i < this.texCoordSetMap.length; i++) {
+ texCoordSetMap[i] = this.texCoordSetMap[i];
+ }
+ }
+ }
+
+ void freeDlistId() {
+ if (dlistId != -1) {
+ VirtualUniverse.mc.freeDisplayListId(dlistObj);
+ dlistId = -1;
+ }
+ }
+
+ void assignDlistId() {
+ if (dlistId == -1) {
+ dlistObj = VirtualUniverse.mc.getDisplayListId();
+ dlistId = dlistObj.intValue();
+ }
+ }
+
+// Add the specified render atom as a user of this geometry array
+// (for the specified render bin)
+void addDlistUser(RenderBin renderBin, RenderAtomListInfo ra) {
+ if (dlistUsers == null)
+ dlistUsers = new HashMap<RenderBin, HashSet<RenderAtomListInfo>>(2, 1.0f);
+
+ HashSet<RenderAtomListInfo> raSet = dlistUsers.get(renderBin);
+ if (raSet == null) {
+ raSet = new HashSet<RenderAtomListInfo>();
+ dlistUsers.put(renderBin, raSet);
+ }
+ raSet.add(ra);
+}
+
+// Remove the specified render atom from the set of users of this
+// geometry array (for the specified render bin)
+void removeDlistUser(RenderBin renderBin, RenderAtomListInfo ra) {
+ if (dlistUsers == null)
+ return;
+
+ HashSet<RenderAtomListInfo> raSet = dlistUsers.get(renderBin);
+ if (raSet == null)
+ return;
+
+ raSet.remove(ra);
+}
+
+// Returns true if the set of render atoms using this geometry
+// array in the specified render bin is empty.
+boolean isDlistUserSetEmpty(RenderBin renderBin) {
+ if (dlistUsers == null)
+ return true;
+
+ HashSet<RenderAtomListInfo> raSet = dlistUsers.get(renderBin);
+ if (raSet == null) {
+ return true;
+ }
+ return raSet.isEmpty();
+}
+
+// This method is used for debugging only
+int numDlistUsers(RenderBin renderBin) {
+ if (isDlistUserSetEmpty(renderBin))
+ return 0;
+
+ HashSet<RenderAtomListInfo> raSet = dlistUsers.get(renderBin);
+ return raSet.size();
+}
+
+ void setDlistTimeStamp(int rdrBit, long timeStamp) {
+ int index = getIndex(rdrBit);
+ if (index >= timeStampPerDlist.length) {
+ long[] newList = new long[index * 2];
+ for (int i = 0; i < timeStampPerDlist.length; i++) {
+ newList[i] = timeStampPerDlist[i];
+ }
+ timeStampPerDlist = newList;
+ }
+ timeStampPerDlist[index] = timeStamp;
+ }
+
+ long getDlistTimeStamp(int rdrBit) {
+ int index = getIndex(rdrBit);
+ // If index is greater than what currently exists, increase
+ // the array and return zero
+ if (index >= timeStampPerDlist.length) {
+ setDlistTimeStamp(rdrBit, 0);
+ }
+ return timeStampPerDlist[index];
+ }
+
+ int getIndex(int bit) {
+ int num = 0;
+
+ while (bit > 0) {
+ num++;
+ bit >>= 1;
+ }
+ return num;
+ }
+
+
+ boolean isWriteStatic() {
+
+ if (source.getCapability(GeometryArray.ALLOW_COORDINATE_WRITE ) ||
+ source.getCapability(GeometryArray.ALLOW_COLOR_WRITE) ||
+ source.getCapability(GeometryArray.ALLOW_NORMAL_WRITE) ||
+ source.getCapability(GeometryArray.ALLOW_TEXCOORD_WRITE) ||
+ source.getCapability(GeometryArray.ALLOW_VERTEX_ATTR_WRITE) ||
+ source.getCapability(GeometryArray.ALLOW_COUNT_WRITE) ||
+ source.getCapability(GeometryArray.ALLOW_REF_DATA_WRITE))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * The functions below are only used in compile mode
+ */
+ void setCompiled(ArrayList curList) {
+ int i;
+ int num = curList.size();
+ int offset = 0;
+ geoOffset = new int[num];
+ compileVcount = new int[num];
+ int vcount = 0, vformat = 0;
+ vcount = 0;
+ isCompiled = true;
+
+ if (num > 0)
+ source = ((SceneGraphObjectRetained)curList.get(0)).source;
+ for (i = 0; i < num; i++) {
+ // Build the back mapping
+ GeometryArrayRetained geo = (GeometryArrayRetained)curList.get(i);
+ ((GeometryArray)geo.source).retained = this;
+ compileVcount[i] = geo.getValidVertexCount();
+ vcount += geo.getValidVertexCount();
+ geoOffset[i] = offset;
+ offset += geo.stride() * compileVcount[i];
+ vformat = geo.getVertexFormat();
+ }
+ createGeometryArrayData(vcount, vformat);
+
+ // Assign the initial and valid fields
+ validVertexCount = vcount;
+ initialVertexIndex = 0;
+
+ mergeGeometryArrays(curList);
+
+ }
+
+ /*
+ // Ununsed
+ int getVertexCount(int index) {
+ return compileVcount[index];
+ }
+
+
+ int getValidVertexCount(int index) {
+ return compileVcount[index];
+ }
+
+
+ int getInitialVertexIndex(int index) {
+ return 0;
+ }
+ */
+
+ void mergeGeometryArrays(ArrayList list) {
+ float[] curVertexData;
+ int length, srcOffset;
+ int curOffset = 0;
+ // We only merge if the texCoordSetCount is 1 and there are no
+ // vertex attrs
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
+ texCoordSetCount = 1;
+ texCoordSetMap = new int[1];
+ texCoordSetMap[0] = 1;
+ }
+ for (int i = 0; i < list.size(); i++) {
+ GeometryArrayRetained geo = (GeometryArrayRetained)list.get(i);
+ // Take into account the validVertexCount and initialVertexIndex
+ curVertexData = geo.vertexData;
+ length = geo.validVertexCount * stride;
+ srcOffset = geo.initialVertexIndex * stride;
+ System.arraycopy(curVertexData, srcOffset, this.vertexData, curOffset,
+ length);
+ curOffset += length;
+
+ // assign geoBounds
+ geoBounds.combine(geo.geoBounds);
+
+ }
+ geoBounds.getCenter(this.centroid);
+ }
+
+ boolean isMergeable() {
+
+ // For now, turn off by ref geometry
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) != 0)
+ return false;
+
+ if (!isStatic())
+ return false;
+
+ // If there is more than one set of texture coordinate set defined
+ // then don't merge geometry (we avoid dealing with texCoordSetMap
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0 &&
+ (texCoordSetCount > 1 ||
+ texCoordSetMap != null && texCoordSetMap.length > 1)) {
+ return false;
+ }
+
+ // We will avoid merging geometry if there are any vertex attributes.
+ if ((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
+ return false;
+ }
+
+ // If intersect is allowed turn off merging
+ if (source.getCapability(Geometry.ALLOW_INTERSECT))
+ return false;
+
+ return true;
+ }
+
+ @Override
+ void compile(CompileState compState) {
+ super.compile(compState);
+
+ if ((vertexFormat & GeometryArray.NORMALS) != 0) {
+ compState.needNormalsTransform = true;
+ }
+ }
+
+ @Override
+ void mergeTransform(TransformGroupRetained xform) {
+ if (geoBounds != null) {
+ geoBounds.transform(xform.transform);
+ }
+ }
+
+ // This adds a MorphRetained to the list of users of this geometry
+ void addMorphUser(MorphRetained m) {
+ int index;
+
+ if(morphUniverseList == null) {
+ morphUniverseList = new ArrayList<VirtualUniverse>(1);
+ morphUserLists = new ArrayList<ArrayList<MorphRetained>>(1);
+ }
+ synchronized (morphUniverseList) {
+ if (morphUniverseList.contains(m.universe)) {
+ index = morphUniverseList.indexOf(m.universe);
+ morphUserLists.get(index).add(m);
+ } else {
+ morphUniverseList.add(m.universe);
+ ArrayList<MorphRetained> morphList = new ArrayList<MorphRetained>(5);
+ morphList.add(m);
+ morphUserLists.add(morphList);
+ }
+ }
+ }
+
+ // This adds a MorphRetained to the list of users of this geometry
+ void removeMorphUser(MorphRetained m) {
+ int index;
+
+ if(morphUniverseList == null)
+ return;
+
+ synchronized (morphUniverseList) {
+ index = morphUniverseList.indexOf(m.universe);
+ ArrayList<MorphRetained> morphList = morphUserLists.get(index);
+ morphList.remove(morphList.indexOf(m));
+ if (morphList.size() == 0) {
+ morphUserLists.remove(index);
+ morphUniverseList.remove(index);
+ }
+ }
+ }
+ // Initialize mirror object when geometry is first setLived
+ void initMirrorGeometry() {
+ geomLock.getLock();
+ if (this instanceof IndexedGeometryArrayRetained) {
+ if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) {
+ mirrorGeometry =
+ ((IndexedGeometryArrayRetained)this).cloneNonIndexedGeometry();
+ }
+ else {
+ mirrorGeometry = null;
+ }
+ }
+ geomLock.unLock();
+
+ }
+
+ // Update Mirror Object in response to change in geometry
+ void updateMirrorGeometry() {
+ geomLock.getLock();
+ if (this instanceof IndexedGeometryArrayRetained) {
+ if (mirrorGeometry != null) {
+ mirrorGeometry =
+ ((IndexedGeometryArrayRetained)this).cloneNonIndexedGeometry();
+ }
+ }
+ geomLock.unLock();
+
+ }
+
+
+ // Used by the picking intersect routines
+ void getVertexData(int i, Point3d pnts) {
+ int offset;
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ offset = stride * i + coordinateOffset;
+ pnts.x = this.vertexData[offset];
+ pnts.y = this.vertexData[offset+1];
+ pnts.z = this.vertexData[offset+2];
+ return;
+ }
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0 ) {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ offset = stride * i + coordinateOffset;
+ pnts.x = this.interLeavedVertexData[offset];
+ pnts.y = this.interLeavedVertexData[offset+1];
+ pnts.z = this.interLeavedVertexData[offset+2];
+ }
+ else {
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case GeometryArrayRetained.PF:
+ offset = i*3;
+ pnts.x = this.floatRefCoords[offset];
+ pnts.y = this.floatRefCoords[offset+1];
+ pnts.z = this.floatRefCoords[offset+2];
+ break;
+ case GeometryArrayRetained.PD:
+ offset = i*3;
+ pnts.x = this.doubleRefCoords[offset];
+ pnts.y = this.doubleRefCoords[offset+1];
+ pnts.z = this.doubleRefCoords[offset+2];
+ break;
+ case GeometryArrayRetained.P3F:
+ pnts.x = this.p3fRefCoords[i].x;
+ pnts.y = this.p3fRefCoords[i].y;
+ pnts.z = this.p3fRefCoords[i].z;
+ break;
+ case GeometryArrayRetained.P3D:
+ pnts.x = this.p3dRefCoords[i].x;
+ pnts.y = this.p3dRefCoords[i].y;
+ pnts.z = this.p3dRefCoords[i].z;
+ break;
+ }
+ }
+ }// end of non nio buffer
+ else { // NIO BUFFER
+ if ((vertexFormat & GeometryArray.INTERLEAVED) != 0) {
+ offset = stride * i + coordinateOffset;
+ pnts.x = this.interleavedFloatBufferImpl.get(offset);
+ pnts.y = this.interleavedFloatBufferImpl.get(offset+1);
+ pnts.z = this.interleavedFloatBufferImpl.get(offset+2);
+ }
+ else {
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case GeometryArrayRetained.PF:
+ offset = i*3;
+ pnts.x = this.floatBufferRefCoords.get(offset);
+ pnts.y = this.floatBufferRefCoords.get(offset+1);
+ pnts.z = this.floatBufferRefCoords.get(offset+2);
+ break;
+ case GeometryArrayRetained.PD:
+ offset = i*3;
+ pnts.x = this.doubleBufferRefCoords.get(offset);
+ pnts.y = this.doubleBufferRefCoords.get(offset+1);
+ pnts.z = this.doubleBufferRefCoords.get(offset+2);
+ break;
+ }
+ }
+ } // end of nio buffer
+ }
+
+ void getCrossValue(Point3d p1, Point3d p2, Vector3d value) {
+ value.x += p1.y*p2.z - p1.z*p2.y;
+ value.y += p2.x*p1.z - p2.z*p1.x;
+ value.z += p1.x*p2.y - p1.y*p2.x;
+ }
+
+
+ @Override
+ boolean intersect(Transform3D thisLocalToVworld,
+ Transform3D otherLocalToVworld, GeometryRetained geom) {
+
+ Transform3D t3d = new Transform3D();
+ boolean isIntersect = false;
+
+ if (geom instanceof GeometryArrayRetained ) {
+ GeometryArrayRetained geomArray = (GeometryArrayRetained) geom;
+
+ if (geomArray.validVertexCount >= validVertexCount) {
+ t3d.invert(otherLocalToVworld);
+ t3d.mul(thisLocalToVworld);
+ isIntersect = intersect(t3d, geom);
+ } else {
+ t3d.invert(thisLocalToVworld);
+ t3d.mul(otherLocalToVworld);
+ isIntersect = geomArray.intersect(t3d, this);
+ }
+ } else {
+ t3d.invert(thisLocalToVworld);
+ t3d.mul(otherLocalToVworld);
+ isIntersect = geom.intersect(t3d, this);
+ }
+ return isIntersect;
+ }
+
+ int getNumCoordCount() {
+ int count = 0;
+ if ((vertexFormat & GeometryArray.COORDINATES) != 0){
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){
+ count = vertexCount;
+ return count;
+ }
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case PF:
+ count = floatRefCoords.length/3;
+ break;
+ case PD:
+ count = doubleRefCoords.length/3;
+ break;
+ case P3F:
+ count = p3fRefCoords.length;
+ break;
+ case P3D:
+ count = p3dRefCoords.length;
+ break;
+ }
+ }
+ else {
+ count = interLeavedVertexData.length/stride;
+ }
+ }
+ else { // nio buffer
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ switch ((vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
+ case PF:
+ count = floatBufferRefCoords.limit()/3; // XXXX: limit or capacity?
+ break;
+ case PD:
+ count = doubleBufferRefCoords.limit()/3;
+ break;
+ }
+ }
+ else {
+ count = interleavedFloatBufferImpl.limit()/stride;
+ }
+ }
+ }
+ return count;
+ }
+
+ int getNumColorCount() {
+ int count = 0;
+ if ((vertexFormat & GeometryArray.COLOR) != 0){
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){
+ count = vertexCount;
+ return count;
+ }
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ switch ((vertexType & GeometryArrayRetained.COLOR_DEFINED)) {
+ case CF:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ count = floatRefColors.length/3;
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){
+ count = floatRefColors.length/4;
+ }
+ break;
+ case CUB:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ count = byteRefColors.length/3;
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){
+ count = byteRefColors.length/4;
+ }
+ break;
+ case C3F:
+ count = c3fRefColors.length;
+ break;
+ case C4F:
+ count = c4fRefColors.length;
+ break;
+ case C3UB:
+ count = c3bRefColors.length;
+ break;
+ case C4UB:
+ count = c4bRefColors.length;
+ break;
+ }
+ }
+ else {
+ count = interLeavedVertexData.length/stride;
+ }
+ } // end of non nio buffer
+ else {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ switch ((vertexType & GeometryArrayRetained.COLOR_DEFINED)) {
+ case CF:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ count = floatBufferRefColors.limit()/3;
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){
+ count = floatBufferRefColors.limit()/4;
+ }
+ break;
+ case CUB:
+ if ((vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
+ count = byteBufferRefColors.limit()/3;
+ }
+ else if ((vertexFormat & GeometryArray.COLOR_4)== GeometryArray.COLOR_4){
+ count = byteBufferRefColors.limit()/4;
+ }
+ break;
+ }
+ }
+ else {
+ count = interleavedFloatBufferImpl.limit()/stride;
+ }
+ } // end of nio buffer
+ }
+ return count;
+ }
+
+ int getNumNormalCount() {
+ int count = 0;
+ if ((vertexFormat & GeometryArray.NORMALS) != 0){
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){
+ count = vertexCount;
+ return count;
+ }
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ switch ((vertexType & NORMAL_DEFINED)) {
+ case NF:
+ count = floatRefNormals.length/3;
+ break;
+ case N3F:
+ count = v3fRefNormals.length;
+ break;
+ }
+ }
+ else {
+ count = interLeavedVertexData.length/stride;
+ }
+ } // end of non nio buffer
+ else {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ if ((vertexType & NORMAL_DEFINED) == NF ) {
+ count = floatBufferRefNormals.limit()/3;
+ }
+ }
+ else {
+ count = interleavedFloatBufferImpl.limit()/stride;
+ }
+ }
+ }
+ return count;
+ }
+
+ int getNumTexCoordCount(int i) {
+ int count = 0;
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0){
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0){
+ count = vertexCount;
+ return count;
+ }
+
+ if ((vertexFormat & GeometryArray.USE_NIO_BUFFER) == 0) {
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ switch ((vertexType & TEXCOORD_DEFINED)) {
+ case TF:
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ count = ((float[])refTexCoords[i]).length/2;
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ count = ((float[])refTexCoords[i]).length/3;
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ count = ((float[])refTexCoords[i]).length/4;
+ }
+
+ break;
+ case T2F:
+ count = ((TexCoord2f[])refTexCoords[i]).length;
+ break;
+ case T3F:
+ count = ((TexCoord3f[])refTexCoords[i]).length;
+ }
+ }
+ else {
+ count = interLeavedVertexData.length/stride;
+ }
+ }
+ else { // nio buffer
+ if ((vertexFormat & GeometryArray.INTERLEAVED) == 0){
+ if ((vertexType & TEXCOORD_DEFINED) == TF) {
+ FloatBuffer texBuffer = (FloatBuffer)refTexCoordsBuffer[i].getROBuffer();
+ if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
+ count = texBuffer.limit()/2;
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
+ count = texBuffer.limit()/3;
+ } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
+ count = texBuffer.limit()/4;
+ }
+ }
+ }
+ else {
+ count = interleavedFloatBufferImpl.limit()/stride;
+ }
+ }
+ }
+ return count;
+ }
+
+ // NOTE: we don't need a getNumVertexAttrCount method, since getNum*Count
+ // is only called by Morph, which doesn't support vertex attrs
+
+
+ // Found the min distance from center to the point/line/tri/quad
+ // form by dist[]
+ void computeMinDistance(Point3d coordinates[], Point3d center,
+ Vector3d normal,
+ double dist[], Point3d iPnt) {
+ double x, y, z;
+ int i, j;
+
+ if (coordinates.length == 1) {
+ // a point
+ iPnt.x = coordinates[0].x;
+ iPnt.y = coordinates[0].y;
+ iPnt.z = coordinates[0].z;
+ x = iPnt.x - center.x;
+ y = iPnt.y - center.y;
+ z = iPnt.z - center.z;
+ dist[0] = Math.sqrt(x*x + y*y + z*z);
+ return;
+ }
+
+
+ if (coordinates.length == 2) {
+ // a line
+ dist[0] = Math.sqrt(Utils.ptToSegSquare(center, coordinates[0], coordinates[1], iPnt));
+ return;
+ }
+
+ double normalLen = 0;
+
+ if (normal == null) {
+ Vector3d vec0 = new Vector3d();
+ Vector3d vec1 = new Vector3d();
+ normal = new Vector3d();
+ // compute plane normal for coordinates.
+ for (i=0; i<coordinates.length-1;) {
+ vec0.x = coordinates[i+1].x - coordinates[i].x;
+ vec0.y = coordinates[i+1].y - coordinates[i].y;
+ vec0.z = coordinates[i+1].z - coordinates[i++].z;
+ if(vec0.length() > 0.0)
+ break;
+ }
+
+ for (j=i; j<coordinates.length-1; j++) {
+ vec1.x = coordinates[j+1].x - coordinates[j].x;
+ vec1.y = coordinates[j+1].y - coordinates[j].y;
+ vec1.z = coordinates[j+1].z - coordinates[j].z;
+ if(vec1.length() > 0.0)
+ break;
+ }
+
+ if (j == (coordinates.length-1)) {
+ // Degenerate polygon, check with edge only
+ normal = null;
+ } else {
+ normal.cross(vec0,vec1);
+ }
+ }
+
+ if (normal != null) {
+ normalLen = normal.length();
+ if ( normalLen == 0.0) {
+ // Degenerate polygon, check with edge only
+ normal = null;
+ }
+ }
+
+
+ if (coordinates.length == 3) {
+ // a triangle
+ if (normal != null) {
+ double d = -(normal.x*coordinates[0].x +
+ normal.y*coordinates[0].y +
+ normal.z*coordinates[0].z);
+ dist[0] = (normal.x*center.x + normal.y*center.y +
+ normal.z*center.z +
+ d)/normalLen;
+ iPnt.x = center.x - dist[0]*normal.x/normalLen;
+ iPnt.y = center.y - dist[0]*normal.y/normalLen;
+ iPnt.z = center.z - dist[0]*normal.z/normalLen;
+
+ if (pointInTri(iPnt, coordinates[0], coordinates[1],
+ coordinates[2], normal)) {
+ return;
+ }
+ }
+
+ // checking point to line distance
+ double minDist;
+ Point3d minPnt = new Point3d();
+
+ dist[0] = Utils.ptToSegSquare(center, coordinates[0], coordinates[1], iPnt);
+ minDist = Utils.ptToSegSquare(center, coordinates[1], coordinates[2], minPnt);
+ if (minDist < dist[0]) {
+ dist[0] = minDist;
+ iPnt.x = minPnt.x;
+ iPnt.y = minPnt.y;
+ iPnt.z = minPnt.z;
+ }
+ minDist = Utils.ptToSegSquare(center, coordinates[2], coordinates[0], minPnt);
+ if (minDist < dist[0]) {
+ dist[0] = minDist;
+ iPnt.x = minPnt.x;
+ iPnt.y = minPnt.y;
+ iPnt.z = minPnt.z;
+ }
+ dist[0] = Math.sqrt(dist[0]);
+ return;
+ }
+
+ // a quad
+ if (normal != null) {
+ double d = -(normal.x*coordinates[0].x +
+ normal.y*coordinates[0].y +
+ normal.z*coordinates[0].z);
+ dist[0] = (normal.x*center.x + normal.y*center.y +
+ normal.z*center.z +
+ d)/normalLen;
+ iPnt.x = center.x - dist[0]*normal.x/normalLen;
+ iPnt.y = center.y - dist[0]*normal.y/normalLen;
+ iPnt.z = center.z - dist[0]*normal.z/normalLen;
+
+ if (pointInTri(iPnt, coordinates[0], coordinates[1],
+ coordinates[2], normal) ||
+ pointInTri(iPnt, coordinates[1], coordinates[2],
+ coordinates[3], normal)) {
+ return;
+ }
+ }
+
+ // checking point to line distance
+ double minDist;
+ Point3d minPnt = new Point3d();
+
+ dist[0] = Utils.ptToSegSquare(center, coordinates[0], coordinates[1], iPnt);
+ minDist = Utils.ptToSegSquare(center, coordinates[1], coordinates[2], minPnt);
+ if (minDist < dist[0]) {
+ dist[0] = minDist;
+ iPnt.x = minPnt.x;
+ iPnt.y = minPnt.y;
+ iPnt.z = minPnt.z;
+ }
+ minDist = Utils.ptToSegSquare(center, coordinates[2], coordinates[3], minPnt);
+ if (minDist < dist[0]) {
+ dist[0] = minDist;
+ iPnt.x = minPnt.x;
+ iPnt.y = minPnt.y;
+ iPnt.z = minPnt.z;
+ }
+
+ minDist = Utils.ptToSegSquare(center, coordinates[3], coordinates[0], minPnt);
+ if (minDist < dist[0]) {
+ dist[0] = minDist;
+ iPnt.x = minPnt.x;
+ iPnt.y = minPnt.y;
+ iPnt.z = minPnt.z;
+ }
+
+ dist[0] = Math.sqrt(dist[0]);
+ }
+
+ @Override
+ void handleFrequencyChange(int bit) {
+ int mask = 0;
+ if ((vertexFormat & GeometryArray.BY_REFERENCE) == 0) {
+ if ((bit == GeometryArray.ALLOW_COORDINATE_WRITE) ||
+ (((vertexFormat & GeometryArray.COLOR) != 0) &&
+ bit == GeometryArray.ALLOW_COLOR_WRITE)||
+ (((vertexFormat & GeometryArray.NORMALS) != 0) &&
+ bit == GeometryArray.ALLOW_NORMAL_WRITE) ||
+ (((vertexFormat & GeometryArray.TEXTURE_COORDINATE) != 0) &&
+ bit == GeometryArray.ALLOW_TEXCOORD_WRITE) ||
+ (((vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) &&
+ bit == GeometryArray.ALLOW_VERTEX_ATTR_WRITE) ||
+ (bit == GeometryArray.ALLOW_COUNT_WRITE)) {
+ mask = 1;
+ }
+ }
+ else {
+ if (bit == GeometryArray.ALLOW_REF_DATA_WRITE)
+ mask = 1;
+ }
+ if (mask != 0) {
+ setFrequencyChangeMask(bit, mask);
+ }
+ }
+
+ int getTexCoordType() {
+ return texCoordType;
+ }
+
+ int getVertexAttrType() {
+ return vertexAttrType;
+ }
+
+}