浏览代码

Update Mesh Generator

ShiroSmith 6 年之前
父节点
当前提交
3f775b7ece
共有 3 个文件被更改,包括 265 次插入76 次删除
  1. 24 1
      bin/style.css
  2. 32 4
      bin/style.less
  3. 209 71
      hide/prefab/l3d/MeshGenerator.hx

+ 24 - 1
bin/style.css

@@ -898,7 +898,7 @@ input[type=checkbox]:checked:after {
 }
 .poly-editor .description {
   margin: 5px;
-  background-color: black;
+  background-color: #303030;
   outline: 4px solid #4a4a4a;
   padding: 2px;
 }
@@ -913,6 +913,29 @@ input[type=checkbox]:checked:after {
   display: block;
   padding: 5px;
 }
+.spline-editor .editModeButton {
+  margin: 10px;
+  outline: 4px solid #fd5151;
+}
+.spline-editor .editModeEnabled {
+  outline: 4px solid #5897fb;
+}
+.spline-editor .description {
+  margin: 5px;
+  background-color: #303030;
+  outline: 4px solid #4a4a4a;
+  padding: 2px;
+}
+/* Mesh Generator */
+.meshGenerator-thumbnail {
+  display: inline-block;
+  margin: 5px;
+  width: 75px;
+  height: 75px;
+  background-size: 75px 75px;
+  outline: 2px solid #4a4a4a;
+  background-size: contain;
+}
 /* Terrain editor */
 .terrain-brushModeDescription {
   margin: 5px;

+ 32 - 4
bin/style.less

@@ -307,9 +307,7 @@ input[type=checkbox] {
 	width:100%;
 	height:100%;
 	display:flex;
-	>* {
-		//flex-grow : 100;
-	}
+	//flex-grow : 100;
 }
 
 .flex-elt {
@@ -976,6 +974,7 @@ input[type=checkbox] {
 		}
 	}
 }
