Browse Source

Merge branch 'master' of https://github.com/HeapsIO/hide

trethaller 6 years ago
parent
commit
4dc339e9fe

+ 84 - 75
bin/style.css

@@ -1030,89 +1030,98 @@ input[type=checkbox]:checked:after {
   visibility: visible;
 }
 /* Shader Editor */
-.shader-view .tabs {
+.graph-view .tabs {
   z-index: 1;
   background: #222222;
   height: 100%;
   user-select: none;
 }
-.shader-view .tabs .tab {
+.graph-view .tabs .tab {
   height: 100%;
 }
-.shader-view .tabs .tab .hide-block {
+.graph-view .tabs .tab .hide-block {
   height: 70%;
 }
-.shader-view .tabs .tab .hide-block #parametersList {
+.graph-view .tabs .tab .hide-block #parametersList {
   height: 100%;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter {
+.graph-view .tabs .tab .hide-block #parametersList .parameter {
   border: 1px solid;
   margin: 5px;
   background-color: #222;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .header {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .header {
   background-color: #d6d6d6;
   height: 20px;
   padding: 5px;
   color: black;
   cursor: pointer;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .header .title {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .header .title {
   float: left;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .header .title input {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .header .title input {
   width: 130px;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .header .type {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .header .type {
   float: right;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .header .type span {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .header .type span {
   color: black;
   font-style: italic;
   font-size: 13px;
   padding-right: 5px;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .content {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .content {
   background-color: #b3b3b3;
   padding: 5px;
   box-shadow: inset 0px 13px 6px -15px black;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .content div {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .content div:first-child {
+  display: inline;
+}
+.graph-view .tabs .tab .hide-block #parametersList .parameter .content div {
   width: 100%;
   height: 20px;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .content div span {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .content div span {
   float: left;
   color: black;
   font-size: 13px;
   padding-right: 5px;
   font-weight: normal;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter .content .action-btns input {
+.graph-view .tabs .tab .hide-block #parametersList .parameter .content .texture-preview {
+  background-repeat: no-repeat;
+  background-size: 20px 20px!important;
+  border: 2px #444444 solid;
+  width: 20px;
+}
+.graph-view .tabs .tab .hide-block #parametersList .parameter .content .action-btns input {
   float: right;
 }
-.shader-view .tabs .tab .hide-block #parametersList .parameter > span {
+.graph-view .tabs .tab .hide-block #parametersList .parameter > span {
   font-size: 12px;
 }
-.shader-view .tabs .tab .options-block {
+.graph-view .tabs .tab .options-block {
   height: 25%;
 }
-.shader-view .tabs .tab .options-block > * {
+.graph-view .tabs .tab .options-block > * {
   display: block;
   margin-bottom: 10px;
   width: 100%;
 }
-.shader-view #add-menu {
+.graph-view #add-menu {
   position: absolute;
   width: 400px;
   box-shadow: 0px 0px 25px -4px black;
   background-color: #222222;
   border: 1px solid #444;
 }
-.shader-view #add-menu .search-container {
+.graph-view #add-menu .search-container {
   display: flex;
 }
-.shader-view #add-menu .search-container .icon {
+.graph-view #add-menu .search-container .icon {
   width: 16px;
   font-size: 15px;
   text-align: center;
@@ -1121,61 +1130,61 @@ input[type=checkbox]:checked:after {
   background: #2d2d2d;
   border-width: 0 1px 1px 0;
 }
-.shader-view #add-menu .search-container .search-bar {
+.graph-view #add-menu .search-container .search-bar {
   flex: 1;
   margin: -1px 11px 0px -1px;
 }
-.shader-view #add-menu .search-container .search-bar input {
+.graph-view #add-menu .search-container .search-bar input {
   width: 100%;
   height: 30px;
   padding-left: 10px;
   outline: none;
 }
-.shader-view #add-menu .search-container .search-bar input:focus {
+.graph-view #add-menu .search-container .search-bar input:focus {
   border: 1px solid #888888;
 }
-.shader-view #add-menu #results {
+.graph-view #add-menu #results {
   max-height: 300px;
   overflow-y: auto;
 }
-.shader-view #add-menu #results div {
+.graph-view #add-menu #results div {
   padding: 5px;
   border-top: 1px solid #444444;
   cursor: pointer;
   color: #d4d4d4;
   position: relative;
 }
-.shader-view #add-menu #results div.group {
+.graph-view #add-menu #results div.group {
   background: #474747;
   color: #c0c0c0;
   cursor: default;
   z-index: 1;
   box-shadow: 0px 0px 34px -9px black;
 }
-.shader-view #add-menu #results div.group:hover {
+.graph-view #add-menu #results div.group:hover {
   background: #474747!important;
   color: #dadada!important;
   box-shadow: none;
 }
-.shader-view #add-menu #results div > span:first-child {
+.graph-view #add-menu #results div > span:first-child {
   font-weight: bold;
   padding-left: 10px;
 }
-.shader-view #add-menu #results div > span:last-child {
+.graph-view #add-menu #results div > span:last-child {
   font-style: oblique;
   padding-left: 7px;
 }
-.shader-view #add-menu #results div:first-child {
+.graph-view #add-menu #results div:first-child {
   border-top: 0;
 }
-.shader-view #add-menu #results div:hover,
-.shader-view #add-menu #results div.selected {
+.graph-view #add-menu #results div:hover,
+.graph-view #add-menu #results div.selected {
   background: #5eb7bf;
   color: #000000;
   box-shadow: inset 0px 0px 12px -1px black;
   z-index: 3;
 }
-.shader-view #context-menu {
+.graph-view #context-menu {
   position: absolute;
   width: 100px;
   box-shadow: 0px 0px 25px -4px black;
@@ -1183,51 +1192,51 @@ input[type=checkbox]:checked:after {
   border: 1px solid #444;
   z-index: 2;
 }
-.shader-view #context-menu #options {
+.graph-view #context-menu #options {
   max-height: 300px;
   overflow-y: auto;
 }
-.shader-view #context-menu #options div {
+.graph-view #context-menu #options div {
   padding: 5px;
   border-top: 1px solid #444444;
   cursor: pointer;
   color: #d4d4d4;
   position: relative;
 }
-.shader-view #context-menu #options div.group {
+.graph-view #context-menu #options div.group {
   background: #474747;
   color: #c0c0c0;
   cursor: default;
   z-index: 3;
   box-shadow: 0px 0px 34px -9px black;
 }
-.shader-view #context-menu #options div.group:hover {
+.graph-view #context-menu #options div.group:hover {
   background: #474747!important;
   color: #dadada!important;
   box-shadow: none;
 }
-.shader-view #context-menu #options div > span:first-child {
+.graph-view #context-menu #options div > span:first-child {
   font-weight: bold;
   padding-left: 10px;
 }
-.shader-view #context-menu #options div > span:last-child {
+.graph-view #context-menu #options div > span:last-child {
   font-style: oblique;
   padding-left: 7px;
 }
-.shader-view #context-menu #options div:first-child {
+.graph-view #context-menu #options div:first-child {
   border-top: 0;
 }
-.shader-view #context-menu #options div:hover,
-.shader-view #context-menu #options div.selected {
+.graph-view #context-menu #options div:hover,
+.graph-view #context-menu #options div.selected {
   background: #5eb7bf;
   color: #000000;
   box-shadow: inset 0px 0px 12px -1px black;
   z-index: 3;
 }
-.shader-view .heaps-scene {
+.graph-view .heaps-scene {
   outline: none !important;
 }
-.shader-view .heaps-scene #preview {
+.graph-view .heaps-scene #preview {
   position: absolute;
   width: 300px;
   height: 300px;
@@ -1236,7 +1245,7 @@ input[type=checkbox]:checked:after {
   right: 290px;
   bottom: 35px;
 }
-.shader-view .heaps-scene #status-bar {
+.graph-view .heaps-scene #status-bar {
   position: absolute;
   width: 84%;
   min-height: 20px;
@@ -1245,96 +1254,96 @@ input[type=checkbox]:checked:after {
   left: -1px;
   bottom: -1px;
 }
-.shader-view .heaps-scene #status-bar span {
+.graph-view .heaps-scene #status-bar span {
   padding: 10px;
   vertical-align: sub;
 }
-.shader-view .heaps-scene #status-bar span.error {
+.graph-view .heaps-scene #status-bar span.error {
   color: #c74848;
 }
