Where possible, merge meshes with identical attributes.
git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@201 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -29,6 +29,7 @@ import java.nio.FloatBuffer;
|
|||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import com.jme.bounding.BoundingBox;
|
import com.jme.bounding.BoundingBox;
|
||||||
@@ -141,6 +142,51 @@ public class ModelMesh extends TriMesh
|
|||||||
Boolean.parseBoolean(tprops.getProperty("translucent"));
|
Boolean.parseBoolean(tprops.getProperty("translucent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an opaque object representing this mesh's attributes. The
|
||||||
|
* object will implement {@link Object#hashCode} and {@link Object#equals}
|
||||||
|
* so that meshes with the same attributes will have identical keys.
|
||||||
|
*/
|
||||||
|
public Object getAttributeKey ()
|
||||||
|
{
|
||||||
|
return new AttributeKey(_textureKey, _textures, _sphereMapped,
|
||||||
|
_filterMode, _mipMapMode, _emissiveMap, _emissive, _additive,
|
||||||
|
_solid, _transparent, _alphaThreshold, _translucent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges another mesh into this one. The mesh is assumed to be in the same coordinate system
|
||||||
|
* and have the same attributes.
|
||||||
|
*/
|
||||||
|
public void merge (ModelMesh mesh)
|
||||||
|
{
|
||||||
|
TriangleBatch batch = (TriangleBatch)getBatch(0);
|
||||||
|
TriangleBatch mbatch = (TriangleBatch)mesh.getBatch(0);
|
||||||
|
|
||||||
|
int vcount = batch.getVertexCount();
|
||||||
|
batch.setVertexBuffer(concatenate(batch.getVertexBuffer(), mbatch.getVertexBuffer()));
|
||||||
|
batch.setNormalBuffer(concatenate(batch.getNormalBuffer(), mbatch.getNormalBuffer()));
|
||||||
|
if (batch.getColorBuffer() != null && mbatch.getColorBuffer() != null) {
|
||||||
|
batch.setColorBuffer(concatenate(batch.getColorBuffer(), mbatch.getColorBuffer()));
|
||||||
|
}
|
||||||
|
batch.setTextureBuffer(concatenate(
|
||||||
|
batch.getTextureBuffer(0), mbatch.getTextureBuffer(0)), 0);
|
||||||
|
for (int ii = 1, nn = getTextureCount(); ii < nn; ii++) {
|
||||||
|
batch.setTextureBuffer(batch.getTextureBuffer(0), ii);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntBuffer ibuf = batch.getIndexBuffer(), mibuf = mbatch.getIndexBuffer();
|
||||||
|
IntBuffer nibuf = BufferUtils.createIntBuffer(ibuf.capacity() + mibuf.capacity());
|
||||||
|
ibuf.clear();
|
||||||
|
nibuf.put(ibuf);
|
||||||
|
mibuf.clear();
|
||||||
|
while (mibuf.hasRemaining()) {
|
||||||
|
nibuf.put(mibuf.get() + vcount);
|
||||||
|
}
|
||||||
|
nibuf.clear();
|
||||||
|
batch.setIndexBuffer(nibuf);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the vertices and the transform of the mesh so that the mesh's
|
* Adjusts the vertices and the transform of the mesh so that the mesh's
|
||||||
* position lies at the center of its bounding volume.
|
* position lies at the center of its bounding volume.
|
||||||
@@ -588,6 +634,20 @@ public class ModelMesh extends TriMesh
|
|||||||
return astate;
|
return astate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates the two provided buffers.
|
||||||
|
*/
|
||||||
|
protected static FloatBuffer concatenate (FloatBuffer b1, FloatBuffer b2)
|
||||||
|
{
|
||||||
|
FloatBuffer nb = BufferUtils.createFloatBuffer(b1.capacity() + b2.capacity());
|
||||||
|
b1.clear();
|
||||||
|
nb.put(b1);
|
||||||
|
b2.clear();
|
||||||
|
nb.put(b2);
|
||||||
|
nb.clear();
|
||||||
|
return nb;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the encoded triangle index/distance pairs in {@link #_tcodes}
|
* Sorts the encoded triangle index/distance pairs in {@link #_tcodes}
|
||||||
* using a two-pass (16 bit) radix sort (as described by
|
* using a two-pass (16 bit) radix sort (as described by
|
||||||
@@ -745,8 +805,29 @@ public class ModelMesh extends TriMesh
|
|||||||
new RenderState[RenderState.RS_MAX_STATE];
|
new RenderState[RenderState.RS_MAX_STATE];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The type of bounding volume that this mesh should use. */
|
/** A wrapper around an array of attributes that uses {@link Arrays#deepHashCode} and
|
||||||
protected int _boundingType;
|
* {@link Arrays#deepEquals} for hashing/comparison. */
|
||||||
|
protected static class AttributeKey
|
||||||
|
{
|
||||||
|
public AttributeKey (Object... attrs)
|
||||||
|
{
|
||||||
|
_attrs = attrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
public int hashCode ()
|
||||||
|
{
|
||||||
|
return Arrays.deepHashCode(_attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
public boolean equals (Object other)
|
||||||
|
{
|
||||||
|
return Arrays.deepEquals(_attrs, ((AttributeKey)other)._attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object[] _attrs;
|
||||||
|
}
|
||||||
|
|
||||||
/** The name of the texture specified in the model file, which acts as a
|
/** The name of the texture specified in the model file, which acts as a
|
||||||
* property key and a default value. */
|
* property key and a default value. */
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ import java.util.Set;
|
|||||||
import com.jme.bounding.BoundingBox;
|
import com.jme.bounding.BoundingBox;
|
||||||
import com.jme.bounding.BoundingSphere;
|
import com.jme.bounding.BoundingSphere;
|
||||||
import com.jme.math.FastMath;
|
import com.jme.math.FastMath;
|
||||||
|
import com.jme.math.Vector3f;
|
||||||
import com.jme.scene.Spatial;
|
import com.jme.scene.Spatial;
|
||||||
|
import com.jme.scene.batch.GeomBatch;
|
||||||
import com.jme.util.geom.BufferUtils;
|
import com.jme.util.geom.BufferUtils;
|
||||||
|
|
||||||
import com.samskivert.util.PropertiesUtil;
|
import com.samskivert.util.PropertiesUtil;
|
||||||
@@ -51,6 +53,7 @@ import com.threerings.jme.model.ModelController;
|
|||||||
import com.threerings.jme.model.ModelMesh;
|
import com.threerings.jme.model.ModelMesh;
|
||||||
import com.threerings.jme.model.ModelNode;
|
import com.threerings.jme.model.ModelNode;
|
||||||
import com.threerings.jme.model.SkinMesh;
|
import com.threerings.jme.model.SkinMesh;
|
||||||
|
import com.threerings.jme.util.SpatialVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An intermediate representation for models used to store data parsed from
|
* An intermediate representation for models used to store data parsed from
|
||||||
@@ -63,15 +66,15 @@ public class ModelDef
|
|||||||
{
|
{
|
||||||
/** The node's name. */
|
/** The node's name. */
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
/** The name of the node's parent. */
|
/** The name of the node's parent. */
|
||||||
public String parent;
|
public String parent;
|
||||||
|
|
||||||
/** The node's transformation. */
|
/** The node's transformation. */
|
||||||
public float[] translation;
|
public float[] translation;
|
||||||
public float[] rotation;
|
public float[] rotation;
|
||||||
public float[] scale;
|
public float[] scale;
|
||||||
|
|
||||||
/** Returns a JME node for this definition. */
|
/** Returns a JME node for this definition. */
|
||||||
public Spatial getSpatial (Properties props)
|
public Spatial getSpatial (Properties props)
|
||||||
{
|
{
|
||||||
@@ -82,7 +85,7 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
return _spatial;
|
return _spatial;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the transform of the created node. */
|
/** Sets the transform of the created node. */
|
||||||
protected void setTransform ()
|
protected void setTransform ()
|
||||||
{
|
{
|
||||||
@@ -92,10 +95,10 @@ public class ModelDef
|
|||||||
rotation[2], rotation[3]);
|
rotation[2], rotation[3]);
|
||||||
_spatial.getLocalScale().set(scale[0], scale[1], scale[2]);
|
_spatial.getLocalScale().set(scale[0], scale[1], scale[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a JME node for this definition. */
|
/** Creates a JME node for this definition. */
|
||||||
public abstract Spatial createSpatial (Properties props);
|
public abstract Spatial createSpatial (Properties props);
|
||||||
|
|
||||||
/** Resolves any name references using the supplied map. */
|
/** Resolves any name references using the supplied map. */
|
||||||
public void resolveReferences (
|
public void resolveReferences (
|
||||||
HashMap<String, Spatial> nodes, HashSet<Spatial> referenced)
|
HashMap<String, Spatial> nodes, HashSet<Spatial> referenced)
|
||||||
@@ -103,17 +106,17 @@ public class ModelDef
|
|||||||
Spatial pnode = nodes.get(parent);
|
Spatial pnode = nodes.get(parent);
|
||||||
if (pnode instanceof ModelNode) {
|
if (pnode instanceof ModelNode) {
|
||||||
((ModelNode)pnode).attachChild(_spatial);
|
((ModelNode)pnode).attachChild(_spatial);
|
||||||
|
|
||||||
} else if (parent != null) {
|
} else if (parent != null) {
|
||||||
Log.warning("Missing or invalid parent node [spatial=" +
|
Log.warning("Missing or invalid parent node [spatial=" +
|
||||||
name + ", parent=" + parent + "].");
|
name + ", parent=" + parent + "].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The JME node created for this definition. */
|
/** The JME node created for this definition. */
|
||||||
protected Spatial _spatial;
|
protected Spatial _spatial;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A rigid triangle mesh. */
|
/** A rigid triangle mesh. */
|
||||||
public static class TriMeshDef extends SpatialDef
|
public static class TriMeshDef extends SpatialDef
|
||||||
{
|
{
|
||||||
@@ -121,25 +124,25 @@ public class ModelDef
|
|||||||
public float[] offsetTranslation;
|
public float[] offsetTranslation;
|
||||||
public float[] offsetRotation;
|
public float[] offsetRotation;
|
||||||
public float[] offsetScale;
|
public float[] offsetScale;
|
||||||
|
|
||||||
/** Whether or not the mesh allows back face culling. */
|
/** Whether or not the mesh allows back face culling. */
|
||||||
public boolean solid;
|
public boolean solid;
|
||||||
|
|
||||||
/** The texture of the mesh, if any. */
|
/** The texture of the mesh, if any. */
|
||||||
public String texture;
|
public String texture;
|
||||||
|
|
||||||
/** Whether or not the mesh is (partially) transparent. */
|
/** Whether or not the mesh is (partially) transparent. */
|
||||||
public boolean transparent;
|
public boolean transparent;
|
||||||
|
|
||||||
/** The vertices of the mesh. */
|
/** The vertices of the mesh. */
|
||||||
public ArrayList<Vertex> vertices = new ArrayList<Vertex>();
|
public ArrayList<Vertex> vertices = new ArrayList<Vertex>();
|
||||||
|
|
||||||
/** The triangle indices. */
|
/** The triangle indices. */
|
||||||
public ArrayList<Integer> indices = new ArrayList<Integer>();
|
public ArrayList<Integer> indices = new ArrayList<Integer>();
|
||||||
|
|
||||||
/** Whether or not any of the vertices have texture coordinates. */
|
/** Whether or not any of the vertices have texture coordinates. */
|
||||||
public boolean tcoords;
|
public boolean tcoords;
|
||||||
|
|
||||||
public void addVertex (Vertex vertex)
|
public void addVertex (Vertex vertex)
|
||||||
{
|
{
|
||||||
int idx = vertices.indexOf(vertex);
|
int idx = vertices.indexOf(vertex);
|
||||||
@@ -151,7 +154,7 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
tcoords = tcoords || vertex.tcoords != null;
|
tcoords = tcoords || vertex.tcoords != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
public Spatial createSpatial (Properties props)
|
public Spatial createSpatial (Properties props)
|
||||||
{
|
{
|
||||||
@@ -163,13 +166,13 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates the mesh to attach to the node. */
|
/** Creates the mesh to attach to the node. */
|
||||||
protected ModelMesh createMesh ()
|
protected ModelMesh createMesh ()
|
||||||
{
|
{
|
||||||
return new ModelMesh("mesh");
|
return new ModelMesh("mesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Configures the mesh. */
|
/** Configures the mesh. */
|
||||||
protected void configureMesh (Properties props)
|
protected void configureMesh (Properties props)
|
||||||
{
|
{
|
||||||
@@ -186,17 +189,17 @@ public class ModelDef
|
|||||||
_mesh.getLocalScale().set(offsetScale[0], offsetScale[1],
|
_mesh.getLocalScale().set(offsetScale[0], offsetScale[1],
|
||||||
offsetScale[2]);
|
offsetScale[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure texture is just a filename
|
// make sure texture is just a filename
|
||||||
int sidx = (texture == null) ? -1 :
|
int sidx = (texture == null) ? -1 :
|
||||||
Math.max(texture.lastIndexOf('/'), texture.lastIndexOf('\\'));
|
Math.max(texture.lastIndexOf('/'), texture.lastIndexOf('\\'));
|
||||||
if (sidx != -1) {
|
if (sidx != -1) {
|
||||||
texture = texture.substring(sidx + 1);
|
texture = texture.substring(sidx + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure using properties
|
// configure using properties
|
||||||
_mesh.configure(solid, texture, transparent, props);
|
_mesh.configure(solid, texture, transparent, props);
|
||||||
|
|
||||||
// set the various buffers
|
// set the various buffers
|
||||||
int vsize = vertices.size();
|
int vsize = vertices.size();
|
||||||
FloatBuffer vbuf = BufferUtils.createVector3Buffer(vsize),
|
FloatBuffer vbuf = BufferUtils.createVector3Buffer(vsize),
|
||||||
@@ -210,19 +213,19 @@ public class ModelDef
|
|||||||
ibuf.put(indices.get(ii));
|
ibuf.put(indices.get(ii));
|
||||||
}
|
}
|
||||||
_mesh.reconstruct(vbuf, nbuf, null, tbuf, ibuf);
|
_mesh.reconstruct(vbuf, nbuf, null, tbuf, ibuf);
|
||||||
|
|
||||||
_mesh.setModelBound("sphere".equals(props.getProperty("bound")) ?
|
_mesh.setModelBound("sphere".equals(props.getProperty("bound")) ?
|
||||||
new BoundingSphere() : new BoundingBox());
|
new BoundingSphere() : new BoundingBox());
|
||||||
_mesh.updateModelBound();
|
_mesh.updateModelBound();
|
||||||
|
|
||||||
// set the mesh's origin to the center of its bounding box
|
// set the mesh's origin to the center of its bounding box
|
||||||
_mesh.centerVertices();
|
_mesh.centerVertices();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The mesh that contains the actual geometry. */
|
/** The mesh that contains the actual geometry. */
|
||||||
protected ModelMesh _mesh;
|
protected ModelMesh _mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A triangle mesh that deforms according to bone positions. */
|
/** A triangle mesh that deforms according to bone positions. */
|
||||||
public static class SkinMeshDef extends TriMeshDef
|
public static class SkinMeshDef extends TriMeshDef
|
||||||
{
|
{
|
||||||
@@ -231,7 +234,7 @@ public class ModelDef
|
|||||||
{
|
{
|
||||||
return new SkinMesh("mesh");
|
return new SkinMesh("mesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // documentation inherited
|
||||||
public void resolveReferences (
|
public void resolveReferences (
|
||||||
HashMap<String, Spatial> nodes, HashSet<Spatial> referenced)
|
HashMap<String, Spatial> nodes, HashSet<Spatial> referenced)
|
||||||
@@ -240,7 +243,7 @@ public class ModelDef
|
|||||||
if (_mesh == null) {
|
if (_mesh == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and set the final weight groups
|
// create and set the final weight groups
|
||||||
SkinMesh.WeightGroup[] wgroups =
|
SkinMesh.WeightGroup[] wgroups =
|
||||||
new SkinMesh.WeightGroup[_groups.size()];
|
new SkinMesh.WeightGroup[_groups.size()];
|
||||||
@@ -268,7 +271,7 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
((SkinMesh)_mesh).setWeightGroups(wgroups);
|
((SkinMesh)_mesh).setWeightGroups(wgroups);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // documentation inherited
|
||||||
protected void configureMesh (Properties props)
|
protected void configureMesh (Properties props)
|
||||||
{
|
{
|
||||||
@@ -286,7 +289,7 @@ public class ModelDef
|
|||||||
group.weights.add(svertex.boneWeights.get(bone).weight);
|
group.weights.add(svertex.boneWeights.get(bone).weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reorder the vertices by group
|
// reorder the vertices by group
|
||||||
ArrayList<Vertex> overts = vertices;
|
ArrayList<Vertex> overts = vertices;
|
||||||
vertices = new ArrayList<Vertex>();
|
vertices = new ArrayList<Vertex>();
|
||||||
@@ -301,14 +304,14 @@ public class ModelDef
|
|||||||
for (int ii = 0, nn = indices.size(); ii < nn; ii++) {
|
for (int ii = 0, nn = indices.size(); ii < nn; ii++) {
|
||||||
indices.set(ii, imap[indices.get(ii)]);
|
indices.set(ii, imap[indices.get(ii)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.configureMesh(props);
|
super.configureMesh(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The intermediate weight groups, mapped by bone names. */
|
/** The intermediate weight groups, mapped by bone names. */
|
||||||
protected HashMap<Set<String>, WeightGroupDef> _groups;
|
protected HashMap<Set<String>, WeightGroupDef> _groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A generic node. */
|
/** A generic node. */
|
||||||
public static class NodeDef extends SpatialDef
|
public static class NodeDef extends SpatialDef
|
||||||
{
|
{
|
||||||
@@ -318,20 +321,20 @@ public class ModelDef
|
|||||||
return new ModelNode(name);
|
return new ModelNode(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A basic vertex. */
|
/** A basic vertex. */
|
||||||
public static class Vertex
|
public static class Vertex
|
||||||
{
|
{
|
||||||
public float[] location;
|
public float[] location;
|
||||||
public float[] normal;
|
public float[] normal;
|
||||||
public float[] tcoords;
|
public float[] tcoords;
|
||||||
|
|
||||||
public void setInBuffers (
|
public void setInBuffers (
|
||||||
FloatBuffer vbuf, FloatBuffer nbuf, FloatBuffer tbuf)
|
FloatBuffer vbuf, FloatBuffer nbuf, FloatBuffer tbuf)
|
||||||
{
|
{
|
||||||
vbuf.put(location);
|
vbuf.put(location);
|
||||||
nbuf.put(normal);
|
nbuf.put(normal);
|
||||||
|
|
||||||
if (tbuf != null) {
|
if (tbuf != null) {
|
||||||
if (tcoords != null) {
|
if (tcoords != null) {
|
||||||
tbuf.put(tcoords);
|
tbuf.put(tcoords);
|
||||||
@@ -341,7 +344,7 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals (Object obj)
|
public boolean equals (Object obj)
|
||||||
{
|
{
|
||||||
Vertex overt = (Vertex)obj;
|
Vertex overt = (Vertex)obj;
|
||||||
@@ -350,14 +353,14 @@ public class ModelDef
|
|||||||
Arrays.equals(tcoords, overt.tcoords);
|
Arrays.equals(tcoords, overt.tcoords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A vertex influenced by a number of bones. */
|
/** A vertex influenced by a number of bones. */
|
||||||
public static class SkinVertex extends Vertex
|
public static class SkinVertex extends Vertex
|
||||||
{
|
{
|
||||||
/** The bones influencing the vertex, mapped by name. */
|
/** The bones influencing the vertex, mapped by name. */
|
||||||
public HashMap<String, BoneWeight> boneWeights =
|
public HashMap<String, BoneWeight> boneWeights =
|
||||||
new HashMap<String, BoneWeight>();
|
new HashMap<String, BoneWeight>();
|
||||||
|
|
||||||
public void addBoneWeight (BoneWeight weight)
|
public void addBoneWeight (BoneWeight weight)
|
||||||
{
|
{
|
||||||
if (weight.weight == 0f) {
|
if (weight.weight == 0f) {
|
||||||
@@ -370,7 +373,7 @@ public class ModelDef
|
|||||||
boneWeights.put(weight.bone, weight);
|
boneWeights.put(weight.bone, weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Finds the bone nodes influencing this vertex. */
|
/** Finds the bone nodes influencing this vertex. */
|
||||||
public HashSet<ModelNode> getBones (HashMap<String, Spatial> nodes)
|
public HashSet<ModelNode> getBones (HashMap<String, Spatial> nodes)
|
||||||
{
|
{
|
||||||
@@ -386,7 +389,7 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
return bones;
|
return bones;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the weight of the given bone. */
|
/** Returns the weight of the given bone. */
|
||||||
public float getWeight (ModelNode bone)
|
public float getWeight (ModelNode bone)
|
||||||
{
|
{
|
||||||
@@ -394,13 +397,13 @@ public class ModelDef
|
|||||||
return (bweight == null) ? 0f : bweight.weight;
|
return (bweight == null) ? 0f : bweight.weight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The influence of a bone on a vertex. */
|
/** The influence of a bone on a vertex. */
|
||||||
public static class BoneWeight
|
public static class BoneWeight
|
||||||
{
|
{
|
||||||
/** The name of the influencing bone. */
|
/** The name of the influencing bone. */
|
||||||
public String bone;
|
public String bone;
|
||||||
|
|
||||||
/** The amount of influence. */
|
/** The amount of influence. */
|
||||||
public float weight;
|
public float weight;
|
||||||
}
|
}
|
||||||
@@ -410,21 +413,21 @@ public class ModelDef
|
|||||||
{
|
{
|
||||||
/** The indices of the affected vertex. */
|
/** The indices of the affected vertex. */
|
||||||
public ArrayList<Integer> indices = new ArrayList<Integer>();
|
public ArrayList<Integer> indices = new ArrayList<Integer>();
|
||||||
|
|
||||||
/** The interleaved vertex weights. */
|
/** The interleaved vertex weights. */
|
||||||
public ArrayList<Float> weights = new ArrayList<Float>();
|
public ArrayList<Float> weights = new ArrayList<Float>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The meshes and bones comprising the model. */
|
/** The meshes and bones comprising the model. */
|
||||||
public ArrayList<SpatialDef> spatials = new ArrayList<SpatialDef>();
|
public ArrayList<SpatialDef> spatials = new ArrayList<SpatialDef>();
|
||||||
|
|
||||||
public void addSpatial (SpatialDef spatial)
|
public void addSpatial (SpatialDef spatial)
|
||||||
{
|
{
|
||||||
// put nodes before meshes so that bones are updated before skin
|
// put nodes before meshes so that bones are updated before skin
|
||||||
spatials.add(spatial instanceof NodeDef ? 0 : spatials.size(),
|
spatials.add(spatial instanceof NodeDef ? 0 : spatials.size(),
|
||||||
spatial);
|
spatial);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the model node defined herein.
|
* Creates the model node defined herein.
|
||||||
*
|
*
|
||||||
@@ -434,16 +437,13 @@ public class ModelDef
|
|||||||
public Model createModel (Properties props, HashMap<String, Spatial> nodes)
|
public Model createModel (Properties props, HashMap<String, Spatial> nodes)
|
||||||
{
|
{
|
||||||
Model model = new Model(props.getProperty("name", "model"), props);
|
Model model = new Model(props.getProperty("name", "model"), props);
|
||||||
|
|
||||||
// set the overall scale
|
|
||||||
model.setLocalScale(Float.parseFloat(props.getProperty("scale", "1")));
|
|
||||||
|
|
||||||
// start by creating the spatials and mapping them to their names
|
// start by creating the spatials and mapping them to their names
|
||||||
for (int ii = 0, nn = spatials.size(); ii < nn; ii++) {
|
for (int ii = 0, nn = spatials.size(); ii < nn; ii++) {
|
||||||
Spatial spatial = spatials.get(ii).getSpatial(props);
|
Spatial spatial = spatials.get(ii).getSpatial(props);
|
||||||
nodes.put(spatial.getName(), spatial);
|
nodes.put(spatial.getName(), spatial);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then go through again, resolving any name references and attaching
|
// then go through again, resolving any name references and attaching
|
||||||
// root children
|
// root children
|
||||||
HashSet<Spatial> referenced = new HashSet<Spatial>();
|
HashSet<Spatial> referenced = new HashSet<Spatial>();
|
||||||
@@ -454,12 +454,12 @@ public class ModelDef
|
|||||||
model.attachChild(sdef.getSpatial(props));
|
model.attachChild(sdef.getSpatial(props));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create any controllers listed
|
// create any controllers listed
|
||||||
String[] controllers = StringUtil.parseStringArray(
|
String[] controllers = StringUtil.parseStringArray(
|
||||||
props.getProperty("controllers", ""));
|
props.getProperty("controllers", ""));
|
||||||
for (int ii = 0; ii < controllers.length; ii++) {
|
for (int ii = 0; ii < controllers.length; ii++) {
|
||||||
Properties subProps =
|
Properties subProps =
|
||||||
PropertiesUtil.getSubProperties(props, controllers[ii]);
|
PropertiesUtil.getSubProperties(props, controllers[ii]);
|
||||||
String node = subProps.getProperty("node", controllers[ii]);
|
String node = subProps.getProperty("node", controllers[ii]);
|
||||||
Spatial target = node.equals(model.getName()) ?
|
Spatial target = node.equals(model.getName()) ?
|
||||||
@@ -471,15 +471,24 @@ public class ModelDef
|
|||||||
ModelController ctrl = createController(subProps, target);
|
ModelController ctrl = createController(subProps, target);
|
||||||
if (ctrl != null) {
|
if (ctrl != null) {
|
||||||
model.addController(ctrl);
|
model.addController(ctrl);
|
||||||
|
referenced.add(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in non-animated models, merge meshes with the same attributes
|
||||||
|
if (StringUtil.isBlank(props.getProperty("animations"))) {
|
||||||
|
mergeEquivalentMeshes(model, nodes, referenced);
|
||||||
|
}
|
||||||
|
|
||||||
// get rid of any nodes that serve no purpose
|
// get rid of any nodes that serve no purpose
|
||||||
pruneUnusedNodes(model, nodes, referenced);
|
pruneUnusedNodes(model, nodes, referenced);
|
||||||
|
|
||||||
|
// set the overall scale
|
||||||
|
model.setLocalScale(Float.parseFloat(props.getProperty("scale", "1")));
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates, configures, and returns a model controller. */
|
/** Creates, configures, and returns a model controller. */
|
||||||
protected ModelController createController (
|
protected ModelController createController (
|
||||||
Properties props, Spatial target)
|
Properties props, Spatial target)
|
||||||
@@ -497,7 +506,7 @@ public class ModelDef
|
|||||||
ctrl.configure(props, target);
|
ctrl.configure(props, target);
|
||||||
return ctrl;
|
return ctrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Recursively removes any unused nodes. */
|
/** Recursively removes any unused nodes. */
|
||||||
protected boolean pruneUnusedNodes (
|
protected boolean pruneUnusedNodes (
|
||||||
ModelNode node, HashMap<String, Spatial> nodes,
|
ModelNode node, HashMap<String, Spatial> nodes,
|
||||||
@@ -516,7 +525,66 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
return referenced.contains(node) || hasValidChildren;
|
return referenced.contains(node) || hasValidChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Merges meshes with the same attributes. */
|
||||||
|
protected void mergeEquivalentMeshes (
|
||||||
|
Model model, HashMap<String, Spatial> nodes, final HashSet<Spatial> referenced)
|
||||||
|
{
|
||||||
|
final HashMap<Object, ArrayList<ModelMesh>> meshes =
|
||||||
|
new HashMap<Object, ArrayList<ModelMesh>>();
|
||||||
|
new SpatialVisitor<ModelMesh>(ModelMesh.class) {
|
||||||
|
public void traverse (Spatial spatial) {
|
||||||
|
// cut out when we encounter referenced nodes
|
||||||
|
if (!referenced.contains(spatial)) {
|
||||||
|
spatial.updateWorldVectors();
|
||||||
|
super.traverse(spatial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected void visit (ModelMesh mesh) {
|
||||||
|
// make sure we don't try this with skinned meshes
|
||||||
|
if (mesh instanceof SkinMesh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Object key = mesh.getAttributeKey();
|
||||||
|
ArrayList<ModelMesh> list = meshes.get(key);
|
||||||
|
if (list == null) {
|
||||||
|
meshes.put(key, list = new ArrayList<ModelMesh>());
|
||||||
|
}
|
||||||
|
list.add(mesh);
|
||||||
|
}
|
||||||
|
}.traverse(model);
|
||||||
|
|
||||||
|
for (ArrayList<ModelMesh> list : meshes.values()) {
|
||||||
|
// the first in the list becomes the base
|
||||||
|
ModelMesh base = list.get(0);
|
||||||
|
flattenTransforms(base);
|
||||||
|
model.attachChild(base);
|
||||||
|
|
||||||
|
// the rest are merged with it
|
||||||
|
for (int ii = 1, nn = list.size(); ii < nn; ii++) {
|
||||||
|
ModelMesh mesh = list.get(ii);
|
||||||
|
flattenTransforms(mesh);
|
||||||
|
mesh.getParent().detachChild(mesh);
|
||||||
|
base.merge(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the model bound and recenter
|
||||||
|
base.updateModelBound();
|
||||||
|
base.centerVertices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Transforms the mesh's vertices and normals into model coordinates. */
|
||||||
|
protected static void flattenTransforms (ModelMesh mesh)
|
||||||
|
{
|
||||||
|
GeomBatch batch = mesh.getBatch(0);
|
||||||
|
batch.getWorldCoords(batch.getVertexBuffer());
|
||||||
|
batch.getWorldNormals(batch.getNormalBuffer());
|
||||||
|
mesh.getLocalTranslation().zero();
|
||||||
|
mesh.getLocalRotation().loadIdentity();
|
||||||
|
mesh.getLocalScale().set(Vector3f.UNIT_XYZ);
|
||||||
|
}
|
||||||
|
|
||||||
/** Converts a boxed Integer list to an unboxed int array. */
|
/** Converts a boxed Integer list to an unboxed int array. */
|
||||||
protected static int[] toArray (ArrayList<Integer> list)
|
protected static int[] toArray (ArrayList<Integer> list)
|
||||||
{
|
{
|
||||||
@@ -526,7 +594,7 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts a boxed Float list to an unboxed float array. */
|
/** Converts a boxed Float list to an unboxed float array. */
|
||||||
protected static float[] toArray (ArrayList<Float> list)
|
protected static float[] toArray (ArrayList<Float> list)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user