Misc. fixes, added random texture selection to models.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4073 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Andrzej Kapolka
2006-04-28 01:47:49 +00:00
parent d8f7e48cbf
commit 33ab4146c8
8 changed files with 153 additions and 61 deletions
+1
View File
@@ -10,6 +10,7 @@ m.file_load = Load Model...
m.file_quit = Quit m.file_quit = Quit
m.view_menu = View m.view_menu = View
m.view_wireframe = Wireframe
m.view_pivots = Show Pivots m.view_pivots = Show Pivots
m.view_bounds = Show Bounds m.view_bounds = Show Bounds
m.view_normals = Show Normals m.view_normals = Show Normals
@@ -21,6 +21,8 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.util.Properties;
import com.jme.math.Vector3f; import com.jme.math.Vector3f;
import com.jme.scene.Geometry; import com.jme.scene.Geometry;
import com.jme.scene.Spatial; import com.jme.scene.Spatial;
@@ -31,6 +33,19 @@ import com.jme.util.geom.BufferUtils;
*/ */
public abstract class EmissionController extends ModelController public abstract class EmissionController extends ModelController
{ {
@Override // documentation inherited
public void configure (Properties props, Spatial target)
{
// substitute underlying mesh for geometry targets
if (target instanceof ModelNode) {
Spatial mesh = ((ModelNode)target).getChild("mesh");
if (mesh != null) {
target = mesh;
}
}
super.configure(props, target);
}
@Override // documentation inherited @Override // documentation inherited
public void init (Model model) public void init (Model model)
{ {
@@ -59,4 +74,6 @@ public abstract class EmissionController extends ModelController
} }
_target.getWorldRotation().multLocal(result); _target.getWorldRotation().multLocal(result);
} }
private static final long serialVersionUID = 1;
} }
+47 -19
View File
@@ -49,6 +49,8 @@ import com.jme.scene.Controller;
import com.jme.scene.Node; import com.jme.scene.Node;
import com.jme.scene.Spatial; import com.jme.scene.Spatial;
import com.threerings.util.RandomUtil;
import com.threerings.jme.Log; import com.threerings.jme.Log;
/** /**
@@ -475,24 +477,7 @@ public class Model extends ModelNode
return _prototype.createInstance(); return _prototype.createInstance();
} }
if (_ccreator == null) { if (_ccreator == null) {
// allow adding and removing properties at any time _ccreator = new ModelCloneCreator(this);
_ccreator = new CloneCreator(this) {
public void addProperty (String name) {
props.put(name, Boolean.TRUE);
}
public void removeProperty (String name) {
props.remove(name);
}
};
_ccreator.addProperty("vertices");
_ccreator.addProperty("colors");
_ccreator.addProperty("normals");
_ccreator.addProperty("texcoords");
_ccreator.addProperty("vboinfo");
_ccreator.addProperty("indices");
_ccreator.addProperty("obbtree");
_ccreator.addProperty("displaylistid");
_ccreator.addProperty("bound");
} }
Model instance = (Model)_ccreator.createCopy(); Model instance = (Model)_ccreator.createCopy();
instance.initInstance(); instance.initInstance();
@@ -599,7 +584,7 @@ public class Model extends ModelNode
/** For prototype models, a customized clone creator used to generate /** For prototype models, a customized clone creator used to generate
* instances. */ * instances. */
protected CloneCreator _ccreator; protected ModelCloneCreator _ccreator;
/** For instances, maps prototype nodes to their corresponding instance /** For instances, maps prototype nodes to their corresponding instance
* nodes. */ * nodes. */
@@ -645,6 +630,7 @@ public class Model extends ModelNode
_name = name; _name = name;
} }
// documentation inherited from interface ObserverOp
public boolean apply (AnimationObserver obs) public boolean apply (AnimationObserver obs)
{ {
return obs.animationStarted(Model.this, _name); return obs.animationStarted(Model.this, _name);
@@ -663,6 +649,7 @@ public class Model extends ModelNode
_name = name; _name = name;
} }
// documentation inherited from interface ObserverOp
public boolean apply (AnimationObserver obs) public boolean apply (AnimationObserver obs)
{ {
return obs.animationCompleted(Model.this, _name); return obs.animationCompleted(Model.this, _name);
@@ -681,6 +668,7 @@ public class Model extends ModelNode
_name = name; _name = name;
} }
// documentation inherited from interface ObserverOp
public boolean apply (AnimationObserver obs) public boolean apply (AnimationObserver obs)
{ {
return obs.animationCancelled(Model.this, _name); return obs.animationCancelled(Model.this, _name);
@@ -690,5 +678,45 @@ public class Model extends ModelNode
protected String _name; protected String _name;
} }
/** Customized clone creator for models. */
protected static class ModelCloneCreator extends CloneCreator
{
/** A shared seed used to select textures consistently. */
public int random;
public ModelCloneCreator (Model toCopy)
{
super(toCopy);
addProperty("vertices");
addProperty("colors");
addProperty("normals");
addProperty("texcoords");
addProperty("vboinfo");
addProperty("indices");
addProperty("obbtree");
addProperty("displaylistid");
addProperty("bound");
}
@Override // documentation inherited
public void addProperty (String name)
{
props.put(name, Boolean.TRUE);
}
@Override // documentation inherited
public void removeProperty (String name)
{
props.remove(name);
}
@Override // documentation inherited
public Spatial createCopy ()
{
random = RandomUtil.getInt(Integer.MAX_VALUE);
return super.createCopy();
}
}
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
} }
@@ -49,12 +49,7 @@ public abstract class ModelController extends Controller
*/ */
public void configure (Properties props, Spatial target) public void configure (Properties props, Spatial target)
{ {
if (target instanceof ModelNode) { _target = target;
_target = ((ModelNode)target).getChild("mesh");
}
if (_target == null) {
_target = target;
}
String[] anims = StringUtil.parseStringArray( String[] anims = StringUtil.parseStringArray(
props.getProperty("animations", "")); props.getProperty("animations", ""));
if (anims.length == 0) { if (anims.length == 0) {
@@ -156,4 +151,6 @@ public abstract class ModelController extends Controller
return true; return true;
} }
}; };
private static final long serialVersionUID = 1;
} }
@@ -52,6 +52,8 @@ import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem; import com.jme.system.DisplaySystem;
import com.jme.util.geom.BufferUtils; import com.jme.util.geom.BufferUtils;
import com.samskivert.util.StringUtil;
import com.threerings.jme.Log; import com.threerings.jme.Log;
/** /**
@@ -80,7 +82,7 @@ public class ModelMesh extends TriMesh
* Configures this mesh based on the given parameters and (sub-)properties. * Configures this mesh based on the given parameters and (sub-)properties.
* *
* @param texture the texture specified in the model export, if any (can be * @param texture the texture specified in the model export, if any (can be
* overridden by a texture specified in the properties) * overridden by textures specified in the properties)
* @param solid whether or not the mesh allows back face culling * @param solid whether or not the mesh allows back face culling
* @param transparent whether or not the mesh is (partially) transparent * @param transparent whether or not the mesh is (partially) transparent
*/ */
@@ -89,8 +91,8 @@ public class ModelMesh extends TriMesh
{ {
_boundingType = "sphere".equals(props.getProperty("bound")) ? _boundingType = "sphere".equals(props.getProperty("bound")) ?
SPHERE_BOUND : BOX_BOUND; SPHERE_BOUND : BOX_BOUND;
_texture = (texture == null) ? null : _textures = (texture == null) ? null : StringUtil.parseStringArray(
props.getProperty(texture, texture); props.getProperty(texture, texture));
_solid = solid; _solid = solid;
_transparent = transparent; _transparent = transparent;
} }
@@ -132,12 +134,19 @@ public class ModelMesh extends TriMesh
} }
if (_solid) { if (_solid) {
setRenderState(_backCull); setRenderState(_backCull);
} else {
setRenderState(_noCull);
} }
if (_transparent) { if (_transparent) {
setRenderQueueMode(Renderer.QUEUE_TRANSPARENT); setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
setRenderState(_blendAlpha); setRenderState(_blendAlpha);
setRenderState(_overlayZBuffer); setRenderState(_overlayZBuffer);
} else {
setRenderQueueMode(Renderer.QUEUE_OPAQUE);
setRenderState(_noAlpha);
setRenderState(_lequalZBuffer);
} }
setTextureCombineMode(TextureState.REPLACE);
} }
/** /**
@@ -146,14 +155,12 @@ public class ModelMesh extends TriMesh
*/ */
public void centerVertices () public void centerVertices ()
{ {
Vector3f offset = getLocalTranslation().subtract( Vector3f offset = getModelBound().getCenter().negate();
getModelBound().getCenter()); if (!offset.equals(Vector3f.ZERO)) {
FloatBuffer vbuf = getVertexBuffer(); getLocalTranslation().subtractLocal(offset);
for (int ii = 0, nn = getVertexCount(); ii < nn; ii++) { getModelBound().getCenter().set(Vector3f.ZERO);
BufferUtils.addInBuffer(offset, vbuf, ii); getBatch().translatePoints(offset);
} }
getLocalTranslation().subtractLocal(offset);
getModelBound().getCenter().zero();
} }
@Override // documentation inherited @Override // documentation inherited
@@ -199,7 +206,17 @@ public class ModelMesh extends TriMesh
if (properties.isSet("bound")) { if (properties.isSet("bound")) {
mstore.setModelBound(getModelBound()); mstore.setModelBound(getModelBound());
} }
mstore._texture = _texture; if (_textures != null && _textures.length > 1 &&
properties instanceof Model.ModelCloneCreator) {
int tidx = ((Model.ModelCloneCreator)properties).random %
_textures.length;
mstore._textures = new String[] { _textures[tidx] };
mstore._tstates = new TextureState[] { _tstates[tidx] };
mstore.setRenderState(_tstates[tidx]);
} else {
mstore._textures = _textures;
mstore._tstates = _tstates;
}
return mstore; return mstore;
} }
@@ -217,7 +234,7 @@ public class ModelMesh extends TriMesh
out.writeInt(_textureBufferSize); out.writeInt(_textureBufferSize);
out.writeInt(_indexBufferSize); out.writeInt(_indexBufferSize);
out.writeInt(_boundingType); out.writeInt(_boundingType);
out.writeObject(_texture); out.writeObject(_textures);
out.writeBoolean(_solid); out.writeBoolean(_solid);
out.writeBoolean(_transparent); out.writeBoolean(_transparent);
} }
@@ -236,7 +253,7 @@ public class ModelMesh extends TriMesh
_textureBufferSize = in.readInt(); _textureBufferSize = in.readInt();
_indexBufferSize = in.readInt(); _indexBufferSize = in.readInt();
_boundingType = in.readInt(); _boundingType = in.readInt();
_texture = (String)in.readObject(); _textures = (String[])in.readObject();
_solid = in.readBoolean(); _solid = in.readBoolean();
_transparent = in.readBoolean(); _transparent = in.readBoolean();
} }
@@ -264,11 +281,15 @@ public class ModelMesh extends TriMesh
// documentation inherited from interface ModelSpatial // documentation inherited from interface ModelSpatial
public void resolveTextures (TextureProvider tprov) public void resolveTextures (TextureProvider tprov)
{ {
if (_texture != null) { if (_textures == null) {
TextureState tstate = tprov.getTexture(_texture); return;
if (tstate != null) { }
setRenderState(tstate); _tstates = new TextureState[_textures.length];
} for (int ii = 0; ii < _textures.length; ii++) {
_tstates[ii] = tprov.getTexture(_textures[ii]);
}
if (_tstates[0] != null) {
setRenderState(_tstates[0]);
} }
} }
@@ -357,31 +378,31 @@ public class ModelMesh extends TriMesh
if (_vertexBufferSize > 0) { if (_vertexBufferSize > 0) {
int npos = map.position() + _vertexBufferSize*4; int npos = map.position() + _vertexBufferSize*4;
map.limit(npos); map.limit(npos);
vbbuf = map.slice(); vbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos); map.position(npos);
} }
if (_normalBufferSize > 0) { if (_normalBufferSize > 0) {
int npos = map.position() + _normalBufferSize*4; int npos = map.position() + _normalBufferSize*4;
map.limit(npos); map.limit(npos);
nbbuf = map.slice(); nbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos); map.position(npos);
} }
if (_colorBufferSize > 0) { if (_colorBufferSize > 0) {
int npos = map.position() + _colorBufferSize*4; int npos = map.position() + _colorBufferSize*4;
map.limit(npos); map.limit(npos);
cbbuf = map.slice(); cbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos); map.position(npos);
} }
if (_textureBufferSize > 0) { if (_textureBufferSize > 0) {
int npos = map.position() + _textureBufferSize*4; int npos = map.position() + _textureBufferSize*4;
map.limit(npos); map.limit(npos);
tbbuf = map.slice(); tbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos); map.position(npos);
} }
if (_indexBufferSize > 0) { if (_indexBufferSize > 0) {
int npos = map.position() + _indexBufferSize*4; int npos = map.position() + _indexBufferSize*4;
map.limit(npos); map.limit(npos);
ibbuf = map.slice(); ibbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos); map.position(npos);
} }
reconstruct(vbbuf, nbbuf, cbbuf, tbbuf, ibbuf); reconstruct(vbbuf, nbbuf, cbbuf, tbbuf, ibbuf);
@@ -411,11 +432,15 @@ public class ModelMesh extends TriMesh
Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer(); Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer();
_backCull = renderer.createCullState(); _backCull = renderer.createCullState();
_backCull.setCullMode(CullState.CS_BACK); _backCull.setCullMode(CullState.CS_BACK);
_noCull = renderer.createCullState();
_blendAlpha = renderer.createAlphaState(); _blendAlpha = renderer.createAlphaState();
_blendAlpha.setBlendEnabled(true); _blendAlpha.setBlendEnabled(true);
_noAlpha = renderer.createAlphaState();
_overlayZBuffer = renderer.createZBufferState(); _overlayZBuffer = renderer.createZBufferState();
_overlayZBuffer.setFunction(ZBufferState.CF_LEQUAL); _overlayZBuffer.setFunction(ZBufferState.CF_LEQUAL);
_overlayZBuffer.setWritable(false); _overlayZBuffer.setWritable(false);
_lequalZBuffer = renderer.createZBufferState();
_lequalZBuffer.setFunction(ZBufferState.CF_LEQUAL);
} }
/** The sizes of the various buffers (zero for <code>null</code>). */ /** The sizes of the various buffers (zero for <code>null</code>). */
@@ -429,8 +454,8 @@ public class ModelMesh extends TriMesh
/** The type of bounding volume that this mesh should use. */ /** The type of bounding volume that this mesh should use. */
protected int _boundingType; protected int _boundingType;
/** The name of this model's texture, or <code>null</code> for none. */ /** The name of this model's textures, or <code>null</code> for none. */
protected String _texture; protected String[] _textures;
/** Whether or not this mesh can enable back-face culling. */ /** Whether or not this mesh can enable back-face culling. */
protected boolean _solid; protected boolean _solid;
@@ -438,15 +463,27 @@ public class ModelMesh extends TriMesh
/** Whether or not this mesh must be rendered as transparent. */ /** Whether or not this mesh must be rendered as transparent. */
protected boolean _transparent; protected boolean _transparent;
/** The shared state for back-face culling. */ /** For prototype meshes, the resolved texture states. */
protected TextureState[] _tstates;
/** The shared state for back face culling. */
protected static CullState _backCull; protected static CullState _backCull;
/** The shared state for no back face culling. */
protected static CullState _noCull;
/** The shared state for alpha blending. */ /** The shared state for alpha blending. */
protected static AlphaState _blendAlpha; 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. */ /** The shared state for checking, but not writing to, the z buffer. */
protected static ZBufferState _overlayZBuffer; 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. */ /** Indicates that this mesh should use a bounding box. */
protected static final int BOX_BOUND = 0; protected static final int BOX_BOUND = 0;
@@ -123,4 +123,6 @@ public class Rotator extends ModelController
/** A temporary quaternion. */ /** A temporary quaternion. */
protected Quaternion _rot = new Quaternion(); protected Quaternion _rot = new Quaternion();
private static final long serialVersionUID = 1;
} }
@@ -287,15 +287,6 @@ public class ModelDef
FloatBuffer vbuf, FloatBuffer nbuf, FloatBuffer tbuf) FloatBuffer vbuf, FloatBuffer nbuf, FloatBuffer tbuf)
{ {
vbuf.put(location); vbuf.put(location);
// make sure the normal is normalized
float nlen = FastMath.sqrt(normal[0]*normal[0] +
normal[1]*normal[1] + normal[2]*normal[2]);
if (nlen != 1f) {
normal[0] /= nlen;
normal[1] /= nlen;
normal[2] /= nlen;
}
nbuf.put(normal); nbuf.put(normal);
if (tbuf != null) { if (tbuf != null) {
@@ -74,6 +74,7 @@ import com.jme.scene.Spatial;
import com.jme.scene.state.LightState; import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState; import com.jme.scene.state.MaterialState;
import com.jme.scene.state.TextureState; import com.jme.scene.state.TextureState;
import com.jme.scene.state.WireframeState;
import com.jme.scene.state.ZBufferState; import com.jme.scene.state.ZBufferState;
import com.jme.util.LoggingSystem; import com.jme.util.LoggingSystem;
import com.jme.util.TextureManager; import com.jme.util.TextureManager;
@@ -153,6 +154,18 @@ public class ModelViewer extends JmeCanvasApp
JMenu view = new JMenu(_msg.get("m.view_menu")); JMenu view = new JMenu(_msg.get("m.view_menu"));
view.setMnemonic(KeyEvent.VK_V); view.setMnemonic(KeyEvent.VK_V);
menu.add(view); menu.add(view);
Action wireframe = new AbstractAction(_msg.get("m.view_wireframe")) {
public void actionPerformed (ActionEvent e) {
_wfstate.setEnabled(!_wfstate.isEnabled());
}
};
wireframe.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_W);
wireframe.putValue(Action.ACCELERATOR_KEY,
KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_MASK));
view.add(new JCheckBoxMenuItem(wireframe));
view.addSeparator();
_pivots = new JCheckBoxMenuItem(_msg.get("m.view_pivots")); _pivots = new JCheckBoxMenuItem(_msg.get("m.view_pivots"));
_pivots.setMnemonic(KeyEvent.VK_P); _pivots.setMnemonic(KeyEvent.VK_P);
_pivots.setAccelerator( _pivots.setAccelerator(
@@ -252,11 +265,14 @@ public class ModelViewer extends JmeCanvasApp
{ {
super.initRoot(); super.initRoot();
// set a default material // set default states
MaterialState mstate = _ctx.getRenderer().createMaterialState(); MaterialState mstate = _ctx.getRenderer().createMaterialState();
mstate.getDiffuse().set(ColorRGBA.white); mstate.getDiffuse().set(ColorRGBA.white);
mstate.getAmbient().set(ColorRGBA.white); mstate.getAmbient().set(ColorRGBA.white);
_ctx.getGeometry().setRenderState(mstate); _ctx.getGeometry().setRenderState(mstate);
_ctx.getGeometry().setRenderState(
_wfstate = _ctx.getRenderer().createWireframeState());
_wfstate.setEnabled(false);
// create a grid on the XY plane to provide some reference // create a grid on the XY plane to provide some reference
Vector3f[] points = new Vector3f[GRID_SIZE*2 + GRID_SIZE*2]; Vector3f[] points = new Vector3f[GRID_SIZE*2 + GRID_SIZE*2];
@@ -524,6 +540,9 @@ public class ModelViewer extends JmeCanvasApp
/** The model file chooser. */ /** The model file chooser. */
protected JFileChooser _chooser; protected JFileChooser _chooser;
/** Used to toggle wireframe rendering. */
protected WireframeState _wfstate;
/** The currently loaded model. */ /** The currently loaded model. */
protected Model _model; protected Model _model;