Ver código fonte

added UV animation support through loadXtra

ncannasse 11 anos atrás
pai
commit
fe686ec0c3

+ 8 - 0
h3d/anim/FrameAnimation.hx

@@ -4,11 +4,13 @@ import h3d.anim.Animation;
 class FrameObject extends AnimatedObject {
 class FrameObject extends AnimatedObject {
 	public var frames : haxe.ds.Vector<h3d.Matrix>;
 	public var frames : haxe.ds.Vector<h3d.Matrix>;
 	public var alphas : haxe.ds.Vector<Float>;
 	public var alphas : haxe.ds.Vector<Float>;
+	public var uvs : haxe.ds.Vector<Float>;
 	
 	
 	override function clone() : AnimatedObject {
 	override function clone() : AnimatedObject {
 		var o = new FrameObject(objectName);
 		var o = new FrameObject(objectName);
 		o.frames = frames;
 		o.frames = frames;
 		o.alphas = alphas;
 		o.alphas = alphas;
+		o.uvs = uvs;
 		return o;
 		return o;
 	}
 	}
 }
 }
@@ -33,6 +35,12 @@ class FrameAnimation extends Animation {
 		f.alphas = alphas;
 		f.alphas = alphas;
 		objects.push(f);
 		objects.push(f);
 	}
 	}
