Switch to using JME's serialization mechanism, which promises a degree

of version safety (meaning we won't necessarily have to recompile all 
the models when we add a new field) and should help avoid the frequent 
binary changes to which Java serialization is prone.


git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@71 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Andrzej Kapolka
2006-11-07 03:14:35 +00:00
parent 04a833f169
commit 09627624c6
10 changed files with 350 additions and 482 deletions
@@ -22,13 +22,15 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Properties; import java.util.Properties;
import com.jme.scene.Controller; import com.jme.scene.Controller;
import com.jme.scene.Spatial; import com.jme.scene.Spatial;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
/** /**
* A model controller whose target represents an emitter. * A model controller whose target represents an emitter.
@@ -71,19 +73,21 @@ public abstract class EmissionController extends ModelController
} }
@Override // documentation inherited @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException throws IOException
{ {
super.writeExternal(out); super.read(im);
out.writeBoolean(_hideTarget); InputCapsule capsule = im.getCapsule(this);
_hideTarget = capsule.readBoolean("hideTarget", true);
} }
@Override // documentation inherited @Override // documentation inherited
public void readExternal (ObjectInput in) public void write (JMEExporter ex)
throws IOException, ClassNotFoundException throws IOException
{ {
super.readExternal(in); super.write(ex);
_hideTarget = in.readBoolean(); OutputCapsule capsule = ex.getCapsule(this);
capsule.write(_hideTarget, "hideTarget", true);
} }
/** Whether or not the target should be hidden from view. */ /** Whether or not the target should be hidden from view. */
+124 -87
View File
@@ -21,20 +21,15 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.nio.ByteOrder; import java.nio.FloatBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -52,6 +47,13 @@ import com.jme.renderer.Renderer;
import com.jme.scene.Controller; 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.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
import com.jme.util.export.Savable;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.export.binary.BinaryImporter;
import com.samskivert.util.ObserverList; import com.samskivert.util.ObserverList;
import com.samskivert.util.PropertiesUtil; import com.samskivert.util.PropertiesUtil;
@@ -99,7 +101,7 @@ public class Model extends ModelNode
/** An animation for the model. */ /** An animation for the model. */
public static class Animation public static class Animation
implements Serializable implements Savable
{ {
/** The rate of the animation in frames per second. */ /** The rate of the animation in frames per second. */
public int frameRate; public int frameRate;
@@ -171,30 +173,52 @@ public class Model extends ModelNode
} }
} }
private void writeObject (ObjectOutputStream out) // documentation inherited
public Class getClassTag ()
{
return getClass();
}
// documentation inherited
public void read (JMEImporter im)
throws IOException throws IOException
{ {
out.defaultWriteObject(); InputCapsule capsule = im.getCapsule(this);
out.writeInt(transforms.length); frameRate = capsule.readInt("frameRate", 0);
repeatType = capsule.readInt("repeatType", Controller.RT_CLAMP);
Savable[] ttargs = capsule.readSavableArray(
"transformTargets", null);
transformTargets = new Spatial[ttargs.length];
System.arraycopy(ttargs, 0, transformTargets, 0, ttargs.length);
FloatBuffer pxforms = capsule.readFloatBuffer("transforms", null);
transforms = new Transform[pxforms.capacity() /
Transform.PACKED_SIZE / transformTargets.length][];
for (int ii = 0; ii < transforms.length; ii++) { for (int ii = 0; ii < transforms.length; ii++) {
for (int jj = 0; jj < transformTargets.length; jj++) { Transform[] frame = transforms[ii] =
transforms[ii][jj].writeExternal(out); new Transform[transformTargets.length];
for (int jj = 0; jj < frame.length; jj++) {
frame[jj] = new Transform(pxforms);
} }
} }
} }
private void readObject (ObjectInputStream in) // documentation inherited
throws IOException, ClassNotFoundException public void write (JMEExporter ex)
throws IOException
{ {
in.defaultReadObject(); OutputCapsule capsule = ex.getCapsule(this);
transforms = new Transform[in.readInt()][transformTargets.length]; capsule.write(frameRate, "frameRate", 0);
for (int ii = 0; ii < transforms.length; ii++) { capsule.write(repeatType, "repeatType", Controller.RT_CLAMP);
for (int jj = 0; jj < transformTargets.length; jj++) { capsule.write(transformTargets, "transformTargets", null);
transforms[ii][jj] = new Transform(new Vector3f(), FloatBuffer pxforms = FloatBuffer.allocate(transforms.length *
new Quaternion(), new Vector3f()); transformTargets.length * Transform.PACKED_SIZE);
transforms[ii][jj].readExternal(in); for (Transform[] frame : transforms) {
for (Transform xform : frame) {
xform.writeToBuffer(pxforms);
} }
} }
pxforms.rewind();
capsule.write(pxforms, "transforms", null);
} }
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
@@ -202,8 +226,10 @@ public class Model extends ModelNode
/** A frame element that manipulates the target's transform. */ /** A frame element that manipulates the target's transform. */
public static final class Transform public static final class Transform
implements Externalizable
{ {
/** The number of floats required to store a packed transform. */
public static final int PACKED_SIZE = 3 + 4 + 3;
public Transform ( public Transform (
Vector3f translation, Quaternion rotation, Vector3f scale) Vector3f translation, Quaternion rotation, Vector3f scale)
{ {
@@ -212,6 +238,14 @@ public class Model extends ModelNode
_scale = scale; _scale = scale;
} }
public Transform (FloatBuffer buf)
{
_translation = new Vector3f(buf.get(), buf.get(), buf.get());
_rotation = new Quaternion(buf.get(), buf.get(), buf.get(),
buf.get());
_scale = new Vector3f(buf.get(), buf.get(), buf.get());
}
public void apply (Spatial target) public void apply (Spatial target)
{ {
target.getLocalTranslation().set(_translation); target.getLocalTranslation().set(_translation);
@@ -234,29 +268,29 @@ public class Model extends ModelNode
target.getLocalScale().interpolate(_scale, next._scale, alpha); target.getLocalScale().interpolate(_scale, next._scale, alpha);
} }
// documentation inherited from interface Externalizable /**
public void writeExternal (ObjectOutput out) * Writes this transform to the current position in the supplied
throws IOException * buffer.
*/
public void writeToBuffer (FloatBuffer buf)
{ {
_translation.writeExternal(out); buf.put(_translation.x);
_rotation.writeExternal(out); buf.put(_translation.y);
_scale.writeExternal(out); buf.put(_translation.z);
buf.put(_rotation.x);
buf.put(_rotation.y);
buf.put(_rotation.z);
buf.put(_rotation.w);
buf.put(_scale.x);
buf.put(_scale.y);
buf.put(_scale.z);
} }
// documentation inherited from interface Externalizable
public void readExternal (ObjectInput in)
throws IOException, ClassNotFoundException
{
_translation.readExternal(in);
_rotation.readExternal(in);
_scale.readExternal(in);
}
/** The transform at this frame. */ /** The transform at this frame. */
protected Vector3f _translation, _scale; protected Vector3f _translation, _scale;
protected Quaternion _rotation; protected Quaternion _rotation;
private static final long serialVersionUID = 1;
} }
/** Customized clone creator for models. */ /** Customized clone creator for models. */
@@ -326,34 +360,14 @@ public class Model extends ModelNode
/** /**
* Attempts to read a model from the specified file. * Attempts to read a model from the specified file.
*
* @param map if true, map buffers into memory directly from the
* file
*/ */
public static Model readFromFile (File file, boolean map) public static Model readFromFile (File file)
throws IOException throws IOException
{ {
// read the serialized model and its children // read the serialized model and its children
FileInputStream fis = new FileInputStream(file); FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis); Model model = (Model)BinaryImporter.getInstance().load(fis);
Model model; fis.close();
try {
model = (Model)ois.readObject();
} catch (ClassNotFoundException e) {
Log.warning("Encountered unknown class [error=" + e + "].");
return null;
}
// then either read or map the buffers
FileChannel fc = fis.getChannel();
if (map) {
long pos = fc.position();
model.sliceBuffers(fc.map(FileChannel.MapMode.READ_ONLY,
pos, fc.size() - pos));
} else {
model.readBuffers(fc);
}
ois.close();
// initialize the model as a prototype // initialize the model as a prototype
model.initPrototype(); model.initPrototype();
@@ -677,17 +691,44 @@ public class Model extends ModelNode
{ {
// start out by writing this node and its children // start out by writing this node and its children
FileOutputStream fos = new FileOutputStream(file); FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos); BinaryExporter.getInstance().save(this, fos);
oos.writeObject(this); fos.close();
// now traverse the scene graph appending buffers to the
// end of the file
writeBuffers(fos.getChannel());
oos.close();
} }
@Override // documentation inherited @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException
{
super.read(im);
InputCapsule capsule = im.getCapsule(this);
String[] propNames = capsule.readStringArray("propNames", null),
propValues = capsule.readStringArray("propValues", null);
_props = new Properties();
for (int ii = 0; ii < propNames.length; ii++) {
_props.setProperty(propNames[ii], propValues[ii]);
}
String[] animNames = capsule.readStringArray("animNames", null);
if (animNames != null) {
Savable[] animValues = capsule.readSavableArray(
"animValues", null);
_anims = new HashMap<String, Animation>();
for (int ii = 0; ii < animNames.length; ii++) {
_anims.put(animNames[ii], (Animation)animValues[ii]);
}
} else {
_anims = null;
}
ArrayList controllers = capsule.readSavableArrayList(
"controllers", null);
if (controllers != null) {
for (Object ctrl : controllers) {
addController((Controller)ctrl);
}
}
}
@Override // documentation inherited
public void write (JMEExporter ex)
throws IOException throws IOException
{ {
// don't serialize the emission node; it contains transient geometry // don't serialize the emission node; it contains transient geometry
@@ -695,28 +736,24 @@ public class Model extends ModelNode
if (_emissionNode != null) { if (_emissionNode != null) {
detachChild(_emissionNode); detachChild(_emissionNode);
} }
super.writeExternal(out); super.write(ex);
if (_emissionNode != null) { if (_emissionNode != null) {
attachChild(_emissionNode); attachChild(_emissionNode);
} }
out.writeObject(_props); OutputCapsule capsule = ex.getCapsule(this);
out.writeObject(_anims); capsule.write(_props.keySet().toArray(new String[_props.size()]),
out.writeObject(getControllers()); "propNames", null);
capsule.write(_props.values().toArray(new String[_props.size()]),
"propValues", null);
if (_anims != null) {
capsule.write(_anims.keySet().toArray(
new String[_anims.size()]), "animNames", null);
capsule.write(_anims.values().toArray(
new Animation[_anims.size()]), "animValues", null);
}
capsule.writeSavableArrayList(getControllers(), "controllers", null);
} }
@Override // documentation inherited
public void readExternal (ObjectInput in)
throws IOException, ClassNotFoundException
{
super.readExternal(in);
_props = (Properties)in.readObject();
_anims = (HashMap<String, Animation>)in.readObject();
ArrayList controllers = (ArrayList)in.readObject();
for (Object ctrl : controllers) {
addController((Controller)ctrl);
}
}
@Override // documentation inherited @Override // documentation inherited
public void resolveTextures (TextureProvider tprov) public void resolveTextures (TextureProvider tprov)
{ {
@@ -21,10 +21,7 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@@ -33,6 +30,10 @@ import java.util.Properties;
import com.jme.scene.Controller; 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.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
@@ -40,7 +41,6 @@ import com.samskivert.util.StringUtil;
* The superclass of procedural animation controllers for models. * The superclass of procedural animation controllers for models.
*/ */
public abstract class ModelController extends Controller public abstract class ModelController extends Controller
implements Externalizable
{ {
/** /**
* Configures this controller based on the supplied (sub-)properties and * Configures this controller based on the supplied (sub-)properties and
@@ -113,20 +113,30 @@ public abstract class ModelController extends Controller
return mstore; return mstore;
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException throws IOException
{ {
out.writeObject(_target); InputCapsule capsule = im.getCapsule(this);
out.writeObject(_animations); _target = (Spatial)capsule.readSavable("target", null);
String[] anims = capsule.readStringArray("animations", null);
if (anims != null) {
_animations = new HashSet<String>();
Collections.addAll(_animations, anims);
} else {
_animations = null;
}
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void readExternal (ObjectInput in) public void write (JMEExporter ex)
throws IOException, ClassNotFoundException throws IOException
{ {
_target = (Spatial)in.readObject(); OutputCapsule capsule = ex.getCapsule(this);
_animations = (HashSet<String>)in.readObject(); capsule.write(_target, "target", null);
capsule.write((_animations == null) ?
null : _animations.toArray(new String[_animations.size()]),
"animations", null);
} }
/** /**
+62 -240
View File
@@ -21,17 +21,12 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Properties; import java.util.Properties;
@@ -58,6 +53,10 @@ import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState; import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState; import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem; import com.jme.system.DisplaySystem;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
import com.jme.util.geom.BufferUtils; import com.jme.util.geom.BufferUtils;
import com.samskivert.util.PropertiesUtil; import com.samskivert.util.PropertiesUtil;
@@ -69,7 +68,7 @@ import com.threerings.jme.Log;
* A {@link TriMesh} with a serialization mechanism tailored to stored models. * A {@link TriMesh} with a serialization mechanism tailored to stored models.
*/ */
public class ModelMesh extends TriMesh public class ModelMesh extends TriMesh
implements Externalizable, ModelSpatial implements ModelSpatial
{ {
/** /**
* No-arg constructor for deserialization. * No-arg constructor for deserialization.
@@ -127,37 +126,6 @@ public class ModelMesh extends TriMesh
Boolean.parseBoolean(tprops.getProperty("translucent")); Boolean.parseBoolean(tprops.getProperty("translucent"));
} }
/**
* Sets the buffers as {@link ByteBuffer}s, because we can't create byte
* views of non-byte buffers. This method is where the model is
* initialized after loading.
*/
public void reconstruct (
ByteBuffer vertices, ByteBuffer normals, ByteBuffer colors,
ByteBuffer textures, ByteBuffer indices)
{
reconstruct(
vertices == null ? null : vertices.asFloatBuffer(),
normals == null ? null : normals.asFloatBuffer(),
colors == null ? null : colors.asFloatBuffer(),
textures == null ? null : textures.asFloatBuffer(),
indices == null ? null : indices.asIntBuffer());
for (int ii = 1, nn = getTextureCount(); ii < nn; ii++) {
setTextureBuffer(0, getTextureBuffer(0, 0), ii);
}
_vertexByteBuffer = vertices;
_normalByteBuffer = normals;
_colorByteBuffer = colors;
_textureByteBuffer = textures;
_indexByteBuffer = indices;
// store any buffers that will be manipulated on a per-instance basis
storeOriginalBuffers();
// initialize the model if we're displaying
setRenderStates();
}
/** /**
* 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.
@@ -209,27 +177,11 @@ public class ModelMesh extends TriMesh
setTextureBuffer(0, getTextureBuffer(0, 0), ii); setTextureBuffer(0, getTextureBuffer(0, 0), ii);
} }
_vertexBufferSize = (vertices == null) ? 0 : vertices.capacity(); // store any buffers that will be manipulated on a per-instance basis
_normalBufferSize = (normals == null) ? 0 : normals.capacity(); storeOriginalBuffers();
_colorBufferSize = (colors == null) ? 0 : colors.capacity();
_textureBufferSize = (textures == null) ? 0 : textures.capacity();
_indexBufferSize = (indices == null) ? 0 : indices.capacity();
}
@Override // documentation inherited
public void reconstruct (
FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors,
FloatBuffer textures)
{
super.reconstruct(vertices, normals, colors, textures);
for (int ii = 1, nn = getTextureCount(); ii < nn; ii++) {
setTextureBuffer(0, getTextureBuffer(0, 0), ii);
}
_vertexBufferSize = (vertices == null) ? 0 : vertices.capacity(); // initialize the model if we're displaying
_normalBufferSize = (normals == null) ? 0 : normals.capacity(); setRenderStates();
_colorBufferSize = (colors == null) ? 0 : colors.capacity();
_textureBufferSize = (textures == null) ? 0 : textures.capacity();
} }
// documentation inherited from interface ModelSpatial // documentation inherited from interface ModelSpatial
@@ -331,56 +283,64 @@ public class ModelMesh extends TriMesh
} }
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException throws IOException
{ {
out.writeUTF(getName()); InputCapsule capsule = im.getCapsule(this);
out.writeObject(getLocalTranslation()); setName(capsule.readString("name", null));
out.writeObject(getLocalRotation()); setLocalTranslation((Vector3f)capsule.readSavable(
out.writeObject(getLocalScale()); "localTranslation", null));
out.writeObject(getBatch(0).getModelBound()); setLocalRotation((Quaternion)capsule.readSavable(
out.writeInt(_vertexBufferSize); "localRotation", null));
out.writeInt(_normalBufferSize); setLocalScale((Vector3f)capsule.readSavable(
out.writeInt(_colorBufferSize); "localScale", null));
out.writeInt(_textureBufferSize); TriangleBatch batch = (TriangleBatch)getBatch(0);
out.writeInt(_indexBufferSize); batch.setModelBound((BoundingVolume)capsule.readSavable(
out.writeObject(_textureKey); "modelBound", null));
out.writeObject(_textures); _textureKey = capsule.readString("textureKey", null);
out.writeBoolean(_sphereMapped); _textures = capsule.readStringArray("textures", null);
out.writeInt(_filterMode); _sphereMapped = capsule.readBoolean("sphereMapped", false);
out.writeInt(_mipMapMode); _filterMode = capsule.readInt("filterMode", Texture.FM_LINEAR);
out.writeObject(_emissiveMap); _mipMapMode = capsule.readInt("mipMapMode", Texture.MM_LINEAR_LINEAR);
out.writeBoolean(_solid); _emissiveMap = capsule.readString("emissiveMap", null);
out.writeBoolean(_transparent); _solid = capsule.readBoolean("solid", true);
out.writeFloat(_alphaThreshold); _transparent = capsule.readBoolean("transparent", false);
out.writeBoolean(_translucent); _alphaThreshold = capsule.readFloat("alphaThreshold",
DEFAULT_ALPHA_THRESHOLD);
_translucent = capsule.readBoolean("translucent", false);
reconstruct(capsule.readFloatBuffer("vertexBuffer", null),
capsule.readFloatBuffer("normalBuffer", null), null,
capsule.readFloatBuffer("textureBuffer", null),
capsule.readIntBuffer("indexBuffer", null));
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void readExternal (ObjectInput in) public void write (JMEExporter ex)
throws IOException, ClassNotFoundException throws IOException
{ {
setName(in.readUTF()); OutputCapsule capsule = ex.getCapsule(this);
setLocalTranslation((Vector3f)in.readObject()); capsule.write(getName(), "name", null);
setLocalRotation((Quaternion)in.readObject()); capsule.write(getLocalTranslation(), "localTranslation", null);
setLocalScale((Vector3f)in.readObject()); capsule.write(getLocalRotation(), "localRotation", null);
setModelBound((BoundingVolume)in.readObject()); capsule.write(getLocalScale(), "localScale", null);
_vertexBufferSize = in.readInt(); capsule.write(getBatch(0).getModelBound(), "modelBound", null);
_normalBufferSize = in.readInt(); capsule.write(getVertexBuffer(0), "vertexBuffer", null);
_colorBufferSize = in.readInt(); capsule.write(getNormalBuffer(0), "normalBuffer", null);
_textureBufferSize = in.readInt(); capsule.write(getTextureBuffer(0, 0), "textureBuffer", null);
_indexBufferSize = in.readInt(); capsule.write(getIndexBuffer(0), "indexBuffer", null);
_textureKey = (String)in.readObject(); capsule.write(_textureKey, "textureKey", null);
_textures = (String[])in.readObject(); capsule.write(_textures, "textures", null);
_sphereMapped = in.readBoolean(); capsule.write(_sphereMapped, "sphereMapped", false);
_filterMode = in.readInt(); capsule.write(_filterMode, "filterMode", Texture.FM_LINEAR);
_mipMapMode = in.readInt(); capsule.write(_mipMapMode, "mipMapMode", Texture.MM_LINEAR_LINEAR);
_emissiveMap = (String)in.readObject(); capsule.write(_emissiveMap, "emissiveMap", null);
_solid = in.readBoolean(); capsule.write(_solid, "solid", true);
_transparent = in.readBoolean(); capsule.write(_transparent, "transparent", false);
_alphaThreshold = in.readFloat(); capsule.write(_alphaThreshold, "alphaThreshold",
_translucent = in.readBoolean(); DEFAULT_ALPHA_THRESHOLD);
capsule.write(_translucent, "translucent", false);
} }
// documentation inherited from interface ModelSpatial // documentation inherited from interface ModelSpatial
@@ -463,121 +423,6 @@ public class ModelMesh extends TriMesh
// no-op // no-op
} }
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
{
if (_vertexBufferSize > 0) {
_vertexByteBuffer.rewind();
convertOrder(_vertexByteBuffer, ByteOrder.LITTLE_ENDIAN);
out.write(_vertexByteBuffer);
convertOrder(_vertexByteBuffer, ByteOrder.nativeOrder());
}
if (_normalBufferSize > 0) {
_normalByteBuffer.rewind();
convertOrder(_normalByteBuffer, ByteOrder.LITTLE_ENDIAN);
out.write(_normalByteBuffer);
convertOrder(_normalByteBuffer, ByteOrder.nativeOrder());
}
if (_colorBufferSize > 0) {
_colorByteBuffer.rewind();
convertOrder(_colorByteBuffer, ByteOrder.LITTLE_ENDIAN);
out.write(_colorByteBuffer);
convertOrder(_colorByteBuffer, ByteOrder.nativeOrder());
}
if (_textureBufferSize > 0) {
_textureByteBuffer.rewind();
convertOrder(_textureByteBuffer, ByteOrder.LITTLE_ENDIAN);
out.write(_textureByteBuffer);
convertOrder(_textureByteBuffer, ByteOrder.nativeOrder());
}
if (_indexBufferSize > 0) {
_indexByteBuffer.rewind();
convertOrder(_indexByteBuffer, ByteOrder.LITTLE_ENDIAN);
out.write(_indexByteBuffer);
convertOrder(_indexByteBuffer, ByteOrder.nativeOrder());
}
}
// documentation inherited from interface ModelSpatial
public void readBuffers (FileChannel in)
throws IOException
{
ByteBuffer vbbuf = null, nbbuf = null, cbbuf = null, tbbuf = null,
ibbuf = null;
ByteOrder le = ByteOrder.LITTLE_ENDIAN;
if (_vertexBufferSize > 0) {
vbbuf = ByteBuffer.allocateDirect(_vertexBufferSize*4).order(le);
in.read(vbbuf);
vbbuf.rewind();
convertOrder(vbbuf, ByteOrder.nativeOrder());
}
if (_normalBufferSize > 0) {
nbbuf = ByteBuffer.allocateDirect(_normalBufferSize*4).order(le);
in.read(nbbuf);
nbbuf.rewind();
convertOrder(nbbuf, ByteOrder.nativeOrder());
}
if (_colorBufferSize > 0) {
cbbuf = ByteBuffer.allocateDirect(_colorBufferSize*4).order(le);
in.read(cbbuf);
cbbuf.rewind();
convertOrder(cbbuf, ByteOrder.nativeOrder());
}
if (_textureBufferSize > 0) {
tbbuf = ByteBuffer.allocateDirect(_textureBufferSize*4).order(le);
in.read(tbbuf);
tbbuf.rewind();
convertOrder(tbbuf, ByteOrder.nativeOrder());
}
if (_indexBufferSize > 0) {
ibbuf = ByteBuffer.allocateDirect(_indexBufferSize*4).order(le);
in.read(ibbuf);
ibbuf.rewind();
convertOrder(ibbuf, ByteOrder.nativeOrder());
}
reconstruct(vbbuf, nbbuf, cbbuf, tbbuf, ibbuf);
}
// documentation inherited from interface ModelSpatial
public void sliceBuffers (MappedByteBuffer map)
{
ByteBuffer vbbuf = null, nbbuf = null, cbbuf = null, tbbuf = null,
ibbuf = null;
int total = 0;
if (_vertexBufferSize > 0) {
int npos = map.position() + _vertexBufferSize*4;
map.limit(npos);
vbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos);
}
if (_normalBufferSize > 0) {
int npos = map.position() + _normalBufferSize*4;
map.limit(npos);
nbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos);
}
if (_colorBufferSize > 0) {
int npos = map.position() + _colorBufferSize*4;
map.limit(npos);
cbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos);
}
if (_textureBufferSize > 0) {
int npos = map.position() + _textureBufferSize*4;
map.limit(npos);
tbbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos);
}
if (_indexBufferSize > 0) {
int npos = map.position() + _indexBufferSize*4;
map.limit(npos);
ibbuf = map.slice().order(ByteOrder.LITTLE_ENDIAN);
map.position(npos);
}
reconstruct(vbbuf, nbbuf, cbbuf, tbbuf, ibbuf);
}
@Override // documentation inherited @Override // documentation inherited
protected void setupBatchList () protected void setupBatchList ()
{ {
@@ -675,21 +520,6 @@ public class ModelMesh extends TriMesh
} }
} }
/**
* Imposes the specified order on the given buffer of 32 bit values.
*/
protected static void convertOrder (ByteBuffer buf, ByteOrder order)
{
if (buf.order() == order) {
return;
}
IntBuffer obuf = buf.asIntBuffer(),
nbuf = buf.order(order).asIntBuffer();
while (obuf.hasRemaining()) {
nbuf.put(obuf.get());
}
}
/** /**
* Initializes the states shared between all models. Requires an active * Initializes the states shared between all models. Requires an active
* display. * display.
@@ -879,14 +709,6 @@ public class ModelMesh extends TriMesh
new RenderState[RenderState.RS_MAX_STATE]; new RenderState[RenderState.RS_MAX_STATE];
} }
/** The sizes of the various buffers (zero for <code>null</code>). */
protected int _vertexBufferSize, _normalBufferSize, _colorBufferSize,
_textureBufferSize, _indexBufferSize;
/** The backing byte buffers for the various buffers. */
protected ByteBuffer _vertexByteBuffer, _normalByteBuffer,
_colorByteBuffer, _textureByteBuffer, _indexByteBuffer;
/** 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;
@@ -22,13 +22,7 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.Externalizable;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
@@ -41,6 +35,10 @@ 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.jme.scene.state.RenderState; import com.jme.scene.state.RenderState;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
import com.threerings.jme.Log; import com.threerings.jme.Log;
@@ -48,7 +46,7 @@ import com.threerings.jme.Log;
* A {@link Node} with a serialization mechanism tailored to stored models. * A {@link Node} with a serialization mechanism tailored to stored models.
*/ */
public class ModelNode extends Node public class ModelNode extends Node
implements Externalizable, ModelSpatial implements ModelSpatial
{ {
/** /**
* No-arg constructor for deserialization. * No-arg constructor for deserialization.
@@ -174,33 +172,38 @@ public class ModelNode extends Node
return mstore; return mstore;
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException throws IOException
{ {
out.writeUTF(getName()); InputCapsule capsule = im.getCapsule(this);
out.writeObject(getLocalTranslation()); setName(capsule.readString("name", null));
out.writeObject(getLocalRotation()); setLocalTranslation((Vector3f)capsule.readSavable(
out.writeObject(getLocalScale()); "localTranslation", null));
out.writeObject(getChildren()); setLocalRotation((Quaternion)capsule.readSavable(
} "localRotation", null));
setLocalScale((Vector3f)capsule.readSavable(
// documentation inherited from interface Externalizable "localScale", null));
public void readExternal (ObjectInput in) ArrayList children = capsule.readSavableArrayList("children", null);
throws IOException, ClassNotFoundException
{
setName(in.readUTF());
setLocalTranslation((Vector3f)in.readObject());
setLocalRotation((Quaternion)in.readObject());
setLocalScale((Vector3f)in.readObject());
ArrayList<Spatial> children = (ArrayList<Spatial>)in.readObject();
if (children != null) { if (children != null) {
for (Spatial child : children) { for (Object child : children) {
attachChild(child); attachChild((Spatial)child);
} }
} }
} }
@Override // documentation inherited
public void write (JMEExporter ex)
throws IOException
{
OutputCapsule capsule = ex.getCapsule(this);
capsule.write(getName(), "name", null);
capsule.write(getLocalTranslation(), "localTranslation", null);
capsule.write(getLocalRotation(), "localRotation", null);
capsule.write(getLocalScale(), "localScale", null);
capsule.writeSavableArrayList(getChildren(), "children", null);
}
// documentation inherited from interface ModelSpatial // documentation inherited from interface ModelSpatial
public void expandModelBounds () public void expandModelBounds ()
{ {
@@ -300,41 +303,6 @@ public class ModelNode extends Node
return _forceCull; return _forceCull;
} }
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
{
for (int ii = 0, nn = getQuantity(); ii < nn; ii++) {
Spatial child = getChild(ii);
if (child instanceof ModelSpatial) {
((ModelSpatial)child).writeBuffers(out);
}
}
}
// documentation inherited from interface ModelSpatial
public void readBuffers (FileChannel in)
throws IOException
{
for (int ii = 0, nn = getQuantity(); ii < nn; ii++) {
Spatial child = getChild(ii);
if (child instanceof ModelSpatial) {
((ModelSpatial)child).readBuffers(in);
}
}
}
// documentation inherited from interface ModelSpatial
public void sliceBuffers (MappedByteBuffer map)
{
for (int ii = 0, nn = getQuantity(); ii < nn; ii++) {
Spatial child = getChild(ii);
if (child instanceof ModelSpatial) {
((ModelSpatial)child).sliceBuffers(map);
}
}
}
/** /**
* Sets the cull state of any nodes that do not contain geometric * Sets the cull state of any nodes that do not contain geometric
* descendants to {@link CULL_ALWAYS} so that they don't waste * descendants to {@link CULL_ALWAYS} so that they don't waste
@@ -21,13 +21,6 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import com.jme.math.Matrix4f;
import com.jme.renderer.Renderer; import com.jme.renderer.Renderer;
import com.jme.scene.Spatial; import com.jme.scene.Spatial;
@@ -95,21 +88,4 @@ public interface ModelSpatial
* to create a new instance * to create a new instance
*/ */
public Spatial putClone (Spatial store, Model.CloneCreator properties); public Spatial putClone (Spatial store, Model.CloneCreator properties);
/**
* Recursively writes any data buffers to the output channel.
*/
public void writeBuffers (FileChannel out)
throws IOException;
/**
* Recursively reads any data buffers from the input channel.
*/
public void readBuffers (FileChannel in)
throws IOException;
/**
* Recursively slices any data buffers from the buffer map.
*/
public void sliceBuffers (MappedByteBuffer map);
} }
+18 -14
View File
@@ -22,8 +22,6 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Properties; import java.util.Properties;
@@ -31,6 +29,10 @@ import com.jme.math.Quaternion;
import com.jme.math.Vector3f; import com.jme.math.Vector3f;
import com.jme.scene.Controller; import com.jme.scene.Controller;
import com.jme.scene.Spatial; import com.jme.scene.Spatial;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
@@ -97,24 +99,26 @@ public class Rotator extends ModelController
return rstore; return rstore;
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException throws IOException
{ {
super.writeExternal(out); super.read(im);
out.writeObject(_axis); InputCapsule capsule = im.getCapsule(this);
out.writeFloat(_velocity); _axis = (Vector3f)capsule.readSavable("axis", null);
_velocity = capsule.readFloat("velocity", 0f);
} }
// documentation inherited from interface Externalizable @Override // documentation inherited
public void readExternal (ObjectInput in) public void write (JMEExporter ex)
throws IOException, ClassNotFoundException throws IOException
{ {
super.readExternal(in); super.write(ex);
_axis = (Vector3f)in.readObject(); OutputCapsule capsule = ex.getCapsule(this);
_velocity = in.readFloat(); capsule.write(_axis, "axis", null);
capsule.write(_velocity, "velocity", 0f);
} }
/** The axis about which to rotate. */ /** The axis about which to rotate. */
protected Vector3f _axis; protected Vector3f _axis;
+74 -21
View File
@@ -22,9 +22,7 @@
package com.threerings.jme.model; package com.threerings.jme.model;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.Serializable; import java.io.Serializable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@@ -45,6 +43,11 @@ import com.jme.scene.VBOInfo;
import com.jme.scene.batch.SharedBatch; import com.jme.scene.batch.SharedBatch;
import com.jme.scene.batch.TriangleBatch; import com.jme.scene.batch.TriangleBatch;
import com.jme.system.DisplaySystem; import com.jme.system.DisplaySystem;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.OutputCapsule;
import com.jme.util.export.Savable;
import com.jme.util.geom.BufferUtils; import com.jme.util.geom.BufferUtils;
import com.samskivert.util.HashIntMap; import com.samskivert.util.HashIntMap;
@@ -59,7 +62,7 @@ public class SkinMesh extends ModelMesh
/** Represents the vertex weights of a group of vertices influenced by the /** Represents the vertex weights of a group of vertices influenced by the
* same set of bones. */ * same set of bones. */
public static class WeightGroup public static class WeightGroup
implements Serializable implements Savable
{ {
/** The number of vertices in this weight group. */ /** The number of vertices in this weight group. */
public int vertexCount; public int vertexCount;
@@ -89,12 +92,40 @@ public class SkinMesh extends ModelMesh
return wgroup; return wgroup;
} }
// documentation inherited
public Class getClassTag ()
{
return getClass();
}
// documentation inherited
public void read (JMEImporter im)
throws IOException
{
InputCapsule capsule = im.getCapsule(this);
vertexCount = capsule.readInt("vertexCount", 0);
Savable[] sbones = capsule.readSavableArray("bones", null);
bones = new Bone[sbones.length];
System.arraycopy(sbones, 0, bones, 0, sbones.length);
weights = capsule.readFloatArray("weights", null);
}
// documentation inherited
public void write (JMEExporter ex)
throws IOException
{
OutputCapsule capsule = ex.getCapsule(this);
capsule.write(vertexCount, "vertexCount", 0);
capsule.write(bones, "bones", null);
capsule.write(weights, "weights", null);
}
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
} }
/** Represents a bone that influences the mesh. */ /** Represents a bone that influences the mesh. */
public static class Bone public static class Bone
implements Serializable implements Savable
{ {
/** The node that defines the bone's position. */ /** The node that defines the bone's position. */
public ModelNode node; public ModelNode node;
@@ -107,7 +138,12 @@ public class SkinMesh extends ModelMesh
public Bone (ModelNode node) public Bone (ModelNode node)
{ {
this();
this.node = node; this.node = node;
}
public Bone ()
{
transform = new Matrix4f(); transform = new Matrix4f();
} }
@@ -124,16 +160,28 @@ public class SkinMesh extends ModelMesh
return bone; return bone;
} }
/** // documentation inherited
* Initializes the bone's transient state. public Class getClassTag ()
*/
private void readObject (ObjectInputStream in)
throws IOException, ClassNotFoundException
{ {
in.defaultReadObject(); return getClass();
transform = new Matrix4f();
} }
// documentation inherited
public void read (JMEImporter im)
throws IOException
{
InputCapsule capsule = im.getCapsule(this);
node = (ModelNode)capsule.readSavable("node", null);
}
// documentation inherited
public void write (JMEExporter ex)
throws IOException
{
OutputCapsule capsule = ex.getCapsule(this);
capsule.write(node, "node", null);
}
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
} }
@@ -170,8 +218,8 @@ public class SkinMesh extends ModelMesh
@Override // documentation inherited @Override // documentation inherited
public void reconstruct ( public void reconstruct (
ByteBuffer vertices, ByteBuffer normals, ByteBuffer colors, FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors,
ByteBuffer textures, ByteBuffer indices) FloatBuffer textures, IntBuffer indices)
{ {
super.reconstruct(vertices, normals, colors, textures, indices); super.reconstruct(vertices, normals, colors, textures, indices);
@@ -218,19 +266,24 @@ public class SkinMesh extends ModelMesh
} }
@Override // documentation inherited @Override // documentation inherited
public void writeExternal (ObjectOutput out) public void read (JMEImporter im)
throws IOException throws IOException
{ {
super.writeExternal(out); super.read(im);
out.writeObject(_weightGroups); InputCapsule capsule = im.getCapsule(this);
Savable[] swgroups = capsule.readSavableArray("weightGroups", null);
WeightGroup[] wgroups = new WeightGroup[swgroups.length];
System.arraycopy(swgroups, 0, wgroups, 0, swgroups.length);
setWeightGroups(wgroups);
} }
@Override // documentation inherited @Override // documentation inherited
public void readExternal (ObjectInput in) public void write (JMEExporter ex)
throws IOException, ClassNotFoundException throws IOException
{ {
super.readExternal(in); super.write(ex);
setWeightGroups((WeightGroup[])in.readObject()); OutputCapsule capsule = ex.getCapsule(this);
capsule.write(_weightGroups, "weightGroups", null);
} }
@Override // documentation inherited @Override // documentation inherited
@@ -199,23 +199,17 @@ public class ModelDef
// set the various buffers // set the various buffers
int vsize = vertices.size(); int vsize = vertices.size();
ByteOrder no = ByteOrder.nativeOrder(); FloatBuffer vbuf = BufferUtils.createVector3Buffer(vsize),
ByteBuffer vbbuf = ByteBuffer.allocateDirect(vsize*3*4).order(no), nbuf = BufferUtils.createVector3Buffer(vsize),
nbbuf = ByteBuffer.allocateDirect(vsize*3*4).order(no), tbuf = tcoords ? BufferUtils.createVector2Buffer(vsize) : null;
tbbuf = tcoords ?
ByteBuffer.allocateDirect(vsize*2*4).order(no) : null,
ibbuf = ByteBuffer.allocateDirect(indices.size()*4).order(no);
FloatBuffer vbuf = vbbuf.asFloatBuffer(),
nbuf = nbbuf.asFloatBuffer(),
tbuf = tcoords ? tbbuf.asFloatBuffer() : null;
for (int ii = 0; ii < vsize; ii++) { for (int ii = 0; ii < vsize; ii++) {
vertices.get(ii).setInBuffers(vbuf, nbuf, tbuf); vertices.get(ii).setInBuffers(vbuf, nbuf, tbuf);
} }
IntBuffer ibuf = ibbuf.asIntBuffer(); IntBuffer ibuf = BufferUtils.createIntBuffer(indices.size());
for (int ii = 0, nn = indices.size(); ii < nn; ii++) { for (int ii = 0, nn = indices.size(); ii < nn; ii++) {
ibuf.put(indices.get(ii)); ibuf.put(indices.get(ii));
} }
_mesh.reconstruct(vbbuf, nbbuf, null, tbbuf, ibbuf); _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());
@@ -624,7 +624,7 @@ public class ModelViewer extends JmeCanvasApp
throws IOException throws IOException
{ {
_status.setText(_msg.get("m.loading_model", file)); _status.setText(_msg.get("m.loading_model", file));
setModel(Model.readFromFile(file, false), file); setModel(Model.readFromFile(file), file);
} }
/** /**