diff --git a/engine/src/core/com/jme3/math/Spline.java b/engine/src/core/com/jme3/math/Spline.java index d08d4f7f3..5ded475f6 100644 --- a/engine/src/core/com/jme3/math/Spline.java +++ b/engine/src/core/com/jme3/math/Spline.java @@ -22,12 +22,12 @@ import com.jme3.export.Savable; public class Spline implements Savable { public enum SplineType { - Linear, CatmullRom, Bezier, Nurb } + private List controlPoints = new ArrayList(); private List knots; //knots of NURBS spline private float[] weights; //weights of NURBS spline diff --git a/engine/src/core/com/jme3/scene/Mesh.java b/engine/src/core/com/jme3/scene/Mesh.java index f5b3e0f29..fa03116b2 100644 --- a/engine/src/core/com/jme3/scene/Mesh.java +++ b/engine/src/core/com/jme3/scene/Mesh.java @@ -94,14 +94,14 @@ public class Mesh implements Savable, Cloneable { * A primitive is a single point in space. The size of the points * can be specified with {@link Mesh#setPointSize(float) }. */ - Points, + Points(true), /** * A primitive is a line segment. Every two vertices specify * a single line. {@link Mesh#setLineWidth(float) } can be used * to set the width of the lines. */ - Lines, + Lines(true), /** * A primitive is a line segment. The first two vertices specify @@ -109,7 +109,7 @@ public class Mesh implements Savable, Cloneable { * previous vertex to make a line. {@link Mesh#setLineWidth(float) } can * be used to set the width of the lines. */ - LineStrip, + LineStrip(false), /** * Identical to {@link #LineStrip} except that at the end @@ -117,27 +117,27 @@ public class Mesh implements Savable, Cloneable { * {@link Mesh#setLineWidth(float) } can be used * to set the width of the lines. */ - LineLoop, + LineLoop(false), /** * A primitive is a triangle. Each 3 vertices specify a single * triangle. */ - Triangles, + Triangles(true), /** * Similar to {@link #Triangles}, the first 3 vertices * specify a triangle, while subsequent vertices are combined with * the previous two to form a triangle. */ - TriangleStrip, + TriangleStrip(false), /** * Similar to {@link #Triangles}, the first 3 vertices * specify a triangle, each 2 subsequent vertices are combined * with the very first vertex to make a triangle. */ - TriangleFan, + TriangleFan(false), /** * A combination of various triangle modes. It is best to avoid @@ -146,7 +146,26 @@ public class Mesh implements Savable, Cloneable { * {@link Mesh#setElementLengths(int[]) element lengths} must * be specified for this mode. */ - Hybrid; + Hybrid(false); + + private boolean listMode = false; + + private Mode(boolean listMode){ + this.listMode = listMode; + } + + /** + * Returns true if the specified mode is a list mode (meaning + * ,it specifies the indices as a linear list and not some special + * format). + * Will return true for the types {@link #Points}, {@link #Lines} and + * {@link #Triangles}. + * + * @return true if the mode is a list type mode + */ + public boolean isListMode(){ + return listMode; + } } /** @@ -691,31 +710,44 @@ public class Mesh implements Savable, Cloneable { } /** - * Returns how many triangles are on this Mesh. + * Returns how many triangles or elements are on this Mesh. * This value is only updated when {@link #updateCounts() } is called. + * If the mesh mode is not a triangle mode, then this returns the + * number of elements/primitives, e.g. how many lines or how many points, + * instead of how many triangles. * - * @return how many triangles are on this Mesh. + * @return how many triangles/elements are on this Mesh. */ public int getTriangleCount(){ return elementCount; } - + /** + * Returns the number of vertices on this mesh. + * The value is computed based on the position buffer, which + * must be set on all meshes. + * + * @return Number of vertices on the mesh + */ public int getVertexCount(){ return vertCount; } + /** + * Gets the triangle vertex positions at the given triangle index + * and stores them into the v1, v2, v3 arguments. + * + * @param index The index of the triangle. + * Should be between 0 and {@link #getTriangleCount()}. + * + * @param v1 Vector to contain first vertex position + * @param v2 Vector to contain second vertex position + * @param v3 Vector to contain third vertex position + */ public void getTriangle(int index, Vector3f v1, Vector3f v2, Vector3f v3){ VertexBuffer pb = getBuffer(Type.Position); - - IndexBuffer ib = getIndexBuffer(); - if (ib == null){ - ib = new VirtualIndexBuffer(vertCount, mode); - }else if (mode != Mode.Triangles){ - ib = new WrappedIndexBuffer(this); - } - - if (pb.getFormat() == Format.Float){ + IndexBuffer ib = getIndicesAsList(); + if (pb != null && pb.getFormat() == Format.Float && pb.getNumComponents() == 3){ FloatBuffer fpb = (FloatBuffer) pb.getData(); // aquire triangle's vertex indices @@ -727,33 +759,56 @@ public class Mesh implements Savable, Cloneable { BufferUtils.populateFromBuffer(v1, fpb, vert1); BufferUtils.populateFromBuffer(v2, fpb, vert2); BufferUtils.populateFromBuffer(v3, fpb, vert3); - + }else{ + throw new UnsupportedOperationException("Position buffer not set or " + + " has incompatible format"); } } + /** + * Gets the triangle vertex positions at the given triangle index + * and stores them into the {@link Triangle} argument. + * Also sets the triangle index to the index argument. + * + * @param index The index of the triangle. + * Should be between 0 and {@link #getTriangleCount()}. + * + * @param tri The triangle to store the positions in + */ public void getTriangle(int index, Triangle tri){ getTriangle(index, tri.get1(), tri.get2(), tri.get3()); tri.setIndex(index); } + /** + * Gets the triangle vertex indices at the given triangle index + * and stores them into the given int array. + * + * @param index The index of the triangle. + * Should be between 0 and {@link #getTriangleCount()}. + * + * @param indices Indices of the triangle's vertices + */ public void getTriangle(int index, int[] indices){ - VertexBuffer ib = getBuffer(Type.Index); - if (ib.getFormat() == Format.UnsignedShort){ - // accepted format for buffers - ShortBuffer sib = (ShortBuffer) ib.getData(); + IndexBuffer ib = getIndicesAsList(); - // acquire triangle's vertex indices - int vertIndex = index * 3; - indices[0] = sib.get(vertIndex); - indices[1] = sib.get(vertIndex+1); - indices[2] = sib.get(vertIndex+2); - } + // acquire triangle's vertex indices + int vertIndex = index * 3; + indices[0] = ib.get(vertIndex); + indices[1] = ib.get(vertIndex+1); + indices[2] = ib.get(vertIndex+2); } + /** + * Returns the mesh's VAO ID. Internal use only. + */ public int getId(){ return vertexArrayID; } + /** + * Sets the mesh's VAO ID. Internal use only. + */ public void setId(int id){ if (vertexArrayID != -1) throw new IllegalStateException("ID has already been set."); @@ -761,12 +816,24 @@ public class Mesh implements Savable, Cloneable { vertexArrayID = id; } + /** + * Generates a collision tree for the mesh. + * Called automatically by {@link #collideWith(com.jme3.collision.Collidable, + * com.jme3.math.Matrix4f, + * com.jme3.bounding.BoundingVolume, + * com.jme3.collision.CollisionResults) }. + */ public void createCollisionData(){ BIHTree tree = new BIHTree(this); tree.construct(); collisionTree = tree; } + /** + * Handles collision detection, internal use only. + * User code should only use collideWith() on scene + * graph elements such as {@link Spatial}s. + */ public int collideWith(Collidable other, Matrix4f worldMatrix, BoundingVolume worldBound, @@ -779,6 +846,17 @@ public class Mesh implements Savable, Cloneable { return collisionTree.collideWith(other, worldMatrix, worldBound, results); } + /** + * Set a floating point {@link VertexBuffer} on the mesh. + * + * @param type The type of {@link VertexBuffer}, + * e.g. {@link Type#Position}, {@link Type#Normal}, etc. + * + * @param components Number of components on the vertex buffer, should + * be between 1 and 4. + * + * @param buf The floating point data to contain + */ public void setBuffer(Type type, int components, FloatBuffer buf) { // VertexBuffer vb = buffers.get(type); VertexBuffer vb = buffers.get(type.ordinal()); @@ -851,6 +929,13 @@ public class Mesh implements Savable, Cloneable { updateCounts(); } + /** + * Clears or unsets the {@link VertexBuffer} set on this mesh + * with the given type. + * Does nothing if the vertex buffer type is not set initially + * + * @param type The type to remove + */ public void clearBuffer(VertexBuffer.Type type){ VertexBuffer vb = buffers.remove(type.ordinal()); if (vb != null){ @@ -863,10 +948,24 @@ public class Mesh implements Savable, Cloneable { setBuffer(type, components, BufferUtils.createShortBuffer(buf)); } + /** + * Get the {@link VertexBuffer} stored on this mesh with the given + * type. + * + * @param type The type of VertexBuffer + * @return the VertexBuffer data, or null if not set + */ public VertexBuffer getBuffer(Type type){ return buffers.get(type.ordinal()); } + /** + * Get the {@link VertexBuffer} data stored on this mesh in float + * format. + * + * @param type The type of VertexBuffer + * @return the VertexBuffer data, or null if not set + */ public FloatBuffer getFloatBuffer(Type type) { VertexBuffer vb = getBuffer(type); if (vb == null) @@ -875,6 +974,13 @@ public class Mesh implements Savable, Cloneable { return (FloatBuffer) vb.getData(); } + /** + * Get the {@link VertexBuffer} data stored on this mesh in short + * format. + * + * @param type The type of VertexBuffer + * @return the VertexBuffer data, or null if not set + */ public ShortBuffer getShortBuffer(Type type) { VertexBuffer vb = getBuffer(type); if (vb == null) @@ -883,6 +989,42 @@ public class Mesh implements Savable, Cloneable { return (ShortBuffer) vb.getData(); } + /** + * Acquires an index buffer that will read the vertices on the mesh + * as a list. + * + * @param mesh The mesh to read from + * @return A virtual or wrapped index buffer to read the data as a list + */ + public IndexBuffer getIndicesAsList(){ + if (mode == Mode.Hybrid) + throw new UnsupportedOperationException("Hybrid mode not supported"); + + IndexBuffer ib = getIndexBuffer(); + if (ib != null){ + if (mode.isListMode()){ + // already in list mode + return ib; + }else{ + // not in list mode but it does have an index buffer + // wrap it so the data is converted to list format + return new WrappedIndexBuffer(this); + } + }else{ + // return a virtual index buffer that will supply + // "fake" indices in list format + return new VirtualIndexBuffer(vertCount, mode); + } + } + + /** + * Get the index buffer for this mesh. + * Will return null if no index buffer is set. + * + * @return The index buffer of this mesh. + * + * @see Type#Index + */ public IndexBuffer getIndexBuffer() { VertexBuffer vb = getBuffer(Type.Index); if (vb == null) @@ -902,10 +1044,20 @@ public class Mesh implements Savable, Cloneable { /** * Scales the texture coordinate buffer on this mesh by the given - * scale factor. + * scale factor. + *

+ * Note that values above 1 will cause the + * texture to tile, while values below 1 will cause the texture + * to stretch. + *

* + * @param scaleFactor The scale factor to scale by. Every texture + * coordinate is multiplied by this vector to get the result. * - * @param scaleFactor + * @throws IllegalStateException If there's no texture coordinate + * buffer on the mesh + * @throws UnsupportedOperationException If the texture coordinate + * buffer is not in 2D float format. */ public void scaleTextureCoordinates(Vector2f scaleFactor){ VertexBuffer tc = getBuffer(Type.TexCoord); diff --git a/engine/src/core/com/jme3/scene/UserData.java b/engine/src/core/com/jme3/scene/UserData.java index 542faee07..7ac8a4478 100644 --- a/engine/src/core/com/jme3/scene/UserData.java +++ b/engine/src/core/com/jme3/scene/UserData.java @@ -47,6 +47,12 @@ import java.io.IOException; */ public final class UserData implements Savable { + /** + * Boolean type on Geometries to indicate that physics collision + * shape generation should ignore them. + */ + public static final String JME_PHYSICSIGNORE = "JmePhysicsIgnore"; + protected byte type; protected Object value; diff --git a/engine/src/core/com/jme3/scene/mesh/IndexBuffer.java b/engine/src/core/com/jme3/scene/mesh/IndexBuffer.java index 08e92390d..5c41c046b 100644 --- a/engine/src/core/com/jme3/scene/mesh/IndexBuffer.java +++ b/engine/src/core/com/jme3/scene/mesh/IndexBuffer.java @@ -32,6 +32,7 @@ package com.jme3.scene.mesh; +import com.jme3.util.BufferUtils; import java.nio.Buffer; /** @@ -42,6 +43,25 @@ import java.nio.Buffer; * @author lex */ public abstract class IndexBuffer { + + /** + * Creates an index buffer that can contain the given amount + * of vertices. + * Returns {@link IndexShortBuffer} + * + * @param vertexCount The amount of vertices to contain + * @param indexCount The amount of indices + * to contain. + * @return A new index buffer + */ + public static IndexBuffer createIndexBuffer(int vertexCount, int indexCount){ + if (vertexCount > 65535){ + return new IndexIntBuffer(BufferUtils.createIntBuffer(indexCount)); + }else{ + return new IndexShortBuffer(BufferUtils.createShortBuffer(indexCount)); + } + } + /** * Returns the vertex index for the given index in the index buffer. * diff --git a/engine/src/core/com/jme3/scene/mesh/WrappedIndexBuffer.java b/engine/src/core/com/jme3/scene/mesh/WrappedIndexBuffer.java index 38e833dae..c7dcd6e9a 100644 --- a/engine/src/core/com/jme3/scene/mesh/WrappedIndexBuffer.java +++ b/engine/src/core/com/jme3/scene/mesh/WrappedIndexBuffer.java @@ -54,28 +54,29 @@ public class WrappedIndexBuffer extends VirtualIndexBuffer { public Buffer getBuffer() { return ib.getBuffer(); } - + public static void convertToList(Mesh mesh){ - IndexBuffer inBuf = mesh.getIndexBuffer(); - if (inBuf == null){ - inBuf = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode()); - }else{ - inBuf = new WrappedIndexBuffer(mesh); - } - - IndexBuffer outBuf; - if (inBuf.size() > Short.MAX_VALUE * 2){ - outBuf = new IndexIntBuffer(BufferUtils.createIntBuffer(inBuf.size())); - }else{ - outBuf = new IndexShortBuffer(BufferUtils.createShortBuffer(inBuf.size())); - } + IndexBuffer inBuf = mesh.getIndicesAsList(); + IndexBuffer outBuf = IndexBuffer.createIndexBuffer(mesh.getVertexCount(), + inBuf.size()); for (int i = 0; i < inBuf.size(); i++){ outBuf.put(i, inBuf.get(i)); } mesh.clearBuffer(Type.Index); - mesh.setMode(Mode.Triangles); + switch (mesh.getMode()){ + case LineLoop: + case LineStrip: + mesh.setMode(Mode.Lines); + break; + case TriangleStrip: + case TriangleFan: + mesh.setMode(Mode.Triangles); + break; + default: + break; + } if (outBuf instanceof IndexIntBuffer){ mesh.setBuffer(Type.Index, 3, (IntBuffer)outBuf.getBuffer()); }else{ diff --git a/engine/src/jbullet/com/jme3/bullet/util/CollisionShapeFactory.java b/engine/src/jbullet/com/jme3/bullet/util/CollisionShapeFactory.java index 012d8a9d5..52bed4895 100644 --- a/engine/src/jbullet/com/jme3/bullet/util/CollisionShapeFactory.java +++ b/engine/src/jbullet/com/jme3/bullet/util/CollisionShapeFactory.java @@ -46,6 +46,7 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; import com.jme3.scene.Node; import com.jme3.scene.Spatial; +import com.jme3.scene.UserData; import com.jme3.terrain.geomipmap.TerrainPatch; import com.jme3.terrain.geomipmap.TerrainQuad; import java.util.Iterator; @@ -91,6 +92,11 @@ public class CollisionShapeFactory { if (spatial instanceof Node) { createCompoundShape(realRootNode, (Node) spatial, shape, meshAccurate, dynamic); } else if (spatial instanceof Geometry) { + Boolean bool = spatial.getUserData(UserData.JME_PHYSICSIGNORE); + if (bool != null && bool.booleanValue()){ + continue; // go to the next child in the loop + } + if (meshAccurate) { CollisionShape childShape = dynamic ? createSingleDynamicMeshShape((Geometry) spatial, realRootNode) diff --git a/engine/src/jbullet/com/jme3/bullet/util/Converter.java b/engine/src/jbullet/com/jme3/bullet/util/Converter.java index b10523810..d257d09b4 100644 --- a/engine/src/jbullet/com/jme3/bullet/util/Converter.java +++ b/engine/src/jbullet/com/jme3/bullet/util/Converter.java @@ -37,6 +37,7 @@ import com.jme3.math.FastMath; import com.jme3.scene.mesh.IndexBuffer; import com.jme3.scene.Mesh; import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.mesh.WrappedIndexBuffer; import com.jme3.util.BufferUtils; import java.nio.ByteBuffer; import java.nio.FloatBuffer; @@ -224,12 +225,12 @@ public class Converter { } public static IndexedMesh convert(Mesh mesh) { - IndexedMesh jBulletIndexedMesh = new IndexedMesh(); jBulletIndexedMesh.triangleIndexBase = ByteBuffer.allocate(mesh.getTriangleCount() * 3 * 4); jBulletIndexedMesh.vertexBase = ByteBuffer.allocate(mesh.getVertexCount() * 3 * 4); - IndexBuffer indices = mesh.getIndexBuffer(); + IndexBuffer indices = mesh.getIndicesAsList(); + FloatBuffer vertices = mesh.getFloatBuffer(Type.Position); vertices.rewind(); diff --git a/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java b/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java index 2deff6917..d60cd3def 100644 --- a/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java +++ b/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java @@ -176,12 +176,7 @@ public class GeometryBatchFactory { if (Type.Index.ordinal() == bufType) { int components = compsForBuf[bufType]; - IndexBuffer inIdx = inMesh.getIndexBuffer(); - if (inIdx == null) { - inIdx = new VirtualIndexBuffer(geomVertCount, inMesh.getMode()); - } else if (inMesh.getMode() != mode) { - inIdx = new WrappedIndexBuffer(inMesh); - } + IndexBuffer inIdx = inMesh.getIndicesAsList(); IndexBuffer outIdx = outMesh.getIndexBuffer(); for (int tri = 0; tri < geomTriCount; tri++) {