Further progress: texturing, compiling animations.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4020 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Andrzej Kapolka
2006-04-14 03:26:50 +00:00
parent fc2870f7e5
commit 3c6ac7ac67
11 changed files with 560 additions and 35 deletions
@@ -21,6 +21,7 @@
package com.threerings.jme.model;
import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -29,13 +30,19 @@ import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Properties;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
import com.threerings.jme.Log;
/**
@@ -43,6 +50,97 @@ import com.threerings.jme.Log;
*/
public class Model extends ModelNode
{
/** An animation for the model. */
public static class Animation
implements Serializable
{
/** The transformation targets of the animation. */
public Spatial[] transformTargets;
/** The animation transforms (one transform per target per frame). */
public transient Transform[][] transforms;
private void writeObject (ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
out.writeInt(transforms.length);
for (int ii = 0; ii < transforms.length; ii++) {
for (int jj = 0; jj < transformTargets.length; jj++) {
transforms[ii][jj].writeExternal(out);
}
}
}
private void readObject (ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
transforms = new Transform[in.readInt()][transformTargets.length];
for (int ii = 0; ii < transforms.length; ii++) {
for (int jj = 0; jj < transformTargets.length; jj++) {
transforms[ii][jj] = new Transform(new Vector3f(),
new Quaternion(), new Vector3f());
transforms[ii][jj].readExternal(in);
}
}
}
private static final long serialVersionUID = 1;
}
/** A frame element that manipulates the target's transform. */
public static final class Transform
implements Externalizable
{
public Transform (
Vector3f translation, Quaternion rotation, Vector3f scale)
{
_translation = translation;
_rotation = rotation;
_scale = scale;
}
/**
* Blends between this transform and the next, applying the result to
* the given target.
*
* @param alpha the blend factor: 0.0 for entirely this frame, 1.0 for
* entirely the next
*/
public void blend (Transform next, float alpha, Spatial target)
{
target.getLocalTranslation().interpolate(_translation,
next._translation, alpha);
target.getLocalRotation().slerp(_rotation, next._rotation, alpha);
target.getLocalScale().interpolate(_scale, next._scale, alpha);
}
// documentation inherited from interface Externalizable
public void writeExternal (ObjectOutput out)
throws IOException
{
_translation.writeExternal(out);
_rotation.writeExternal(out);
_scale.writeExternal(out);
}
// 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. */
protected Vector3f _translation, _scale;
protected Quaternion _rotation;
private static final long serialVersionUID = 1;
}
/**
* Attempts to read a model from the specified file.
*
@@ -102,6 +200,48 @@ public class Model extends ModelNode
return _props;
}
/**
* Adds an animation to the model's library.
*/
public void addAnimation (String name, Animation anim)
{
if (_anims == null) {
_anims = new HashMap<String, Animation>();
}
_anims.put(name, anim);
}
/**
* Returns the names of the model's animations.
*/
public String[] getAnimations ()
{
return (_anims == null) ? new String[0] :
_anims.keySet().toArray(new String[_anims.size()]);
}
/**
* Starts the named animation.
*/
public void startAnimation (String name)
{
_anim = _anims.get(name);
if (_anim == null) {
Log.warning("Requested unknown animation [name=" +
name + "].");
return;
}
_fidx = -1;
}
/**
* Stops the currently running animation.
*/
public void stopAnimation ()
{
_anim = null;
}
/**
* Writes this model out to a file.
*/
@@ -125,6 +265,7 @@ public class Model extends ModelNode
{
super.writeExternal(out);
out.writeObject(_props);
out.writeObject(_anims);
}
@Override // documentation inherited
@@ -133,10 +274,45 @@ public class Model extends ModelNode
{
super.readExternal(in);
_props = (Properties)in.readObject();
_anims = (HashMap<String, Animation>)in.readObject();
}
@Override // documentation inherited
public void updateWorldData (float time)
{
if (_anim != null) {
updateAnimation(time);
}
// update children
super.updateWorldData(time);
}
/**
* Updates the model's state according to the current animation.
*/
protected void updateAnimation (float time)
{
}
/** The model properties. */
protected Properties _props;
/** The model animations. */
protected HashMap<String, Animation> _anims;
/** The currently running animation, or <code>null</code> for none. */
protected Animation _anim;
/** The last frame index. */
protected int _fidx;
/** The time corresponding to the last frame. */
protected float _ftime;
/** Identifies a transform frame element. */
protected static final byte TRANSFORM_ELEMENT = 0;
private static final long serialVersionUID = 1;
}
@@ -39,7 +39,13 @@ import com.jme.bounding.BoundingBox;
import com.jme.bounding.BoundingSphere;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.TriMesh;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.threerings.jme.Log;
@@ -82,11 +88,15 @@ public class ModelMesh extends TriMesh
{
_boundingType = "sphere".equals(props.getProperty("bound")) ?
SPHERE_BOUND : BOX_BOUND;
_texture = props.getProperty("texture");
_solid = !"false".equals(props.getProperty("solid"));
_transparent = "true".equals(props.getProperty("transparent"));
}
/**
* Sets the buffers as {@link ByteBuffer}s, because we can't create byte
* views of non-byte buffers.
* views of non-byte buffers. This method is where the model is
* initialized after loading.
*/
public void reconstruct (
ByteBuffer vertices, ByteBuffer normals, ByteBuffer colors,
@@ -104,12 +114,28 @@ public class ModelMesh extends TriMesh
_textureByteBuffer = textures;
_indexByteBuffer = indices;
// initialize the model if we're displaying
if (DisplaySystem.getDisplaySystem() == null) {
return;
}
if (_boundingType == BOX_BOUND) {
setModelBound(new BoundingBox());
} else { // _boundingType == SPHERE_BOUND
setModelBound(new BoundingSphere());
}
updateModelBound();
if (_backCull == null) {
initSharedStates();
}
if (_solid) {
setRenderState(_backCull);
}
if (_transparent) {
setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
setRenderState(_blendAlpha);
setRenderState(_overlayZBuffer);
}
}
// documentation inherited
@@ -153,6 +179,9 @@ public class ModelMesh extends TriMesh
out.writeInt(_textureBufferSize);
out.writeInt(_indexBufferSize);
out.writeInt(_boundingType);
out.writeObject(_texture);
out.writeBoolean(_solid);
out.writeBoolean(_transparent);
}
// documentation inherited from interface Externalizable
@@ -169,6 +198,20 @@ public class ModelMesh extends TriMesh
_textureBufferSize = in.readInt();
_indexBufferSize = in.readInt();
_boundingType = in.readInt();
_texture = (String)in.readObject();
_solid = in.readBoolean();
_transparent = in.readBoolean();
}
// documentation inherited from interface ModelSpatial
public void resolveTextures (TextureProvider tprov)
{
if (_texture != null) {
TextureState tstate = tprov.getTexture(_texture);
if (tstate != null) {
setRenderState(tstate);
}
}
}
// documentation inherited from interface ModelSpatial
@@ -289,7 +332,7 @@ public class ModelMesh extends TriMesh
/**
* Imposes the specified order on the given buffer of 32 bit values.
*/
protected void convertOrder (ByteBuffer buf, ByteOrder order)
protected static void convertOrder (ByteBuffer buf, ByteOrder order)
{
if (buf.order() == order) {
return;
@@ -301,6 +344,22 @@ public class ModelMesh extends TriMesh
}
}
/**
* Initializes the states shared between all models. Requires an active
* display.
*/
protected static void initSharedStates ()
{
Renderer renderer = DisplaySystem.getDisplaySystem().getRenderer();
_backCull = renderer.createCullState();
_backCull.setCullMode(CullState.CS_BACK);
_blendAlpha = renderer.createAlphaState();
_blendAlpha.setBlendEnabled(true);
_overlayZBuffer = renderer.createZBufferState();
_overlayZBuffer.setFunction(ZBufferState.CF_LEQUAL);
_overlayZBuffer.setWritable(false);
}
/** The sizes of the various buffers (zero for <code>null</code>). */
protected int _vertexBufferSize, _normalBufferSize, _colorBufferSize,
_textureBufferSize, _indexBufferSize;
@@ -312,6 +371,24 @@ public class ModelMesh extends TriMesh
/** The type of bounding volume that this mesh should use. */
protected int _boundingType;
/** The name of this model's texture, or <code>null</code> for none. */
protected String _texture;
/** Whether or not this mesh can enable back-face culling. */
protected boolean _solid;
/** Whether or not this mesh must be rendered as transparent. */
protected boolean _transparent;
/** The shared state for back-face culling. */
protected static CullState _backCull;
/** The shared state for alpha blending. */
protected static AlphaState _blendAlpha;
/** The shared state for checking, but not writing to, the z buffer. */
protected static ZBufferState _overlayZBuffer;
/** Indicates that this mesh should use a bounding box. */
protected static final int BOX_BOUND = 0;
@@ -98,7 +98,17 @@ public class ModelNode extends Node
attachChild((Spatial)children.get(ii));
}
}
// documentation inherited from interface ModelSpatial
public void resolveTextures (TextureProvider tprov)
{
for (Object child : getChildren()) {
if (child instanceof ModelSpatial) {
((ModelSpatial)child).resolveTextures(tprov);
}
}
}
// documentation inherited from interface ModelSpatial
public void writeBuffers (FileChannel out)
throws IOException
@@ -32,6 +32,11 @@ import java.nio.channels.FileChannel;
*/
public interface ModelSpatial
{
/**
* Recursively resolves texture references using the given provider.
*/
public void resolveTextures (TextureProvider tprov);
/**
* Recursively writes any data buffers to the output channel.
*/
@@ -0,0 +1,35 @@
//
// $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 com.jme.scene.state.TextureState;
/**
* Provides a means for models to resolve their texture references.
*/
public interface TextureProvider
{
/**
* Returns a texture state containing the named texture.
*/
public TextureState getTexture (String name);
}