From d6b05553b510f349ef6da27ecff90b05791f950c Mon Sep 17 00:00:00 2001
From: Nehon
Date: Tue, 26 Dec 2017 23:19:34 +0100
Subject: [PATCH] Ogre loader now loads animations and armature with the new
system
---
.../control/KinematicRagdollControl.java | 28 ++--
.../jme3/anim/util/AnimMigrationUtils.java | 24 +--
.../jme3/cinematic/events/AnimationEvent.java | 17 +-
.../jme3test/animation/TestCinematic.java | 20 +--
.../java/jme3test/bullet/TestBoneRagdoll.java | 16 +-
.../jme3test/bullet/TestRagdollCharacter.java | 12 +-
.../java/jme3test/bullet/TestWalkingChar.java | 16 +-
.../java/jme3test/export/TestOgreConvert.java | 15 +-
.../jme3test/helloworld/HelloAnimation.java | 7 +-
.../jme3test/model/anim/TestAnimBlendBug.java | 132 ----------------
.../model/anim/TestAnimMigration.java | 9 +-
.../jme3test/model/anim/TestHWSkinning.java | 27 ++--
.../model/anim/TestModelExportingCloning.java | 23 ++-
.../jme3test/model/anim/TestOgreAnim.java | 15 +-
.../model/anim/TestOgreComplexAnim.java | 23 ++-
.../anim/TestSkeletonControlRefresh.java | 15 +-
.../jme3test/stress/TestLodGeneration.java | 17 +-
.../com/jme3/scene/plugins/ogre/AnimData.java | 13 +-
.../jme3/scene/plugins/ogre/MeshLoader.java | 60 +++----
.../scene/plugins/ogre/SkeletonLoader.java | 149 +++++++++---------
.../main/resources/Models/Oto/OtoOldAnim.j3o | Bin 0 -> 389275 bytes
.../resources/Models/Sinbad/SinbadOldAnim.j3o | Bin 0 -> 842731 bytes
22 files changed, 212 insertions(+), 426 deletions(-)
delete mode 100644 jme3-examples/src/main/java/jme3test/model/anim/TestAnimBlendBug.java
create mode 100644 jme3-testdata/src/main/resources/Models/Oto/OtoOldAnim.j3o
create mode 100644 jme3-testdata/src/main/resources/Models/Sinbad/SinbadOldAnim.j3o
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
index c1a79c946..49c0e0f34 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
@@ -31,36 +31,23 @@
*/
package com.jme3.bullet.control;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.Bone;
-import com.jme3.animation.Skeleton;
-import com.jme3.animation.SkeletonControl;
+import com.jme3.animation.*;
import com.jme3.bullet.PhysicsSpace;
-import com.jme3.bullet.collision.PhysicsCollisionEvent;
-import com.jme3.bullet.collision.PhysicsCollisionListener;
-import com.jme3.bullet.collision.PhysicsCollisionObject;
-import com.jme3.bullet.collision.RagdollCollisionListener;
+import com.jme3.bullet.collision.*;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.HullCollisionShape;
-import com.jme3.bullet.control.ragdoll.HumanoidRagdollPreset;
-import com.jme3.bullet.control.ragdoll.RagdollPreset;
-import com.jme3.bullet.control.ragdoll.RagdollUtils;
+import com.jme3.bullet.control.ragdoll.*;
import com.jme3.bullet.joints.SixDofJoint;
import com.jme3.bullet.objects.PhysicsRigidBody;
-import com.jme3.export.InputCapsule;
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.export.OutputCapsule;
-import com.jme3.export.Savable;
-import com.jme3.math.FastMath;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
+import com.jme3.export.*;
+import com.jme3.math.*;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.TempVars;
import com.jme3.util.clone.JmeCloneable;
+
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
@@ -91,7 +78,10 @@ import java.util.logging.Logger;
*
*
* @author Normen Hansen and Rémy Bouquet (Nehon)
+ *
+ * TODO this needs to be redone with the new animation system
*/
+@Deprecated
public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener, JmeCloneable {
protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName());
diff --git a/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java b/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java
index ba049c3ae..799c4a7d6 100644
--- a/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java
+++ b/jme3-core/src/main/java/com/jme3/anim/util/AnimMigrationUtils.java
@@ -80,16 +80,7 @@ public class AnimMigrationUtils {
}
for (int i = 0; i < staticJoints.length; i++) {
- Joint j = staticJoints[i];
- if (j != null) {
- // joint has no track , we create one with the default pose
- float[] times = new float[]{0};
- Vector3f[] translations = new Vector3f[]{j.getLocalTranslation()};
- Quaternion[] rotations = new Quaternion[]{j.getLocalRotation()};
- Vector3f[] scales = new Vector3f[]{j.getLocalScale()};
- JointTrack track = new JointTrack(j, times, translations, rotations, scales);
- clip.addTrack(track);
- }
+ padJointTracks(clip, staticJoints[i]);
}
composer.addAnimClip(clip);
@@ -104,6 +95,19 @@ public class AnimMigrationUtils {
}
}
+ public static void padJointTracks(AnimClip clip, Joint staticJoint) {
+ Joint j = staticJoint;
+ if (j != null) {
+ // joint has no track , we create one with the default pose
+ float[] times = new float[]{0};
+ Vector3f[] translations = new Vector3f[]{j.getLocalTranslation()};
+ Quaternion[] rotations = new Quaternion[]{j.getLocalRotation()};
+ Vector3f[] scales = new Vector3f[]{j.getLocalScale()};
+ JointTrack track = new JointTrack(j, times, translations, rotations, scales);
+ clip.addTrack(track);
+ }
+ }
+
private static class SkeletonControlVisitor implements SceneGraphVisitor {
Map skeletonArmatureMap;
diff --git a/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java b/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java
index 6dfc2a260..9616ebca5 100644
--- a/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java
+++ b/jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java
@@ -31,24 +31,16 @@
*/
package com.jme3.cinematic.events;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.LoopMode;
+import com.jme3.animation.*;
import com.jme3.app.Application;
import com.jme3.cinematic.Cinematic;
import com.jme3.cinematic.PlayState;
-import com.jme3.export.InputCapsule;
-import com.jme3.export.JmeExporter;
-import com.jme3.export.JmeImporter;
-import com.jme3.export.OutputCapsule;
+import com.jme3.export.*;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
-import com.jme3.util.clone.Cloner;
-import com.jme3.util.clone.JmeCloneable;
+
import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
import java.util.logging.Logger;
/**
@@ -60,6 +52,7 @@ import java.util.logging.Logger;
*
* @author Nehon
*/
+@Deprecated
public class AnimationEvent extends AbstractCinematicEvent {
// Version #2: directly keeping track on the model instead of trying to retrieve
diff --git a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java
index 93ad16f7f..8332ffafe 100644
--- a/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java
+++ b/jme3-examples/src/main/java/jme3test/animation/TestCinematic.java
@@ -31,13 +31,9 @@
*/
package jme3test.animation;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.AnimationFactory;
-import com.jme3.animation.LoopMode;
+import com.jme3.animation.*;
import com.jme3.app.SimpleApplication;
-import com.jme3.cinematic.Cinematic;
-import com.jme3.cinematic.MotionPath;
-import com.jme3.cinematic.PlayState;
+import com.jme3.cinematic.*;
import com.jme3.cinematic.events.*;
import com.jme3.font.BitmapText;
import com.jme3.input.ChaseCamera;
@@ -45,21 +41,18 @@ import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.FastMath;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.FadeFilter;
import com.jme3.renderer.Caps;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
-import com.jme3.scene.CameraNode;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Spatial;
+import com.jme3.scene.*;
import com.jme3.scene.shape.Box;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import de.lessvoid.nifty.Nifty;
+//TODO rework this Test when the new animation system is done.
public class TestCinematic extends SimpleApplication {
private Spatial model;
@@ -77,7 +70,6 @@ public class TestCinematic extends SimpleApplication {
app.start();
-
}
@Override
@@ -202,7 +194,7 @@ public class TestCinematic extends SimpleApplication {
private void createScene() {
- model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ model = assetManager.loadModel("Models/Oto/OtoOldAnim.j3o");
model.center();
model.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(model);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java b/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java
index bc806b018..8b86f1b0c 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestBoneRagdoll.java
@@ -36,24 +36,17 @@ import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
-import com.jme3.bullet.collision.PhysicsCollisionEvent;
-import com.jme3.bullet.collision.PhysicsCollisionObject;
-import com.jme3.bullet.collision.RagdollCollisionListener;
+import com.jme3.bullet.collision.*;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.KinematicRagdollControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
-import com.jme3.input.controls.ActionListener;
-import com.jme3.input.controls.KeyTrigger;
-import com.jme3.input.controls.MouseButtonTrigger;
+import com.jme3.input.controls.*;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.FastMath;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.debug.SkeletonDebugger;
@@ -65,6 +58,7 @@ import com.jme3.texture.Texture;
* PHYSICS RAGDOLLS ARE NOT WORKING PROPERLY YET!
* @author normenhansen
*/
+//TODO rework this Test when the new animation system is done.
public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisionListener, AnimEventListener {
private BulletAppState bulletAppState;
@@ -101,7 +95,7 @@ public class TestBoneRagdoll extends SimpleApplication implements RagdollCollisi
PhysicsTestHelper.createPhysicsTestWorld(rootNode, assetManager, bulletAppState.getPhysicsSpace());
setupLight();
- model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
+ model = (Node) assetManager.loadModel("Models/Sinbad/SinbadOldAnim.j3o");
// model.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X));
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java
index 5b9e948c8..f94307d6e 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestRagdollCharacter.java
@@ -31,10 +31,7 @@
*/
package jme3test.bullet;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.AnimEventListener;
-import com.jme3.animation.LoopMode;
+import com.jme3.animation.*;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
import com.jme3.bullet.BulletAppState;
@@ -46,9 +43,7 @@ import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
@@ -58,6 +53,7 @@ import com.jme3.texture.Texture;
/**
* @author normenhansen
*/
+//TODO rework this Test when the new animation system is done.
public class TestRagdollCharacter extends SimpleApplication implements AnimEventListener, ActionListener {
BulletAppState bulletAppState;
@@ -89,7 +85,7 @@ public class TestRagdollCharacter extends SimpleApplication implements AnimEvent
cam.setLocation(new Vector3f(-8,0,-4));
cam.lookAt(new Vector3f(4,0,-7), Vector3f.UNIT_Y);
- model = (Node) assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
+ model = (Node) assetManager.loadModel("Models/Sinbad/SinbadOldAnim.j3o");
model.lookAt(new Vector3f(0,0,-1), Vector3f.UNIT_Y);
model.setLocalTranslation(4, 0, -7f);
diff --git a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java
index d5b42d01b..4359154d1 100644
--- a/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java
+++ b/jme3-examples/src/main/java/jme3test/bullet/TestWalkingChar.java
@@ -31,10 +31,7 @@
*/
package jme3test.bullet;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.AnimEventListener;
-import com.jme3.animation.LoopMode;
+import com.jme3.animation.*;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
@@ -54,16 +51,12 @@ import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
+import com.jme3.scene.*;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.scene.shape.Sphere.TextureMode;
@@ -74,6 +67,7 @@ import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.util.SkyFactory;
+
import java.util.ArrayList;
import java.util.List;
@@ -297,7 +291,7 @@ public class TestWalkingChar extends SimpleApplication implements ActionListener
private void createCharacter() {
CapsuleCollisionShape capsule = new CapsuleCollisionShape(3f, 4f);
character = new CharacterControl(capsule, 0.01f);
- model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ model = (Node) assetManager.loadModel("Models/Oto/OtoOldAnim.j3o");
//model.setLocalScale(0.5f);
model.addControl(character);
character.setPhysicsLocation(new Vector3f(-140, 40, -10));
diff --git a/jme3-examples/src/main/java/jme3test/export/TestOgreConvert.java b/jme3-examples/src/main/java/jme3test/export/TestOgreConvert.java
index bfc03c0c5..6495c1de1 100644
--- a/jme3-examples/src/main/java/jme3test/export/TestOgreConvert.java
+++ b/jme3-examples/src/main/java/jme3test/export/TestOgreConvert.java
@@ -32,8 +32,7 @@
package jme3test.export;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
+import com.jme3.anim.AnimComposer;
import com.jme3.app.SimpleApplication;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.export.binary.BinaryImporter;
@@ -42,9 +41,8 @@ import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
+
+import java.io.*;
public class TestOgreConvert extends SimpleApplication {
@@ -71,10 +69,9 @@ public class TestOgreConvert extends SimpleApplication {
BinaryImporter imp = new BinaryImporter();
imp.setAssetManager(assetManager);
Node ogreModelReloaded = (Node) imp.load(bais, null, null);
-
- AnimControl control = ogreModelReloaded.getControl(AnimControl.class);
- AnimChannel chan = control.createChannel();
- chan.setAnim("Walk");
+
+ AnimComposer composer = ogreModelReloaded.getControl(AnimComposer.class);
+ composer.setCurrentAnimClip("Walk");
rootNode.attachChild(ogreModelReloaded);
} catch (IOException ex){
diff --git a/jme3-examples/src/main/java/jme3test/helloworld/HelloAnimation.java b/jme3-examples/src/main/java/jme3test/helloworld/HelloAnimation.java
index bb1587b3e..db9c700c8 100644
--- a/jme3-examples/src/main/java/jme3test/helloworld/HelloAnimation.java
+++ b/jme3-examples/src/main/java/jme3test/helloworld/HelloAnimation.java
@@ -32,10 +32,7 @@
package jme3test.helloworld;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.AnimEventListener;
-import com.jme3.animation.LoopMode;
+import com.jme3.animation.*;
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
@@ -70,7 +67,7 @@ public class HelloAnimation extends SimpleApplication
rootNode.addLight(dl);
/** Load a model that contains animation */
- player = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ player = (Node) assetManager.loadModel("Models/Oto/OtoOldAnim.j3o");
player.setLocalScale(0.5f);
rootNode.attachChild(player);
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestAnimBlendBug.java b/jme3-examples/src/main/java/jme3test/model/anim/TestAnimBlendBug.java
deleted file mode 100644
index b57fc83cb..000000000
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestAnimBlendBug.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package jme3test.model.anim;
-
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.app.SimpleApplication;
-import com.jme3.input.KeyInput;
-import com.jme3.input.controls.ActionListener;
-import com.jme3.input.controls.KeyTrigger;
-import com.jme3.light.DirectionalLight;
-import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Vector3f;
-import com.jme3.scene.Node;
-import com.jme3.scene.debug.SkeletonDebugger;
-
-public class TestAnimBlendBug extends SimpleApplication implements ActionListener {
-
-// private AnimControl control;
- private AnimChannel channel1, channel2;
- private String[] animNames;
-
- private float blendTime = 0.5f;
- private float lockAfterBlending = blendTime + 0.25f;
- private float blendingAnimationLock;
-
- public static void main(String[] args) {
- TestAnimBlendBug app = new TestAnimBlendBug();
- app.start();
- }
-
- public void onAction(String name, boolean value, float tpf) {
- if (name.equals("One") && value){
- channel1.setAnim(animNames[4], blendTime);
- channel2.setAnim(animNames[4], 0);
- channel1.setSpeed(0.25f);
- channel2.setSpeed(0.25f);
- blendingAnimationLock = lockAfterBlending;
- }
- }
-
- public void onPreUpdate(float tpf) {
- }
-
- public void onPostUpdate(float tpf) {
- }
-
- @Override
- public void simpleUpdate(float tpf) {
- // Is there currently a blending underway?
- if (blendingAnimationLock > 0f) {
- blendingAnimationLock -= tpf;
- }
- }
-
- @Override
- public void simpleInitApp() {
- inputManager.addMapping("One", new KeyTrigger(KeyInput.KEY_1));
- inputManager.addListener(this, "One");
-
- flyCam.setMoveSpeed(100f);
- cam.setLocation( new Vector3f( 0f, 150f, -325f ) );
- cam.lookAt( new Vector3f( 0f, 100f, 0f ), Vector3f.UNIT_Y );
-
- DirectionalLight dl = new DirectionalLight();
- dl.setDirection(new Vector3f(-0.1f, -0.7f, 1).normalizeLocal());
- dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
- rootNode.addLight(dl);
-
- Node model1 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
- Node model2 = (Node) assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
-// Node model2 = model1.clone();
-
- model1.setLocalTranslation(-60, 0, 0);
- model2.setLocalTranslation(60, 0, 0);
-
- AnimControl control1 = model1.getControl(AnimControl.class);
- animNames = control1.getAnimationNames().toArray(new String[0]);
- channel1 = control1.createChannel();
-
- AnimControl control2 = model2.getControl(AnimControl.class);
- channel2 = control2.createChannel();
-
- SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton1", control1.getSkeleton());
- Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
- mat.getAdditionalRenderState().setWireframe(true);
- mat.setColor("Color", ColorRGBA.Red);
- mat.setFloat("PointSize", 7f);
- mat.getAdditionalRenderState().setDepthTest(false);
- skeletonDebug.setMaterial(mat);
- model1.attachChild(skeletonDebug);
-
- skeletonDebug = new SkeletonDebugger("skeleton2", control2.getSkeleton());
- skeletonDebug.setMaterial(mat);
- model2.attachChild(skeletonDebug);
-
- rootNode.attachChild(model1);
- rootNode.attachChild(model2);
- }
-
-}
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java b/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java
index 3b0e8e0a3..4ed76312a 100644
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java
+++ b/jme3-examples/src/main/java/jme3test/model/anim/TestAnimMigration.java
@@ -2,7 +2,6 @@ package jme3test.model.anim;
import com.jme3.anim.AnimComposer;
import com.jme3.anim.SkinningControl;
-import com.jme3.anim.util.AnimMigrationUtils;
import com.jme3.app.ChaseCameraAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
@@ -41,12 +40,12 @@ public class TestAnimMigration extends SimpleApplication {
rootNode.addLight(new DirectionalLight(new Vector3f(-1, -1, -1).normalizeLocal()));
rootNode.addLight(new AmbientLight(ColorRGBA.DarkGray));
- Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
- // Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml").scale(0.2f).move(0, 1, 0);
+ //Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
+ Spatial model = assetManager.loadModel("Models/Oto/Oto.mesh.xml").scale(0.2f).move(0, 1, 0);
//Spatial model = assetManager.loadModel("Models/Sinbad/Sinbad.mesh.xml");
- // Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml").scale(0.02f);
+ //Spatial model = assetManager.loadModel("Models/Elephant/Elephant.mesh.xml").scale(0.02f);
- AnimMigrationUtils.migrate(model);
+ // AnimMigrationUtils.migrate(model);
rootNode.attachChild(model);
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestHWSkinning.java b/jme3-examples/src/main/java/jme3test/model/anim/TestHWSkinning.java
index 9a2e78804..980d8ca59 100644
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestHWSkinning.java
+++ b/jme3-examples/src/main/java/jme3test/model/anim/TestHWSkinning.java
@@ -31,28 +31,28 @@
*/
package jme3test.model.anim;
-import com.jme3.animation.*;
+import com.jme3.anim.AnimComposer;
+import com.jme3.anim.SkinningControl;
import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.scene.Spatial;
+
import java.util.ArrayList;
import java.util.List;
public class TestHWSkinning extends SimpleApplication implements ActionListener{
- private AnimChannel channel;
- private AnimControl control;
+
+ private AnimComposer composer;
private String[] animNames = {"Dodge", "Walk", "pull", "push"};
private final static int SIZE = 10;
private boolean hwSkinningEnable = true;
- private List skControls = new ArrayList();
+ private List skControls = new ArrayList();
private BitmapText hwsText;
public static void main(String[] args) {
@@ -77,13 +77,12 @@ public class TestHWSkinning extends SimpleApplication implements ActionListener{
Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
model.setLocalScale(0.1f);
model.setLocalTranslation(i - SIZE / 2, 0, j - SIZE / 2);
- control = model.getControl(AnimControl.class);
+ composer = model.getControl(AnimComposer.class);
- channel = control.createChannel();
- channel.setAnim(animNames[(i + j) % 4]);
- SkeletonControl skeletonControl = model.getControl(SkeletonControl.class);
- skeletonControl.setHardwareSkinningPreferred(hwSkinningEnable);
- skControls.add(skeletonControl);
+ composer.setCurrentAnimClip(animNames[(i + j) % 4]);
+ SkinningControl skinningControl = model.getControl(SkinningControl.class);
+ skinningControl.setHardwareSkinningPreferred(hwSkinningEnable);
+ skControls.add(skinningControl);
rootNode.attachChild(model);
}
}
@@ -96,7 +95,7 @@ public class TestHWSkinning extends SimpleApplication implements ActionListener{
public void onAction(String name, boolean isPressed, float tpf) {
if(isPressed && name.equals("toggleHWS")){
hwSkinningEnable = !hwSkinningEnable;
- for (SkeletonControl control : skControls) {
+ for (SkinningControl control : skControls) {
control.setHardwareSkinningPreferred(hwSkinningEnable);
hwsText.setText("HWS : "+ hwSkinningEnable);
}
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestModelExportingCloning.java b/jme3-examples/src/main/java/jme3test/model/anim/TestModelExportingCloning.java
index de162907d..80b6feb4c 100644
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestModelExportingCloning.java
+++ b/jme3-examples/src/main/java/jme3test/model/anim/TestModelExportingCloning.java
@@ -31,8 +31,7 @@
*/
package jme3test.model.anim;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
+import com.jme3.anim.AnimComposer;
import com.jme3.app.SimpleApplication;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.light.DirectionalLight;
@@ -57,27 +56,23 @@ public class TestModelExportingCloning extends SimpleApplication {
dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
rootNode.addLight(dl);
- AnimControl control;
- AnimChannel channel;
-
+ AnimComposer composer;
+
Spatial originalModel = assetManager.loadModel("Models/Oto/Oto.mesh.xml");
- control = originalModel.getControl(AnimControl.class);
- channel = control.createChannel();
- channel.setAnim("Walk");
+ composer = originalModel.getControl(AnimComposer.class);
+ composer.setCurrentAnimClip("Walk");
rootNode.attachChild(originalModel);
Spatial clonedModel = originalModel.clone();
clonedModel.move(10, 0, 0);
- control = clonedModel.getControl(AnimControl.class);
- channel = control.createChannel();
- channel.setAnim("push");
+ composer = clonedModel.getControl(AnimComposer.class);
+ composer.setCurrentAnimClip("push");
rootNode.attachChild(clonedModel);
Spatial exportedModel = BinaryExporter.saveAndLoad(assetManager, originalModel);
exportedModel.move(20, 0, 0);
- control = exportedModel.getControl(AnimControl.class);
- channel = control.createChannel();
- channel.setAnim("pull");
+ composer = exportedModel.getControl(AnimComposer.class);
+ composer.setCurrentAnimClip("pull");
rootNode.attachChild(exportedModel);
}
}
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestOgreAnim.java b/jme3-examples/src/main/java/jme3test/model/anim/TestOgreAnim.java
index b6bd4cd63..a7616f7b5 100644
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestOgreAnim.java
+++ b/jme3-examples/src/main/java/jme3test/model/anim/TestOgreAnim.java
@@ -38,15 +38,12 @@ import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
+import com.jme3.math.*;
+import com.jme3.scene.*;
import com.jme3.scene.shape.Box;
-public class TestOgreAnim extends SimpleApplication
+//TODO rework this Test when the new animation system is done.
+public class TestOgreAnim extends SimpleApplication
implements AnimEventListener, ActionListener {
private AnimChannel channel;
@@ -69,7 +66,7 @@ public class TestOgreAnim extends SimpleApplication
dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
rootNode.addLight(dl);
- Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ Spatial model = (Spatial) assetManager.loadModel("Models/Oto/OtoOldAnim.j3o");
model.center();
control = model.getControl(AnimControl.class);
@@ -102,7 +99,7 @@ public class TestOgreAnim extends SimpleApplication
// geom.getMesh().createCollisionData();
}
-
+
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
if (animName.equals("Dodge")){
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestOgreComplexAnim.java b/jme3-examples/src/main/java/jme3test/model/anim/TestOgreComplexAnim.java
index fa1283540..e83fa7a6b 100644
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestOgreComplexAnim.java
+++ b/jme3-examples/src/main/java/jme3test/model/anim/TestOgreComplexAnim.java
@@ -32,20 +32,15 @@
package jme3test.model.anim;
-import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.Bone;
-import com.jme3.animation.LoopMode;
+import com.jme3.animation.*;
import com.jme3.app.SimpleApplication;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.FastMath;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.scene.Node;
import com.jme3.scene.debug.SkeletonDebugger;
+//TODO rework this Test when the new animation system is done.
public class TestOgreComplexAnim extends SimpleApplication {
private AnimControl control;
@@ -69,7 +64,7 @@ public class TestOgreComplexAnim extends SimpleApplication {
dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));
rootNode.addLight(dl);
- Node model = (Node) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ Node model = (Node) assetManager.loadModel("Models/Oto/OtoOldAnim.j3o");
control = model.getControl(AnimControl.class);
@@ -118,8 +113,8 @@ public class TestOgreComplexAnim extends SimpleApplication {
public void simpleUpdate(float tpf){
Bone b = control.getSkeleton().getBone("spinehigh");
Bone b2 = control.getSkeleton().getBone("uparm.left");
-
- angle += tpf * rate;
+
+ angle += tpf * rate;
if (angle > FastMath.HALF_PI / 2f){
angle = FastMath.HALF_PI / 2f;
rate = -1;
@@ -133,11 +128,11 @@ public class TestOgreComplexAnim extends SimpleApplication {
b.setUserControl(true);
b.setUserTransforms(Vector3f.ZERO, q, Vector3f.UNIT_XYZ);
-
+
b2.setUserControl(true);
b2.setUserTransforms(Vector3f.ZERO, Quaternion.IDENTITY, new Vector3f(1+angle,1+ angle, 1+angle));
-
-
+
+
}
}
diff --git a/jme3-examples/src/main/java/jme3test/model/anim/TestSkeletonControlRefresh.java b/jme3-examples/src/main/java/jme3test/model/anim/TestSkeletonControlRefresh.java
index d594f197f..bbc727af3 100644
--- a/jme3-examples/src/main/java/jme3test/model/anim/TestSkeletonControlRefresh.java
+++ b/jme3-examples/src/main/java/jme3test/model/anim/TestSkeletonControlRefresh.java
@@ -37,7 +37,6 @@ package jme3test.model.anim;
*/
-
import com.jme3.animation.*;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.TextureKey;
@@ -47,11 +46,7 @@ import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.FastMath;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
+import com.jme3.math.*;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.ssao.SSAOFilter;
import com.jme3.renderer.queue.RenderQueue;
@@ -59,11 +54,11 @@ import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Quad;
import com.jme3.shadow.DirectionalLightShadowFilter;
-import com.jme3.shadow.DirectionalLightShadowRenderer;
+
import java.util.ArrayList;
import java.util.List;
-import jme3test.post.SSAOUI;
-
+
+//TODO rework this Test when the new animation system is done.
public class TestSkeletonControlRefresh extends SimpleApplication implements ActionListener{
private AnimChannel channel;
@@ -97,7 +92,7 @@ public class TestSkeletonControlRefresh extends SimpleApplication implements Act
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
- Spatial model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml");
+ Spatial model = (Spatial) assetManager.loadModel("Models/Oto/OtoOldAnim.j3o");
//setting a different material
model.setMaterial(m.clone());
model.setLocalScale(0.1f);
diff --git a/jme3-examples/src/main/java/jme3test/stress/TestLodGeneration.java b/jme3-examples/src/main/java/jme3test/stress/TestLodGeneration.java
index cf8dbb64b..5400e98d8 100644
--- a/jme3-examples/src/main/java/jme3test/stress/TestLodGeneration.java
+++ b/jme3-examples/src/main/java/jme3test/stress/TestLodGeneration.java
@@ -31,9 +31,8 @@
*/
package jme3test.stress;
+import com.jme3.anim.SkinningControl;
import com.jme3.animation.AnimChannel;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.SkeletonControl;
import com.jme3.app.SimpleApplication;
import com.jme3.bounding.BoundingBox;
import com.jme3.font.BitmapText;
@@ -43,18 +42,14 @@ import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.FastMath;
-import com.jme3.math.Vector3f;
-import com.jme3.scene.Geometry;
-import com.jme3.scene.Node;
-import com.jme3.scene.Spatial;
-import com.jme3.scene.VertexBuffer;
+import com.jme3.math.*;
+import com.jme3.scene.*;
+import jme3tools.optimize.LodGenerator;
+
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
-import jme3tools.optimize.LodGenerator;
public class TestLodGeneration extends SimpleApplication {
@@ -101,7 +96,7 @@ public class TestLodGeneration extends SimpleApplication {
// ch = model.getControl(AnimControl.class).createChannel();
// ch.setAnim("Wave");
- SkeletonControl c = model.getControl(SkeletonControl.class);
+ SkinningControl c = model.getControl(SkinningControl.class);
if (c != null) {
c.setEnabled(false);
}
diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/AnimData.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/AnimData.java
index 1b1eb2a9b..281926a46 100644
--- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/AnimData.java
+++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/AnimData.java
@@ -31,17 +31,18 @@
*/
package com.jme3.scene.plugins.ogre;
-import com.jme3.animation.Animation;
-import com.jme3.animation.Skeleton;
+import com.jme3.anim.AnimClip;
+import com.jme3.anim.Armature;
+
import java.util.ArrayList;
public class AnimData {
- public final Skeleton skeleton;
- public final ArrayList anims;
+ public final Armature armature;
+ public final ArrayList anims;
- public AnimData(Skeleton skeleton, ArrayList anims) {
- this.skeleton = skeleton;
+ public AnimData(Armature armature, ArrayList anims) {
+ this.armature = armature;
this.anims = anims;
}
}
diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MeshLoader.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MeshLoader.java
index baa30a0d1..01474b5c4 100644
--- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MeshLoader.java
+++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/MeshLoader.java
@@ -31,9 +31,7 @@
*/
package com.jme3.scene.plugins.ogre;
-import com.jme3.animation.AnimControl;
-import com.jme3.animation.Animation;
-import com.jme3.animation.SkeletonControl;
+import com.jme3.anim.*;
import com.jme3.asset.*;
import com.jme3.material.Material;
import com.jme3.material.MaterialList;
@@ -41,30 +39,23 @@ import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.*;
-import com.jme3.scene.VertexBuffer.Format;
-import com.jme3.scene.VertexBuffer.Type;
-import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.scene.VertexBuffer.*;
import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
-import com.jme3.util.BufferUtils;
-import com.jme3.util.IntMap;
+import com.jme3.util.*;
import com.jme3.util.IntMap.Entry;
-import com.jme3.util.PlaceholderAssets;
-import static com.jme3.util.xml.SAXUtil.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.*;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParserFactory;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
+
+import static com.jme3.util.xml.SAXUtil.*;
/**
* Loads Ogre3D mesh.xml files.
@@ -799,35 +790,28 @@ public class MeshLoader extends DefaultHandler implements AssetLoader {
for (int i = 0; i < geoms.size(); i++) {
Geometry g = geoms.get(i);
Mesh m = geoms.get(i).getMesh();
-
- //FIXME the parameter is now useless.
- //It was !HADWARE_SKINNING before, but since toggleing
- //HW skinning does not happen at load time it was always true.
- //We should use something similar as for the HWBoneIndex and
- //HWBoneWeight : create the vertex buffers empty so that they
- //are put in the cache, and really populate them the first time
- //software skinning is used on the mesh.
- m.generateBindPose(true);
-
+ m.generateBindPose();
}
// Put the animations in the AnimControl
- HashMap anims = new HashMap();
- ArrayList animList = animData.anims;
+ HashMap anims = new HashMap<>();
+ ArrayList animList = animData.anims;
for (int i = 0; i < animList.size(); i++) {
- Animation anim = animList.get(i);
+ AnimClip anim = animList.get(i);
anims.put(anim.getName(), anim);
}
- AnimControl ctrl = new AnimControl(animData.skeleton);
- ctrl.setAnimations(anims);
- model.addControl(ctrl);
+ AnimComposer composer = new AnimComposer();
+ for (AnimClip clip : anims.values()) {
+ composer.addAnimClip(clip);
+ }
+ model.addControl(composer);
// Put the skeleton in the skeleton control
- SkeletonControl skeletonControl = new SkeletonControl(animData.skeleton);
+ SkinningControl skinningControl = new SkinningControl(animData.armature);
// This will acquire the targets from the node
- model.addControl(skeletonControl);
+ model.addControl(skinningControl);
}
return model;
diff --git a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/SkeletonLoader.java b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/SkeletonLoader.java
index 56dc95bb6..b1350c93c 100644
--- a/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/SkeletonLoader.java
+++ b/jme3-plugins/src/ogre/java/com/jme3/scene/plugins/ogre/SkeletonLoader.java
@@ -31,45 +31,35 @@
*/
package com.jme3.scene.plugins.ogre;
-import com.jme3.animation.Animation;
-import com.jme3.animation.Bone;
-import com.jme3.animation.BoneTrack;
-import com.jme3.animation.Skeleton;
+import com.jme3.anim.*;
+import com.jme3.anim.util.AnimMigrationUtils;
import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetLoader;
-import com.jme3.asset.AssetManager;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.util.xml.SAXUtil;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Stack;
-import java.util.logging.Logger;
+import org.xml.sax.*;
+import org.xml.sax.helpers.DefaultHandler;
+
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
+import java.io.*;
+import java.util.*;
+import java.util.logging.Logger;
public class SkeletonLoader extends DefaultHandler implements AssetLoader {
private static final Logger logger = Logger.getLogger(SceneLoader.class.getName());
- private AssetManager assetManager;
+ //private AssetManager assetManager;
private Stack elementStack = new Stack();
- private HashMap indexToBone = new HashMap();
- private HashMap nameToBone = new HashMap();
- private BoneTrack track;
- private ArrayList tracks = new ArrayList();
- private Animation animation;
- private ArrayList animations;
- private Bone bone;
- private Skeleton skeleton;
+ private HashMap indexToJoint = new HashMap<>();
+ private HashMap nameToJoint = new HashMap<>();
+ private JointTrack track;
+ private ArrayList tracks = new ArrayList<>();
+ private AnimClip animClip;
+ private ArrayList animClips;
+ private Joint joint;
+ private Armature armature;
private ArrayList times = new ArrayList();
private ArrayList translations = new ArrayList();
private ArrayList rotations = new ArrayList();
@@ -80,6 +70,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
private Vector3f scale;
private float angle;
private Vector3f axis;
+ private List unusedJoints = new ArrayList<>();
public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
if (qName.equals("position") || qName.equals("translate")) {
@@ -99,38 +90,40 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
assert elementStack.peek().equals("track");
} else if (qName.equals("track")) {
assert elementStack.peek().equals("tracks");
- String boneName = SAXUtil.parseString(attribs.getValue("bone"));
- Bone bone = nameToBone.get(boneName);
- int index = skeleton.getBoneIndex(bone);
- track = new BoneTrack(index);
+ String jointName = SAXUtil.parseString(attribs.getValue("bone"));
+ joint = nameToJoint.get(jointName);
+ track = new JointTrack();
+ track.setTarget(joint);
} else if (qName.equals("boneparent")) {
assert elementStack.peek().equals("bonehierarchy");
- String boneName = attribs.getValue("bone");
+ String jointName = attribs.getValue("bone");
String parentName = attribs.getValue("parent");
- Bone bone = nameToBone.get(boneName);
- Bone parent = nameToBone.get(parentName);
- parent.addChild(bone);
+ Joint joint = nameToJoint.get(jointName);
+ Joint parent = nameToJoint.get(parentName);
+ parent.addChild(joint);
} else if (qName.equals("bone")) {
assert elementStack.peek().equals("bones");
// insert bone into indexed map
- bone = new Bone(attribs.getValue("name"));
+ joint = new Joint(attribs.getValue("name"));
int id = SAXUtil.parseInt(attribs.getValue("id"));
- indexToBone.put(id, bone);
- nameToBone.put(bone.getName(), bone);
+ indexToJoint.put(id, joint);
+ nameToJoint.put(joint.getName(), joint);
} else if (qName.equals("tracks")) {
assert elementStack.peek().equals("animation");
tracks.clear();
+ unusedJoints.clear();
+ unusedJoints.addAll(nameToJoint.values());
} else if (qName.equals("animation")) {
assert elementStack.peek().equals("animations");
String name = SAXUtil.parseString(attribs.getValue("name"));
- float length = SAXUtil.parseFloat(attribs.getValue("length"));
- animation = new Animation(name, length);
+ //float length = SAXUtil.parseFloat(attribs.getValue("length"));
+ animClip = new AnimClip(name);
} else if (qName.equals("bonehierarchy")) {
assert elementStack.peek().equals("skeleton");
} else if (qName.equals("animations")) {
assert elementStack.peek().equals("skeleton");
- animations = new ArrayList();
+ animClips = new ArrayList<>();
} else if (qName.equals("bones")) {
assert elementStack.peek().equals("skeleton");
} else if (qName.equals("skeleton")) {
@@ -149,32 +142,42 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
angle = 0;
axis = null;
} else if (qName.equals("bone")) {
- bone.setBindTransforms(position, rotation, scale);
- bone = null;
+ joint.getLocalTransform().setTranslation(position);
+ joint.getLocalTransform().setRotation(rotation);
+ if (scale != null) {
+ joint.getLocalTransform().setScale(scale);
+ }
+ joint = null;
position = null;
rotation = null;
scale = null;
} else if (qName.equals("bonehierarchy")) {
- Bone[] bones = new Bone[indexToBone.size()];
- // find bones without a parent and attach them to the skeleton
- // also assign the bones to the bonelist
- for (Map.Entry entry : indexToBone.entrySet()) {
- Bone bone = entry.getValue();
- bones[entry.getKey()] = bone;
+ Joint[] joints = new Joint[indexToJoint.size()];
+ // find joints without a parent and attach them to the armature
+ // also assign the joints to the jointList
+ for (Map.Entry entry : indexToJoint.entrySet()) {
+ Joint joint = entry.getValue();
+ joints[entry.getKey()] = joint;
}
- indexToBone.clear();
- skeleton = new Skeleton(bones);
+ indexToJoint.clear();
+ armature = new Armature(joints);
+ armature.setBindPose();
} else if (qName.equals("animation")) {
- animations.add(animation);
- animation = null;
+ //nameToJoint contains the joints with no track
+ for (Joint j : unusedJoints) {
+ AnimMigrationUtils.padJointTracks(animClip, j);
+ }
+ animClips.add(animClip);
+ animClip = null;
} else if (qName.equals("track")) {
if (track != null) { // if track has keyframes
tracks.add(track);
+ unusedJoints.remove(joint);
track = null;
}
} else if (qName.equals("tracks")) {
- BoneTrack[] trackList = tracks.toArray(new BoneTrack[tracks.size()]);
- animation.setTracks(trackList);
+ JointTrack[] trackList = tracks.toArray(new JointTrack[tracks.size()]);
+ animClip.setTracks(trackList);
tracks.clear();
} else if (qName.equals("keyframe")) {
assert time >= 0;
@@ -182,14 +185,13 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
assert rotation != null;
times.add(time);
- translations.add(position);
- rotations.add(rotation);
+ translations.add(position.addLocal(joint.getLocalTranslation()));
+ rotations.add(joint.getLocalRotation().mult(rotation, rotation));
if (scale != null) {
- scales.add(scale);
+ scales.add(scale.multLocal(joint.getLocalScale()));
}else{
scales.add(new Vector3f(1,1,1));
}
-
time = -1;
position = null;
rotation = null;
@@ -206,7 +208,6 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
Vector3f[] scalesArray = scales.toArray(new Vector3f[scales.size()]);
track.setKeyframes(timesArray, transArray, rotArray, scalesArray);
- //track.setKeyframes(timesArray, transArray, rotArray);
} else {
track = null;
}
@@ -216,7 +217,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
rotations.clear();
scales.clear();
} else if (qName.equals("skeleton")) {
- nameToBone.clear();
+ nameToJoint.clear();
}
assert elementStack.peek().equals(qName);
elementStack.pop();
@@ -228,17 +229,17 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
*/
private void fullReset() {
elementStack.clear();
- indexToBone.clear();
- nameToBone.clear();
+ indexToJoint.clear();
+ nameToJoint.clear();
track = null;
tracks.clear();
- animation = null;
- if (animations != null) {
- animations.clear();
+ animClip = null;
+ if (animClips != null) {
+ animClips.clear();
}
- bone = null;
- skeleton = null;
+ joint = null;
+ armature = null;
times.clear();
rotations.clear();
translations.clear();
@@ -266,12 +267,12 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
xr.setErrorHandler(this);
InputStreamReader r = new InputStreamReader(in);
xr.parse(new InputSource(r));
- if (animations == null) {
- animations = new ArrayList();
+ if (animClips == null) {
+ animClips = new ArrayList();
}
- AnimData data = new AnimData(skeleton, animations);
- skeleton = null;
- animations = null;
+ AnimData data = new AnimData(armature, animClips);
+ armature = null;
+ animClips = null;
return data;
} catch (SAXException ex) {
IOException ioEx = new IOException("Error while parsing Ogre3D dotScene");
@@ -288,7 +289,7 @@ public class SkeletonLoader extends DefaultHandler implements AssetLoader {
}
public Object load(AssetInfo info) throws IOException {
- assetManager = info.getManager();
+ //AssetManager assetManager = info.getManager();
InputStream in = null;
try {
in = info.openStream();
diff --git a/jme3-testdata/src/main/resources/Models/Oto/OtoOldAnim.j3o b/jme3-testdata/src/main/resources/Models/Oto/OtoOldAnim.j3o
new file mode 100644
index 0000000000000000000000000000000000000000..101dd8405eacf4d6193b2a5e72ede4bd608d3f82
GIT binary patch
literal 389275
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