فهرست منبع

added timeline events support

ncannasse 10 سال پیش
والد
کامیت
a8749cfdc1
9فایلهای تغییر یافته به همراه132 افزوده شده و 76 حذف شده
  1. 23 53
      h3d/anim/Animation.hx
  2. 4 0
      hxd/fmt/fbx/BaseLibrary.hx
  3. 1 0
      hxd/fmt/fbx/HMDOut.hx
  4. 8 0
      hxd/fmt/hmd/Data.hx
  5. 3 2
      hxd/fmt/hmd/Library.hx
  6. 11 1
      hxd/fmt/hmd/Reader.hx
  7. 8 1
      hxd/fmt/hmd/Writer.hx
  8. 28 9
      tools/fbx/Viewer.hx
  9. 46 10
      tools/xtra/xtraExporter.ms

+ 23 - 53
h3d/anim/Animation.hx

@@ -19,17 +19,6 @@ class AnimatedObject {
 
 }
 
-private class AnimWait {
-	public var frame : Float;
-	public var callb : Void -> Void;
-	public var next : AnimWait;
-	public function new(f, c, n) {
-		frame = f;
-		callb = c;
-		next = n;
-	}
-}
-
 class Animation {
 
 	static inline var EPSILON = 0.000001;
@@ -41,20 +30,23 @@ class Animation {
 
 	public var speed : Float;
 	public var onAnimEnd : Void -> Void;
+	public var onEvent : String -> Void;
 
 	public var pause : Bool;
 	public var loop : Bool;
 
-	var waits : AnimWait;
 	var isInstance : Bool;
 	var objects : Array<AnimatedObject>;
 	var isSync : Bool;
+	var events : Array<String>;
+	var lastEvent : Int;
 
 	function new(name, frameCount, sampling) {
 		this.name = name;
 		this.frameCount = frameCount;
 		this.sampling = sampling;
 		objects = [];
+		lastEvent = -1;
 		frame = 0.;
 		speed = 1.;
 		loop = true;
@@ -83,31 +75,15 @@ class Animation {
 	/**
 		Register a callback function that will be called once when a frame is reached.
 	**/
-	public function waitForFrame( f : Float, callb : Void -> Void ) {
-		// add sorted
-		var prev = null;
-		var cur = waits;
-		while( cur != null ) {
-			if( cur.frame > f )
-				break;
-			prev = cur;
-			cur = cur.next;
-		}
-		if( prev == null )
-			waits = new AnimWait(f, callb, waits);
-		else
-			prev.next = new AnimWait(f, callb, prev.next);
-	}
-
-	/**
-		Remove all frame listeners
-	**/
-	public function clearWaits() {
-		waits = null;
+	public function setEvents( el : Iterable<{ frame : Int, data : String }> ) {
+		events = [for( i in 0...frameCount ) null];
+		for( e in el )
+			events[e.frame] = e.data;
 	}
 
 	public function setFrame( f : Float ) {
 		frame = f;
+		lastEvent = -1;
 		while( frame < 0 ) frame += frameCount;
 		while( frame > frameCount ) frame -= frameCount;
 	}
@@ -119,6 +95,7 @@ class Animation {
 		a.speed = speed;
 		a.loop = loop;
 		a.pause = pause;
+		a.events = events;
 		return a;
 	}
 
@@ -201,27 +178,20 @@ class Animation {
 		if( !isPlaying() )
 			return 0;
 
-		// check waits
-		var w = waits;
-		var prev = null;
-		while( w != null ) {
-			var wt = (w.frame - frame) / (speed * sampling);
-			// don't run if we're already on the frame (allow to set waitForFrame on the same frame we are)
-			if( wt <= 0 ) {
-				prev = w;
-				w = w.next;
-				continue;
+		// check events
+		if( events != null && onEvent != null ) {
+			var f0 = Std.int(frame);
+			var f1 = Std.int(frame + dt * speed * sampling);
+			for( f in f0...f1 + 1 ) {
+				if( f == lastEvent ) continue;
+				lastEvent = f;
+				if( events[f] != null ) {
+					dt -= (f - frame) / (speed * sampling);
+					frame = f;
+					onEvent(events[f]);
+					return dt;
+				}
 			}
-			if( wt > dt )
-				break;
-			frame = w.frame;
-			dt -= wt;
-			if( prev == null )
-				waits = w.next;
-			else
-				prev.next = w.next;
-			w.callb();
-			return dt;
 		}
 
 		// check on anim end

+ 4 - 0
hxd/fmt/fbx/BaseLibrary.hx

@@ -91,6 +91,7 @@ class BaseLibrary {
 	var leftHand : Bool;
 	var defaultModelMatrixes : Map<String,DefaultMatrixes>;
 	var uvAnims : Map<String, Array<{ t : Float, u : Float, v : Float }>>;
+	var animationEvents : Array<{ frame : Int, data : String }>;
 
 	/**
 		Allows to prevent some terminal unskinned joints to be removed, for instance if we want to track their position
@@ -160,6 +161,9 @@ class BaseLibrary {
 							var frames = [for( f in new haxe.xml.Fast(xml.firstElement()).elements ) { var f = f.innerData.split(" ");  { t : Std.parseFloat(f[0]) * 9622116.25, u : Std.parseFloat(f[1]), v : Std.parseFloat(f[2]) }} ];
 							if( uvAnims == null ) uvAnims = new Map();
 							uvAnims.set(m.getName(), frames);
+						case "Events":
+							var xml = try Xml.parse(pval) catch( e : Dynamic ) throw "Invalid Events data in " + m.getName();
+							animationEvents = [for( f in new haxe.xml.Fast(xml.firstElement()).elements ) { var f = f.innerData.split(" ");  { frame : Std.parseInt(f.shift()), data : StringTools.trim(f.join(" ")) }} ];
 						default:
 						}
 					}

+ 1 - 0
hxd/fmt/fbx/HMDOut.hx

@@ -576,6 +576,7 @@ class HMDOut extends BaseLibrary {
 		a.frames = anim.frameCount;
 		a.objects = [];
 		a.dataPosition = dataOut.length;
+		a.events = [for( a in animationEvents ) { var e = new AnimationEvent(); e.frame = a.frame; e.data = a.data; e; } ];
 		var objects : Array<h3d.anim.LinearAnimation.LinearObject> = cast @:privateAccess anim.objects;
 		objects.sort(function(o1, o2) return Reflect.compare(o1.objectName, o2.objectName));
 		for( obj in objects ) {

+ 8 - 0
hxd/fmt/hmd/Data.hx

@@ -187,6 +187,13 @@ class AnimationObject {
 	}
 }
 
+class AnimationEvent {
+	public var frame : Int;
+	public var data : String;
+	public function new() {
+	}
+}
+
 class Animation {
 	public var name : String;
 	public var props : Properties;
@@ -195,6 +202,7 @@ class Animation {
 	public var speed : Float;
 	public var loop : Bool;
 	public var objects : Array<AnimationObject>;
+	public var events : Null<Array<AnimationEvent>>;
 	public var dataPosition : DataPosition;
 	public function new() {
 	}

+ 3 - 2
hxd/fmt/hmd/Library.hx

@@ -309,13 +309,13 @@ class Library {
 		return s;
 	}
 
-	public function getModelProperty<T>( objName : String, p : Property<T> ) : T {
+	public function getModelProperty<T>( objName : String, p : Property<T>, ?def : Null<T> ) : Null<T> {
 		for( m in header.models )
 			if( m.name == objName ) {
 				for( pr in m.props )
 					if( pr.getIndex() == p.getIndex() )
 						return pr.getParameters()[0];
-				throw '${objName} has no property ${p.getName()}';
+				return def;
 			}
 		throw 'Model ${objName} not found';
 	}
@@ -383,6 +383,7 @@ class Library {
 		var l = new h3d.anim.LinearAnimation(a.name, a.frames, a.sampling);
 		l.speed = a.speed;
 		l.loop = a.loop;
+		if( a.events != null ) l.setEvents(a.events);
 
 		entry.open();
 		entry.skip(header.dataPosition + a.dataPosition);

+ 11 - 1
hxd/fmt/hmd/Reader.hx

@@ -169,7 +169,8 @@ class Reader {
 			a.frames = i.readInt32();
 			a.sampling = i.readFloat();
 			a.speed = i.readFloat();
-			a.loop = i.readByte() == 1;
+			var flags = i.readByte();
+			a.loop = flags & 1 != 0;
 			a.dataPosition = i.readInt32();
 			a.objects = [];
 			for( k in 0...i.readInt32() ) {
@@ -180,6 +181,15 @@ class Reader {
 				if( o.flags.has(HasProps) )
 					o.props = [for( i in 0...i.readByte() ) readName()];
 			}
+			if( flags & 2 != 0 ) {
+				a.events = [];
+				for( k in 0...i.readInt32() ) {
+					var e = new AnimationEvent();
+					e.frame = i.readInt32();
+					e.data = readName();
+					a.events.push(e);
+				}
+			}
 			d.animations.push(a);
 		}
 

+ 8 - 1
hxd/fmt/hmd/Writer.hx

@@ -160,7 +160,7 @@ class Writer {
 			out.writeInt32(a.frames);
 			writeFloat(a.sampling);
 			writeFloat(a.speed);
-			out.writeByte(a.loop?1:0);
+			out.writeByte( (a.loop?1:0) | (a.events != null?2:0) );
 			out.writeInt32(a.dataPosition);
 			out.writeInt32(a.objects.length);
 			for( o in a.objects ) {
@@ -172,6 +172,13 @@ class Writer {
 						writeName(n);
 				}
 			}
+			if( a.events != null ) {
+				out.writeInt32(a.events.length);
+				for( e in a.events ) {
+					out.writeInt32(e.frame);
+					writeName(e.data);
+				}
+			}
 		}
 
 		var bytes = header.getBytes();

+ 28 - 9
tools/fbx/Viewer.hx

@@ -508,15 +508,7 @@ class Viewer extends hxd.App {
 		if( cameras.length == 1 && curHmd != null ) {
 			var c = cameras[0];
 			var t = obj.getObjectByName(c.name+".Target");
-			for( m in curHmd.header.models )
-				if( m.name == c.name && m.props != null ) {
-					for( p in m.props )
-						switch( p ) {
-						case CameraFOVY(v):
-							s3d.camera.fovY = v;
-						default:
-						}
-				}
+			s3d.camera.fovY = curHmd.getModelProperty(t.name, CameraFOVY(0), 25);
 			s3d.camera.follow = { pos : c, target : t };
 		}
 	}
@@ -565,6 +557,33 @@ class Viewer extends hxd.App {
 			return;
 		var prev = s3d.currentAnimation;
 		anim = s3d.playAnimation(anim);
+		anim.onEvent = function(e:String) {
+			var param = null;
+			var name = e;
+			if( StringTools.endsWith(e, ")") ) {
+				var f = e.split("(");
+				name = f[0];
+				param = f[1].substr(0, -1);
+				if( param == "" ) param = null;
+			}
+			switch( name ) {
+			case "camera":
+				if( param == null )
+					s3d.camera.follow = null;
+				else {
+					var o = s3d.getObjectByName(param);
+					var t = s3d.getObjectByName(param + ".Target");
+					if( o == null || t == null )
+						trace("Camera not found " + param);
+					else {
+						s3d.camera.follow = { pos : o, target : t };
+						s3d.camera.fovY = curHmd.getModelProperty(param, CameraFOVY(0), 25);
+					}
+				}
+			default:
+				trace("EVENT @"+anim.frame+" : "+e);
+			}
+		};
 		if( !props.loop ) {
 			anim.loop = false;
 			anim.onAnimEnd = function() anim.setFrame(0);

+ 46 - 10
tools/xtra/xtraExporter.ms

@@ -1,8 +1,50 @@
+
+fn setProp m p v = (
+	local buf = substituteString (substituteString (getUserPropBuffer m) "\r\n" "\n") "\r" "\n"
+	local props = filterString buf "\n"
+	local found = false
+	for pid in 1 to props.count do (		
+		local pname = substituteString ((filterString (props[pid]) "=")[1]) " " ""
+		if pname == p then (
+			found = true
+			if v == undefined then props[pid] = "" else props[pid] = p+"="+v
+		)
+	)
+	if (not found) and v != undefined then append props (p+"="+v)	
+	buf = ""
+	for i in 1 to props.count do (
+		if props[i] == "" then continue
+		buf = buf + props[i]+"\r\n"
+	)
+	setUserPropBuffer m buf
+)
+
+fn unsetProp m p = (
+	setProp m p undefined
+)
+
 macroScript XtraExport Category:"Shiro" tooltip:"Add Extra Infos" buttontext:"XTRA"
 (
 
 	local somethingDone = false
+
+	local tcount = FrameTagManager.GetTagCount()
+	
+	if tcount > 0 then (
+		for m in Geometry do unsetProp m "Events"
+		local evData = "<el>"
+		for i = 1 to tcount do (
+			local tid = FrameTagManager.GetTagID i
+			local ttime = FrameTagManager.GetTimeByID tid
+			local tname = FrameTagManager.GetNameByID tid
+			evData = evData + "<e>"+(ttime as string)+" "+tname+"</e>";
+		)
+		setProp Geometry[1] "Events" (evData + "</el>")
+		somethingDone = true
+	)
+	
 	for m in Geometry do (
+		unsetProp m "UV"
 		if m.material == undefined then continue
 		local diffuse = m.material.diffuseMap
 		if diffuse == undefined then continue
@@ -34,17 +76,11 @@ macroScript XtraExport Category:"Shiro" tooltip:"Add Extra Infos" buttontext:"XT
 				)
 			)
 		)
-
-		if hasUVAnim then (
-			setUserProp m "UV" (uvData+"</uv>");
-		) else if getUserProp m "UV" != undefined then (
-			local buf = getUserPropBuffer m
-			setUserProp m "UV" "";
-			buf = substituteString buf "UV = \r\n" ""
-			setUserPropBuffer m buf
-		)
+		if hasUVAnim then setProp m "UV" (uvData+"</uv>")
 	)
 	if not somethingDone then (
-		messageBox "No UV animation has been found"
+		messageBox "No XTRA info has been found"
 	)
 )
+
+