Pārlūkot izejas kodu

Model: WIP merge tool in model view

lviguier 3 mēneši atpakaļ
vecāks
revīzija
6da546ea1f
1 mainītis faili ar 192 papildinājumiem un 0 dzēšanām
  1. 192 0
      hide/view/Model.hx

+ 192 - 0
hide/view/Model.hx

@@ -234,6 +234,7 @@ class Model extends FileView {
 	var selectedMesh : h3d.scene.Mesh = null;
 	var selectedMesh : h3d.scene.Mesh = null;
 	var displayJoints = null;
 	var displayJoints = null;
 	var selectedCount = 0;
 	var selectedCount = 0;
+	var selectedElements : Array<Dynamic>;
 	function onTreeSelectionChanged(elts : Array<Dynamic>) {
 	function onTreeSelectionChanged(elts : Array<Dynamic>) {
 		function canMultiEdit<T>(cl : Class<T>) {
 		function canMultiEdit<T>(cl : Class<T>) {
 			for (e in elts)
 			for (e in elts)
@@ -243,6 +244,8 @@ class Model extends FileView {
 			return true;
 			return true;
 		}
 		}
 
 
+		selectedElements = elts;
+
 		var properties = sceneEditor.properties;
 		var properties = sceneEditor.properties;
 		properties.clear();
 		properties.clear();
 
 
@@ -1296,6 +1299,18 @@ class Model extends FileView {
 		tree.onSelectionChanged = onTreeSelectionChanged;
 		tree.onSelectionChanged = onTreeSelectionChanged;
 		tree.saveDisplayKey = this.saveDisplayKey;
 		tree.saveDisplayKey = this.saveDisplayKey;
 
 
+		function ctxMenu(tree, e) {
+			e.preventDefault();
+			var current = tree.getCurrentOver();
+			var menuItems : Array<hide.comp.ContextMenu.MenuItem> = [
+				{ label : "Merge selected", enabled : canMergeElements(selectedElements), click: () -> mergeModels(cast selectedElements) },
+				{ label : "Merge all meshes", enabled : true, click: () -> mergeModels(cast [for (m in obj.findAll(o -> Std.downcast(o, h3d.scene.Mesh))) m]) },
+			];
+
+			hide.comp.ContextMenu.createFromEvent(cast e, menuItems);
+		};
+		tree.element.parent().contextmenu(ctxMenu.bind(tree));
+
 		tools.clear();
 		tools.clear();
 		var anims = scene.listAnims(getPath());
 		var anims = scene.listAnims(getPath());
 
 
@@ -1476,6 +1491,183 @@ class Model extends FileView {
 
 
 
 
 
 
+	function canMergeElements(objects : Array<Dynamic>) {
+		if (objects == null || objects.length <= 1)
+			return false;
+
+		var format : hxd.BufferFormat = null;
+		for (o in objects) {
+			var m = Std.downcast(o, h3d.scene.Mesh);
+			if (m == null)
+				return false;
+			if (format == null)
+				format = m.primitive.buffer.format;
+			if (format != m.primitive.buffer.format)
+				return false;
+		}
+
+		return true;
+	}
+
+	function mergeModels(models : Array<h3d.scene.Object>) {
+		var relFilePath = ".tmp/tmp.hmd";
+		var tmpFilePath = ide.resourceDir + '/$relFilePath';
+
+		function merge(m1: h3d.scene.Mesh, m2: h3d.scene.Mesh, format: hxd.BufferFormat) : h3d.scene.Mesh {
+			var p1 = Std.downcast(m1.primitive, h3d.prim.HMDModel);
+			var p2 = Std.downcast(m2.primitive, h3d.prim.HMDModel);
+
+			if (p1 == null || p2 == null)
+				throw "!";
+
+			// Creation of the merged HMD
+			var hmd = new hxd.fmt.hmd.Data();
+			hmd.version = hxd.fmt.hmd.Data.CURRENT_VERSION;
+			hmd.geometries = [];
+			hmd.materials = [];
+			hmd.models = [];
+			hmd.animations = [];
+			hmd.shapes = [];
+
+			var mat = new hxd.fmt.hmd.Data.Material();
+			mat.name = "SimpleBlock";
+			mat.blendMode = None;
+			mat.props = [];
+			hmd.materials.push(mat);
+
+			var dataOut = new haxe.io.BytesOutput();
+			var maxLod = Std.int(hxd.Math.max(p1.lodCount(), p2.lodCount()));
+			for (idx in 0...maxLod) {
+				var newFormat = hxd.BufferFormat.make([for (i in format.getInputs()) i]);
+
+				var d1 = hxd.fmt.fbx.Writer.getPrimitiveInfos(p1, newFormat, idx);
+				var d2 = hxd.fmt.fbx.Writer.getPrimitiveInfos(p2, newFormat, idx);
+
+				var vertexCount = Std.int((d1.vertexBuffer.length + d2.vertexBuffer.length) / d1.vertexFormat.stride);
+				var indexCount = d1.indexesBuffer.length + d2.indexesBuffer.length;
+
+				var g = new hxd.fmt.hmd.Data.Geometry();
+				g.bounds = new h3d.col.Bounds();
+				g.indexCounts = [ indexCount ];
+				g.vertexCount = vertexCount;
+				g.vertexFormat = newFormat;
+				g.vertexPosition = dataOut.length;
+				hmd.geometries.push(g);
+
+				var model = new hxd.fmt.hmd.Data.Model();
+				model.name = m1.name + "_" + m2.name;
+				model.geometry = 0;
+				model.materials = [0];
+				model.parent = -1;
+				model.position = new hxd.fmt.hmd.Data.Position();
+				model.position.x = 0;
+				model.position.y = 0;
+				model.position.z = 0;
+				model.position.sx = 1;
+				model.position.sy = 1;
+				model.position.sz = 1;
+				model.position.qx = 0;
+				model.position.qy = 0;
+				model.position.qz = 0;
+				hmd.models.push(model);
+
+				var idx = 0;
+				while (idx < vertexCount * g.vertexFormat.stride) {
+					function get(vIdx: Int) {
+						if (vIdx < d1.vertexBuffer.length)
+							return d1.vertexBuffer[vIdx];
+						else
+							return d2.vertexBuffer[vIdx % d1.vertexBuffer.length];
+					}
+
+					for (i in g.vertexFormat.getInputs()) {
+						var prec = i.precision;
+						var size = i.type.getSize();
+						if (i.name == "position") {
+							var pos = new h3d.Vector(get(idx), get(idx + 1), get(idx + 2));
+							var trs = idx < d1.vertexBuffer.length ? m1.defaultTransform : m2.defaultTransform;
+							pos.transform(trs);
+							hxd.fmt.fbx.HMDOut.writePrec(dataOut, pos.x, prec);
+							hxd.fmt.fbx.HMDOut.writePrec(dataOut, pos.y, prec);
+							hxd.fmt.fbx.HMDOut.writePrec(dataOut, pos.z, prec);
+						}
+						else {
+							for (idx2 in 0...size)
+								hxd.fmt.fbx.HMDOut.writePrec(dataOut, get(idx + idx2), prec);
+						}
+
+						hxd.fmt.fbx.HMDOut.flushPrec(dataOut, prec, size);
+						idx += size;
+					}
+				}
+
+				g.indexPosition = dataOut.length;
+				var offset = 0;
+				for (idx in 0...indexCount) {
+					function get(vIdx: Int) {
+						if (vIdx < d1.indexesBuffer.length) {
+							if (offset < d1.indexesBuffer[vIdx])
+								offset = d1.indexesBuffer[vIdx];
+							return d1.indexesBuffer[vIdx];
+						}
+						else
+							return d2.indexesBuffer[vIdx % d1.indexesBuffer.length] + offset + 1;
+					}
+
+					dataOut.writeUInt16(get(idx));
+				}
+			}
+
+			hmd.data = dataOut.getBytes();
+
+			var out = new haxe.io.BytesOutput();
+			var w = new hxd.fmt.hmd.Writer(out);
+			w.write(hmd);
+
+			var bytes = out.getBytes();
+			sys.io.File.saveBytes(tmpFilePath, bytes);
+
+			// Reload library
+			var lib = hxd.res.Loader.currentInstance.load(relFilePath).toModel().toHmd();
+			var mesh = lib.makeObject();
+			lib.dispose();
+			return cast mesh;
+		}
+
+		var oldData = sys.io.File.getContent(Ide.inst.getPath(state.path));
+		var meshes : Array<h3d.scene.Mesh> = cast models;
+		var format = meshes[0].primitive.buffer.format;
+		var tmp : h3d.scene.Mesh = meshes[0];
+		for (idx => m in meshes) {
+			if (idx == 0) {
+				tmp = m;
+				continue;
+			}
+			tmp = merge(tmp, m, format);
+		}
+
+		var root = models[0].parent;
+		for (m in models)
+			m.remove();
+		root.addChild(tmp);
+		meshes = [tmp];
+
+		// Export merge objects
+		var filePath = Ide.inst.getPath(state.path);
+		var params = { forward:"0", forwardSign:"1", up:"2", upSign:"1" };
+		new hxd.fmt.fbx.Writer(null).export(
+				cast meshes,
+				Ide.inst.getPath(filePath),
+				() -> Ide.inst.quickMessage('Successfully merged objects at path : ${filePath}'),
+				params);
+
+		var newData = sys.io.File.getContent(Ide.inst.getPath(state.path));
+
+		// undo.change(Custom(function(undo) {
+		// 	sys.io.File.saveContent(state.path, undo ? oldData : newData);
+		// }));
+	}
+
 	function loadProps() {
 	function loadProps() {
 		var propsPath = getPropsPath();
 		var propsPath = getPropsPath();
 		var hideData : h3d.prim.ModelCache.HideProps;
 		var hideData : h3d.prim.ModelCache.HideProps;