diff options
author | Scott Barta <sbarta@google.com> | 2012-03-01 12:35:35 -0800 |
---|---|---|
committer | Scott Barta <sbarta@google.com> | 2012-03-01 12:40:08 -0800 |
commit | 59b2e6871c65f58fdad78cd7229c292f6a177578 (patch) | |
tree | 2d4e7bfc05b93f40b34675d77e403dd1c25efafd /engine/src/core/com/jme3/cinematic | |
parent | f9b30489e75ac1eabc365064959804e99534f7ab (diff) | |
download | jmonkeyengine-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')
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); + + } +} |