Pārlūkot izejas kodu

added SCN serialization support (requires -lib hxbit)

Nicolas Cannasse 8 gadi atpakaļ
vecāks
revīzija
32ac3cfdd5

+ 6 - 0
h3d/impl/MacroHelper.hx

@@ -28,4 +28,10 @@ class MacroHelper {
 
 
 #end
 #end
 
 
+	public static macro function getResourcesPath() {
+		var dir = haxe.macro.Context.definedValue("resourcesPath");
+		if( dir == null ) dir = "res";
+		return macro $v{try Context.resolvePath(dir) catch( e : Dynamic ) null};
+	}
+
 }
 }

+ 204 - 0
h3d/impl/Serializable.hx

@@ -0,0 +1,204 @@
+package h3d.impl;
+
+#if !hxbit
+private interface EmptyInterface {}
+#end
+
+typedef Serializable = #if hxbit hxbit.Serializable #else EmptyInterface #end;
+
+#if hxbit
+class SceneSerializer extends hxbit.Serializer {
+
+	public var materialRef = new Map<String,h3d.mat.Material>();
+
+	var version = 0;
+
+	var resPath : String = MacroHelper.getResourcesPath();
+	var shaderVarIndex : Int;
+	var shaderUID = 0;
+	var shaderIndexes = new Map<hxsl.Shader,Int>();
+	var cachedShaders = new Array<hxsl.Shader>();
+
+	function addTexture( t : h3d.mat.Texture ) {
+		if( t == null ) {
+			addInt(0);
+			return true;
+		}
+		if( t.name != null ) {
+			addInt(1);
+			addString(t.name);
+			return true;
+		}
+		return false;
+	}
+
+	function getTexture() {
+		switch( getInt() ) {
+		case 0:
+			return null;
+		case 1:
+			return resolveTexture(getString());
+		default:
+			throw "assert";
+		}
+	}
+
+	function resolveTexture( path : String ) {
+		return hxd.res.Loader.currentInstance.load(path).toTexture();
+	}
+
+	public function loadHMD( path : String ) {
+		return hxd.res.Loader.currentInstance.load(path).toHmd();
+	}
+
+	public function addShader( s : hxsl.Shader ) {
+		if( s == null ) {
+			addInt(0);
+			return;
+		}
+		var id = shaderIndexes.get(s);
+		if( id != null ) {
+			addInt(id);
+			return;
+		}
+		id = ++shaderUID;
+		shaderIndexes.set(s, id);
+		addInt(id);
+		addString(Type.getClassName(Type.getClass(s)));
+		shaderVarIndex = 0;
+		for( v in @:privateAccess s.shader.data.vars )
+			addShaderVar(v, s);
+	}
+
+	public function getShader() {
+		var id = getInt();
+		if( id == 0 )
+			return null;
+		var s = cachedShaders[id];
+		if( s != null )
+			return s;
+		var sname = getString();
+		var cl : Class<hxsl.Shader> = cast Type.resolveClass(sname);
+		if( cl == null ) throw "Missing shader " + sname;
+		s = Type.createEmptyInstance(cl);
+		@:privateAccess s.initialize();
+		for( v in @:privateAccess s.shader.data.vars ) {
+			if( !canSerializeVar(v) ) continue;
+			var val : Dynamic = getShaderVar(v, s);
+			Reflect.setField(s, v.name+"__", val);
+		}
+		cachedShaders[id] = s;
+		return s;
+	}
+
+	function canSerializeVar( v : hxsl.Ast.TVar ) {
+		return v.kind == Param && (v.qualifiers == null || v.qualifiers.indexOf(Ignore) < 0);
+	}
+
+	function addShaderVar( v : hxsl.Ast.TVar, s : hxsl.Shader ) {
+		if( !canSerializeVar(v) )
+			return;
+		switch( v.type ) {
+		case TStruct(vl):
+			for( v in vl )
+				addShaderVar(v, s);
+			return;
+		default:
+		}
+		var val : Dynamic = s.getParamValue(shaderVarIndex++);
+		switch( v.type ) {
+		case TBool:
+			addBool(val);
+		case TInt:
+			addInt(val);
+		case TFloat:
+			addFloat(val);
+		case TVec(n, VFloat):
+			var v : h3d.Vector = val;
+			addFloat(v.x);
+			addFloat(v.y);
+			if( n >= 3 ) addFloat(v.z);
+			if( n >= 4 ) addFloat(v.w);
+		case TSampler2D:
+			if( !addTexture(val) )
+				throw "Cannot serialize unnamed texture " + s+"."+v.name+" = "+val;
+		default:
+			throw "Cannot serialize macro var " + v.name+":"+hxsl.Ast.Tools.toString(v.type);
+		}
+	}
+
+	function getShaderVar( v : hxsl.Ast.TVar, s : hxsl.Shader ) : Dynamic {
+		switch( v.type ) {
+		case TStruct(vl):
+			var obj = {};
+			for( v in vl ) {
+				if( !canSerializeVar(v) ) continue;
+				Reflect.setField(obj, v.name, getShaderVar(v, s));
+			}
+			return obj;
+		default:
+		}
+		switch( v.type ) {
+		case TBool:
+			return getBool();
+		case TFloat:
+			return getFloat();
+		case TInt:
+			return getInt();
+		case TVec(n, VFloat):
+			var v = new h3d.Vector(getFloat(), getFloat());
+			if( n >= 3 ) v.z = getFloat();
+			if( n >= 4 ) v.w = getFloat();
+			return v;
+		case TSampler2D:
+			return getTexture();
+		default:
+			throw "Cannot unserialize macro var " + v.name+":"+hxsl.Ast.Tools.toString(v.type);
+		}
+	}
+
+	function initSCNPaths( resPath : String, projectPath : String ) {
+		this.resPath = resPath;
+	}
+
+	public function loadSCN( bytes ) {
+		setInput(bytes, 0);
+		if( getString() != "SCN" )
+			throw "Invalid SCN file";
+		version = getInt();
+		beginLoad(bytes, inPos);
+		initSCNPaths(getString(), getString());
+		var objs = [];
+		for( i in 0...getInt() ) {
+			var obj : h3d.scene.Object = cast getAnyRef();
+			objs.push(obj);
+		}
+		endLoad();
+		return { content : objs };
+	}
+
+	public function saveSCN( obj : h3d.scene.Object, includeRoot : Bool ) {
+		begin();
+		addString("SCN");
+		addInt(version); // version
+
+		var pos = out.length;
+		usedClasses = [];
+		addString(resPath);
+		#if sys
+		addString(Sys.getCwd());
+		#else
+		addString(null);
+		#end
+
+		var objs = includeRoot ? [obj] : [for( o in obj ) o];
+		objs = [for( o in obj ) if( @:privateAccess !o.flags.has(FNoSerialize) ) o];
+		addInt(objs.length);
+		for( o in objs )
+			addAnyRef(o);
+
+		return endSave(pos);
+	}
+
+}
+#end

