Browse Source

Fixes to GraphEdit:

-Working area is bigger now, solves #1148
-Using Position now works, fixes #1141
-RGB ops now work, fixes #1139
-Missing bindings to GraphEdit and GraphNode added
-Shader Graph Editor Shows errors on cyclic links and missing connections
Juan Linietsky 10 years ago
parent
commit
78f4b93703

+ 3 - 0
drivers/gles2/shader_compiler_gles2.cpp

@@ -131,6 +131,7 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 			SL::BlockNode *bnode=(SL::BlockNode*)p_node;
 
 			//variables
+			code+="{"ENDL;
 			for(Map<StringName,SL::DataType>::Element *E=bnode->variables.front();E;E=E->next()) {
 
 				code+=_mktab(p_level)+_typestr(E->value())+" "+replace_string(E->key())+";"ENDL;
@@ -141,6 +142,7 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 				code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";"ENDL;
 			}
 
+			code+="}"ENDL;
 
 		} break;
 		case SL::Node::TYPE_VARIABLE: {
@@ -676,6 +678,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	//mode_replace_table[1]["POSITION"]="IN_POSITION";
 	mode_replace_table[1]["NORMAL"]="normal";
 	mode_replace_table[1]["TANGENT"]="tangent";
+	mode_replace_table[1]["POSITION"]="gl_Position";
 	mode_replace_table[1]["BINORMAL"]="binormal";
 	mode_replace_table[1]["NORMALMAP"]="normalmap";
 	mode_replace_table[1]["NORMALMAP_DEPTH"]="normaldepth";

+ 24 - 5
scene/gui/graph_edit.cpp

@@ -1,5 +1,6 @@
 #include "graph_edit.h"
-
+#include "os/input.h"
+#include "os/keyboard.h"
 bool GraphEditFilter::has_point(const Point2& p_point) const {
 
 	return ge->_filter_input(p_point);
@@ -53,7 +54,7 @@ void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const
 	}
 }
 
-void GraphEdit::get_connection_list(List<Connection> *r_connections) {
+void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
 
 	*r_connections=connections;
 }
@@ -88,7 +89,6 @@ void GraphEdit::_update_scroll() {
 
 	updating=true;
 	Rect2 screen;
-	screen.size=get_size();
 	for(int i=0;i<get_child_count();i++) {
 
 		GraphNode *gn=get_child(i)->cast_to<GraphNode>();
@@ -101,6 +101,10 @@ void GraphEdit::_update_scroll() {
 		screen = screen.merge(r);
 	}
 
+	screen.pos-=get_size();
+	screen.size+=get_size()*2.0;
+
+
 	h_scroll->set_min(screen.pos.x);
 	h_scroll->set_max(screen.pos.x+screen.size.x);
 	h_scroll->set_page(get_size().x);
@@ -492,7 +496,7 @@ void GraphEdit::_top_layer_draw() {
 
 void GraphEdit::_input_event(const InputEvent& p_ev) {
 
-	if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) {
+	if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
 		h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x );
 		v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y );
 	}
@@ -515,12 +519,27 @@ bool GraphEdit::is_right_disconnects_enabled() const{
 	return right_disconnects;
 }
 
-
+Array GraphEdit::_get_connection_list() const {
+
+	List<Connection> conns;
+	get_connection_list(&conns);
+	Array arr;
+	for(List<Connection>::Element *E=conns.front();E;E=E->next()) {
+		Dictionary d;
+		d["from"]=E->get().from;
+		d["from_port"]=E->get().from_port;
+		d["to"]=E->get().to;
+		d["to_port"]=E->get().to_port;
+		arr.push_back(d);
+	}
+	return arr;
+}
 void GraphEdit::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("connect_node:Error","from","from_port","to","to_port"),&GraphEdit::connect_node);
 	ObjectTypeDB::bind_method(_MD("is_node_connected","from","from_port","to","to_port"),&GraphEdit::is_node_connected);
 	ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node);
