Clément Espeute 1 месяц назад
Родитель
Сommit
56d5424a06
3 измененных файлов с 266 добавлено и 217 удалено
  1. 30 76
      hide/view/FXEditor.hx
  2. 236 137
      hrt/prefab/fx/FX.hx
  3. 0 4
      hrt/prefab/fx/SubFX.hx

+ 30 - 76
hide/view/FXEditor.hx

@@ -341,6 +341,7 @@ class FXEditor extends hide.view.FileView {
 
 	var pauseButton : hide.comp.Toolbar.ToolToggle;
 	@:isVar var currentTime(get, set) : Float;
+	var lastTime : Float;
 	var selectMin : Float;
 	var selectMax : Float;
 	var previewMin : Float;
@@ -1744,82 +1745,35 @@ class FXEditor extends hide.view.FileView {
 		if(local3d == null)
 			return;
 
-		var allFx = local3d.findAll(o -> Std.downcast(o, hrt.prefab.fx.FX.FXAnimation));
-
-		if(!pauseButton.isDown()) {
-			currentTime += scene.speed * dt;
-			if(this.curveEditor != null) {
-				this.curveEditor.refreshTimeline(currentTime);
-				this.curveEditor.refreshOverlay(data.duration);
-			}
-			if(currentTime >= previewMax) {
-				currentTime = previewMin;
-
-				for(f in allFx)
-					f.setRandSeed(Std.random(0xFFFFFF));
-			}
-		}
-
-		for(fx in allFx) {
-			@:privateAccess if (fx.parentFX != null)
-				continue;
-			fx.setTime(currentTime - fx.startDelay);
-			currentTime = fx.localTime + fx.startDelay;
-		}
-
-		// Fix anim events :
-		// we force play the first or last frame of the nearset
-		// anim event for each prefab that has anim events in the FX
-		// if we are not in the middle of playing an animation
-		@:privateAccess
-		for (fx in allFx) {
-			var time = fx.localTime;
-
-			if (fx.events == null)
-				continue;
-
-			var closest : Map<h3d.scene.Object, {instance: EventInstance, distance: Float, jumpTo: Float}> = [];
-
-			for (instance in fx.events) {
-				var event = Std.downcast(instance.evt, hrt.prefab.fx.AnimEvent);
-				if (event == null)
-					continue;
-
-				var previous = MapUtils.getOrPut(closest, event.findFirstLocal3d(), {instance: instance, distance: hxd.Math.POSITIVE_INFINITY, jumpTo: 0.0});
-				if (previous.distance == 0)
-					continue;
+		var fx = local3d.find(o -> {
+			var fx = Std.downcast(o, hrt.prefab.fx.FX.FXAnimation);
+			if (fx == null || @:privateAccess fx.parentFX != null)
+				return null;
+			return fx;
+		});
 
-				var firstFrame = event.time;
-				var toFirstFrame = firstFrame - time;
-				if (toFirstFrame >= 0 && toFirstFrame < previous.distance) {
-					previous.instance = instance;
-					previous.distance = toFirstFrame;
-					previous.jumpTo = 0.0001;
-				}
+		if (fx != null) {
+			var hasJumped = currentTime != lastTime ;
 
-				var anim = event.animation != null ? event.shared.loadAnimation(event.animation) : null;
-				var duration = event.duration > 0 ? event.duration : (anim?.getDuration() ?? 0.0);
-				var lastFrame = event.time + duration;
-				var toLastFrame = time - lastFrame;
-				if (toLastFrame >= 0 && toLastFrame < previous.distance) {
-					previous.instance = instance;
-					previous.distance = toLastFrame;
-					previous.jumpTo = duration-0.0001;
+			if(!pauseButton.isDown() || hasJumped) {
+				if (currentTime + scene.speed * dt >= previewMax) {
+					fx.seek(previewMin);
+					fx.setRandSeed(Std.random(0xFFFFFF));
+				} else if (hasJumped) {
+					fx.seek(currentTime + scene.speed * dt);
+				} else {
+					fx.update(scene.speed * dt);
 				}
 
-				// We are currently playing this animation
-				if (toFirstFrame < 0 && toLastFrame < 0) {
-					previous.instance = null;
-					previous.distance = 0;
-					continue;
-				}
+				currentTime = fx.localTime;
+				lastTime = currentTime;
 			}
+		}
 
-			for (obj in closest) {
-				if (obj.instance == null) // can be null if we are in the middle of the animation
-					continue;
-				obj.instance.setTime(obj.jumpTo);
-			}
+
+		if(this.curveEditor != null) {
+			this.curveEditor.refreshTimeline(currentTime);
+			this.curveEditor.refreshOverlay(data.duration);
 		}
 
 		var cam = scene.s3d.camera;
@@ -1852,6 +1806,12 @@ class FXEditor extends hide.view.FileView {
 		return this.currentTime = value;
 	}
 
+	function get_currentTime():Float {
+		if (this.curveEditor != null)
+			return @:privateAccess this.curveEditor.currentTime;
+		return this.currentTime;
+	}
+
 	public function setRenderPropsEditionVisibility(visible : Bool) {
 		var renderPropsEditionEl = this.element?.find('.render-props-edition');
 		// can appen on close
@@ -1865,12 +1825,6 @@ class FXEditor extends hide.view.FileView {
 
 		renderPropsEditionEl.css({ display : 'block' });
 	}
-
-	function get_currentTime():Float {
-		if (this.curveEditor != null)
-			return @:privateAccess this.curveEditor.currentTime;
-		return this.currentTime;
-	}
 }
 
 

+ 236 - 137
hrt/prefab/fx/FX.hx

@@ -51,7 +51,6 @@ class FXAnimation extends h3d.scene.Object {
 	var evaluator : Evaluator;
 	var parentFX : FXAnimation;
 	var random : hxd.Rand;
-	var prevTime = -1.0;
 	var randSeed : Int;
 	var firstSync = true;
 	var playState : FXPlayState = End;
@@ -106,7 +105,9 @@ class FXAnimation extends h3d.scene.Object {
 		subFXs = [];
 		for (fx in root.findAll(SubFX)) {
 			var anim = Std.downcast(fx.refInstance?.findFirstLocal3d(), FXAnimation);
-			subFXs.push(anim);
+			if (anim != null) {
+				subFXs.push(anim);
+			}
 		}
 	}
 
@@ -150,7 +151,6 @@ class FXAnimation extends h3d.scene.Object {
 
 	function resetSelf() {
 		firstSync = true;
-		prevTime = -1.0;
 		localTime = 0;
 
 		if (loop) {
@@ -284,184 +284,283 @@ class FXAnimation extends h3d.scene.Object {
 		ctx.visibleFlag = old;
 	}
 
-	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) {
-		time = hxd.Math.max(0, time - startDelay);
-		var dt = time - this.prevTime;
+	public function seek(time: Float) {
+		setTimeInternal(time, false);
+	}
 
-		if (playState == Start) {
-			if (time >= loopStart) {
-				playState = Loop;
+	public function update(dt: Float) {
+		setTimeInternal(dt, true);
+	}
+
+	static var closest : Map<h3d.scene.Object, {instance: EventInstance, distance: Float, jumpTo: Float}> = [];
+
+	/**
+		If continuous, timeParam is relative to localTime, else it's absolute
+	**/
+	function setTimeInternal(timeParam:Float, continuous:Bool ) {
+		var newTime = continuous ? localTime + timeParam : timeParam;
+
+		if (continuous) {
+			if (playState == Start) {
+				if (newTime >= loopStart) {
+					playState = Loop;
+				}
 			}
-		}
 
-		if (playState == Loop) {
-			time = ((time - loopStart) % (loopEnd - loopStart)) + loopStart;
+			if (playState == Loop) {
+				newTime = ((newTime - loopStart) % (loopEnd - loopStart)) + loopStart;
+			}
+		}
+		else {
+			if (loop) {
+				if (newTime < loopStart) {
+					playState = Start;
+				} else if (newTime >= loopEnd) {
+					playState = End;
+				} else {
+					playState = Loop;
+				}
+			} else {
+				playState = End;
+			}
 		}
 
-		this.localTime = time;
+		var oldTime = localTime;
+		localTime = newTime;
 
 		for (subFX in subFXs) {
-			if (subFX.playState == Loop) {
-				subFX.setTime(subFX.localTime + subFX.startDelay + dt, fullSync);
+			if (continuous) {
+				subFX.update(timeParam);
 			} else {
-				subFX.setTime(time);
+				subFX.seek(newTime);
 			}
 		}
 
-		if(fullSync) {
-			if(objAnims != null) {
-				for(anim in objAnims) {
-					if(anim.scale != null || anim.rotation != null || anim.position != null) {
-						var m = tempMat;
-						if(anim.scale != null) {
-							var scale = evaluator.getVector(anim.scale, time, tempVec);
-							m.initScale(scale.x, scale.y, scale.z);
-						}
-						else
-							m.identity();
+		syncAnims(newTime);
+		syncParticles(timeParam, continuous);
 
-						if(anim.rotation != null) {
-							var rotation = evaluator.getVector(anim.rotation, time, tempVec);
-							rotation.scale3(Math.PI / 180.0);
-							m.rotate(rotation.x, rotation.y, rotation.z);
-						}
+		for (t in trails) {
+			t.update(hxd.Math.max(newTime - oldTime, 0.0));
+		}
 
-						var baseMat = anim.elt.getTransform(tempTransform);
-						var offset = baseMat.getPosition();
-						baseMat.tx = baseMat.ty = baseMat.tz = 0.0;  // Ignore
-						m.multiply(baseMat, m);
-						m.translate(offset.x, offset.y, offset.z);
+		Event.updateEvents(events, newTime, oldTime, duration);
 
-						if(anim.position != null) {
-							var pos = evaluator.getVector(anim.position, time, tempVec);
-							m.translate(pos.x, pos.y, pos.z);
-						}
+		if (!continuous) {
+			fixEventSeek();
+		}
+	}
+
+	function fixEventSeek() {
+		var time = localTime;
+
+		if (events == null)
+			return;
+
+		var closest : Map<h3d.scene.Object, {instance: EventInstance, distance: Float, jumpTo: Float}> = [];
+
+		for (instance in events) {
+			var event = Std.downcast(instance.evt, hrt.prefab.fx.AnimEvent);
+			if (event == null)
+				continue;
+
+			var previous = hrt.tools.MapUtils.getOrPut(closest, event.findFirstLocal3d(), {instance: instance, distance: hxd.Math.POSITIVE_INFINITY, jumpTo: 0.0});
+			if (previous.distance == 0)
+				continue;
+
+			var firstFrame = event.time;
+			var toFirstFrame = firstFrame - time;
+			if (toFirstFrame >= 0 && toFirstFrame < previous.distance) {
+				previous.instance = instance;
+				previous.distance = toFirstFrame;
+				previous.jumpTo = 0.0001;
+			}
+
+			var anim = event.animation != null ? event.shared.loadAnimation(event.animation) : null;
+			var duration = event.duration > 0 ? event.duration : (anim?.getDuration() ?? 0.0);
+			var lastFrame = event.time + duration;
+			var toLastFrame = time - lastFrame;
+			if (toLastFrame >= 0 && toLastFrame < previous.distance) {
+				previous.instance = instance;
+				previous.distance = toLastFrame;
+				previous.jumpTo = duration-0.0001;
+			}
+
+			// We are currently playing this animation
+			if (toFirstFrame < 0 && toLastFrame < 0) {
+				previous.instance = null;
+				previous.distance = 0;
+				continue;
+			}
+		}
+
+		for (obj in closest) {
+			if (obj.instance == null) // can be null if we are in the middle of the animation
+				continue;
+			obj.instance.setTime(obj.jumpTo);
+		}
+	}
 
-						anim.obj.setTransform(m);
+	function syncParticles(timeParam: Float, continuous: Bool) {
+		if(emitters != null) {
+			for(em in emitters) {
+				if(em.visible)
+				{
+					if (continuous) {
+						em.setTime(@:privateAccess em.curTime + timeParam);
+					} else {
+						em.setTime(timeParam);
 					}
+				}
+			}
+		}
 
-					// Animations that are only applied on local transforms of leafs objects
-					if (anim.localRotation != null || anim.localPosition != null) {
-						var leafObjects = anim.elt.findAll(Object3D, o -> o.children == null || o.children.length == 0);
 
-						for (o in leafObjects) {
-							if (o.local3d == null)
-								continue;
-							var baseMat = o.getTransform();
+	}
 
-							tempMat.identity();
-							var m = tempMat;
+	static var tempMat = new h3d.Matrix();
+	static var tempTransform = new h3d.Matrix();
+	static var tempVec = new h3d.Vector4();
 
-							if(anim.localRotation != null) {
-								var localRotation = evaluator.getVector(anim.localRotation, time, tempVec);
-								localRotation.scale3(Math.PI / 180.0);
-								m.rotate(localRotation.x, localRotation.y, localRotation.z);
-							}
+	/** Use seek or update depending on what you want to do instead of this function**/
+	@:deprecated
+	public function setTime( time : Float, fullSync=true) {
+		// broken heuristic for back-compat
+		var continuous = time - localTime < hxd.Timer.dt * 1.5;
+		setTimeInternal(continuous ? time - localTime : time, continuous);
+	}
 
-							if(anim.localPosition != null) {
-								var localPosition = evaluator.getVector(anim.localPosition, time, tempVec);
-								m.translate(localPosition.x, localPosition.y, localPosition.z);
-							}
+	function syncAnims(time: Float) {
+		if(objAnims != null) {
+			for(anim in objAnims) {
+				if(anim.scale != null || anim.rotation != null || anim.position != null) {
+					var m = tempMat;
+					if(anim.scale != null) {
+						var scale = evaluator.getVector(anim.scale, time, tempVec);
+						m.initScale(scale.x, scale.y, scale.z);
+					}
+					else
+						m.identity();
 
-							m.multiply(m, baseMat);
-							o.local3d.setTransform(m);
-						}
+					if(anim.rotation != null) {
+						var rotation = evaluator.getVector(anim.rotation, time, tempVec);
+						rotation.scale3(Math.PI / 180.0);
+						m.rotate(rotation.x, rotation.y, rotation.z);
 					}
 
-					if(anim.visibility != null) {
-						var visible = anim.elt.visible;
-						#if editor
-						var editor = anim.elt.shared.editor;
-						visible = visible && (editor?.isVisible(anim.elt) ?? true);
-						#end
-						anim.obj.visible = visible && evaluator.getFloat(anim.visibility, time) > 0.5;
+					var baseMat = anim.elt.getTransform(tempTransform);
+					var offset = baseMat.getPosition();
+					baseMat.tx = baseMat.ty = baseMat.tz = 0.0;  // Ignore
+					m.multiply(baseMat, m);
+					m.translate(offset.x, offset.y, offset.z);
+
+					if(anim.position != null) {
+						var pos = evaluator.getVector(anim.position, time, tempVec);
+						m.translate(pos.x, pos.y, pos.z);
 					}
 
-					if(anim.color != null) {
-						switch(anim.color) {
-							case VCurve(a):
-								for(mat in anim.obj.getMaterials())
-									mat.color.a = evaluator.getFloat(anim.color, time);
-							default:
-								for(mat in anim.obj.getMaterials())
-									mat.color.load(evaluator.getVector(anim.color, time, tempVec));
+					anim.obj.setTransform(m);
+				}
+
+				// Animations that are only applied on local transforms of leafs objects
+				if (anim.localRotation != null || anim.localPosition != null) {
+					var leafObjects = anim.elt.findAll(Object3D, o -> o.children == null || o.children.length == 0);
+
+					for (o in leafObjects) {
+						if (o.local3d == null)
+							continue;
+						var baseMat = o.getTransform();
+
+						tempMat.identity();
+						var m = tempMat;
+
+						if(anim.localRotation != null) {
+							var localRotation = evaluator.getVector(anim.localRotation, time, tempVec);
+							localRotation.scale3(Math.PI / 180.0);
+							m.rotate(localRotation.x, localRotation.y, localRotation.z);
 						}
-					}
 
-					if( anim.additionalProperies != null ) {
-						switch(anim.additionalProperies) {
-							case None :
-							case PointLight( color, power, size, range ) :
-								var l = Std.downcast(anim.obj, h3d.scene.pbr.PointLight);
-								if( l != null ) {
-									if( color != null ) {
-										var v = evaluator.getVector(color, time, tempVec);
-										l.color.set(v.x, v.y, v.z);
-									}
-									if( power != null ) l.power = evaluator.getFloat(power, time);
-									if( size != null ) l.size = evaluator.getFloat(size, time);
-									if( range != null ) l.range = evaluator.getFloat(range, time);
-								}
-							case DirLight(color, power):
-								var l = Std.downcast(anim.obj, h3d.scene.pbr.DirLight);
-								if( l != null ) {
-									if( color != null ) {
-										var v = evaluator.getVector(color, time, tempVec);
-										l.color.set(v.x, v.y, v.z);
-									}
-									if( power != null ) l.power = evaluator.getFloat(power, time);
-								}
-							case SpotLight(color, power, range, angle, fallOff):
-								var l = Std.downcast(anim.obj, h3d.scene.pbr.SpotLight);
-								if( l != null ) {
-									if( color != null ) {
-										var v = evaluator.getVector(color, time, tempVec);
-										l.color.set(v.x, v.y, v.z);
-									}
-									if( power != null ) l.power = evaluator.getFloat(power, time);
-									if( range != null ) l.range = evaluator.getFloat(range, time);
-									if( angle != null ) l.angle = evaluator.getFloat(angle, time);
-									if( fallOff != null ) l.fallOff = evaluator.getFloat(fallOff, time);
-								}
+						if(anim.localPosition != null) {
+							var localPosition = evaluator.getVector(anim.localPosition, time, tempVec);
+							m.translate(localPosition.x, localPosition.y, localPosition.z);
 						}
+
+						m.multiply(m, baseMat);
+						o.local3d.setTransform(m);
 					}
 				}
-			}
 
-			if (effects != null) {
-				for (e in effects)
-					@:privateAccess e.updateInstance();
-			}
-
-			if(customAnims != null)
-				for(anim in customAnims)
-					anim.setTime(this.prevTime + dt);
+				if(anim.visibility != null) {
+					var visible = anim.elt.visible;
+					#if editor
+					var editor = anim.elt.shared.editor;
+					visible = visible && (editor?.isVisible(anim.elt) ?? true);
+					#end
+					anim.obj.visible = visible && evaluator.getFloat(anim.visibility, time) > 0.5;
+				}
 
-			if(emitters != null) {
-				for(em in emitters) {
-					if(em.visible)
-						em.setTime(@:privateAccess em.curTime + dt);
+				if(anim.color != null) {
+					switch(anim.color) {
+						case VCurve(a):
+							for(mat in anim.obj.getMaterials())
+								mat.color.a = evaluator.getFloat(anim.color, time);
+						default:
+							for(mat in anim.obj.getMaterials())
+								mat.color.load(evaluator.getVector(anim.color, time, tempVec));
+					}
 				}
-			}
 
-			for (t in trails) {
-				t.update(hxd.Math.max(dt, 0.0));
+				if( anim.additionalProperies != null ) {
+					switch(anim.additionalProperies) {
+						case None :
+						case PointLight( color, power, size, range ) :
+							var l = Std.downcast(anim.obj, h3d.scene.pbr.PointLight);
+							if( l != null ) {
+								if( color != null ) {
+									var v = evaluator.getVector(color, time, tempVec);
+									l.color.set(v.x, v.y, v.z);
+								}
+								if( power != null ) l.power = evaluator.getFloat(power, time);
+								if( size != null ) l.size = evaluator.getFloat(size, time);
+								if( range != null ) l.range = evaluator.getFloat(range, time);
+							}
+						case DirLight(color, power):
+							var l = Std.downcast(anim.obj, h3d.scene.pbr.DirLight);
+							if( l != null ) {
+								if( color != null ) {
+									var v = evaluator.getVector(color, time, tempVec);
+									l.color.set(v.x, v.y, v.z);
+								}
+								if( power != null ) l.power = evaluator.getFloat(power, time);
+							}
+						case SpotLight(color, power, range, angle, fallOff):
+							var l = Std.downcast(anim.obj, h3d.scene.pbr.SpotLight);
+							if( l != null ) {
+								if( color != null ) {
+									var v = evaluator.getVector(color, time, tempVec);
+									l.color.set(v.x, v.y, v.z);
+								}
+								if( power != null ) l.power = evaluator.getFloat(power, time);
+								if( range != null ) l.range = evaluator.getFloat(range, time);
+								if( angle != null ) l.angle = evaluator.getFloat(angle, time);
+								if( fallOff != null ) l.fallOff = evaluator.getFloat(fallOff, time);
+							}
+					}
+				}
 			}
 		}
 
-		Event.updateEvents(events, time, prevTime, duration);
-
-		this.prevTime = localTime;
+		if (effects != null) {
+			for (e in effects)
+				@:privateAccess e.updateInstance();
+		}
 	}
 
+
 	public function stop(instant: Bool = false, onEnd: () -> Void) {
 		this.onEnd = onEnd;
 		playState = End;
 		if (instant == true) {
-			setTime(duration, false);
+			setTime(duration);
 		}
 	}
 

+ 0 - 4
hrt/prefab/fx/SubFX.hx

@@ -33,10 +33,6 @@ class SubFX extends Reference implements hrt.prefab.fx.Event.IEvent{
 	}
 
 	public function getDuration() {
-		#if !release
-		if (refInstance != null && instance == null)
-			throw "refInstance is init but instance is not";
-		#end
 		if (instance != null)
 			return instance.duration;
 		return 0.0;