+ 3 - 3
h3d/mat/BaseMaterial.hx

@@ -2,10 +2,10 @@ package h3d.mat;
 import h3d.mat.Data;
 import h3d.mat.Data;
 import h3d.mat.Pass;
 import h3d.mat.Pass;
 
 
-class BaseMaterial {
+class BaseMaterial implements h3d.impl.Serializable {
 
 
-	var passes : Pass;
-	public var name : String;
+	@:s var passes : Pass;
+	@:s public var name : String;
 	public var mainPass(get, never) : Pass;
 	public var mainPass(get, never) : Pass;
 
 
 	public var props(default,set) : MaterialProps;
 	public var props(default,set) : MaterialProps;

+ 10 - 0
h3d/mat/Material.hx

@@ -166,4 +166,14 @@ class Material extends BaseMaterial {
 		return t;
 		return t;
 	}
 	}
 
 
+	#if hxbit
+	function customSerialize( ctx : hxbit.Serializer ) {
+	}
+	function customUnserialize( ctx : hxbit.Serializer ) {
+		var last = mainPass.shaders;
+		while( last.next != null ) last = last.next;
+		mshader = cast last.s;
+	}
+	#end
+
 }
 }

+ 38 - 8
h3d/mat/Pass.hx

@@ -3,22 +3,22 @@ import h3d.mat.Data;
 
 
 @:allow(h3d.mat.BaseMaterial)
 @:allow(h3d.mat.BaseMaterial)
 @:build(hxd.impl.BitsBuilder.build())
 @:build(hxd.impl.BitsBuilder.build())
-class Pass {
+class Pass implements h3d.impl.Serializable {
 
 
-	public var name(default, null) : String;
+	@:s public var name(default, null) : String;
 	var passId : Int;
 	var passId : Int;
-	var bits : Int = 0;
-	var parentPass : Pass;
+	@:s var bits : Int = 0;
+	@:s var parentPass : Pass;
 	var parentShaders : hxsl.ShaderList;
 	var parentShaders : hxsl.ShaderList;
 	var shaders : hxsl.ShaderList;
 	var shaders : hxsl.ShaderList;
-	var nextPass : Pass;
+	@:s var nextPass : Pass;
 
 
-	public var enableLights : Bool;
+	@:s public var enableLights : Bool;
 	/**
 	/**
 		Inform the pass system that the parameters will be modified in object draw() command,
 		Inform the pass system that the parameters will be modified in object draw() command,
 		so they will be manually uploaded by calling RenderContext.uploadParams.
 		so they will be manually uploaded by calling RenderContext.uploadParams.
 	**/
 	**/
-	public var dynamicParameters : Bool;
+	@:s public var dynamicParameters : Bool;
 
 
 	@:bits(bits) public var culling : Face;
 	@:bits(bits) public var culling : Face;
 	@:bits(bits) public var depthWrite : Bool;
 	@:bits(bits) public var depthWrite : Bool;
@@ -31,7 +31,7 @@ class Pass {
 	@:bits(bits) public var blendAlphaOp : Operation;
 	@:bits(bits) public var blendAlphaOp : Operation;
 	@:bits(bits, 4) public var colorMask : Int;
 	@:bits(bits, 4) public var colorMask : Int;
 
 
-	public var stencil : Stencil;
+	@:s public var stencil : Stencil;
 
 
 	public function new(name, ?shaders, ?parent) {
 	public function new(name, ?shaders, ?parent) {
 		this.parentPass = parent;
 		this.parentPass = parent;
@@ -188,4 +188,34 @@ class Pass {
 		return "VERTEX=\n" + toString(shader.vertex.data) + "\n\nFRAGMENT=\n" + toString(shader.fragment.data);
 		return "VERTEX=\n" + toString(shader.vertex.data) + "\n\nFRAGMENT=\n" + toString(shader.fragment.data);
 	}
 	}
 
 
+	#if hxbit
+
+	public function customSerialize( ctx : hxbit.Serializer ) {
+		var ctx : h3d.impl.Serializable.SceneSerializer = cast ctx;
+		var s = shaders;
+		while( s != parentShaders ) {
+			ctx.addShader(s.s);
+			s = s.next;
+		}
+		ctx.addShader(null);
+	}
+	public function customUnserialize( ctx : hxbit.Serializer ) {
+		var ctx : h3d.impl.Serializable.SceneSerializer = cast ctx;
+		var head = null;
+		while( true ) {
+			var s = ctx.getShader();
+			if( s == null ) break;
+			var sl = new hxsl.ShaderList(s);
+			if( head == null ) {
+				head = shaders = sl;
+			} else {
+				head.next = sl;
+				head = sl;
+			}
+		}
+		setPassName(name);
+		//loadBits(bits);
+	}
+	#end
+
 }
 }

+ 12 - 2
h3d/mat/Stencil.hx

@@ -3,8 +3,8 @@ import h3d.mat.Data;
 
 
 @:allow(h3d.mat.Material)
 @:allow(h3d.mat.Material)
 @:build(hxd.impl.BitsBuilder.build())
 @:build(hxd.impl.BitsBuilder.build())
-class Stencil
-{
+class Stencil implements h3d.impl.Serializable {
+
 	var frontRefBits : Int = 0;
 	var frontRefBits : Int = 0;
 	var backRefBits  : Int = 0;
 	var backRefBits  : Int = 0;
 	var opBits       : Int = 0;
 	var opBits       : Int = 0;
@@ -98,4 +98,14 @@ class Stencil
 		opBits = s.opBits;
 		opBits = s.opBits;
 	}
 	}
 
 
+	#if hxbit
+	public function customSerialize( ctx : hxbit.Serializer ) {
+	}
+	public function customUnserialize( ctx : hxbit.Serializer ) {
+		//loadFrontRefBits(frontRefBits);
+		//loadBackRefBits(backRefBits);
+		//loadOpBits(opBits);
+	}
+	#end
+
 }
 }