+	ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list);
 
 	ObjectTypeDB::bind_method(_MD("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects);
 	ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled);

+ 4 - 1
scene/gui/graph_edit.h

@@ -69,6 +69,8 @@ private:
 	void _top_layer_draw();
 	void _update_scroll_offset();
 
+	Array _get_connection_list() const;
+
 friend class GraphEditFilter;
 	bool _filter_input(const Point2& p_point);
 protected:
@@ -85,7 +87,8 @@ public:
 	void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
 	void clear_connections();
 
-	void get_connection_list(List<Connection> *r_connections);
+	GraphEditFilter *get_top_layer() const { return top_layer; }
+	void get_connection_list(List<Connection> *r_connections) const;
 
 	void set_right_disconnects(bool p_enable);
 	bool is_right_disconnects_enabled() const;

+ 27 - 4
scene/gui/graph_node.cpp

@@ -1,4 +1,5 @@
 #include "graph_node.h"
+#include "method_bind_ext.inc"
 
 
 bool GraphNode::_set(const StringName& p_name, const Variant& p_value) {
@@ -38,9 +39,8 @@ bool GraphNode::_set(const StringName& p_name, const Variant& p_value) {
 bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
 
 
-	print_line("get "+p_name.operator String());
-	if (!p_name.operator String().begins_with("slot/")) {
-		print_line("no begins");
+
+	if (!p_name.operator String().begins_with("slot/")) {		
 		return false;
 	}
 
@@ -68,7 +68,6 @@ bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
 	else
 		return false;
 
-	print_line("ask for: "+p_name.operator String()+" get: "+String(r_ret));
 	return true;
 }
 void GraphNode::_get_property_list( List<PropertyInfo> *p_list) const{
@@ -540,6 +539,30 @@ void GraphNode::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title);
 	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event);
 
+	ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right"),&GraphNode::set_slot);
+	ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot);
+	ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots);
+	ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left);
+	ObjectTypeDB::bind_method(_MD("get_slot_type_left","idx"),&GraphNode::get_slot_type_left);
+	ObjectTypeDB::bind_method(_MD("get_slot_color_left","idx"),&GraphNode::get_slot_color_left);
+	ObjectTypeDB::bind_method(_MD("is_slot_enabled_right","idx"),&GraphNode::is_slot_enabled_right);
+	ObjectTypeDB::bind_method(_MD("get_slot_type_right","idx"),&GraphNode::get_slot_type_right);
+	ObjectTypeDB::bind_method(_MD("get_slot_color_right","idx"),&GraphNode::get_slot_color_right);
+
+	ObjectTypeDB::bind_method(_MD("set_offset","offset"),&GraphNode::set_offset);
+	ObjectTypeDB::bind_method(_MD("get_offset"),&GraphNode::get_offset);
+
+	ObjectTypeDB::bind_method(_MD("get_connection_output_count"),&GraphNode::get_connection_output_count);
+	ObjectTypeDB::bind_method(_MD("get_connection_input_count"),&GraphNode::get_connection_input_count);
+
+	ObjectTypeDB::bind_method(_MD("get_connection_output_pos","idx"),&GraphNode::get_connection_output_pos);
+	ObjectTypeDB::bind_method(_MD("get_connection_output_type","idx"),&GraphNode::get_connection_output_type);
+	ObjectTypeDB::bind_method(_MD("get_connection_output_color","idx"),&GraphNode::get_connection_output_color);
+	ObjectTypeDB::bind_method(_MD("get_connection_input_pos","idx"),&GraphNode::get_connection_input_pos);
+	ObjectTypeDB::bind_method(_MD("get_connection_input_type","idx"),&GraphNode::get_connection_input_type);
+	ObjectTypeDB::bind_method(_MD("get_connection_input_color","idx"),&GraphNode::get_connection_input_color);
+
+
 	ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button);
 	ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible);
 

+ 167 - 24
scene/resources/shader_graph.cpp