-.shader-view .heaps-scene svg g {
+.graph-view .heaps-scene svg g {
   stroke: #202020;
 }
-.shader-view .heaps-scene svg g.selected .outline {
+.graph-view .heaps-scene svg g.selected .outline {
   stroke: #668fff;
 }
-.shader-view .heaps-scene svg g.error .outline {
+.graph-view .heaps-scene svg g.error .outline {
   stroke: #ff6666;
 }
-.shader-view .heaps-scene svg .outline {
+.graph-view .heaps-scene svg .outline {
   fill: none;
 }
-.shader-view .heaps-scene svg .head-box {
-  fill: #3e3e3e;
+.graph-view .heaps-scene svg .head-box {
+  fill: #155358;
 }
-.shader-view .heaps-scene svg .title-box {
+.graph-view .heaps-scene svg .title-box {
   fill: #ffffff;
   stroke: none;
   user-select: none;
 }
-.shader-view .heaps-scene svg .title-box::selection {
+.graph-view .heaps-scene svg .title-box::selection {
   background: none;
 }
-.shader-view .heaps-scene svg .nodes,
-.shader-view .heaps-scene svg .properties {
+.graph-view .heaps-scene svg .nodes,
+.graph-view .heaps-scene svg .properties {
   fill: #737373;
   opacity: 0.75;
 }
-.shader-view .heaps-scene svg .hasLink .input-field {
+.graph-view .heaps-scene svg .hasLink .input-field {
   display: none;
 }
-.shader-view .heaps-scene svg .input-node,
-.shader-view .heaps-scene svg .output-node {
+.graph-view .heaps-scene svg .input-node,
+.graph-view .heaps-scene svg .output-node {
   fill: #c8c8c8;
   stroke-width: 13px;
   stroke-opacity: 0;
 }
-.shader-view .heaps-scene svg .input-node.nodeMatch,
-.shader-view .heaps-scene svg .output-node.nodeMatch {
+.graph-view .heaps-scene svg .input-node.nodeMatch,
+.graph-view .heaps-scene svg .output-node.nodeMatch {
   fill: #5ca4ab;
 }
-.shader-view .heaps-scene svg .title-node {
+.graph-view .heaps-scene svg .title-node {
   fill: #ffffff;
   stroke: none;
   user-select: none;
 }
-.shader-view .heaps-scene svg .title-node::selection {
+.graph-view .heaps-scene svg .title-node::selection {
   background: none;
 }
-.shader-view .heaps-scene svg .properties-group span {
+.graph-view .heaps-scene svg .properties-group span {
   color: #ffffff;
   user-select: none;
 }
-.shader-view .heaps-scene svg .properties-group span::selection {
+.graph-view .heaps-scene svg .properties-group span::selection {
   background: none;
 }
-.shader-view .heaps-scene svg .properties-group input[type=text],
-.shader-view .heaps-scene svg .properties-group select {
+.graph-view .heaps-scene svg .properties-group input[type=text],
+.graph-view .heaps-scene svg .properties-group select {
   width: 100%;
 }
-.shader-view .heaps-scene svg .properties-group input[type=text].error {
+.graph-view .heaps-scene svg .properties-group input[type=text].error {
   border: red 1px solid;
 }
-.shader-view .heaps-scene svg .edge {
+.graph-view .heaps-scene svg .edge {
   stroke-width: 2;
   stroke: #c8c8c8;
   fill: transparent;
 }
-.shader-view .heaps-scene svg .edge:not(.draft):hover,
-.shader-view .heaps-scene svg .edge:not(.draft).selected {
+.graph-view .heaps-scene svg .edge:not(.draft):hover,
+.graph-view .heaps-scene svg .edge:not(.draft).selected {
   stroke-width: 5;
   stroke: #72b4ff;
 }
-.shader-view .heaps-scene svg .rect-selection {
+.graph-view .heaps-scene svg .rect-selection {
   stroke: rgba(0, 0, 255, 0.7);
   fill: rgba(70, 70, 116, 0.08);
 }
-.shader-view .tabs {
+.graph-view .tabs {
   width: 280px;
   padding-top: 10px;
   border-left: 1px solid #444444;
 }
-.shader-view .tabs span {
+.graph-view .tabs span {
   margin-left: 5px;
   font-size: 15px;
   font-weight: bold;

+ 12 - 2
bin/style.less

@@ -1145,7 +1145,7 @@ input[type=checkbox] {
 }
 
 /* Shader Editor */
-.shader-view {
+.graph-view {
 	.tabs {
 		z-index: 1;
     	background: #222222;
@@ -1195,6 +1195,10 @@ input[type=checkbox] {
 							padding: 5px;
 							box-shadow: inset 0px 13px 6px -15px black;
 
+							div:first-child {
+								display: inline;
+							}
+
 							div {
 								width: 100%;
 								height: 20px;
@@ -1207,6 +1211,12 @@ input[type=checkbox] {
 									font-weight: normal;
 								}
 							}
+							.texture-preview {
+								background-repeat: no-repeat;
+								background-size: 20px 20px!important;
+								border: 2px #444444 solid;
+								width: 20px;
+							}
 							.action-btns {
 								input {
 									float: right;
@@ -1431,7 +1441,7 @@ input[type=checkbox] {
 			}
 
 			.head-box {
-				fill: #3e3e3e;
+				fill: #155358;
 			}
 
 			.title-box {

+ 30 - 589
hide/view/ShaderEditor.hx → hide/view/Graph.hx

@@ -1,22 +1,13 @@
 package hide.view;
 
-import hrt.shgraph.ShaderException;
 import haxe.Timer;
-import h3d.shader.LineShader;
-import h3d.shader.ColorAdd;
-using hxsl.Ast.Type;
 
-import haxe.rtti.Rtti;
 import haxe.rtti.Meta;
-import hxsl.Shader;
-import hxsl.SharedShader;
-import hide.comp.SceneEditor;
 import js.jquery.JQuery;
 import h2d.col.Point;
 import h2d.col.IPoint;
 import hide.comp.SVG;
 import hide.view.shadereditor.Box;
-import hrt.shgraph.ShaderGraph;
 import hrt.shgraph.ShaderNode;
 import hrt.shgraph.ShaderType;
 import hrt.shgraph.ShaderType.SType;
@@ -26,13 +17,12 @@ typedef NodeInfo = { name : String, description : String, key : String };
 
 typedef Edge = { from : Box, nodeFrom : JQuery, to : Box, nodeTo : JQuery, elt : JQuery };
 
-class ShaderEditor extends FileView {
+class Graph extends FileView {
 
 	var parent : JQuery;
 	var editor : SVG;
 	var editorMatrix : JQuery;
 	var statusBar : JQuery;
-	var parametersList : JQuery;
 
 	var listOfClasses : Map<String, Array<NodeInfo>>;
 	var addMenu : JQuery;
@@ -45,6 +35,11 @@ class ShaderEditor extends FileView {
 
 	var transformMatrix : Array<Float> = [1, 0, 0, 1, 0, 0];
 	var isPanning : Bool = false;
+
+
+	// used for moving when mouse is close to borders
+	static var BORDER_SIZE = 75;
+	static var SPEED_BORDER_MOVE = 0.05;
 	var timerUpdateView : Timer;
 
 	// used for selection
@@ -66,87 +61,25 @@ class ShaderEditor extends FileView {
 	// used for deleting
 	var currentEdge : Edge;
 
-	// used to preview
-	var sceneEditor : SceneEditor;
-
-	var root : hrt.prefab.Prefab;
-	var obj : h3d.scene.Object;
-	var plight : hrt.prefab.Prefab;
-	var light : h3d.scene.Object;
-	var lightDirection : h3d.Vector;
-
-	var shaderGraph : ShaderGraph;
-
-	var timerCompileShader : Timer;
-	var COMPILE_SHADER_DEBOUNCE : Int = 100;
-	var shaderGenerated : Shader;
-
 	override function onDisplay() {
-		shaderGraph = new ShaderGraph(getPath());
-		addMenu = null;
 		element.html('
 			<div class="flex vertical">
-				<div class="flex-elt shader-view">
+				<div class="flex-elt graph-view">
 					<div class="heaps-scene" tabindex="0" >
 					</div>
-					<div class="tabs">
-						<span>Parameters</span>
-						<div class="tab expand" name="Scene" icon="sitemap">
-							<div class="hide-block" >
-								<div id="parametersList" class="hide-scene-tree hide-list">
-								</div>
-							</div>
-							<div class="options-block hide-block">
-								<input id="addParameter" type="button" value="Add parameter" />
-								<input id="launchCompileShader" type="button" value="Compile shader" />
-								<input id="saveShader" type="button" value="Save" />
-							</div>
-						</div>
+					<div id="rightPanel" class="tabs">
 					</div>
 				</div>
 			</div>');
 		parent = element.find(".heaps-scene");
 		editor = new SVG(parent);
-		var preview = new Element('<div id="preview" ></div>');
-		preview.on("mousedown", function(e) { e.stopPropagation(); });
-		preview.on("wheel", function(e) { e.stopPropagation(); });
-		parent.append(preview);
 		statusBar = new Element('<div id="status-bar" ><span> </span></div>').appendTo(parent).find("span");
 
-		var def = new hrt.prefab.Library();
-		new hrt.prefab.RenderProps(def).name = "renderer";
-		var l = new hrt.prefab.Light(def);
-		l.name = "sunLight";
-		l.kind = Directional;
-		l.power = 1.5;
-		var q = new h3d.Quat();
-		q.initDirection(new h3d.Vector(-1,-1.5,-3));
-		var a = q.toEuler();
-		l.rotationX = Math.round(a.x * 180 / Math.PI);
-		l.rotationY = Math.round(a.y * 180 / Math.PI);
-		l.rotationZ = Math.round(a.z * 180 / Math.PI);
-		l.shadows.mode = Dynamic;
-		l.shadows.size = 1024;
-		root = def;
-
-		sceneEditor = new hide.comp.SceneEditor(this, root);
-		sceneEditor.editorDisplay = false;
-		sceneEditor.onRefresh = onRefresh;
-		sceneEditor.onUpdate = update;
-		sceneEditor.view.keys = new hide.ui.Keys(null); // Remove SceneEditor Shortcuts
-		sceneEditor.view.keys.register("save", function() {
-			save();
-			skipNextChange = true;
-			modified = false;
-		});
-
 		editorMatrix = editor.group(editor.element);
 
 		// rectangle Selection
 		parent.on("mousedown", function(e) {
 
-			closeAddMenu();
-
 			if (e.button == 0) {
 				startRecSelection = new Point(lX(e.clientX), lY(e.clientY));
 				if (currentEdge != null) {
@@ -176,20 +109,6 @@ class ShaderEditor extends FileView {
 			if(timerUpdateView != null)
 				stopUpdateViewPosition();
 			if (e.button == 0) {
-				// Stop link creation
-				if (isCreatingLink != None) {
-					if (startLinkBox != null && endLinkBox != null && createEdgeInShaderGraph()) {
-
-					} else {
-						if (currentLink != null) currentLink.remove();
-						currentLink = null;
-					}
-					startLinkBox = endLinkBox = null;
-					startLinkGrNode = endLinkNode = null;
-					isCreatingLink = None;
-					clearAvailableNodes();
-					return;
-				}
 
 				// Stop rectangle selection
 				lastClickDrag = null;
@@ -224,12 +143,6 @@ class ShaderEditor extends FileView {
 
 		parent.on("keydown", function(e) {
 
-			if (e.shiftKey && e.keyCode != 16) {
-				openAddMenu();
-
-				return;
-			}
-
 			if (e.keyCode == 46) {
 				if (currentEdge != null) {
 					removeEdge(currentEdge);
@@ -243,269 +156,13 @@ class ShaderEditor extends FileView {
 				return;
 			} else if (e.keyCode == 32) {
 
-			} else if (e.keyCode == 83 && e.ctrlKey) { // CTRL+S : save
-				shaderGraph.save();
-			} else if (e.keyCode == 74 && e.ctrlKey) { // CTRL+J : test
-				trace(shaderGraph.hasCycle());
 			}
 		});
 
-		element.find("#addParameter").on("click", function() {
-			function createElement(name : String, type : Type) : Element {
-				var elt = new Element('
-					<div>
-						<span> ${name} </span>
-					</div>');
-				elt.on("click", function() {
-					addParameter(type);
-				});
-				return elt;
-			}
-
-			customContextMenu([
-				createElement("Boolean", TBool),
-				createElement("Color", TVec(4, VFloat)),
-				createElement("Texture", TSampler2D)
-				]);
-		});
-
-		element.find("#launchCompileShader").on("click", function() {
-			launchCompileShader();
-		});
-
-		element.find("#saveShader").on("click", function() {
-			save();
-		});
-
-		parametersList = element.find("#parametersList");
-
-		editorMatrix.on("change", "input, select", function(ev) {
-			try {
-				shaderGraph.nodeUpdated(ev.target.closest(".box").id);
-				launchCompileShader();
-			} catch (e : Dynamic) {
-				if (Std.is(e, ShaderException)) {
-					error(e.msg, e.idBox);
-				}
-			}
-		});
-
-		addMenu = null;
-		listOfClasses = new Map<String, Array<NodeInfo>>();
-		var mapOfNodes = ShaderNode.registeredNodes;
-		for (key in mapOfNodes.keys()) {
-			var metas = haxe.rtti.Meta.getType(mapOfNodes[key]);
-			if (metas.group == null) {
-				continue;
-			}
-			var group = metas.group[0];
-
-			if (listOfClasses[group] == null)
-				listOfClasses[group] = new Array<NodeInfo>();
-
-			listOfClasses[group].push({ name : (metas.name != null) ? metas.name[0] : key , description : (metas.description != null) ? metas.description[0] : "" , key : key });
-		}
-
-		for (key in listOfClasses.keys()) {
-			listOfClasses[key].sort(function (a, b): Int {
-				if (a.name < b.name) return -1;
-				else if (a.name > b.name) return 1;
-				return 0;
-			});
-		}
-
 		listOfBoxes = [];
 		listOfEdges = [];
 
 		updateMatrix();
-
-		new Element("svg").ready(function(e) {
-
-			for (node in shaderGraph.getNodes()) {
-				addBox(new Point(node.x, node.y), std.Type.getClass(node.instance), node.instance);
-			}
-
-			new Element(".nodes").ready(function(e) {
-
-				for (box in listOfBoxes) {
-					for (key in box.getShaderNode().getInputsKey()) {
-						var input = box.getShaderNode().getInput(key);
-						if (input != null) {
-							var fromBox : Box = null;
-							for (boxFrom in listOfBoxes) {
-								if (boxFrom.getId() == input.node.id) {
-									fromBox = boxFrom;
-									break;
-								}
-							}
-							var nodeFrom = fromBox.getElement().find('[field=${input.getKey()}]');
-							var nodeTo = box.getElement().find('[field=${key}]');
-							createEdgeInEditorGraph({from: fromBox, nodeFrom: nodeFrom, to : box, nodeTo: nodeTo, elt : createCurve(nodeFrom, nodeTo) });
-						}
-					}
-				}
-
-			});
-		});
-
-	}
-
-	override function save() {
-		var content = shaderGraph.save();
-		currentSign = haxe.crypto.Md5.encode(content);
-		sys.io.File.saveContent(getPath(), content);
-		super.save();
-		info("Shader saved");
-	}
-
-	function update(dt : Float) {
-
-	}
-
-	function onRefresh() {
-
-		plight = root.getAll(hrt.prefab.Light)[0];
-		if( plight != null ) {
-			this.light = sceneEditor.context.shared.contexts.get(plight).local3d;
-			lightDirection = this.light.getDirection();
-		}
-
-		obj = sceneEditor.scene.loadModel("fx/Common/PrimitiveShapes/Sphere.fbx", true);
-		sceneEditor.scene.s3d.addChild(obj);
-
-		element.find("#preview").first().append(sceneEditor.scene.element);
-
-		launchCompileShader();
-	}
-
-	function addParameter(type : Type, ?title : String, ?value : Dynamic) {
-
-		//TODO: link with shadergraph
-		//TODO: drag to graph
-		//TODO: edit => edit everywhere
-		//TODO: type sampler => file choosen
-
-		var exist = (title != null);
-
-		var elt = new Element('<div class="parameter"></div>').appendTo(parametersList);
-		var content = new Element('<div class="content" ${(!exist) ? "style='display: none'" : "" } ></div>');
-		var defaultValue = new Element("<div><span>Default: </span></div>").appendTo(content);
-
-		var typeName = "";
-
-		switch(type) {
-			case TBool:
-				var checkbox = new Element('<input type="checkbox" />');
-				checkbox.prop("checked", ${(value != null && value == "true") ? true : false});
-				defaultValue.append(checkbox);
-				typeName = "Boolean";
-			default:
-				defaultValue.append(new Element('<input type="text" value="${(value != null) ? value : ""}" />'));
-				typeName = "String";
-		}
-
-		var header = new Element('<div class="header">
-									<div class="title">
-										<i class="fa fa-chevron-right" ></i>
-										<input class="input-title" type="input" value="${(title != null) ? title : ""}" />
-									</div>
-									<div class="type">
-										<span>${typeName}</span>
-									</div>
-								</div>');
-
-		header.appendTo(elt);
-		content.appendTo(elt);
-		var actionBtns = new Element('<div class="action-btns" ></div>').appendTo(content);
-		var deleteBtn = new Element('<input type="button" value="Delete" />');
-		deleteBtn.on("click", function() {
-			elt.remove();
-		});
-		deleteBtn.appendTo(actionBtns);
-
-
-		var inputTitle = elt.find(".input-title");
-		inputTitle.on("click", function(e) {
-			e.stopPropagation();
-		});
-		inputTitle.on("change", function(e) {
-		});
-		elt.find(".header").on("click", function(e) {
-			content.toggle();
-			var icon = elt.find(".fa");
-			if (icon.hasClass("fa-chevron-right")) {
-				icon.removeClass("fa-chevron-right");
-				icon.addClass("fa-chevron-down");
-			} else {
-				icon.addClass("fa-chevron-right");
-				icon.removeClass("fa-chevron-down");
-			}
-		});
-	}
-
-	function launchCompileShader() {
-		if (timerCompileShader != null) {
-			timerCompileShader.stop();
-		}
-		timerCompileShader = new Timer(COMPILE_SHADER_DEBOUNCE);
-		timerCompileShader.run = function() {
-			compileShader();
-			timerCompileShader.stop();
-		};
-	}
-
-	function compileShader() {
-		var saveShader : Shader = null;
-		if (shaderGenerated != null)
-			saveShader = shaderGenerated.clone();
-		try {
-			var timeStart = Date.now().getTime();
-			var s = new SharedShader("");
-			s.data = shaderGraph.buildFragment();
-			@:privateAccess s.initialize();
-
-			if (shaderGenerated != null)
-				for (m in obj.getMaterials())
-					m.mainPass.removeShader(shaderGenerated);
-
-			shaderGenerated = new hxsl.DynamicShader(s);
-			for (m in obj.getMaterials()) {
-				m.mainPass.addShader(shaderGenerated);
-			}
-			@:privateAccess sceneEditor.scene.render(sceneEditor.scene.engine);
-			info('Shader compiled in  ${Date.now().getTime() - timeStart}ms');
-
-		} catch (e : Dynamic) {
-			if (Std.is(e, String)) {
-				var str : String = e;
-				if (str.split(":")[0] == "An error occurred compiling the shaders") { // aie
-					error("Compilation of shader failed > " + str);
-					if (shaderGenerated != null)
-						for (m in obj.getMaterials())
-							m.mainPass.removeShader(shaderGenerated);
-					if (saveShader != null) {
-						shaderGenerated = saveShader;
-						for (m in obj.getMaterials()) {
-							m.mainPass.addShader(shaderGenerated);
-						}
-					}
-					return;
-				}
-			} else if (Std.is(e, ShaderException)) {
-				error(e.msg, e.idBox);
-				return;
-			}
-			error("Compilation of shader failed > " + e);
-			if (shaderGenerated != null)
-				for (m in obj.getMaterials())
-					m.mainPass.removeShader(shaderGenerated);
-			if (saveShader != null) {
-				shaderGenerated = saveShader;
-				for (m in obj.getMaterials()) {
-					m.mainPass.addShader(shaderGenerated);
-				}
-			}
-		}
 	}
 
 	function mouseMoveFunction(clientX : Int, clientY : Int) {
@@ -565,7 +222,7 @@ class ShaderEditor extends FileView {
 
 			for (b in listOfBoxesSelected) {
 				b.setPosition(b.getX() + dx, b.getY() + dy);
-				shaderGraph.setPosition(b.getId(), b.getX(), b.getY());
+				updatePosition(b.getId(), b.getX(), b.getY());
 				// move edges from and to this box
 				for (edge in listOfEdges) {
 					if (edge.from == b || edge.to == b) {
@@ -587,11 +244,7 @@ class ShaderEditor extends FileView {
 		}
 	}
 
-	function addNode(p : Point, nodeClass : Class<ShaderNode>) {
-		var node = shaderGraph.addNode(p.x, p.y, nodeClass);
-
-		addBox(p, nodeClass, node);
-	}
+	dynamic function updatePosition(id : Int, x : Float, y : Float) { }
 
 	function addBox(p : Point, nodeClass : Class<ShaderNode>, node : ShaderNode) {
 
@@ -643,7 +296,7 @@ class ShaderEditor extends FileView {
 
 				var defaultValue = null;
 				if (m.input.length >= 2 && inputMeta[1]) {
-					defaultValue = Reflect.field(box.getShaderNode(), 'prop_${f}');
+					defaultValue = Reflect.field(box.getInstance(), 'prop_${f}');
 					if (defaultValue == null) {
 						defaultValue = "0";
 					}
@@ -656,7 +309,7 @@ class ShaderEditor extends FileView {
 						if (Math.isNaN(tmpValue) ) {
 							fieldEditInput.addClass("error");
 						} else {
-							Reflect.setField(box.getShaderNode(), 'prop_${f}', tmpValue);
+							Reflect.setField(box.getInstance(), 'prop_${f}', tmpValue);
 							fieldEditInput.val(tmpValue);
 							fieldEditInput.removeClass("error");
 						}
@@ -710,30 +363,27 @@ class ShaderEditor extends FileView {
 		}
 		box.dispose();
 		listOfBoxes.remove(box);
-		shaderGraph.removeNode(box.getId());
 	}
 
 	function removeEdge(edge : Edge) {
 		edge.elt.remove();
 		edge.nodeTo.removeAttr("hasLink");
 		edge.nodeTo.parent().removeClass("hasLink");
-		shaderGraph.removeEdge(edge.to.getId(), edge.nodeTo.attr("field"));
 		listOfEdges.remove(edge);
-		launchCompileShader();
 	}
 
 	function setAvailableInputNodes(boxOutput : Box, field : String) {
-		var type = boxOutput.getShaderNode().getOutputType(field);
+		var type = boxOutput.getInstance().getOutputType(field);
 		var sType : SType;
 		if (type == null) {
-			sType = boxOutput.getShaderNode().getOutputInfo(field);
+			sType = boxOutput.getInstance().getOutputInfo(field);
 		} else {
 			sType = ShaderType.getType(type);
 		}
 
 		for (box in listOfBoxes) {
 			for (input in box.inputs) {
-				if (box.getShaderNode().checkTypeAndCompatibilyInput(input.attr("field"), sType)) {
+				if (box.getInstance().checkTypeAndCompatibilyInput(input.attr("field"), sType)) {
 					input.addClass("nodeMatch");
 				}
 			}
@@ -744,14 +394,14 @@ class ShaderEditor extends FileView {
 		for (box in listOfBoxes) {
 			for (output in box.outputs) {
 				var outputField = output.attr("field");
-				var type = box.getShaderNode().getOutputType(outputField);
+				var type = box.getInstance().getOutputType(outputField);
 				var sType : SType;
 				if (type == null) {
-					sType = box.getShaderNode().getOutputInfo(outputField);
+					sType = box.getInstance().getOutputInfo(outputField);
 				} else {
 					sType = ShaderType.getType(type);
 				}
-				if (boxInput.getShaderNode().checkTypeAndCompatibilyInput(field, sType)) {
+				if (boxInput.getInstance().checkTypeAndCompatibilyInput(field, sType)) {
 					output.addClass("nodeMatch");
 				}
 			}
@@ -779,46 +429,6 @@ class ShaderEditor extends FileView {
 		new Element(".box").removeClass("error");
 	}
 
-	function createEdgeInShaderGraph() : Bool {
-		var startLinkNode = startLinkGrNode.find(".node");
-		if (isCreatingLink == FromInput) {
-			var tmpBox = startLinkBox;
-			startLinkBox = endLinkBox;
-			endLinkBox = tmpBox;
-
-			var tmpNode = startLinkNode;
-			startLinkNode = endLinkNode;
-			endLinkNode = tmpNode;
-		}
-
-		var newEdge = { from: startLinkBox, nodeFrom : startLinkNode, to : endLinkBox, nodeTo : endLinkNode, elt : currentLink };
-		if (endLinkNode.attr("hasLink") != null) {
-			for (edge in listOfEdges) {
-				if (edge.nodeTo.is(endLinkNode)) {
-					removeEdge(edge);
-					break;
-				}
-			}
-		}
-		try {
-			if (shaderGraph.addEdge({ idOutput: startLinkBox.getId(), nameOutput: startLinkNode.attr("field"), idInput: endLinkBox.getId(), nameInput: endLinkNode.attr("field") })) {
-				createEdgeInEditorGraph(newEdge);
-				currentLink.removeClass("draft");
-				currentLink = null;
-				launchCompileShader();
-				return true;
-			} else {
-				error("This edge creates a cycle.");
-				return false;
-			}
-		} catch (e : Dynamic) {
-			if (Std.is(e, ShaderException)) {
-				error(e.msg, e.idBox);
-			}
-			return false;
-		}
-	}
-
 	function createEdgeInEditorGraph(edge) {
 		listOfEdges.push(edge);
 		edge.nodeTo.attr("hasLink", "true");
@@ -940,7 +550,7 @@ class ShaderEditor extends FileView {
 	}
 
 	function customContextMenu( elts : Array<Element> ) {
-			closeCustomContextMenu();
+		closeCustomContextMenu();
 
 		if (elts.length == 0) return;
 
@@ -953,9 +563,6 @@ class ShaderEditor extends FileView {
 
 		var posCursor = new IPoint(Std.int(ide.mouseX - parent.offset().left), Std.int(ide.mouseY - parent.offset().top));
 
-		contextMenu.css("left", posCursor.x);
-		contextMenu.css("top", posCursor.y);
-
 		contextMenu.on("mousedown", function(e) {
 			e.stopPropagation();
 		});
@@ -968,6 +575,9 @@ class ShaderEditor extends FileView {
 		for (elt in elts) {
 			elt.appendTo(options);
 		}
+
+		contextMenu.css("left", Math.min(posCursor.x, element.width() - contextMenu.width() - 5));
+		contextMenu.css("top", Math.min(posCursor.y, element.height() - contextMenu.height() - 5));
 	}
 
 	function closeCustomContextMenu() {
@@ -977,171 +587,6 @@ class ShaderEditor extends FileView {
 		}
 	}
 
-	function openAddMenu() {
-		if (addMenu != null) {
-			var input = addMenu.find("#search-input");
-			input.val("");
-			addMenu.show();
-			input.focus();
-			var posCursor = new IPoint(Std.int(ide.mouseX - parent.offset().left), Std.int(ide.mouseY - parent.offset().top));
-
-			addMenu.css("left", posCursor.x);
-			addMenu.css("top", posCursor.y);
-			return;
-		}
-
-		addMenu = new Element('
-		<div id="add-menu">
-			<div class="search-container">
-				<div class="icon" >
-					<i class="fa fa-search"></i>
-				</div>
-				<div class="search-bar" >
-					<input type="text" id="search-input" >
-				</div>
-			</div>
-			<div id="results">
-			</div>
-		</div>').appendTo(parent);
-
-		var posCursor = new IPoint(Std.int(ide.mouseX - parent.offset().left), Std.int(ide.mouseY - parent.offset().top));
-
-		addMenu.css("left", posCursor.x);
-		addMenu.css("top", posCursor.y);
-
-		addMenu.on("mousedown", function(e) {
-			e.stopPropagation();
-		});
-
-		var results = addMenu.find("#results");
-		results.on("wheel", function(e) {
-			e.stopPropagation();
-		});
-
-		var keys = listOfClasses.keys();
-		var sortedKeys = [];
-		for (k in keys) {
-			sortedKeys.push(k);
-		}
-		sortedKeys.sort(function (a, b) {
-			if (a < b) return -1;
-			if (a > b) return 1;
-			return 0;
-		});
-
-		for (key in sortedKeys) {
-			new Element('
-				<div class="group" >
-					<span> ${key} </span>
-				</div>').appendTo(results);
-			for (node in listOfClasses[key]) {
-				new Element('
-					<div node="${node.key}" >
-						<span> ${node.name} </span> <span> ${node.description} </span>
-					</div>').appendTo(results);
-			}
-		}
-
-		var input = addMenu.find("#search-input");
-		input.focus();
-		var divs = new Element("#results > div");
-		input.on("keydown", function(ev) {
-			if (ev.keyCode == 38 || ev.keyCode == 40) {
-				ev.stopPropagation();
-				ev.preventDefault();
-
-				if (selectedNode != null)
-					this.selectedNode.removeClass("selected");
-
-				var selector = "div[node]:not([style*='display: none'])";
-				var elt = this.selectedNode;
-
-				if (ev.keyCode == 38) {
-					do {
-						elt = elt.prev();
-					} while (elt.length > 0 && !elt.is(selector));
-				} else if (ev.keyCode == 40) {
-					do {
-						elt = elt.next();
-					} while (elt.length > 0 && !elt.is(selector));
-				}
-				if (elt.length == 1) {
-					this.selectedNode = elt;
-				}
-				if (this.selectedNode != null)
-					this.selectedNode.addClass("selected");
-
-				var offsetDiff = this.selectedNode.offset().top - results.offset().top;
-				if (offsetDiff > 225) {
-					results.scrollTop((offsetDiff-225)+results.scrollTop());
-				} else if (offsetDiff < 35) {
-					results.scrollTop(results.scrollTop()-(35-offsetDiff));
-				}
-			}
-		});
-		input.on("keyup", function(ev) {
-			if (ev.keyCode == 38 || ev.keyCode == 40) {
-				return;
-			}
-
-			if (ev.keyCode == 13) {
-				var key = this.selectedNode.attr("node");
-				var posCursor = new Point(lX(ide.mouseX - 25), lY(ide.mouseY - 10));
-				addNode(posCursor, ShaderNode.registeredNodes[key]);
-				closeAddMenu();
-			} else {
-				if (this.selectedNode != null)
-					this.selectedNode.removeClass("selected");
-				var value = input.val();
-				var children = divs.elements();
-				var isFirst = true;
-				var lastGroup = null;
-				for (elt in children) {
-					if (elt.hasClass("group")) {
-						lastGroup = elt;
-						elt.hide();
-						continue;
-					}
-					if (elt.children().first().html().toLowerCase().indexOf(value.toLowerCase()) != -1) {
-						if (isFirst) {
-							this.selectedNode = elt;
-							isFirst = false;
-						}
-						elt.show();
-						if (lastGroup != null)
-							lastGroup.show();
-					} else {
-						elt.hide();
-					}
-				}
-				if (this.selectedNode != null)
-					this.selectedNode.addClass("selected");
-			}
-		});
-		divs.mouseover(function(ev) {
-			if (ev.getThis().hasClass("group")) {
-				return;
-			}
-			this.selectedNode.removeClass("selected");
-			this.selectedNode = ev.getThis();
-			this.selectedNode.addClass("selected");
-		});
-		divs.mouseup(function(ev) {
-			if (ev.getThis().hasClass("group")) {
-				return;
-			}
-			var key = ev.getThis().attr("node");
-			var posCursor = new Point(lX(ide.mouseX - 25), lY(ide.mouseY - 10));
-			addNode(posCursor, ShaderNode.registeredNodes[key]);
-			closeAddMenu();
-		});
-	}
-
-	function closeAddMenu() {
-		if (addMenu != null)
-			addMenu.hide();
-	}
-
 	function clearSelectionBoxes() {
 		for(b in listOfBoxesSelected) b.setSelected(false);
 		listOfBoxesSelected = [];
@@ -1153,28 +598,26 @@ class ShaderEditor extends FileView {
 	function startUpdateViewPosition() {
 		if (timerUpdateView != null)
 			return;
-		var PADDING_BOUNDS = 75;
-		var SPEED_BOUNDS = 0.1;
 		timerUpdateView = new Timer(0);
 		timerUpdateView.run = function() {
 			var posCursor = new Point(ide.mouseX - parent.offset().left, ide.mouseY - parent.offset().top);
 			var wasUpdated = false;
-			if (posCursor.x < PADDING_BOUNDS) {
-				pan(new Point((PADDING_BOUNDS - posCursor.x)*SPEED_BOUNDS, 0));
+			if (posCursor.x < BORDER_SIZE) {
+				pan(new Point((BORDER_SIZE - posCursor.x)*SPEED_BORDER_MOVE, 0));
 				wasUpdated = true;
 			}
-			if (posCursor.y < PADDING_BOUNDS) {
-				pan(new Point(0, (PADDING_BOUNDS - posCursor.y)*SPEED_BOUNDS));
+			if (posCursor.y < BORDER_SIZE) {
+				pan(new Point(0, (BORDER_SIZE - posCursor.y)*SPEED_BORDER_MOVE));
 				wasUpdated = true;
 			}
-			var rightBorder = parent.width() - PADDING_BOUNDS;
+			var rightBorder = parent.width() - BORDER_SIZE;
 			if (posCursor.x > rightBorder) {
-				pan(new Point((rightBorder - posCursor.x)*SPEED_BOUNDS, 0));
+				pan(new Point((rightBorder - posCursor.x)*SPEED_BORDER_MOVE, 0));
 				wasUpdated = true;
 			}
-			var botBorder = parent.height() - PADDING_BOUNDS;
+			var botBorder = parent.height() - BORDER_SIZE;
 			if (posCursor.y > botBorder) {
-				pan(new Point(0, (botBorder - posCursor.y)*SPEED_BOUNDS));
+				pan(new Point(0, (botBorder - posCursor.y)*SPEED_BORDER_MOVE));
 				wasUpdated = true;
 			}
 			mouseMoveFunction(ide.mouseX, ide.mouseY);
@@ -1260,6 +703,4 @@ class ShaderEditor extends FileView {
 		return new Point(lX(x), lY(y));
 	}
 
-	static var _ = FileTree.registerExtension(ShaderEditor,["hlshader"],{ icon : "scribd" });
-
 }

+ 19 - 7
hide/view/shadereditor/Box.hx

@@ -15,7 +15,7 @@ class Box {
 	var height : Int;
 	var propsHeight : Int = 0;
 
-	var HEADER_HEIGHT = 27;
+	var HEADER_HEIGHT = 22;
 	@const var NODE_MARGIN = 17;
 	public static var NODE_RADIUS = 5;
 	@const var NODE_TITLE_PADDING = 10;
@@ -24,6 +24,9 @@ class Box {
 	public var inputs : Array<JQuery> = [];
 	public var outputs : Array<JQuery> = [];
 
+	var hasHeader : Bool = true;
+	var color : String;
+
 	var element : JQuery;
 	var propertiesGroup : JQuery;
 
@@ -34,6 +37,9 @@ class Box {
 		if (metas.width != null) {
 			this.width = metas.width[0];
 		}
+		if (Reflect.hasField(metas, "color")) {
+			color = Reflect.field(metas, "color");
+		}
 		var className = (metas.name != null) ? metas.name[0] : "Undefined";
 
 		element = editor.group(parent).addClass("box").addClass("not-selected");
@@ -47,15 +53,20 @@ class Box {
 
 		if (Reflect.hasField(metas, "noheader")) {
 			HEADER_HEIGHT = 0;
+			hasHeader = false;
 		} else {
-			editor.rect(element, 0, 0, this.width, HEADER_HEIGHT).addClass("head-box");
-			editor.text(element, 10, HEADER_HEIGHT-8, className).addClass("title-box");
+			var header = editor.rect(element, 0, 0, this.width, HEADER_HEIGHT).addClass("head-box");
+			if (color != null) header.css("fill", color);
+			editor.text(element, 7, HEADER_HEIGHT-6, className).addClass("title-box");
 		}
 
 		propertiesGroup = editor.group(element).addClass("properties-group");
 
 		// nodes div
-		editor.rect(element, 0, HEADER_HEIGHT, this.width, 0).addClass("nodes");
+		var bg = editor.rect(element, 0, HEADER_HEIGHT, this.width, 0).addClass("nodes");
+		if (!hasHeader && color != null) {
+			bg.css("fill", color);
+		}
 		editor.line(element, width/2, HEADER_HEIGHT, width/2, 0, {display: "none"}).addClass("nodes-separator");
 	}
 
@@ -103,8 +114,9 @@ class Box {
 			element.find(".output-node-group > .title-node").html("");
 		}
 
-			// create properties box
-		editor.rect(propertiesGroup, 0, 0, this.width, 0).addClass("properties");
+		// create properties box
+		var bgParam = editor.rect(propertiesGroup, 0, 0, this.width, 0).addClass("properties");
+		if (!hasHeader && color != null) bgParam.css("fill", color);
 		propsHeight = 5;
 
 		for (p in props) {
@@ -160,7 +172,7 @@ class Box {
 	public function getId() {
 		return this.nodeInstance.id;
 	}
-	public function getShaderNode() {
+	public function getInstance() {
 		return this.nodeInstance;
 	}
 	public function getX() {

+ 700 - 0
hide/view/shadereditor/ShaderEditor.hx

@@ -0,0 +1,700 @@
+package hide.view.shadereditor;
+
+import hrt.shgraph.ShaderParam;
+import hrt.shgraph.ShaderException;
+import haxe.Timer;
+using hxsl.Ast.Type;
+
+import haxe.rtti.Meta;
+import hxsl.Shader;
+import hxsl.SharedShader;
+import hide.comp.SceneEditor;
+import js.jquery.JQuery;
+import h2d.col.Point;
+import h2d.col.IPoint;
+import hide.view.shadereditor.Box;
+import hrt.shgraph.ShaderGraph;
+import hrt.shgraph.ShaderNode;
+
+class ShaderEditor extends hide.view.Graph {
+
+	var parametersList : JQuery;
+	var draggedParamId : Int;
+
+
+	// used to preview
+	var sceneEditor : SceneEditor;
+
+	var root : hrt.prefab.Prefab;
+	var obj : h3d.scene.Object;
+	var plight : hrt.prefab.Prefab;
+	var light : h3d.scene.Object;
+	var lightDirection : h3d.Vector;
+
+	var shaderGraph : ShaderGraph;
+
+	var timerCompileShader : Timer;
+	var COMPILE_SHADER_DEBOUNCE : Int = 100;
+	var shaderGenerated : Shader;
+
+	override function onDisplay() {
+		super.onDisplay();
+		shaderGraph = new ShaderGraph(getPath());
+		addMenu = null;
+
+		element.find("#rightPanel").html('
+						<span>Parameters</span>
+						<div class="tab expand" name="Scene" icon="sitemap">
+							<div class="hide-block" >
+								<div id="parametersList" class="hide-scene-tree hide-list">
+								</div>
+							</div>
+							<div class="options-block hide-block">
+								<input id="createParameter" type="button" value="Add parameter" />
+								<input id="launchCompileShader" type="button" value="Compile shader" />
+								<input id="saveShader" type="button" value="Save" />
+							</div>
+						</div>)');
+		parent.on("drop", function(e) {
+			var posCursor = new Point(lX(ide.mouseX - 25), lY(ide.mouseY - 10));
+			var node = Std.instance(shaderGraph.addNode(posCursor.x, posCursor.y, ShaderParam), ShaderParam);
+			node.parameterId = draggedParamId;
+			var paramShader = shaderGraph.getParameter(draggedParamId);
+			node.variable = paramShader.variable;
+			node.setName(paramShader.name);
+			node.computeOutputs();
+			addBox(posCursor, ShaderParam, node);
+		});
+
+		var preview = new Element('<div id="preview" ></div>');
+		preview.on("mousedown", function(e) { e.stopPropagation(); });
+		preview.on("wheel", function(e) { e.stopPropagation(); });
+		parent.append(preview);
+
+		var def = new hrt.prefab.Library();
+		new hrt.prefab.RenderProps(def).name = "renderer";
+		var l = new hrt.prefab.Light(def);
+		l.name = "sunLight";
+		l.kind = Directional;
+		l.power = 1.5;
+		var q = new h3d.Quat();
+		q.initDirection(new h3d.Vector(-1,-1.5,-3));
+		var a = q.toEuler();
+		l.rotationX = Math.round(a.x * 180 / Math.PI);
+		l.rotationY = Math.round(a.y * 180 / Math.PI);
+		l.rotationZ = Math.round(a.z * 180 / Math.PI);
+		l.shadows.mode = Dynamic;
+		l.shadows.size = 1024;
+		root = def;
+
+		sceneEditor = new hide.comp.SceneEditor(this, root);
+		sceneEditor.editorDisplay = false;
+		sceneEditor.onRefresh = onRefresh;
+		sceneEditor.onUpdate = function(dt : Float) {};
+		sceneEditor.view.keys = new hide.ui.Keys(null); // Remove SceneEditor Shortcuts
+		sceneEditor.view.keys.register("save", function() {
+			save();
+			skipNextChange = true;
+			modified = false;
+		});
+
+		editorMatrix = editor.group(editor.element);
+
+		element.on("mousedown", function(e) {
+			closeAddMenu();
+			closeCustomContextMenu();
+		});
+
+		parent.on("mouseup", function(e) {
+			if (e.button == 0) {
+				// Stop link creation
+				if (isCreatingLink != None) {
+					if (startLinkBox != null && endLinkBox != null && createEdgeInShaderGraph()) {
+
+					} else {
+						if (currentLink != null) currentLink.remove();
+						currentLink = null;
+					}
+					startLinkBox = endLinkBox = null;
+					startLinkGrNode = endLinkNode = null;
+					isCreatingLink = None;
+					clearAvailableNodes();
+					return;
+				}
+				return;
+			}
+		});
+
+		parent.on("keydown", function(e) {
+
+			if (e.shiftKey && e.keyCode != 16) {
+				openAddMenu();
+
+				return;
+			}
+			if (e.keyCode == 83 && e.ctrlKey) { // CTRL+S : save
+				shaderGraph.save();
+			}
+		});
+
+		element.find("#createParameter").on("click", function() {
+			function createElement(name : String, type : Type) : Element {
+				var elt = new Element('
+					<div>
+						<span> ${name} </span>
+					</div>');
+				elt.on("click", function() {
+					createParameter(type);
+				});
+				return elt;
+			}
+
+			customContextMenu([
+				createElement("Number", TFloat),
+				createElement("Color", TVec(4, VFloat)),
+				createElement("Texture", TSampler2D)
+				]);
+		});
+
+		element.find("#launchCompileShader").on("click", function() {
+			launchCompileShader();
+		});
+
+		element.find("#saveShader").on("click", function() {
+			save();
+		});
+
+		parametersList = element.find("#parametersList");
+
+		editorMatrix.on("change", "input, select", function(ev) {
+			try {
+				shaderGraph.nodeUpdated(ev.target.closest(".box").id);
+				launchCompileShader();
+			} catch (e : Dynamic) {
+				if (Std.is(e, ShaderException)) {
+					error(e.msg, e.idBox);
+				}
+			}
+		});
+
+		addMenu = null;
+		listOfClasses = new Map<String, Array<Graph.NodeInfo>>();
+		var mapOfNodes = ShaderNode.registeredNodes;
+		for (key in mapOfNodes.keys()) {
+			var metas = haxe.rtti.Meta.getType(mapOfNodes[key]);
+			if (metas.group == null) {
+				continue;
+			}
+			var group = metas.group[0];
+
+			if (listOfClasses[group] == null)
+				listOfClasses[group] = new Array<Graph.NodeInfo>();
+
+			listOfClasses[group].push({ name : (metas.name != null) ? metas.name[0] : key , description : (metas.description != null) ? metas.description[0] : "" , key : key });
+		}
+
+		for (key in listOfClasses.keys()) {
+			listOfClasses[key].sort(function (a, b): Int {
+				if (a.name < b.name) return -1;
+				else if (a.name > b.name) return 1;
+				return 0;
+			});
+		}
+
+		listOfBoxes = [];
+		listOfEdges = [];
+
+		updateMatrix();
+
+		new Element("svg").ready(function(e) {
+
+			for (node in shaderGraph.getNodes()) {
+				var paramNode = Std.instance(node.instance, ShaderParam);
+				if (paramNode != null) {
+					var paramShader = shaderGraph.getParameter(paramNode.parameterId);
+					paramNode.variable = paramShader.variable;
+					paramNode.setName(paramShader.name);
+					paramNode.computeOutputs();
+					shaderGraph.nodeUpdated(paramNode.id);
+					addBox(new Point(node.x, node.y), ShaderParam, paramNode);
+				} else {
+					addBox(new Point(node.x, node.y), std.Type.getClass(node.instance), node.instance);
+				}
+			}
+
+			new Element(".nodes").ready(function(e) {
+
+				for (box in listOfBoxes) {
+					for (key in box.getInstance().getInputsKey()) {
+						var input = box.getInstance().getInput(key);
+						if (input != null) {
+							var fromBox : Box = null;
+							for (boxFrom in listOfBoxes) {
+								if (boxFrom.getId() == input.node.id) {
+									fromBox = boxFrom;
+									break;
+								}
+							}
+							var nodeFrom = fromBox.getElement().find('[field=${input.getKey()}]');
+							var nodeTo = box.getElement().find('[field=${key}]');
+							createEdgeInEditorGraph({from: fromBox, nodeFrom: nodeFrom, to : box, nodeTo: nodeTo, elt : createCurve(nodeFrom, nodeTo) });
+						}
+					}
+				}
+
+			});
+
+
+			for (p in shaderGraph.parametersAvailable) {
+				addParameter(p.id, p.name, p.type, p.defaultValue);
+			}
+		});
+
+	}
+
+	override function save() {
+		var content = shaderGraph.save();
+		currentSign = haxe.crypto.Md5.encode(content);
+		sys.io.File.saveContent(getPath(), content);
+		super.save();
+		info("Shader saved");
+	}
+
+	function onRefresh() {
+
+		plight = root.getAll(hrt.prefab.Light)[0];
+		if( plight != null ) {
+			this.light = sceneEditor.context.shared.contexts.get(plight).local3d;
+			lightDirection = this.light.getDirection();
+		}
+
+		obj = sceneEditor.scene.loadModel("fx/Common/PrimitiveShapes/Sphere.fbx", true);
+		sceneEditor.scene.s3d.addChild(obj);
+
+		element.find("#preview").first().append(sceneEditor.scene.element);
+
+		launchCompileShader();
+	}
+
+	function addParameter(id : Int, name : String, type : Type, ?value : Dynamic) {
+		var elt = new Element('<div class="parameter" draggable="true" ></div>').appendTo(parametersList);
+		var content = new Element('<div class="content" ></div>');
+		content.hide();
+		var defaultValue = new Element("<div><span>Default: </span></div>").appendTo(content);
+
+		var typeName = "";
+		switch(type) {
+			case TFloat:
+				var inputText = new Element('<input type="text" style="width: 50px" />').appendTo(defaultValue);
+				if (value != null && value.length > 0) inputText.val(value);
+				inputText.on("change", function() {
+					var tmpValue = Std.parseFloat(inputText.val());
+					if (Math.isNaN(tmpValue) ) {
+						inputText.val("0");
+					} else {
+						inputText.val(tmpValue);
+					}
+					shaderGraph.setParameterDefaultValue(id, inputText.val());
+					launchCompileShader();
+				});
+				typeName = "Number";
+			case TVec(4, VFloat):
+				var parentPicker = new Element('<div style="width: 35px; height: 25px; display: inline-block;"></div>').appendTo(defaultValue);
+				var picker = new hide.comp.ColorPicker(true, parentPicker);
+
+				var start : h3d.Vector;
+				if (value != null)
+					start = h3d.Vector.fromArray([value.x, value.y, value.z, value.w]);
+				else
+					start = h3d.Vector.fromArray([0, 0, 0, 1]);
+				picker.value = start.toColor();
+
+				picker.onChange = function(move) {
+					shaderGraph.setParameterDefaultValue(id, h3d.Vector.fromColor(picker.value));
+					launchCompileShader();
+				};
+				typeName = "Color";
+			case TSampler2D:
+				var parentSampler = new Element('<input type="texturepath" field="sampler2d" />').appendTo(defaultValue);
+
+				var tselect = new hide.comp.TextureSelect(null, parentSampler);
+				if (value != null && value.length > 0) tselect.path = value;
+				tselect.onChange = function() {
+					shaderGraph.setParameterDefaultValue(id, tselect.path);
+					launchCompileShader();
+				}
+				typeName = "Texture";
+			default:
+				var inputText = new Element('<input type="text" />').appendTo(defaultValue);
+				if (value != null && value.length > 0) inputText.val(value);
+				inputText.on("change", function() {
+					if (inputText.val().length > 0) {
+						shaderGraph.setParameterDefaultValue(id, inputText.val());
+						launchCompileShader();
+					}
+				});
+				typeName = "String";
+		}
+
+		var header = new Element('<div class="header">
+									<div class="title">
+										<i class="fa fa-chevron-right" ></i>
+										<input class="input-title" type="input" value="${name}" />
+									</div>
+									<div class="type">
+										<span>${typeName}</span>
+									</div>
+								</div>');
+
+		header.appendTo(elt);
+		content.appendTo(elt);
+		var actionBtns = new Element('<div class="action-btns" ></div>').appendTo(content);
+		var deleteBtn = new Element('<input type="button" value="Delete" />');
+		deleteBtn.on("click", function() {
+			shaderGraph.removeParameter(id);
+			elt.remove();
+		});
+		deleteBtn.appendTo(actionBtns);
+
+		var inputTitle = elt.find(".input-title");
+		inputTitle.on("click", function(e) {
+			e.stopPropagation();
+		});
+		inputTitle.on("change", function(e) {
+			var newName = inputTitle.val();
+			if (shaderGraph.setParameterTitle(id, newName)) {
+				for (b in listOfBoxes) {
+					var shaderParam = Std.instance(b.getInstance(), ShaderParam);
+					if (shaderParam != null && shaderParam.parameterId == id) {
+						shaderParam.setName(newName);
+					}
+				}
+			}
+		});
+		elt.find(".header").on("click", function(ev) {
+			elt.find(".content").toggle();
+			var icon = elt.find(".fa");
+			if (icon.hasClass("fa-chevron-right")) {
+				icon.removeClass("fa-chevron-right");
+				icon.addClass("fa-chevron-down");
+			} else {
+				icon.addClass("fa-chevron-right");
+				icon.removeClass("fa-chevron-down");
+			}
+		});
+
+		elt.on("dragstart", function(e) {
+			draggedParamId = id;
+		});
+
+		return elt;
+	}
+
+	function createParameter(type : Type) {
+
+		//TODO: link with shadergraph
+		//TODO: drag to graph
+		//TODO: edit => edit everywhere
+		//TODO: type sampler => file choosen
+
+		var paramShaderID = shaderGraph.addParameter(type);
+		var paramShader = shaderGraph.getParameter(paramShaderID);
+
+		var elt = addParameter(paramShaderID, paramShader.name, type, null);
+
+		elt.find(".input-title").focus();
+	}
+
+	function launchCompileShader() {
+		if (timerCompileShader != null) {
+			timerCompileShader.stop();
+		}
+		timerCompileShader = new Timer(COMPILE_SHADER_DEBOUNCE);
+		timerCompileShader.run = function() {
+			compileShader();
+			timerCompileShader.stop();
+		};
+	}
+
+	function compileShader() {
+		var saveShader : Shader = null;
+		if (shaderGenerated != null)
+			saveShader = shaderGenerated.clone();
+		try {
+			var timeStart = Date.now().getTime();
+
+			if (shaderGenerated != null)
+				for (m in obj.getMaterials())
+					m.mainPass.removeShader(shaderGenerated);
+
+			shaderGenerated = shaderGraph.compile();
+			for (m in obj.getMaterials()) {
+				m.mainPass.addShader(shaderGenerated);
+			}
+			@:privateAccess sceneEditor.scene.render(sceneEditor.scene.engine);
+			info('Shader compiled in  ${Date.now().getTime() - timeStart}ms');
+
+		} catch (e : Dynamic) {
+			if (Std.is(e, String)) {
+				var str : String = e;
+				if (str.split(":")[0] == "An error occurred compiling the shaders") { // aie
+					error("Compilation of shader failed > " + str);
+					if (shaderGenerated != null)
+						for (m in obj.getMaterials())
+							m.mainPass.removeShader(shaderGenerated);
+					if (saveShader != null) {
+						shaderGenerated = saveShader;
+						for (m in obj.getMaterials()) {
+							m.mainPass.addShader(shaderGenerated);
+						}
+					}
+					return;
+				}
+			} else if (Std.is(e, ShaderException)) {
+				error(e.msg, e.idBox);
+				return;
+			}
+			error("Compilation of shader failed > " + e);
+			if (shaderGenerated != null)
+				for (m in obj.getMaterials())
+					m.mainPass.removeShader(shaderGenerated);
+			if (saveShader != null) {
+				shaderGenerated = saveShader;
+				for (m in obj.getMaterials()) {
+					m.mainPass.addShader(shaderGenerated);
+				}
+			}
+		}
+	}
+
+	function addNode(p : Point, nodeClass : Class<ShaderNode>) {
+		var node = shaderGraph.addNode(p.x, p.y, nodeClass);
+
+		addBox(p, nodeClass, node);
+
+		return node;
+	}
+
+	function createEdgeInShaderGraph() : Bool {
+		var startLinkNode = startLinkGrNode.find(".node");
+		if (isCreatingLink == FromInput) {
+			var tmpBox = startLinkBox;
+			startLinkBox = endLinkBox;
+			endLinkBox = tmpBox;
+
+			var tmpNode = startLinkNode;
+			startLinkNode = endLinkNode;
+			endLinkNode = tmpNode;
+		}
+
+		var newEdge = { from: startLinkBox, nodeFrom : startLinkNode, to : endLinkBox, nodeTo : endLinkNode, elt : currentLink };
+		if (endLinkNode.attr("hasLink") != null) {
+			for (edge in listOfEdges) {
+				if (edge.nodeTo.is(endLinkNode)) {
+					removeEdge(edge);
+					break;
+				}
+			}
+		}
+		try {
+			if (shaderGraph.addEdge({ idOutput: startLinkBox.getId(), nameOutput: startLinkNode.attr("field"), idInput: endLinkBox.getId(), nameInput: endLinkNode.attr("field") })) {
+				createEdgeInEditorGraph(newEdge);
+				currentLink.removeClass("draft");
+				currentLink = null;
+				launchCompileShader();
+				return true;
+			} else {
+				error("This edge creates a cycle.");
+				return false;
+			}
+		} catch (e : Dynamic) {
+			if (Std.is(e, ShaderException)) {
+				error(e.msg, e.idBox);
+			}
+			return false;
+		}
+	}
+
+	function openAddMenu() {
+		if (addMenu != null) {
+			var input = addMenu.find("#search-input");
+			input.val("");
+			addMenu.show();
+			input.focus();
+			var posCursor = new IPoint(Std.int(ide.mouseX - parent.offset().left), Std.int(ide.mouseY - parent.offset().top));
+
+			addMenu.css("left", posCursor.x);
+			addMenu.css("top", posCursor.y);
+			return;
+		}
+
+		addMenu = new Element('
+		<div id="add-menu">
+			<div class="search-container">
+				<div class="icon" >
+					<i class="fa fa-search"></i>
+				</div>
+				<div class="search-bar" >
+					<input type="text" id="search-input" >
+				</div>
+			</div>
+			<div id="results">
+			</div>
+		</div>').appendTo(parent);
+
+		var posCursor = new IPoint(Std.int(ide.mouseX - parent.offset().left), Std.int(ide.mouseY - parent.offset().top));
+
+		addMenu.css("left", posCursor.x);
+		addMenu.css("top", posCursor.y);
+
+		addMenu.on("mousedown", function(e) {
+			e.stopPropagation();
+		});
+
+		var results = addMenu.find("#results");
+		results.on("wheel", function(e) {
+			e.stopPropagation();
+		});
+
+		var keys = listOfClasses.keys();
+		var sortedKeys = [];
+		for (k in keys) {
+			sortedKeys.push(k);
+		}
+		sortedKeys.sort(function (a, b) {
+			if (a < b) return -1;
+			if (a > b) return 1;
+			return 0;
+		});
+
+		for (key in sortedKeys) {
+			new Element('
+				<div class="group" >
+					<span> ${key} </span>
+				</div>').appendTo(results);
+			for (node in listOfClasses[key]) {
+				new Element('
+					<div node="${node.key}" >
+						<span> ${node.name} </span> <span> ${node.description} </span>
+					</div>').appendTo(results);
+			}
+		}
+
+		var input = addMenu.find("#search-input");
+		input.focus();
+		var divs = new Element("#results > div");
+		input.on("keydown", function(ev) {
+			if (ev.keyCode == 38 || ev.keyCode == 40) {
+				ev.stopPropagation();
+				ev.preventDefault();
+
+				if (selectedNode != null)
+					this.selectedNode.removeClass("selected");
+
+				var selector = "div[node]:not([style*='display: none'])";
+				var elt = this.selectedNode;
+
+				if (ev.keyCode == 38) {
+					do {
+						elt = elt.prev();
+					} while (elt.length > 0 && !elt.is(selector));
+				} else if (ev.keyCode == 40) {
+					do {
+						elt = elt.next();
+					} while (elt.length > 0 && !elt.is(selector));
+				}
+				if (elt.length == 1) {
+					this.selectedNode = elt;
+				}
+				if (this.selectedNode != null)
+					this.selectedNode.addClass("selected");
+
+				var offsetDiff = this.selectedNode.offset().top - results.offset().top;
+				if (offsetDiff > 225) {
+					results.scrollTop((offsetDiff-225)+results.scrollTop());
+				} else if (offsetDiff < 35) {
+					results.scrollTop(results.scrollTop()-(35-offsetDiff));
+				}
+			}
+		});
+		input.on("keyup", function(ev) {
+			if (ev.keyCode == 38 || ev.keyCode == 40) {
+				return;
+			}
+
+			if (ev.keyCode == 13) {
+				var key = this.selectedNode.attr("node");
+				var posCursor = new Point(lX(ide.mouseX - 25), lY(ide.mouseY - 10));
+				addNode(posCursor, ShaderNode.registeredNodes[key]);
+				closeAddMenu();
+			} else {
+				if (this.selectedNode != null)
+					this.selectedNode.removeClass("selected");
+				var value = input.val();
+				var children = divs.elements();
+				var isFirst = true;
+				var lastGroup = null;
+				for (elt in children) {
+					if (elt.hasClass("group")) {
+						lastGroup = elt;
+						elt.hide();
+						continue;
+					}
+					if (elt.children().first().html().toLowerCase().indexOf(value.toLowerCase()) != -1) {
+						if (isFirst) {
+							this.selectedNode = elt;
+							isFirst = false;
+						}
+						elt.show();
+						if (lastGroup != null)
+							lastGroup.show();
+					} else {
+						elt.hide();
+					}
+				}
+				if (this.selectedNode != null)
+					this.selectedNode.addClass("selected");
+			}
+		});
+		divs.mouseover(function(ev) {
+			if (ev.getThis().hasClass("group")) {
+				return;
+			}
+			this.selectedNode.removeClass("selected");
+			this.selectedNode = ev.getThis();
+			this.selectedNode.addClass("selected");
+		});
+		divs.mouseup(function(ev) {
+			if (ev.getThis().hasClass("group")) {
+				return;
+			}
+			var key = ev.getThis().attr("node");
+			var posCursor = new Point(lX(ide.mouseX - 25), lY(ide.mouseY - 10));
+			addNode(posCursor, ShaderNode.registeredNodes[key]);
+			closeAddMenu();
+		});
+	}
+
+	function closeAddMenu() {
+		if (addMenu != null)
+			addMenu.hide();
+	}
+
+	override function removeBox(box : Box) {
+		super.removeBox(box);
+		shaderGraph.removeNode(box.getId());
+	}
+
+	override function removeEdge(edge : Graph.Edge) {
+		super.removeEdge(edge);
+		shaderGraph.removeEdge(edge.to.getId(), edge.nodeTo.attr("field"));
+		launchCompileShader();
+	}
+
+	override function updatePosition(id : Int, x : Float, y : Float) {
+		shaderGraph.setPosition(id, x, y);
+	}
+
+	static var _ = FileTree.registerExtension(ShaderEditor,["hlshader"],{ icon : "scribd" });
+
+}

+ 1 - 1
hrt/shgraph/ShaderFunction.hx

@@ -18,7 +18,7 @@ class ShaderFunction extends ShaderNode {
 		var args = [];
 		var varArgs = [];
 
-		for (k in getInputsKey()) {
+		for (k in getInputInfoKeys()) {
 			args.push({ name: k, type: getInput(k).getType() });
 			varArgs.push(getInput(k).getVar());
 		}

+ 82 - 22
hrt/shgraph/ShaderGraph.hx

@@ -1,8 +1,10 @@
 package hrt.shgraph;
 
+import hxsl.SharedShader;
+import hxsl.DynamicShader;
 using hxsl.Ast;
 
-private typedef Node = {
+typedef Node = {
 	x : Float,
 	y : Float,
 	comment : String,
@@ -25,16 +27,18 @@ private typedef Parameter = {
 	name : String,
 	type : Type,
 	defaultValue : Dynamic,
+	?id : Int,
 	?variable : TVar
 };
 
 class ShaderGraph {
 
 	var current_node_id = 0;
+	var current_param_id = 0;
 	var filepath : String;
 	var nodes : Map<Int, Node> = [];
 	var allVariables : Array<TVar> = [];
-	public var parametersAvailable : Array<Parameter> = [];
+	public var parametersAvailable : Map<Int, Parameter> = [];
 
 	public function new(filepath : String) {
 		if (filepath == null) return;
@@ -47,11 +51,24 @@ class ShaderGraph {
 			throw "Invalid shader graph parsing ("+e+")";
 		}
 
-		generate(Reflect.getProperty(json, "nodes"), Reflect.getProperty(json, "edges"));
+		generate(Reflect.getProperty(json, "nodes"), Reflect.getProperty(json, "edges"), Reflect.getProperty(json, "parameters"));
 
 	}
 
-	public function generate(nodes : Array<Node>, edges : Array<Edge>) {
+	public function generate(nodes : Array<Node>, edges : Array<Edge>, parameters : Array<Parameter>) {
+
+		for (p in parameters) {
+			var typeString : Array<Dynamic> = Reflect.field(p, "type");
+			if (typeString[1] == null || typeString[1].length == 0)
+				p.type = std.Type.createEnum(Type, typeString[0]);
+			else {
+				var paramsEnum = typeString[1].split(",");
+				p.type = std.Type.createEnum(Type, typeString[0], [Std.parseInt(paramsEnum[0]), std.Type.createEnum(VecType, paramsEnum[1])]);
+			}
+			p.variable = generateParameter(p.name, p.type);
+			this.parametersAvailable.set(p.id, p);
+			current_param_id = p.id + 1;
+		}
 
 		for (n in nodes) {
 			n.outputs = [];
@@ -91,6 +108,7 @@ class ShaderGraph {
 		var output = this.nodes.get(edge.idOutput);
 		node.instance.setInput(edge.nameInput, new NodeVar(output.instance, edge.nameOutput));
 		output.outputs.push(node);
+		#if editor
 		if (hasCycle()){
 			removeEdge(edge.idInput, edge.nameInput, false);
 			return false;
@@ -101,6 +119,7 @@ class ShaderGraph {
 			removeEdge(edge.idInput, edge.nameInput);
 			throw e;
 		}
+		#end
 		return true;
 	}
 
@@ -178,31 +197,46 @@ class ShaderGraph {
 			};
 	}
 
-	public function addParameter(name : String, type : Type, defaultValue : Dynamic) {
-		parametersAvailable.push({name : name, type : type, defaultValue : defaultValue, variable : generateParameter(name, type)});
-		return parametersAvailable.length-1;
+	public function addParameter(type : Type) {
+		var name = "Param_" + current_param_id;
+		parametersAvailable.set(current_param_id, {id: current_param_id, name : name, type : type, defaultValue : null, variable : generateParameter(name, type)});
+		current_param_id++;
+		return current_param_id-1;
+	}
+
+	public function getParameter(id : Int) {
+		return parametersAvailable.get(id);
 	}
 
-	public function setParameter(id : Int, ?newName : String, ?newDefaultValue : Dynamic) {
-		if (parametersAvailable[id] != null) {
+	public function setParameterTitle(id : Int, newName : String) {
+		var p = parametersAvailable.get(id);
+		if (p != null) {
 			if (newName != null) {
-				parametersAvailable[id].name = newName;
-				parametersAvailable[id].variable = generateParameter(newName, parametersAvailable[id].type);
+				for (p in parametersAvailable) {
+					if (p.name == newName) {
+						return false;
+					}
+				}
+				p.name = newName;
+				p.variable = generateParameter(newName, p.type);
+				return true;
 			}
-			if (newDefaultValue != null)
-				parametersAvailable[id].defaultValue = newDefaultValue;
 		}
+		return false;
 	}
 
-	public function removeParameter(name : String) {
-		for (p in parametersAvailable) {
-			if (p.name == name) {
-				parametersAvailable.remove(p);
-				return;
-			}
+	public function setParameterDefaultValue(id : Int, newDefaultValue : Dynamic) {
+		var p = parametersAvailable.get(id);
+		if (p != null) {
+			if (newDefaultValue != null)
+				p.defaultValue = newDefaultValue;
 		}
 	}
 
+	public function removeParameter(id : Int) {
+		parametersAvailable.remove(id);
+	}
+
 	function buildNodeVar(nodeVar : NodeVar) : Array<TExpr>{
 		var node = nodeVar.node;
 		if (node == null)
@@ -232,13 +266,18 @@ class ShaderGraph {
 		return false;
 	}
 
-	public function buildFragment() : ShaderData {
+	public function compile() : DynamicShader {
 
 		allVariables = [];
+		var allParameters = [];
+		var allParamDefaultValue = [];
 		var content = [];
 
 		for (n in nodes) {
 			n.instance.outputCompiled = [];
+			if (Std.is(n.instance, ShaderInput) || Std.is(n.instance, ShaderParam)) {
+				//updateOutputs(n);
+			}
 		}
 
 		for (n in nodes) {
@@ -256,9 +295,15 @@ class ShaderGraph {
 				var nodeVar = new NodeVar(n.instance, "input");
 				content = content.concat(buildNodeVar(nodeVar));
 			}
+			if (Std.is(n.instance, ShaderParam)) {
+				var shaderParam = Std.instance(n.instance, ShaderParam);
+				allVariables.push(shaderParam.variable);
+				allParameters.push(shaderParam.variable);
+				allParamDefaultValue.push(getParameter(shaderParam.parameterId).defaultValue);
+			}
 		}
 
-		return {
+		var shaderData = {
 			funs : [{
 					ret : TVoid, kind : Fragment,
 					ref : {
@@ -277,6 +322,21 @@ class ShaderGraph {
 			name: "MON_FRAGMENT",
 			vars: allVariables
 		};
+
+		var s = new SharedShader("");
+		s.data = shaderData;
+		@:privateAccess s.initialize();
+		var shaderCompiled = new hxsl.DynamicShader(s);
+
+		for (i in 0...allParameters.length) {
+			switch (allParameters[i].type) {
+				case TSampler2D:
+					shaderCompiled.setParamValue(allParameters[i], hxd.Res.load(allParamDefaultValue[i]).toTexture());
+				default:
+					shaderCompiled.setParamValue(allParameters[i], allParamDefaultValue[i]);
+			}
+		}
+		return shaderCompiled;
 	}
 
 	public function save() {
@@ -294,7 +354,7 @@ class ShaderGraph {
 			],
 			edges: edgesJson,
 			parameters: [
-				for (p in parametersAvailable) { name : p.name, type : p.type }
+				for (p in parametersAvailable) { id : p.id, name : p.name, type : [p.type.getName(), p.type.getParameters().toString()], defaultValue : p.defaultValue }
 			]
 		});
 

+ 1 - 0
hrt/shgraph/ShaderInput.hx

@@ -9,6 +9,7 @@ using hxsl.Ast;
 @description("Shader inputs of Heaps, it's dynamic")
 @group("Input")
 @noheader()
+@color("#1F690A")
 class ShaderInput extends ShaderNode {
 
 	@output() var output = SType.Variant;

+ 1 - 1
hrt/shgraph/ShaderNode.hx

@@ -88,7 +88,7 @@ class ShaderNode {
 	}
 
 	public function build(key : String) : TExpr {
-		throw "Not implemented";
+		throw "Build function not implemented";
 	}
 
 	public function checkTypeAndCompatibilyInput(key : String, type : ShaderType.SType) : Bool {

+ 1 - 0
hrt/shgraph/ShaderOutput.hx

@@ -10,6 +10,7 @@ using hxsl.Ast;
 @description("Parameters outputs, it's dynamic")
 @group("Output")
 @noheader()
+@color("#A90707")
 class ShaderOutput extends ShaderNode {
 
 	@input("input") var input = SType.Variant;

+ 26 - 15
hrt/shgraph/ShaderParam.hx

@@ -5,45 +5,56 @@ import hxsl.*;
 
 using hxsl.Ast;
 
-@name("Param")
-@description("Parameters inputs, it's dynamic")
-@group("Input")
 @noheader()
+@width(100)
+@color("#1F690A")
 class ShaderParam extends ShaderNode {
 
 	@output() var output = SType.Variant;
 
-	@prop() public var parameterName : String;
+	@prop() public var parameterId : Int;
 
-	private var variable : TVar;
+	public var variable : TVar;
+	private var parameterName : String;
+
+	override public function computeOutputs() {
+		if (variable != null)
+			addOutput("output", variable.type);
+		else
+			removeOutput("output");
+	}
 
 	override public function getOutput(key : String) : TVar {
 		return variable;
 	}
 
 	override public function loadProperties(props : Dynamic) {
-		parameterName = Reflect.field(props, "parameterName");
+		parameterId = Reflect.field(props, "parameterId");
 	}
 
 	override public function saveProperties() : Dynamic {
 		var parameters = {
-			parameterName: parameterName
+			parameterId: parameterId
 		};
 
 		return parameters;
 	}
 
+	override public function build(key : String) : TExpr {
+		return null;
+	}
+
 	#if editor
+	private var eltName : Element;
+	public function setName(s : String) {
+		parameterName = s;
+		if (eltName != null)
+			eltName.html(s);
+	}
 	override public function getPropertiesHTML(width : Float) : Array<Element> {
 		var elements = super.getPropertiesHTML(width);
-		var element = new Element('<div style="width: 110px; height: 30px"></div>');
-		element.append(new Element('<select class="variable"></select>'));
-
-		var input = element.children("select");
-		input.on("change", function(e) {
-			this.variable = input.val();
-		});
-
+		var element = new Element('<div style="width: 75px; height: 30px"></div>');
+		eltName = new Element('<span class="variable">${parameterName}</span>').appendTo(element);
 
 		elements.push(element);
 

+ 0 - 1
hrt/shgraph/nodes/Cond.hx

@@ -43,7 +43,6 @@ class Cond extends ShaderNode {
 	}
 
 	override public function build(key : String) : TExpr {
-
 		return {
 				p : null,
 				t : output.type,

+ 1 - 1
hrt/shgraph/nodes/Sampler.hx

@@ -6,7 +6,7 @@ using hxsl.Ast;
 
 @name("Sampler")
 @description("Get color from texture and UV")
-@group("AAAAA")
+@group("Input")
 class Sampler extends ShaderFunction {
 
 	@input("texture") var texture = SType.Sampler;

+ 0 - 30
hrt/shgraph/nodes/Texture.hx

@@ -1,30 +0,0 @@
-package hrt.shgraph.nodes;
-
-import hxsl.*;
-
-using hxsl.Ast;
-
-@name("Texture")
-@description("Create a texture from a file")
-@group("AAAA")
-class Texture extends ShaderNode {
-
-	@output("texture") var texture = SType.Sampler;
-
-	@prop("Variable") public var variable : TVar;
-
-	@prop() var fileTexture : String;
-
-	override public function computeOutputs() {
-		addOutput("texture", TSampler2D);
-	}
-
-	override public function getOutput(key : String) : TVar {
-		return variable;
-	}
-
-	override public function build(key : String) : TExpr {
-		return null;
-	}
-
-}