Checkpoint checkin for new model exporting/loading/animating code.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4013 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Andrzej Kapolka
2006-04-12 03:34:10 +00:00
parent 4aa1971f30
commit bb32d03c66
13 changed files with 1806 additions and 0 deletions
@@ -0,0 +1,99 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import com.jme.scene.Node;
import com.jme.math.Quaternion;
import com.jme.math.TransformMatrix;
import com.jme.math.Vector3f;
import com.threerings.jme.Log;
/**
* Represents a bone in a scene. Bones can have simple meshes as children,
* or they can be used to deform {@link SkinMesh}es.
*/
public class BoneNode extends ModelNode
{
/**
* No-arg constructor for deserialization.
*/
public BoneNode ()
{
}
/**
* Default constructor.
*
* @param name the name of the node
*/
public BoneNode (String name)
{
super(name);
}
@Override // documentation inherited
public void setReferenceTransforms ()
{
super.setReferenceTransforms();
// store the inverse of the reference transform
_invRefTransform.set(worldRotation, worldTranslation);
_invRefTransform.setScale(worldScale);
_invRefTransform.inverse();
}
@Override // documentation inherited
public void updateWorldVectors ()
{
super.updateWorldVectors();
_skinTransform.set(worldRotation, worldTranslation);
_skinTransform.setScale(worldScale);
_skinTransform.multLocal(_invRefTransform, _tempStore);
}
/**
* Returns a reference to the matrix that transforms vertices in the
* reference position to vertices in the current position.
*/
public TransformMatrix getSkinTransform ()
{
return _skinTransform;
}
/** The inverse of the bone's world space reference transform. */
protected TransformMatrix _invRefTransform = new TransformMatrix();
/** The bone's current skin transform. */
protected TransformMatrix _skinTransform = new TransformMatrix();
/** A temporary vector for transformations. */
protected Vector3f _tempStore = new Vector3f();
private static final long serialVersionUID = 1;
}
@@ -0,0 +1,122 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.jme.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.nio.channels.FileChannel;
import com.threerings.jme.Log;
/**
* The base node for models.
*/
public class Model extends ModelNode
{
/**
* 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)
throws IOException
{
// read the serialized model and its children
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Model model;
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();
return model;
}
/**
* No-arg constructor for deserialization.
*/
public Model ()
{
}
/**
* Standard constructor.
*/
public Model (String name)
{
super(name);
}
/**
* Writes this model out to a file.
*/
public void writeToFile (File file)
throws IOException
{
// start out by writing this node and its children
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(this);
// now traverse the scene graph appending buffers to the
// end of the file
writeBuffers(fos.getChannel());
oos.close();
}
@Override // documentation inherited
public void writeExternal (ObjectOutput out)
throws IOException
{
super.writeExternal(out);
}
@Override // documentation inherited
public void readExternal (ObjectInput in)
throws IOException
{
super.readExternal(in);
}
private static final long serialVersionUID = 1;
}
@@ -0,0 +1,263 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.TriMesh;
import com.threerings.jme.Log;
/**
* A {@link TriMesh} with a serialization mechanism tailored to stored models.
*/
public class ModelMesh extends TriMesh
implements Externalizable, ModelSpatial
{
/**
* No-arg constructor for deserialization.
*/
public ModelMesh ()
{
}
/**
* Creates a mesh with no vertex data.
*/
public ModelMesh (String name)
{
super(name);
}
/**
* Creates and populates a mesh.
*/
public ModelMesh (
String name, FloatBuffer vertices, FloatBuffer normals,
FloatBuffer colors, FloatBuffer tcoords, IntBuffer indices)
{
super(name, vertices, normals, colors, tcoords, indices);
}
/**
* Sets the buffers as {@link ByteBuffer}s, because we can't create byte
* views of non-byte buffers.
*/
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());
_vertexByteBuffer = vertices;
_normalByteBuffer = normals;
_colorByteBuffer = colors;
_textureByteBuffer = textures;
_indexByteBuffer = indices;
}
// documentation inherited
public void reconstruct (
FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors,
FloatBuffer textures, IntBuffer indices)
{
super.reconstruct(vertices, normals, colors, textures, indices);
_vertexBufferSize = (vertices == null) ? 0 : vertices.capacity();
_normalBufferSize = (normals == null) ? 0 : normals.capacity();
_colorBufferSize = (colors == null) ? 0 : colors.capacity();
_textureBufferSize = (textures == null) ? 0 : textures.capacity();
_indexBufferSize = (indices == null) ? 0 : indices.capacity();
}
// documentation inherited
public void reconstruct (
FloatBuffer vertices, FloatBuffer normals, FloatBuffer colors,
FloatBuffer textures)
{
super.reconstruct(vertices, normals, colors, textures);
_vertexBufferSize = (vertices == null) ? 0 : vertices.capacity();
_normalBufferSize = (normals == null) ? 0 : normals.capacity();
_colorBufferSize = (colors == null) ? 0 : colors.capacity();
_textureBufferSize = (textures == null) ? 0 : textures.capacity();
}
// documentation inherited from interface Externalizable
public void writeExternal (ObjectOutput out)
throws IOException
{
out.writeUTF(getName());
out.writeObject(getLocalTranslation());
out.writeObject(getLocalRotation());
out.writeObject(getLocalScale());
out.writeInt(_vertexBufferSize);
out.writeInt(_normalBufferSize);
out.writeInt(_colorBufferSize);
out.writeInt(_textureBufferSize);
out.writeInt(_indexBufferSize);
}
// documentation inherited from interface Externalizable
public void readExternal (ObjectInput in)
throws IOException
{
setName(in.readUTF());
try {
setLocalTranslation((Vector3f)in.readObject());
setLocalRotation((Quaternion)in.readObject());
setLocalScale((Vector3f)in.readObject());
} catch (ClassNotFoundException e) {
Log.warning("Encounted unknown class [mesh=" + getName() +
", exception=" + e + "].");
}
_vertexBufferSize = in.readInt();
_normalBufferSize = in.readInt();
_colorBufferSize = in.readInt();
_textureBufferSize = in.readInt();
_indexBufferSize = in.readInt();
}
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
{
if (_vertexBufferSize > 0) {
_vertexByteBuffer.rewind();
out.write(_vertexByteBuffer);
}
if (_normalBufferSize > 0) {
_normalByteBuffer.rewind();
out.write(_normalByteBuffer);
}
if (_colorBufferSize > 0) {
_colorByteBuffer.rewind();
out.write(_colorByteBuffer);
}
if (_textureBufferSize > 0) {
_indexByteBuffer.rewind();
out.write(_indexByteBuffer);
}
if (_indexBufferSize > 0) {
_indexByteBuffer.rewind();
out.write(_indexByteBuffer);
}
}
// documentation inherited from interface ModelSpatial
public void readBuffers (FileChannel in)
throws IOException
{
ByteBuffer vbbuf = null, nbbuf = null, cbbuf = null, tbbuf = null,
ibbuf = null;
if (_vertexBufferSize > 0) {
vbbuf = ByteBuffer.allocateDirect(_vertexBufferSize*3*4);
in.read(vbbuf);
vbbuf.rewind();
}
if (_normalBufferSize > 0) {
nbbuf = ByteBuffer.allocateDirect(_normalBufferSize*3*4);
in.read(nbbuf);
nbbuf.rewind();
}
if (_colorBufferSize > 0) {
cbbuf = ByteBuffer.allocateDirect(_colorBufferSize*4*4);
in.read(cbbuf);
cbbuf.rewind();
}
if (_textureBufferSize > 0) {
tbbuf = ByteBuffer.allocateDirect(_textureBufferSize*2*4);
in.read(tbbuf);
tbbuf.rewind();
}
if (_indexBufferSize > 0) {
ibbuf = ByteBuffer.allocateDirect(_indexBufferSize*4);
in.read(ibbuf);
ibbuf.rewind();
}
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;
if (_vertexBufferSize > 0) {
int npos = map.position() + _vertexBufferSize*3*4;
map.limit(npos);
vbbuf = map.slice();
map.position(npos);
}
if (_normalBufferSize > 0) {
int npos = map.position() + _normalBufferSize*3*4;
map.limit(npos);
nbbuf = map.slice();
map.position(npos);
}
if (_colorBufferSize > 0) {
int npos = map.position() + _colorBufferSize*4*4;
map.limit(npos);
cbbuf = map.slice();
map.position(npos);
}
if (_textureBufferSize > 0) {
int npos = map.position() + _textureBufferSize*2*4;
map.limit(npos);
tbbuf = map.slice();
map.position(npos);
}
if (_indexBufferSize > 0) {
int npos = map.position() + _indexBufferSize*4;
map.limit(npos);
ibbuf = map.slice();
map.position(npos);
}
reconstruct(vbbuf, nbbuf, cbbuf, tbbuf, ibbuf);
}
/** 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;
private static final long serialVersionUID = 1;
}
@@ -0,0 +1,139 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.jme.model;
import java.io.DataOutput;
import java.io.Externalizable;
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 com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.threerings.jme.Log;
/**
* A {@link Node} with a serialization mechanism tailored to stored models.
*/
public class ModelNode extends Node
implements Externalizable, ModelSpatial
{
/**
* No-arg constructor for deserialization.
*/
public ModelNode ()
{
}
/**
* Standard constructor.
*/
public ModelNode (String name)
{
super(name);
}
/**
* Recursively sets the reference transforms for any {@link BoneNode}s in
* the model.
*/
public void setReferenceTransforms ()
{
for (Object child : getChildren()) {
if (child instanceof ModelNode) {
((ModelNode)child).setReferenceTransforms();
}
}
}
// documentation inherited from interface Externalizable
public void writeExternal (ObjectOutput out)
throws IOException
{
out.writeUTF(getName());
out.writeObject(getLocalTranslation());
out.writeObject(getLocalRotation());
out.writeObject(getLocalScale());
out.writeObject(getChildren());
}
// documentation inherited from interface Externalizable
public void readExternal (ObjectInput in)
throws IOException
{
setName(in.readUTF());
try {
setLocalTranslation((Vector3f)in.readObject());
setLocalRotation((Quaternion)in.readObject());
setLocalScale((Vector3f)in.readObject());
ArrayList children = (ArrayList)in.readObject();
for (int ii = 0, nn = children.size(); ii < nn; ii++) {
attachChild((Spatial)children.get(ii));
}
} catch (ClassNotFoundException e) {
Log.warning("Encounted unknown class [node=" + getName() +
", exception=" + e + "].");
}
}
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
{
for (Object child : getChildren()) {
if (child instanceof ModelSpatial) {
((ModelSpatial)child).writeBuffers(out);
}
}
}
// documentation inherited from interface ModelSpatial
public void readBuffers (FileChannel in)
throws IOException
{
for (Object child : getChildren()) {
if (child instanceof ModelSpatial) {
((ModelSpatial)child).readBuffers(in);
}
}
}
// documentation inherited from interface ModelSpatial
public void sliceBuffers (MappedByteBuffer map)
{
for (Object child : getChildren()) {
if (child instanceof ModelSpatial) {
((ModelSpatial)child).sliceBuffers(map);
}
}
}
private static final long serialVersionUID = 1;
}
@@ -0,0 +1,51 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
* Contains method common to both {@link ModelNode}s and {@link ModelMesh}es.
*/
public interface ModelSpatial
{
/**
* 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);
}
@@ -0,0 +1,137 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2005 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import com.threerings.jme.Log;
/**
* A triangle mesh that deforms according to a bone hierarchy.
*/
public class SkinMesh extends ModelMesh
{
/** Represents the vertex weights of a group of vertices influenced by the
* same set of bones. */
public static class WeightGroup
implements Serializable
{
/** The indices of the affected vertices. */
public int[] indices;
/** The bones influencing this group. */
public BoneNode[] bones;
/** The array of interleaved weights (of length <code>indices.length *
* bones.length</code>): weights for first vertex, weights for second,
* etc. */
public float[] weights;
private static final long serialVersionUID = 1;
}
/**
* No-arg constructor for deserialization.
*/
public SkinMesh ()
{
}
/**
* Creates an empty mesh.
*/
public SkinMesh (String name)
{
super(name);
}
/**
* Creates and populates a mesh.
*/
public SkinMesh (
String name, FloatBuffer vertices, FloatBuffer normals,
FloatBuffer color, FloatBuffer texture, IntBuffer indices)
{
super(name, vertices, normals, color, texture, indices);
}
/**
* Sets the weight groups that determine how vertices are affected by
* bones.
*/
public void setWeightGroups (WeightGroup[] weightGroups)
{
_weightGroups = weightGroups;
}
/**
* Returns a reference to the array of weight groups.
*/
public WeightGroup[] getWeightGroups ()
{
return _weightGroups;
}
@Override // documentation inherited
public void writeExternal (ObjectOutput out)
throws IOException
{
super.writeExternal(out);
out.writeObject(_weightGroups);
}
@Override // documentation inherited
public void readExternal (ObjectInput in)
throws IOException
{
super.readExternal(in);
try {
_weightGroups = (WeightGroup[])in.readObject();
} catch (ClassNotFoundException e) {
Log.warning("Encounted unknown class [mesh=" + getName() +
", exception=" + e + "].");
}
}
@Override // documentation inherited
public void updateWorldData (float time)
{
super.updateWorldData(time);
// deform the mesh according to the positions of the bones
for (int ii = 0; ii < _weightGroups.length; ii++) {
}
}
/** The groups of vertices influenced by different sets of bones. */
protected WeightGroup[] _weightGroups;
private static final long serialVersionUID = 1;
}