Trying to make Cinematic serialization work.

This way at least it doesn't crash: Removed anonymous inner class and made new class; CameraEvent
Added a bunch of default constructors for other related classes in the process.
empirephoenix-patch-1
Rickard Edén 7 years ago committed by Rémy Bouquet
parent 2120c9d334
commit ae97614c83
  1. 734
      jme3-core/src/main/java/com/jme3/animation/AnimChannel.java
  2. 4
      jme3-core/src/main/java/com/jme3/animation/AnimationUtils.java
  3. 1426
      jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java
  4. 182
      jme3-core/src/main/java/com/jme3/cinematic/KeyFrame.java
  5. 895
      jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java
  6. 146
      jme3-core/src/main/java/com/jme3/cinematic/events/CameraEvent.java
  7. 982
      jme3-core/src/main/java/com/jme3/cinematic/events/MotionEvent.java
  8. 459
      jme3-core/src/main/java/com/jme3/cinematic/events/SoundEvent.java
  9. 245
      jme3-core/src/main/java/com/jme3/scene/CameraNode.java

@ -1,365 +1,369 @@
/*
* 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.animation;
import com.jme3.math.FastMath;
import com.jme3.util.TempVars;
import java.util.BitSet;
/**
* <code>AnimChannel</code> provides controls, such as play, pause,
* fast forward, etc, for an animation. The animation
* channel may influence the entire model or specific bones of the model's
* skeleton. A single model may have multiple animation channels influencing
* various parts of its body. For example, a character model may have an
* animation channel for its feet, and another for its torso, and
* the animations for each channel are controlled independently.
*
* @author Kirill Vainer
*/
public final class AnimChannel {
private static final float DEFAULT_BLEND_TIME = 0.15f;
private AnimControl control;
private BitSet affectedBones;
private Animation animation;
private Animation blendFrom;
private float time;
private float speed;
private float timeBlendFrom;
private float blendTime;
private float speedBlendFrom;
private boolean notified=false;
private LoopMode loopMode, loopModeBlendFrom;
private float blendAmount = 1f;
private float blendRate = 0;
AnimChannel(AnimControl control){
this.control = control;
}
/**
* Returns the parent control of this AnimChannel.
*
* @return the parent control of this AnimChannel.
* @see AnimControl
*/
public AnimControl getControl() {
return control;
}
/**
* @return The name of the currently playing animation, or null if
* none is assigned.
*
* @see AnimChannel#setAnim(java.lang.String)
*/
public String getAnimationName() {
return animation != null ? animation.getName() : null;
}
/**
* @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
* @see AnimChannel#setLoopMode(com.jme3.animation.LoopMode)
*/
public LoopMode getLoopMode() {
return loopMode;
}
/**
* @param loopMode 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 loopMode) {
this.loopMode = loopMode;
}
/**
* @return The speed that is assigned to the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*
* @see AnimChannel#setSpeed(float)
*/
public float getSpeed() {
return speed;
}
/**
* @param speed Set the speed of the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*/
public void setSpeed(float speed) {
this.speed = speed;
if(blendTime>0){
this.speedBlendFrom = speed;
blendTime = Math.min(blendTime, animation.getLength() / speed);
blendRate = 1/ blendTime;
}
}
/**
* @return The time of the currently playing animation. The time
* starts at 0 and continues on until getAnimMaxTime().
*
* @see AnimChannel#setTime(float)
*/
public float getTime() {
return time;
}
/**
* @param time Set the time of the currently playing animation, the time
* is clamped from 0 to {@link #getAnimMaxTime()}.
*/
public void setTime(float time) {
this.time = FastMath.clamp(time, 0, getAnimMaxTime());
}
/**
* @return The length of the currently playing animation, or zero
* if no animation is playing.
*
* @see AnimChannel#getTime()
*/
public float getAnimMaxTime(){
return animation != null ? animation.getLength() : 0f;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* This resets the time to zero, and optionally blends the animation
* over <code>blendTime</code> seconds with the currently playing animation.
* Notice that this method will reset the control's speed to 1.0.
*
* @param name The name of the animation to play
* @param blendTime The blend time over which to blend the new animation
* with the old one. If zero, then no blending will occur and the new
* animation will be applied instantly.
*/
public void setAnim(String name, float blendTime){
if (name == null)
throw new IllegalArgumentException("name cannot be null");
if (blendTime < 0f)
throw new IllegalArgumentException("blendTime cannot be less than zero");
Animation anim = control.animationMap.get(name);
if (anim == null)
throw new IllegalArgumentException("Cannot find animation named: '"+name+"'");
control.notifyAnimChange(this, name);
if (animation != null && blendTime > 0f){
this.blendTime = blendTime;
// activate blending
blendTime = Math.min(blendTime, anim.getLength() / speed);
blendFrom = animation;
timeBlendFrom = time;
speedBlendFrom = speed;
loopModeBlendFrom = loopMode;
blendAmount = 0f;
blendRate = 1f / blendTime;
}else{
blendFrom = null;
}
animation = anim;
time = 0;
speed = 1f;
loopMode = LoopMode.Loop;
notified = false;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* See {@link #setAnim(java.lang.String, float)}.
* The blendTime argument by default is 150 milliseconds.
*
* @param name The name of the animation to play
*/
public void setAnim(String name){
setAnim(name, DEFAULT_BLEND_TIME);
}
/**
* Add all the bones of the model's skeleton to be
* influenced by this animation channel.
*/
public void addAllBones() {
affectedBones = null;
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(String name) {
addBone(control.getSkeleton().getBone(name));
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(Bone bone) {
int boneIndex = control.getSkeleton().getBoneIndex(bone);
if(affectedBones == null) {
affectedBones = new BitSet(control.getSkeleton().getBoneCount());
}
affectedBones.set(boneIndex);
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone name and going toward the root bone.
*/
public void addToRootBone(String name) {
addToRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone and going toward the root bone.
*/
public void addToRootBone(Bone bone) {
addBone(bone);
while (bone.getParent() != null) {
bone = bone.getParent();
addBone(bone);
}
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given named bone and going toward its children.
*/
public void addFromRootBone(String name) {
addFromRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given bone and going toward its children.
*/
public void addFromRootBone(Bone bone) {
addBone(bone);
if (bone.getChildren() == null)
return;
for (Bone childBone : bone.getChildren()) {
addBone(childBone);
addFromRootBone(childBone);
}
}
BitSet getAffectedBones(){
return affectedBones;
}
public void reset(boolean rewind){
if(rewind){
setTime(0);
if(control.getSkeleton()!=null){
control.getSkeleton().resetAndUpdate();
}else{
TempVars vars = TempVars.get();
update(0, vars);
vars.release();
}
}
animation = null;
notified = false;
}
void update(float tpf, TempVars vars) {
if (animation == null)
return;
if (blendFrom != null && blendAmount != 1.0f){
// The blendFrom anim is set, the actual animation
// playing will be set
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
timeBlendFrom += tpf * speedBlendFrom;
timeBlendFrom = AnimationUtils.clampWrapTime(timeBlendFrom,
blendFrom.getLength(),
loopModeBlendFrom);
if (timeBlendFrom < 0){
timeBlendFrom = -timeBlendFrom;
speedBlendFrom = -speedBlendFrom;
}
blendAmount += tpf * blendRate;
if (blendAmount > 1f){
blendAmount = 1f;
blendFrom = null;
}
}
animation.setTime(time, blendAmount, control, this, vars);
time += tpf * speed;
if (animation.getLength() > 0){
if (!notified && (time >= animation.getLength() || time < 0)) {
if (loopMode == LoopMode.DontLoop) {
// Note that this flag has to be set before calling the notify
// since the notify may start a new animation and then unset
// the flag.
notified = true;
}
control.notifyAnimCycleDone(this, animation.getName());
}
}
time = AnimationUtils.clampWrapTime(time, animation.getLength(), loopMode);
if (time < 0){
// Negative time indicates that speed should be inverted
// (for cycle loop mode only)
time = -time;
speed = -speed;
}
}
}
/*
* 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.animation;
import com.jme3.math.FastMath;
import com.jme3.util.TempVars;
import java.util.BitSet;
/**
* <code>AnimChannel</code> provides controls, such as play, pause,
* fast forward, etc, for an animation. The animation
* channel may influence the entire model or specific bones of the model's
* skeleton. A single model may have multiple animation channels influencing
* various parts of its body. For example, a character model may have an
* animation channel for its feet, and another for its torso, and
* the animations for each channel are controlled independently.
*
* @author Kirill Vainer
*/
public final class AnimChannel {
private static final float DEFAULT_BLEND_TIME = 0.15f;
private AnimControl control;
private BitSet affectedBones;
private Animation animation;
private Animation blendFrom;
private float time;
private float speed;
private float timeBlendFrom;
private float blendTime;
private float speedBlendFrom;
private boolean notified=false;
private LoopMode loopMode, loopModeBlendFrom;
private float blendAmount = 1f;
private float blendRate = 0;
public AnimChannel(){
}
public AnimChannel(AnimControl control){
this.control = control;
}
/**
* Returns the parent control of this AnimChannel.
*
* @return the parent control of this AnimChannel.
* @see AnimControl
*/
public AnimControl getControl() {
return control;
}
/**
* @return The name of the currently playing animation, or null if
* none is assigned.
*
* @see AnimChannel#setAnim(java.lang.String)
*/
public String getAnimationName() {
return animation != null ? animation.getName() : null;
}
/**
* @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
* @see AnimChannel#setLoopMode(com.jme3.animation.LoopMode)
*/
public LoopMode getLoopMode() {
return loopMode;
}
/**
* @param loopMode 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 loopMode) {
this.loopMode = loopMode;
}
/**
* @return The speed that is assigned to the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*
* @see AnimChannel#setSpeed(float)
*/
public float getSpeed() {
return speed;
}
/**
* @param speed Set the speed of the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*/
public void setSpeed(float speed) {
this.speed = speed;
if(blendTime>0){
this.speedBlendFrom = speed;
blendTime = Math.min(blendTime, animation.getLength() / speed);
blendRate = 1/ blendTime;
}
}
/**
* @return The time of the currently playing animation. The time
* starts at 0 and continues on until getAnimMaxTime().
*
* @see AnimChannel#setTime(float)
*/
public float getTime() {
return time;
}
/**
* @param time Set the time of the currently playing animation, the time
* is clamped from 0 to {@link #getAnimMaxTime()}.
*/
public void setTime(float time) {
this.time = FastMath.clamp(time, 0, getAnimMaxTime());
}
/**
* @return The length of the currently playing animation, or zero
* if no animation is playing.
*
* @see AnimChannel#getTime()
*/
public float getAnimMaxTime(){
return animation != null ? animation.getLength() : 0f;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* This resets the time to zero, and optionally blends the animation
* over <code>blendTime</code> seconds with the currently playing animation.
* Notice that this method will reset the control's speed to 1.0.
*
* @param name The name of the animation to play
* @param blendTime The blend time over which to blend the new animation
* with the old one. If zero, then no blending will occur and the new
* animation will be applied instantly.
*/
public void setAnim(String name, float blendTime){
if (name == null)
throw new IllegalArgumentException("name cannot be null");
if (blendTime < 0f)
throw new IllegalArgumentException("blendTime cannot be less than zero");
Animation anim = control.animationMap.get(name);
if (anim == null)
throw new IllegalArgumentException("Cannot find animation named: '"+name+"'");
control.notifyAnimChange(this, name);
if (animation != null && blendTime > 0f){
this.blendTime = blendTime;
// activate blending
blendTime = Math.min(blendTime, anim.getLength() / speed);
blendFrom = animation;
timeBlendFrom = time;
speedBlendFrom = speed;
loopModeBlendFrom = loopMode;
blendAmount = 0f;
blendRate = 1f / blendTime;
}else{
blendFrom = null;
}
animation = anim;
time = 0;
speed = 1f;
loopMode = LoopMode.Loop;
notified = false;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* See {@link #setAnim(java.lang.String, float)}.
* The blendTime argument by default is 150 milliseconds.
*
* @param name The name of the animation to play
*/
public void setAnim(String name){
setAnim(name, DEFAULT_BLEND_TIME);
}
/**
* Add all the bones of the model's skeleton to be
* influenced by this animation channel.
*/
public void addAllBones() {
affectedBones = null;
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(String name) {
addBone(control.getSkeleton().getBone(name));
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(Bone bone) {
int boneIndex = control.getSkeleton().getBoneIndex(bone);
if(affectedBones == null) {
affectedBones = new BitSet(control.getSkeleton().getBoneCount());
}
affectedBones.set(boneIndex);
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone name and going toward the root bone.
*/
public void addToRootBone(String name) {
addToRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone and going toward the root bone.
*/
public void addToRootBone(Bone bone) {
addBone(bone);
while (bone.getParent() != null) {
bone = bone.getParent();
addBone(bone);
}
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given named bone and going toward its children.
*/
public void addFromRootBone(String name) {
addFromRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given bone and going toward its children.
*/
public void addFromRootBone(Bone bone) {
addBone(bone);
if (bone.getChildren() == null)
return;
for (Bone childBone : bone.getChildren()) {
addBone(childBone);
addFromRootBone(childBone);
}
}
BitSet getAffectedBones(){
return affectedBones;
}
public void reset(boolean rewind){
if(rewind){
setTime(0);
if(control.getSkeleton()!=null){
control.getSkeleton().resetAndUpdate();
}else{
TempVars vars = TempVars.get();
update(0, vars);
vars.release();
}
}
animation = null;
notified = false;
}
void update(float tpf, TempVars vars) {
if (animation == null)
return;
if (blendFrom != null && blendAmount != 1.0f){
// The blendFrom anim is set, the actual animation
// playing will be set
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
timeBlendFrom += tpf * speedBlendFrom;
timeBlendFrom = AnimationUtils.clampWrapTime(timeBlendFrom,
blendFrom.getLength(),
loopModeBlendFrom);
if (timeBlendFrom < 0){
timeBlendFrom = -timeBlendFrom;
speedBlendFrom = -speedBlendFrom;
}
blendAmount += tpf * blendRate;
if (blendAmount > 1f){
blendAmount = 1f;
blendFrom = null;
}
}
animation.setTime(time, blendAmount, control, this, vars);
time += tpf * speed;
if (animation.getLength() > 0){
if (!notified && (time >= animation.getLength() || time < 0)) {
if (loopMode == LoopMode.DontLoop) {
// Note that this flag has to be set before calling the notify
// since the notify may start a new animation and then unset
// the flag.
notified = true;
}
control.notifyAnimCycleDone(this, animation.getName());
}
}
time = AnimationUtils.clampWrapTime(time, animation.getLength(), loopMode);
if (time < 0){
// Negative time indicates that speed should be inverted
// (for cycle loop mode only)
time = -time;
speed = -speed;
}
}
}

@ -41,7 +41,9 @@ import static com.jme3.animation.LoopMode.Loop;
*/
public class AnimationUtils {
public AnimationUtils(){
}
/**
* Clamps the time according to duration and loopMode
* @param time

File diff suppressed because it is too large Load Diff

@ -1,89 +1,93 @@
/*
* 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;
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 boolean isEmpty(){
return cinematicEvents.isEmpty();
}
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;
}
}
/*
* 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;
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 {
public KeyFrame(){
}
List<CinematicEvent> cinematicEvents = new ArrayList<>();
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 boolean isEmpty(){
return cinematicEvents.isEmpty();
}
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;
}
}

@ -1,447 +1,448 @@
/*
* 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.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.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
/**
* An event based on an animation of a model. The model has to hold an
* AnimControl with valid animation (bone or spatial animations).
*
* It helps to schedule the playback of an animation on a model in a Cinematic.
*
*
* @author Nehon
*/
public class AnimationEvent extends AbstractCinematicEvent {
// Version #2: directly keeping track on the model instead of trying to retrieve
//it from the scene according to its name, because the name is not supposed to be unique
//For backward compatibility, if the model is null it's looked up into the scene
public static final int SAVABLE_VERSION = 2;
private static final Logger log = Logger.getLogger(AnimationEvent.class.getName());
public static final String MODEL_CHANNELS = "modelChannels";
protected AnimChannel channel;
protected String animationName;
protected Spatial model;
//kept for backward compatibility
protected String modelName;
protected float blendTime = 0;
protected int channelIndex = 0;
// parent cinematic
protected Cinematic cinematic;
/**
* used for serialization don't call directly use one of the following
* constructors
*/
public AnimationEvent() {
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
*/
public AnimationEvent(Spatial model, String animationName) {
this.model = model;
this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration) {
super(initialDuration);
this.model = model;
this.animationName = animationName;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param loopMode the loopMode
* @see LoopMode
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode) {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.animationName = animationName;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.model = model;
this.animationName = animationName;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param blendTime the time during the animation are gonna be blended
* @see AnimChannel#setAnim(java.lang.String, float)
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, float blendTime) {
super(initialDuration);
this.model = model;
this.animationName = animationName;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param loopMode the loopMode
* @see LoopMode
* @param blendTime the time during the animation are gonna be blended
* @see AnimChannel#setAnim(java.lang.String, float)
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, float blendTime) {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.animationName = animationName;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
* @param blendTime the time during the animation are gonna be blended
* @see AnimChannel#setAnim(java.lang.String, float)
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, float blendTime) {
super(initialDuration, loopMode);
this.model = model;
this.animationName = animationName;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param loopMode the loopMode
* @see LoopMode
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex) {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.animationName = animationName;
this.channelIndex = channelIndex;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, int channelIndex) {
this.model = model;
this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.channelIndex = channelIndex;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param channelIndex the index of the channel default is 0. Events on the
* @param blendTime the time during the animation are gonna be blended
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex, float blendTime) {
this.model = model;
this.animationName = animationName;
this.loopMode = loopMode;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.channelIndex = channelIndex;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, int channelIndex) {
super(initialDuration);
this.model = model;
this.animationName = animationName;
this.channelIndex = channelIndex;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, int channelIndex) {
super(initialDuration, loopMode);
this.model = model;
this.animationName = animationName;
this.channelIndex = channelIndex;
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
this.cinematic = cinematic;
if (channel == null) {
Object s = cinematic.getEventData(MODEL_CHANNELS, model);
if (s == null) {
s = new HashMap<Integer, AnimChannel>();
int numChannels = model.getControl(AnimControl.class).getNumChannels();
for(int i = 0; i < numChannels; i++){
((HashMap<Integer, AnimChannel>)s).put(i, model.getControl(AnimControl.class).getChannel(i));
}
cinematic.putEventData(MODEL_CHANNELS, model, s);
}
Map<Integer, AnimChannel> map = (Map<Integer, AnimChannel>) s;
this.channel = map.get(channelIndex);
if (this.channel == null) {
if (model == null) {
//the model is null we try to find it according to the name
//this should occur only when loading an old saved cinematic
//othewise it's an error
model = cinematic.getScene().getChild(modelName);
}
if (model != null) {
channel = model.getControl(AnimControl.class).createChannel();
map.put(channelIndex, channel);
} else {
//it's an error
throw new UnsupportedOperationException("model should not be null");
}
}
}
}
@Override
public void setTime(float time) {
super.setTime(time);
if (!animationName.equals(channel.getAnimationName())) {
channel.setAnim(animationName, blendTime);
}
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();
}
}
if (t < 0) {
channel.setTime(0);
channel.reset(true);
}
if (t > channel.getAnimMaxTime()) {
channel.setTime(t);
channel.getControl().update(0);
stop();
} else {
channel.setTime(t);
channel.getControl().update(0);
}
}
@Override
public void onPlay() {
channel.getControl().setEnabled(true);
if (playState == PlayState.Stopped) {
channel.setAnim(animationName, blendTime);
channel.setSpeed(speed);
channel.setLoopMode(loopMode);
channel.setTime(0);
}
}
@Override
public void setSpeed(float speed) {
super.setSpeed(speed);
if (channel != null) {
channel.setSpeed(speed);
}
}
@Override
public void onUpdate(float tpf) {
}
@Override
public void onStop() {
}
@Override
public void forceStop() {
if (channel != null) {
channel.setTime(time);
channel.reset(false);
}
super.forceStop();
}
@Override
public void onPause() {
if (channel != null) {
channel.getControl().setEnabled(false);
}
}
@Override
public void setLoopMode(LoopMode loopMode) {
super.setLoopMode(loopMode);
if (channel != null) {
channel.setLoopMode(loopMode);
}
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(model, "model", null);
oc.write(animationName, "animationName", "");
oc.write(blendTime, "blendTime", 0f);
oc.write(channelIndex, "channelIndex", 0);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
if (im.getFormatVersion() == 0) {
modelName = ic.readString("modelName", "");
}
//FIXME always the same issue, because of the clonning of assets, this won't work
//we have to somehow store userdata in the spatial and then recurse the
//scene sub scenegraph to find the correct instance of the model
//This brings a reflaxion about the cinematic being an appstate,
//shouldn't it be a control over the scene
// this would allow to use the cloneForSpatial method and automatically
//rebind cloned references of original objects.
//for now as nobody probably ever saved a cinematic, this is not a critical issue
model = (Spatial) ic.readSavable("model", null);
animationName = ic.readString("animationName", "");
blendTime = ic.readFloat("blendTime", 0f);
channelIndex = ic.readInt("channelIndex", 0);
}
@Override
public void dispose() {
super.dispose();
if (cinematic != null) {
Object o = cinematic.getEventData(MODEL_CHANNELS, model);
if (o != null) {
Collection<AnimChannel> values = ((HashMap<Integer, AnimChannel>) o).values();
while (values.remove(channel));
if (values.isEmpty()) {
cinematic.removeEventData(MODEL_CHANNELS, model);
}
}
cinematic = null;
channel = null;
}
}
}
/*
* 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.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.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
/**
* An event based on an animation of a model. The model has to hold an
* AnimControl with valid animation (bone or spatial animations).
*
* It helps to schedule the playback of an animation on a model in a Cinematic.
*
*
* @author Nehon
*/
public class AnimationEvent extends AbstractCinematicEvent {
// Version #2: directly keeping track on the model instead of trying to retrieve
//it from the scene according to its name, because the name is not supposed to be unique
//For backward compatibility, if the model is null it's looked up into the scene
public static final int SAVABLE_VERSION = 2;
private static final Logger log = Logger.getLogger(AnimationEvent.class.getName());
public static final String MODEL_CHANNELS = "modelChannels";
protected AnimChannel channel;
protected String animationName;
protected Spatial model;
//kept for backward compatibility
protected String modelName;
protected float blendTime = 0;
protected int channelIndex = 0;
// parent cinematic
protected Cinematic cinematic;
/**
* used for serialization don't call directly use one of the following
* constructors
*/
public AnimationEvent() {
super();
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
*/
public AnimationEvent(Spatial model, String animationName) {
this.model = model;
this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration) {
super(initialDuration);
this.model = model;
this.animationName = animationName;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param loopMode the loopMode
* @see LoopMode
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode) {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.animationName = animationName;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.model = model;
this.animationName = animationName;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param blendTime the time during the animation are gonna be blended
* @see AnimChannel#setAnim(java.lang.String, float)
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, float blendTime) {
super(initialDuration);
this.model = model;
this.animationName = animationName;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param loopMode the loopMode
* @see LoopMode
* @param blendTime the time during the animation are gonna be blended
* @see AnimChannel#setAnim(java.lang.String, float)
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, float blendTime) {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.animationName = animationName;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
* @param blendTime the time during the animation are gonna be blended
* @see AnimChannel#setAnim(java.lang.String, float)
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, float blendTime) {
super(initialDuration, loopMode);
this.model = model;
this.animationName = animationName;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param loopMode the loopMode
* @see LoopMode
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex) {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.animationName = animationName;
this.channelIndex = channelIndex;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, int channelIndex) {
this.model = model;
this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.channelIndex = channelIndex;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param channelIndex the index of the channel default is 0. Events on the
* @param blendTime the time during the animation are gonna be blended
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex, float blendTime) {
this.model = model;
this.animationName = animationName;
this.loopMode = loopMode;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.channelIndex = channelIndex;
this.blendTime = blendTime;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, int channelIndex) {
super(initialDuration);
this.model = model;
this.animationName = animationName;
this.channelIndex = channelIndex;
}
/**
* creates an animation event
*
* @param model the model on which the animation will be played
* @param animationName the name of the animation to play
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
* @param channelIndex the index of the channel default is 0. Events on the
* same channelIndex will use the same channel.
*/
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, int channelIndex) {
super(initialDuration, loopMode);
this.model = model;
this.animationName = animationName;
this.channelIndex = channelIndex;
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
this.cinematic = cinematic;
if (channel == null) {
Object s = cinematic.getEventData(MODEL_CHANNELS, model);
if (s == null) {
s = new HashMap<Integer, AnimChannel>();
int numChannels = model.getControl(AnimControl.class).getNumChannels();
for(int i = 0; i < numChannels; i++){
((HashMap<Integer, AnimChannel>)s).put(i, model.getControl(AnimControl.class).getChannel(i));
}
cinematic.putEventData(MODEL_CHANNELS, model, s);
}
Map<Integer, AnimChannel> map = (Map<Integer, AnimChannel>) s;
this.channel = map.get(channelIndex);
if (this.channel == null) {
if (model == null) {
//the model is null we try to find it according to the name
//this should occur only when loading an old saved cinematic
//othewise it's an error
model = cinematic.getScene().getChild(modelName);
}
if (model != null) {
channel = model.getControl(AnimControl.class).createChannel();
map.put(channelIndex, channel);
} else {
//it's an error
throw new UnsupportedOperationException("model should not be null");
}
}
}
}
@Override
public void setTime(float time) {
super.setTime(time);
if (!animationName.equals(channel.getAnimationName())) {
channel.setAnim(animationName, blendTime);
}
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();
}
}
if (t < 0) {
channel.setTime(0);
channel.reset(true);
}
if (t > channel.getAnimMaxTime()) {
channel.setTime(t);
channel.getControl().update(0);
stop();
} else {
channel.setTime(t);
channel.getControl().update(0);
}
}
@Override
public void onPlay() {
channel.getControl().setEnabled(true);
if (playState == PlayState.Stopped) {
channel.setAnim(animationName, blendTime);
channel.setSpeed(speed);
channel.setLoopMode(loopMode);
channel.setTime(0);
}
}
@Override
public void setSpeed(float speed) {
super.setSpeed(speed);
if (channel != null) {
channel.setSpeed(speed);
}
}
@Override
public void onUpdate(float tpf) {
}
@Override
public void onStop() {
}
@Override
public void forceStop() {
if (channel != null) {
channel.setTime(time);
channel.reset(false);
}
super.forceStop();
}
@Override
public void onPause() {
if (channel != null) {
channel.getControl().setEnabled(false);
}
}
@Override
public void setLoopMode(LoopMode loopMode) {
super.setLoopMode(loopMode);
if (channel != null) {
channel.setLoopMode(loopMode);
}
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(model, "model", null);
oc.write(animationName, "animationName", "");
oc.write(blendTime, "blendTime", 0f);
oc.write(channelIndex, "channelIndex", 0);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
if (im.getFormatVersion() == 0) {
modelName = ic.readString("modelName", "");
}
//FIXME always the same issue, because of the clonning of assets, this won't work
//we have to somehow store userdata in the spatial and then recurse the
//scene sub scenegraph to find the correct instance of the model
//This brings a reflaxion about the cinematic being an appstate,
//shouldn't it be a control over the scene
// this would allow to use the cloneForSpatial method and automatically
//rebind cloned references of original objects.
//for now as nobody probably ever saved a cinematic, this is not a critical issue
model = (Spatial) ic.readSavable("model", null);
animationName = ic.readString("animationName", "");
blendTime = ic.readFloat("blendTime", 0f);
channelIndex = ic.readInt("channelIndex", 0);
}
@Override
public void dispose() {
super.dispose();
if (cinematic != null) {
Object o = cinematic.getEventData(MODEL_CHANNELS, model);
if (o != null) {
Collection<AnimChannel> values = ((HashMap<Integer, AnimChannel>) o).values();
while (values.remove(channel));
if (values.isEmpty()) {
cinematic.removeEventData(MODEL_CHANNELS, model);
}
}
cinematic = null;
channel = null;
}
}
}

@ -0,0 +1,146 @@
/*
* Copyright (c) 2009-2017 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.app.Application;
import com.jme3.cinematic.Cinematic;
import com.jme3.cinematic.TimeLine;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import com.jme3.scene.CameraNode;
import java.io.IOException;
import java.util.Map;
/**
*
* @author Rickard <neph1 @ github>
*/
public class CameraEvent extends AbstractCinematicEvent{
private String cameraName;
private Cinematic cinematic;
public String getCameraName() {
return cameraName;
}
public void setCameraName(String cameraName) {
this.cameraName = cameraName;
}
public CameraEvent(){
}
public CameraEvent(Cinematic parentEvent, String cameraName){
this.cinematic = parentEvent;
this.cameraName = cameraName;
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
this.cinematic = cinematic;
}
@Override
public void play() {
super.play();
stop();
}
@Override
public void onPlay() {
cinematic.setActiveCamera(cameraName);
}
@Override
public void onUpdate(float tpf) {
}
@Override
public void onStop() {
}
@Override
public void onPause() {
}
@Override
public void forceStop() {
}
@Override
public void setTime(float time) {
play();
}
public Cinematic getCinematic() {
return cinematic;
}
public void setCinematic(Cinematic cinematic) {
this.cinematic = cinematic;
}
/**
* used internally for serialization
*
* @param ex
* @throws IOException
*/
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(cameraName, "cameraName", null);
}
/**
* used internally for serialization
*
* @param im
* @throws IOException
*/
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
cameraName = ic.readString("cameraName", null);
}
}

@ -1,491 +1,491 @@
/*
* Copyright (c) 2009-2016 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.AnimationUtils;
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.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.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
* A MotionEvent is a control over the spatial that manages the position and direction of the spatial while following a motion Path.
*
* You must first create a MotionPath and then create a MotionEvent to associate a spatial and the path.
*
* @author Nehon
*/
public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable {
protected Spatial spatial;
protected int currentWayPoint;
protected float currentValue;
protected Vector3f direction = new Vector3f();
protected Vector3f lookAt = null;
protected Vector3f upVector = Vector3f.UNIT_Y;
protected Quaternion rotation = null;
protected Direction directionType = Direction.None;
protected MotionPath path;
private boolean isControl = true;
private int travelDirection = 1;
/**
* 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 stays 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 addition of a rotation.
* You need to use the setRotation method 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 MotionEvent,
* when using this constructor don't forget to assign spatial and path.
*/
public MotionEvent() {
super();
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path) {
super();
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, LoopMode loopMode) {
super();
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 MotionEvent(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
this.loopMode = loopMode;
}
public void update(float tpf) {
if (isControl) {
internalUpdate(tpf);
}
}
@Override
public void internalUpdate(float tpf) {
if (playState == PlayState.Playing) {
time = time + (tpf * speed);
if (loopMode == LoopMode.Loop && time < 0) {
time = initialDuration;
}
if ((time >= initialDuration || time < 0) && loopMode == LoopMode.DontLoop) {
if (time >= initialDuration) {
path.triggerWayPointReach(path.getNbWayPoints() - 1, this);
}
stop();
} else {
time = AnimationUtils.clampWrapTime(time, initialDuration, loopMode);
if(time<0){
speed = - speed;
time = - time;
}
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, tpf);
computeTargetDirection();
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(lookAt, "lookAt", null);
oc.write(upVector, "upVector", Vector3f.UNIT_Y);
oc.write(rotation, "rotation", null);
oc.write(directionType, "directionType", Direction.None);
oc.write(path, "path", null);
oc.write(spatial, "spatial", null);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule in = im.getCapsule(this);
lookAt = (Vector3f) in.readSavable("lookAt", null);
upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
rotation = (Quaternion) in.readSavable("rotation", null);
directionType = in.readEnum("directionType", Direction.class, Direction.None);
path = (MotionPath) in.readSavable("path", null);
spatial = (Spatial) in.readSavable("spatial", 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, upVector);
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, upVector);
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
*/
@Override
public Control cloneForSpatial(Spatial spatial) {
MotionEvent control = new MotionEvent();
control.setPath(path);
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
return control;
}
@Override
public Object jmeClone() {
MotionEvent control = new MotionEvent();
control.path = path;
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
control.spatial = spatial;
return control;
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial);
}
@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) {
this.currentWayPoint = currentWayPoint;
}
/**
* Returns the direction the spatial is moving.
* @return
*/
public Vector3f getDirection() {
return direction;
}
/**
* Sets the direction of the spatial, using the Y axis as the up vector.
* Use MotionEvent#setDirection((Vector3f direction,Vector3f upVector) if
* you want a custum up vector.
* This method is used by the motion path.
* @param direction
*/
public void setDirection(Vector3f direction) {
setDirection(direction, Vector3f.UNIT_Y);
}
/**
* Sets the direction of the spatial with the given up vector.
* This method is used by the motion path.
* @param direction
* @param upVector the up vector to consider for this direction.
*/
public void setDirection(Vector3f direction,Vector3f upVector) {
this.direction.set(direction);
this.upVector.set(upVector);
}
/**
* 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;
}
/**
* Return 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;
}
}
/*
* Copyright (c) 2009-2016 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.AnimationUtils;
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.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.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
* A MotionEvent is a control over the spatial that manages the position and direction of the spatial while following a motion Path.
*
* You must first create a MotionPath and then create a MotionEvent to associate a spatial and the path.
*
* @author Nehon
*/
public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable {
protected Spatial spatial;
protected int currentWayPoint;
protected float currentValue;
protected Vector3f direction = new Vector3f();
protected Vector3f lookAt = null;
protected Vector3f upVector = Vector3f.UNIT_Y;
protected Quaternion rotation = null;
protected Direction directionType = Direction.None;
protected MotionPath path;
private boolean isControl = true;
private int travelDirection = 1;
/**
* 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 stays 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 addition of a rotation.
* You need to use the setRotation method 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 MotionEvent,
* when using this constructor don't forget to assign spatial and path.
*/
public MotionEvent() {
super();
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path) {
super();
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, LoopMode loopMode) {
super();
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 MotionEvent(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
this.loopMode = loopMode;
}
public void update(float tpf) {
if (isControl) {
internalUpdate(tpf);
}
}
@Override
public void internalUpdate(float tpf) {
if (playState == PlayState.Playing) {
time = time + (tpf * speed);
if (loopMode == LoopMode.Loop && time < 0) {
time = initialDuration;
}
if ((time >= initialDuration || time < 0) && loopMode == LoopMode.DontLoop) {
if (time >= initialDuration) {
path.triggerWayPointReach(path.getNbWayPoints() - 1, this);
}
stop();
} else {
time = AnimationUtils.clampWrapTime(time, initialDuration, loopMode);
if(time<0){
speed = - speed;
time = - time;
}
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, tpf);
computeTargetDirection();
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(lookAt, "lookAt", null);
oc.write(upVector, "upVector", Vector3f.UNIT_Y);
oc.write(rotation, "rotation", null);
oc.write(directionType, "directionType", Direction.None);
oc.write(path, "path", null);
oc.write(spatial, "spatial", null);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule in = im.getCapsule(this);
lookAt = (Vector3f) in.readSavable("lookAt", null);
upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
rotation = (Quaternion) in.readSavable("rotation", null);
directionType = in.readEnum("directionType", Direction.class, Direction.None);
path = (MotionPath) in.readSavable("path", null);
spatial = (Spatial) in.readSavable("spatial", 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, upVector);
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, upVector);
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
*/
@Override
public Control cloneForSpatial(Spatial spatial) {
MotionEvent control = new MotionEvent();
control.setPath(path);
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
return control;
}
@Override
public Object jmeClone() {
MotionEvent control = new MotionEvent();
control.path = path;
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
control.spatial = spatial;
return control;
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial);
}
@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) {
this.currentWayPoint = currentWayPoint;
}
/**
* Returns the direction the spatial is moving.
* @return
*/
public Vector3f getDirection() {
return direction;
}
/**
* Sets the direction of the spatial, using the Y axis as the up vector.
* Use MotionEvent#setDirection((Vector3f direction,Vector3f upVector) if
* you want a custum up vector.
* This method is used by the motion path.
* @param direction
*/
public void setDirection(Vector3f direction) {
setDirection(direction, Vector3f.UNIT_Y);
}
/**
* Sets the direction of the spatial with the given up vector.
* This method is used by the motion path.
* @param direction
* @param upVector the up vector to consider for this direction.
*/
public void setDirection(Vector3f direction,Vector3f upVector) {
this.direction.set(direction);
this.upVector.set(upVector);
}
/**
* 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;
}
/**
* Return 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;
}
}

@ -1,229 +1,230 @@
/*
* 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.audio.AudioNode;
import com.jme3.audio.AudioSource;
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 SoundEvent 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 audio file (ie : "Sounds/mySound.wav")
*/
public SoundEvent(String path) {
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
*/
public SoundEvent(String path, boolean stream) {
this(path);
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, boolean stream, float initialDuration) {
super(initialDuration);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, LoopMode loopMode) {
super(loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, float initialDuration) {
super(initialDuration);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, LoopMode loopMode) {
super(loopMode);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
}
/**
* creates a sound event
* used for serialization
*/
public SoundEvent() {
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
audioNode = new AudioNode(app.getAssetManager(), path, stream);
audioNode.setPositional(false);
setLoopMode(loopMode);
}
@Override
public void setTime(float time) {
super.setTime(time);
//can occur on rewind
if (time < 0f) {
stop();
}else{
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() == AudioSource.Status.Stopped) {
stop();
}
}
/**
* Returns the underlying audio 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);
}
}
/*
* 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.audio.AudioNode;
import com.jme3.audio.AudioSource;
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 SoundEvent 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 audio file (ie : "Sounds/mySound.wav")
*/
public SoundEvent(String path) {
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
*/
public SoundEvent(String path, boolean stream) {
this(path);
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, boolean stream, float initialDuration) {
super(initialDuration);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, LoopMode loopMode) {
super(loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, float initialDuration) {
super(initialDuration);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, LoopMode loopMode) {
super(loopMode);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
}
/**
* creates a sound event
* used for serialization
*/
public SoundEvent() {
super();
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
audioNode = new AudioNode(app.getAssetManager(), path, stream);
audioNode.setPositional(false);
setLoopMode(loopMode);
}
@Override
public void setTime(float time) {
super.setTime(time);
//can occur on rewind
if (time < 0f) {
stop();
}else{
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() == AudioSource.Status.Stopped) {
stop();
}
}
/**
* Returns the underlying audio 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);
}
}

@ -1,122 +1,123 @@
/*
* 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.scene;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.renderer.Camera;
import com.jme3.scene.control.CameraControl;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.util.clone.Cloner;
import java.io.IOException;
/**
* <code>CameraNode</code> simply uses {@link CameraControl} to implement
* linking of camera and node data.
*
* @author Tim8Dev
*/
public class CameraNode extends Node {
private CameraControl camControl;
/**
* Serialization only. Do not use.
*/
public CameraNode() {
}
public CameraNode(String name, Camera camera) {
this(name, new CameraControl(camera));
}
public CameraNode(String name, CameraControl control) {
super(name);
addControl(control);
camControl = control;
}
public void setEnabled(boolean enabled) {
camControl.setEnabled(enabled);
}
public boolean isEnabled() {
return camControl.isEnabled();
}
public void setControlDir(ControlDirection controlDir) {
camControl.setControlDir(controlDir);
}
public void setCamera(Camera camera) {
camControl.setCamera(camera);
}
public ControlDirection getControlDir() {
return camControl.getControlDir();
}
public Camera getCamera() {
return camControl.getCamera();
}
// @Override
// public void lookAt(Vector3f position, Vector3f upVector) {
// this.lookAt(position, upVector);
// camControl.getCamera().lookAt(position, upVector);
// }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);
// A change in behavior... I think previously CameraNode was probably
// not really cloneable... or at least its camControl would be pointing
// to the wrong control. -pspeed
this.camControl = cloner.clone(camControl);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
camControl = (CameraControl)im.getCapsule(this).readSavable("camControl", null);
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
ex.getCapsule(this).write(camControl, "camControl", null);
}
}
/*
* 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.scene;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.renderer.Camera;
import com.jme3.scene.control.CameraControl;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.util.clone.Cloner;
import java.io.IOException;
/**
* <code>CameraNode</code> simply uses {@link CameraControl} to implement
* linking of camera and node data.
*
* @author Tim8Dev
*/
public class CameraNode extends Node {
private CameraControl camControl;
/**
* Serialization only. Do not use.
*/
public CameraNode() {
super();
}
public CameraNode(String name, Camera camera) {
this(name, new CameraControl(camera));
}
public CameraNode(String name, CameraControl control) {
super(name);
addControl(control);
camControl = control;
}
public void setEnabled(boolean enabled) {
camControl.setEnabled(enabled);
}
public boolean isEnabled() {
return camControl.isEnabled();
}
public void setControlDir(ControlDirection controlDir) {
camControl.setControlDir(controlDir);
}
public void setCamera(Camera camera) {
camControl.setCamera(camera);
}
public ControlDirection getControlDir() {
return camControl.getControlDir();
}
public Camera getCamera() {
return camControl.getCamera();
}
// @Override
// public void lookAt(Vector3f position, Vector3f upVector) {
// this.lookAt(position, upVector);
// camControl.getCamera().lookAt(position, upVector);
// }
/**
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
*/
@Override
public void cloneFields( Cloner cloner, Object original ) {
super.cloneFields(cloner, original);
// A change in behavior... I think previously CameraNode was probably
// not really cloneable... or at least its camControl would be pointing
// to the wrong control. -pspeed
this.camControl = cloner.clone(camControl);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
camControl = (CameraControl)im.getCapsule(this).readSavable("camControl", null);
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
ex.getCapsule(this).write(camControl, "camControl", null);
}
}

Loading…
Cancel
Save