+
 /* Poly editor */
 .poly-editor{
 	.editModeButton{
@@ -987,7 +986,7 @@ input[type=checkbox] {
 	}
 	.description{
 		margin: 5px;
-		background-color: black;
+		background-color:#303030;
 		outline: 4px solid #4a4a4a;
 		padding : 2px;
 	}
@@ -1007,6 +1006,35 @@ input[type=checkbox] {
 	}
 }
 
+// Spline editor
+.spline-editor{
+	.editModeButton{
+		margin: 10px;
+		outline: 4px solid #fd5151;
+	}
+	.editModeEnabled {
+		outline: 4px solid #5897fb;
+	}
+	.description{
+		margin: 5px;
+		background-color: #303030;
+		outline: 4px solid #4a4a4a;
+		padding : 2px;
+	}
+}
+
+/* Mesh Generator */
+.meshGenerator-thumbnail {
+	display: inline-block;
+	margin: 5px;
+	@size: 75px;
+	width: @size;
+	height: @size;
+	background-size: @size @size;
+	outline: 2px solid #4a4a4a;
+	background-size: contain;
+}
+
 /* Terrain editor */
 .terrain-brushModeDescription{
 	margin: 5px;

+ 209 - 71
hide/prefab/l3d/MeshGenerator.hx

@@ -1,60 +1,84 @@
 package hide.prefab.l3d;
 
 class Socket {
+
 	public var type : String;
 	public var name : String;
-	public function new() {}
+
+	public function new( ?type, ?name ) {
+		this.type = type;
+		this.name = name;
+	}
+
 }
 
 class MeshPart {
 
-	public var socketType : String;
-	public var socketName : String;
-	public var mesh : String;
-	public var parts : Array<MeshPart> = [];
+	public var socket : Socket;
+	public var meshPath : String;
+	public var childParts : Array<MeshPart> = [];
 
 	#if editor
 	public var previewPos = false;
 	#end
 
 	public function new() {
-		mesh = "none";
+		socket = new Socket();
+	}
+
+	public function save() {
+		var o : Dynamic = {};
+		o.socket = { type : socket.type, name : socket.name };
+		o.meshPath = meshPath;
+
+		if( childParts.length > 0 ) {
+			var sp : Array<Dynamic> = [];
+			for( mp in childParts )
+				if( mp.meshPath != null )
+					sp.push(mp.save());
+			o.childParts = sp;
+		}
+
+		return o;
 	}
 
 	public function load( o : Dynamic ) {
-		socketType = o.socketType;
-		socketName = o.socketName;
-		mesh = o.mesh == null ? "none" : o.mesh;
-		var ps : Array<Dynamic> = o.parts;
+		if( o.socket != null ) {
+			socket.type = o.socket.type;
+			socket.name = o.socket.name;
+		}
+		meshPath = o.meshPath == "none" ? null : o.meshPath;
+		var ps : Array<Dynamic> = o.childParts;
 		if( ps != null ) {
 			for( p in ps ) {
 				var mp = new MeshPart();
 				mp.load(p);
-				parts.push(mp);
+				childParts.push(mp);
 			}
 		}
 	}
 
 	public function isRoot() : Bool {
-		return socketType == "Root";
+		return socket.type == "Root";
 	}
 
 	public function getSocketFullName() : String {
-		return socketType + (socketName == null ? "" : " " + socketName);
+		return socket.type + (socket.name == null ? "" : " " + socket.name);
 	}
 }
 
 class MeshGenerator extends Object3D {
 
-	var root : MeshPart;
+	public var root : MeshPart;
 
 	#if editor
 	static var filter : Array<String> = [];
+	static var customScene : h3d.scene.Scene;
 	#end
 
 	override function save() {
 		var obj : Dynamic = super.save();
-		obj.root = root;
+		obj.root = root.save();
 		return obj;
 	}
 
@@ -64,43 +88,50 @@ class MeshGenerator extends Object3D {
 		root.load(obj.root);
 	}
 
-	override function makeInstance(ctx:Context):Context {
+	override function makeInstance( ctx : Context ) : Context {
 		ctx = ctx.clone(this);
 		ctx.local3d = new h3d.scene.Object(ctx.local3d);
 		ctx.local3d.name = name;
 
 		if( root == null ) {
 			root = new MeshPart();
-			root.socketType = "Root";
+			root.socket.type = "Root";
 		}
 		updateInstance(ctx);
 
+		#if editor
+		if( customScene == null ) {
+			customScene = new h3d.scene.Scene(true, false);
+			customScene.checkPasses = false;
+		}
+		#end
+
 		return ctx;
 	}
 
 	override function updateInstance( ctx: Context, ?propName : String ) {
 		super.updateInstance(ctx,propName);
 		resetMesh(ctx);
-		generateMesh(ctx);
-	}
 
-	function generateMesh( ctx : Context ) {
-		if( root != null )
-			createMeshPart(ctx, root, ctx.local3d);
+		#if editor
+		createEmptyMeshPart(ctx, root);
+		#end
+
+		createMeshPart(ctx, root, ctx.local3d);
 	}
 
-	function getSocket( obj : h3d.scene.Object, type: String , name : String ) : h3d.scene.Object {
+	public function getSocket( obj : h3d.scene.Object, s : Socket ) : h3d.scene.Object {
 		for( c in @:privateAccess obj.children ) {
 			if( c.name == null ) continue;
 			var nameInfos = c.name.split("_");
 			if( nameInfos.length < 1 ) continue;
 			if( nameInfos[0] == "Socket" ) {
 				if( nameInfos.length < 2 ) continue;
-				if( nameInfos[1] == type ) {
-					if( name == null ) return c;
+				if( nameInfos[1] == s.type ) {
+					if( s.name == null ) return c;
 					else {
 						if( nameInfos.length < 3 ) continue;
-						if( nameInfos[2] == name ) return c;
+						if( nameInfos[2] == s.name ) return c;
 					}
 				}
 			}
@@ -109,29 +140,27 @@ class MeshGenerator extends Object3D {
 	}
 
 	function createMeshPart( ctx : Context, mp : MeshPart, parent : h3d.scene.Object ) {
+		if( mp.meshPath == null )
+			return;
 
-		var obj : h3d.scene.Object = null;
-		if( mp.mesh != "none" ){
-			obj = ctx.loadModel(mp.mesh);
-		}
-
+		var obj = ctx.loadModel(mp.meshPath);
 		if( mp.isRoot() ) {
-			if( obj != null ) parent.addChild(obj);
+			parent.addChild(obj);
 			#if editor
 			if( mp.previewPos ) parent.addChild(createPreviewSphere());
 			#end
 		}
 		else {
-			var socket = getSocket(parent, mp.socketType, mp.socketName);
+			var socket = getSocket(parent, mp.socket);
 			if( socket != null ) {
-				if( obj != null ) socket.addChild(obj);
+				socket.addChild(obj);
 				#if editor
 				if( mp.previewPos ) socket.addChild(createPreviewSphere());
 				#end
 			}
 		}
 
-		for( cmp in mp.parts )
+		for( cmp in mp.childParts )
 			createMeshPart(ctx, cmp, obj);
 	}
 
@@ -139,9 +168,100 @@ class MeshGenerator extends Object3D {
 		ctx.local3d.removeChildren();
 	}
 
+	function getSocketMatFromHMD( hmd : hxd.fmt.hmd.Library, s : Socket ) : h3d.Matrix {
+		if( hmd == null ) return null;
+		for( m in @:privateAccess hmd.header.models ) {
+			if( m.name == null ) continue;
+			var nameInfos = m.name.split("_");
+			if( nameInfos.length < 2 ) continue;
+			if( nameInfos[0] == "Socket" && nameInfos[1] == s.type && ((s.name == null && nameInfos.length < 3) || (nameInfos.length >= 3 && s.name == nameInfos[2])) ) {
+				return m.position.toMatrix();
+			}
+		}
+		return null;
+	}
+
 	#if editor
 
-	function hasFilter( s : String ){
+	function createEmptyMeshPart( ctx : Context, mp : MeshPart ) {
+		var sl = getSocketListFromHMD(getHMD(ctx, mp.meshPath));
+		if( mp.childParts.length < sl.length ) {
+			for( s in sl ) {
+				var b = true;
+				for( cmp in mp.childParts ){
+					if ( cmp.socket.name == s.name && cmp.socket.type == s.type ){
+						b = false;
+						break;
+					}
+				}
+				if( b ) {
+					var cmp = new MeshPart();
+					cmp.socket.name = s.name;
+					cmp.socket.type = s.type;
+					mp.childParts.push(cmp);
+				}
+			}
+		}
+		for( cmp in mp.childParts )
+			createEmptyMeshPart(ctx, cmp);
+	}
+
+	var target : h3d.mat.Texture;
+	function renderMeshThumbnail( ctx : Context, meshPath : String ) {
+
+		if( target == null )
+			target = new h3d.mat.Texture(256, 256, [Target], RGBA);
+
+		if( meshPath == null )
+			return;
+
+		var obj = ctx.loadModel(meshPath);
+		if( obj == null )
+			return;
+
+		for( m in obj.getMaterials() ) {
+			m.mainPass.culling = None;
+		}
+
+		if(!sys.FileSystem.isDirectory(hide.Ide.inst.getPath(".tmp/meshGeneratorData")))
+			sys.FileSystem.createDirectory(hide.Ide.inst.getPath(".tmp/meshGeneratorData"));
+
+		var path = new haxe.io.Path("");
+		path.dir = ".tmp/meshGeneratorData/";
+		path.file =  extractMeshName(meshPath) + "_thumbnail";
+		path.ext = "png";
+		var file = hide.Ide.inst.getPath(path.toString());
+
+		if(sys.FileSystem.exists(file))
+			return;
+
+		var mainScene = @:privateAccess ctx.local3d.getScene();
+		@:privateAccess customScene.children = [];
+		@:privateAccess customScene.children.push(obj);
+
+		var cam = new h3d.Camera(45, 1.0, 1.0);
+		obj.rotate(0, 0, hxd.Math.degToRad(45));
+		var b = obj.getBounds();
+		var s = b.toSphere();
+		cam.pos.set(0, s.r * 1.8, s.r * 1.25);
+		cam.target.set((b.xMax + b.xMin) * 0.5, (b.yMax + b.yMin) * 0.5, (b.zMax + b.zMin) * 0.5);
+
+		customScene.camera = cam;
+		var engine = h3d.Engine.getCurrent();
+		engine.begin();
+		engine.pushTarget(target);
+		engine.clear(0,1,0);
+		customScene.render(engine);
+		engine.popTarget();
+		customScene.camera = null;
+
+		var pixels = target.capturePixels();
+		var bytes = pixels.toPNG();
+
+		sys.io.File.saveBytes(file, bytes);
+	}
+
+	function hasFilter( s : String ) {
 		for( f in filter )
 			if ( s == f )
 				return true;
@@ -160,7 +280,7 @@ class MeshGenerator extends Object3D {
 
 	function resetPreview( mp : MeshPart ) {
 		mp.previewPos = false;
-		for( cmp in mp.parts )
+		for( cmp in mp.childParts )
 			resetPreview(cmp);
 	}
 
@@ -170,19 +290,26 @@ class MeshGenerator extends Object3D {
 
 	override function setSelected( ctx : Context, b : Bool ) {
 		super.setSelected(ctx, b);
+
+		if( !b ) {
+			var previewSpheres = ctx.local3d.findAll(c -> if(c.name == "previewSphere") c else null);
+			for( s in previewSpheres ) {
+				s.remove();
+			}
+		}
 	}
 
-	function getHMD( ctx : Context, path : String ) : hxd.fmt.hmd.Library {
-		if( path == null || path == "none" ) return null;
-		return @:privateAccess ctx.shared.cache.loadLibrary(hxd.res.Loader.currentInstance.load(path).toModel());
+	function getHMD( ctx : Context, meshPath : String ) : hxd.fmt.hmd.Library {
+		if( meshPath == null ) return null;
+		return @:privateAccess ctx.shared.cache.loadLibrary(hxd.res.Loader.currentInstance.load(meshPath).toModel());
 	}
 
 	function createMeshParts( sl : Array<Socket> ) : Array<MeshPart> {
 		var r : Array<MeshPart> = [];
 		for( s in sl ){
 			var mp = new MeshPart();
-			mp.socketName = s.name;
-			mp.socketType = s.type;
+			mp.socket.name = s.name;
+			mp.socket.type = s.type;
 			r.push(mp);
 		}
 		return r;
@@ -207,11 +334,15 @@ class MeshGenerator extends Object3D {
 
 	function extractMeshName( path : String ) : String {
 		if( path == null ) return "None";
-		var parts = path.split("/");
-		return parts[parts.length - 1].split(".")[0];
+		var childParts = path.split("/");
+		return childParts[childParts.length - 1].split(".")[0];
 	}
 
-	function fillSelectMenu( ctx : EditContext, select : hide.Element, socketType : String ) {
+	function getThumbnailPath( ctx : EditContext, meshPath : String ) : String {
+		return ctx.ide.getPath(".tmp/meshGeneratorData/"+ extractMeshName(meshPath) +"_thumbnail.png");
+	}
+
+	function fillSelectMenu( ctx : EditContext, select : hide.Element, socket : Socket ) {
 		for( f in filter ) {
 			var meshList : Array<Dynamic> = ctx.scene.config.get("meshGenerator." + f);
 			if( meshList == null ) continue;
@@ -222,15 +353,14 @@ class MeshGenerator extends Object3D {
 					available = true;
 				else {
 					for( s in sockets ) {
-						if( s == socketType ) {
+						if( s == socket.type ) {
 							available = true;
 							break;
 						}
 					}
 				}
-				if( available ) {
-					new hide.Element('<option>').attr("value", m.path ).text(extractMeshName(m.path)).appendTo(select);
-				}
+				if( available )
+					new hide.Element('<option>').attr("value", m.path).text(extractMeshName(m.path)).appendTo(select);
 			}
 		}
 	}
@@ -246,39 +376,43 @@ class MeshGenerator extends Object3D {
 				</div>
 			');
 			var select = rootElement.find("select");
-			fillSelectMenu(ctx, select, mp.socketType);
-			if(select.find('option[value="${mp.mesh}"]').length == 0)
-				new hide.Element('<option>').attr("value", mp.mesh).text(extractMeshName(mp.mesh)).appendTo(select);
+			fillSelectMenu(ctx, select, mp.socket);
+			if( mp.meshPath != null && select.find('option[value="${mp.meshPath}"]').length == 0 )
+				new hide.Element('<option>').attr("value", mp.meshPath).text(extractMeshName(mp.meshPath)).appendTo(select);
 			select.change(function(_) {
-				mp.mesh = select.val();
-				mp.parts = createMeshParts(getSocketListFromHMD(getHMD(ctx.rootContext, mp.mesh)));
+				var val = select.val();
+				mp.meshPath = val == "none" ? null : val;
+				mp.childParts = createMeshParts(getSocketListFromHMD(getHMD(ctx.rootContext, mp.meshPath)));
 				ctx.onChange(this, null);
 				ctx.rebuildProperties();
 			});
-			select.val(mp.mesh);
+			select.val(mp.meshPath);
 
 			ctx.properties.add(rootElement, mp, function(pname) {});
 		}
-		var socketList = getSocketListFromHMD(getHMD(ctx.rootContext, mp.mesh));
-		if( mp.mesh != "none" && socketList.length != 0 ) {
-			var s = '<div class="group" name="${extractMeshName(mp.mesh)}"><dl>';
-			for( cmp in mp.parts )
-				s += '<dt>${cmp.getSocketFullName()}</dt><dd><select class="${mp.parts.indexOf(cmp)}"><option value="none">None</option></select>';
+
+		var socketList = getSocketListFromHMD(getHMD(ctx.rootContext, mp.meshPath));
+		if( mp.meshPath != null && socketList.length != 0 ) {
+			var s = '<div class="group" name="${extractMeshName(mp.meshPath)}">';
+			s += '<div align="center"><div class="meshGenerator-thumbnail"></div></div><dl>';
+			for( cmp in mp.childParts )
+				s += '<dt>${cmp.getSocketFullName()}</dt><dd><select class="${mp.childParts.indexOf(cmp)}"><option value="none">None</option></select>';
 			s += '</dl></div>';
 			var rootElement = new hide.Element(s);
-			for( cmp in mp.parts ) {
-				var select = rootElement.find('.${mp.parts.indexOf(cmp)}');
-				fillSelectMenu(ctx, select, cmp.socketType);
-				if(select.find('option[value="${cmp.mesh}"]').length == 0)
-					new hide.Element('<option>').attr("value", cmp.mesh).text(extractMeshName(cmp.mesh)).appendTo(select);
+			for( cmp in mp.childParts ) {
+				var select = rootElement.find('.${mp.childParts.indexOf(cmp)}');
+				fillSelectMenu(ctx, select, cmp.socket);
+				if( cmp.meshPath != null && select.find('option[value="${cmp.meshPath}"]').length == 0 )
+					new hide.Element('<option>').attr("value", cmp.meshPath).text(extractMeshName(cmp.meshPath)).appendTo(select);
 				select.change(function(_) {
-					var mp = mp.parts[mp.parts.indexOf(cmp)];
-					mp.mesh = select.val();
-					mp.parts = createMeshParts(getSocketListFromHMD(getHMD(ctx.rootContext, cmp.mesh)));
+					var mp = mp.childParts[mp.childParts.indexOf(cmp)];
+					var val = select.val();
+					mp.meshPath = val == "none" ? null : val;
+					mp.childParts = createMeshParts(getSocketListFromHMD(getHMD(ctx.rootContext, cmp.meshPath)));
 					ctx.onChange(this, null);
 					ctx.rebuildProperties();
 				});
-				select.val(cmp.mesh);
+				select.val(cmp.meshPath);
 
 				select.on("mouseover", function(_) {
 					resetPreview(root);
@@ -290,9 +424,13 @@ class MeshGenerator extends Object3D {
 					ctx.onChange(this, null);
 				});
 			}
+
+			renderMeshThumbnail(ctx.rootContext, mp.meshPath);
+			rootElement.find('.meshGenerator-thumbnail').css("background-image", 'url("file://${getThumbnailPath(ctx, mp.meshPath)}")');
+
 			ctx.properties.add(rootElement, mp, function(pname) {});
 
-			for( cmp in mp.parts ) {
+			for( cmp in mp.childParts ) {
 				createMenu(ctx, cmp);
 			}
 		}
@@ -316,7 +454,7 @@ class MeshGenerator extends Object3D {
 				ctx.rebuildProperties();
 			});
 		}
-		ctx.properties.add(props, this, function(pname) { });
+		ctx.properties.add(props, this, function(pname) {});
 
 		createMenu(ctx, root);
 	}