- fixed bad time calculation on cinematics

- Used a nano timer for precision
- javadoc'ed a bit

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8443 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 13 years ago
parent 4c71cbc818
commit be6259e5ba
  1. 9
      engine/src/core/com/jme3/cinematic/Cinematic.java
  2. 107
      engine/src/core/com/jme3/cinematic/events/AbstractCinematicEvent.java
  3. 3
      engine/src/core/com/jme3/cinematic/events/AnimationTrack.java
  4. 3
      engine/src/core/com/jme3/cinematic/events/GuiTrack.java
  5. 20
      engine/src/core/com/jme3/cinematic/events/MotionTrack.java
  6. 4
      engine/src/core/com/jme3/cinematic/events/PositionTrack.java
  7. 4
      engine/src/core/com/jme3/cinematic/events/RotationTrack.java
  8. 4
      engine/src/core/com/jme3/cinematic/events/ScaleTrack.java
  9. 3
      engine/src/core/com/jme3/cinematic/events/SoundTrack.java
  10. 3
      engine/src/test/jme3test/animation/SubtitleTrack.java
  11. 18
      engine/src/test/jme3test/animation/TestCinematic.java

@ -166,7 +166,6 @@ public class Cinematic extends AbstractCinematicEvent implements AppState {
@Override @Override
public void setSpeed(float speed) { public void setSpeed(float speed) {
super.setSpeed(speed); super.setSpeed(speed);
duration = initialDuration / speed;
for (int i = 0; i < cinematicEvents.size(); i++) { for (int i = 0; i < cinematicEvents.size(); i++) {
CinematicEvent ce = cinematicEvents.get(i); CinematicEvent ce = cinematicEvents.get(i);
ce.setSpeed(speed); ce.setSpeed(speed);
@ -185,6 +184,7 @@ public class Cinematic extends AbstractCinematicEvent implements AppState {
nifty.fromXmlWithoutStartScreen(niftyXmlPath); nifty.fromXmlWithoutStartScreen(niftyXmlPath);
app.getGuiViewPort().addProcessor(niftyDisplay); app.getGuiViewPort().addProcessor(niftyDisplay);
} }
initEvent(app, this);
for (CinematicEvent cinematicEvent : cinematicEvents) { for (CinematicEvent cinematicEvent : cinematicEvents) {
cinematicEvent.initEvent(app, this); cinematicEvent.initEvent(app, this);
} }
@ -203,12 +203,11 @@ public class Cinematic extends AbstractCinematicEvent implements AppState {
play(); play();
} }
} }
public boolean isEnabled() { public boolean isEnabled() {
return playState == PlayState.Playing; return playState == PlayState.Playing;
} }
public void stateAttached(AppStateManager stateManager) { public void stateAttached(AppStateManager stateManager) {
} }
@ -303,8 +302,8 @@ public class Cinematic extends AbstractCinematicEvent implements AppState {
enableCurrentCam(true); enableCurrentCam(true);
} }
public void activateCamera(float time, final String cameraName) { public void activateCamera(float timeStamp, final String cameraName) {
addCinematicEvent(time, new AbstractCinematicEvent() { addCinematicEvent(timeStamp, new AbstractCinematicEvent() {
@Override @Override
public void onPlay() { public void onPlay() {

@ -39,13 +39,16 @@ import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable; import com.jme3.system.NanoTimer;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* * This calls contains basic behavior of a cinematic event
* every cinematic event must extend this class
*
* A cinematic event must be given an inital duration in seconds (duration of the event at speed = 1) (default is 10)
* @author Nehon * @author Nehon
*/ */
public abstract class AbstractCinematicEvent implements CinematicEvent { public abstract class AbstractCinematicEvent implements CinematicEvent {
@ -53,32 +56,61 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
protected PlayState playState = PlayState.Stopped; protected PlayState playState = PlayState.Stopped;
protected float speed = 1; protected float speed = 1;
protected float initialDuration = 10; protected float initialDuration = 10;
protected float duration = initialDuration / speed;
protected LoopMode loopMode = LoopMode.DontLoop; protected LoopMode loopMode = LoopMode.DontLoop;
protected float time = 0; protected float time = 0;
//nano timer for precisely computing the elapsed time
protected NanoTimer timer;
/**
* the last time the event was paused
*/
protected float elapsedTimePause = 0;
/**
* the list of listeners
*/
protected List<CinematicEventListener> listeners; protected List<CinematicEventListener> listeners;
/**
* contruct a cinematic event
*/
public AbstractCinematicEvent() { public AbstractCinematicEvent() {
} }
/**
* contruct a cinematic event wwith the given initial duration
* @param initialDuration
*/
public AbstractCinematicEvent(float initialDuration) { public AbstractCinematicEvent(float initialDuration) {
this.initialDuration = initialDuration; this.initialDuration = initialDuration;
duration = initialDuration / speed;
} }
/**
* contruct a cinematic event with the given loopMode
* @param loopMode
*/
public AbstractCinematicEvent(LoopMode loopMode) { public AbstractCinematicEvent(LoopMode loopMode) {
this.loopMode = loopMode; this.loopMode = loopMode;
} }
/**
* contruct a cinematic event with the given loopMode and the given initialDuration
* @param initialDuration the duration of the event at speed = 1
* @param loopMode the loop mode of the event
*/
public AbstractCinematicEvent(float initialDuration, LoopMode loopMode) { public AbstractCinematicEvent(float initialDuration, LoopMode loopMode) {
this.initialDuration = initialDuration; this.initialDuration = initialDuration;
this.loopMode = loopMode; this.loopMode = loopMode;
duration = initialDuration / speed;
} }
/**
* Play this event
*/
public void play() { public void play() {
onPlay(); onPlay();
playState = PlayState.Playing; playState = PlayState.Playing;
if (timer == null) {
timer = new NanoTimer();
}
timer.reset();
if (listeners != null) { if (listeners != null) {
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
CinematicEventListener cel = listeners.get(i); CinematicEventListener cel = listeners.get(i);
@ -87,21 +119,32 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
} }
} }
public abstract void onPlay(); /**
* Place here the code you want to execute when the event is started
*/
protected abstract void onPlay();
/**
* should be used internally only
* @param tpf time per frame
*/
public void internalUpdate(float tpf) { public void internalUpdate(float tpf) {
if (playState == PlayState.Playing) { if (playState == PlayState.Playing) {
time += tpf * speed; time = (elapsedTimePause + timer.getTimeInSeconds()) * speed;
onUpdate(tpf); onUpdate(tpf);
if (time >= duration && loopMode == loopMode.DontLoop) { if (time >= initialDuration && loopMode == loopMode.DontLoop) {
stop(); stop();
} }
} }
} }
public abstract void onUpdate(float tpf); /**
* Place here the code you want to execute on update (only called when the event is playing)
* @param tpf time per frame
*/
protected abstract void onUpdate(float tpf);
/** /**
* stops the animation, next time play() is called the animation will start from the begining. * stops the animation, next time play() is called the animation will start from the begining.
@ -110,6 +153,7 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
onStop(); onStop();
time = 0; time = 0;
playState = PlayState.Stopped; playState = PlayState.Stopped;
elapsedTimePause = 0;
if (listeners != null) { if (listeners != null) {
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
CinematicEventListener cel = listeners.get(i); CinematicEventListener cel = listeners.get(i);
@ -118,11 +162,18 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
} }
} }
public abstract void onStop(); /**
* Place here the code you want to execute when the event is stoped.
*/
protected abstract void onStop();
/**
* pause this event
*/
public void pause() { public void pause() {
onPause(); onPause();
playState = PlayState.Paused; playState = PlayState.Paused;
elapsedTimePause = time;
if (listeners != null) { if (listeners != null) {
for (int i = 0; i < listeners.size(); i++) { for (int i = 0; i < listeners.size(); i++) {
CinematicEventListener cel = listeners.get(i); CinematicEventListener cel = listeners.get(i);
@ -131,6 +182,9 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
} }
} }
/**
* place here the code you want to execute when the event is paused
*/
public abstract void onPause(); public abstract void onPause();
/** /**
@ -138,7 +192,7 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
* @return * @return
*/ */
public float getDuration() { public float getDuration() {
return duration; return initialDuration / speed;
} }
/** /**
@ -149,7 +203,6 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
*/ */
public void setSpeed(float speed) { public void setSpeed(float speed) {
this.speed = speed; this.speed = speed;
duration = initialDuration / speed;
} }
/** /**
@ -182,7 +235,6 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
*/ */
public void setInitialDuration(float initialDuration) { public void setInitialDuration(float initialDuration) {
this.initialDuration = initialDuration; this.initialDuration = initialDuration;
duration = initialDuration / speed;
} }
/** /**
@ -203,6 +255,11 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
this.loopMode = loopMode; this.loopMode = loopMode;
} }
/**
* for serialization only
* @param ex exporter
* @throws IOException
*/
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
oc.write(playState, "playState", PlayState.Stopped); oc.write(playState, "playState", PlayState.Stopped);
@ -211,18 +268,32 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
oc.write(loopMode, "loopMode", LoopMode.DontLoop); oc.write(loopMode, "loopMode", LoopMode.DontLoop);
} }
/**
* for serialization only
* @param im importer
* @throws IOException
*/
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this); InputCapsule ic = im.getCapsule(this);
playState = ic.readEnum("playState", PlayState.class, PlayState.Stopped); playState = ic.readEnum("playState", PlayState.class, PlayState.Stopped);
speed = ic.readFloat("speed", 1); speed = ic.readFloat("speed", 1);
initialDuration = ic.readFloat("initalDuration", 10); initialDuration = ic.readFloat("initalDuration", 10);
duration = initialDuration / speed;
loopMode = ic.readEnum("loopMode", LoopMode.class, LoopMode.DontLoop); loopMode = ic.readEnum("loopMode", LoopMode.class, LoopMode.DontLoop);
} }
/**
* initialize this event (should be called internally only)
* @param app
* @param cinematic
*/
public void initEvent(Application app, Cinematic cinematic) { public void initEvent(Application app, Cinematic cinematic) {
timer = new NanoTimer();
} }
/**
* return a list of CinematicEventListener added on this event
* @return
*/
private List<CinematicEventListener> getListeners() { private List<CinematicEventListener> getListeners() {
if (listeners == null) { if (listeners == null) {
listeners = new ArrayList<CinematicEventListener>(); listeners = new ArrayList<CinematicEventListener>();
@ -230,10 +301,18 @@ public abstract class AbstractCinematicEvent implements CinematicEvent {
return listeners; return listeners;
} }
/**
* Add a CinematicEventListener to this event
* @param listener CinematicEventListener
*/
public void addListener(CinematicEventListener listener) { public void addListener(CinematicEventListener listener) {
getListeners().add(listener); getListeners().add(listener);
} }
/**
* remove a CinematicEventListener from this event
* @param listener CinematicEventListener
*/
public void removeListener(CinematicEventListener listener) { public void removeListener(CinematicEventListener listener) {
getListeners().remove(listener); getListeners().remove(listener);
} }

@ -85,6 +85,7 @@ public class AnimationTrack extends AbstractCinematicEvent {
@Override @Override
public void initEvent(Application app, Cinematic cinematic) { public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
if (channel == null) { if (channel == null) {
Object s = cinematic.getEventData("modelChannels", modelName); Object s = cinematic.getEventData("modelChannels", modelName);
if (s != null && s instanceof AnimChannel) { if (s != null && s instanceof AnimChannel) {
@ -107,6 +108,7 @@ public class AnimationTrack extends AbstractCinematicEvent {
channel.getControl().setEnabled(true); channel.getControl().setEnabled(true);
if (playState == PlayState.Stopped) { if (playState == PlayState.Stopped) {
channel.setAnim(animationName); channel.setAnim(animationName);
channel.setSpeed(speed);
} }
} }
@ -117,6 +119,7 @@ public class AnimationTrack extends AbstractCinematicEvent {
@Override @Override
public void onStop() { public void onStop() {
channel.getControl().setEnabled(false); channel.getControl().setEnabled(false);
channel.setTime(0);
} }
@Override @Override

@ -75,12 +75,13 @@ public class GuiTrack extends AbstractCinematicEvent {
@Override @Override
public void initEvent(Application app, Cinematic cinematic) { public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
nifty = cinematic.getNifty(); nifty = cinematic.getNifty();
} }
@Override @Override
public void onPlay() { public void onPlay() {
nifty.gotoScreen(screen); nifty.gotoScreen(screen);
} }
@Override @Override

@ -46,6 +46,7 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control; import com.jme3.scene.control.Control;
import com.jme3.system.NanoTimer;
import java.io.IOException; import java.io.IOException;
/** /**
@ -66,7 +67,7 @@ public class MotionTrack extends AbstractCinematicEvent implements Control {
protected Quaternion rotation; protected Quaternion rotation;
protected Direction directionType = Direction.None; protected Direction directionType = Direction.None;
protected MotionPath path; protected MotionPath path;
private boolean isControl=true; private boolean isControl = true;
/** /**
@ -157,11 +158,12 @@ public class MotionTrack extends AbstractCinematicEvent implements Control {
} }
public void update(float tpf) { public void update(float tpf) {
if(isControl){ if (isControl) {
if (playState == PlayState.Playing) { if (playState == PlayState.Playing) {
time += tpf * speed; time = (elapsedTimePause + timer.getTimeInSeconds()) * speed;
onUpdate(tpf); onUpdate(tpf);
if (time >= duration && loopMode == loopMode.DontLoop) { if (time >= initialDuration && loopMode == loopMode.DontLoop) {
stop(); stop();
} }
} }
@ -171,13 +173,13 @@ public class MotionTrack extends AbstractCinematicEvent implements Control {
@Override @Override
public void initEvent(Application app, Cinematic cinematic) { public void initEvent(Application app, Cinematic cinematic) {
isControl=false; super.initEvent(app, cinematic);
isControl = false;
timer = null;
} }
public void onUpdate(float tpf) { public void onUpdate(float tpf) {
spatial.setLocalTranslation(path.interpolatePath(tpf, this)); spatial.setLocalTranslation(path.interpolatePath(tpf * speed, this));
computeTargetDirection(); computeTargetDirection();
if (currentValue >= 1.0f) { if (currentValue >= 1.0f) {
@ -270,10 +272,8 @@ public class MotionTrack extends AbstractCinematicEvent implements Control {
control.lookAt = lookAt.clone(); control.lookAt = lookAt.clone();
control.upVector = upVector.clone(); control.upVector = upVector.clone();
control.rotation = rotation.clone(); control.rotation = rotation.clone();
control.duration = duration;
control.initialDuration = initialDuration; control.initialDuration = initialDuration;
control.speed = speed; control.speed = speed;
control.duration = duration;
control.loopMode = loopMode; control.loopMode = loopMode;
control.directionType = directionType; control.directionType = directionType;

@ -78,7 +78,7 @@ public class PositionTrack extends AbstractCinematicEvent {
if (playState != playState.Paused) { if (playState != playState.Paused) {
startPosition = spatial.getWorldTranslation().clone(); startPosition = spatial.getWorldTranslation().clone();
} }
if (duration == 0 && spatial != null) { if (initialDuration == 0 && spatial != null) {
spatial.setLocalTranslation(endPosition); spatial.setLocalTranslation(endPosition);
} }
@ -87,7 +87,7 @@ public class PositionTrack extends AbstractCinematicEvent {
@Override @Override
public void onUpdate(float tpf) { public void onUpdate(float tpf) {
if (spatial != null) { if (spatial != null) {
value += Math.min(tpf * speed / duration, 1.0f); value = Math.min(time / initialDuration, 1.0f);
Vector3f pos = FastMath.interpolateLinear(value, startPosition, endPosition); Vector3f pos = FastMath.interpolateLinear(value, startPosition, endPosition);
spatial.setLocalTranslation(pos); spatial.setLocalTranslation(pos);
} }

@ -78,7 +78,7 @@ public class RotationTrack extends AbstractCinematicEvent {
if (playState != playState.Paused) { if (playState != playState.Paused) {
startRotation.set(spatial.getWorldRotation()); startRotation.set(spatial.getWorldRotation());
} }
if (duration == 0 && spatial != null) { if (initialDuration == 0 && spatial != null) {
spatial.setLocalRotation(endRotation); spatial.setLocalRotation(endRotation);
stop(); stop();
} }
@ -87,7 +87,7 @@ public class RotationTrack extends AbstractCinematicEvent {
@Override @Override
public void onUpdate(float tpf) { public void onUpdate(float tpf) {
if (spatial != null) { if (spatial != null) {
value += Math.min(tpf * speed / duration, 1.0f); value = Math.min(time / initialDuration, 1.0f);
TempVars vars = TempVars.get(); TempVars vars = TempVars.get();
Quaternion q = vars.quat1; Quaternion q = vars.quat1;
q.set(startRotation).slerp(endRotation, value); q.set(startRotation).slerp(endRotation, value);

@ -78,7 +78,7 @@ public class ScaleTrack extends AbstractCinematicEvent {
if (playState != playState.Paused) { if (playState != playState.Paused) {
startScale = spatial.getWorldScale().clone(); startScale = spatial.getWorldScale().clone();
} }
if (duration == 0 && spatial != null) { if (initialDuration == 0 && spatial != null) {
spatial.setLocalScale(endScale); spatial.setLocalScale(endScale);
stop(); stop();
} }
@ -87,7 +87,7 @@ public class ScaleTrack extends AbstractCinematicEvent {
@Override @Override
public void onUpdate(float tpf) { public void onUpdate(float tpf) {
if (spatial != null) { if (spatial != null) {
value += Math.min(tpf * speed / duration, 1.0f); value = Math.min(time / initialDuration, 1.0f);
spatial.setLocalScale(FastMath.interpolateLinear(value, startScale, endScale)); spatial.setLocalScale(FastMath.interpolateLinear(value, startScale, endScale));
} }
} }

@ -107,7 +107,8 @@ public class SoundTrack extends AbstractCinematicEvent {
} }
@Override @Override
public void initEvent(Application app, Cinematic cinematic) { public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
audioNode = new AudioNode(app.getAssetManager(), path, stream); audioNode = new AudioNode(app.getAssetManager(), path, stream);
setLoopMode(loopMode); setLoopMode(loopMode);

@ -23,8 +23,7 @@ public class SubtitleTrack extends GuiTrack{
@Override @Override
public void onPlay() { public void onPlay() {
super.onPlay(); super.onPlay();
//REMY FIX THIS nifty.getScreen(screen).findElementByName("text").getRenderer(TextRenderer.class).setText(text);
//nifty.getScreen(screen).findElementByName("text").getRenderer(TextRenderer.class).changeText(text);
} }

@ -64,6 +64,8 @@ import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box; import com.jme3.scene.shape.Box;
import com.jme3.shadow.PssmShadowRenderer; import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.system.NanoTimer;
import com.jme3.system.lwjgl.LwjglTimer;
public class TestCinematic extends SimpleApplication { public class TestCinematic extends SimpleApplication {
@ -79,6 +81,8 @@ public class TestCinematic extends SimpleApplication {
public static void main(String[] args) { public static void main(String[] args) {
TestCinematic app = new TestCinematic(); TestCinematic app = new TestCinematic();
app.start(); app.start();
} }
@ -106,6 +110,7 @@ public class TestCinematic extends SimpleApplication {
@Override @Override
public void onPlay() { public void onPlay() {
fade.setDuration(1f/cinematic.getSpeed());
fade.setValue(0); fade.setValue(0);
fade.fadeIn(); fade.fadeIn();
} }
@ -148,6 +153,7 @@ public class TestCinematic extends SimpleApplication {
@Override @Override
public void onPlay() { public void onPlay() {
fade.setDuration(1f/cinematic.getSpeed());
fade.fadeOut(); fade.fadeOut();
} }
@ -164,10 +170,13 @@ public class TestCinematic extends SimpleApplication {
} }
}); });
final NanoTimer myTimer = new NanoTimer();
cinematic.addListener(new CinematicEventListener() { cinematic.addListener(new CinematicEventListener() {
public void onPlay(CinematicEvent cinematic) { public void onPlay(CinematicEvent cinematic) {
chaseCam.setEnabled(false); chaseCam.setEnabled(false);
myTimer.reset();
System.out.println("play"); System.out.println("play");
} }
@ -180,9 +189,13 @@ public class TestCinematic extends SimpleApplication {
chaseCam.setEnabled(true); chaseCam.setEnabled(true);
fade.setValue(1); fade.setValue(1);
System.out.println("stop"); System.out.println("stop");
System.out.println((float)myTimer.getTime()/(float)myTimer.getResolution());
} }
}); });
cinematic.setSpeed(2);
flyCam.setEnabled(false); flyCam.setEnabled(false);
chaseCam = new ChaseCamera(cam, model, inputManager); chaseCam = new ChaseCamera(cam, model, inputManager);
initInputs(); initInputs();
@ -270,4 +283,9 @@ public class TestCinematic extends SimpleApplication {
}; };
inputManager.addListener(acl, "togglePause"); inputManager.addListener(acl, "togglePause");
} }
} }

Loading…
Cancel
Save