/* * 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 gaList = new ArrayList(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> 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 morphUniverseList = null; // A list of ArrayLists which contain all the MorphRetained objects // refering to this geometry. Each list corresponds to the universe // above. ArrayList> 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 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 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 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 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 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 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 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 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 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= 0.0; /* System.err.println("updateAlphaInFloatRefColors ** : lastAlpha[screen] " + lastAlpha[screen]); System.err.println("((colorChanged & (1<= 0.0; /* System.err.println("updateAlphaInByteRefColors ## : lastAlpha[screen] " + lastAlpha[screen]); System.err.println("((colorChanged & (1< 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<= 0.0; if ((colorChanged & (1<= 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 * vertexAttrCount 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 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 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 start for length vertices. * @param index the vertex index * @param coordinates an array of vectors containing new coordinates * @param start starting vertex index of data in coordinates . * @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 start for length 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 coordinates . * @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 start for length vertices. * @param index the vertex index * @param coordinates an array of vectors containing new coordinates * @param start starting vertex index of data in coordinates . * @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 start for length vertices. * @param index the vertex index * @param coordinates an array of vectors containing new coordinates * @param start starting vertex index of data in coordinates . * @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 colors * starting at index start for length 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 colors. * @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 colors * starting at index start for length 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 colors. * @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 colors * starting at index start for length 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 colors. * @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 colors * starting at index start for length 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 colors. * @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 colors * starting at index start for length 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 colors. * @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 colors * starting at index start for length 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 colors. * @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 normals * starting at index start and ending at index start+length. * @param index the vertex index * @param normals the new normals * @param start starting normal index of data in colors . * @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 normals * starting at index start and ending at index start+length. * @param index the vertex index * @param normals the new normals * @param start starting normal index of data in colors . * @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 texCoords * starting at index start and ending at index start+length. * @param index the vertex index * @param texCoords the new texture coordinates * @param start starting texture coordinate index of data in texCoords . * @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 texCoords * starting at index start and ending at index start+length. * @param index the vertex index * @param texCoords the new texture coordinates * @param start starting texture coordinate index of data in texCoords . * @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 texCoords * starting at index start and ending at index start+length. * @param index the vertex index * @param texCoords the new texture coordinates * @param start starting texture coordinate index of data in texCoords . * @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 texCoords * starting at index start and ending at index start+length. * @param index the vertex index * @param texCoords the new texture coordinates * @param start starting texture coordinate index of data in texCoords . * @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 texCoords * starting at index start and ending at index start+length. * @param index the vertex index * @param texCoords the new texture coordinates * @param start starting texture coordinate index of data in texCoords . * @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 texCoords * starting at index start and ending at index start+length. * @param index the vertex index * @param texCoords the new texture coordinates * @param start starting texture coordinate index of data in texCoords . * @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 * vertexAttrs starting at index start and * ending at index start+length. * * @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 vertexAttrs * 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 * vertexAttrs starting at index start and * ending at index start+length. * * @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 vertexAttrs * 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 * vertexAttrs starting at index start and * ending at index start+length. * * @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 vertexAttrs * 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 * vertexAttrs starting at index start and * ending at index start+length. * * @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 vertexAttrs * 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= 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 0.0) break; } for(j=i; j 0.0) break; } if(j == (coordinates.length-1)) { // System.err.println("(1) Degenerate polygon."); return false; // Degenerate polygon. } /* for(i=0; i 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; i0.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 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) 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)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)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 0.0) break; } for(j=i; j 0.0) break; } if(j == (coord1.length-1)) { // System.err.println("(1) Degenerate polygon."); return false; // Degenerate polygon. } /* for(i=0; i1) { 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 0.0) { break; } } for (j=l; j 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 -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 -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 -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 0.0) break; } for(j=i; j 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 (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 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= 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>(2, 1.0f); HashSet raSet = dlistUsers.get(renderBin); if (raSet == null) { raSet = new HashSet(); 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 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 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 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(1); morphUserLists = new ArrayList>(1); } synchronized (morphUniverseList) { if (morphUniverseList.contains(m.universe)) { index = morphUniverseList.indexOf(m.universe); morphUserLists.get(index).add(m); } else { morphUniverseList.add(m.universe); ArrayList morphList = new ArrayList(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 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 0.0) break; } for (j=i; j 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; } }