+
+	public function addUVCurve( objName, uvs ) {
+		var f = new FrameObject(objName);
+		f.uvs = uvs;
+		objects.push(f);
+	}
 	
 	
 	inline function getFrames() : Array<FrameObject> {
 	inline function getFrames() : Array<FrameObject> {
 		return cast objects;
 		return cast objects;

+ 19 - 0
h3d/anim/LinearAnimation.hx

@@ -21,6 +21,7 @@ class LinearObject extends AnimatedObject {
 	public var hasScale : Bool;
 	public var hasScale : Bool;
 	public var frames : haxe.ds.Vector<LinearFrame>;
 	public var frames : haxe.ds.Vector<LinearFrame>;
 	public var alphas : haxe.ds.Vector<Float>;
 	public var alphas : haxe.ds.Vector<Float>;
+	public var uvs : haxe.ds.Vector<Float>;
 	public var matrix : h3d.Matrix;
 	public var matrix : h3d.Matrix;
 	override function clone() : AnimatedObject {
 	override function clone() : AnimatedObject {
 		var o = new LinearObject(objectName);
 		var o = new LinearObject(objectName);
@@ -28,6 +29,7 @@ class LinearObject extends AnimatedObject {
 		o.hasScale = hasScale;
 		o.hasScale = hasScale;
 		o.frames = frames;
 		o.frames = frames;
 		o.alphas = alphas;
 		o.alphas = alphas;
+		o.uvs = uvs;
 		return o;
 		return o;
 	}
 	}
 }
 }
@@ -54,6 +56,12 @@ class LinearAnimation extends Animation {
 		f.alphas = alphas;
 		f.alphas = alphas;
 		objects.push(f);
 		objects.push(f);
 	}
 	}
+
+	public function addUVCurve( objName, uvs ) {
+		var f = new LinearObject(objName);
+		f.uvs = uvs;
+		objects.push(f);
+	}
 	
 	
 	inline function getFrames() : Array<LinearObject> {
 	inline function getFrames() : Array<LinearObject> {
 		return cast objects;
 		return cast objects;
@@ -101,6 +109,17 @@ class LinearAnimation extends Animation {
 				mat.colorMul.w = o.alphas[frame1] * k1 + o.alphas[frame2] * k2;
 				mat.colorMul.w = o.alphas[frame1] * k1 + o.alphas[frame2] * k2;
 				continue;
 				continue;
 			}
 			}
+			if( o.uvs != null ) {
+				var mat = o.targetObject.toMesh().material;
+				if( mat.uvDelta == null ) {
+					mat.uvDelta = new Vector();
+					mat.texture.wrap = Repeat;
+				}
+				mat.uvDelta.x = o.uvs[frame1 << 1] * k1 + o.uvs[frame2 << 1] * k2;
+				mat.uvDelta.y = o.uvs[(frame1 << 1) | 1] * k1 + o.uvs[(frame2 << 1) | 1] * k2;
+				trace(frame1, mat.uvDelta);
+				continue;
+			}
 			var f1 = o.frames[frame1], f2 = o.frames[frame2];
 			var f1 = o.frames[frame1], f2 = o.frames[frame2];
 			
 			
 			var m = o.matrix;
 			var m = o.matrix;

+ 104 - 39
h3d/fbx/Library.hx

@@ -7,6 +7,20 @@ enum AnimationMode {
 	LinearAnim;
 	LinearAnim;
 }
 }
 
 
+private class AnimCurve {
+	public var def : DefaultMatrixes;
+	public var object : String;
+	public var t : { t : Array<Float>, x : Array<Float>, y : Array<Float>, z : Array<Float> };
+	public var r : { t : Array<Float>, x : Array<Float>, y : Array<Float>, z : Array<Float> };
+	public var s : { t : Array<Float>, x : Array<Float>, y : Array<Float>, z : Array<Float> };
+	public var a : { t : Array<Float>, v : Array<Float> };
+	public var uv : Array<{ t : Float, u : Float, v : Float }>;
+	public function new(def, object) {
+		this.def = def;
+		this.object = object;
+	}
+}
+
 class DefaultMatrixes {
 class DefaultMatrixes {
 	public var trans : Null<Point>;
 	public var trans : Null<Point>;
 	public var scale : Null<Point>;
 	public var scale : Null<Point>;
@@ -50,6 +64,7 @@ class Library {
 	var invConnect : Map<Int,Array<Int>>;
 	var invConnect : Map<Int,Array<Int>>;
 	var leftHand : Bool;
 	var leftHand : Bool;
 	var defaultModelMatrixes : Map<String,DefaultMatrixes>;
 	var defaultModelMatrixes : Map<String,DefaultMatrixes>;
+	var uvAnims : Map<String, Array<{ t : Float, u : Float, v : Float }>>;
 
 
 	/**
 	/**
 		Allows to prevent some terminal unskinned joints to be removed, for instance if we want to track their position
 		Allows to prevent some terminal unskinned joints to be removed, for instance if we want to track their position
@@ -101,6 +116,16 @@ class Library {
 			init(c);
 			init(c);
 	}
 	}
 	
 	
+	public function loadXtra( data : String ) {
+		var xml = Xml.parse(data).firstElement();
+		if( uvAnims == null ) uvAnims = new Map();
+		for( e in new haxe.xml.Fast(xml).elements ) {
+			var obj = e.att.name;
+			var frames = [for( f in e.elements ) { var f = f.innerData.split(" ");  { t : Std.parseFloat(f[0]) * 9622116.25, u : Std.parseFloat(f[1]), v : Std.parseFloat(f[2]) }} ];
+			uvAnims.set(obj, frames);
+		}
+	}
+	
 	function convertPoints( a : Array<Float> ) {
 	function convertPoints( a : Array<Float> ) {
 		var p = 0;
 		var p = 0;
 		for( i in 0...Std.int(a.length / 3) ) {
 		for( i in 0...Std.int(a.length / 3) ) {
@@ -222,6 +247,38 @@ class Library {
 		}
 		}
 	}
 	}
 
 
+	function getObjectCurve( curves : Map < Int, AnimCurve > , model : FbxNode, curveName : String, animName : String ) : AnimCurve {
+		var c = curves.get(model.getId());
+		if( c != null )
+			return c;
+		var name = model.getName();
+		if( skipObjects.get(name) )
+			return null;
+		// if it's an empty model with no sub nodes, let's ignore it (ex : Camera)
+		if( model.getType() == "Null" && getChilds(model, "Model").length == 0 )
+			return null;
+		var def = defaultModelMatrixes.get(name);
+		if( def == null )
+			throw "Object "+name+" used in anim "+animName+" was not found in library";
+		// if it's a move animation on a terminal unskinned joint, let's skip it
+		if( def.wasRemoved != null ) {
+			if( curveName != "Visibility" && curveName != "UV" )
+				return null;
+			// apply it on the skin instead
+			model = ids.get(def.wasRemoved);
+			name = model.getName();
+			c = curves.get(def.wasRemoved);
+			def = defaultModelMatrixes.get(name);
+			// todo : change behavior not to remove the mesh but the skin instead!
+			if( def == null ) throw "assert";
+		}
+		if( c == null ) {
+			c = new AnimCurve(def, name);
+			curves.set(model.getId(), c);
+		}
+		return c;
+	}
+	
 	public function loadAnimation( mode : AnimationMode, ?animName : String, ?root : FbxNode, ?lib : Library ) : h3d.anim.Animation {
 	public function loadAnimation( mode : AnimationMode, ?animName : String, ?root : FbxNode, ?lib : Library ) : h3d.anim.Animation {
 		if( lib != null ) {
 		if( lib != null ) {
 			lib.defaultModelMatrixes = defaultModelMatrixes;
 			lib.defaultModelMatrixes = defaultModelMatrixes;
@@ -254,34 +311,8 @@ class Library {
 		var allTimes = new Map();
 		var allTimes = new Map();
 		for( cn in getChilds(animNode, "AnimationCurveNode") ) {
 		for( cn in getChilds(animNode, "AnimationCurveNode") ) {
 			var model = getParent(cn, "Model");
 			var model = getParent(cn, "Model");
-			var c = curves.get(model.getId());
-			if( c == null ) {
-				var name = model.getName();
-				if( skipObjects.get(name) )
-					continue;
-				// if it's an empty model with no sub nodes, let's ignore it (ex : Camera)
-				if( model.getType() == "Null" && getChilds(model, "Model").length == 0 )
-					continue;
-				var def = defaultModelMatrixes.get(name);
-				if( def == null )
-					throw "Object "+name+" used in anim "+animName+" was not found in library";
-				// if it's a move animation on a terminal unskinned joint, let's skip it
-				if( def.wasRemoved != null ) {
-					if( cn.getName() != "Visibility" )
-						continue;
-					// apply it on the skin instead
-					model = ids.get(def.wasRemoved);
-					name = model.getName();
-					c = curves.get(def.wasRemoved);
-					def = defaultModelMatrixes.get(name);
-					// todo : change behavior not to remove the mesh but the skin instead!
-					if( def == null ) throw "assert";
-				}
-				if( c == null ) {
-					c = { def : def, t : null, r : null, s : null, a : null, name : name };
-					curves.set(model.getId(), c);
-				}
-			}
+			var c = getObjectCurve(curves, model, cn.getName(), animName);
+			if( c == null ) continue;
 			var data = getChilds(cn, "AnimationCurve");
 			var data = getChilds(cn, "AnimationCurve");
 			var cname = cn.getName();
 			var cname = cn.getName();
 			// collect all the timestamps
 			// collect all the timestamps
@@ -359,11 +390,25 @@ class Library {
 			default: throw "assert";
 			default: throw "assert";
 			}
 			}
 		}
 		}
+
+		// process UVs
+		if( uvAnims != null ) {
+			var modelByName = new Map();
+			for( obj in this.root.getAll("Objects.Model") )
+				modelByName.set(obj.getName(), obj);
+			for( obj in uvAnims.keys() ) {
+				var frames = uvAnims.get(obj);
+				var model = modelByName.get(obj);
+				if( model == null ) throw "Missing model '" + obj + "' requires by UV animation";
+				var c = getObjectCurve(curves, model, "UV", animName);
+				if( c == null ) continue;
+				c.uv = frames;
+				for( f in frames )
+					allTimes.set(Std.int(f.t / 200000), f.t);
+			}
+		}
 		
 		
-		var times = [];
-		for( a in allTimes )
-			times.push(a);
-		var allTimes = times;
+		var allTimes = [for( a in allTimes ) a];
 		allTimes.sort(sortDistinctFloats);
 		allTimes.sort(sortDistinctFloats);
 		var maxTime = allTimes[allTimes.length - 1];
 		var maxTime = allTimes[allTimes.length - 1];
 		var minDT = maxTime;
 		var minDT = maxTime;
@@ -384,8 +429,9 @@ class Library {
 			for( c in curves ) {
 			for( c in curves ) {
 				var frames = c.t == null && c.r == null && c.s == null ? null : new haxe.ds.Vector(numFrames);
 				var frames = c.t == null && c.r == null && c.s == null ? null : new haxe.ds.Vector(numFrames);
 				var alpha = c.a == null ? null : new haxe.ds.Vector(numFrames);
 				var alpha = c.a == null ? null : new haxe.ds.Vector(numFrames);
+				var uvs = c.uv == null ? null : new haxe.ds.Vector(numFrames * 2);
 				// skip empty curves
 				// skip empty curves
-				if( frames == null && alpha == null )
+				if( frames == null && alpha == null && uvs == null )
 					continue;
 					continue;
 				var ctx = c.t == null ? null : c.t.x;
 				var ctx = c.t == null ? null : c.t.x;
 				var cty = c.t == null ? null : c.t.y;
 				var cty = c.t == null ? null : c.t.y;
@@ -401,8 +447,9 @@ class Library {
 				var cst = c.s == null ? [ -1.] : c.s.t;
 				var cst = c.s == null ? [ -1.] : c.s.t;
 				var cav = c.a == null ? null : c.a.v;
 				var cav = c.a == null ? null : c.a.v;
 				var cat = c.a == null ? null : c.a.t;
 				var cat = c.a == null ? null : c.a.t;
+				var cuv = c.uv;
 				var def = c.def;
 				var def = c.def;
-				var tp = 0, rp = 0, sp = 0, ap = 0;
+				var tp = 0, rp = 0, sp = 0, ap = 0, uvp = 0;
 				var curMat = null;
 				var curMat = null;
 				for( f in 0...numFrames ) {
 				for( f in 0...numFrames ) {
 					var changed = curMat == null;
 					var changed = curMat == null;
@@ -454,12 +501,20 @@ class Library {
 							ap++;
 							ap++;
 						alpha[f] = cav[ap - 1];
 						alpha[f] = cav[ap - 1];
 					}
 					}
+					if( uvs != null ) {
+						if( allTimes[f] == cuv[uvp].t )
+							uvp++;
+						uvs[f<<1] = cuv[uvp - 1].u;
+						uvs[(f<<1)|1] = cuv[uvp - 1].v;
+					}
 				}
 				}
 				
 				
 				if( frames != null )
 				if( frames != null )
-					anim.addCurve(c.name, frames);
+					anim.addCurve(c.object, frames);
 				if( alpha != null )
 				if( alpha != null )
-					anim.addAlphaCurve(c.name, alpha);
+					anim.addAlphaCurve(c.object, alpha);
+				if( uvs != null )
+					anim.addUVCurve(c.object, uvs);
 			}
 			}
 			return anim;
 			return anim;
 			
 			
@@ -471,6 +526,7 @@ class Library {
 			for( c in curves ) {
 			for( c in curves ) {
 				var frames = c.t == null && c.r == null && c.s == null ? null : new haxe.ds.Vector(numFrames);
 				var frames = c.t == null && c.r == null && c.s == null ? null : new haxe.ds.Vector(numFrames);
 				var alpha = c.a == null ? null : new haxe.ds.Vector(numFrames);
 				var alpha = c.a == null ? null : new haxe.ds.Vector(numFrames);
+				var uvs = c.uv == null ? null : new haxe.ds.Vector(numFrames * 2);
 				// skip empty curves
 				// skip empty curves
 				if( frames == null && alpha == null )
 				if( frames == null && alpha == null )
 					continue;
 					continue;
@@ -488,8 +544,9 @@ class Library {
 				var cst = c.s == null ? [ -1.] : c.s.t;
 				var cst = c.s == null ? [ -1.] : c.s.t;
 				var cav = c.a == null ? null : c.a.v;
 				var cav = c.a == null ? null : c.a.v;
 				var cat = c.a == null ? null : c.a.t;
 				var cat = c.a == null ? null : c.a.t;
+				var cuv = c.uv;
 				var def = c.def;
 				var def = c.def;
-				var tp = 0, rp = 0, sp = 0, ap = 0;
+				var tp = 0, rp = 0, sp = 0, ap = 0, uvp = 0;
 				var curFrame = null;
 				var curFrame = null;
 				for( f in 0...numFrames ) {
 				for( f in 0...numFrames ) {
 					var changed = curFrame == null;
 					var changed = curFrame == null;
@@ -572,12 +629,20 @@ class Library {
 							ap++;
 							ap++;
 						alpha[f] = cav[ap - 1];
 						alpha[f] = cav[ap - 1];
 					}
 					}
+					if( uvs != null ) {
+						if( uvp < cuv.length && allTimes[f] == cuv[uvp].t )
+							uvp++;
+						uvs[f<<1] = cuv[uvp - 1].u;
+						uvs[(f<<1)|1] = cuv[uvp - 1].v;
+					}
 				}
 				}
 				
 				
 				if( frames != null )
 				if( frames != null )
-					anim.addCurve(c.name, frames, c.r != null || def.rotate != null, c.s != null || def.scale != null);
+					anim.addCurve(c.object, frames, c.r != null || def.rotate != null, c.s != null || def.scale != null);
 				if( alpha != null )
 				if( alpha != null )
-					anim.addAlphaCurve(c.name, alpha);
+					anim.addAlphaCurve(c.object, alpha);
+				if( uvs != null )
+					anim.addUVCurve(c.object, uvs);
 			}
 			}
 			return anim;
 			return anim;
 			
 			

+ 1 - 1
hxd/res/Any.hx

@@ -28,7 +28,7 @@ class Any extends Resource {
 	}
 	}
 	
 	
 	public function toFbx() {
 	public function toFbx() {
-		return loader.loadFbxModel(entry.path).toFbx();
+		return loader.loadFbxModel(entry.path).toFbx(loader);
 	}
 	}
 	
 	
 	public function toAwd() {
 	public function toAwd() {

+ 5 - 1
hxd/res/FbxModel.hx

@@ -4,7 +4,7 @@ class FbxModel extends Resource {
 	
 	
 	public static var isLeftHanded = true;
 	public static var isLeftHanded = true;
 	
 	
-	public function toFbx() : h3d.fbx.Library {
+	public function toFbx( ?loader : Loader ) : h3d.fbx.Library {
 		var lib = new h3d.fbx.Library();
 		var lib = new h3d.fbx.Library();
 		switch( entry.getSign() & 0xFF ) {
 		switch( entry.getSign() & 0xFF ) {
 		case ';'.code: // FBX
 		case ';'.code: // FBX
@@ -14,6 +14,10 @@ class FbxModel extends Resource {
 			var xbx = new h3d.fbx.XBXReader(f).read();
 			var xbx = new h3d.fbx.XBXReader(f).read();
 			lib.load(xbx);
 			lib.load(xbx);
 			f.close();
 			f.close();
+		case '<'.code: // XTRA
+			if( loader == null ) throw "Loader parameter required for XTRA";
+			lib = loader.load(entry.path.substr(0, -4) + "FBX").toFbx();
+			lib.loadXtra(entry.getBytes().toString());
 		default:
 		default:
 			throw "Unsupported model format " + entry.path;
 			throw "Unsupported model format " + entry.path;
 		}
 		}

+ 2 - 1
hxd/res/FileTree.hx

@@ -30,6 +30,7 @@ class FileTree {
 		pairedExt.set("fnt", ["png"]);
 		pairedExt.set("fnt", ["png"]);
 		pairedExt.set("fbx", ["png"]);
 		pairedExt.set("fbx", ["png"]);
 		pairedExt.set("cdb", ["img"]);
 		pairedExt.set("cdb", ["img"]);
+		pairedExt.set("xtra", ["fbx"]);
 		isFlash = Context.defined("flash");
 		isFlash = Context.defined("flash");
 		isJS = Context.defined("js");
 		isJS = Context.defined("js");
 	}
 	}
@@ -310,7 +311,7 @@ class FileTree {
 		switch( ext.toLowerCase() ) {
 		switch( ext.toLowerCase() ) {
 		case "jpg", "png":
 		case "jpg", "png":
 			return { e : macro loader.loadImage($epath), t : macro : hxd.res.Image };
 			return { e : macro loader.loadImage($epath), t : macro : hxd.res.Image };
-		case "fbx", "xbx":
+		case "fbx", "xbx", "xtra":
 			return { e : macro loader.loadFbxModel($epath), t : macro : hxd.res.FbxModel };
 			return { e : macro loader.loadFbxModel($epath), t : macro : hxd.res.FbxModel };
 		case "awd":
 		case "awd":
 			return { e : macro loader.loadAwdModel($epath), t : macro : hxd.res.AwdModel };
 			return { e : macro loader.loadAwdModel($epath), t : macro : hxd.res.AwdModel };