+ 3 - 3
h3d/prim/Cube.hx

@@ -3,9 +3,9 @@ import h3d.col.Point;
 
 
 class Cube extends Polygon {
 class Cube extends Polygon {
 
 
-	var sizeX : Float;
-	var sizeY : Float;
-	var sizeZ : Float;
+	@:s var sizeX : Float;
+	@:s var sizeY : Float;
+	@:s var sizeZ : Float;
 
 
 	public function new( x = 1., y = 1., z = 1. )
 	public function new( x = 1., y = 1., z = 1. )
 	{
 	{

+ 24 - 0
h3d/prim/HMDModel.hx

@@ -159,4 +159,28 @@ class HMDModel extends MeshPrimitive {
 		return collider;
 		return collider;
 	}
 	}
 
 
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		ctx.addString(@:privateAccess lib.entry.path);
+		for( m in lib.header.models )
+			if( lib.header.geometries[m.geometry] == this.data ) {
+				ctx.addString(m.name);
+				break;
+			}
+	}
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		var libPath = ctx.getString();
+		var modelPath = ctx.getString();
+		var ctx : h3d.impl.Serializable.SceneSerializer = cast ctx;
+		lib = ctx.loadHMD(libPath);
+		for( m in lib.header.models )
+			if( m.name == modelPath ) {
+				this.data = lib.header.geometries[m.geometry];
+				@:privateAccess lib.cachedPrimitives[m.geometry] = this;
+				break;
+			}
+		dataPosition = lib.header.dataPosition;
+	}
+	#end
+
 }
 }

+ 68 - 4
h3d/prim/Polygon.hx

@@ -8,10 +8,10 @@ class Polygon extends Primitive {
 	public var uvs : Array<UV>;
 	public var uvs : Array<UV>;
 	public var idx : hxd.IndexBuffer;
 	public var idx : hxd.IndexBuffer;
 	public var colors : Array<Point>;
 	public var colors : Array<Point>;
-	var scaled = 1.;
-	var translatedX = 0.;
-	var translatedY = 0.;
-	var translatedZ = 0.;
+	@:s var scaled = 1.;
+	@:s var translatedX = 0.;
+	@:s var translatedY = 0.;
+	@:s var translatedZ = 0.;
 
 
 	public function new( points, ?idx ) {
 	public function new( points, ?idx ) {
 		this.points = points;
 		this.points = points;
@@ -194,4 +194,68 @@ class Polygon extends Primitive {
 		return poly;
 		return poly;
 	}
 	}
 
 
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		ctx.addInt(points.length);
+		for( p in points ) {
+			ctx.addDouble(p.x);
+			ctx.addDouble(p.y);
+			ctx.addDouble(p.z);
+		}
+		if( normals == null )
+			ctx.addInt(0);
+		else {
+			ctx.addInt(normals.length);
+			for( p in normals ) {
+				ctx.addDouble(p.x);
+				ctx.addDouble(p.y);
+				ctx.addDouble(p.z);
+			}
+		}
+		if( uvs == null )
+			ctx.addInt(0);
+		else {
+			ctx.addInt(uvs.length);
+			for( uv in uvs ) {
+				ctx.addDouble(uv.u);
+				ctx.addDouble(uv.v);
+			}
+		}
+		if( idx == null )
+			ctx.addInt(0);
+		else {
+			ctx.addInt(idx.length);
+			for( i in idx )
+				ctx.addInt(i);
+		}
+		if( colors == null )
+			ctx.addInt(0);
+		else {
+			ctx.addInt(colors.length);
+			for( c in colors ) {
+				ctx.addDouble(c.x);
+				ctx.addDouble(c.y);
+				ctx.addDouble(c.z);
+			}
+		}
+	}
+
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		points = [for( i in 0...ctx.getInt() ) new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())];
+		normals = [for( i in 0...ctx.getInt() ) new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())];
+		uvs = [for( i in 0...ctx.getInt() ) new UV(ctx.getDouble(), ctx.getDouble())];
+		if( normals.length == 0 ) normals = null;
+		if( uvs.length == 0 ) uvs = null;
+		var nindex = ctx.getInt();
+		if( nindex > 0 ) {
+			idx = new hxd.IndexBuffer();
+			idx.grow(nindex);
+			for( i in 0...nindex )
+				idx[i] = ctx.getInt();
+		}
+		colors = [for( i in 0...ctx.getInt() ) new h3d.col.Point(ctx.getDouble(), ctx.getDouble(), ctx.getDouble())];
+		if( colors.length == 0 ) colors = null;
+	}
+	#end
+
 }
 }

+ 14 - 1
h3d/prim/Primitive.hx

@@ -1,6 +1,6 @@
 package h3d.prim;
 package h3d.prim;
 
 
-class Primitive {
+class Primitive implements h3d.impl.Serializable {
 
 
 	public var buffer : Buffer;
 	public var buffer : Buffer;
 	public var indexes : Indexes;
 	public var indexes : Indexes;
@@ -57,4 +57,17 @@ class Primitive {
 		}
 		}
 	}
 	}
 
 
+	public function toString() {
+		return Type.getClassName(Type.getClass(this)).split(".").pop();
+	}
+
+	#if hxbit
+	function customSerialize( ctx : hxbit.Serializer ) {
+		throw "Cannot serialize " + toString();
+	}
+	function customUnserialize( ctx : hxbit.Serializer ) {
+		throw "customUnserialize not implemented on " + toString();
+	}
+	#end
+
 }
 }

