aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/cinematic
diff options
context:
space:
mode:
authorScott Barta <sbarta@google.com>2012-03-01 12:35:35 -0800
committerScott Barta <sbarta@google.com>2012-03-01 12:40:08 -0800
commit59b2e6871c65f58fdad78cd7229c292f6a177578 (patch)
tree2d4e7bfc05b93f40b34675d77e403dd1c25efafd /engine/src/core/com/jme3/cinematic
parentf9b30489e75ac1eabc365064959804e99534f7ab (diff)
downloadjmonkeyengine-59b2e6871c65f58fdad78cd7229c292f6a177578.tar.gz
Adds the jMonkeyEngine library to the build.
Adds the jMonkeyEngine open source 3D game engine to the build. This is built as a static library and is only used by the Finsky client. Change-Id: I06a3f054df7b8a67757267d884854f70c5a16ca0
Diffstat (limited to 'engine/src/core/com/jme3/cinematic')
-rw-r--r--engine/src/core/com/jme3/cinematic/Cinematic.java381
-rw-r--r--engine/src/core/com/jme3/cinematic/KeyFrame.java85
-rw-r--r--engine/src/core/com/jme3/cinematic/MotionPath.java371
-rw-r--r--engine/src/core/com/jme3/cinematic/MotionPathListener.java50
-rw-r--r--engine/src/core/com/jme3/cinematic/PlayState.java48
-rw-r--r--engine/src/core/com/jme3/cinematic/TimeLine.java120
-rw-r--r--engine/src/core/com/jme3/cinematic/events/AbstractCinematicEvent.java320
-rw-r--r--engine/src/core/com/jme3/cinematic/events/AnimationTrack.java175
-rw-r--r--engine/src/core/com/jme3/cinematic/events/CinematicEvent.java143
-rw-r--r--engine/src/core/com/jme3/cinematic/events/CinematicEventListener.java17
-rw-r--r--engine/src/core/com/jme3/cinematic/events/MotionTrack.java440
-rw-r--r--engine/src/core/com/jme3/cinematic/events/PositionTrack.java122
-rw-r--r--engine/src/core/com/jme3/cinematic/events/RotationTrack.java126
-rw-r--r--engine/src/core/com/jme3/cinematic/events/ScaleTrack.java121
-rw-r--r--engine/src/core/com/jme3/cinematic/events/SoundTrack.java183
15 files changed, 2702 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/cinematic/Cinematic.java b/engine/src/core/com/jme3/cinematic/Cinematic.java
new file mode 100644
index 0000000..3477c22
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/Cinematic.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.app.state.AppState;
+import com.jme3.app.state.AppStateManager;
+import com.jme3.asset.TextureKey;
+import com.jme3.cinematic.events.AbstractCinematicEvent;
+import com.jme3.cinematic.events.CinematicEvent;
+import com.jme3.cinematic.events.CinematicEventListener;
+import com.jme3.export.*;
+import com.jme3.renderer.Camera;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.CameraNode;
+import com.jme3.scene.Node;
+import com.jme3.scene.control.CameraControl;
+import com.jme3.scene.control.CameraControl.ControlDirection;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Nehon
+ */
+public class Cinematic extends AbstractCinematicEvent implements AppState {
+
+ private static final Logger logger = Logger.getLogger(Application.class.getName());
+ private Node scene;
+ protected TimeLine timeLine = new TimeLine();
+ private int lastFetchedKeyFrame = -1;
+ private List<CinematicEvent> cinematicEvents = new ArrayList<CinematicEvent>();
+ private Map<String, CameraNode> cameras = new HashMap<String, CameraNode>();
+ private CameraNode currentCam;
+ private boolean initialized = false;
+ private Map<String, Map<String, Object>> eventsData;
+
+ public Cinematic() {
+ }
+
+ public Cinematic(Node scene) {
+ this.scene = scene;
+ }
+
+ public Cinematic(Node scene, float initialDuration) {
+ super(initialDuration);
+ this.scene = scene;
+ }
+
+ public Cinematic(Node scene, LoopMode loopMode) {
+ super(loopMode);
+ this.scene = scene;
+ }
+
+ public Cinematic(Node scene, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ this.scene = scene;
+ }
+
+ @Override
+ public void onPlay() {
+ if (isInitialized()) {
+ if (playState == PlayState.Paused) {
+ for (int i = 0; i < cinematicEvents.size(); i++) {
+ CinematicEvent ce = cinematicEvents.get(i);
+ if (ce.getPlayState() == PlayState.Paused) {
+ ce.play();
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStop() {
+ time = 0;
+ lastFetchedKeyFrame = -1;
+ for (int i = 0; i < cinematicEvents.size(); i++) {
+ CinematicEvent ce = cinematicEvents.get(i);
+ ce.stop();
+ }
+ enableCurrentCam(false);
+ }
+
+ @Override
+ public void onPause() {
+ for (int i = 0; i < cinematicEvents.size(); i++) {
+ CinematicEvent ce = cinematicEvents.get(i);
+ if (ce.getPlayState() == PlayState.Playing) {
+ ce.pause();
+ }
+ }
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+
+ oc.writeSavableArrayList((ArrayList) cinematicEvents, "cinematicEvents", null);
+ oc.writeStringSavableMap(cameras, "cameras", null);
+ oc.write(timeLine, "timeLine", null);
+
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+
+ cinematicEvents = ic.readSavableArrayList("cinematicEvents", null);
+ cameras = (Map<String, CameraNode>) ic.readStringSavableMap("cameras", null);
+ timeLine = (TimeLine) ic.readSavable("timeLine", null);
+ }
+
+ @Override
+ public void setSpeed(float speed) {
+ super.setSpeed(speed);
+ for (int i = 0; i < cinematicEvents.size(); i++) {
+ CinematicEvent ce = cinematicEvents.get(i);
+ ce.setSpeed(speed);
+ }
+
+
+ }
+
+ public void initialize(AppStateManager stateManager, Application app) {
+ initEvent(app, this);
+ for (CinematicEvent cinematicEvent : cinematicEvents) {
+ cinematicEvent.initEvent(app, this);
+ }
+
+ initialized = true;
+ }
+
+ public boolean isInitialized() {
+ return initialized;
+ }
+
+ public void setEnabled(boolean enabled) {
+ if (enabled) {
+ play();
+ }
+ }
+
+ public boolean isEnabled() {
+ return playState == PlayState.Playing;
+ }
+
+ public void stateAttached(AppStateManager stateManager) {
+ }
+
+ public void stateDetached(AppStateManager stateManager) {
+ stop();
+ }
+
+ public void update(float tpf) {
+ if (isInitialized()) {
+ internalUpdate(tpf);
+ }
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ for (int i = 0; i < cinematicEvents.size(); i++) {
+ CinematicEvent ce = cinematicEvents.get(i);
+ ce.internalUpdate(tpf);
+ }
+
+ int keyFrameIndex = timeLine.getKeyFrameIndexFromTime(time);
+
+ //iterate to make sure every key frame is triggered
+ for (int i = lastFetchedKeyFrame + 1; i <= keyFrameIndex; i++) {
+ KeyFrame keyFrame = timeLine.get(i);
+ if (keyFrame != null) {
+ keyFrame.trigger();
+ }
+ }
+
+ lastFetchedKeyFrame = keyFrameIndex;
+ }
+
+ @Override
+ public void setTime(float time) {
+ super.setTime(time);
+ int keyFrameIndex = timeLine.getKeyFrameIndexFromTime(time);
+
+ //triggering all the event from start to "time"
+ //then computing timeOffset for each event
+ for (int i = 0; i <= keyFrameIndex; i++) {
+ KeyFrame keyFrame = timeLine.get(i);
+ if (keyFrame != null) {
+ for (CinematicEvent ce : keyFrame.getCinematicEvents()) {
+ ce.play();
+ ce.setTime(time - timeLine.getKeyFrameTime(keyFrame));
+ }
+ }
+ }
+ if (playState != PlayState.Playing) {
+ pause();
+ }
+
+ // step();
+ }
+
+ public KeyFrame addCinematicEvent(float timeStamp, CinematicEvent cinematicEvent) {
+ KeyFrame keyFrame = timeLine.getKeyFrameAtTime(timeStamp);
+ if (keyFrame == null) {
+ keyFrame = new KeyFrame();
+ timeLine.addKeyFrameAtTime(timeStamp, keyFrame);
+ }
+ keyFrame.cinematicEvents.add(cinematicEvent);
+ cinematicEvents.add(cinematicEvent);
+ return keyFrame;
+ }
+
+ public void render(RenderManager rm) {
+ }
+
+ public void postRender() {
+ }
+
+ public void cleanup() {
+ }
+
+ /**
+ * fits the duration of the cinamatic to the duration of all its child cinematic events
+ */
+ public void fitDuration() {
+ KeyFrame kf = timeLine.getKeyFrameAtTime(timeLine.getLastKeyFrameIndex());
+ float d = 0;
+ for (int i = 0; i < kf.getCinematicEvents().size(); i++) {
+ CinematicEvent ce = kf.getCinematicEvents().get(i);
+ if (d < (ce.getDuration() * ce.getSpeed())) {
+ d = (ce.getDuration() * ce.getSpeed());
+ }
+ }
+
+ initialDuration = d;
+ }
+
+ public CameraNode bindCamera(String cameraName, Camera cam) {
+ CameraNode node = new CameraNode(cameraName, cam);
+ node.setControlDir(ControlDirection.SpatialToCamera);
+ node.getControl(CameraControl.class).setEnabled(false);
+ cameras.put(cameraName, node);
+ scene.attachChild(node);
+ return node;
+ }
+
+ public CameraNode getCamera(String cameraName) {
+ return cameras.get(cameraName);
+ }
+
+ private void enableCurrentCam(boolean enabled) {
+ if (currentCam != null) {
+ currentCam.getControl(CameraControl.class).setEnabled(enabled);
+ }
+ }
+
+ public void setActiveCamera(String cameraName) {
+ enableCurrentCam(false);
+ currentCam = cameras.get(cameraName);
+ if (currentCam == null) {
+ logger.log(Level.WARNING, "{0} is not a camera bond to the cinematic, cannot activate", cameraName);
+ }
+ enableCurrentCam(true);
+ }
+
+ public void activateCamera(final float timeStamp, final String cameraName) {
+ addCinematicEvent(timeStamp, new AbstractCinematicEvent() {
+
+ @Override
+ public void play() {
+ super.play();
+ stop();
+ }
+
+ @Override
+ public void onPlay() {
+ setActiveCamera(cameraName);
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ }
+
+ @Override
+ public void onStop() {
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ @Override
+ public void setTime(float time) {
+ play();
+ }
+ });
+ }
+
+ public void setScene(Node scene) {
+ this.scene = scene;
+ }
+
+ private Map<String, Map<String, Object>> getEventsData() {
+ if (eventsData == null) {
+ eventsData = new HashMap<String, Map<String, Object>>();
+ }
+ return eventsData;
+ }
+
+ public void putEventData(String type, String name, Object object) {
+ Map<String, Map<String, Object>> data = getEventsData();
+ Map<String, Object> row = data.get(type);
+ if (row == null) {
+ row = new HashMap<String, Object>();
+ }
+ row.put(name, object);
+ }
+
+ public Object getEventData(String type, String name) {
+ if (eventsData != null) {
+ Map<String, Object> row = eventsData.get(type);
+ if (row != null) {
+ return row.get(name);
+ }
+ }
+ return null;
+ }
+
+ public Savable removeEventData(String type, String name) {
+ if (eventsData != null) {
+ Map<String, Object> row = eventsData.get(type);
+ if (row != null) {
+ row.remove(name);
+ }
+ }
+ return null;
+ }
+
+ public Node getScene() {
+ return scene;
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/KeyFrame.java b/engine/src/core/com/jme3/cinematic/KeyFrame.java
new file mode 100644
index 0000000..2a4b200
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/KeyFrame.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic;
+
+import com.jme3.cinematic.events.CinematicEvent;
+import com.jme3.export.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Nehon
+ */
+public class KeyFrame implements Savable {
+
+ List<CinematicEvent> cinematicEvents = new ArrayList<CinematicEvent>();
+ private int index;
+
+ public List<CinematicEvent> getCinematicEvents() {
+ return cinematicEvents;
+ }
+
+ public void setCinematicEvents(List<CinematicEvent> cinematicEvents) {
+ this.cinematicEvents = cinematicEvents;
+ }
+
+ public List<CinematicEvent> trigger() {
+ for (CinematicEvent event : cinematicEvents) {
+ event.play();
+ }
+ return cinematicEvents;
+ }
+
+ public void write(JmeExporter ex) throws IOException {
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.writeSavableArrayList((ArrayList) cinematicEvents, "cinematicEvents", null);
+ oc.write(index, "index", 0);
+ }
+
+ public void read(JmeImporter im) throws IOException {
+ InputCapsule ic = im.getCapsule(this);
+ cinematicEvents = ic.readSavableArrayList("cinematicEvents", null);
+ index=ic.readInt("index", 0);
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+
+}
diff --git a/engine/src/core/com/jme3/cinematic/MotionPath.java b/engine/src/core/com/jme3/cinematic/MotionPath.java
new file mode 100644
index 0000000..cdb31d0
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/MotionPath.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic;
+
+import com.jme3.asset.AssetManager;
+import com.jme3.cinematic.events.MotionTrack;
+import com.jme3.export.*;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Spline;
+import com.jme3.math.Spline.SplineType;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.Node;
+import com.jme3.scene.shape.Box;
+import com.jme3.scene.shape.Curve;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Motion path is used to create a path between way points.
+ * @author Nehon
+ */
+public class MotionPath implements Savable {
+
+ private Node debugNode;
+ private AssetManager assetManager;
+ private List<MotionPathListener> listeners;
+ private Spline spline = new Spline();
+ private float eps = 0.0001f;
+
+ /**
+ * Create a motion Path
+ */
+ public MotionPath() {
+ }
+
+ /**
+ * interpolate the path giving the time since the beginnin and the motionControl
+ * this methods sets the new localTranslation to the spatial of the motionTrack control.
+ * @param time the time since the animation started
+ * @param control the ocntrol over the moving spatial
+ */
+ public float interpolatePath(float time, MotionTrack control) {
+
+ float traveledDistance = 0;
+ TempVars vars = TempVars.get();
+ Vector3f temp = vars.vect1;
+ Vector3f tmpVector = vars.vect2;
+ //computing traveled distance according to new time
+ traveledDistance = time * (getLength() / control.getInitialDuration());
+
+ //getting waypoint index and current value from new traveled distance
+ Vector2f v = getWayPointIndexForDistance(traveledDistance);
+
+ //setting values
+ control.setCurrentWayPoint((int) v.x);
+ control.setCurrentValue(v.y);
+
+ //interpolating new position
+ getSpline().interpolate(control.getCurrentValue(), control.getCurrentWayPoint(), temp);
+ if (control.needsDirection()) {
+ tmpVector.set(temp);
+ control.setDirection(tmpVector.subtractLocal(control.getSpatial().getLocalTranslation()).normalizeLocal());
+ }
+
+ control.getSpatial().setLocalTranslation(temp);
+ vars.release();
+ return traveledDistance;
+ }
+
+ private void attachDebugNode(Node root) {
+ if (debugNode == null) {
+ debugNode = new Node();
+ Material m = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
+ for (Iterator<Vector3f> it = spline.getControlPoints().iterator(); it.hasNext();) {
+ Vector3f cp = it.next();
+ Geometry geo = new Geometry("box", new Box(cp, 0.3f, 0.3f, 0.3f));
+ geo.setMaterial(m);
+ debugNode.attachChild(geo);
+
+ }
+ switch (spline.getType()) {
+ case CatmullRom:
+ debugNode.attachChild(CreateCatmullRomPath());
+ break;
+ case Linear:
+ debugNode.attachChild(CreateLinearPath());
+ break;
+ default:
+ debugNode.attachChild(CreateLinearPath());
+ break;
+ }
+
+ root.attachChild(debugNode);
+ }
+ }
+
+ private Geometry CreateLinearPath() {
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.setColor("Color", ColorRGBA.Blue);
+ Geometry lineGeometry = new Geometry("line", new Curve(spline, 0));
+ lineGeometry.setMaterial(mat);
+ return lineGeometry;
+ }
+
+ private Geometry CreateCatmullRomPath() {
+
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.getAdditionalRenderState().setWireframe(true);
+ mat.setColor("Color", ColorRGBA.Blue);
+ Geometry lineGeometry = new Geometry("line", new Curve(spline, 10));
+ lineGeometry.setMaterial(mat);
+ return lineGeometry;
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(spline, "spline", null);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ InputCapsule in = im.getCapsule(this);
+ spline = (Spline) in.readSavable("spline", null);
+
+ }
+
+ /**
+ * compute the index of the waypoint and the interpolation value according to a distance
+ * returns a vector 2 containing the index in the x field and the interpolation value in the y field
+ * @param distance the distance traveled on this path
+ * @return the waypoint index and the interpolation value in a vector2
+ */
+ public Vector2f getWayPointIndexForDistance(float distance) {
+ float sum = 0;
+ distance = distance % spline.getTotalLength();
+ int i = 0;
+ for (Float len : spline.getSegmentsLength()) {
+ if (sum + len >= distance) {
+ return new Vector2f((float) i, (distance - sum) / len);
+ }
+ sum += len;
+ i++;
+ }
+ return new Vector2f((float) spline.getControlPoints().size() - 1, 1.0f);
+ }
+
+ /**
+ * Addsa waypoint to the path
+ * @param wayPoint a position in world space
+ */
+ public void addWayPoint(Vector3f wayPoint) {
+ spline.addControlPoint(wayPoint);
+ }
+
+ /**
+ * retruns the length of the path in world units
+ * @return the length
+ */
+ public float getLength() {
+ return spline.getTotalLength();
+ }
+
+ /**
+ * returns the waypoint at the given index
+ * @param i the index
+ * @return returns the waypoint position
+ */
+ public Vector3f getWayPoint(int i) {
+ return spline.getControlPoints().get(i);
+ }
+
+ /**
+ * remove the waypoint from the path
+ * @param wayPoint the waypoint to remove
+ */
+ public void removeWayPoint(Vector3f wayPoint) {
+ spline.removeControlPoint(wayPoint);
+ }
+
+ /**
+ * remove the waypoint at the given index from the path
+ * @param i the index of the waypoint to remove
+ */
+ public void removeWayPoint(int i) {
+ removeWayPoint(spline.getControlPoints().get(i));
+ }
+
+ /**
+ * returns an iterator on the waypoints collection
+ * @return
+ */
+ public Iterator<Vector3f> iterator() {
+ return spline.getControlPoints().iterator();
+ }
+
+ /**
+ * return the type of spline used for the path interpolation for this path
+ * @return the path interpolation spline type
+ */
+ public SplineType getPathSplineType() {
+ return spline.getType();
+ }
+
+ /**
+ * sets the type of spline used for the path interpolation for this path
+ * @param pathSplineType
+ */
+ public void setPathSplineType(SplineType pathSplineType) {
+ spline.setType(pathSplineType);
+ if (debugNode != null) {
+ Node parent = debugNode.getParent();
+ debugNode.removeFromParent();
+ debugNode.detachAllChildren();
+ debugNode = null;
+ attachDebugNode(parent);
+ }
+ }
+
+ /**
+ * disable the display of the path and the waypoints
+ */
+ public void disableDebugShape() {
+
+ debugNode.detachAllChildren();
+ debugNode = null;
+ assetManager = null;
+ }
+
+ /**
+ * enable the display of the path and the waypoints
+ * @param manager the assetManager
+ * @param rootNode the node where the debug shapes must be attached
+ */
+ public void enableDebugShape(AssetManager manager, Node rootNode) {
+ assetManager = manager;
+ // computeTotalLentgh();
+ attachDebugNode(rootNode);
+ }
+
+ /**
+ * Adds a motion pathListener to the path
+ * @param listener the MotionPathListener to attach
+ */
+ public void addListener(MotionPathListener listener) {
+ if (listeners == null) {
+ listeners = new ArrayList<MotionPathListener>();
+ }
+ listeners.add(listener);
+ }
+
+ /**
+ * remove the given listener
+ * @param listener the listener to remove
+ */
+ public void removeListener(MotionPathListener listener) {
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * return the number of waypoints of this path
+ * @return
+ */
+ public int getNbWayPoints() {
+ return spline.getControlPoints().size();
+ }
+
+ public void triggerWayPointReach(int wayPointIndex, MotionTrack control) {
+ if (listeners != null) {
+ for (Iterator<MotionPathListener> it = listeners.iterator(); it.hasNext();) {
+ MotionPathListener listener = it.next();
+ listener.onWayPointReach(control, wayPointIndex);
+ }
+ }
+ }
+
+ /**
+ * Returns the curve tension
+ * @return
+ */
+ public float getCurveTension() {
+ return spline.getCurveTension();
+ }
+
+ /**
+ * sets the tension of the curve (only for catmull rom) 0.0 will give a linear curve, 1.0 a round curve
+ * @param curveTension
+ */
+ public void setCurveTension(float curveTension) {
+ spline.setCurveTension(curveTension);
+ if (debugNode != null) {
+ Node parent = debugNode.getParent();
+ debugNode.removeFromParent();
+ debugNode.detachAllChildren();
+ debugNode = null;
+ attachDebugNode(parent);
+ }
+ }
+
+ public void clearWayPoints() {
+ spline.clearControlPoints();
+ }
+
+ /**
+ * Sets the path to be a cycle
+ * @param cycle
+ */
+ public void setCycle(boolean cycle) {
+
+ spline.setCycle(cycle);
+ if (debugNode != null) {
+ Node parent = debugNode.getParent();
+ debugNode.removeFromParent();
+ debugNode.detachAllChildren();
+ debugNode = null;
+ attachDebugNode(parent);
+ }
+
+ }
+
+ /**
+ * returns true if the path is a cycle
+ * @return
+ */
+ public boolean isCycle() {
+ return spline.isCycle();
+ }
+
+ public Spline getSpline() {
+ return spline;
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/MotionPathListener.java b/engine/src/core/com/jme3/cinematic/MotionPathListener.java
new file mode 100644
index 0000000..99a3dcb
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/MotionPathListener.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic;
+
+import com.jme3.cinematic.events.MotionTrack;
+
+/**
+ * Trigger the events appening on an motion path
+ * @author Nehon
+ */
+public interface MotionPathListener {
+
+ /**
+ * Triggers every time the target reach a waypoint on the path
+ * @param motionControl the MotionTrack objects that reached the waypoint
+ * @param wayPointIndex the index of the way point reached
+ */
+ public void onWayPointReach(MotionTrack motionControl,int wayPointIndex);
+
+}
diff --git a/engine/src/core/com/jme3/cinematic/PlayState.java b/engine/src/core/com/jme3/cinematic/PlayState.java
new file mode 100644
index 0000000..648dc3d
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/PlayState.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic;
+
+/**
+ * The play state of a cinematic event
+ * @author Nehon
+ */
+public enum PlayState {
+
+ /**The CinematicEvent is currently beeing played*/
+ Playing,
+ /**The animatable has been paused*/
+ Paused,
+ /**the animatable is stoped*/
+ Stopped
+}
+
diff --git a/engine/src/core/com/jme3/cinematic/TimeLine.java b/engine/src/core/com/jme3/cinematic/TimeLine.java
new file mode 100644
index 0000000..ae3e06d
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/TimeLine.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic;
+
+import com.jme3.export.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ *
+ * @author Nehon
+ */
+public class TimeLine extends HashMap<Integer, KeyFrame> implements Savable {
+
+ protected int keyFramesPerSeconds = 30;
+ protected int lastKeyFrameIndex = 0;
+
+ public TimeLine() {
+ super();
+ }
+
+ public KeyFrame getKeyFrameAtTime(float time) {
+ return get(getKeyFrameIndexFromTime(time));
+ }
+
+ public KeyFrame getKeyFrameAtIndex(int keyFrameIndex) {
+ return get(keyFrameIndex);
+ }
+
+ public void addKeyFrameAtTime(float time, KeyFrame keyFrame) {
+ addKeyFrameAtIndex(getKeyFrameIndexFromTime(time), keyFrame);
+ }
+
+ public void addKeyFrameAtIndex(int keyFrameIndex, KeyFrame keyFrame) {
+ put(keyFrameIndex, keyFrame);
+ keyFrame.setIndex(keyFrameIndex);
+ if (lastKeyFrameIndex < keyFrameIndex) {
+ lastKeyFrameIndex = keyFrameIndex;
+ }
+ }
+
+ public void removeKeyFrame(int keyFrameIndex) {
+ remove(keyFrameIndex);
+ if (lastKeyFrameIndex == keyFrameIndex) {
+ KeyFrame kf = null;
+ for (int i = keyFrameIndex; kf == null && i >= 0; i--) {
+ kf = getKeyFrameAtIndex(i);
+ lastKeyFrameIndex = i;
+ }
+ }
+ }
+
+ public void removeKeyFrame(float time) {
+ removeKeyFrame(getKeyFrameIndexFromTime(time));
+ }
+
+ public int getKeyFrameIndexFromTime(float time) {
+ return Math.round(time * keyFramesPerSeconds);
+ }
+
+ public float getKeyFrameTime(KeyFrame keyFrame) {
+ return (float)keyFrame.getIndex()/(float)keyFramesPerSeconds;
+ }
+
+ public Collection<KeyFrame> getAllKeyFrames() {
+ return values();
+ }
+
+ public int getLastKeyFrameIndex() {
+ return lastKeyFrameIndex;
+ }
+
+ public void write(JmeExporter ex) throws IOException {
+ OutputCapsule oc = ex.getCapsule(this);
+ ArrayList list = new ArrayList();
+ list.addAll(values());
+ oc.writeSavableArrayList(list, "keyFrames", null);
+ }
+
+ public void read(JmeImporter im) throws IOException {
+ InputCapsule ic = im.getCapsule(this);
+ ArrayList list = ic.readSavableArrayList("keyFrames", null);
+ for (Iterator it = list.iterator(); it.hasNext();) {
+ KeyFrame keyFrame = (KeyFrame) it.next();
+ addKeyFrameAtIndex(keyFrame.getIndex(), keyFrame);
+ }
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/AbstractCinematicEvent.java b/engine/src/core/com/jme3/cinematic/events/AbstractCinematicEvent.java
new file mode 100644
index 0000000..ea2d132
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/AbstractCinematicEvent.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+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 java.io.IOException;
+import java.util.ArrayList;
+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
+ */
+public abstract class AbstractCinematicEvent implements CinematicEvent {
+
+ protected PlayState playState = PlayState.Stopped;
+ protected float speed = 1;
+ protected float initialDuration = 10;
+ protected LoopMode loopMode = LoopMode.DontLoop;
+ protected float time = 0;
+ protected boolean resuming = false;
+
+ /**
+ * the list of listeners
+ */
+ protected List<CinematicEventListener> listeners;
+
+ /**
+ * contruct a cinematic event
+ */
+ public AbstractCinematicEvent() {
+ }
+
+ /**
+ * contruct a cinematic event wwith the given initial duration
+ * @param initialDuration
+ */
+ public AbstractCinematicEvent(float initialDuration) {
+ this.initialDuration = initialDuration;
+ }
+
+ /**
+ * contruct a cinematic event with the given loopMode
+ * @param loopMode
+ */
+ public AbstractCinematicEvent(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) {
+ this.initialDuration = initialDuration;
+ this.loopMode = loopMode;
+ }
+
+ /**
+ * Play this event
+ */
+ public void play() {
+ onPlay();
+ playState = PlayState.Playing;
+ if (listeners != null) {
+ for (int i = 0; i < listeners.size(); i++) {
+ CinematicEventListener cel = listeners.get(i);
+ cel.onPlay(this);
+ }
+ }
+ }
+
+ /**
+ * 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) {
+ if (playState == PlayState.Playing) {
+ time = time + (tpf * speed);
+ //time = elapsedTimePause + (timer.getTimeInSeconds() - start) * speed;
+
+ onUpdate(tpf);
+ if (time >= initialDuration && loopMode == loopMode.DontLoop) {
+ stop();
+ }
+ }
+
+ }
+
+ /**
+ * 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.
+ */
+ public void stop() {
+ onStop();
+ time = 0;
+ playState = PlayState.Stopped;
+ if (listeners != null) {
+ for (int i = 0; i < listeners.size(); i++) {
+ CinematicEventListener cel = listeners.get(i);
+ cel.onStop(this);
+ }
+ }
+ }
+
+ /**
+ * Place here the code you want to execute when the event is stoped.
+ */
+ protected abstract void onStop();
+
+ /**
+ * pause this event
+ */
+ public void pause() {
+ onPause();
+ playState = PlayState.Paused;
+ if (listeners != null) {
+ for (int i = 0; i < listeners.size(); i++) {
+ CinematicEventListener cel = listeners.get(i);
+ cel.onPause(this);
+ }
+ }
+ }
+
+ /**
+ * place here the code you want to execute when the event is paused
+ */
+ public abstract void onPause();
+
+ /**
+ * returns the actual duration of the animtion (initialDuration/speed)
+ * @return
+ */
+ public float getDuration() {
+ return initialDuration / speed;
+ }
+
+ /**
+ * Sets the speed of the animation.
+ * At speed = 1, the animation will last initialDuration seconds,
+ * At speed = 2 the animation will last initialDuraiton/2...
+ * @param speed
+ */
+ public void setSpeed(float speed) {
+ this.speed = speed;
+ }
+
+ /**
+ * returns the speed of the animation.
+ * @return
+ */
+ public float getSpeed() {
+ return speed;
+ }
+
+ /**
+ * Returns the current playstate of the animation
+ * @return
+ */
+ public PlayState getPlayState() {
+ return playState;
+ }
+
+ /**
+ * returns the initial duration of the animation at speed = 1 in seconds.
+ * @return
+ */
+ public float getInitialDuration() {
+ return initialDuration;
+ }
+
+ /**
+ * Sets the duration of the antionamtion at speed = 1 in seconds
+ * @param initialDuration
+ */
+ public void setInitialDuration(float initialDuration) {
+ this.initialDuration = initialDuration;
+ }
+
+ /**
+ * retursthe loopMode of the animation
+ * @see LoopMode
+ * @return
+ */
+ public LoopMode getLoopMode() {
+ return loopMode;
+ }
+
+ /**
+ * Sets the loopMode of the animation
+ * @see LoopMode
+ * @param loopMode
+ */
+ public void setLoopMode(LoopMode loopMode) {
+ this.loopMode = loopMode;
+ }
+
+ /**
+ * for serialization only
+ * @param ex exporter
+ * @throws IOException
+ */
+ public void write(JmeExporter ex) throws IOException {
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(playState, "playState", PlayState.Stopped);
+ oc.write(speed, "speed", 1);
+ oc.write(initialDuration, "initalDuration", 10);
+ oc.write(loopMode, "loopMode", LoopMode.DontLoop);
+ }
+
+ /**
+ * for serialization only
+ * @param im importer
+ * @throws IOException
+ */
+ public void read(JmeImporter im) throws IOException {
+ InputCapsule ic = im.getCapsule(this);
+ playState = ic.readEnum("playState", PlayState.class, PlayState.Stopped);
+ speed = ic.readFloat("speed", 1);
+ initialDuration = ic.readFloat("initalDuration", 10);
+ 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) {
+ }
+
+ /**
+ * return a list of CinematicEventListener added on this event
+ * @return
+ */
+ private List<CinematicEventListener> getListeners() {
+ if (listeners == null) {
+ listeners = new ArrayList<CinematicEventListener>();
+ }
+ return listeners;
+ }
+
+ /**
+ * Add a CinematicEventListener to this event
+ * @param listener CinematicEventListener
+ */
+ public void addListener(CinematicEventListener listener) {
+ getListeners().add(listener);
+ }
+
+ /**
+ * remove a CinematicEventListener from this event
+ * @param listener CinematicEventListener
+ */
+ public void removeListener(CinematicEventListener listener) {
+ getListeners().remove(listener);
+ }
+
+ /**
+ * When this method is invoked, the event should fast forward to the given time according tim 0 is the start of the event.
+ * @param time the time to fast forward to
+ */
+ public void setTime(float time) {
+ this.time = time / speed;
+ }
+
+ public float getTime() {
+ return time;
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/AnimationTrack.java b/engine/src/core/com/jme3/cinematic/events/AnimationTrack.java
new file mode 100644
index 0000000..e857706
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/AnimationTrack.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic.events;
+
+import com.jme3.animation.AnimChannel;
+import com.jme3.animation.AnimControl;
+import com.jme3.animation.LoopMode;
+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.scene.Spatial;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Nehon
+ */
+public class AnimationTrack extends AbstractCinematicEvent {
+
+ private static final Logger log = Logger.getLogger(AnimationTrack.class.getName());
+ protected AnimChannel channel;
+ protected String animationName;
+ protected String modelName;
+
+ public AnimationTrack() {
+ }
+
+ public AnimationTrack(Spatial model, String animationName) {
+ modelName = model.getName();
+ this.animationName = animationName;
+ initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
+ }
+
+ public AnimationTrack(Spatial model, String animationName, float initialDuration) {
+ super(initialDuration);
+ modelName = model.getName();
+ this.animationName = animationName;
+ }
+
+ public AnimationTrack(Spatial model, String animationName, LoopMode loopMode) {
+ super(loopMode);
+ initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
+ modelName = model.getName();
+ this.animationName = animationName;
+ }
+
+ public AnimationTrack(Spatial model, String animationName, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ modelName = model.getName();
+ this.animationName = animationName;
+ }
+
+ @Override
+ public void initEvent(Application app, Cinematic cinematic) {
+ super.initEvent(app, cinematic);
+ if (channel == null) {
+ Object s = cinematic.getEventData("modelChannels", modelName);
+ if (s != null && s instanceof AnimChannel) {
+ this.channel = (AnimChannel) s;
+ } else if (s == null) {
+ Spatial model = cinematic.getScene().getChild(modelName);
+ if (model != null) {
+ channel = model.getControl(AnimControl.class).createChannel();
+ cinematic.putEventData("modelChannels", modelName, channel);
+ } else {
+ log.log(Level.WARNING, "spatial {0} not found in the scene, cannot perform animation", modelName);
+ }
+ }
+
+ }
+ }
+
+ @Override
+ public void setTime(float time) {
+ super.setTime(time);
+ float t = time;
+ if(loopMode == loopMode.Loop){
+ t = t % channel.getAnimMaxTime();
+ }
+ if(loopMode == loopMode.Cycle){
+ float parity = (float)Math.ceil(time / channel.getAnimMaxTime());
+ if(parity >0 && parity%2 ==0){
+ t = channel.getAnimMaxTime() - t % channel.getAnimMaxTime();
+ }else{
+ t = t % channel.getAnimMaxTime();
+ }
+
+ }
+ channel.setTime(t);
+ channel.getControl().update(0);
+ }
+
+ @Override
+ public void onPlay() {
+ channel.getControl().setEnabled(true);
+ if (playState == PlayState.Stopped) {
+ channel.setAnim(animationName);
+ channel.setSpeed(speed);
+ channel.setLoopMode(loopMode);
+ channel.setTime(time);
+ }
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ }
+
+ @Override
+ public void onStop() {
+ channel.getControl().setEnabled(false);
+ channel.setTime(0);
+ }
+
+ @Override
+ public void onPause() {
+ channel.getControl().setEnabled(false);
+ }
+
+ @Override
+ public void setLoopMode(LoopMode loopMode) {
+ super.setLoopMode(loopMode);
+ channel.setLoopMode(loopMode);
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(modelName, "modelName", "");
+ oc.write(animationName, "animationName", "");
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ modelName = ic.readString("modelName", "");
+ animationName = ic.readString("animationName", "");
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/CinematicEvent.java b/engine/src/core/com/jme3/cinematic/events/CinematicEvent.java
new file mode 100644
index 0000000..37e70f9
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/CinematicEvent.java
@@ -0,0 +1,143 @@
+/*
+ * 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 com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.cinematic.PlayState;
+import com.jme3.export.Savable;
+
+/**
+ *
+ * @author Nehon
+ */
+public interface CinematicEvent extends Savable {
+
+ /**
+ * Starts the animation
+ */
+ public void play();
+
+ /**
+ * Stops the animation
+ */
+ public void stop();
+
+ /**
+ * Pauses the animation
+ */
+ public void pause();
+
+ /**
+ * Returns the actual duration of the animation
+ * @return the duration
+ */
+ public float getDuration();
+
+ /**
+ * Sets the speed of the animation (1 is normal speed, 2 is twice faster)
+ * @param speed
+ */
+ public void setSpeed(float speed);
+
+ /**
+ * returns the speed of the animation
+ * @return the speed
+ */
+ public float getSpeed();
+
+ /**
+ * returns the PlayState of the animation
+ * @return the plat state
+ */
+ public PlayState getPlayState();
+
+ /**
+ * @param loop Set the loop mode for the channel. The loop mode
+ * determines what will happen to the animation once it finishes
+ * playing.
+ *
+ * For more information, see the LoopMode enum class.
+ * @see LoopMode
+ */
+ public void setLoopMode(LoopMode loop);
+
+ /**
+ * @return The loop mode currently set for the animation. The loop mode
+ * determines what will happen to the animation once it finishes
+ * playing.
+ *
+ * For more information, see the LoopMode enum class.
+ * @see LoopMode
+ */
+ public LoopMode getLoopMode();
+
+ /**
+ * returns the initial duration of the animation at speed = 1 in seconds.
+ * @return the initial duration
+ */
+ public float getInitialDuration();
+
+ /**
+ * Sets the duration of the antionamtion at speed = 1 in seconds
+ * @param initialDuration
+ */
+ public void setInitialDuration(float initialDuration);
+
+ /**
+ * called internally in the update method, place here anything you want to run in the update loop
+ * @param tpf time per frame
+ */
+ public void internalUpdate(float tpf);
+
+ /**
+ * initialize this event
+ * @param app the application
+ * @param cinematic the cinematic
+ */
+ public void initEvent(Application app, Cinematic cinematic);
+
+ /**
+ * When this method is invoked, the event should fast forward to the given time according tim 0 is the start of the event.
+ * @param time the time to fast forward to
+ */
+ public void setTime(float time);
+
+ /**
+ * returns the current time of the cinematic event
+ * @return the time
+ */
+ public float getTime();
+
+
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/CinematicEventListener.java b/engine/src/core/com/jme3/cinematic/events/CinematicEventListener.java
new file mode 100644
index 0000000..9a5f5a6
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/CinematicEventListener.java
@@ -0,0 +1,17 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.jme3.cinematic.events;
+
+/**
+ *
+ * @author Nehon
+ */
+public interface CinematicEventListener {
+
+ public void onPlay(CinematicEvent cinematic);
+ public void onPause(CinematicEvent cinematic);
+ public void onStop(CinematicEvent cinematic);
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/MotionTrack.java b/engine/src/core/com/jme3/cinematic/events/MotionTrack.java
new file mode 100644
index 0000000..2995452
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/MotionTrack.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.cinematic.MotionPath;
+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.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.ViewPort;
+import com.jme3.scene.Spatial;
+import com.jme3.scene.control.Control;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+
+/**
+ * A MotionTrack is a control over the spatial that manage the position and direction of the spatial while following a motion Path
+ *
+ * You must first create a MotionPath and then create a MotionTrack to associate a spatial and the path.
+ *
+ * @author Nehon
+ */
+public class MotionTrack extends AbstractCinematicEvent implements Control {
+
+ protected Spatial spatial;
+ protected int currentWayPoint;
+ protected float currentValue;
+ protected Vector3f direction = new Vector3f();
+ protected Vector3f lookAt;
+ protected Vector3f upVector;
+ protected Quaternion rotation;
+ protected Direction directionType = Direction.None;
+ protected MotionPath path;
+ private boolean isControl = true;
+ /**
+ * the distance traveled by the spatial on the path
+ */
+ protected float traveledDistance = 0;
+
+ /**
+ * Enum for the different type of target direction behavior
+ */
+ public enum Direction {
+
+ /**
+ * the target stay in the starting direction
+ */
+ None,
+ /**
+ * The target rotates with the direction of the path
+ */
+ Path,
+ /**
+ * The target rotates with the direction of the path but with the additon of a rtotation
+ * you need to use the setRotation mathod when using this Direction
+ */
+ PathAndRotation,
+ /**
+ * The target rotates with the given rotation
+ */
+ Rotation,
+ /**
+ * The target looks at a point
+ * You need to use the setLookAt method when using this direction
+ */
+ LookAt
+ }
+
+ /**
+ * Create MotionTrack,
+ * when using this constructor don't forget to assign spatial and path
+ */
+ public MotionTrack() {
+ super();
+ }
+
+ /**
+ * Creates a MotionPath for the given spatial on the given motion path
+ * @param spatial
+ * @param path
+ */
+ public MotionTrack(Spatial spatial, MotionPath path) {
+ super();
+ this.spatial = spatial;
+ spatial.addControl(this);
+ this.path = path;
+ }
+
+ /**
+ * Creates a MotionPath for the given spatial on the given motion path
+ * @param spatial
+ * @param path
+ */
+ public MotionTrack(Spatial spatial, MotionPath path, float initialDuration) {
+ super(initialDuration);
+ this.spatial = spatial;
+ spatial.addControl(this);
+ this.path = path;
+ }
+
+ /**
+ * Creates a MotionPath for the given spatial on the given motion path
+ * @param spatial
+ * @param path
+ */
+ public MotionTrack(Spatial spatial, MotionPath path, LoopMode loopMode) {
+ super();
+ this.spatial = spatial;
+ spatial.addControl(this);
+ this.path = path;
+ this.loopMode = loopMode;
+ }
+
+ /**
+ * Creates a MotionPath for the given spatial on the given motion path
+ * @param spatial
+ * @param path
+ */
+ public MotionTrack(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
+ super(initialDuration);
+ this.spatial = spatial;
+ spatial.addControl(this);
+ this.path = path;
+ this.loopMode = loopMode;
+ }
+
+ public void update(float tpf) {
+ if (isControl) {
+
+ if (playState == PlayState.Playing) {
+ time = time + (tpf * speed);
+
+ if (time >= initialDuration && loopMode == loopMode.DontLoop) {
+ stop();
+ } else {
+ onUpdate(tpf);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void initEvent(Application app, Cinematic cinematic) {
+ super.initEvent(app, cinematic);
+ isControl = false;
+ }
+
+ @Override
+ public void setTime(float time) {
+ super.setTime(time);
+ onUpdate(0);
+ }
+
+ public void onUpdate(float tpf) {
+ traveledDistance = path.interpolatePath(time, this);
+ computeTargetDirection();
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(lookAt, "lookAt", Vector3f.ZERO);
+ oc.write(upVector, "upVector", Vector3f.UNIT_Y);
+ oc.write(rotation, "rotation", Quaternion.IDENTITY);
+ oc.write(directionType, "directionType", Direction.None);
+ oc.write(path, "path", null);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule in = im.getCapsule(this);
+ lookAt = (Vector3f) in.readSavable("lookAt", Vector3f.ZERO);
+ upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
+ rotation = (Quaternion) in.readSavable("rotation", Quaternion.IDENTITY);
+ directionType = in.readEnum("directionType", Direction.class, Direction.None);
+ path = (MotionPath) in.readSavable("path", null);
+ }
+
+ /**
+ * this method is meant to be called by the motion path only
+ * @return
+ */
+ public boolean needsDirection() {
+ return directionType == Direction.Path || directionType == Direction.PathAndRotation;
+ }
+
+ private void computeTargetDirection() {
+ switch (directionType) {
+ case Path:
+ Quaternion q = new Quaternion();
+ q.lookAt(direction, Vector3f.UNIT_Y);
+ spatial.setLocalRotation(q);
+ break;
+ case LookAt:
+ if (lookAt != null) {
+ spatial.lookAt(lookAt, upVector);
+ }
+ break;
+ case PathAndRotation:
+ if (rotation != null) {
+ Quaternion q2 = new Quaternion();
+ q2.lookAt(direction, Vector3f.UNIT_Y);
+ q2.multLocal(rotation);
+ spatial.setLocalRotation(q2);
+ }
+ break;
+ case Rotation:
+ if (rotation != null) {
+ spatial.setLocalRotation(rotation);
+ }
+ break;
+ case None:
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Clone this control for the given spatial
+ * @param spatial
+ * @return
+ */
+ public Control cloneForSpatial(Spatial spatial) {
+ MotionTrack control = new MotionTrack(spatial, path);
+ control.playState = playState;
+ control.currentWayPoint = currentWayPoint;
+ control.currentValue = currentValue;
+ control.direction = direction.clone();
+ control.lookAt = lookAt.clone();
+ control.upVector = upVector.clone();
+ control.rotation = rotation.clone();
+ control.initialDuration = initialDuration;
+ control.speed = speed;
+ control.loopMode = loopMode;
+ control.directionType = directionType;
+
+ return control;
+ }
+
+ @Override
+ public void onPlay() {
+ traveledDistance = 0;
+ }
+
+ @Override
+ public void onStop() {
+ currentWayPoint = 0;
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ /**
+ * this method is meant to be called by the motion path only
+ * @return
+ */
+ public float getCurrentValue() {
+ return currentValue;
+ }
+
+ /**
+ * this method is meant to be called by the motion path only
+ *
+ */
+ public void setCurrentValue(float currentValue) {
+ this.currentValue = currentValue;
+ }
+
+ /**
+ * this method is meant to be called by the motion path only
+ * @return
+ */
+ public int getCurrentWayPoint() {
+ return currentWayPoint;
+ }
+
+ /**
+ * this method is meant to be called by the motion path only
+ *
+ */
+ public void setCurrentWayPoint(int currentWayPoint) {
+ if (this.currentWayPoint != currentWayPoint) {
+ this.currentWayPoint = currentWayPoint;
+ path.triggerWayPointReach(currentWayPoint, this);
+ }
+ }
+
+ /**
+ * returns the direction the spatial is moving
+ * @return
+ */
+ public Vector3f getDirection() {
+ return direction;
+ }
+
+ /**
+ * Sets the direction of the spatial
+ * This method is used by the motion path.
+ * @param direction
+ */
+ public void setDirection(Vector3f direction) {
+ this.direction.set(direction);
+ }
+
+ /**
+ * returns the direction type of the target
+ * @return the direction type
+ */
+ public Direction getDirectionType() {
+ return directionType;
+ }
+
+ /**
+ * Sets the direction type of the target
+ * On each update the direction given to the target can have different behavior
+ * See the Direction Enum for explanations
+ * @param directionType the direction type
+ */
+ public void setDirectionType(Direction directionType) {
+ this.directionType = directionType;
+ }
+
+ /**
+ * Set the lookAt for the target
+ * This can be used only if direction Type is Direction.LookAt
+ * @param lookAt the position to look at
+ * @param upVector the up vector
+ */
+ public void setLookAt(Vector3f lookAt, Vector3f upVector) {
+ this.lookAt = lookAt;
+ this.upVector = upVector;
+ }
+
+ /**
+ * returns the rotation of the target
+ * @return the rotation quaternion
+ */
+ public Quaternion getRotation() {
+ return rotation;
+ }
+
+ /**
+ * sets the rotation of the target
+ * This can be used only if direction Type is Direction.PathAndRotation or Direction.Rotation
+ * With PathAndRotation the target will face the direction of the path multiplied by the given Quaternion.
+ * With Rotation the rotation of the target will be set with the given Quaternion.
+ * @param rotation the rotation quaternion
+ */
+ public void setRotation(Quaternion rotation) {
+ this.rotation = rotation;
+ }
+
+ /**
+ * retun the motion path this control follows
+ * @return
+ */
+ public MotionPath getPath() {
+ return path;
+ }
+
+ /**
+ * Sets the motion path to follow
+ * @param path
+ */
+ public void setPath(MotionPath path) {
+ this.path = path;
+ }
+
+ public void setEnabled(boolean enabled) {
+ if (enabled) {
+ play();
+ } else {
+ pause();
+ }
+ }
+
+ public boolean isEnabled() {
+ return playState != PlayState.Stopped;
+ }
+
+ public void render(RenderManager rm, ViewPort vp) {
+ }
+
+ public void setSpatial(Spatial spatial) {
+ this.spatial = spatial;
+ }
+
+ public Spatial getSpatial() {
+ return spatial;
+ }
+
+ /**
+ * return the distance traveled by the spatial on the path
+ * @return
+ */
+ public float getTraveledDistance() {
+ return traveledDistance;
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/PositionTrack.java b/engine/src/core/com/jme3/cinematic/events/PositionTrack.java
new file mode 100644
index 0000000..abab712
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/PositionTrack.java
@@ -0,0 +1,122 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Nehon
+ * @deprecated use spatial animation instead.
+ */
+@Deprecated
+public class PositionTrack extends AbstractCinematicEvent {
+
+ private static final Logger log = Logger.getLogger(PositionTrack.class.getName());
+ private Vector3f startPosition;
+ private Vector3f endPosition;
+ private Spatial spatial;
+ private String spatialName = "";
+ private float value = 0;
+
+ public PositionTrack() {
+ }
+
+ public PositionTrack(Spatial spatial, Vector3f endPosition) {
+ this.endPosition = endPosition;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ @Override
+ public void initEvent(Application app, Cinematic cinematic) {
+ super.initEvent(app, cinematic);
+ if (spatial == null) {
+ spatial = cinematic.getScene().getChild(spatialName);
+ if (spatial == null) {
+ } else {
+ log.log(Level.WARNING, "spatial {0} not found in the scene", spatialName);
+ }
+ }
+ }
+
+ public PositionTrack(Spatial spatial, Vector3f endPosition, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ this.endPosition = endPosition;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public PositionTrack(Spatial spatial, Vector3f endPosition, LoopMode loopMode) {
+ super(loopMode);
+ this.endPosition = endPosition;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public PositionTrack(Spatial spatial, Vector3f endPosition, float initialDuration) {
+ super(initialDuration);
+ this.endPosition = endPosition;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ @Override
+ public void onPlay() {
+ if (playState != playState.Paused) {
+ startPosition = spatial.getWorldTranslation().clone();
+ }
+ if (initialDuration == 0 && spatial != null) {
+
+ spatial.setLocalTranslation(endPosition);
+ }
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ if (spatial != null) {
+ value = Math.min(time / initialDuration, 1.0f);
+ Vector3f pos = FastMath.interpolateLinear(value, startPosition, endPosition);
+ spatial.setLocalTranslation(pos);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ value = 0;
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(spatialName, "spatialName", "");
+ oc.write(endPosition, "endPosition", null);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ spatialName = ic.readString("spatialName", "");
+ endPosition = (Vector3f) ic.readSavable("endPosition", null);
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/RotationTrack.java b/engine/src/core/com/jme3/cinematic/events/RotationTrack.java
new file mode 100644
index 0000000..60acf9d
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/RotationTrack.java
@@ -0,0 +1,126 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.math.Quaternion;
+import com.jme3.scene.Spatial;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Nehon
+ * @deprecated use spatial animation instead.
+ */
+@Deprecated
+public class RotationTrack extends AbstractCinematicEvent {
+
+ private static final Logger log = Logger.getLogger(RotationTrack.class.getName());
+ private Quaternion startRotation = new Quaternion();
+ private Quaternion endRotation = new Quaternion();
+ private Spatial spatial;
+ private String spatialName = "";
+ private float value = 0;
+
+ @Override
+ public void initEvent(Application app, Cinematic cinematic) {
+ super.initEvent(app, cinematic);
+ if (spatial == null) {
+ spatial = cinematic.getScene().getChild(spatialName);
+ if (spatial == null) {
+ } else {
+ log.log(Level.WARNING, "spatial {0} not found in the scene", spatialName);
+ }
+ }
+ }
+
+ public RotationTrack() {
+ }
+
+ public RotationTrack(Spatial spatial, Quaternion endRotation) {
+ this.endRotation.set(endRotation);
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public RotationTrack(Spatial spatial, Quaternion endRotation, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ this.endRotation.set(endRotation);
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public RotationTrack(Spatial spatial, Quaternion endRotation, LoopMode loopMode) {
+ super(loopMode);
+ this.endRotation.set(endRotation);
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public RotationTrack(Spatial spatial, Quaternion endRotation, float initialDuration) {
+ super(initialDuration);
+ this.endRotation.set(endRotation);
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ @Override
+ public void onPlay() {
+ if (playState != playState.Paused) {
+ startRotation.set(spatial.getWorldRotation());
+ }
+ if (initialDuration == 0 && spatial != null) {
+ spatial.setLocalRotation(endRotation);
+ stop();
+ }
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ if (spatial != null) {
+ value = Math.min(time / initialDuration, 1.0f);
+ TempVars vars = TempVars.get();
+ Quaternion q = vars.quat1;
+ q.set(startRotation).slerp(endRotation, value);
+
+ spatial.setLocalRotation(q);
+ vars.release();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ value = 0;
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(spatialName, "spatialName", "");
+ oc.write(endRotation, "endRotation", null);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ spatialName = ic.readString("spatialName", "");
+ endRotation = (Quaternion) ic.readSavable("endRotation", null);
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/ScaleTrack.java b/engine/src/core/com/jme3/cinematic/events/ScaleTrack.java
new file mode 100644
index 0000000..582adb5
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/ScaleTrack.java
@@ -0,0 +1,121 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.Spatial;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Nehon
+ * @deprecated use spatial animation instead.
+ */
+@Deprecated
+public class ScaleTrack extends AbstractCinematicEvent {
+
+ private static final Logger log = Logger.getLogger(RotationTrack.class.getName());
+ private Vector3f startScale;
+ private Vector3f endScale;
+ private Spatial spatial;
+ private String spatialName = "";
+ private float value = 0;
+
+ @Override
+ public void initEvent(Application app, Cinematic cinematic) {
+ super.initEvent(app, cinematic);
+ if (spatial == null) {
+ spatial = cinematic.getScene().getChild(spatialName);
+ if (spatial == null) {
+ } else {
+ log.log(Level.WARNING, "spatial {0} not found in the scene", spatialName);
+ }
+ }
+ }
+
+ public ScaleTrack() {
+ }
+
+ public ScaleTrack(Spatial spatial, Vector3f endScale) {
+ this.endScale = endScale;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public ScaleTrack(Spatial spatial, Vector3f endScale, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ this.endScale = endScale;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public ScaleTrack(Spatial spatial, Vector3f endScale, LoopMode loopMode) {
+ super(loopMode);
+ this.endScale = endScale;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ public ScaleTrack(Spatial spatial, Vector3f endScale, float initialDuration) {
+ super(initialDuration);
+ this.endScale = endScale;
+ this.spatial = spatial;
+ spatialName = spatial.getName();
+ }
+
+ @Override
+ public void onPlay() {
+ if (playState != playState.Paused) {
+ startScale = spatial.getWorldScale().clone();
+ }
+ if (initialDuration == 0 && spatial != null) {
+ spatial.setLocalScale(endScale);
+ stop();
+ }
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ if (spatial != null) {
+ value = Math.min(time / initialDuration, 1.0f);
+ spatial.setLocalScale(FastMath.interpolateLinear(value, startScale, endScale));
+ }
+ }
+
+ @Override
+ public void onStop() {
+ value = 0;
+ }
+
+ @Override
+ public void onPause() {
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(spatialName, "spatialName", "");
+ oc.write(endScale, "endScale", null);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ spatialName = ic.readString("spatialName", "");
+ endScale = (Vector3f) ic.readSavable("endScale", null);
+ }
+}
diff --git a/engine/src/core/com/jme3/cinematic/events/SoundTrack.java b/engine/src/core/com/jme3/cinematic/events/SoundTrack.java
new file mode 100644
index 0000000..77aae31
--- /dev/null
+++ b/engine/src/core/com/jme3/cinematic/events/SoundTrack.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.audio.AudioNode;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import java.io.IOException;
+
+/**
+ * A sound track to be played in a cinematic.
+ * @author Nehon
+ */
+public class SoundTrack extends AbstractCinematicEvent {
+
+ protected String path;
+ protected AudioNode audioNode;
+ protected boolean stream = false;
+
+ /**
+ * creates a sound track from the given resource path
+ * @param path the path to an audi file (ie : "Sounds/mySound.wav")
+ */
+ public SoundTrack(String path) {
+ this.path = path;
+ }
+
+ /**
+ * creates a sound track from the given resource path
+ * @param path the path to an audi file (ie : "Sounds/mySound.wav")
+ * @param stream true to make the audio data streamed
+ */
+ public SoundTrack(String path, boolean stream) {
+ this(path);
+ this.stream = stream;
+ }
+
+ public SoundTrack(String path, boolean stream, float initialDuration) {
+ super(initialDuration);
+ this.path = path;
+ this.stream = stream;
+ }
+
+ public SoundTrack(String path, boolean stream, LoopMode loopMode) {
+ super(loopMode);
+ this.path = path;
+ this.stream = stream;
+ }
+
+ public SoundTrack(String path, boolean stream, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ this.path = path;
+ this.stream = stream;
+ }
+
+ public SoundTrack(String path, float initialDuration) {
+ super(initialDuration);
+ this.path = path;
+ }
+
+ public SoundTrack(String path, LoopMode loopMode) {
+ super(loopMode);
+ this.path = path;
+ }
+
+ public SoundTrack(String path, float initialDuration, LoopMode loopMode) {
+ super(initialDuration, loopMode);
+ this.path = path;
+ }
+
+ public SoundTrack() {
+ }
+
+ @Override
+ public void initEvent(Application app, Cinematic cinematic) {
+ super.initEvent(app, cinematic);
+ audioNode = new AudioNode(app.getAssetManager(), path, stream);
+ setLoopMode(loopMode);
+ }
+
+ @Override
+ public void setTime(float time) {
+ super.setTime(time);
+ //can occur on rewind
+ if (time < 0) {
+ stop();
+ }
+ audioNode.setTimeOffset(time);
+ }
+
+ @Override
+ public void onPlay() {
+ audioNode.play();
+ }
+
+ @Override
+ public void onStop() {
+ audioNode.stop();
+
+ }
+
+ @Override
+ public void onPause() {
+ audioNode.pause();
+ }
+
+ @Override
+ public void onUpdate(float tpf) {
+ if (audioNode.getStatus() == AudioNode.Status.Stopped) {
+ stop();
+ }
+ }
+
+ /**
+ * Returns the underlying audion node of this sound track
+ * @return
+ */
+ public AudioNode getAudioNode() {
+ return audioNode;
+ }
+
+ @Override
+ public void setLoopMode(LoopMode loopMode) {
+ super.setLoopMode(loopMode);
+
+ if (loopMode != LoopMode.DontLoop) {
+ audioNode.setLooping(true);
+ } else {
+ audioNode.setLooping(false);
+ }
+ }
+
+ @Override
+ public void write(JmeExporter ex) throws IOException {
+ super.write(ex);
+ OutputCapsule oc = ex.getCapsule(this);
+ oc.write(path, "path", "");
+ oc.write(stream, "stream", false);
+ }
+
+ @Override
+ public void read(JmeImporter im) throws IOException {
+ super.read(im);
+ InputCapsule ic = im.getCapsule(this);
+ path = ic.readString("path", "");
+ stream = ic.readBoolean("stream", false);
+
+ }
+}