Strange error while key animation

Started by Thunderfox, July 20, 2011, 01:19:24 AM

Previous topic - Next topic

Thunderfox

Hello :)
Today I found this engine for Android. It seems to be really usefull and I want to use it for a little game.

But while I testing the key animation function, I got strange results:
There are two 3ds files, which I load in an animation object. When I use the Object3D.animate(index, seq); function on the object, the object is animate only from first object to second. I cannot go back by reducing index from 1 to 0 over the time.
Later I note that the animation is played also when I used a static value for index. If index is 0.0001f, the animation is very slow and when it's higher, the animation is also faster.

I used this code but I don't think that there is an error:
package com.threed.jpct.example;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;

import com.threed.jpct.Animation;
import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Light;
import com.threed.jpct.Loader;
import com.threed.jpct.Logger;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.BitmapHelper;
import com.threed.jpct.util.MemoryHelper;

/**
* A simple demo. This shows more how to use jPCT-AE than it shows how to write
* a proper application for Android.
* It includes basic activity management to handle pause and resume...
*
* @author EgonOlsen
*
*/
public class HelloWorld extends Activity {

// Used to handle pause and resume...
private static HelloWorld master = null;

private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private World world = null;
private RGBColor back = new RGBColor(50, 50, 100);

private float touchTurn = 0;
private float touchTurnUp = 0;

private float xpos = -1;
private float ypos = -1;

private Object3D cube = null;
private int fps = 0;

private Light sun = null;

protected void onCreate(Bundle savedInstanceState) {

Logger.log("onCreate");

if (master != null) {
copy(master);
}

super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(getApplication());

mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
// Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
// back to Pixelflinger on some device (read: Samsung I7500)
int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}
});

renderer = new MyRenderer();
mGLView.setRenderer(renderer);
setContentView(mGLView);
}

@Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}

@Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}

protected void onStop() {
super.onStop();
}

private void copy(Object src) {
try {
Logger.log("Copying data from master Activity!");
Field[] fs = src.getClass().getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
f.set(this, f.get(src));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public boolean onTouchEvent(MotionEvent me) {

if (me.getAction() == MotionEvent.ACTION_DOWN) {
xpos = me.getX();
ypos = me.getY();
return true;
}

if (me.getAction() == MotionEvent.ACTION_UP) {
xpos = -1;
ypos = -1;
touchTurn = 0;
touchTurnUp = 0;
return true;
}

if (me.getAction() == MotionEvent.ACTION_MOVE) {
float xd = me.getX() - xpos;
float yd = me.getY() - ypos;

xpos = me.getX();
ypos = me.getY();

touchTurn = xd / -100f;
touchTurnUp = yd / -100f;
return true;
}

try {
Thread.sleep(15);
} catch (Exception e) {
// No need for this...
}

return super.onTouchEvent(me);
}

protected boolean isFullscreenOpaque() {
return true;
}

class MyRenderer implements GLSurfaceView.Renderer {

private long time = System.currentTimeMillis();
private boolean stop = false;
private float ind;
private int an = 2;

public MyRenderer() {
}

public void stop() {
stop = true;
}

public void onSurfaceChanged(GL10 gl, int w, int h) {
if (fb != null) {
fb.dispose();
}
fb = new FrameBuffer(gl, w, h);

if (master == null) {

world = new World();
world.setAmbientLight(20, 20, 20);

sun = new Light(world);
sun.setIntensity(250, 250, 250);

// Create a texture out of the icon...:-)
Texture texture = new Texture(BitmapHelper.rescale(BitmapHelper.convert(getResources().getDrawable(R.drawable.icon)), 64, 64));
TextureManager.getInstance().addTexture("texture", texture);



try {
cube = loadModel(getAssets().open( "magiera.3ds" ), 10);

        Animation anim = new Animation(3);
        anim.setInterpolationMethod(Animation.LINEAR);
        anim.setCaching(false);
       
        anim.createSubSequence("idle");
        anim.addKeyFrame(cube.getMesh());

        anim.createSubSequence("walk");
        anim.addKeyFrame(cube.getMesh());
        anim.addKeyFrame(loadModel(getAssets().open( "magierb.3ds" ), 10).getMesh());

        cube.setAnimationSequence(anim);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

cube.calcTextureWrapSpherical();
cube.setTexture("texture");
cube.strip();
cube.build();

world.addObject(cube);

Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
cam.lookAt(cube.getTransformedCenter());

SimpleVector sv = new SimpleVector();
sv.set(cube.getTransformedCenter());
sv.y -= 100;
sv.z -= 100;
sun.setPosition(sv);
MemoryHelper.compact();

if (master == null) {
Logger.log("Saving master Activity!");
master = HelloWorld.this;
}
}
}

    private Object3D loadModel(InputStream objStream, float scale) {
        Loader.setVertexOptimization(false);
        Object3D[] model = Loader.load3DS(objStream, scale);

        Object3D o3d = new Object3D(0);

        Object3D temp = null;

        for (int i = 0; i < model.length; i++) {
            temp = model[i];
            temp.setCenter(SimpleVector.ORIGIN);
            temp.rotateX((float)( -.5*Math.PI));
            temp.rotateMesh();
            temp.setRotationMatrix(new Matrix());
            o3d = Object3D.mergeObjects(o3d, temp);
            o3d.calcBoundingBox();
            o3d.calcNormals();
        }
        return o3d;
    }

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}

public void onDrawFrame(GL10 gl) {

try {
if (!stop) {
doAnim();
if (touchTurn != 0) {
cube.rotateY(touchTurn);
touchTurn = 0;
}

if (touchTurnUp != 0) {
cube.rotateX(touchTurnUp);
touchTurnUp = 0;
}

fb.clear(back);
world.renderScene(fb);
world.draw(fb);
fb.display();

if (System.currentTimeMillis() - time >= 1000) {
Logger.log(fps + "fps");
fps = 0;
time = System.currentTimeMillis();
}
fps++;
} else {
if (fb != null) {
fb.dispose();
fb = null;
}
}
} catch (Exception e) {
Logger.log(e, Logger.MESSAGE);
}
}

    public void doAnim() {
    ind += 0.01f;
    if(ind > 1){
    ind--;
    }
   
        cube.animate(0.003f,2);

   
    }
}
}


Could be an error in the Object.animate(index,seq); function?

EgonOlsen

That's because you are using the same mesh as keyframe and the objects base mesh resulting in making the animation modify it's own keyframes, which isn't a good idea. Try to add the .cloneMesh(true); behind each getMesh() and see if that helps.

Thunderfox


EgonOlsen

I'll add a check to the next version that should help to auto-fix this issue at runtime.