+ 3 - 4
h3d/prim/Sphere.hx

@@ -3,9 +3,9 @@ import h3d.col.Point;
 
 
 class Sphere extends Polygon {
 class Sphere extends Polygon {
 
 
-	var ray : Float;
-	var segsH : Int;
-	var segsW : Int;
+	@:s var ray : Float;
+	@:s var segsH : Int;
+	@:s var segsW : Int;
 
 
 	public function new( ray = 1., segsW = 8, segsH = 6 ) {
 	public function new( ray = 1., segsW = 8, segsH = 6 ) {
 		this.ray = ray;
 		this.ray = ray;
@@ -66,4 +66,3 @@ class Sphere extends Polygon {
 	}
 	}
 
 
 }
 }
-

+ 1 - 0
h3d/scene/CameraController.hx

@@ -28,6 +28,7 @@ class CameraController extends h3d.scene.Object {
 	public function new(?distance,?parent) {
 	public function new(?distance,?parent) {
 		super(parent);
 		super(parent);
 		set(distance);
 		set(distance);
+		flags.set(FNoSerialize,true);
 		toTarget();
 		toTarget();
 	}
 	}
 
 

+ 14 - 0
h3d/scene/DirLight.hx

@@ -30,4 +30,18 @@ class DirLight extends Light {
 		super.emit(ctx);
 		super.emit(ctx);
 	}
 	}
 
 
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		super.customSerialize(ctx);
+		ctx.addDouble(direction.x);
+		ctx.addDouble(direction.y);
+		ctx.addDouble(direction.z);
+	}
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		shader = dshader = new h3d.shader.DirLight();
+		super.customUnserialize(ctx);
+		direction = new h3d.Vector(ctx.getDouble(), ctx.getDouble(), ctx.getDouble());
+	}
+	#end
+
 }
 }

+ 19 - 2
h3d/scene/Light.hx

@@ -4,11 +4,11 @@ class Light extends Object {
 
 
 	var shader : hxsl.Shader;
 	var shader : hxsl.Shader;
 	var objectDistance : Float; // used internaly
 	var objectDistance : Float; // used internaly
-	var cullingDistance : Float = 1e10;
+	@:s var cullingDistance : Float = 1e10;
 	@:noCompletion public var next : Light;
 	@:noCompletion public var next : Light;
 
 
+	@:s public var priority : Int = 0;
 	public var color(get, never) : h3d.Vector;
 	public var color(get, never) : h3d.Vector;
-	public var priority : Int = 0;
 	public var enableSpecular(get, set) : Bool;
 	public var enableSpecular(get, set) : Bool;
 
 
 	function new(shader,?parent) {
 	function new(shader,?parent) {
@@ -34,4 +34,21 @@ class Light extends Object {
 		ctx.emitLight(this);
 		ctx.emitLight(this);
 	}
 	}
 
 
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		super.customSerialize(ctx);
+		ctx.addDouble(color.x);
+		ctx.addDouble(color.y);
+		ctx.addDouble(color.z);
+		ctx.addDouble(color.w);
+		ctx.addBool(enableSpecular);
+	}
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		super.customUnserialize(ctx);
+		color.set(ctx.getDouble(), ctx.getDouble(), ctx.getDouble(), ctx.getDouble());
+		enableSpecular = ctx.getBool();
+	}
+	#end
+
+
 }
 }

+ 14 - 0
h3d/scene/Mesh.hx

@@ -58,4 +58,18 @@ class Mesh extends Object {
 		if( primitive != null ) primitive.dispose();
 		if( primitive != null ) primitive.dispose();
 		super.dispose();
 		super.dispose();
 	}
 	}
+
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		super.customSerialize(ctx);
+		ctx.addKnownRef(primitive);
+		ctx.addKnownRef(material);
+	}
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		super.customUnserialize(ctx);
+		primitive = ctx.getKnownRef(h3d.prim.Primitive);
+		material = ctx.getKnownRef(h3d.mat.Material);
+	}
+	#end
+
 }
 }

+ 14 - 1
h3d/scene/MultiMaterial.hx

@@ -37,7 +37,7 @@ class MultiMaterial extends Mesh {
 		for( m in materials )
 		for( m in materials )
 			if( m != null )
 			if( m != null )
 				a.push(m);
 				a.push(m);
-		for( o in childs )
+		for( o in children )
 			o.getMaterials(a);
 			o.getMaterials(a);
 		return a;
 		return a;
 	}
 	}
@@ -48,4 +48,17 @@ class MultiMaterial extends Mesh {
 		super.draw(ctx);
 		super.draw(ctx);
 	}
 	}
 
 
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		super.customSerialize(ctx);
+		ctx.addInt(materials.length);
+		for( m in materials ) ctx.addKnownRef(m);
+	}
+
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		super.customUnserialize(ctx);
+		materials = [for( i in 0...ctx.getInt() ) ctx.getKnownRef(h3d.mat.Material)];
+	}
+	#end
+
 }
 }

+ 71 - 42
h3d/scene/Object.hx

@@ -9,6 +9,7 @@ package h3d.scene;
 	public var FAllocated = 32;
 	public var FAllocated = 32;
 	public var FAlwaysSync = 64;
 	public var FAlwaysSync = 64;
 	public var FInheritCulled = 128;
 	public var FInheritCulled = 128;
+	public var FNoSerialize = 256;
 	public inline function new() {
 	public inline function new() {
 		this = 0;
 		this = 0;
 	}
 	}
@@ -20,29 +21,29 @@ package h3d.scene;
 	}
 	}
 }
 }
 
 