@@ -27,7 +27,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "shader_graph.h"
-
+#include "scene/scene_string_names.h"
 //todo
 //-RGB ops
 //-mostrar error de conexion
@@ -137,6 +137,13 @@ Dictionary ShaderGraph::_get_data() const {
 }
 
 
+
+ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
+
+	ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK);
+	return shader[p_type].error;
+}
+
 void ShaderGraph::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
@@ -180,9 +187,9 @@ void ShaderGraph::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op);
 	ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op);
 
-	ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op","c"),&ShaderGraph::rgb_op_node_set_op);
+	ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op);
 	ObjectTypeDB::bind_method(_MD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op);
-	ObjectTypeDB::bind_method(_MD("rgb_op_node_get_c","shader_type","id"),&ShaderGraph::rgb_op_node_get_c);
+
 
 	ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation);
 	ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation);
@@ -356,6 +363,8 @@ void ShaderGraph::_bind_methods() {
 	BIND_CONSTANT( VEC_FUNC_HSV2RGB );
 	BIND_CONSTANT( VEC_MAX_FUNC );
 
+	ADD_SIGNAL(MethodInfo("updated"));
+
 
 #if 0
 	ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add );
@@ -568,7 +577,7 @@ void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
 	}
 
 	shader[p_type].node_map.erase(p_id);
-	print_line("erased node, amount left: "+itos(shader[p_type].node_map.size()));
+
 	_request_update();
 
 }
@@ -634,7 +643,6 @@ bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slo
 void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
 	ERR_FAIL_INDEX(p_type,3);
 
-	print_line("** dsisconnect");
 	SourceSlot ts;
 	ts.id=p_src_id;
 	ts.slot=p_src_slot;
@@ -871,14 +879,14 @@ ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_typ
 
 }
 
-void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op,float p_c){
+void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){
 
 	ERR_FAIL_INDEX(p_type,3);
 	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 	Node& n = shader[p_type].node_map[p_id];
 	ERR_FAIL_COND(n.type!=NODE_RGB_OP);
 	n.param1=p_op;
-	n.param2=p_c;
+
 	_request_update();
 
 }
@@ -892,15 +900,7 @@ ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id)
 	return RGBOp(op);
 
 }
-float ShaderGraph::rgb_op_node_get_c(ShaderType p_type,float p_id) const{
 
-	ERR_FAIL_INDEX_V(p_type,3,0);
-	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
-	const Node& n = shader[p_type].node_map[p_id];
-	ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,0);
-	return n.param2;
-
-}
 
 void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){
 
@@ -928,7 +928,9 @@ void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,Scala
 	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 	Node& n = shader[p_type].node_map[p_id];
 	ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC);
-	n.param1=p_func;
+	int func = p_func;
+	ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+	n.param1=func;
 	_request_update();
 
 }
@@ -948,7 +950,9 @@ void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc
 	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 	Node& n = shader[p_type].node_map[p_id];
 	ERR_FAIL_COND(n.type!=NODE_VEC_FUNC);
-	n.param1=p_func;
+	int func = p_func;
+	ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+	n.param1=func;
 
 	_request_update();
 
@@ -1216,7 +1220,7 @@ const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
 	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT},
 	//pixel vertex in
 	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
-	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN},
 	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
 	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
 	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
