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:
@@ -9,6 +9,9 @@ m.file_menu = File
|
|||||||
m.file_load = Load Model...
|
m.file_load = Load Model...
|
||||||
m.file_quit = Quit
|
m.file_quit = Quit
|
||||||
|
|
||||||
|
m.anim_menu = Animations
|
||||||
|
m.anim_stop = Stop
|
||||||
|
|
||||||
m.load_title = Select Model to Load
|
m.load_title = Select Model to Load
|
||||||
m.load_filter = Model Files (*.properties, *.dat)
|
m.load_filter = Model Files (*.properties, *.dat)
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
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;
|
||||||
@@ -29,13 +30,19 @@ import java.io.ObjectInput;
|
|||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutput;
|
import java.io.ObjectOutput;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.MappedByteBuffer;
|
import java.nio.MappedByteBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.jme.math.Quaternion;
|
||||||
|
import com.jme.math.Vector3f;
|
||||||
|
import com.jme.scene.Spatial;
|
||||||
|
|
||||||
import com.threerings.jme.Log;
|
import com.threerings.jme.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,6 +50,97 @@ import com.threerings.jme.Log;
|
|||||||
*/
|
*/
|
||||||
public class Model extends ModelNode
|
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.
|
* Attempts to read a model from the specified file.
|
||||||
*
|
*
|
||||||
@@ -102,6 +200,48 @@ public class Model extends ModelNode
|
|||||||
return _props;
|
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.
|
* Writes this model out to a file.
|
||||||
*/
|
*/
|
||||||
@@ -125,6 +265,7 @@ public class Model extends ModelNode
|
|||||||
{
|
{
|
||||||
super.writeExternal(out);
|
super.writeExternal(out);
|
||||||
out.writeObject(_props);
|
out.writeObject(_props);
|
||||||
|
out.writeObject(_anims);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // documentation inherited
|
||||||
@@ -133,10 +274,45 @@ public class Model extends ModelNode
|
|||||||
{
|
{
|
||||||
super.readExternal(in);
|
super.readExternal(in);
|
||||||
_props = (Properties)in.readObject();
|
_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. */
|
/** The model properties. */
|
||||||
protected Properties _props;
|
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;
|
private static final long serialVersionUID = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,13 @@ import com.jme.bounding.BoundingBox;
|
|||||||
import com.jme.bounding.BoundingSphere;
|
import com.jme.bounding.BoundingSphere;
|
||||||
import com.jme.math.Quaternion;
|
import com.jme.math.Quaternion;
|
||||||
import com.jme.math.Vector3f;
|
import com.jme.math.Vector3f;
|
||||||
|
import com.jme.renderer.Renderer;
|
||||||
import com.jme.scene.TriMesh;
|
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;
|
import com.threerings.jme.Log;
|
||||||
|
|
||||||
@@ -82,11 +88,15 @@ 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 = 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
|
* 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 (
|
public void reconstruct (
|
||||||
ByteBuffer vertices, ByteBuffer normals, ByteBuffer colors,
|
ByteBuffer vertices, ByteBuffer normals, ByteBuffer colors,
|
||||||
@@ -104,12 +114,28 @@ public class ModelMesh extends TriMesh
|
|||||||
_textureByteBuffer = textures;
|
_textureByteBuffer = textures;
|
||||||
_indexByteBuffer = indices;
|
_indexByteBuffer = indices;
|
||||||
|
|
||||||
|
// initialize the model if we're displaying
|
||||||
|
if (DisplaySystem.getDisplaySystem() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_boundingType == BOX_BOUND) {
|
if (_boundingType == BOX_BOUND) {
|
||||||
setModelBound(new BoundingBox());
|
setModelBound(new BoundingBox());
|
||||||
} else { // _boundingType == SPHERE_BOUND
|
} else { // _boundingType == SPHERE_BOUND
|
||||||
setModelBound(new BoundingSphere());
|
setModelBound(new BoundingSphere());
|
||||||
}
|
}
|
||||||
updateModelBound();
|
updateModelBound();
|
||||||
|
|
||||||
|
if (_backCull == null) {
|
||||||
|
initSharedStates();
|
||||||
|
}
|
||||||
|
if (_solid) {
|
||||||
|
setRenderState(_backCull);
|
||||||
|
}
|
||||||
|
if (_transparent) {
|
||||||
|
setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
|
||||||
|
setRenderState(_blendAlpha);
|
||||||
|
setRenderState(_overlayZBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited
|
// documentation inherited
|
||||||
@@ -153,6 +179,9 @@ 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.writeBoolean(_solid);
|
||||||
|
out.writeBoolean(_transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface Externalizable
|
// documentation inherited from interface Externalizable
|
||||||
@@ -169,6 +198,20 @@ 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();
|
||||||
|
_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
|
// 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.
|
* 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) {
|
if (buf.order() == order) {
|
||||||
return;
|
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>). */
|
/** The sizes of the various buffers (zero for <code>null</code>). */
|
||||||
protected int _vertexBufferSize, _normalBufferSize, _colorBufferSize,
|
protected int _vertexBufferSize, _normalBufferSize, _colorBufferSize,
|
||||||
_textureBufferSize, _indexBufferSize;
|
_textureBufferSize, _indexBufferSize;
|
||||||
@@ -312,6 +371,24 @@ 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. */
|
||||||
|
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. */
|
/** Indicates that this mesh should use a bounding box. */
|
||||||
protected static final int BOX_BOUND = 0;
|
protected static final int BOX_BOUND = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,17 @@ public class ModelNode extends Node
|
|||||||
attachChild((Spatial)children.get(ii));
|
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
|
// documentation inherited from interface ModelSpatial
|
||||||
public void writeBuffers (FileChannel out)
|
public void writeBuffers (FileChannel out)
|
||||||
throws IOException
|
throws IOException
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ import java.nio.channels.FileChannel;
|
|||||||
*/
|
*/
|
||||||
public interface ModelSpatial
|
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.
|
* 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);
|
||||||
|
}
|
||||||
@@ -22,6 +22,16 @@
|
|||||||
package com.threerings.jme.tools;
|
package com.threerings.jme.tools;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.jme.math.Quaternion;
|
||||||
|
import com.jme.math.Vector3f;
|
||||||
|
import com.jme.scene.Spatial;
|
||||||
|
|
||||||
|
import com.threerings.jme.Log;
|
||||||
|
import com.threerings.jme.model.Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic representation for keyframe animations.
|
* A basic representation for keyframe animations.
|
||||||
@@ -29,34 +39,112 @@ import java.util.ArrayList;
|
|||||||
public class AnimationDef
|
public class AnimationDef
|
||||||
{
|
{
|
||||||
/** A single frame of the animation. */
|
/** A single frame of the animation. */
|
||||||
public static class Frame
|
public static class FrameDef
|
||||||
{
|
{
|
||||||
/** Transforms for affected nodes. */
|
/** Transform for affected nodes. */
|
||||||
public ArrayList<Transform> transforms = new ArrayList<Transform>();
|
public ArrayList<TransformDef> transforms =
|
||||||
|
new ArrayList<TransformDef>();
|
||||||
|
|
||||||
public void addTransform (Transform transform)
|
public void addTransform (TransformDef transform)
|
||||||
{
|
{
|
||||||
transforms.add(transform);
|
transforms.add(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Adds all transform targets in this frame to the supplied set. */
|
||||||
|
public void addTransformTargets (
|
||||||
|
HashMap<String, Spatial> nodes, HashSet<Spatial> targets)
|
||||||
|
{
|
||||||
|
for (int ii = 0, nn = transforms.size(); ii < nn; ii++) {
|
||||||
|
String name = transforms.get(ii).name;
|
||||||
|
Spatial target = nodes.get(name);
|
||||||
|
if (target != null) {
|
||||||
|
targets.add(target);
|
||||||
|
} else {
|
||||||
|
Log.warning("Missing animation target [name=" + name +
|
||||||
|
"].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the array of transforms for this frame. */
|
||||||
|
public Model.Transform[] getTransforms (Spatial[] targets)
|
||||||
|
{
|
||||||
|
Model.Transform[] mtransforms =
|
||||||
|
new Model.Transform[targets.length];
|
||||||
|
for (int ii = 0; ii < targets.length; ii++) {
|
||||||
|
mtransforms[ii] = getTransform(targets[ii]);
|
||||||
|
}
|
||||||
|
return mtransforms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the transform for the supplied target. */
|
||||||
|
protected Model.Transform getTransform (Spatial target)
|
||||||
|
{
|
||||||
|
String name = target.getName();
|
||||||
|
for (int ii = 0, nn = transforms.size(); ii < nn; ii++) {
|
||||||
|
TransformDef transform = transforms.get(ii);
|
||||||
|
if (name.equals(transform.name)) {
|
||||||
|
return transform.getTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A transform for a single node. */
|
/** A transform for a single node. */
|
||||||
public static class Transform
|
public static class TransformDef
|
||||||
{
|
{
|
||||||
/** The name of the node to transform. */
|
/** The name of the affected node. */
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
/** The transformation parameters. */
|
/** The transformation parameters. */
|
||||||
public float[] translation;
|
public float[] translation;
|
||||||
public float[] rotation;
|
public float[] rotation;
|
||||||
public float[] scale;
|
public float[] scale;
|
||||||
|
|
||||||
|
/** Returns the live transform object. */
|
||||||
|
public Model.Transform getTransform ()
|
||||||
|
{
|
||||||
|
return new Model.Transform(
|
||||||
|
new Vector3f(translation[0], translation[1], translation[2]),
|
||||||
|
new Quaternion(rotation[0], rotation[1], rotation[2],
|
||||||
|
rotation[3]),
|
||||||
|
new Vector3f(scale[0], scale[1], scale[2]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The individual frames of the animation. */
|
/** The individual frames of the animation. */
|
||||||
public ArrayList<Frame> frames = new ArrayList<Frame>();
|
public ArrayList<FrameDef> frames = new ArrayList<FrameDef>();
|
||||||
|
|
||||||
public void addFrame (Frame frame)
|
public void addFrame (FrameDef frame)
|
||||||
{
|
{
|
||||||
frames.add(frame);
|
frames.add(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the "live" animation object that will be serialized with the
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @param props the model properties
|
||||||
|
* @param nodes the nodes in the model, mapped by name
|
||||||
|
*/
|
||||||
|
public Model.Animation createAnimation (
|
||||||
|
Properties props, HashMap<String, Spatial> nodes)
|
||||||
|
{
|
||||||
|
// find all affected nodes
|
||||||
|
HashSet<Spatial> targets = new HashSet<Spatial>();
|
||||||
|
for (int ii = 0, nn = frames.size(); ii < nn; ii++) {
|
||||||
|
frames.get(ii).addTransformTargets(nodes, targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all transforms
|
||||||
|
Model.Animation anim = new Model.Animation();
|
||||||
|
anim.transformTargets = targets.toArray(new Spatial[targets.size()]);
|
||||||
|
anim.transforms = new Model.Transform[frames.size()][targets.size()];
|
||||||
|
for (int ii = 0; ii < anim.transforms.length; ii++) {
|
||||||
|
anim.transforms[ii] =
|
||||||
|
frames.get(ii).getTransforms(anim.transformTargets);
|
||||||
|
}
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.io.IOException;
|
|||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.apache.tools.ant.BuildException;
|
import org.apache.tools.ant.BuildException;
|
||||||
@@ -35,11 +36,16 @@ import org.apache.tools.ant.DirectoryScanner;
|
|||||||
import org.apache.tools.ant.Task;
|
import org.apache.tools.ant.Task;
|
||||||
import org.apache.tools.ant.types.FileSet;
|
import org.apache.tools.ant.types.FileSet;
|
||||||
|
|
||||||
|
import com.jme.scene.Spatial;
|
||||||
|
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
import com.threerings.jme.model.BoneNode;
|
import com.threerings.jme.model.BoneNode;
|
||||||
import com.threerings.jme.model.Model;
|
import com.threerings.jme.model.Model;
|
||||||
import com.threerings.jme.model.ModelMesh;
|
import com.threerings.jme.model.ModelMesh;
|
||||||
import com.threerings.jme.model.ModelNode;
|
import com.threerings.jme.model.ModelNode;
|
||||||
import com.threerings.jme.model.SkinMesh;
|
import com.threerings.jme.model.SkinMesh;
|
||||||
|
import com.threerings.jme.tools.xml.AnimationParser;
|
||||||
import com.threerings.jme.tools.xml.ModelParser;
|
import com.threerings.jme.tools.xml.ModelParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,21 +69,45 @@ public class CompileModelTask extends Task
|
|||||||
String root = (didx == -1) ? spath : spath.substring(0, didx);
|
String root = (didx == -1) ? spath : spath.substring(0, didx);
|
||||||
File content = new File(root + ".xml"),
|
File content = new File(root + ".xml"),
|
||||||
target = new File(root + ".dat");
|
target = new File(root + ".dat");
|
||||||
if (source.lastModified() < target.lastModified() &&
|
boolean needsUpdate = false;
|
||||||
content.lastModified() < target.lastModified()) {
|
if (source.lastModified() >= target.lastModified() ||
|
||||||
return null;
|
content.lastModified() >= target.lastModified()) {
|
||||||
|
needsUpdate = true;
|
||||||
}
|
}
|
||||||
System.out.println("Compiling " + source.getParent() + "...");
|
|
||||||
|
|
||||||
// load the model properties
|
// load the model properties
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
FileInputStream in = new FileInputStream(source);
|
FileInputStream in = new FileInputStream(source);
|
||||||
props.load(in);
|
props.load(in);
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
|
// locate the animations, if any
|
||||||
|
String[] actions =
|
||||||
|
StringUtil.parseStringArray(props.getProperty("actions", ""));
|
||||||
|
File[] afiles = new File[actions.length];
|
||||||
|
File dir = source.getParentFile();
|
||||||
|
for (int ii = 0; ii < actions.length; ii++) {
|
||||||
|
afiles[ii] = new File(dir, actions[ii] + ".xml");
|
||||||
|
if (afiles[ii].lastModified() >= target.lastModified()) {
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needsUpdate) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
System.out.println("Compiling " + source.getParent() + "...");
|
||||||
|
|
||||||
// load the model content
|
// load the model content
|
||||||
ModelDef mdef = _mparser.parseModel(content.toString());
|
ModelDef mdef = _mparser.parseModel(content.toString());
|
||||||
Model model = mdef.createModel(props);
|
HashMap<String, Spatial> nodes = new HashMap<String, Spatial>();
|
||||||
|
Model model = mdef.createModel(props, nodes);
|
||||||
|
|
||||||
|
// load the actions, if any
|
||||||
|
for (int ii = 0; ii < actions.length; ii++) {
|
||||||
|
System.out.println(" Adding " + afiles[ii] + "...");
|
||||||
|
AnimationDef adef = _aparser.parseAnimation(afiles[ii].toString());
|
||||||
|
model.addAnimation(actions[ii], adef.createAnimation(props, nodes));
|
||||||
|
}
|
||||||
|
|
||||||
// write and return the model
|
// write and return the model
|
||||||
model.writeToFile(target);
|
model.writeToFile(target);
|
||||||
@@ -114,4 +144,7 @@ public class CompileModelTask extends Task
|
|||||||
|
|
||||||
/** A parser for the model definitions. */
|
/** A parser for the model definitions. */
|
||||||
protected static ModelParser _mparser = new ModelParser();
|
protected static ModelParser _mparser = new ModelParser();
|
||||||
|
|
||||||
|
/** A parser for the animation definitions. */
|
||||||
|
protected static AnimationParser _aparser = new AnimationParser();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class ModelDef
|
|||||||
public Spatial getSpatial (Properties props)
|
public Spatial getSpatial (Properties props)
|
||||||
{
|
{
|
||||||
if (_spatial == null) {
|
if (_spatial == null) {
|
||||||
_spatial = createSpatial(props);
|
_spatial = createSpatial(new NodeProperties(props, name));
|
||||||
setTransform();
|
setTransform();
|
||||||
}
|
}
|
||||||
return _spatial;
|
return _spatial;
|
||||||
@@ -137,8 +137,8 @@ public class ModelDef
|
|||||||
/** Configures the new mesh and returns it. */
|
/** Configures the new mesh and returns it. */
|
||||||
protected ModelMesh configure (ModelMesh mmesh, Properties props)
|
protected ModelMesh configure (ModelMesh mmesh, Properties props)
|
||||||
{
|
{
|
||||||
// configure using sub-properties
|
// configure using properties
|
||||||
mmesh.configure(PropertiesUtil.getSubProperties(props, name, ""));
|
mmesh.configure(props);
|
||||||
|
|
||||||
// set the various buffers
|
// set the various buffers
|
||||||
int vsize = vertices.size();
|
int vsize = vertices.size();
|
||||||
@@ -344,13 +344,15 @@ public class ModelDef
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the model node defined herein.
|
* Creates the model node defined herein.
|
||||||
|
*
|
||||||
|
* @param props the properties of the model
|
||||||
|
* @param nodes a node map to populate
|
||||||
*/
|
*/
|
||||||
public Model createModel (Properties props)
|
public Model createModel (Properties props, HashMap<String, Spatial> nodes)
|
||||||
{
|
{
|
||||||
Model model = new Model(props.getProperty("name", "model"), props);
|
Model model = new Model(props.getProperty("name", "model"), props);
|
||||||
|
|
||||||
// start by creating the spatials and mapping them to their names
|
// start by creating the spatials and mapping them to their names
|
||||||
HashMap<String, Spatial> nodes = new HashMap<String, Spatial>();
|
|
||||||
for (int ii = 0, nn = spatials.size(); ii < nn; ii++) {
|
for (int ii = 0, nn = spatials.size(); ii < nn; ii++) {
|
||||||
Spatial spatial = spatials.get(ii).getSpatial(props);
|
Spatial spatial = spatials.get(ii).getSpatial(props);
|
||||||
nodes.put(spatial.getName(), spatial);
|
nodes.put(spatial.getName(), spatial);
|
||||||
@@ -388,4 +390,34 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A wrapper for the model properties providing access to the properties
|
||||||
|
* of a node within the model. */
|
||||||
|
protected static class NodeProperties extends Properties
|
||||||
|
{
|
||||||
|
public NodeProperties (Properties mprops, String name)
|
||||||
|
{
|
||||||
|
_mprops = mprops;
|
||||||
|
_prefix = name + ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
public String getProperty (String key)
|
||||||
|
{
|
||||||
|
return getProperty(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
public String getProperty (String key, String defaultValue)
|
||||||
|
{
|
||||||
|
return _mprops.getProperty(_prefix + key,
|
||||||
|
_mprops.getProperty(key, defaultValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The properties of the model. */
|
||||||
|
protected Properties _mprops;
|
||||||
|
|
||||||
|
/** The node prefix. */
|
||||||
|
protected String _prefix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ import java.awt.event.WindowEvent;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
import javax.swing.JButton;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
@@ -52,6 +54,7 @@ import javax.swing.JPopupMenu;
|
|||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
|
||||||
|
import com.jme.image.Texture;
|
||||||
import com.jme.light.DirectionalLight;
|
import com.jme.light.DirectionalLight;
|
||||||
import com.jme.math.FastMath;
|
import com.jme.math.FastMath;
|
||||||
import com.jme.math.Vector3f;
|
import com.jme.math.Vector3f;
|
||||||
@@ -59,7 +62,9 @@ import com.jme.renderer.ColorRGBA;
|
|||||||
import com.jme.scene.Line;
|
import com.jme.scene.Line;
|
||||||
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.util.LoggingSystem;
|
import com.jme.util.LoggingSystem;
|
||||||
|
import com.jme.util.TextureManager;
|
||||||
|
|
||||||
import com.samskivert.swing.GroupLayout;
|
import com.samskivert.swing.GroupLayout;
|
||||||
import com.samskivert.util.Config;
|
import com.samskivert.util.Config;
|
||||||
@@ -68,7 +73,9 @@ import com.threerings.util.MessageBundle;
|
|||||||
import com.threerings.util.MessageManager;
|
import com.threerings.util.MessageManager;
|
||||||
|
|
||||||
import com.threerings.jme.JmeCanvasApp;
|
import com.threerings.jme.JmeCanvasApp;
|
||||||
|
import com.threerings.jme.Log;
|
||||||
import com.threerings.jme.model.Model;
|
import com.threerings.jme.model.Model;
|
||||||
|
import com.threerings.jme.model.TextureProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple viewer application that allows users to examine models and their
|
* A simple viewer application that allows users to examine models and their
|
||||||
@@ -104,6 +111,7 @@ public class ModelViewer extends JmeCanvasApp
|
|||||||
_frame.setJMenuBar(menu);
|
_frame.setJMenuBar(menu);
|
||||||
|
|
||||||
JMenu file = new JMenu(_msg.get("m.file_menu"));
|
JMenu file = new JMenu(_msg.get("m.file_menu"));
|
||||||
|
file.setMnemonic(KeyEvent.VK_F);
|
||||||
menu.add(file);
|
menu.add(file);
|
||||||
Action load = new AbstractAction(_msg.get("m.file_load")) {
|
Action load = new AbstractAction(_msg.get("m.file_load")) {
|
||||||
public void actionPerformed (ActionEvent e) {
|
public void actionPerformed (ActionEvent e) {
|
||||||
@@ -126,11 +134,20 @@ public class ModelViewer extends JmeCanvasApp
|
|||||||
KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_MASK));
|
KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_MASK));
|
||||||
file.add(quit);
|
file.add(quit);
|
||||||
|
|
||||||
_frame.getContentPane().add(getCanvas(), BorderLayout.CENTER);
|
_amenu = new JMenu(_msg.get("m.anim_menu"));
|
||||||
|
_amenu.setMnemonic(KeyEvent.VK_A);
|
||||||
|
menu.add(_amenu);
|
||||||
|
_amenu.setVisible(false);
|
||||||
|
_stop = new AbstractAction(_msg.get("m.anim_stop")) {
|
||||||
|
public void actionPerformed (ActionEvent e) {
|
||||||
|
_model.stopAnimation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_stop.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
|
||||||
|
_stop.putValue(Action.ACCELERATOR_KEY,
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK));
|
||||||
|
|
||||||
_controls = GroupLayout.makeVBox(GroupLayout.NONE, GroupLayout.TOP);
|
_frame.getContentPane().add(getCanvas(), BorderLayout.CENTER);
|
||||||
_controls.setPreferredSize(new Dimension(100, 100));
|
|
||||||
_frame.getContentPane().add(_controls, BorderLayout.EAST);
|
|
||||||
|
|
||||||
_status = new JLabel(" ");
|
_status = new JLabel(" ");
|
||||||
_status.setHorizontalAlignment(JLabel.LEFT);
|
_status.setHorizontalAlignment(JLabel.LEFT);
|
||||||
@@ -283,7 +300,7 @@ public class ModelViewer extends JmeCanvasApp
|
|||||||
_status.setText(_msg.get("m.compiling_model", file));
|
_status.setText(_msg.get("m.compiling_model", file));
|
||||||
Model model = CompileModelTask.compileModel(file);
|
Model model = CompileModelTask.compileModel(file);
|
||||||
if (model != null) {
|
if (model != null) {
|
||||||
setModel(model);
|
setModel(model, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if compileModel returned null, the .dat file is up-to-date
|
// if compileModel returned null, the .dat file is up-to-date
|
||||||
@@ -300,20 +317,65 @@ 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));
|
setModel(Model.readFromFile(file, false), file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the model once it's been loaded.
|
* Sets the model once it's been loaded.
|
||||||
|
*
|
||||||
|
* @param file the file from which the model was loaded
|
||||||
*/
|
*/
|
||||||
protected void setModel (Model model)
|
protected void setModel (Model model, File file)
|
||||||
{
|
{
|
||||||
if (_model != null) {
|
if (_model != null) {
|
||||||
_ctx.getGeometry().detachChild(_model);
|
_ctx.getGeometry().detachChild(_model);
|
||||||
}
|
}
|
||||||
_ctx.getGeometry().attachChild(_model = model);
|
_ctx.getGeometry().attachChild(_model = model);
|
||||||
_model.setLocalScale(0.04f);
|
_model.setLocalScale(0.04f);
|
||||||
|
|
||||||
|
// resolve the textures from the file's directory
|
||||||
|
final File dir = file.getParentFile();
|
||||||
|
_model.resolveTextures(new TextureProvider() {
|
||||||
|
public TextureState getTexture (String name) {
|
||||||
|
TextureState tstate = _tstates.get(name);
|
||||||
|
if (tstate == null) {
|
||||||
|
File file = new File(dir, name);
|
||||||
|
Texture tex = TextureManager.loadTexture(file.toString(),
|
||||||
|
Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR);
|
||||||
|
if (tex == null) {
|
||||||
|
Log.warning("Couldn't find texture [path=" + file +
|
||||||
|
"].");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
tstate = _ctx.getRenderer().createTextureState();
|
||||||
|
tstate.setTexture(tex);
|
||||||
|
_tstates.put(name, tstate);
|
||||||
|
}
|
||||||
|
return tstate;
|
||||||
|
}
|
||||||
|
protected HashMap<String, TextureState> _tstates =
|
||||||
|
new HashMap<String, TextureState>();
|
||||||
|
});
|
||||||
_model.updateRenderState();
|
_model.updateRenderState();
|
||||||
|
|
||||||
|
// create buttons for the model's animations
|
||||||
|
String[] anims = _model.getAnimations();
|
||||||
|
_amenu.removeAll();
|
||||||
|
if (anims.length == 0) {
|
||||||
|
_amenu.setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_amenu.setVisible(true);
|
||||||
|
for (int ii = 0; ii < anims.length; ii++) {
|
||||||
|
final String anim = anims[ii];
|
||||||
|
_amenu.add(new AbstractAction(anim) {
|
||||||
|
public void actionPerformed (ActionEvent e) {
|
||||||
|
_model.startAnimation(anim);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_amenu.addSeparator();
|
||||||
|
_amenu.add(_stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The translation bundle. */
|
/** The translation bundle. */
|
||||||
@@ -325,8 +387,11 @@ public class ModelViewer extends JmeCanvasApp
|
|||||||
/** The viewer frame. */
|
/** The viewer frame. */
|
||||||
protected JFrame _frame;
|
protected JFrame _frame;
|
||||||
|
|
||||||
/** The control panel. */
|
/** The animation menu. */
|
||||||
protected JPanel _controls;
|
protected JMenu _amenu;
|
||||||
|
|
||||||
|
/** The stop animation action. */
|
||||||
|
protected Action _stop;
|
||||||
|
|
||||||
/** The status bar. */
|
/** The status bar. */
|
||||||
protected JLabel _status;
|
protected JLabel _status;
|
||||||
|
|||||||
@@ -48,16 +48,17 @@ public class AnimationParser
|
|||||||
AnimationDef.class.getName());
|
AnimationDef.class.getName());
|
||||||
|
|
||||||
String frame = anim + "/frame";
|
String frame = anim + "/frame";
|
||||||
_digester.addObjectCreate(frame, AnimationDef.Frame.class.getName());
|
_digester.addObjectCreate(frame,
|
||||||
|
AnimationDef.FrameDef.class.getName());
|
||||||
_digester.addSetNext(frame, "addFrame",
|
_digester.addSetNext(frame, "addFrame",
|
||||||
AnimationDef.Frame.class.getName());
|
AnimationDef.FrameDef.class.getName());
|
||||||
|
|
||||||
String xform = frame + "/transform";
|
String xform = frame + "/transform";
|
||||||
_digester.addObjectCreate(xform,
|
_digester.addObjectCreate(xform,
|
||||||
AnimationDef.Transform.class.getName());
|
AnimationDef.TransformDef.class.getName());
|
||||||
_digester.addRule(xform, new SetPropertyFieldsRule());
|
_digester.addRule(xform, new SetPropertyFieldsRule());
|
||||||
_digester.addSetNext(xform, "addTransform",
|
_digester.addSetNext(xform, "addTransform",
|
||||||
AnimationDef.Transform.class.getName());
|
AnimationDef.TransformDef.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user