|
@@ -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);
|
|
|
}
|