@@ -1286,7 +1290,7 @@ const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
 		{NODE_SCALAR_OP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
 		{NODE_VEC_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
 		{NODE_VEC_SCALAR_OP,{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
-		{NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
+		{NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
 		{NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4
 		{NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option)
 		{NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
@@ -1669,7 +1673,7 @@ void ShaderGraph::_update_shader() {
 
 
 		shader[i].error=GRAPH_OK;
-		print_line("ShADER: "+code[i]);
+
 	}
 
 	bool all_ok=true;
@@ -1682,8 +1686,9 @@ void ShaderGraph::_update_shader() {
 		set_code(code[0],code[1],code[2]);
 	}
 	//do shader here
-	print_line("UPDATING SHADER");
+
 	_pending_update_shader=false;
+	emit_signal(SceneStringNames::get_singleton()->updated);
 }
 
 void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
@@ -1691,6 +1696,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 	const char *typestr[4]={"float","vec3","mat4","texture"};
 #define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot)))
+#define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot))
 
 	switch(p_node->type) {
 
@@ -1778,7 +1784,85 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 		}break;
 		case NODE_RGB_OP: {
 
+			int op = p_node->param1;
+			static const char*axisn[3]={"x","y","z"};
+			switch(op) {
+				case RGB_OP_SCREEN: {
 
+					code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n";
+				} break;
+				case RGB_OP_DIFFERENCE: {
+
+					code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
+
+				} break;
+				case RGB_OP_DARKEN: {
+
+					code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n";
+				} break;
+				case RGB_OP_LIGHTEN: {
+
+					code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n";
+
+				} break;
+				case RGB_OP_OVERLAY: {
+
+					code += OUTNAME(p_node->id,0)+";\n";
+					for(int i=0;i<3;i++) {
+						code += "{\n";
+						code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+						code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+						code += "\tif (base < 0.5) {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n";
+						code += "\t} else {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
+						code += "\t}\n";
+						code += "}\n";
+					}
+
+				} break;
+				case RGB_OP_DODGE: {
+
+					code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n";
+
+				} break;
+				case RGB_OP_BURN: {
+
+					code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n";
+				} break;
+				case RGB_OP_SOFT_LIGHT: {
+
+					code += OUTNAME(p_node->id,0)+";\n";
+					for(int i=0;i<3;i++) {
+						code += "{\n";
+						code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+						code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+						code += "\tif (base < 0.5) {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n";
+						code += "\t} else {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n";
+						code += "\t}\n";
+						code += "}\n";
+					}
+
+				} break;
+				case RGB_OP_HARD_LIGHT: {
+
+					code += OUTNAME(p_node->id,0)+";\n";
+					for(int i=0;i<3;i++) {
+						code += "{\n";
+						code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+						code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+						code += "\tif (base < 0.5) {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n";
+						code += "\t} else {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n";
+						code += "\t}\n";
+						code += "}\n";
+					}
+
+				} break;
+			}
 		}break;
 		case NODE_XFORM_MULT: {
 
@@ -1804,11 +1888,70 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			}
 		}break;
 		case NODE_SCALAR_FUNC: {
-
-
-		}break;
+			static const char*scalar_func_id[SCALAR_MAX_FUNC]={
+				"sin($)",
+				"cos($)",
+				"tan($)",
+				"asin($)",
+				"acos($)",
+				"atan($)",
+				"sinh($)",
+				"cosh($)",
+				"tanh($)",
+				"log($)",
+				"exp($)",
+				"sqrt($)",
+				"abs($)",
+				"sign($)",
+				"floor($)",
+				"round($)",
+				"ceil($)",
+				"frac($)",
+				"min(max($,0),1)",
+				"-($)",
+			};
+
+			int func = p_node->param1;
+			ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+			code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n";
+
+		} break;
 		case NODE_VEC_FUNC: {
+			static const char*vec_func_id[VEC_MAX_FUNC]={
+				"normalize($)",
+				"max(min($,vec3(1,1,1)),vec3(0,0,0))",
+				"-($)",
+				"1.0/($)",
+				"",
+				"",
+			};
+
+
+			int func = p_node->param1;
+			ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+			if (func==VEC_FUNC_RGB2HSV) {
+				code += OUTNAME(p_node->id,0)+";\n";
+				code+="{\n";
+				code+="\tvec3 c = "+p_inputs[0]+";\n";
+				code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
+				code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
+				code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
+				code+="\tfloat d = q.x - min(q.w, q.y);\n";
+				code+="\tfloat e = 1.0e-10;\n";
+				code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
+				code+="}\n";
+			} else if (func==VEC_FUNC_HSV2RGB) {
+				code += OUTNAME(p_node->id,0)+";\n";;
+				code+="{\n";
+				code+="\tvec3 c = "+p_inputs[0]+";\n";
+				code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
+				code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
+				code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
+				code+="}\n";
 
+			} else {
+				code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n";
+			}
 		}break;
 		case NODE_VEC_LEN: {
 

+ 4 - 2
scene/resources/shader_graph.h

@@ -267,9 +267,8 @@ public:
 		RGB_MAX_OP
 	};
 
-	void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op,float p_c);
+	void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op);
 	RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const;
-	float rgb_op_node_get_c(ShaderType p_which,float p_id) const;
 
 	void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation);
 	bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const;
@@ -349,6 +348,8 @@ public:
 	Variant node_get_state(ShaderType p_type, int p_node) const;
 	void node_set_state(ShaderType p_type, int p_id, const Variant& p_state);
 
+	GraphError get_graph_error(ShaderType p_type) const;
+
 	static int get_type_input_count(NodeType p_type);
 	static int get_type_output_count(NodeType p_type);
 	static SlotType get_type_input_type(NodeType p_type,int p_idx);
@@ -388,6 +389,7 @@ VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
 VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
 VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
 VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
+VARIANT_ENUM_CAST( ShaderGraph::GraphError );
 
 
 class MaterialShaderGraph : public ShaderGraph {

+ 1 - 0
scene/scene_string_names.cpp

@@ -67,6 +67,7 @@ SceneStringNames::SceneStringNames() {
 	idle=StaticCString::create("idle");
 	iteration=StaticCString::create("iteration");
 	update=StaticCString::create("update");
+	updated=StaticCString::create("updated");
 
 	_get_gizmo_geometry=StaticCString::create("_get_gizmo_geometry");
 	_can_gizmo_scale=StaticCString::create("_can_gizmo_scale");

+ 1 - 0
scene/scene_string_names.h

@@ -63,6 +63,7 @@ public:
 	StringName idle;
 	StringName iteration;
 	StringName update;
+	StringName updated;
 
 	StringName line_separation;
 

+ 27 - 4
servers/visual/shader_language.cpp

@@ -768,16 +768,20 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
 	//constructors
 	{"bool",TYPE_BOOL,{TYPE_BOOL,TYPE_VOID}},
 	{"float",TYPE_FLOAT,{TYPE_FLOAT,TYPE_VOID}},
+	{"vec2",TYPE_VEC2,{TYPE_FLOAT,TYPE_VOID}},
 	{"vec2",TYPE_VEC2,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+	{"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_VOID}},
 	{"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
 	{"vec3",TYPE_VEC3,{TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
 	{"vec3",TYPE_VEC3,{TYPE_FLOAT,TYPE_VEC2,TYPE_VOID}},
+	{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VOID}},
 	{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
 	{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
 	{"vec4",TYPE_VEC4,{TYPE_VEC2,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
 	{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_FLOAT,TYPE_VEC2,TYPE_VOID}},
 	{"vec4",TYPE_VEC4,{TYPE_FLOAT,TYPE_VEC3,TYPE_VOID}},
 	{"vec4",TYPE_VEC4,{TYPE_VEC3,TYPE_FLOAT,TYPE_VOID}},
+	{"vec4",TYPE_VEC4,{TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
 	{"mat3",TYPE_MAT3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}},
 	{"mat4",TYPE_MAT4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}},
 	//intrinsics - trigonometry
@@ -856,6 +860,9 @@ const ShaderLanguage::IntrinsicFuncDef ShaderLanguage::intrinsic_func_defs[]={
 	{"clamp",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
 	{"clamp",TYPE_VEC3,{TYPE_VEC3,TYPE_VEC3,TYPE_VEC3,TYPE_VOID}},
 	{"clamp",TYPE_VEC4,{TYPE_VEC4,TYPE_VEC4,TYPE_VEC4,TYPE_VOID}},
+	{"clamp",TYPE_VEC2,{TYPE_VEC2,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+	{"clamp",TYPE_VEC3,{TYPE_VEC3,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
+	{"clamp",TYPE_VEC4,{TYPE_VEC4,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
 	{"mix",TYPE_FLOAT,{TYPE_FLOAT,TYPE_FLOAT,TYPE_FLOAT,TYPE_VOID}},
 	{"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_FLOAT,TYPE_VOID}},
 	{"mix",TYPE_VEC2,{TYPE_VEC2,TYPE_VEC2,TYPE_VEC2,TYPE_VOID}},
@@ -1047,7 +1054,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
 const ShaderLanguage::BuiltinsDef ShaderLanguage::fragment_builtins_defs[]={
 
 	{ "VERTEX", TYPE_VEC3},
-	{ "POSITION", TYPE_VEC3},
+	{ "POSITION", TYPE_VEC4},
 	{ "NORMAL", TYPE_VEC3},
 	{ "TANGENT", TYPE_VEC3},
 	{ "BINORMAL", TYPE_VEC3},
@@ -1210,9 +1217,25 @@ ShaderLanguage::Node* ShaderLanguage::validate_function_call(Parser&parser, Oper
 			Variant data;
 			switch(p_func->return_cache) {
 				case TYPE_FLOAT: data = cdata[0]; break;
-				case TYPE_VEC2: data = Vector2(cdata[0],cdata[1]); break;
-				case TYPE_VEC3: data = Vector3(cdata[0],cdata[1],cdata[2]); break;
-				case TYPE_VEC4: data = Plane(cdata[0],cdata[1],cdata[2],cdata[3]); break;
+				case TYPE_VEC2:
+					if (cdata.size()==1)
+						data = Vector2(cdata[0],cdata[0]);
+					else
+						data = Vector2(cdata[0],cdata[1]);
+
+					break;
+				case TYPE_VEC3:
+					if (cdata.size()==1)
+						data = Vector3(cdata[0],cdata[0],cdata[0]);
+					else
+						data = Vector3(cdata[0],cdata[1],cdata[2]);
+					break;
+				case TYPE_VEC4:
+					if (cdata.size()==1)
+						data = Plane(cdata[0],cdata[0],cdata[0],cdata[0]);
+					else
+						data = Plane(cdata[0],cdata[1],cdata[2],cdata[3]);
+					break;
 			}
 
 			cn->datatype=p_func->return_cache;

+ 35 - 8
tools/editor/plugins/shader_graph_editor_plugin.cpp

@@ -200,7 +200,7 @@ void ShaderGraphView::_vec_input_changed(double p_value, int p_id,Array p_arr){
 }
 void ShaderGraphView::_xform_input_changed(int p_id, Node *p_button){
 
-	print_line("XFIC");
+
 	ToolButton *tb = p_button->cast_to<ToolButton>();
 	ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
 	ped_popup->set_size(tb->get_size());
@@ -445,7 +445,7 @@ void ShaderGraphView::_node_removed(int p_id) {
 
 void ShaderGraphView::_node_moved(const Vector2& p_from, const Vector2& p_to,int p_id) {
 
-	print_line("moved from "+p_from+" to "+p_to);
+
 	ERR_FAIL_COND(!node_map.has(p_id));
 	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
 	ur->create_action("Move Shader Graph Node");
@@ -1213,7 +1213,7 @@ void ShaderGraphView::_create_node(int p_id) {
 	graph_edit->add_child(gn);
 	node_map[p_id]=gn;
 	gn->set_offset(graph->node_get_pos(type,p_id));
-	print_line("NODE "+itos(p_id)+" OFS "+gn->get_offset());
+
 
 }
 
@@ -1236,7 +1236,7 @@ void ShaderGraphView::_update_graph() {
 
 	List<int> nl;
 	graph->get_node_list(type,&nl);
-	print_line("graph nodes: "+itos(nl.size()));
+
 	for(List<int>::Element *E=nl.front();E;E=E->next()) {
 
 		_create_node(E->get());
@@ -1255,11 +1255,29 @@ void ShaderGraphView::_update_graph() {
 
 }
 
+void ShaderGraphView::_sg_updated() {
+
+	if (!graph.is_valid())
+		return;
+	switch(graph->get_graph_error(type)) {
+		case ShaderGraph::GRAPH_OK: status->set_text(""); break;
+		case ShaderGraph::GRAPH_ERROR_CYCLIC: status->set_text("Error: Cyclic Connection Link"); break;
+		case ShaderGraph::GRAPH_ERROR_MISSING_CONNECTIONS: status->set_text("Error: Missing Input Connections"); break;
+	}
+}
+
 void ShaderGraphView::set_graph(Ref<ShaderGraph> p_graph){
 
-	print_line("GRAPH EDIT: "+itos(p_graph.is_valid()));
+
+	if (graph.is_valid()) {
+		graph->disconnect("updated",this,"_sg_updated");
+	}
 	graph=p_graph;
+	if (graph.is_valid()) {
+		graph->connect("updated",this,"_sg_updated");
+	}
 	_update_graph();
+	_sg_updated();
 
 }
 
@@ -1343,6 +1361,7 @@ void ShaderGraphView::_bind_methods() {
 	ObjectTypeDB::bind_method("_cube_edited",&ShaderGraphView::_cube_edited);
 	ObjectTypeDB::bind_method("_comment_edited",&ShaderGraphView::_comment_edited);
 
+	ObjectTypeDB::bind_method("_sg_updated",&ShaderGraphView::_sg_updated);
 }
 
 ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
@@ -1352,8 +1371,15 @@ ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
 	block_update=false;
 	ped_popup = memnew( CustomPropertyEditor );
 	graph_edit->add_child(ped_popup);
-
-
+	status = memnew( Label );
+	graph_edit->get_top_layer()->add_child(status);
+	status->set_pos(Vector2(5,5));
+	status->add_color_override("font_color_shadow",Color(0,0,0));
+	status->add_color_override("font_color",Color(1,0.4,0.3));
+	status->add_constant_override("shadow_as_outline",1);
+	status->add_constant_override("shadow_offset_x",2);
+	status->add_constant_override("shadow_offset_y",2);
+	status->set_text("");
 }
 
 
@@ -1444,7 +1470,7 @@ ShaderGraphEditor::ShaderGraphEditor() {
 
 	HBoxContainer *hbc = memnew( HBoxContainer );
 	menu = memnew( MenuButton );
-	menu->set_text("Add..");
+	menu->set_text("Add Node..");
 	hbc->add_child(menu);
 	add_child(hbc);
 
@@ -1466,6 +1492,7 @@ ShaderGraphEditor::ShaderGraphEditor() {
 		graph_edits[i]->get_graph_edit()->connect("connection_request",graph_edits[i],"_connection_request");
 		graph_edits[i]->get_graph_edit()->connect("disconnection_request",graph_edits[i],"_disconnection_request");
 		graph_edits[i]->get_graph_edit()->set_right_disconnects(true);
+
 	}
 
 	tabs->set_current_tab(1);

+ 2 - 1
tools/editor/plugins/shader_graph_editor_plugin.h

@@ -54,6 +54,7 @@ class ShaderGraphView : public Node {
 	CustomPropertyEditor *ped_popup;
 	bool block_update;
 
+	Label *status;
 	GraphEdit *graph_edit;
 	Ref<ShaderGraph> graph;
 	int edited_id;
@@ -95,7 +96,7 @@ class ShaderGraphView : public Node {
 	void _variant_edited();
 	void _comment_edited(int p_id,Node* p_button);
 
-
+	void _sg_updated();
 	Map<int,GraphNode*> node_map;
 protected:
 	void _notification(int p_what);