2
0
Clément Espeute 1 жил өмнө
parent
commit
ba337d048d

+ 117 - 2
hide/view/GraphEditor.hx

@@ -23,6 +23,11 @@ typedef UndoFn = (isUndo : Bool) -> Void;
 typedef UndoBuffer = Array<UndoFn>;
 typedef UndoBuffer = Array<UndoFn>;
 typedef SelectionUndoSave = {newSelections: Map<Int, Bool>, buffer: UndoBuffer};
 typedef SelectionUndoSave = {newSelections: Map<Int, Bool>, buffer: UndoBuffer};
 
 
+typedef CopySelectionData = {
+	nodes: Array<{id: Int, serData: Dynamic}>,
+	edges: Array<Edge>,
+};
+
 @:access(hide.view.shadereditor.Box)
 @:access(hide.view.shadereditor.Box)
 class GraphEditor extends hide.comp.Component {
 class GraphEditor extends hide.comp.Component {
 	public var editor : hide.view.GraphInterface.IGraphEditor;
 	public var editor : hide.view.GraphInterface.IGraphEditor;
@@ -129,6 +134,9 @@ class GraphEditor extends hide.comp.Component {
 
 
 		var keys = new hide.ui.Keys(element);
 		var keys = new hide.ui.Keys(element);
 		keys.register("delete", deleteSelection);
 		keys.register("delete", deleteSelection);
+		keys.register("sceneeditor.focus", centerView);
+		keys.register("copy", copySelection);
+		keys.register("paste", paste);
 
 
 		var miniPreviews = new Element('<div class="mini-preview"></div>');
 		var miniPreviews = new Element('<div class="mini-preview"></div>');
 		heapsScene.prepend(miniPreviews);
 		heapsScene.prepend(miniPreviews);
@@ -241,6 +249,28 @@ class GraphEditor extends hide.comp.Component {
 
 
 		updateMatrix();
 		updateMatrix();
 
 
+		reloadInternal();
+	}
+
+	var reloadQueued = false;
+	public function reload() {
+		reloadQueued = true;
+	}
+
+	function reloadInternal() {
+		reloadQueued = false;
+		boxesSelected.clear();
+		for (box in boxes) {
+			box.dispose();
+		}
+		boxes.clear();
+		outputsToInputs.clear();
+
+		for (e in edges) {
+			e.remove();
+		}
+		edges.clear();
+
 		var nodes = editor.getNodes();
 		var nodes = editor.getNodes();
 		for (node in nodes) {
 		for (node in nodes) {
 			node.getPos(tmpPoint);
 			node.getPos(tmpPoint);
@@ -291,6 +321,11 @@ class GraphEditor extends hide.comp.Component {
 			sceneEditor.scene.s3d.renderer.ctx.time = previewsScene.s3d.renderer.ctx.time;
 			sceneEditor.scene.s3d.renderer.ctx.time = previewsScene.s3d.renderer.ctx.time;
 		}*/
 		}*/
 
 
+		if (reloadQueued) {
+			reloadInternal();
+			return;
+		}
+
 		if (!onPreviewUpdate())
 		if (!onPreviewUpdate())
 			return;
 			return;
 
 
@@ -794,7 +829,7 @@ class GraphEditor extends hide.comp.Component {
 		var exec = function(isUndo : Bool) : Void {
 		var exec = function(isUndo : Bool) : Void {
 			if (!doAdd) isUndo = !isUndo;
 			if (!doAdd) isUndo = !isUndo;
 			if (!isUndo) {
 			if (!isUndo) {
-				var node = editor.unserializeNode(data);
+				var node = editor.unserializeNode(data, false);
 				node.getPos(Box.tmpPoint);
 				node.getPos(Box.tmpPoint);
 				addBox(Box.tmpPoint, node);
 				addBox(Box.tmpPoint, node);
 				editor.addNode(node);
 				editor.addNode(node);
@@ -1139,6 +1174,86 @@ class GraphEditor extends hide.comp.Component {
 		edgeCreationCurve = createCurve(edgeCreationOutput, edgeCreationInput, minDistNode, clientX, clientY, true);
 		edgeCreationCurve = createCurve(edgeCreationOutput, edgeCreationInput, minDistNode, clientX, clientY, true);
 	}
 	}
 
 
+	function copySelection() {
+		var data : CopySelectionData = {
+			nodes:  [],
+			edges: [],
+		};
+		for (nodeId => _ in boxesSelected) {
+			var box = boxes[nodeId];
+			data.nodes.push({id: nodeId, serData: editor.serializeNode(box.node)});
+			for (inputId => _ in box.info.inputs) {
+				var output = outputsToInputs.getLeft(packIO(nodeId, inputId));
+				if (output != null) {
+					var unpack = unpackIO(output);
+					if ( boxesSelected.get(unpack.nodeId) != null) {
+						data.edges.push({nodeFromId: unpack.nodeId, outputFromId: unpack.ioId, nodeToId: nodeId, inputToId: inputId});
+					}
+				}
+			}
+		}
+
+		if (!data.nodes.empty()) {
+			var str = haxe.Json.stringify(data);
+			Ide.inst.setClipboard(str);
+		}
+	}
+
+	function paste() {
+		var nodes : Array<IGraphNode> = [];
+		var idRemap : Map<Int, Int> = [];
+		var edges : Array<Edge> = [];
+		try {
+			var cb = Ide.inst.getClipboard();
+			var data : CopySelectionData = haxe.Json.parse(cb);
+			for (nodeInfo in data.nodes) {
+				var node = editor.unserializeNode(nodeInfo.serData, true);
+				nodes.push(node);
+				var newId = node.getId();
+				idRemap.set(nodeInfo.id, newId);
+			}
+			for (e in data.edges) {
+				edges.push({nodeFromId: e.nodeFromId, nodeToId: e.nodeToId, outputFromId: e.outputFromId, inputToId: e.inputToId});
+			}
+		}
+		catch (e) {
+			Ide.inst.quickError('Could not paste content of clipboard ($e)');
+			return;
+		}
+
+		if (nodes.length <= 0)
+			return;
+
+		// center of all the boxes
+		var offset = new h2d.col.Point(0,0);
+		var pt = Box.tmpPoint;
+		for (count => node in nodes) {
+			node.getPos(pt);
+			offset.set(offset.x + (pt.x - offset.x) / (count + 1),offset.y + (pt.y - offset.y) / (count + 1));
+		}
+
+
+		currentUndoBuffer = [];
+
+		for (node in nodes) {
+			node.getPos(pt);
+			pt -= offset;
+			pt.x += lX(ide.mouseX);
+			pt.y += lY(ide.mouseY);
+			node.setPos(pt);
+			opBox(node, true, currentUndoBuffer);
+			opSelect(node.getId(), true, currentUndoBuffer);
+		}
+
+		for (edge in edges) {
+			var newFromId = idRemap.get(edge.nodeFromId);
+			var newToId = idRemap.get(edge.nodeToId);
+			opEdge(packIO(newFromId, edge.outputFromId), packIO(newToId, edge.inputToId), true, currentUndoBuffer);
+		}
+
+		commitUndo();
+	}
+
 	function createCurve(packedOutput: Null<Int>, packedInput: Null<Int>, ?distance : Float, ?x : Float, ?y : Float, ?isDraft : Bool) {
 	function createCurve(packedOutput: Null<Int>, packedInput: Null<Int>, ?distance : Float, ?x : Float, ?y : Float, ?isDraft : Bool) {
 		var offsetEnd = {top : y ?? 0.0, left : x ?? 0.0};
 		var offsetEnd = {top : y ?? 0.0, left : x ?? 0.0};
 		if (packedInput != null) {
 		if (packedInput != null) {
@@ -1296,7 +1411,7 @@ class GraphEditor extends hide.comp.Component {
 		};
 		};
 	}
 	}
 
 
-	function centerView() {
+	public function centerView() {
 		if (!boxes.iterator().hasNext()) return;
 		if (!boxes.iterator().hasNext()) return;
 		var dims = getGraphDims();
 		var dims = getGraphDims();
 		var scale = Math.min(1, Math.min((editorDisplay.element.width() - 50) / (dims.xMax - dims.xMin), (editorDisplay.element.height() - 50) / (dims.yMax - dims.yMin)));
 		var scale = Math.min(1, Math.min((editorDisplay.element.width() - 50) / (dims.xMax - dims.xMin), (editorDisplay.element.height() - 50) / (dims.yMax - dims.yMin)));

+ 3 - 1
hide/view/GraphInterface.hx

@@ -91,7 +91,9 @@ interface IGraphEditor {
     public function removeNode(id:Int) : Void;
     public function removeNode(id:Int) : Void;
 
 
     public function serializeNode(node : IGraphNode) : Dynamic;
     public function serializeNode(node : IGraphNode) : Dynamic;
-    public function unserializeNode(data: Dynamic) : IGraphNode;
+
+    /**If newId is true, then the returned node must have a new unique id. This is used when duplicating nodes**/
+    public function unserializeNode(data: Dynamic, newId: Bool) : IGraphNode;
 
 
     /**Returns false if the edge can't be created because the input/output types don't match**/
     /**Returns false if the edge can't be created because the input/output types don't match**/
     public function canAddEdge(edge : Edge) : Bool;
     public function canAddEdge(edge : Edge) : Bool;

+ 45 - 8
hide/view/shadereditor/ShaderEditor.hx

@@ -145,6 +145,8 @@ class ShaderEditor extends hide.view.FileView implements GraphInterface.IGraphEd
 	var defaultLight : hrt.prefab.Light;
 	var defaultLight : hrt.prefab.Light;
 
 
 	var queueReloadMesh = false;
 	var queueReloadMesh = false;
+
+	var domainSelection : JQuery;
 	
 	
 	override function onDisplay() {
 	override function onDisplay() {
 		super.onDisplay();
 		super.onDisplay();
@@ -191,13 +193,7 @@ class ShaderEditor extends hide.view.FileView implements GraphInterface.IGraphEd
 					<div class="options-block hide-block">
 					<div class="options-block hide-block">
 						<input id="createParameter" type="button" value="Add parameter" />
 						<input id="createParameter" type="button" value="Add parameter" />
 						<select id="domainSelection"></select>
 						<select id="domainSelection"></select>
-						<input id="launchCompileShader" type="button" value="Compile shader" />
 
 
-						<input id="saveShader" type="button" value="Save" />
-						<div>
-							<input id="changeModel" type="button" value="Change Model" />
-							<input id="removeModel" type="button" value="Remove Model" />
-						</div>
 						<input id="centerView" type="button" value="Center Graph" />
 						<input id="centerView" type="button" value="Center Graph" />
 						<div>
 						<div>
 							Display Compiled
 							Display Compiled
@@ -213,6 +209,22 @@ class ShaderEditor extends hide.view.FileView implements GraphInterface.IGraphEd
 			</div>'
 			</div>'
 		);
 		);
 
 
+		rightPannel.find("#centerView").click((e) -> graphEditor.centerView());
+
+		domainSelection = rightPannel.find("#domainSelection");
+		for (domain in haxe.EnumTools.getConstructors(hrt.shgraph.ShaderGraph.Domain)) {
+			domainSelection.append('<option value="$domain">$domain</option>');
+		};
+
+		domainSelection.val(haxe.EnumTools.EnumValueTools.getName(currentGraph.domain));
+
+		domainSelection.on("change", (e) -> {
+			var domainString : String = domainSelection.val();
+			var domain = haxe.EnumTools.createByName(hrt.shgraph.ShaderGraph.Domain, domainString);
+			setDomain(domain, true);
+		});
+
+
 		rightPannel.appendTo(element);
 		rightPannel.appendTo(element);
 
 
 		var newParamCtxMenu : Array<hide.comp.ContextMenu.ContextMenuItem> = [
 		var newParamCtxMenu : Array<hide.comp.ContextMenu.ContextMenuItem> = [
@@ -254,6 +266,26 @@ class ShaderEditor extends hide.view.FileView implements GraphInterface.IGraphEd
 		initMeshPreview();
 		initMeshPreview();
 	}
 	}
 
 
+	function setDomain(domain : hrt.shgraph.ShaderGraph.Domain, recordUndo : Bool) {
+		if (shaderGraph.getGraph(domain) == currentGraph)
+			return;
+		
+		var from = currentGraph.domain;
+		var to = domain;
+
+		function exec(isUndo : Bool) {
+			var curr = !isUndo ? to : from;
+			currentGraph = shaderGraph.getGraph(curr);
+			domainSelection.val(haxe.EnumTools.EnumValueTools.getName(curr));
+			graphEditor.reload();
+		}
+
+		exec(false);
+		if (recordUndo) {
+			undo.change(Custom(exec));
+		}
+	}
+
 	function createParameter(type : Type) {
 	function createParameter(type : Type) {
 		@:privateAccess var paramShaderID : Int = shaderGraph.current_param_id++;
 		@:privateAccess var paramShaderID : Int = shaderGraph.current_param_id++;
 		@:privateAccess
 		@:privateAccess
@@ -1085,8 +1117,13 @@ class ShaderEditor extends hide.view.FileView implements GraphInterface.IGraphEd
 		return (cast node:ShaderNode).serializeToDynamic();
 		return (cast node:ShaderNode).serializeToDynamic();
 	}
 	}
 
 
-	public function unserializeNode(data : Dynamic) : IGraphNode {
-		return ShaderNode.createFromDynamic(data, shaderGraph);
+	public function unserializeNode(data : Dynamic, newId : Bool) : IGraphNode {
+		var node = ShaderNode.createFromDynamic(data, shaderGraph);
+		if (newId) {
+			@:privateAccess var newId = currentGraph.current_node_id++;
+			node.setId(newId);
+		}
+		return node;
 	}
 	}
 
 
 	public function getAddNodesMenu() : Array<AddNodeMenuEntry> {
 	public function getAddNodesMenu() : Array<AddNodeMenuEntry> {