Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions jme3-core/src/main/java/com/jme3/anim/TransformTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,13 @@ public void getDataAtTime(double t, Transform transform) {
int endFrame = 1;
float blend = 0;
if (time >= times[lastFrame]) {
// extrapolate beyond the final frame of the animation
startFrame = lastFrame;

time = time - times[startFrame] + times[startFrame - 1];
blend = (time - times[startFrame - 1])
/ (times[startFrame] - times[startFrame - 1]);
float inferredInterval = times[lastFrame] - times[lastFrame - 1];
if (inferredInterval > 0f) {
blend = (time - times[startFrame]) / inferredInterval;
}

} else {
// use lastFrame so we never overflow the array
Expand Down
53 changes: 46 additions & 7 deletions jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2019 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -36,7 +36,10 @@
import com.jme3.material.MatParamTexture;

import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -161,16 +164,27 @@ public static int getSavedSavableVersion(Object savable, Class<? extends Savable
* @return the Savable instance of the class.
* @throws InstantiationException thrown if the class does not have an empty constructor.
* @throws IllegalAccessException thrown if the class is not accessable.
* @throws java.lang.reflect.InvocationTargetException
* @throws ClassNotFoundException thrown if the class name is not in the classpath.
* @throws IOException when loading ctor parameters fails
*/
public static Savable fromName(String className) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, IOException {

public static Savable fromName(String className)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, InvocationTargetException {
className = remapClass(className);

Constructor noArgConstructor = findNoArgConstructor(className);
if (noArgConstructor == null) {
throw new InstantiationException(
"Loading requires a no-arg constructor, but class "
+ className + " lacks one.");
}

noArgConstructor.setAccessible(true);

Object[] os = null;
try {
return (Savable) Class.forName(className).newInstance();
} catch (InstantiationException e) {
return (Savable) noArgConstructor.newInstance(os);
} catch (InvocationTargetException | InstantiationException e) {
Logger.getLogger(SavableClassUtil.class.getName()).log(
Level.SEVERE, "Could not access constructor of class ''{0}" + "''! \n"
+ "Some types need to have the BinaryImporter set up in a special way. Please doublecheck the setup.", className);
Expand All @@ -184,6 +198,7 @@ public static Savable fromName(String className) throws InstantiationException,
}

public static Savable fromName(String className, List<ClassLoader> loaders) throws InstantiationException,
InvocationTargetException, NoSuchMethodException,
IllegalAccessException, ClassNotFoundException, IOException {
if (loaders == null) {
return fromName(className);
Expand All @@ -208,4 +223,28 @@ public static Savable fromName(String className, List<ClassLoader> loaders) thro

return fromName(className);
}

/**
* Use reflection to gain access to the no-arg constructor of the named
* class.
*
* @return the pre-existing constructor, or null if the class lacks a no-arg
* constructor
*/
private static Constructor findNoArgConstructor(String className)
throws ClassNotFoundException {
Class clazz = Class.forName(className);
Constructor[] allConstructors = clazz.getDeclaredConstructors();
AccessibleObject.setAccessible(allConstructors, true);

Constructor result = null;
for (Constructor constructor : allConstructors) {
if (constructor.getParameterTypes().length == 0) {
result = constructor;
break;
}
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -345,16 +345,7 @@ public Savable readObject(int id) {

return out;

} catch (IOException e) {
logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e);
return null;
} catch (ClassNotFoundException e) {
logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e);
return null;
} catch (InstantiationException e) {
logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e);
return null;
} catch (IllegalAccessException e) {
} catch (Exception e) {
logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e);
return null;
}
Expand Down
85 changes: 85 additions & 0 deletions jme3-examples/src/main/java/jme3test/animation/TestIssue1138.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2019 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.animation;

import com.jme3.anim.AnimComposer;
import com.jme3.anim.Joint;
import com.jme3.anim.SkinningControl;
import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;

/**
* Test case for JME issue #1138: Elephant's legUp animation sets Joint
* translation to NaN.
* <p>
* If successful, the animation cycle will complete without throwing an
* IllegalStateException.
*
* @author Stephen Gold
*/
public class TestIssue1138 extends SimpleApplication {

SkinningControl sControl;

public static void main(String... argv) {
new TestIssue1138().start();
}

@Override
public void simpleInitApp() {
Node cgModel = (Node) assetManager.loadModel(
"Models/Elephant/Elephant.mesh.xml");
rootNode.attachChild(cgModel);
cgModel.rotate(0f, -1f, 0f);
cgModel.scale(0.04f);

AnimComposer composer = cgModel.getControl(AnimComposer.class);
composer.setCurrentAction("legUp");
sControl = cgModel.getControl(SkinningControl.class);

AmbientLight light = new AmbientLight();
rootNode.addLight(light);
}

@Override
public void simpleUpdate(float tpf) {
for (Joint joint : sControl.getArmature().getJointList()) {
Vector3f translation = joint.getLocalTranslation();
if (!Vector3f.isValidVector(translation)) {
String msg = "Invalid translation for joint " + joint.getName();
throw new IllegalStateException(msg);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2019 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -38,6 +38,7 @@
import com.jme3.util.BufferUtils;
import com.jme3.util.IntMap;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
Expand Down Expand Up @@ -962,6 +963,7 @@ public Savable readSavable(String name, Savable defVal) throws IOException {

private Savable readSavableFromCurrentElem(Savable defVal) throws
InstantiationException, ClassNotFoundException,
NoSuchMethodException, InvocationTargetException,
IOException, IllegalAccessException {
Savable ret = defVal;
Savable tmp = null;
Expand Down