diff --git a/src/java/com/threerings/jme/model/EmissionController.java b/src/java/com/threerings/jme/model/EmissionController.java
index 8512b9871..73e22bc0f 100644
--- a/src/java/com/threerings/jme/model/EmissionController.java
+++ b/src/java/com/threerings/jme/model/EmissionController.java
@@ -58,7 +58,7 @@ public abstract class EmissionController extends ModelController
*/
protected void getEmitterLocation (Vector3f result)
{
- result.set(_target.getWorldBound().getCenter());
+ result.set(_target.getWorldTranslation());
}
/**
diff --git a/src/java/com/threerings/jme/model/Model.java b/src/java/com/threerings/jme/model/Model.java
index 52e4350ba..c9fb6e2a1 100644
--- a/src/java/com/threerings/jme/model/Model.java
+++ b/src/java/com/threerings/jme/model/Model.java
@@ -233,10 +233,8 @@ public class Model extends ModelNode
FileChannel fc = fis.getChannel();
if (map) {
long pos = fc.position();
- MappedByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY,
- pos, fc.size() - pos);
- buf.order(ByteOrder.LITTLE_ENDIAN);
- model.sliceBuffers(buf);
+ model.sliceBuffers(fc.map(FileChannel.MapMode.READ_ONLY,
+ pos, fc.size() - pos));
} else {
model.readBuffers(fc);
}
@@ -343,6 +341,9 @@ public class Model extends ModelNode
*/
public Animation getAnimation (String name)
{
+ if (_anims == null) {
+ return null;
+ }
Animation anim = _anims.get(name);
if (anim != null) {
return anim;
diff --git a/src/java/com/threerings/jme/model/ModelMesh.java b/src/java/com/threerings/jme/model/ModelMesh.java
index b6cd2737c..99ab60ee0 100644
--- a/src/java/com/threerings/jme/model/ModelMesh.java
+++ b/src/java/com/threerings/jme/model/ModelMesh.java
@@ -128,25 +128,18 @@ public class ModelMesh extends TriMesh
// initialize the model if we're displaying
if (DisplaySystem.getDisplaySystem() == null) {
return;
- }
+ }
if (_backCull == null) {
initSharedStates();
}
if (_solid) {
setRenderState(_backCull);
- } else {
- setRenderState(_noCull);
}
if (_transparent) {
setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
setRenderState(_blendAlpha);
setRenderState(_overlayZBuffer);
- } else {
- setRenderQueueMode(Renderer.QUEUE_OPAQUE);
- setRenderState(_noAlpha);
- setRenderState(_lequalZBuffer);
}
- setTextureCombineMode(TextureState.REPLACE);
}
/**
@@ -432,15 +425,11 @@ public class ModelMesh extends TriMesh
Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer();
_backCull = renderer.createCullState();
_backCull.setCullMode(CullState.CS_BACK);
- _noCull = renderer.createCullState();
_blendAlpha = renderer.createAlphaState();
_blendAlpha.setBlendEnabled(true);
- _noAlpha = renderer.createAlphaState();
_overlayZBuffer = renderer.createZBufferState();
_overlayZBuffer.setFunction(ZBufferState.CF_LEQUAL);
_overlayZBuffer.setWritable(false);
- _lequalZBuffer = renderer.createZBufferState();
- _lequalZBuffer.setFunction(ZBufferState.CF_LEQUAL);
}
/** The sizes of the various buffers (zero for null). */
@@ -469,21 +458,12 @@ public class ModelMesh extends TriMesh
/** The shared state for back face culling. */
protected static CullState _backCull;
- /** The shared state for no back face culling. */
- protected static CullState _noCull;
-
/** The shared state for alpha blending. */
protected static AlphaState _blendAlpha;
- /** The shared state for no blending. */
- protected static AlphaState _noAlpha;
-
/** The shared state for checking, but not writing to, the z buffer. */
protected static ZBufferState _overlayZBuffer;
- /** The shared state for checking and writing to the z buffer. */
- protected static ZBufferState _lequalZBuffer;
-
/** Indicates that this mesh should use a bounding box. */
protected static final int BOX_BOUND = 0;
diff --git a/src/java/com/threerings/jme/tools/ModelDef.java b/src/java/com/threerings/jme/tools/ModelDef.java
index b6c9c0a60..a4fc29bdb 100644
--- a/src/java/com/threerings/jme/tools/ModelDef.java
+++ b/src/java/com/threerings/jme/tools/ModelDef.java
@@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
@@ -90,11 +91,13 @@ public class ModelDef
public abstract Spatial createSpatial (Properties props);
/** Resolves any name references using the supplied map. */
- public void resolveReferences (HashMap nodes)
+ public void resolveReferences (
+ HashMap nodes, HashSet referenced)
{
Spatial pnode = nodes.get(parent);
if (pnode instanceof ModelNode) {
((ModelNode)pnode).attachChild(_spatial);
+
} else if (parent != null) {
Log.warning("Missing or invalid parent node [spatial=" +
name + ", parent=" + parent + "].");
@@ -226,9 +229,10 @@ public class ModelDef
}
@Override // documentation inherited
- public void resolveReferences (HashMap nodes)
+ public void resolveReferences (
+ HashMap nodes, HashSet referenced)
{
- super.resolveReferences(nodes);
+ super.resolveReferences(nodes, referenced);
if (_mesh == null) {
return;
}
@@ -258,6 +262,7 @@ public class ModelDef
SkinMesh.WeightGroup wgroup = new SkinMesh.WeightGroup();
wgroup.indices = toArray(entry.getValue().indices);
HashSet bones = entry.getKey();
+ referenced.addAll(bones);
wgroup.bones = bones.toArray(new ModelNode[bones.size()]);
wgroup.weights = toArray(entry.getValue().weights);
wgroups[ii++] = wgroup;
@@ -403,9 +408,10 @@ public class ModelDef
// then go through again, resolving any name references and attaching
// root children
+ HashSet referenced = new HashSet();
for (int ii = 0, nn = spatials.size(); ii < nn; ii++) {
SpatialDef sdef = spatials.get(ii);
- sdef.resolveReferences(nodes);
+ sdef.resolveReferences(nodes, referenced);
if (sdef.getSpatial(props).getParent() == null) {
model.attachChild(sdef.getSpatial(props));
}
@@ -429,6 +435,9 @@ public class ModelDef
}
}
+ // get rid of any nodes that serve no purpose
+ pruneUnusedNodes(model, referenced);
+
return model;
}
@@ -450,6 +459,23 @@ public class ModelDef
return ctrl;
}
+ /** Recursively removes any unused nodes. */
+ protected boolean pruneUnusedNodes (
+ ModelNode node, HashSet referenced)
+ {
+ boolean hasValidChildren = false;
+ for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) {
+ Spatial child = (Spatial)it.next();
+ if (!(child instanceof ModelNode) ||
+ pruneUnusedNodes((ModelNode)child, referenced)) {
+ hasValidChildren = true;
+ } else {
+ it.remove();
+ }
+ }
+ return referenced.contains(node) || hasValidChildren;
+ }
+
/** Converts a boxed Integer list to an unboxed int array. */
protected static int[] toArray (ArrayList list)
{