Clément Espeute пре 2 месеци
родитељ
комит
f68407d345
2 измењених фајлова са 121 додато и 26 уклоњено
  1. 17 0
      hide/view/FXEditor.hx
  2. 104 26
      hrt/prefab/fx/FX.hx

+ 17 - 0
hide/view/FXEditor.hx

@@ -631,6 +631,22 @@ class FXEditor extends hide.view.FileView {
 
 
 		pauseButton = tools.addToggle("pause", "pause", "Pause animation", function(v) {}, false, "play");
+		var loopButton = tools.addToggle("loop", "retweet", "Loop animation", function(v) {
+			var fxAnim = sceneEditor.root3d.find((f) -> Std.downcast(f, hrt.prefab.fx.FX.FXAnimation));
+
+			@:privateAccess
+			if (fxAnim != null) {
+				fxAnim.loop = v;
+				fxAnim.reset();
+				if (!fxAnim.loop) {
+					fxAnim.playState = End;
+				} else {
+					if (fxAnim.playState == End) {
+						fxAnim.playState = Loop;
+					}
+				}
+			}
+		}, false);
 		tools.addRange("Speed", function(v) {
 			scene.speed = v;
 		}, scene.speed);
@@ -1748,6 +1764,7 @@ class FXEditor extends hide.view.FileView {
 			@:privateAccess if (fx.parentFX != null)
 				continue;
 			fx.setTime(currentTime - fx.startDelay);
+			currentTime = fx.localTime + fx.startDelay;
 		}
 
 		// Fix anim events :

+ 104 - 26
hrt/prefab/fx/FX.hx

@@ -6,7 +6,11 @@ import hrt.prefab.fx.BaseFX.ObjectAnimation;
 import hrt.prefab.fx.BaseFX.ShaderAnimation;
 import hrt.prefab.fx.Event;
 
-
+enum FXPlayState {
+	Start;
+	Loop;
+	End;
+}
 @:allow(hrt.prefab.fx.FX)
 class FXAnimation extends h3d.scene.Object {
 	public static var defaultCullingDistance = 0.0;
@@ -15,9 +19,17 @@ class FXAnimation extends h3d.scene.Object {
 	public var playSpeed : Float = 0;
 	public var localTime : Float = 0.0;
 	public var startDelay : Float = 0.0;
-	public var loop : Bool = false;
+	public var loop(default, set) : Bool = false;
+	public var loopStart: Float = -1;
+	public var loopEnd: Float = -1;
 	public var duration : Float;
 
+	function set_loop(v: Bool) {
+		loop = v;
+		initLoop();
+		return loop;
+	}
+
 
 		/** Enable automatic culling based on `cullingRadius` and `cullingDistance`. Will override `culled` on every sync. **/
 	public var autoCull(default, set) = true;
@@ -33,12 +45,15 @@ class FXAnimation extends h3d.scene.Object {
 	public var effects : Array<hrt.prefab.rfx.RendererFX>;
 	public var shaderTargets : Array<hrt.prefab.fx.ShaderTarget.ShaderTargetObj>;
 
+	public var subFXs : Array<FXAnimation> = [];
+
 	var evaluator : Evaluator;
 	var parentFX : FXAnimation;
 	var random : hxd.Rand;
 	var prevTime = -1.0;
 	var randSeed : Int;
 	var firstSync = true;
+	var playState : FXPlayState = End;
 
 	public function new(?parent) {
 		super(parent);
@@ -59,6 +74,7 @@ class FXAnimation extends h3d.scene.Object {
 			shaderTarget.applyShaderTarget(def, shaderTarget.target);
 		}
 
+		initSubFXs(root);
 		initObjAnimations(root);
 		initEmitters(root);
 		updateCustomAnims(root);
@@ -70,6 +86,8 @@ class FXAnimation extends h3d.scene.Object {
 		trails = findAll((p) -> Std.downcast(p, hrt.prefab.l3d.Trails.TrailObj));
 		setParameters(def.parameters);
 
+		initLoop();
+
 		for (p in def.flatten(hrt.prefab.rfx.RendererFX)) {
 			var rfx : hrt.prefab.rfx.RendererFX = cast p;
 			if (@:privateAccess rfx.instance == null)
@@ -79,12 +97,45 @@ class FXAnimation extends h3d.scene.Object {
 				this.effects = [];
 			this.effects.push(rfx);
 		}
+
+		resetSelf();
+	}
+
+	public function initSubFXs(root: PrefabElement) {
+		subFXs = [];
+		for (fx in root.findAll(SubFX)) {
+			var anim = Std.downcast(fx.refInstance?.findFirstLocal3d(), FXAnimation);
+			subFXs.push(anim);
+		}
+	}
+
+	public function initLoop() {
+		loopStart = 0.0;
+		loopEnd = duration;
+
+		if (events == null)
+			return;
+
+		for (event in events) {
+			if (event.evt.getEventPrefab().getRoot().findFirstLocal3d() != this)
+				continue;
+			var nameLower = event.evt.name.toLowerCase();
+			if (nameLower == "loop") {
+				loopStart = event.evt.time;
+				var duration = event.evt.getDuration();
+				if (duration > 0) {
+					loopEnd = loopStart + duration;
+				}
+			}
+			if (nameLower == "end") {
+				loopEnd = event.evt.time;
+			}
+		}
 	}
 
 	public function reset() {
-		firstSync = true;
-		prevTime = -1.0;
-		localTime = 0;
+		resetSelf();
+
 		if(parentFX == null) {
 			for(c in findAll(o -> Std.downcast(o, FXAnimation))) {
 				if(c != this)
@@ -93,6 +144,18 @@ class FXAnimation extends h3d.scene.Object {
 		}
 	}
 
+	function resetSelf() {
+		firstSync = true;
+		prevTime = -1.0;
+		localTime = 0;
+
+		if (loop) {
+			playState = Start;
+		} else {
+			playState = End;
+		}
+	}
+
 	public function updateCustomAnims(root : Prefab) {
 		if (customAnims == null)
 			customAnims = [];
@@ -186,20 +249,12 @@ class FXAnimation extends h3d.scene.Object {
 
 		var needIncrement = false;
 		var curTime = localTime;
+
 		if(playSpeed > 0 || firstSync) {
 			// This is done in syncRec() to make sure time and events are updated regarless of culling state,
 			// so we restore FX in correct state when unculled
-			if(parentFX != null) {
-				var t = hxd.Math.max(0, parentFX.localTime - startDelay);
-				if (loop) {
-					t = (t % duration);
-				}
-				setTime(t, fullSync);
-			}
-			else {
-				setTime(curTime, fullSync);
-				needIncrement = true;
-			}
+			if (parentFX == null)
+				setTime(curTime + ctx.elapsedTime * playSpeed, fullSync);
 		}
 
 		for (t in trails) {
@@ -208,15 +263,10 @@ class FXAnimation extends h3d.scene.Object {
 
 		if(fullSync)
 			super.syncRec(ctx);
-		if (needIncrement) {
-			localTime += ctx.elapsedTime * playSpeed;
-			if( loop && duration > 0 ) {
-				localTime = (localTime % duration);
-			}
-			if( duration > 0 && curTime < duration && localTime >= duration) {
-				localTime = duration;
-				finishedPlaying = true;
-			}
+
+		if(playState == End && duration > 0 && curTime < duration && localTime >= duration) {
+			localTime = duration;
+			finishedPlaying = true;
 		}
 
 		if(finishedPlaying) {
@@ -233,10 +283,30 @@ class FXAnimation extends h3d.scene.Object {
 	static var tempMat = new h3d.Matrix();
 	static var tempTransform = new h3d.Matrix();
 	static var tempVec = new h3d.Vector4();
-	public function setTime( time : Float, fullSync=true ) {
+	public function setTime( time : Float, fullSync=true) {
+		time = hxd.Math.max(0, time - startDelay);
 		var dt = time - this.prevTime;
+
+		if (playState == Start) {
+			if (time >= loopStart) {
+				playState = Loop;
+			}
+		}
+
+		if (playState == Loop) {
+			time = ((time - loopStart) % (loopEnd - loopStart)) + loopStart;
+		}
+
 		this.localTime = time;
 
+		for (subFX in subFXs) {
+			if (subFX.loop) {
+				subFX.setTime(subFX.localTime + subFX.startDelay + dt, fullSync);
+			} else {
+				subFX.setTime(time);
+			}
+		}
+
 		if(fullSync) {
 			if(objAnims != null) {
 				for(anim in objAnims) {
@@ -383,6 +453,14 @@ class FXAnimation extends h3d.scene.Object {
 		this.prevTime = localTime;
 	}
 
+	public function stop(instant: Bool = false, onEnd: () -> Void) {
+		this.onEnd = onEnd;
+		playState = End;
+		if (instant == true) {
+			setTime(duration, false);
+		}
+	}
+
 	function initEvents(elt: PrefabElement, ?out : Array<Event.EventInstance> ) : Array<Event.EventInstance> {
 		if (elt == null || @:privateAccess !elt.shouldBeInstanciated() || elt.findFirstLocal3d() == null)
 			return out;