|
|
|
@ -46,6 +46,7 @@ import com.jme3.export.JmeImporter; |
|
|
|
|
import com.jme3.export.InputCapsule; |
|
|
|
|
import com.jme3.export.OutputCapsule; |
|
|
|
|
import com.jme3.export.Savable; |
|
|
|
|
import com.jme3.material.RenderState; |
|
|
|
|
import com.jme3.math.Matrix4f; |
|
|
|
|
import com.jme3.math.Triangle; |
|
|
|
|
import com.jme3.math.Vector2f; |
|
|
|
@ -65,22 +66,85 @@ import java.nio.IntBuffer; |
|
|
|
|
import java.nio.ShortBuffer; |
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* <code>Mesh</code> is used to store rendering data. |
|
|
|
|
* <p> |
|
|
|
|
* All visible elements in a scene are represented by meshes. |
|
|
|
|
* Meshes may contain three types of geometric primitives: |
|
|
|
|
* <ul> |
|
|
|
|
* <li>Points</li> |
|
|
|
|
* <li>Lines</li> |
|
|
|
|
* <li>Triangles</li> |
|
|
|
|
* </ul> |
|
|
|
|
* |
|
|
|
|
* @author Kirill Vainer |
|
|
|
|
*/ |
|
|
|
|
public class Mesh implements Savable, Cloneable { |
|
|
|
|
|
|
|
|
|
// TODO: Document this enum
|
|
|
|
|
/** |
|
|
|
|
* The mode of the Mesh specifies both the type of primitive represented |
|
|
|
|
* by the mesh and how the data should be interpreted. |
|
|
|
|
*/ |
|
|
|
|
public enum Mode { |
|
|
|
|
/** |
|
|
|
|
* A primitive is a single point in space. The size of the points |
|
|
|
|
* can be specified with {@link Mesh#setPointSize(float) }. |
|
|
|
|
*/ |
|
|
|
|
Points, |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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, |
|
|
|
|
LineLoop, |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A primitive is a line segment. The first two vertices specify |
|
|
|
|
* a single line, while subsequent vertices are combined with the |
|
|
|
|
* previous vertex to make a line. {@link Mesh#setLineWidth(float) } can |
|
|
|
|
* be used to set the width of the lines. |
|
|
|
|
*/ |
|
|
|
|
LineStrip, |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Identical to {@link #LineStrip} except that at the end |
|
|
|
|
* the last vertex is connected with the first to form a line. |
|
|
|
|
* {@link Mesh#setLineWidth(float) } can be used |
|
|
|
|
* to set the width of the lines. |
|
|
|
|
*/ |
|
|
|
|
LineLoop, |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A primitive is a triangle. Each 3 vertices specify a single |
|
|
|
|
* triangle. |
|
|
|
|
*/ |
|
|
|
|
Triangles, |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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, |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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, |
|
|
|
|
Hybrid |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* A combination of various triangle modes. It is best to avoid |
|
|
|
|
* using this mode as it may not be supported by all renderers. |
|
|
|
|
* The {@link Mesh#setModeStart(int[]) mode start points} and |
|
|
|
|
* {@link Mesh#setElementLengths(int[]) element lengths} must |
|
|
|
|
* be specified for this mode. |
|
|
|
|
*/ |
|
|
|
|
Hybrid; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// private static final int BUFFERS_SIZE = VertexBuffer.Type.BoneIndex.ordinal() + 1;
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The bounding volume that contains the mesh entirely. |
|
|
|
|
* By default a BoundingBox (AABB). |
|
|
|
@ -89,6 +153,7 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
|
|
|
|
|
private CollisionData collisionTree = null; |
|
|
|
|
|
|
|
|
|
private ArrayList<VertexBuffer> buffersList = new ArrayList<VertexBuffer>(5); |
|
|
|
|
private IntMap<VertexBuffer> buffers = new IntMap<VertexBuffer>(); |
|
|
|
|
private VertexBuffer[] lodLevels; |
|
|
|
|
private float pointSize = 1; |
|
|
|
@ -105,27 +170,47 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
|
|
|
|
|
private Mode mode = Mode.Triangles; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Creates a new mesh with no {@link VertexBuffer vertex buffers}. |
|
|
|
|
*/ |
|
|
|
|
public Mesh(){ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Create a shallow clone of this Mesh. The {@link VertexBuffer vertex |
|
|
|
|
* buffers} are shared between this and the clone mesh, the rest |
|
|
|
|
* of the data is cloned. |
|
|
|
|
* |
|
|
|
|
* @return A shallow clone of the mesh |
|
|
|
|
*/ |
|
|
|
|
@Override |
|
|
|
|
public Mesh clone(){ |
|
|
|
|
try{ |
|
|
|
|
public Mesh clone() { |
|
|
|
|
try { |
|
|
|
|
Mesh clone = (Mesh) super.clone(); |
|
|
|
|
clone.meshBound = meshBound.clone(); |
|
|
|
|
clone.collisionTree = collisionTree != null ? collisionTree : null; |
|
|
|
|
clone.buffers = buffers.clone(); |
|
|
|
|
clone.buffersList = new ArrayList<VertexBuffer>(buffersList); |
|
|
|
|
clone.vertexArrayID = -1; |
|
|
|
|
if (elementLengths != null) |
|
|
|
|
if (elementLengths != null) { |
|
|
|
|
clone.elementLengths = elementLengths.clone(); |
|
|
|
|
if (modeStart != null) |
|
|
|
|
} |
|
|
|
|
if (modeStart != null) { |
|
|
|
|
clone.modeStart = modeStart.clone(); |
|
|
|
|
} |
|
|
|
|
return clone; |
|
|
|
|
}catch (CloneNotSupportedException ex){ |
|
|
|
|
} catch (CloneNotSupportedException ex) { |
|
|
|
|
throw new AssertionError(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Creates a deep clone of this mesh. |
|
|
|
|
* The {@link VertexBuffer vertex buffers} and the data inside them |
|
|
|
|
* is cloned. |
|
|
|
|
* |
|
|
|
|
* @return a deep clone of this mesh. |
|
|
|
|
*/ |
|
|
|
|
public Mesh deepClone(){ |
|
|
|
|
try{ |
|
|
|
|
Mesh clone = (Mesh) super.clone(); |
|
|
|
@ -136,13 +221,21 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
clone.collisionTree = null; // it will get re-generated in any case
|
|
|
|
|
|
|
|
|
|
clone.buffers = new IntMap<VertexBuffer>(); |
|
|
|
|
clone.buffersList = new ArrayList<VertexBuffer>(); |
|
|
|
|
for (Entry<VertexBuffer> ent : buffers){ |
|
|
|
|
clone.buffers.put(ent.getKey(), ent.getValue().clone()); |
|
|
|
|
VertexBuffer bufClone = ent.getValue().clone(); |
|
|
|
|
clone.buffers.put(ent.getKey(), bufClone); |
|
|
|
|
clone.buffersList.add(bufClone); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
clone.vertexArrayID = -1; |
|
|
|
|
clone.vertCount = -1; |
|
|
|
|
clone.elementCount = -1; |
|
|
|
|
clone.maxNumWeights = -1; |
|
|
|
|
|
|
|
|
|
// although this could change
|
|
|
|
|
// if the bone weight/index buffers are modified
|
|
|
|
|
clone.maxNumWeights = maxNumWeights; |
|
|
|
|
|
|
|
|
|
clone.elementLengths = elementLengths != null ? elementLengths.clone() : null; |
|
|
|
|
clone.modeStart = modeStart != null ? modeStart.clone() : null; |
|
|
|
|
return clone; |
|
|
|
@ -151,6 +244,15 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Clone the mesh for animation use. |
|
|
|
|
* This creates a shallow clone of the mesh, sharing most |
|
|
|
|
* of the {@link VertexBuffer vertex buffer} data, however the |
|
|
|
|
* {@link Type#BindPosePosition} and {@link Type#BindPoseNormal} buffers |
|
|
|
|
* are deeply cloned. |
|
|
|
|
* |
|
|
|
|
* @return A clone of the mesh for animation use. |
|
|
|
|
*/ |
|
|
|
|
public Mesh cloneForAnim(){ |
|
|
|
|
Mesh clone = clone(); |
|
|
|
|
if (getBuffer(Type.BindPosePosition) != null){ |
|
|
|
@ -170,8 +272,17 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
return clone; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void generateBindPose(boolean swAnim){ |
|
|
|
|
if (swAnim){ |
|
|
|
|
/** |
|
|
|
|
* Generates the {@link Type#BindPosePosition} and {@link Type#BindPoseNormal} |
|
|
|
|
* buffers for this mesh by duplicating them based on the position and normal |
|
|
|
|
* buffers already set on the mesh. |
|
|
|
|
* This method does nothing if the mesh has no bone weight or index |
|
|
|
|
* buffers. |
|
|
|
|
* |
|
|
|
|
* @param forSoftwareAnim Should be true if the bind pose is to be generated. |
|
|
|
|
*/ |
|
|
|
|
public void generateBindPose(boolean forSoftwareAnim){ |
|
|
|
|
if (forSoftwareAnim){ |
|
|
|
|
VertexBuffer pos = getBuffer(Type.Position); |
|
|
|
|
if (pos == null || getBuffer(Type.BoneIndex) == null) { |
|
|
|
|
// ignore, this mesh doesn't have positional data
|
|
|
|
@ -200,13 +311,17 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
setBuffer(bindNorm); |
|
|
|
|
norm.setUsage(Usage.Stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
norm.setUsage(Usage.Stream); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void prepareForAnim(boolean swAnim){ |
|
|
|
|
if (swAnim){ |
|
|
|
|
/** |
|
|
|
|
* Prepares the mesh for software skinning by converting the bone index |
|
|
|
|
* and weight buffers to heap buffers. |
|
|
|
|
* |
|
|
|
|
* @param forSoftwareAnim Should be true to enable the conversion. |
|
|
|
|
*/ |
|
|
|
|
public void prepareForAnim(boolean forSoftwareAnim){ |
|
|
|
|
if (forSoftwareAnim){ |
|
|
|
|
// convert indices
|
|
|
|
|
VertexBuffer indices = getBuffer(Type.BoneIndex); |
|
|
|
|
ByteBuffer originalIndex = (ByteBuffer) indices.getData(); |
|
|
|
@ -225,6 +340,11 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the LOD (level of detail) index buffers on this mesh. |
|
|
|
|
* |
|
|
|
|
* @param lodLevels The LOD levels to set |
|
|
|
|
*/ |
|
|
|
|
public void setLodLevels(VertexBuffer[] lodLevels){ |
|
|
|
|
this.lodLevels = lodLevels; |
|
|
|
|
} |
|
|
|
@ -237,62 +357,152 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
return lodLevels != null ? lodLevels.length : 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the lod level at the given index. |
|
|
|
|
* |
|
|
|
|
* @param lod The lod level index, this does not include |
|
|
|
|
* the main index buffer. |
|
|
|
|
* @return The LOD index buffer at the index |
|
|
|
|
* |
|
|
|
|
* @throws IndexOutOfBoundsException If the index is outside of the |
|
|
|
|
* range [0, {@link #getNumLodLevels()}]. |
|
|
|
|
* |
|
|
|
|
* @see #setLodLevels(com.jme3.scene.VertexBuffer[]) |
|
|
|
|
*/ |
|
|
|
|
public VertexBuffer getLodLevel(int lod){ |
|
|
|
|
return lodLevels[lod]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get the element lengths for {@link Mode#Hybrid} mesh mode. |
|
|
|
|
* |
|
|
|
|
* @return element lengths |
|
|
|
|
*/ |
|
|
|
|
public int[] getElementLengths() { |
|
|
|
|
return elementLengths; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the element lengths for {@link Mode#Hybrid} mesh mode. |
|
|
|
|
* |
|
|
|
|
* @param elementLengths The element lengths to set |
|
|
|
|
*/ |
|
|
|
|
public void setElementLengths(int[] elementLengths) { |
|
|
|
|
this.elementLengths = elementLengths; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the mode start indices for {@link Mode#Hybrid} mesh mode. |
|
|
|
|
* |
|
|
|
|
* @return mode start indices |
|
|
|
|
*/ |
|
|
|
|
public int[] getModeStart() { |
|
|
|
|
return modeStart; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get the mode start indices for {@link Mode#Hybrid} mesh mode. |
|
|
|
|
* |
|
|
|
|
* @return mode start indices |
|
|
|
|
*/ |
|
|
|
|
public void setModeStart(int[] modeStart) { |
|
|
|
|
this.modeStart = modeStart; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the mesh mode |
|
|
|
|
* |
|
|
|
|
* @return the mesh mode |
|
|
|
|
* |
|
|
|
|
* @see #setMode(com.jme3.scene.Mesh.Mode) |
|
|
|
|
*/ |
|
|
|
|
public Mode getMode() { |
|
|
|
|
return mode; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Change the Mesh's mode. By default the mode is {@link Mode#Triangles}. |
|
|
|
|
* |
|
|
|
|
* @param mode The new mode to set |
|
|
|
|
* |
|
|
|
|
* @see Mode |
|
|
|
|
*/ |
|
|
|
|
public void setMode(Mode mode) { |
|
|
|
|
this.mode = mode; |
|
|
|
|
updateCounts(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the maximum number of weights per vertex on this mesh. |
|
|
|
|
* |
|
|
|
|
* @return maximum number of weights per vertex |
|
|
|
|
* |
|
|
|
|
* @see #setMaxNumWeights(int) |
|
|
|
|
*/ |
|
|
|
|
public int getMaxNumWeights() { |
|
|
|
|
return maxNumWeights; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the maximum number of weights per vertex on this mesh. |
|
|
|
|
* Only relevant if this mesh has bone index/weight buffers. |
|
|
|
|
* This value should be between 0 and 4. |
|
|
|
|
* |
|
|
|
|
* @param maxNumWeights |
|
|
|
|
*/ |
|
|
|
|
public void setMaxNumWeights(int maxNumWeights) { |
|
|
|
|
this.maxNumWeights = maxNumWeights; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the size of points for point meshes |
|
|
|
|
* |
|
|
|
|
* @return the size of points |
|
|
|
|
* |
|
|
|
|
* @see #setPointSize(float) |
|
|
|
|
*/ |
|
|
|
|
public float getPointSize() { |
|
|
|
|
return pointSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the size of points for meshes of mode {@link Mode#Points}. |
|
|
|
|
* The point size is specified as on-screen pixels, the default |
|
|
|
|
* value is 1.0. The point size |
|
|
|
|
* does nothing if {@link RenderState#setPointSprite(boolean) point sprite} |
|
|
|
|
* render state is enabled, in that case, the vertex shader must specify the |
|
|
|
|
* point size by writing to <code>gl_PointSize</code>. |
|
|
|
|
* |
|
|
|
|
* @param pointSize The size of points |
|
|
|
|
*/ |
|
|
|
|
public void setPointSize(float pointSize) { |
|
|
|
|
this.pointSize = pointSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the line width for line meshes. |
|
|
|
|
* |
|
|
|
|
* @return the line width |
|
|
|
|
*/ |
|
|
|
|
public float getLineWidth() { |
|
|
|
|
return lineWidth; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Specify the line width for meshes of the line modes, such |
|
|
|
|
* as {@link Mode#Lines}. The line width is specified as on-screen pixels, |
|
|
|
|
* the default value is 1.0. |
|
|
|
|
* |
|
|
|
|
* @param lineWidth The line width |
|
|
|
|
*/ |
|
|
|
|
public void setLineWidth(float lineWidth) { |
|
|
|
|
this.lineWidth = lineWidth; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Locks the mesh so it cannot be modified anymore, thus |
|
|
|
|
* optimizing its data. |
|
|
|
|
* Indicates to the GPU that this mesh will not be modified (a hint). |
|
|
|
|
* Sets the usage mode to {@link Usage#Static} |
|
|
|
|
* for all {@link VertexBuffer vertex buffers} on this Mesh. |
|
|
|
|
*/ |
|
|
|
|
public void setStatic() { |
|
|
|
|
for (Entry<VertexBuffer> entry : buffers){ |
|
|
|
@ -301,8 +511,9 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Unlocks the mesh so it can be modified, this |
|
|
|
|
* will un-optimize the data! |
|
|
|
|
* Indicates to the GPU that this mesh will be modified occasionally (a hint). |
|
|
|
|
* Sets the usage mode to {@link Usage#Dynamic} |
|
|
|
|
* for all {@link VertexBuffer vertex buffers} on this Mesh. |
|
|
|
|
*/ |
|
|
|
|
public void setDynamic() { |
|
|
|
|
for (Entry<VertexBuffer> entry : buffers){ |
|
|
|
@ -310,12 +521,22 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Indicates to the GPU that this mesh will be modified every frame (a hint). |
|
|
|
|
* Sets the usage mode to {@link Usage#Stream} |
|
|
|
|
* for all {@link VertexBuffer vertex buffers} on this Mesh. |
|
|
|
|
*/ |
|
|
|
|
public void setStreamed(){ |
|
|
|
|
for (Entry<VertexBuffer> entry : buffers){ |
|
|
|
|
entry.getValue().setUsage(Usage.Stream); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Interleaves the data in this mesh. This operation cannot be reversed. |
|
|
|
|
* Some GPUs may prefer the data in this format, however it is a good idea |
|
|
|
|
* to <em>avoid</em> using this method as it disables some engine features. |
|
|
|
|
*/ |
|
|
|
|
public void setInterleaved(){ |
|
|
|
|
ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>(); |
|
|
|
|
for (Entry<VertexBuffer> entry : buffers){ |
|
|
|
@ -339,8 +560,10 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
VertexBuffer allData = new VertexBuffer(Type.InterleavedData); |
|
|
|
|
ByteBuffer dataBuf = BufferUtils.createByteBuffer(stride * getVertexCount()); |
|
|
|
|
allData.setupData(Usage.Static, 1, Format.UnsignedByte, dataBuf); |
|
|
|
|
|
|
|
|
|
// adding buffer directly so that no update counts is forced
|
|
|
|
|
buffers.put(Type.InterleavedData.ordinal(), allData); |
|
|
|
|
buffersList.add(allData); |
|
|
|
|
|
|
|
|
|
for (int vert = 0; vert < getVertexCount(); vert++){ |
|
|
|
|
for (int i = 0; i < vbs.size(); i++){ |
|
|
|
@ -415,6 +638,16 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Update the {@link #getVertexCount() vertex} and |
|
|
|
|
* {@link #getTriangleCount() triangle} counts for this mesh |
|
|
|
|
* based on the current data. This method should be called |
|
|
|
|
* after the {@link Buffer#capacity() capacities} of the mesh's |
|
|
|
|
* {@link VertexBuffer vertex buffers} has been altered. |
|
|
|
|
* |
|
|
|
|
* @throws IllegalStateException If this mesh is in |
|
|
|
|
* {@link #setInterleaved() interleaved} format. |
|
|
|
|
*/ |
|
|
|
|
public void updateCounts(){ |
|
|
|
|
if (getBuffer(Type.InterleavedData) != null) |
|
|
|
|
throw new IllegalStateException("Should update counts before interleave"); |
|
|
|
@ -431,6 +664,12 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the triangle count for the given LOD level. |
|
|
|
|
* |
|
|
|
|
* @param lod The lod level to look up |
|
|
|
|
* @return The triangle count for that LOD level |
|
|
|
|
*/ |
|
|
|
|
public int getTriangleCount(int lod){ |
|
|
|
|
if (lodLevels != null){ |
|
|
|
|
if (lod < 0) |
|
|
|
@ -447,10 +686,17 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns how many triangles are on this Mesh. |
|
|
|
|
* This value is only updated when {@link #updateCounts() } is called. |
|
|
|
|
* |
|
|
|
|
* @return how many triangles are on this Mesh. |
|
|
|
|
*/ |
|
|
|
|
public int getTriangleCount(){ |
|
|
|
|
return elementCount; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public int getVertexCount(){ |
|
|
|
|
return vertCount; |
|
|
|
|
} |
|
|
|
@ -540,6 +786,7 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
vb.setupData(Usage.Dynamic, components, Format.Float, buf); |
|
|
|
|
// buffers.put(type, vb);
|
|
|
|
|
buffers.put(type.ordinal(), vb); |
|
|
|
|
buffersList.add(vb); |
|
|
|
|
}else{ |
|
|
|
|
vb.setupData(Usage.Dynamic, components, Format.Float, buf); |
|
|
|
|
} |
|
|
|
@ -556,6 +803,7 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
vb = new VertexBuffer(type); |
|
|
|
|
vb.setupData(Usage.Dynamic, components, Format.UnsignedInt, buf); |
|
|
|
|
buffers.put(type.ordinal(), vb); |
|
|
|
|
buffersList.add(vb); |
|
|
|
|
updateCounts(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -570,6 +818,7 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
vb = new VertexBuffer(type); |
|
|
|
|
vb.setupData(Usage.Dynamic, components, Format.UnsignedShort, buf); |
|
|
|
|
buffers.put(type.ordinal(), vb); |
|
|
|
|
buffersList.add(vb); |
|
|
|
|
updateCounts(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -584,6 +833,7 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
vb = new VertexBuffer(type); |
|
|
|
|
vb.setupData(Usage.Dynamic, components, Format.UnsignedByte, buf); |
|
|
|
|
buffers.put(type.ordinal(), vb); |
|
|
|
|
buffersList.add(vb); |
|
|
|
|
updateCounts(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -593,12 +843,16 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
throw new IllegalArgumentException("Buffer type already set: "+vb.getBufferType()); |
|
|
|
|
|
|
|
|
|
buffers.put(vb.getBufferType().ordinal(), vb); |
|
|
|
|
buffersList.add(vb); |
|
|
|
|
updateCounts(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void clearBuffer(VertexBuffer.Type type){ |
|
|
|
|
buffers.remove(type.ordinal()); |
|
|
|
|
updateCounts(); |
|
|
|
|
VertexBuffer vb = buffers.remove(type.ordinal()); |
|
|
|
|
if (vb != null){ |
|
|
|
|
buffersList.remove(vb); |
|
|
|
|
updateCounts(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void setBuffer(Type type, int components, short[] buf){ |
|
|
|
@ -642,6 +896,13 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Scales the texture coordinate buffer on this mesh by the given |
|
|
|
|
* scale factor. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param scaleFactor |
|
|
|
|
*/ |
|
|
|
|
public void scaleTextureCoordinates(Vector2f scaleFactor){ |
|
|
|
|
VertexBuffer tc = getBuffer(Type.TexCoord); |
|
|
|
|
if (tc == null) |
|
|
|
@ -667,6 +928,11 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
tc.updateData(fb); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Updates the bounding volume of this mesh. |
|
|
|
|
* The method does nothing if the mesh has no {@link Type#Position} buffer. |
|
|
|
|
* It is expected that the position buffer is a float buffer with 3 components. |
|
|
|
|
*/ |
|
|
|
|
public void updateBound(){ |
|
|
|
|
VertexBuffer posBuf = getBuffer(VertexBuffer.Type.Position); |
|
|
|
|
if (meshBound != null && posBuf != null){ |
|
|
|
@ -674,17 +940,42 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the {@link BoundingVolume} of this Mesh. |
|
|
|
|
* By default the bounding volume is a {@link BoundingBox}. |
|
|
|
|
* |
|
|
|
|
* @return the bounding volume of this mesh |
|
|
|
|
*/ |
|
|
|
|
public BoundingVolume getBound() { |
|
|
|
|
return meshBound; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sets the {@link BoundingVolume} for this Mesh. |
|
|
|
|
* The bounding volume is recomputed by calling {@link #updateBound() }. |
|
|
|
|
* |
|
|
|
|
* @param modelBound The model bound to set |
|
|
|
|
*/ |
|
|
|
|
public void setBound(BoundingVolume modelBound) { |
|
|
|
|
meshBound = modelBound; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns a map of all {@link VertexBuffer vertex buffers} on this Mesh. |
|
|
|
|
* The integer key for the map is the {@link Enum#ordinal() ordinal} |
|
|
|
|
* of the vertex buffer's {@link Type}. |
|
|
|
|
* Note that the returned map is a reference to the map used internally, |
|
|
|
|
* modifying it will cause undefined results. |
|
|
|
|
* |
|
|
|
|
* @return map of vertex buffers on this mesh. |
|
|
|
|
*/ |
|
|
|
|
public IntMap<VertexBuffer> getBuffers(){ |
|
|
|
|
return buffers; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ArrayList<VertexBuffer> getBufferList(){ |
|
|
|
|
return buffersList; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void write(JmeExporter ex) throws IOException { |
|
|
|
|
OutputCapsule out = ex.getCapsule(this); |
|
|
|
@ -726,6 +1017,10 @@ public class Mesh implements Savable, Cloneable { |
|
|
|
|
|
|
|
|
|
// in.readStringSavableMap("buffers", null);
|
|
|
|
|
buffers = (IntMap<VertexBuffer>) in.readIntSavableMap("buffers", null); |
|
|
|
|
for (Entry<VertexBuffer> entry : buffers){ |
|
|
|
|
buffersList.add(entry.getValue()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Savable[] lodLevelsSavable = in.readSavableArray("lodLevels", null); |
|
|
|
|
if (lodLevelsSavable != null) { |
|
|
|
|
lodLevels = new VertexBuffer[lodLevelsSavable.length]; |
|
|
|
|