|
@@ -50,6 +50,7 @@ import com.jme3.util.clone.JmeCloneable;
|
|
|
import java.io.IOException;
|
|
|
import java.nio.*;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
|
|
|
/**
|
|
|
* <code>Mesh</code> is used to store rendering data.
|
|
@@ -164,8 +165,8 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
|
|
|
private CollisionData collisionTree = null;
|
|
|
|
|
|
- private SafeArrayList<VertexBuffer> buffersList = new SafeArrayList<VertexBuffer>(VertexBuffer.class);
|
|
|
- private IntMap<VertexBuffer> buffers = new IntMap<VertexBuffer>();
|
|
|
+ private SafeArrayList<VertexBuffer> buffersList = new SafeArrayList<>(VertexBuffer.class);
|
|
|
+ private IntMap<VertexBuffer> buffers = new IntMap<>();
|
|
|
private VertexBuffer[] lodLevels;
|
|
|
private float pointSize = 1;
|
|
|
private float lineWidth = 1;
|
|
@@ -183,6 +184,11 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
|
|
|
private Mode mode = Mode.Triangles;
|
|
|
|
|
|
+ private SafeArrayList<MorphTarget> morphTargets;
|
|
|
+ private int numMorphBuffers = 0;
|
|
|
+ private float[] morphState;
|
|
|
+ private boolean dirtyMorph = true;
|
|
|
+
|
|
|
/**
|
|
|
* Creates a new mesh with no {@link VertexBuffer vertex buffers}.
|
|
|
*/
|
|
@@ -203,7 +209,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
clone.meshBound = meshBound.clone();
|
|
|
clone.collisionTree = collisionTree != null ? collisionTree : null;
|
|
|
clone.buffers = buffers.clone();
|
|
|
- clone.buffersList = new SafeArrayList<VertexBuffer>(VertexBuffer.class,buffersList);
|
|
|
+ clone.buffersList = new SafeArrayList<>(VertexBuffer.class, buffersList);
|
|
|
clone.vertexArrayID = -1;
|
|
|
if (elementLengths != null) {
|
|
|
clone.elementLengths = elementLengths.clone();
|
|
@@ -233,8 +239,8 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
//clone.collisionTree = collisionTree != null ? collisionTree : null;
|
|
|
clone.collisionTree = null; // it will get re-generated in any case
|
|
|
|
|
|
- clone.buffers = new IntMap<VertexBuffer>();
|
|
|
- clone.buffersList = new SafeArrayList<VertexBuffer>(VertexBuffer.class);
|
|
|
+ clone.buffers = new IntMap<>();
|
|
|
+ clone.buffersList = new SafeArrayList<>(VertexBuffer.class);
|
|
|
for (VertexBuffer vb : buffersList.getArray()){
|
|
|
VertexBuffer bufClone = vb.clone();
|
|
|
clone.buffers.put(vb.getBufferType().ordinal(), bufClone);
|
|
@@ -697,7 +703,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
*/
|
|
|
@Deprecated
|
|
|
public void setInterleaved(){
|
|
|
- ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>();
|
|
|
+ ArrayList<VertexBuffer> vbs = new ArrayList<>();
|
|
|
vbs.addAll(buffersList);
|
|
|
|
|
|
// ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>(buffers.values());
|
|
@@ -820,8 +826,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
* {@link #setInterleaved() interleaved} format.
|
|
|
*/
|
|
|
public void updateCounts(){
|
|
|
- if (getBuffer(Type.InterleavedData) != null)
|
|
|
+ if (getBuffer(Type.InterleavedData) != null) {
|
|
|
throw new IllegalStateException("Should update counts before interleave");
|
|
|
+ }
|
|
|
|
|
|
VertexBuffer pb = getBuffer(Type.Position);
|
|
|
VertexBuffer ib = getBuffer(Type.Index);
|
|
@@ -844,11 +851,13 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
*/
|
|
|
public int getTriangleCount(int lod){
|
|
|
if (lodLevels != null){
|
|
|
- if (lod < 0)
|
|
|
+ if (lod < 0) {
|
|
|
throw new IllegalArgumentException("LOD level cannot be < 0");
|
|
|
+ }
|
|
|
|
|
|
- if (lod >= lodLevels.length)
|
|
|
- throw new IllegalArgumentException("LOD level "+lod+" does not exist!");
|
|
|
+ if (lod >= lodLevels.length) {
|
|
|
+ throw new IllegalArgumentException("LOD level " + lod + " does not exist!");
|
|
|
+ }
|
|
|
|
|
|
return computeNumElements(lodLevels[lod].getData().limit());
|
|
|
}else if (lod == 0){
|
|
@@ -968,8 +977,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
* Sets the mesh's VAO ID. Internal use only.
|
|
|
*/
|
|
|
public void setId(int id){
|
|
|
- if (vertexArrayID != -1)
|
|
|
+ if (vertexArrayID != -1) {
|
|
|
throw new IllegalStateException("ID has already been set.");
|
|
|
+ }
|
|
|
|
|
|
vertexArrayID = id;
|
|
|
}
|
|
@@ -1037,8 +1047,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
* @throws IllegalArgumentException If the buffer type is already set
|
|
|
*/
|
|
|
public void setBuffer(VertexBuffer vb){
|
|
|
- if (buffers.containsKey(vb.getBufferType().ordinal()))
|
|
|
- throw new IllegalArgumentException("Buffer type already set: "+vb.getBufferType());
|
|
|
+ if (buffers.containsKey(vb.getBufferType().ordinal())) {
|
|
|
+ throw new IllegalArgumentException("Buffer type already set: " + vb.getBufferType());
|
|
|
+ }
|
|
|
|
|
|
buffers.put(vb.getBufferType().ordinal(), vb);
|
|
|
buffersList.add(vb);
|
|
@@ -1151,8 +1162,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
*/
|
|
|
public FloatBuffer getFloatBuffer(Type type) {
|
|
|
VertexBuffer vb = getBuffer(type);
|
|
|
- if (vb == null)
|
|
|
+ if (vb == null) {
|
|
|
return null;
|
|
|
+ }
|
|
|
|
|
|
return (FloatBuffer) vb.getData();
|
|
|
}
|
|
@@ -1166,8 +1178,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
*/
|
|
|
public ShortBuffer getShortBuffer(Type type) {
|
|
|
VertexBuffer vb = getBuffer(type);
|
|
|
- if (vb == null)
|
|
|
+ if (vb == null) {
|
|
|
return null;
|
|
|
+ }
|
|
|
|
|
|
return (ShortBuffer) vb.getData();
|
|
|
}
|
|
@@ -1179,8 +1192,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
* @return A virtual or wrapped index buffer to read the data as a list
|
|
|
*/
|
|
|
public IndexBuffer getIndicesAsList(){
|
|
|
- if (mode == Mode.Hybrid)
|
|
|
+ if (mode == Mode.Hybrid) {
|
|
|
throw new UnsupportedOperationException("Hybrid mode not supported");
|
|
|
+ }
|
|
|
|
|
|
IndexBuffer ib = getIndexBuffer();
|
|
|
if (ib != null){
|
|
@@ -1209,8 +1223,9 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
*/
|
|
|
public IndexBuffer getIndexBuffer() {
|
|
|
VertexBuffer vb = getBuffer(Type.Index);
|
|
|
- if (vb == null)
|
|
|
+ if (vb == null) {
|
|
|
return null;
|
|
|
+ }
|
|
|
|
|
|
return IndexBuffer.wrapIndexBuffer(vb.getData());
|
|
|
}
|
|
@@ -1233,8 +1248,8 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
IndexBuffer indexBuf = getIndexBuffer();
|
|
|
int numIndices = indexBuf.size();
|
|
|
|
|
|
- IntMap<Integer> oldIndicesToNewIndices = new IntMap<Integer>(numIndices);
|
|
|
- ArrayList<Integer> newIndicesToOldIndices = new ArrayList<Integer>();
|
|
|
+ IntMap<Integer> oldIndicesToNewIndices = new IntMap<>(numIndices);
|
|
|
+ ArrayList<Integer> newIndicesToOldIndices = new ArrayList<>();
|
|
|
int newIndex = 0;
|
|
|
|
|
|
for (int i = 0; i < numIndices; i++) {
|
|
@@ -1345,14 +1360,17 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
*/
|
|
|
public void scaleTextureCoordinates(Vector2f scaleFactor){
|
|
|
VertexBuffer tc = getBuffer(Type.TexCoord);
|
|
|
- if (tc == null)
|
|
|
+ if (tc == null) {
|
|
|
throw new IllegalStateException("The mesh has no texture coordinates");
|
|
|
+ }
|
|
|
|
|
|
- if (tc.getFormat() != VertexBuffer.Format.Float)
|
|
|
+ if (tc.getFormat() != VertexBuffer.Format.Float) {
|
|
|
throw new UnsupportedOperationException("Only float texture coord format is supported");
|
|
|
+ }
|
|
|
|
|
|
- if (tc.getNumComponents() != 2)
|
|
|
+ if (tc.getNumComponents() != 2) {
|
|
|
throw new UnsupportedOperationException("Only 2D texture coords are supported");
|
|
|
+ }
|
|
|
|
|
|
FloatBuffer fb = (FloatBuffer) tc.getData();
|
|
|
fb.clear();
|
|
@@ -1504,6 +1522,70 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
return patchVertexCount;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ public void addMorphTarget(MorphTarget target) {
|
|
|
+ if (morphTargets == null) {
|
|
|
+ morphTargets = new SafeArrayList<>(MorphTarget.class);
|
|
|
+ }
|
|
|
+// if (numMorphBuffers == 0) {
|
|
|
+// numMorphBuffers = target.getNumBuffers();
|
|
|
+// int start = Type.MorphTarget0.ordinal();
|
|
|
+// int end = start + numMorphBuffers;
|
|
|
+// for (int i = start; i < end; i++) {
|
|
|
+// VertexBuffer vb = new VertexBuffer(Type.values()[i]);
|
|
|
+// setBuffer(vb);
|
|
|
+// }
|
|
|
+// } else if (target.getNumBuffers() != numMorphBuffers) {
|
|
|
+// throw new IllegalArgumentException("Morph target has different number of buffers");
|
|
|
+// }
|
|
|
+
|
|
|
+ morphTargets.add(target);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setMorphState(float[] state) {
|
|
|
+ if (morphTargets.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (morphState == null) {
|
|
|
+ morphState = new float[morphTargets.size()];
|
|
|
+ }
|
|
|
+ System.arraycopy(state, 0, morphState, 0, morphState.length);
|
|
|
+ this.dirtyMorph = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public float[] getMorphState() {
|
|
|
+ if (morphState == null) {
|
|
|
+ morphState = new float[morphTargets.size()];
|
|
|
+ }
|
|
|
+ return morphState;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setActiveMorphTargets(int... targetsIndex) {
|
|
|
+ int start = Type.MorphTarget0.ordinal();
|
|
|
+ for (int i = 0; i < targetsIndex.length; i++) {
|
|
|
+ MorphTarget t = morphTargets.get(targetsIndex[i]);
|
|
|
+ int idx = 0;
|
|
|
+ for (Type type : t.getBuffers().keySet()) {
|
|
|
+ FloatBuffer b = t.getBuffer(type);
|
|
|
+ setBuffer(Type.values()[start + i + idx], 3, b);
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public MorphTarget[] getMorphTargets() {
|
|
|
+ return morphTargets.getArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean hasMorphTargets() {
|
|
|
+ return morphTargets != null && !morphTargets.isEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean isDirtyMorph() {
|
|
|
+ return dirtyMorph;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
public void write(JmeExporter ex) throws IOException {
|
|
|
OutputCapsule out = ex.getCapsule(this);
|
|
|
|
|
@@ -1550,6 +1632,7 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
|
|
out.write(lodLevels, "lodLevels", null);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
public void read(JmeImporter im) throws IOException {
|
|
|
InputCapsule in = im.getCapsule(this);
|
|
|
meshBound = (BoundingVolume) in.readSavable("modelBound", null);
|