-class Object {
+class Object implements h3d.impl.Serializable {
 
 
 	static inline var ROT2RAD = -0.017453292519943295769236907684886;
 	static inline var ROT2RAD = -0.017453292519943295769236907684886;
 
 
-	var flags : ObjectFlags;
-	var childs : Array<Object>;
+	@:s var flags : ObjectFlags;
+	var children : Array<Object>;
 	public var parent(default, null) : Object;
 	public var parent(default, null) : Object;
 	public var numChildren(get, never) : Int;
 	public var numChildren(get, never) : Int;
 
 
-	public var name : Null<String>;
-	public var x(default,set) : Float;
-	public var y(default, set) : Float;
-	public var z(default, set) : Float;
-	public var scaleX(default,set) : Float;
-	public var scaleY(default, set) : Float;
-	public var scaleZ(default,set) : Float;
+	@:s public var name : Null<String>;
+	@:s public var x(default,set) : Float;
+	@:s public var y(default, set) : Float;
+	@:s public var z(default, set) : Float;
+	@:s public var scaleX(default,set) : Float;
+	@:s public var scaleY(default, set) : Float;
+	@:s public var scaleZ(default,set) : Float;
 	public var visible(get, set) : Bool;
 	public var visible(get, set) : Bool;
 	var allocated(get,set) : Bool;
 	var allocated(get,set) : Bool;
 
 
 	/**
 	/**
 		Follow a given object or joint as if it was our parent. Ignore defaultTransform when set.
 		Follow a given object or joint as if it was our parent. Ignore defaultTransform when set.
 	**/
 	**/
-	public var follow(default, set) : Object;
+	@:s public var follow(default, set) : Object;
 	public var followPositionOnly(get, set) : Bool;
 	public var followPositionOnly(get, set) : Bool;
 
 
 	/**
 	/**
@@ -88,7 +89,7 @@ class Object {
 		qRot = new h3d.Quat();
 		qRot = new h3d.Quat();
 		posChanged = false;
 		posChanged = false;
 		visible = true;
 		visible = true;
-		childs = [];
+		children = [];
 		if( parent != null )
 		if( parent != null )
 			parent.addChild(this);
 			parent.addChild(this);
 	}
 	}
@@ -145,19 +146,19 @@ class Object {
 			defaultTransform = null;
 			defaultTransform = null;
 		}
 		}
 		if( recursive )
 		if( recursive )
-			for( c in childs )
+			for( c in children )
 				c.applyAnimationTransform();
 				c.applyAnimationTransform();
 	}
 	}
 
 
 	public function getObjectsCount() {
 	public function getObjectsCount() {
 		var k = 0;
 		var k = 0;
-		for( c in childs )
+		for( c in children )
 			k += c.getObjectsCount() + 1;
 			k += c.getObjectsCount() + 1;
 		return k;
 		return k;
 	}
 	}
 
 
 	public function getMaterialByName( name : String ) : h3d.mat.Material {
 	public function getMaterialByName( name : String ) : h3d.mat.Material {
-		for( o in childs ) {
+		for( o in children ) {
 			var m = o.getMaterialByName(name);
 			var m = o.getMaterialByName(name);
 			if( m != null ) return m;
 			if( m != null ) return m;
 		}
 		}
@@ -166,7 +167,7 @@ class Object {
 
 
 	public function getMaterials( ?a : Array<h3d.mat.Material> ) {
 	public function getMaterials( ?a : Array<h3d.mat.Material> ) {
 		if( a == null ) a = [];
 		if( a == null ) a = [];
-		for( o in childs )
+		for( o in children )
 			o.getMaterials(a);
 			o.getMaterials(a);
 		return a;
 		return a;
 	}
 	}
@@ -212,12 +213,12 @@ class Object {
 		if( b == null )
 		if( b == null )
 			b = new h3d.col.Bounds();
 			b = new h3d.col.Bounds();
 		if( posChanged ) {
 		if( posChanged ) {
-			for( c in childs )
+			for( c in children )
 				c.posChanged = true;
 				c.posChanged = true;
 			posChanged = false;
 			posChanged = false;
 			calcAbsPos();
 			calcAbsPos();
 		}
 		}
-		for( c in childs )
+		for( c in children )
 			c.getBounds(b, true);
 			c.getBounds(b, true);
 		return b;
 		return b;
 	}
 	}
@@ -226,7 +227,7 @@ class Object {
 		if( out == null ) out = [];
 		if( out == null ) out = [];
 		var m = Std.instance(this, Mesh);
 		var m = Std.instance(this, Mesh);
 		if( m != null ) out.push(m);
 		if( m != null ) out.push(m);
-		for( c in childs )
+		for( c in children )
 			c.getMeshes(out);
 			c.getMeshes(out);
 		return out;
 		return out;
 	}
 	}
@@ -234,7 +235,7 @@ class Object {
 	public function getObjectByName( name : String ) {
 	public function getObjectByName( name : String ) {
 		if( this.name == name )
 		if( this.name == name )
 			return this;
 			return this;
-		for( c in childs ) {
+		for( c in children ) {
 			var o = c.getObjectByName(name);
 			var o = c.getObjectByName(name);
 			if( o != null ) return o;
 			if( o != null ) return o;
 		}
 		}
@@ -258,21 +259,21 @@ class Object {
 		o.visible = visible;
 		o.visible = visible;
 		if( defaultTransform != null )
 		if( defaultTransform != null )
 			o.defaultTransform = defaultTransform.clone();
 			o.defaultTransform = defaultTransform.clone();
-		for( c in childs ) {
+		for( c in children ) {
 			var c = c.clone();
 			var c = c.clone();
 			c.parent = o;
 			c.parent = o;
-			o.childs.push(c);
+			o.children.push(c);
 		}
 		}
 		return o;
 		return o;
 	}
 	}
 
 
 	public function addChild( o : Object ) {
 	public function addChild( o : Object ) {
-		addChildAt(o, childs.length);
+		addChildAt(o, children.length);
 	}
 	}
 
 
 	public function addChildAt( o : Object, pos : Int ) {
 	public function addChildAt( o : Object, pos : Int ) {
 		if( pos < 0 ) pos = 0;
 		if( pos < 0 ) pos = 0;
-		if( pos > childs.length ) pos = childs.length;
+		if( pos > children.length ) pos = children.length;
 		var p = this;
 		var p = this;
 		while( p != null ) {
 		while( p != null ) {
 			if( p == o ) throw "Recursive addChild";
 			if( p == o ) throw "Recursive addChild";
@@ -285,7 +286,7 @@ class Object {
 			o.parent.removeChild(o);
 			o.parent.removeChild(o);
 			o.allocated = old;
 			o.allocated = old;
 		}
 		}
-		childs.insert(pos, o);
+		children.insert(pos, o);
 		if( !allocated && o.allocated )
 		if( !allocated && o.allocated )
 			o.onRemove();
 			o.onRemove();
 		o.parent = this;
 		o.parent = this;
@@ -306,31 +307,31 @@ class Object {
 			var m = Std.instance(this, Mesh);
 			var m = Std.instance(this, Mesh);
 			if( m != null ) callb(m);
 			if( m != null ) callb(m);
 		}
 		}
-		for( o in childs )
+		for( o in children )
 			o.iterVisibleMeshes(callb);
 			o.iterVisibleMeshes(callb);
 	}
 	}
 
 
 	function onParentChanged() {
 	function onParentChanged() {
-		for( c in childs )
+		for( c in children )
 			c.onParentChanged();
 			c.onParentChanged();
 	}
 	}
 
 
 	// kept for internal init
 	// kept for internal init
 	function onAdd() {
 	function onAdd() {
 		allocated = true;
 		allocated = true;
-		for( c in childs )
+		for( c in children )
 			c.onAdd();
 			c.onAdd();
 	}
 	}
 
 
 	// kept for internal cleanup
 	// kept for internal cleanup
 	function onRemove() {
 	function onRemove() {
 		allocated = false;
 		allocated = false;
-		for( c in childs )
+		for( c in children )
 			c.onRemove();
 			c.onRemove();
 	}
 	}
 
 
 	public function removeChild( o : Object ) {
 	public function removeChild( o : Object ) {
-		if( childs.remove(o) ) {
+		if( children.remove(o) ) {
 			if( o.allocated ) o.onRemove();
 			if( o.allocated ) o.onRemove();
 			o.parent = null;
 			o.parent = null;
 			o.posChanged = true;
 			o.posChanged = true;
@@ -364,7 +365,7 @@ class Object {
 
 
 	public function getCollider() : h3d.col.Collider {
 	public function getCollider() : h3d.col.Collider {
 		var colliders = [];
 		var colliders = [];
-		for( obj in childs ) {
+		for( obj in children ) {
 			var c = obj.getCollider();
 			var c = obj.getCollider();
 			var cgrp = Std.instance(c, h3d.col.Collider.GroupCollider);
 			var cgrp = Std.instance(c, h3d.col.Collider.GroupCollider);
 			if( cgrp != null ) {
 			if( cgrp != null ) {
@@ -448,9 +449,9 @@ class Object {
 		sync(ctx);
 		sync(ctx);
 		posChanged = false;
 		posChanged = false;
 		lastFrame = ctx.frame;
 		lastFrame = ctx.frame;
-		var p = 0, len = childs.length;
+		var p = 0, len = children.length;
 		while( p < len ) {
 		while( p < len ) {
-			var c = childs[p];
+			var c = children[p];
 			if( c == null )
 			if( c == null )
 				break;
 				break;
 			if( c.lastFrame != ctx.frame ) {
 			if( c.lastFrame != ctx.frame ) {
@@ -459,9 +460,9 @@ class Object {
 			}
 			}
 			// if the object was removed, let's restart again.
 			// if the object was removed, let's restart again.
 			// our lastFrame ensure that no object will get synched twice
 			// our lastFrame ensure that no object will get synched twice
-			if( childs[p] != c ) {
+			if( children[p] != c ) {
 				p = 0;
 				p = 0;
-				len = childs.length;
+				len = children.length;
 			} else
 			} else
 				p++;
 				p++;
 		}
 		}
@@ -473,7 +474,7 @@ class Object {
 		if( posChanged ) {
 		if( posChanged ) {
 			posChanged = false;
 			posChanged = false;
 			calcAbsPos();
 			calcAbsPos();
-			for( c in childs )
+			for( c in children )
 				c.posChanged = true;
 				c.posChanged = true;
 		}
 		}
 	}
 	}
@@ -491,12 +492,12 @@ class Object {
 			if( currentAnimation != null ) currentAnimation.sync();
 			if( currentAnimation != null ) currentAnimation.sync();
 			posChanged = false;
 			posChanged = false;
 			calcAbsPos();
 			calcAbsPos();
-			for( c in childs )
+			for( c in children )
 				c.posChanged = true;
 				c.posChanged = true;
 		}
 		}
 		if( !culled )
 		if( !culled )
 			emit(ctx);
 			emit(ctx);
-		for( c in childs )
+		for( c in children )
 			c.emitRec(ctx);
 			c.emitRec(ctx);
 	}
 	}
 
 
@@ -597,20 +598,48 @@ class Object {
 	}
 	}
 
 
 	public inline function getChildAt( n ) {
 	public inline function getChildAt( n ) {
-		return childs[n];
+		return children[n];
 	}
 	}
 
 
 	inline function get_numChildren() {
 	inline function get_numChildren() {
-		return childs.length;
+		return children.length;
 	}
 	}
 
 
 	public inline function iterator() : hxd.impl.ArrayIterator<Object> {
 	public inline function iterator() : hxd.impl.ArrayIterator<Object> {
-		return new hxd.impl.ArrayIterator(childs);
+		return new hxd.impl.ArrayIterator(children);
 	}
 	}
 
 
 	public function dispose() {
 	public function dispose() {
-		for( c in childs )
+		for( c in children )
 			c.dispose();
 			c.dispose();
 	}
 	}
 
 
+	#if hxbit
+	function customSerialize( ctx : hxbit.Serializer ) {
+
+		var children = [for( o in children ) if( !o.flags.has(FNoSerialize) ) o];
+		ctx.addInt(children.length);
+		for( o in children )
+			ctx.addKnownRef(o);
+
+		ctx.addDouble(qRot.x);
+		ctx.addDouble(qRot.y);
+		ctx.addDouble(qRot.z);
+		ctx.addDouble(qRot.w);
+		// defaultTransform
+		// currentAnimation
+	}
+
+	function customUnserialize( ctx : hxbit.Serializer ) {
+		children = [for( i in 0...ctx.getInt() ) ctx.getKnownRef(Object)];
+		qRot = new h3d.Quat(ctx.getDouble(),ctx.getDouble(),ctx.getDouble(),ctx.getDouble());
+		for( c in children )
+			c.parent = this;
+		allocated = false;
+		posChanged = true;
+		absPos = new h3d.Matrix();
+		absPos.identity();
+	}
+	#end
+
 }
 }

+ 6 - 0
h3d/scene/Scene.hx

@@ -375,4 +375,10 @@ class Scene extends Object implements h3d.IDrawable implements hxd.SceneEvents.I
 		ctx.engine = null;
 		ctx.engine = null;
 	}
 	}
 
 
+	#if hxbit
+	override function customSerialize(ctx:hxbit.Serializer) {
+		throw this + " should not be serialized";
+	}
+	#end
+
 }
 }

+ 40 - 16
h3d/scene/Skin.hx

@@ -126,25 +126,27 @@ class Skin extends MultiMaterial {
 		return skinData;
 		return skinData;
 	}
 	}
 
 
-	public function setSkinData( s ) {
+	public function setSkinData( s, shaderInit = true ) {
 		skinData = s;
 		skinData = s;
 		jointsUpdated = true;
 		jointsUpdated = true;
 		primitive = s.primitive;
 		primitive = s.primitive;
-		skinShader = new h3d.shader.Skin();
-		var maxBones = 0;
-		if( skinData.splitJoints != null ) {
-			for( s in skinData.splitJoints )
-				if( s.joints.length > maxBones )
-					maxBones = s.joints.length;
-		} else
-			maxBones = skinData.boundJoints.length;
-		if( skinShader.MaxBones < maxBones )
-			skinShader.MaxBones = maxBones;
-		for( m in materials )
-			if( m != null ) {
-				m.mainPass.addShader(skinShader);
-				if( skinData.splitJoints != null ) m.mainPass.dynamicParameters = true;
-			}
+		if( shaderInit ) {
+			skinShader = new h3d.shader.Skin();
+			var maxBones = 0;
+			if( skinData.splitJoints != null ) {
+				for( s in skinData.splitJoints )
+					if( s.joints.length > maxBones )
+						maxBones = s.joints.length;
+			} else
+				maxBones = skinData.boundJoints.length;
+			if( skinShader.MaxBones < maxBones )
+				skinShader.MaxBones = maxBones;
+			for( m in materials )
+				if( m != null ) {
+					m.mainPass.addShader(skinShader);
+					if( skinData.splitJoints != null ) m.mainPass.dynamicParameters = true;
+				}
+		}
 		currentRelPose = [];
 		currentRelPose = [];
 		currentAbsPose = [];
 		currentAbsPose = [];
 		currentPalette = [];
 		currentPalette = [];
@@ -236,5 +238,27 @@ class Skin extends MultiMaterial {
 		}
 		}
 	}
 	}
 
 
+	#if hxbit
+	override function customUnserialize(ctx:hxbit.Serializer) {
+		super.customUnserialize(ctx);
+		var prim = Std.instance(primitive, h3d.prim.HMDModel);
+		if( prim == null ) throw "Cannot load skind primitive " + prim;
+		jointsUpdated = true;
+		skinShader = material.mainPass.getShader(h3d.shader.Skin);
+		@:privateAccess {
+			var lib = prim.lib;
+			for( m in lib.header.models )
+				if( lib.header.geometries[m.geometry] == prim.data ) {
+					var skinData = lib.makeSkin(m.skin);
+					skinData.primitive = prim;
+					setSkinData(skinData, false);
+					break;
+				}
+		}
+		for( p in material.getPasses() )
+			trace(p.name+":"+[for( s in p.getShaders() ) s.toString()]);
+	}
+	#end
+
 
 
 }
 }

+ 1 - 1
h3d/shader/Skin.hx

@@ -16,7 +16,7 @@ class Skin extends hxsl.Shader {
 		var transformedNormal : Vec3;
 		var transformedNormal : Vec3;
 
 
 		@const var MaxBones : Int;
 		@const var MaxBones : Int;
-		@param var bonesMatrixes : Array<Mat3x4,MaxBones>;
+		@ignore @param var bonesMatrixes : Array<Mat3x4,MaxBones>;
 
 
 		function vertex() {
 		function vertex() {
 			#if floatSkinIndexes
 			#if floatSkinIndexes

+ 0 - 18
hxd/App.hx

@@ -110,24 +110,6 @@ class App implements h3d.IDrawable {
 		if( isDisposed ) return;
 		if( isDisposed ) return;
 		s2d.setElapsedTime(Timer.tmod/60);
 		s2d.setElapsedTime(Timer.tmod/60);
 		s3d.setElapsedTime(Timer.tmod / 60);
 		s3d.setElapsedTime(Timer.tmod / 60);
-		#if debug
-		if( hxd.Key.isDown(hxd.Key.CTRL) && hxd.Key.isPressed(hxd.Key.F12) ) {
-			var driver = engine.driver;
-			var old = driver.logEnable;
-			var log = new h3d.impl.LogDriver(driver);
-			log.logLines = [];
-			engine.setDriver(log);
-			try {
-				engine.render(this);
-			} catch( e : Dynamic ) {
-				log.logLines.push(Std.string(e));
-			}
-			driver.logEnable = old;
-			engine.setDriver(driver);
-			hxd.File.saveBytes("log.txt", haxe.io.Bytes.ofString(log.logLines.join("\n")));
-			return;
-		}
-		#end
 		engine.render(this);
 		engine.render(this);
 	}
 	}
 
 

+ 1 - 1
hxd/inspect/ScenePanel.hx

@@ -38,7 +38,7 @@ private class SceneObject extends TreeNode {
 		var name = objectName(o);
 		var name = objectName(o);
 		if( o.parent == null )
 		if( o.parent == null )
 			return name;
 			return name;
-		var idx = Lambda.indexOf(@:privateAccess o.parent.childs, o);
+		var idx = Lambda.indexOf(@:privateAccess o.parent.children, o);
 		var count = 0;
 		var count = 0;
 		for( i in 0...idx )
 		for( i in 0...idx )
 			if( objectName(o.parent.getChildAt(i)) == name )
 			if( objectName(o.parent.getChildAt(i)) == name )

+ 8 - 0
hxsl/Shader.hx

@@ -11,6 +11,10 @@ class Shader {
 	var constModified : Bool;
 	var constModified : Bool;
 
 
 	public function new() {
 	public function new() {
+		initialize();
+	}
+
+	function initialize() {
 		var cl : Dynamic = std.Type.getClass(this);
 		var cl : Dynamic = std.Type.getClass(this);
 		shader = cl._SHADER;
 		shader = cl._SHADER;
 		constModified = true;
 		constModified = true;
@@ -88,4 +92,8 @@ class Shader {
 		return this;
 		return this;
 	}
 	}
 
 
+	public function toString() {
+		return std.Type.getClassName(std.Type.getClass(this));
+	}
+
 }
 }

+ 1 - 1
samples/Base3D.hx

@@ -1,6 +1,6 @@
 import h3d.scene.*;
 import h3d.scene.*;
 
 
-class Base3D extends hxd.App {
+class Base3D extends SampleApp {
 
 
 	var time : Float = 0.;
 	var time : Float = 0.;
 	var obj1 : Mesh;
 	var obj1 : Mesh;

+ 4 - 0
samples/Generator.hx

@@ -43,6 +43,8 @@ class Generator {
 		try sys.FileSystem.createDirectory("build") catch( e : Dynamic ) {};
 		try sys.FileSystem.createDirectory("build") catch( e : Dynamic ) {};
 		sys.io.File.saveContent("build/README.txt","This directory is automatically generated by samples/Script.hx using samples/templates");
 		sys.io.File.saveContent("build/README.txt","This directory is automatically generated by samples/Script.hx using samples/templates");
 
 
+		var hasHxBit = Sys.command("haxelib path hxbit") == 0;
+			
 		for( f in sys.FileSystem.readDirectory(".") ) {
 		for( f in sys.FileSystem.readDirectory(".") ) {
 
 
 			if( sys.FileSystem.isDirectory(f) || !StringTools.endsWith(f,".hx") )
 			if( sys.FileSystem.isDirectory(f) || !StringTools.endsWith(f,".hx") )
@@ -56,6 +58,8 @@ class Generator {
 			var params = [];
 			var params = [];
 			if( sys.FileSystem.exists(name+"_res") )
 			if( sys.FileSystem.exists(name+"_res") )
 				params.push("-D resourcesPath=../../"+name+"_res");
 				params.push("-D resourcesPath=../../"+name+"_res");
+			if( hasHxBit )
+				params.push("-lib hxbit");
 
 
 			var content = sys.io.File.getContent(f);
 			var content = sys.io.File.getContent(f);
 			~/\/\/PARAM=(.*)/g.map(content,function(r) { params.push(StringTools.trim(r.matched(1))); return ""; });
 			~/\/\/PARAM=(.*)/g.map(content,function(r) { params.push(StringTools.trim(r.matched(1))); return ""; });

+ 10 - 0
samples/SampleApp.hx

@@ -9,6 +9,16 @@ class SampleApp extends hxd.App {
 		fui.padding = 10;
 		fui.padding = 10;
 	}
 	}
 
 
+	#if hxbit
+	override function mainLoop() {
+		if( hxd.Key.isDown(hxd.Key.CTRL) && hxd.Key.isPressed("S".code) ) {
+			var bytes = new h3d.impl.Serializable.SceneSerializer().saveSCN(s3d,false);
+			hxd.File.saveBytes("scene.scn", bytes);
+		}
+		super.mainLoop();
+	}
+	#end
+
 	function getFont() {
 	function getFont() {
 		return hxd.res.DefaultFont.get();
 		return hxd.res.DefaultFont.get();
 	}
 	}

+ 1 - 38
samples/Skin.hx

@@ -1,6 +1,6 @@
 import h3d.scene.*;
 import h3d.scene.*;
 
 
-class Skin extends hxd.App {
+class Skin extends SampleApp {
 
 
 	var cache : h3d.prim.ModelCache;
 	var cache : h3d.prim.ModelCache;
 
 
@@ -31,43 +31,6 @@ class Skin extends hxd.App {
 		dir.enableSpecular = true;
 		dir.enableSpecular = true;
 
 
 		new h3d.scene.CameraController(s3d).loadFromCamera();
 		new h3d.scene.CameraController(s3d).loadFromCamera();
-
-		#if hxbit
-		// this is an example for connecting to scene inspector
-		// and enable extra properties
-		// this requires to compile with -lib hxbit and run http://castledb.org
-		var i = new hxd.inspect.Inspector(s3d);
-
-		var delta = s3d.camera.pos.sub(s3d.camera.target);
-		delta.z = 0;
-		var angle = Math.atan2(delta.y, delta.x);
-		var dist = delta.length();
-
-		// add node to scene graph
-		var n = i.scenePanel.addNode("Rotation", "repeat", function() {
-			return [
-				PFloat("v", function() return angle, function(v) {
-					angle = v;
-					s3d.camera.pos.x = Math.cos(angle) * dist;
-					s3d.camera.pos.y = Math.sin(angle) * dist;
-				}),
-				PCustom("", function() {
-					var j = i.J("<button>");
-					j.text("Click Me!");
-					j.click(function(_) {
-						var j = new hxd.inspect.Panel(null,"New Panel");
-						j.content.text("Nothing to see there.");
-						j.show();
-					});
-					return j;
-				})
-			];
-		});
-		i.scenePanel.addNode("Test", "", n);
-		i.addTool("Exit", "bomb", function() {
-			hxd.System.exit();
-		});
-		#end
 	}
 	}
 
 
 	static function main() {
 	static function main() {