Changed the way EffectTrack and AudioTrack are serialized.
EffectTrack and AudioTrack can now porperly update their reference to the Spatial they are using upon loading. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9634 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
ae3cc96caa
commit
3bd77d3048
@ -43,6 +43,7 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>AnimControl</code> is a Spatial control that allows manipulation
|
* <code>AnimControl</code> is a Spatial control that allows manipulation
|
||||||
@ -118,9 +119,12 @@ public final class AnimControl extends AbstractControl implements Cloneable {
|
|||||||
clone.skeleton = new Skeleton(skeleton);
|
clone.skeleton = new Skeleton(skeleton);
|
||||||
}
|
}
|
||||||
|
|
||||||
// animationMap is reference-copied, animation data should be shared
|
// animationMap is cloned, but only ClonableTracks will be cloned as they need a reference to a cloned spatial
|
||||||
// to reduce memory usage.
|
clone.animationMap = new HashMap<String, Animation>();
|
||||||
|
for (Entry<String, Animation> animEntry : animationMap.entrySet()) {
|
||||||
|
clone.animationMap.put(animEntry.getKey(), animEntry.getValue().cloneForSpatial(spatial));
|
||||||
|
}
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
} catch (CloneNotSupportedException ex) {
|
} catch (CloneNotSupportedException ex) {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.util.SafeArrayList;
|
import com.jme3.util.SafeArrayList;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -42,27 +43,26 @@ import java.io.IOException;
|
|||||||
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
|
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class Animation implements Savable, Cloneable {
|
public class Animation implements Savable, Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the animation.
|
* The name of the animation.
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the animation.
|
* The length of the animation.
|
||||||
*/
|
*/
|
||||||
private float length;
|
private float length;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tracks of the animation.
|
* The tracks of the animation.
|
||||||
*/
|
*/
|
||||||
private SafeArrayList<Track> tracks = new SafeArrayList<Track>(Track.class);
|
private SafeArrayList<Track> tracks = new SafeArrayList<Track>(Track.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialization-only. Do not use.
|
* Serialization-only. Do not use.
|
||||||
*/
|
*/
|
||||||
public Animation() {}
|
public Animation() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>Animation</code> with the given name and length.
|
* Creates a new <code>Animation</code> with the given name and length.
|
||||||
*
|
*
|
||||||
@ -73,24 +73,24 @@ public class Animation implements Savable, Cloneable {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the bone animation
|
* The name of the bone animation
|
||||||
* @return name of the bone animation
|
* @return name of the bone animation
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the length in seconds of this animation
|
* Returns the length in seconds of this animation
|
||||||
*
|
*
|
||||||
* @return the length in seconds of this animation
|
* @return the length in seconds of this animation
|
||||||
*/
|
*/
|
||||||
public float getLength() {
|
public float getLength() {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method sets the current time of the animation.
|
* This method sets the current time of the animation.
|
||||||
* This method behaves differently for every known track type.
|
* This method behaves differently for every known track type.
|
||||||
@ -102,58 +102,61 @@ public class Animation implements Savable, Cloneable {
|
|||||||
* @param channel the animation channel
|
* @param channel the animation channel
|
||||||
*/
|
*/
|
||||||
void setTime(float time, float blendAmount, AnimControl control, AnimChannel channel, TempVars vars) {
|
void setTime(float time, float blendAmount, AnimControl control, AnimChannel channel, TempVars vars) {
|
||||||
if (tracks == null)
|
if (tracks == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Track track : tracks) {
|
for (Track track : tracks) {
|
||||||
track.setTime(time, blendAmount, control, channel, vars);
|
track.setTime(time, blendAmount, control, channel, vars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link Track}s to be used by this animation.
|
* Set the {@link Track}s to be used by this animation.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @param tracks The tracks to set.
|
* @param tracks The tracks to set.
|
||||||
*/
|
*/
|
||||||
public void setTracks(Track[] tracksArray){
|
public void setTracks(Track[] tracksArray) {
|
||||||
for (Track track : tracksArray) {
|
for (Track track : tracksArray) {
|
||||||
tracks.add(track);
|
tracks.add(track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a track to this animation
|
* Adds a track to this animation
|
||||||
* @param track the track to add
|
* @param track the track to add
|
||||||
*/
|
*/
|
||||||
public void addTrack(Track track){
|
public void addTrack(Track track) {
|
||||||
tracks.add(track);
|
tracks.add(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* removes a track from this animation
|
* removes a track from this animation
|
||||||
* @param track the track to remove
|
* @param track the track to remove
|
||||||
*/
|
*/
|
||||||
public void removeTrack(Track track){
|
public void removeTrack(Track track) {
|
||||||
tracks.remove(track);
|
tracks.remove(track);
|
||||||
}
|
if (track instanceof ClonableTrack) {
|
||||||
|
((ClonableTrack) track).cleanUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the tracks set in {@link #setTracks(com.jme3.animation.Track[]) }.
|
* Returns the tracks set in {@link #setTracks(com.jme3.animation.Track[]) }.
|
||||||
*
|
*
|
||||||
* @return the tracks set previously
|
* @return the tracks set previously
|
||||||
*/
|
*/
|
||||||
public Track[] getTracks() {
|
public Track[] getTracks() {
|
||||||
return tracks.getArray();
|
return tracks.getArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method creates a clone of the current object.
|
* This method creates a clone of the current object.
|
||||||
* @return a clone of the current object
|
* @return a clone of the current object
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Animation clone() {
|
public Animation clone() {
|
||||||
try {
|
try {
|
||||||
Animation result = (Animation) super.clone();
|
Animation result = (Animation) super.clone();
|
||||||
result.tracks = new SafeArrayList<Track>(Track.class);
|
result.tracks = new SafeArrayList<Track>(Track.class);
|
||||||
@ -166,12 +169,34 @@ public class Animation implements Savable, Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param spat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Animation cloneForSpatial(Spatial spat) {
|
||||||
|
try {
|
||||||
|
Animation result = (Animation) super.clone();
|
||||||
|
result.tracks = new SafeArrayList<Track>(Track.class);
|
||||||
|
for (Track track : tracks) {
|
||||||
|
if (track instanceof ClonableTrack) {
|
||||||
|
result.tracks.add(((ClonableTrack) track).cloneForSpatial(spat));
|
||||||
|
} else {
|
||||||
|
result.tracks.add(track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']';
|
return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
OutputCapsule out = ex.getCapsule(this);
|
OutputCapsule out = ex.getCapsule(this);
|
||||||
out.write(name, "name", null);
|
out.write(name, "name", null);
|
||||||
@ -184,7 +209,7 @@ public class Animation implements Savable, Cloneable {
|
|||||||
InputCapsule in = im.getCapsule(this);
|
InputCapsule in = im.getCapsule(this);
|
||||||
name = in.readString("name", null);
|
name = in.readString("name", null);
|
||||||
length = in.readFloat("length", 0f);
|
length = in.readFloat("length", 0f);
|
||||||
|
|
||||||
Savable[] arr = in.readSavableArray("tracks", null);
|
Savable[] arr = in.readSavableArray("tracks", null);
|
||||||
if (arr != null) {
|
if (arr != null) {
|
||||||
// NOTE: Backward compat only .. Some animations have no
|
// NOTE: Backward compat only .. Some animations have no
|
||||||
@ -193,8 +218,8 @@ public class Animation implements Savable, Cloneable {
|
|||||||
// its only appropriate that the check is made here as well.
|
// its only appropriate that the check is made here as well.
|
||||||
tracks = new SafeArrayList<Track>(Track.class);
|
tracks = new SafeArrayList<Track>(Track.class);
|
||||||
for (Savable savable : arr) {
|
for (Savable savable : arr) {
|
||||||
tracks.add((Track)savable);
|
tracks.add((Track) savable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,12 @@ import com.jme3.export.InputCapsule;
|
|||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AudioTrack is a track to add to an existing animation, to paly a sound during an animations
|
* AudioTrack is a track to add to an existing animation, to paly a sound during an animations
|
||||||
@ -55,8 +59,9 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
public class AudioTrack implements Track {
|
public class AudioTrack implements ClonableTrack {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AudioTrack.class.getName());
|
||||||
private AudioNode audio;
|
private AudioNode audio;
|
||||||
private float startOffset = 0;
|
private float startOffset = 0;
|
||||||
private float length = 0;
|
private float length = 0;
|
||||||
@ -89,6 +94,7 @@ public class AudioTrack implements Track {
|
|||||||
public AudioTrack(AudioNode audio, float length) {
|
public AudioTrack(AudioNode audio, float length) {
|
||||||
this.audio = audio;
|
this.audio = audio;
|
||||||
this.length = length;
|
this.length = length;
|
||||||
|
setUserData(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,6 +147,80 @@ public class AudioTrack implements Track {
|
|||||||
return new AudioTrack(audio, length, startOffset);
|
return new AudioTrack(audio, length, startOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clone the Track and search for the cloned counterpart of the original audio node in the given cloned spatial.
|
||||||
|
* The spatial is assumed to be the Spatial holding the AnimControl controling the animation using this Track.
|
||||||
|
* @param spatial the Spatial holding the AnimControl
|
||||||
|
* @return the cloned Track with proper reference
|
||||||
|
*/
|
||||||
|
public Track cloneForSpatial(Spatial spatial) {
|
||||||
|
AudioTrack audioTrack = new AudioTrack();
|
||||||
|
audioTrack.length = this.length;
|
||||||
|
audioTrack.startOffset = this.startOffset;
|
||||||
|
|
||||||
|
//searching for the newly cloned AudioNode
|
||||||
|
audioTrack.audio = findAudio(spatial);
|
||||||
|
if (audioTrack.audio == null) {
|
||||||
|
logger.log(Level.WARNING, "{0} was not found in {1} or is not bound to this track", new Object[]{audio.getName(), spatial.getName()});
|
||||||
|
audioTrack.audio = audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
//setting user data on the new AudioNode and marking it with a reference to the cloned Track.
|
||||||
|
setUserData(audioTrack);
|
||||||
|
|
||||||
|
return audioTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recursive function responsible for finding the newly cloned AudioNode
|
||||||
|
* @param spat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private AudioNode findAudio(Spatial spat) {
|
||||||
|
if (spat instanceof AudioNode) {
|
||||||
|
//spat is an AudioNode
|
||||||
|
AudioNode em = (AudioNode) spat;
|
||||||
|
//getting the UserData TrackInfo so check if it should be attached to this Track
|
||||||
|
TrackInfo t = (TrackInfo) em.getUserData("TrackInfo");
|
||||||
|
if (t != null && t.getTracks().contains(this)) {
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
} else if (spat instanceof Node) {
|
||||||
|
for (Spatial child : ((Node) spat).getChildren()) {
|
||||||
|
AudioNode em = findAudio(child);
|
||||||
|
if (em != null) {
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUserData(AudioTrack audioTrack) {
|
||||||
|
//fetching the UserData TrackInfo.
|
||||||
|
TrackInfo data = (TrackInfo) audioTrack.audio.getUserData("TrackInfo");
|
||||||
|
|
||||||
|
//if it does not exist, we create it and attach it to the AudioNode.
|
||||||
|
if (data == null) {
|
||||||
|
data = new TrackInfo();
|
||||||
|
audioTrack.audio.setUserData("TrackInfo", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//adding the given Track to the TrackInfo.
|
||||||
|
data.addTrack(audioTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanUp() {
|
||||||
|
TrackInfo t = (TrackInfo) audio.getUserData("TrackInfo");
|
||||||
|
t.getTracks().remove(this);
|
||||||
|
if(!t.getTracks().isEmpty()){
|
||||||
|
audio.setUserData("TrackInfo", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return the audio node used by this track
|
* @return the audio node used by this track
|
||||||
@ -154,7 +234,12 @@ public class AudioTrack implements Track {
|
|||||||
* @param audio
|
* @param audio
|
||||||
*/
|
*/
|
||||||
public void setAudio(AudioNode audio) {
|
public void setAudio(AudioNode audio) {
|
||||||
|
if (this.audio != null) {
|
||||||
|
TrackInfo data = (TrackInfo) audio.getUserData("TrackInfo");
|
||||||
|
data.getTracks().remove(this);
|
||||||
|
}
|
||||||
this.audio = audio;
|
this.audio = audio;
|
||||||
|
setUserData(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
40
engine/src/core/com/jme3/animation/ClonableTrack.java
Normal file
40
engine/src/core/com/jme3/animation/ClonableTrack.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.animation;
|
||||||
|
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that allow to clone a Track for a given Spatial.
|
||||||
|
* The spatial fed to the method is the Spatial holding the AnimControl controling the Animation using this track.
|
||||||
|
*
|
||||||
|
* Implement this interface only if you make your own Savable Track and that the track has a direct reference to a Spatial in the scene graph.
|
||||||
|
* This Spatial is assumed to be a child of the spatial holding the AnimControl.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public interface ClonableTrack extends Track {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to clone the track for a given Spatial.
|
||||||
|
* The spatial fed to the method is the Spatial holding the AnimControl controling the Animation using this track.
|
||||||
|
* This method will be called during the loading process of a j3o model by the assetManager.
|
||||||
|
* The assetManager keeps the original model in cache and returns a clone of the model.
|
||||||
|
*
|
||||||
|
* This method prupose is to find the cloned reference of the original spatial which it refers to in the cloned model.
|
||||||
|
*
|
||||||
|
* See EffectTrack for a proper implementation.
|
||||||
|
*
|
||||||
|
* @param spatial the spatial holding the AnimControl
|
||||||
|
* @return the cloned Track
|
||||||
|
*/
|
||||||
|
public Track cloneForSpatial(Spatial spatial);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method responsible of cleaning UserData on referenced Spatials when the Track is deleted
|
||||||
|
*/
|
||||||
|
public void cleanUp();
|
||||||
|
}
|
@ -38,12 +38,15 @@ import com.jme3.export.JmeImporter;
|
|||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.Spatial.CullHint;
|
import com.jme3.scene.Spatial.CullHint;
|
||||||
import com.jme3.scene.control.AbstractControl;
|
import com.jme3.scene.control.AbstractControl;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EffectTrack is a track to add to an existing animation, to emmit particles during animations
|
* EffectTrack is a track to add to an existing animation, to emmit particles during animations
|
||||||
@ -62,8 +65,9 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
public class EffectTrack implements Track {
|
public class EffectTrack implements ClonableTrack {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(EffectTrack.class.getName());
|
||||||
private ParticleEmitter emitter;
|
private ParticleEmitter emitter;
|
||||||
private float startOffset = 0;
|
private float startOffset = 0;
|
||||||
private float particlesPerSeconds = 0;
|
private float particlesPerSeconds = 0;
|
||||||
@ -71,10 +75,9 @@ public class EffectTrack implements Track {
|
|||||||
private boolean emitted = false;
|
private boolean emitted = false;
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
private boolean stopRequested = false;
|
private boolean stopRequested = false;
|
||||||
|
|
||||||
//control responsible for disable and cull the emitter once all particles are gone
|
//control responsible for disable and cull the emitter once all particles are gone
|
||||||
private AbstractControl killParticles = new AbstractControl() {
|
private AbstractControl killParticles = new AbstractControl() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
if (emitter.getNumVisibleParticles() == 0) {
|
if (emitter.getNumVisibleParticles() == 0) {
|
||||||
@ -84,29 +87,26 @@ public class EffectTrack implements Track {
|
|||||||
stopRequested = false;
|
stopRequested = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//Anim listener that stops the Emmitter when the animation is finished or changed.
|
//Anim listener that stops the Emmitter when the animation is finished or changed.
|
||||||
private class OnEndListener implements AnimEventListener {
|
private class OnEndListener implements AnimEventListener {
|
||||||
|
|
||||||
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
|
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
|
||||||
if(!stopRequested){
|
stop();
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
|
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
|
||||||
if(!stopRequested){
|
stop();
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +128,9 @@ public class EffectTrack implements Track {
|
|||||||
//setting the emmitter to not emmit.
|
//setting the emmitter to not emmit.
|
||||||
this.emitter.setParticlesPerSec(0);
|
this.emitter.setParticlesPerSec(0);
|
||||||
this.length = length;
|
this.length = length;
|
||||||
|
//Marking the emitter with a reference to this track for further use in deserialization.
|
||||||
|
setUserData(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,14 +158,15 @@ public class EffectTrack implements Track {
|
|||||||
//checking fo time to trigger the effect
|
//checking fo time to trigger the effect
|
||||||
if (!emitted && time >= startOffset) {
|
if (!emitted && time >= startOffset) {
|
||||||
emitted = true;
|
emitted = true;
|
||||||
stopRequested = false;
|
|
||||||
emitter.setCullHint(CullHint.Dynamic);
|
emitter.setCullHint(CullHint.Dynamic);
|
||||||
emitter.setEnabled(true);
|
emitter.setEnabled(true);
|
||||||
//if the emitter has 0 particles per seconds emmit all particles in one shot
|
//if the emitter has 0 particles per seconds emmit all particles in one shot
|
||||||
if (particlesPerSeconds == 0) {
|
if (particlesPerSeconds == 0) {
|
||||||
emitter.emitAllParticles();
|
emitter.emitAllParticles();
|
||||||
emitter.addControl(killParticles);
|
if (!stopRequested) {
|
||||||
stopRequested = true;
|
emitter.addControl(killParticles);
|
||||||
|
stopRequested = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//else reset its former particlePerSec value to let it emmit.
|
//else reset its former particlePerSec value to let it emmit.
|
||||||
emitter.setParticlesPerSec(particlesPerSeconds);
|
emitter.setParticlesPerSec(particlesPerSeconds);
|
||||||
@ -175,10 +178,15 @@ public class EffectTrack implements Track {
|
|||||||
private void stop() {
|
private void stop() {
|
||||||
emitter.setParticlesPerSec(0);
|
emitter.setParticlesPerSec(0);
|
||||||
emitted = false;
|
emitted = false;
|
||||||
emitter.addControl(killParticles);
|
if (!stopRequested) {
|
||||||
stopRequested = true;
|
emitter.addControl(killParticles);
|
||||||
|
stopRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retruns the length of the track
|
* Retruns the length of the track
|
||||||
* @return length of the track
|
* @return length of the track
|
||||||
@ -194,7 +202,67 @@ public class EffectTrack implements Track {
|
|||||||
@Override
|
@Override
|
||||||
public Track clone() {
|
public Track clone() {
|
||||||
return new EffectTrack(emitter, length, startOffset);
|
return new EffectTrack(emitter, length, startOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clone the Track and search for the cloned counterpart of the original emmitter in the given cloned spatial.
|
||||||
|
* The spatial is assumed to be the Spatial holding the AnimControl controling the animation using this Track.
|
||||||
|
* @param spatial the Spatial holding the AnimControl
|
||||||
|
* @return the cloned Track with proper reference
|
||||||
|
*/
|
||||||
|
public Track cloneForSpatial(Spatial spatial) {
|
||||||
|
EffectTrack effectTrack = new EffectTrack();
|
||||||
|
effectTrack.particlesPerSeconds = this.particlesPerSeconds;
|
||||||
|
effectTrack.length = this.length;
|
||||||
|
effectTrack.startOffset = this.startOffset;
|
||||||
|
|
||||||
|
//searching for the newly cloned ParticleEmitter
|
||||||
|
effectTrack.emitter = findEmitter(spatial);
|
||||||
|
if (effectTrack.emitter == null) {
|
||||||
|
logger.log(Level.WARNING, "{0} was not found in {1} or is not bound to this track", new Object[]{emitter.getName(), spatial.getName()});
|
||||||
|
effectTrack.emitter = emitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//setting user data on the new emmitter and marking it with a reference to the cloned Track.
|
||||||
|
setUserData(effectTrack);
|
||||||
|
effectTrack.emitter.setParticlesPerSec(0);
|
||||||
|
return effectTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recursive function responsible for finding the newly cloned Emitter
|
||||||
|
* @param spat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ParticleEmitter findEmitter(Spatial spat) {
|
||||||
|
if (spat instanceof ParticleEmitter) {
|
||||||
|
//spat is a PArticleEmitter
|
||||||
|
ParticleEmitter em = (ParticleEmitter) spat;
|
||||||
|
//getting the UserData TrackInfo so check if it should be attached to this Track
|
||||||
|
TrackInfo t = (TrackInfo) em.getUserData("TrackInfo");
|
||||||
|
if (t != null && t.getTracks().contains(this)) {
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
} else if (spat instanceof Node) {
|
||||||
|
for (Spatial child : ((Node) spat).getChildren()) {
|
||||||
|
ParticleEmitter em = findEmitter(child);
|
||||||
|
if (em != null) {
|
||||||
|
return em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void cleanUp() {
|
||||||
|
TrackInfo t = (TrackInfo) emitter.getUserData("TrackInfo");
|
||||||
|
t.getTracks().remove(this);
|
||||||
|
if(!t.getTracks().isEmpty()){
|
||||||
|
emitter.setUserData("TrackInfo", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,7 +278,12 @@ public class EffectTrack implements Track {
|
|||||||
* @param emitter
|
* @param emitter
|
||||||
*/
|
*/
|
||||||
public void setEmitter(ParticleEmitter emitter) {
|
public void setEmitter(ParticleEmitter emitter) {
|
||||||
|
if (this.emitter != null) {
|
||||||
|
TrackInfo data = (TrackInfo) emitter.getUserData("TrackInfo");
|
||||||
|
data.getTracks().remove(this);
|
||||||
|
}
|
||||||
this.emitter = emitter;
|
this.emitter = emitter;
|
||||||
|
setUserData(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,6 +301,22 @@ public class EffectTrack implements Track {
|
|||||||
public void setStartOffset(float startOffset) {
|
public void setStartOffset(float startOffset) {
|
||||||
this.startOffset = startOffset;
|
this.startOffset = startOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setUserData(EffectTrack effectTrack) {
|
||||||
|
//fetching the UserData TrackInfo.
|
||||||
|
TrackInfo data = (TrackInfo) effectTrack.emitter.getUserData("TrackInfo");
|
||||||
|
|
||||||
|
//if it does not exist, we create it and attach it to the emitter.
|
||||||
|
if (data == null) {
|
||||||
|
data = new TrackInfo();
|
||||||
|
effectTrack.emitter.setUserData("TrackInfo", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//adding the given Track to the TrackInfo.
|
||||||
|
data.addTrack(effectTrack);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal use only serialization
|
* Internal use only serialization
|
||||||
@ -236,10 +325,16 @@ public class EffectTrack implements Track {
|
|||||||
*/
|
*/
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
OutputCapsule out = ex.getCapsule(this);
|
OutputCapsule out = ex.getCapsule(this);
|
||||||
|
//reseting the particle emission rate on the emitter before saving.
|
||||||
|
emitter.setParticlesPerSec(particlesPerSeconds);
|
||||||
|
//removing eventual unpersisted control off the emitter
|
||||||
|
emitter.removeControl(killParticles);
|
||||||
out.write(emitter, "emitter", null);
|
out.write(emitter, "emitter", null);
|
||||||
|
out.write(particlesPerSeconds, "particlesPerSeconds", 0);
|
||||||
out.write(length, "length", 0);
|
out.write(length, "length", 0);
|
||||||
|
|
||||||
out.write(startOffset, "startOffset", 0);
|
out.write(startOffset, "startOffset", 0);
|
||||||
|
//Setting emission rate to 0 so that this track can go on being used.
|
||||||
|
emitter.setParticlesPerSec(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,8 +344,10 @@ public class EffectTrack implements Track {
|
|||||||
*/
|
*/
|
||||||
public void read(JmeImporter im) throws IOException {
|
public void read(JmeImporter im) throws IOException {
|
||||||
InputCapsule in = im.getCapsule(this);
|
InputCapsule in = im.getCapsule(this);
|
||||||
|
this.particlesPerSeconds = in.readFloat("particlesPerSeconds", 0);
|
||||||
|
//reading the emitter even if the track will then reference its cloned counter part if it's loaded with the assetManager.
|
||||||
|
//This also avoid null pointer exception if the model is not loaded via the AssetManager.
|
||||||
emitter = (ParticleEmitter) in.readSavable("emitter", null);
|
emitter = (ParticleEmitter) in.readSavable("emitter", null);
|
||||||
this.particlesPerSeconds = emitter.getParticlesPerSec();
|
|
||||||
emitter.setParticlesPerSec(0);
|
emitter.setParticlesPerSec(0);
|
||||||
length = in.readFloat("length", length);
|
length = in.readFloat("length", length);
|
||||||
startOffset = in.readFloat("startOffset", 0);
|
startOffset = in.readFloat("startOffset", 0);
|
||||||
|
48
engine/src/core/com/jme3/animation/TrackInfo.java
Normal file
48
engine/src/core/com/jme3/animation/TrackInfo.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.animation;
|
||||||
|
|
||||||
|
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 java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is intended as a UserData added to a Spatial that is referenced by a Track.
|
||||||
|
* (ParticleEmitter for EffectTrack and AudioNode for AudioTrack)
|
||||||
|
* It holds the list of tracks that are directly referencing the Spatial.
|
||||||
|
*
|
||||||
|
* This is used when loading a Track to find the cloned reference of a Spatial in the cloned model returned by the assetManager.
|
||||||
|
*
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public class TrackInfo implements Savable {
|
||||||
|
|
||||||
|
ArrayList<Track> tracks = new ArrayList<Track>();
|
||||||
|
|
||||||
|
public TrackInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
OutputCapsule c = ex.getCapsule(this);
|
||||||
|
c.writeSavableArrayList(tracks, "tracks", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
InputCapsule c = im.getCapsule(this);
|
||||||
|
tracks = c.readSavableArrayList("tracks", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Track> getTracks() {
|
||||||
|
return tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTrack(Track track) {
|
||||||
|
tracks.add(track);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user