浏览代码

Merge branch 'master' of github.com:okamstudio/godot

Anton Yabchinskiy 10 年之前
父节点
当前提交
a7875c586a
共有 100 个文件被更改,包括 4009 次插入1639 次删除
  1. 2 2
      SConstruct
  2. 1 0
      bin/tests/test_math.cpp
  3. 2 0
      core/dictionary.cpp
  4. 1 1
      core/io/json.cpp
  5. 1 1
      core/io/stream_peer_tcp.cpp
  6. 1 0
      core/method_bind.h
  7. 12 0
      core/object_type_db.cpp
  8. 2 0
      core/object_type_db.h
  9. 25 0
      core/os/input.cpp
  10. 2 0
      core/os/input.h
  11. 5 0
      core/os/keyboard.cpp
  12. 1 0
      core/os/keyboard.h
  13. 5 0
      core/os/os.cpp
  14. 13 0
      core/os/os.h
  15. 59 15
      core/translation.cpp
  16. 9 5
      core/ustring.cpp
  17. 1 1
      core/ustring.h
  18. 23 13
      core/variant_op.cpp
  19. 3 0
      demos/2d/platformer/player.gd
  20. 99 72
      demos/2d/platformer/player.xml
  21. 2 2
      drivers/builtin_openssl2/openssl/md5.h
  22. 15 4
      drivers/gles2/rasterizer_gles2.cpp
  23. 5 3
      drivers/mpc/audio_stream_mpc.cpp
  24. 7 3
      drivers/theoraplayer/SCsub
  25. 1 0
      drivers/theoraplayer/src/TheoraVideoClip.cpp
  26. 4 2
      drivers/theoraplayer/video_stream_theoraplayer.cpp
  27. 3 5
      drivers/unix/memory_pool_static_malloc.cpp
  28. 1 1
      drivers/webp/dsp/dsp.h
  29. 1 0
      drivers/webp/utils/bit_reader.h
  30. 50 3
      modules/gdscript/gd_compiler.cpp
  31. 50 3
      modules/gdscript/gd_editor.cpp
  32. 4 0
      modules/gdscript/gd_functions.cpp
  33. 10 4
      modules/gdscript/gd_parser.cpp
  34. 1 0
      modules/gdscript/gd_parser.h
  35. 2 2
      modules/gridmap/grid_map_editor_plugin.cpp
  36. 4 0
      modules/gridmap/register_types.cpp
  37. 3 3
      platform/android/detect.py
  38. 1 1
      platform/android/java/src/com/android/godot/Godot.java
  39. 0 4
      platform/iphone/detect.py
  40. 1 0
      platform/iphone/platform_config.h
  41. 18 0
      platform/iphone/platform_refcount.h
  42. 21 0
      platform/windows/detect.py
  43. 37 0
      platform/winrt/include/angle_windowsstore.h
  44. 1 0
      scene/2d/sample_player_2d.cpp
  45. 35 0
      scene/3d/camera.cpp
  46. 8 0
      scene/3d/camera.h
  47. 5 0
      scene/3d/collision_object.cpp
  48. 1 1
      scene/3d/immediate_geometry.cpp
  49. 2 3
      scene/3d/physics_body.cpp
  50. 44 14
      scene/3d/ray_cast.cpp
  51. 7 2
      scene/3d/ray_cast.h
  52. 1 0
      scene/3d/spatial_sample_player.cpp
  53. 1 1
      scene/3d/sprite_3d.cpp
  54. 2 1
      scene/animation/animation_tree_player.cpp
  55. 1 0
      scene/audio/sample_player.cpp
  56. 4 2
      scene/gui/control.cpp
  57. 0 59
      scene/gui/empty_control.cpp
  58. 0 48
      scene/gui/empty_control.h
  59. 517 0
      scene/gui/graph_edit.cpp
  60. 93 0
      scene/gui/graph_edit.h
  61. 256 16
      scene/gui/graph_node.cpp
  62. 43 3
      scene/gui/graph_node.h
  63. 1 0
      scene/gui/menu_button.cpp
  64. 14 1
      scene/gui/popup.cpp
  65. 18 1
      scene/gui/popup_menu.cpp
  66. 4 0
      scene/gui/popup_menu.h
  67. 33 0
      scene/gui/tab_container.cpp
  68. 2 0
      scene/gui/tab_container.h
  69. 400 400
      scene/gui/text_edit.cpp
  70. 1 0
      scene/gui/text_edit.h
  71. 65 16
      scene/gui/texture_button.cpp
  72. 7 0
      scene/gui/texture_button.h
  73. 5 0
      scene/main/node.cpp
  74. 15 5
      scene/register_scene_types.cpp
  75. 7 1
      scene/resources/default_theme/default_theme.cpp
  76. 二进制
      scene/resources/default_theme/graph_node_close.png
  77. 5 0
      scene/resources/default_theme/theme_data.h
  78. 1 1
      scene/resources/material.cpp
  79. 3 10
      scene/resources/shader.cpp
  80. 15 3
      scene/resources/shader.h
  81. 1507 760
      scene/resources/shader_graph.cpp
  82. 306 101
      scene/resources/shader_graph.h
  83. 2 2
      scene/resources/surface_tool.cpp
  84. 1 1
      servers/physics/physics_server_sw.cpp
  85. 0 3
      servers/visual/shader_graph.h
  86. 10 7
      tools/SCsub
  87. 4 2
      tools/doc/doc_data.cpp
  88. 5 5
      tools/editor/animation_editor.cpp
  89. 2 2
      tools/editor/animation_editor.h
  90. 13 1
      tools/editor/code_editor.cpp
  91. 2 2
      tools/editor/editor_help.cpp
  92. 10 2
      tools/editor/editor_import_export.cpp
  93. 2 2
      tools/editor/editor_log.cpp
  94. 2 2
      tools/editor/editor_log.h
  95. 11 9
      tools/editor/editor_node.cpp
  96. 4 0
      tools/editor/editor_node.h
  97. 3 0
      tools/editor/editor_settings.cpp
  98. 二进制
      tools/editor/icons/icon_canvas_item_shader.png
  99. 二进制
      tools/editor/icons/icon_canvas_item_shader_graph.png
  100. 二进制
      tools/editor/icons/icon_material_shader.png

+ 2 - 2
SConstruct

@@ -134,8 +134,8 @@ Help(opts.GenerateHelpText(env_base)) # generate help
 # add default include paths
 
 env_base.Append(CPPPATH=['#core','#core/math','#tools','#drivers','#'])
-	
-# configure ENV for platform	
+
+# configure ENV for platform
 env_base.platform_exporters=platform_exporters
 
 """

+ 1 - 0
bin/tests/test_math.cpp

@@ -80,6 +80,7 @@ MainLoop* test() {
 
 	{
 
+
 	//	print_line("NUM: "+itos(237641278346127));
 		print_line("NUM: "+itos(-128));
 		return NULL;

+ 2 - 0
core/dictionary.cpp

@@ -186,10 +186,12 @@ Error Dictionary::parse_json(const String& p_json) {
 
 	String errstr;
 	int errline=0;
+	if (p_json != ""){
 	Error err = JSON::parse(p_json,*this,errstr,errline);
 	if (err!=OK) {
 		ERR_EXPLAIN("Error parsing JSON: "+errstr+" at line: "+itos(errline));
 		ERR_FAIL_COND_V(err!=OK,err);
+		}
 	}
 
 	return OK;

+ 1 - 1
core/io/json.cpp

@@ -250,7 +250,7 @@ Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_toke
 				if (p_str[idx]=='-' || (p_str[idx]>='0' && p_str[idx]<='9')) {
 					//a number
 					const CharType *rptr;
-					double number = String::to_double(&p_str[idx],-1,&rptr);
+					double number = String::to_double(&p_str[idx],&rptr);
 					idx+=(rptr - &p_str[idx]);
 					r_token.type=TK_NUMBER;
 					r_token.value=number;

+ 1 - 1
core/io/stream_peer_tcp.cpp

@@ -32,7 +32,7 @@ StreamPeerTCP* (*StreamPeerTCP::_create)()=NULL;
 
 void StreamPeerTCP::_bind_methods() {
 
-	ObjectTypeDB::bind_method(_MD("connect","host","ip"),&StreamPeerTCP::connect);
+	ObjectTypeDB::bind_method(_MD("connect","host","port"),&StreamPeerTCP::connect);
 	ObjectTypeDB::bind_method(_MD("is_connected"),&StreamPeerTCP::is_connected);
 	ObjectTypeDB::bind_method(_MD("get_status"),&StreamPeerTCP::get_status);
 	ObjectTypeDB::bind_method(_MD("get_connected_host"),&StreamPeerTCP::get_connected_host);

+ 1 - 0
core/method_bind.h

@@ -178,6 +178,7 @@ public:
 #ifdef DEBUG_METHODS_ENABLED
 
 	_FORCE_INLINE_ void set_return_type(const StringName& p_type) { ret_type=p_type; }
+	_FORCE_INLINE_ StringName get_return_type() const { return ret_type; }
 
 	_FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const {
 

+ 12 - 0
core/object_type_db.cpp

@@ -191,6 +191,7 @@ MethodDefinition _MD(const char* p_name,const char *p_arg1,const char *p_arg2,co
 
 HashMap<StringName,ObjectTypeDB::TypeInfo,StringNameHasher> ObjectTypeDB::types;
 HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::resource_base_extensions;
+HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::compat_types;
 
 ObjectTypeDB::TypeInfo::TypeInfo() {
 
@@ -263,12 +264,22 @@ bool ObjectTypeDB::type_exists(const String &p_type) {
 	return types.has(p_type);	
 }
 
+void ObjectTypeDB::add_compatibility_type(const StringName& p_type,const StringName& p_fallback) {
+
+	compat_types[p_type]=p_fallback;
+}
+
 Object *ObjectTypeDB::instance(const String &p_type) {
 	
 	TypeInfo *ti;
 	{
 		OBJTYPE_LOCK;
 		ti=types.getptr(p_type);
+		if (!ti || ti->disabled || !ti->creation_func) {
+			if (compat_types.has(p_type)) {
+				ti=types.getptr(compat_types[p_type]);
+			}
+		}
 		ERR_FAIL_COND_V(!ti,NULL);
 		ERR_FAIL_COND_V(ti->disabled,NULL);
 		ERR_FAIL_COND_V(!ti->creation_func,NULL);
@@ -914,6 +925,7 @@ void ObjectTypeDB::cleanup() {
 	}	
 	types.clear();
 	resource_base_extensions.clear();
+	compat_types.clear();
 }
 
 //

+ 2 - 0
core/object_type_db.h

@@ -151,6 +151,7 @@ class ObjectTypeDB {
 	static Mutex *lock;
 	static HashMap<StringName,TypeInfo,StringNameHasher> types;
 	static HashMap<StringName,StringName,StringNameHasher> resource_base_extensions;
+	static HashMap<StringName,StringName,StringNameHasher> compat_types;
 
 #ifdef DEBUG_METHODS_ENABLED
 	static MethodBind* bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount);
@@ -482,6 +483,7 @@ public:
 	static void get_resource_base_extensions(List<String> *p_extensions);
 	static void get_extensions_for_type(const StringName& p_type,List<String> *p_extensions);
 
+	static void add_compatibility_type(const StringName& p_type,const StringName& p_fallback);
 	static void init();
 	static void cleanup();
 };

+ 25 - 0
core/os/input.cpp

@@ -29,6 +29,7 @@
 #include "input.h"
 #include "input_map.h"
 #include "os/os.h"
+#include "globals.h"
 Input *Input::singleton=NULL;
 
 Input *Input::get_singleton() {
@@ -69,6 +70,30 @@ void Input::_bind_methods() {
 	ADD_SIGNAL( MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")) );
 }
 
+void Input::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+#ifdef TOOLS_ENABLED
+
+	String pf=p_function;
+	if (p_idx==0 && (pf=="is_action_pressed" || pf=="action_press" || pf=="action_release")) {
+
+		List<PropertyInfo> pinfo;
+		Globals::get_singleton()->get_property_list(&pinfo);
+
+		for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+			const PropertyInfo &pi=E->get();
+
+			if (!pi.name.begins_with("input/"))
+				continue;
+
+			String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+			r_options->push_back("\""+name+"\"");
+
+		}
+	}
+#endif
+
+}
+
 Input::Input() {
 
 	singleton=this;

+ 2 - 0
core/os/input.h

@@ -76,6 +76,8 @@ public:
 	virtual void action_press(const StringName& p_action)=0;
 	virtual void action_release(const StringName& p_action)=0;
 
+	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
+
 
 	Input();
 };

+ 5 - 0
core/os/keyboard.cpp

@@ -353,3 +353,8 @@ int find_keycode(const String& p_code) {
 	return 0;
 
 }
+
+int latin_keyboard_keycode_convert(int p_keycode){
+
+	return p_keycode;
+}

+ 1 - 0
core/os/keyboard.h

@@ -328,5 +328,6 @@ enum KeyModifierMask {
 String keycode_get_string(uint32_t p_code);
 bool keycode_has_unicode(uint32_t p_unicode);
 int find_keycode(const String& p_code);
+int latin_keyboard_keycode_convert(int p_keycode);
 
 #endif

+ 5 - 0
core/os/os.cpp

@@ -485,6 +485,11 @@ void OS::set_time_scale(float p_scale) {
 	_time_scale=p_scale;
 }
 
+OS::LatinKeyboardVariant OS::get_latin_keyboard_variant() const {
+
+	return LATIN_KEYBOARD_QWERTY;
+}
+
 float OS::get_time_scale() const {
 
 	return _time_scale;

+ 13 - 0
core/os/os.h

@@ -34,6 +34,7 @@
 #include "vector.h"
 #include "os/main_loop.h"
 #include <stdarg.h>
+
 /**
 	@author Juan Linietsky <[email protected]>
 */
@@ -348,6 +349,18 @@ public:
 	virtual Error dialog_input_text(String p_title, String p_description, String p_partial, Object* p_obj, String p_callback);
 
 
+	enum LatinKeyboardVariant {
+		LATIN_KEYBOARD_QWERTY,
+		LATIN_KEYBOARD_QWERTZ,
+		LATIN_KEYBOARD_AZERTY,
+		LATIN_KEYBOARD_QZERTY,
+		LATIN_KEYBOARD_DVORAK,
+		LATIN_KEYBOARD_NEO,
+	};
+
+
+	virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
 	void set_time_scale(float p_scale);
 	float get_time_scale() const;
 

+ 59 - 15
core/translation.cpp

@@ -550,7 +550,7 @@ StringName TranslationServer::translate(const StringName& p_message) const {
 			continue; // locale not match
 
 		//near match
-		bool match = (l!=lptr);
+		bool match = (l!=locale);
 
 		if (near_match && !match)
 			continue; //only near-match once
@@ -570,6 +570,42 @@ StringName TranslationServer::translate(const StringName& p_message) const {
 
 	}
 
+	if (!res) {
+		//try again with fallback
+		if (fallback.length()>=2) {
+
+			const CharType *fptr=&fallback[0];
+			bool near_match=false;
+			for (const Set< Ref<Translation> >::Element *E=translations.front();E;E=E->next()) {
+
+				const Ref<Translation>& t = E->get();
+				String l = t->get_locale();
+				if (fptr[0]!=l[0] || fptr[1]!=l[1])
+					continue; // locale not match
+
+				//near match
+				bool match = (l!=fallback);
+
+				if (near_match && !match)
+					continue; //only near-match once
+
+				StringName r=t->get_message(p_message);
+
+				if (!r)
+					continue;
+
+				res=r;
+
+				if (match)
+					break;
+				else
+					near_match=true;
+
+			}
+		}
+	}
+
+
 	if (!res)
 		return p_message;
 
@@ -604,9 +640,27 @@ bool TranslationServer::_load_translations(const String& p_from) {
 
 void TranslationServer::setup() {
 
-
-	set_locale( GLOBAL_DEF("locale/default",OS::get_singleton()->get_locale()) );
-	fallback = GLOBAL_DEF("locale/fallback","");
+	String test = GLOBAL_DEF("locale/test","");
+	test=test.strip_edges();
+	if (test!="")
+		set_locale( test );
+	else
+		set_locale( OS::get_singleton()->get_locale() );
+	fallback = GLOBAL_DEF("locale/fallback","en");
+#ifdef TOOLS_ENABLED
+
+	{
+		String options="";
+		int idx=0;
+		while(locale_list[idx]) {
+			if (idx>0)
+				options+=", ";
+			options+=locale_list[idx];
+			idx++;
+		}
+		Globals::get_singleton()->set_custom_property_info("locale/fallback",PropertyInfo(Variant::STRING,"locale/fallback",PROPERTY_HINT_ENUM,options));
+	}
+#endif
 	//load translations
 
 }
@@ -629,6 +683,7 @@ void TranslationServer::load_translations() {
 
 	String locale = get_locale();
 	bool found = _load_translations("locale/translations"); //all
+
 	if (_load_translations("locale/translations_"+locale.substr(0,2)))
 		found=true;
 	if ( locale.substr(0,2) != locale ) {
@@ -637,17 +692,6 @@ void TranslationServer::load_translations() {
 	}
 
 
-	if (!found && fallback!="") { //none found anywhere, use fallback
-
-		_load_translations("locale/translations_"+fallback.substr(0,2));
-		if ( fallback.substr(0,2) != fallback ) {
-			_load_translations("locale/translations_"+fallback);
-		}
-
-		this->locale=fallback;
-
-	}
-
 }
 
 TranslationServer::TranslationServer() {

+ 9 - 5
core/ustring.cpp

@@ -626,7 +626,7 @@ Vector<float> String::split_floats(const String &p_splitter,bool p_allow_empty)
 		if (end<0)
 			end=len;
 		if (p_allow_empty || (end>from))
-			ret.push_back(String::to_double(&c_str()[from],end-from));
+			ret.push_back(String::to_double(&c_str()[from]));
 
 		if (end==len)
 			break;
@@ -654,8 +654,9 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters,bool p_a
 			spl_len=p_splitters[idx].length();
 		}
 
-		if (p_allow_empty || (end>from))
-			ret.push_back(String::to_double(&c_str()[from],end-from));
+		if (p_allow_empty || (end>from)) {
+			ret.push_back(String::to_double(&c_str()[from]));
+		}
 
 		if (end==len)
 			break;
@@ -1959,8 +1960,10 @@ float String::to_float() const {
 	return to_double();
 }
 
-double String::to_double(const CharType* p_str, int p_len, const CharType **r_end)  {
+double String::to_double(const CharType* p_str, const CharType **r_end)  {
 
+	return built_in_strtod<CharType>(p_str,(CharType**)r_end);
+#if 0
 #if 0
 	//ndef NO_USE_STDLIB
 	return wcstod(p_str,p_len<0?NULL:p_str+p_len);
@@ -2053,6 +2056,7 @@ double String::to_double(const CharType* p_str, int p_len, const CharType **r_en
 
 	return sign*(integer+decimal)*Math::pow(10,exp_sign*exp);
 #endif
+#endif
 }
 
 int64_t String::to_int(const CharType* p_str,int p_len)  {
@@ -3437,7 +3441,7 @@ String String::percent_encode() const {
 		uint8_t c = cs[i];
 		if ( (c>='A' && c<='Z') || (c>='a' && c<='z') || (c>='0' && c<='9') || c=='-' || c=='_' || c=='~' || c=='.') {
 
-			char p[2]={c,0};
+			char p[2]={(char)c,0};
 			encoded+=p;
 		} else {
 			char p[4]={'%',0,0,0};

+ 1 - 1
core/ustring.h

@@ -142,7 +142,7 @@ public:
 	int64_t to_int64() const;
 	static int to_int(const char* p_str);
 	static double to_double(const char* p_str);
-	static double to_double(const CharType* p_str, int p_len=-1, const CharType **r_end=NULL);
+	static double to_double(const CharType* p_str, const CharType **r_end=NULL);
 	static int64_t to_int(const CharType* p_str,int p_len=-1);
 	String capitalize() const;
 

+ 23 - 13
core/variant_op.cpp

@@ -922,21 +922,31 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
 		case REAL: {  return;  } break;
 		case STRING: {
 
-			if (p_value.type!=Variant::STRING)
+
+			if (p_index.type!=Variant::INT && p_index.type!=Variant::REAL)
 				return;
-			if (p_index.get_type()==Variant::INT || p_index.get_type()==Variant::REAL) {
-				//string index
 
-				int idx=p_index;
-				String *str=reinterpret_cast<String*>(_data._mem);
-				if (idx >=0 && idx<str->length()) {
-					String chr = p_value;
-					*str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length());
-					valid=true;
-					return;
-				}
+			int idx=p_index;
+			String *str=reinterpret_cast<String*>(_data._mem);
+			if (idx <0 || idx>=str->length())
+				return;
+
+			String chr;
+			if (p_value.type==Variant::INT || p_value.type==Variant::REAL) {
+
+				chr = String::chr(p_value);
+			} else if (p_value.type==Variant::STRING) {
+
+				chr = p_value;
+			} else {
+				return;
 			}
 
+			*str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length());
+			valid=true;
+			return;
+
+
 		} break;
 		case VECTOR2: {
 
@@ -951,7 +961,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
 
 					Vector2 *v=reinterpret_cast<Vector2*>(_data._mem);
 					valid=true;
-					v[idx]=p_value;
+					(*v)[idx]=p_value;
 					return;
 				}
 			} else if (p_index.get_type()==Variant::STRING) {
@@ -1045,7 +1055,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
 
 					Vector3 *v=reinterpret_cast<Vector3*>(_data._mem);
 					valid=true;
-					v[idx]=p_value;
+					(*v)[idx]=p_value;
 					return;
 				}
 			} else if (p_index.get_type()==Variant::STRING) {

+ 3 - 0
demos/2d/platformer/player.gd

@@ -53,12 +53,15 @@ var enemy
 
 func _integrate_forces(s):
 
+	
+
 	var lv = s.get_linear_velocity()
 	var step = s.get_step()
 	
 	var new_anim=anim
 	var new_siding_left=siding_left
 	
+	
 	# Get the controls
 	var move_left = Input.is_action_pressed("move_left")
 	var move_right = Input.is_action_pressed("move_right")

文件差异内容过多而无法显示
+ 99 - 72
demos/2d/platformer/player.xml


+ 2 - 2
drivers/builtin_openssl2/openssl/md5.h

@@ -105,9 +105,9 @@ typedef struct MD5state_st
 	unsigned int num;
 	} MD5_CTX;
 
-#ifdef OPENSSL_FIPS
+//#ifdef OPENSSL_FIPS
 int private_MD5_Init(MD5_CTX *c);
-#endif
+//#endif
 
 //#define MD5_Init _SSL_MD5_Init
 #define MD5_Final _SSL_MD5_Final

+ 15 - 4
drivers/gles2/rasterizer_gles2.cpp

@@ -139,11 +139,13 @@ static _FORCE_INLINE_ uint16_t make_half_float(float f) {
     else if (exp <= 0x38000000)
     {
 
-	// store a denorm half-float value or zero
+	/*// store a denorm half-float value or zero
 	exp = (0x38000000 - exp) >> 23;
 	mantissa >>= (14 + exp);
 
 	hf = (((uint16_t)sign) << 15) | (uint16_t)(mantissa);
+	*/
+	hf=0; //denormals do not work for 3D, convert to zero
     }
     else
     {
@@ -969,7 +971,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
 
 
 
-	if (img.detect_alpha()==Image::ALPHA_BLEND) {
+	if ((!texture->flags&VS::TEXTURE_FLAG_VIDEO_SURFACE) && img.detect_alpha()==Image::ALPHA_BLEND) {
 		texture->has_alpha=true;
 	}
 
@@ -4224,7 +4226,6 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
 	}
 
 	w=DVector<uint8_t>::Write();
-
 	r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels);
 	//r_capture->flip_y();
 
@@ -8188,8 +8189,18 @@ void RasterizerGLES2::canvas_draw_polygon(int p_vertex_count, const int* p_indic
 	}
 
 	if (p_indices) {
-
+#ifdef GLEW_ENABLED
 		glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_INT, p_indices );
+#else
+		static const int _max_draw_poly_indices = 16*1024; // change this size if needed!!!
+		ERR_FAIL_COND(p_vertex_count > _max_draw_poly_indices);
+		static uint16_t _draw_poly_indices[_max_draw_poly_indices];
+		for (int i=0; i<p_vertex_count; i++) {
+			_draw_poly_indices[i] = p_indices[i];
+		};
+		glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_SHORT, _draw_poly_indices );
+#endif
+		//glDrawElements(GL_TRIANGLES, p_vertex_count, GL_UNSIGNED_INT, p_indices );
 	} else {
 		glDrawArrays(GL_TRIANGLES,0,p_vertex_count);
 	}

+ 5 - 3
drivers/mpc/audio_stream_mpc.cpp

@@ -8,6 +8,7 @@ Error AudioStreamMPC::_open_file() {
 		f=NULL;
 	}
 	Error err;
+	//printf("mpc open file %ls\n", file.c_str());
 	f=FileAccess::open(file,FileAccess::READ,&err);
 
 	if (err) {
@@ -16,9 +17,10 @@ Error AudioStreamMPC::_open_file() {
 		return err;
 	}
 
-	f->seek_end(0);
-	streamlen=f->get_pos();
-	f->seek(0);
+	//printf("file size is %i\n", f->get_len());
+	//f->seek_end(0);
+	streamlen=f->get_len();
+	//f->seek(0);
 	if (streamlen<=0) {
 		memdelete(f);
 		f=NULL;

+ 7 - 3
drivers/theoraplayer/SCsub

@@ -61,13 +61,17 @@ src/YUV/C/yuv420_rgb_c.c
 src/TheoraVideoFrame.cpp
 """)
 
+env_theora = env.Clone()
+
 if env["platform"] == "iphone":
 	sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm")
 	env.Append(LINKFLAGS=['-framework', 'CoreVideo', '-framework', 'CoreMedia', '-framework', 'AVFoundation'])
+	if env["target"] == "release":
+		env_theora.Append(CPPFLAGS=["-D_IOS", "-D__ARM_NEON__", "-fstrict-aliasing", "-fmessage-length=210", "-fdiagnostics-show-note-include-stack", "-fmacro-backtrace-limit=0", "-fcolor-diagnostics", "-Wno-trigraphs", "-fpascal-strings", "-fvisibility=hidden", "-fvisibility-inlines-hidden"])
 
-env_theora = env.Clone()
-
-env_theora.Append(CPPFLAGS=["-D_YUV_C", "-D_LIB", "-D__THEORA"])
+env_theora.Append(CPPFLAGS=["-D_LIB", "-D__THEORA"]) # removed -D_YUV_C
+env_theora.Append(CPPFLAGS=["-D_YUV_LIBYUV", "-DLIBYUV_NEON"])
+#env_theora.Append(CPPFLAGS=["-D_YUV_C"])
 
 if env["platform"] == "iphone":
 	env_theora.Append(CPPFLAGS=["-D__AVFOUNDATION"])

+ 1 - 0
drivers/theoraplayer/src/TheoraVideoClip.cpp

@@ -249,6 +249,7 @@ int TheoraVideoClip::discardOutdatedFrames(float absTime)
     
 	if (nPop > 0)
     {
+#define _DEBUG
 #ifdef _DEBUG
         std::string log = getName() + ": dropped frame ";
     

+ 4 - 2
drivers/theoraplayer/video_stream_theoraplayer.cpp

@@ -215,7 +215,7 @@ public:
 		channels = p_channels;
 		freq = p_freq;
 		total_wrote = 0;
-		rb_power = 12;
+		rb_power = 22;
 		rb.resize(rb_power);
 	};
 
@@ -258,10 +258,12 @@ public:
 
 	void update(float time_increase)
 	{
+		float prev_time = mTime;
 		//mTime = (float)(stream->get_total_wrote()) / freq;
 		//mTime = MAX(0,mTime-AudioServer::get_singleton()->get_output_delay());
 		//mTime = (float)sample_count / channels / freq;
 		mTime += time_increase;
+		if (mTime - prev_time > .02) printf("time increase %f secs\n", mTime - prev_time);
 		//float duration=mClip->getDuration();
 		//if (mTime > duration) mTime=duration;
 		//printf("time at timer is %f, %f, samples %i\n", mTime, time_increase, sample_count);
@@ -386,7 +388,7 @@ void VideoStreamTheoraplayer::pop_frame(Ref<ImageTexture> p_tex) {
 	{
 		DVector<uint8_t>::Write wr = data.write();
 		uint8_t* ptr = wr.ptr();
-		copymem(ptr, f->getBuffer(), imgsize);
+		memcpy(ptr, f->getBuffer(), imgsize);
 	}
     /*
     for (int i=0; i<h; i++) {

+ 3 - 5
drivers/unix/memory_pool_static_malloc.cpp

@@ -40,10 +40,9 @@
  * so BE CAREFUL!
  */
 
-
 void* MemoryPoolStaticMalloc::alloc(size_t p_bytes,const char *p_description) {
 
-	#if DFAULT_ALIGNMENT == 1
+	#if DEFAULT_ALIGNMENT == 1
 
 		return _alloc(p_bytes, p_description);
 
@@ -123,7 +122,7 @@ void* MemoryPoolStaticMalloc::_alloc(size_t p_bytes,const char *p_description) {
 
 void* MemoryPoolStaticMalloc::realloc(void *p_memory,size_t p_bytes) {
 
-	#if DFAULT_ALIGNMENT == 1
+	#if DEFAULT_ALIGNMENT == 1
 
 		return _realloc(p_memory,p_bytes);
 	#else
@@ -172,7 +171,6 @@ void* MemoryPoolStaticMalloc::_realloc(void *p_memory,size_t p_bytes) {
 	bool single_element = (ringptr->next == ringptr) && (ringptr->prev == ringptr);
 	bool is_list = ( ringlist == ringptr );
 	
-	
 	RingPtr *new_ringptr=(RingPtr*)::realloc(ringptr, p_bytes+sizeof(RingPtr));
 	
 	ERR_FAIL_COND_V( new_ringptr == 0, NULL ); /// reallocation failed 
@@ -213,7 +211,7 @@ void MemoryPoolStaticMalloc::free(void *p_ptr) {
 
 	ERR_FAIL_COND( !MemoryPoolStatic::get_singleton());
 
-	#if DFAULT_ALIGNMENT == 1
+	#if DEFAULT_ALIGNMENT == 1
 
 		_free(p_ptr);
 	#else

+ 1 - 1
drivers/webp/dsp/dsp.h

@@ -33,7 +33,7 @@ extern "C" {
 #define WEBP_ANDROID_NEON  // Android targets that might support NEON
 #endif
 
-#if (defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED)
+#if ( (defined(__ARM_NEON__) && !defined(__aarch64__)) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED)
 #define WEBP_USE_NEON
 #endif
 

+ 1 - 0
drivers/webp/utils/bit_reader.h

@@ -1,3 +1,4 @@
+//
 // Copyright 2010 Google Inc. All Rights Reserved.
 //
 // This code is licensed under the same terms as WebM:

+ 50 - 3
modules/gdscript/gd_compiler.cpp

@@ -45,8 +45,13 @@ void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node)
 		return;
 
 	error=p_error;
-	err_line=p_node->line;
-	err_column=p_node->column;
+	if (p_node) {
+		err_line=p_node->line;
+		err_column=p_node->column;
+	} else {
+		err_line=0;
+		err_column=0;
+	}
 }
 
 bool GDCompiler::_create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) {
@@ -1522,7 +1527,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
 		GDScript::MemberInfo minfo;
 		minfo.index = p_script->member_indices.size();
 		minfo.setter = p_class->variables[i].setter;
-		minfo.getter = p_class->variables[i].getter;
+		minfo.getter = p_class->variables[i].getter;		
 		p_script->member_indices[name]=minfo;
 		p_script->members.insert(name);
 
@@ -1586,6 +1591,48 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
 			return err;
 	}
 
+#ifdef DEBUG_ENABLED
+	//validate setters/getters if debug is enabled
+	for(int i=0;i<p_class->variables.size();i++) {
+
+		if (p_class->variables[i].setter) {
+			const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().find(p_class->variables[i].setter);
+			if (!E) {
+				_set_error("Setter function '"+String(p_class->variables[i].setter)+"' not found in class.",NULL);
+				err_line=p_class->variables[i].line;
+				err_column=0;
+				return ERR_PARSE_ERROR;
+			}
+
+			if (E->get().is_static()) {
+
+				_set_error("Setter function '"+String(p_class->variables[i].setter)+"' is static.",NULL);
+				err_line=p_class->variables[i].line;
+				err_column=0;
+				return ERR_PARSE_ERROR;
+			}
+
+		}
+		if (p_class->variables[i].getter) {
+			const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().find(p_class->variables[i].getter);
+			if (!E) {
+				_set_error("Getter function '"+String(p_class->variables[i].getter)+"' not found in class.",NULL);
+				err_line=p_class->variables[i].line;
+				err_column=0;
+				return ERR_PARSE_ERROR;
+			}
+
+			if (E->get().is_static()) {
+
+				_set_error("Getter function '"+String(p_class->variables[i].getter)+"' is static.",NULL);
+				err_line=p_class->variables[i].line;
+				err_column=0;
+				return ERR_PARSE_ERROR;
+			}
+
+		}
+	}
+#endif
 	return OK;
 }
 

+ 50 - 3
modules/gdscript/gd_editor.cpp

@@ -28,7 +28,7 @@
 /*************************************************************************/
 #include "gd_script.h"
 #include "gd_compiler.h"
-
+#include "globals.h"
 
 void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
 
@@ -1276,7 +1276,23 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid
 static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set<String>& result, String& arghint) {
 
 
-	if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
+	if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) {
+
+		List<PropertyInfo> pinfo;
+		Globals::get_singleton()->get_property_list(&pinfo);
+
+		for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+			const PropertyInfo &pi=E->get();
+
+			if (!pi.name.begins_with("input/"))
+				continue;
+
+			String name = pi.name.substr(pi.name.find("/")+1,pi.name.length());
+			result.insert("\""+name+"\"");
+		}
+
+
+	} else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
 
 
 		MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
@@ -1299,7 +1315,7 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
 				const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
 				if (op->arguments.size()>)
 
-			}*/
+			}*/		
 		} else {
 
 			Object *obj=id.value;
@@ -1826,6 +1842,37 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
 
 			_find_call_arguments(context,p.get_completion_node(),p.get_completion_line(),p.get_completion_argument_index(),options,r_call_hint);
 		} break;
+		case GDParser::COMPLETION_VIRTUAL_FUNC: {
+
+			GDCompletionIdentifier cid = _get_native_class(context);
+
+			if (cid.obj_type!=StringName()) {
+				List<MethodInfo> vm;
+				ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm);
+				for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) {
+
+					MethodInfo &mi=E->get();
+					String m = mi.name;
+					if (m.find(":")!=-1)
+						m=m.substr(0,m.find(":"));
+					m+="(";
+
+					if (mi.arguments.size()) {
+						for(int i=0;i<mi.arguments.size();i++) {
+							if (i>0)
+								m+=", ";
+							String n =mi.arguments[i].name;
+							if (n.find(":")!=-1)
+								n=n.substr(0,n.find(":"));
+							m+=n;
+						}
+					}
+					m+="):";
+
+					options.insert(m);
+				}
+			}
+		} break;
 
 
 	}

+ 4 - 0
modules/gdscript/gd_functions.cpp

@@ -1166,6 +1166,8 @@ MethodInfo GDFunctions::get_info(Function p_func) {
 
 			MethodInfo mi("weakref",PropertyInfo(Variant::OBJECT,"obj"));
 			mi.return_val.type=Variant::OBJECT;
+			mi.return_val.name="WeakRef";
+
 			return mi;
 
 		} break;
@@ -1173,6 +1175,7 @@ MethodInfo GDFunctions::get_info(Function p_func) {
 
 			MethodInfo mi("funcref",PropertyInfo(Variant::OBJECT,"instance"),PropertyInfo(Variant::STRING,"funcname"));
 			mi.return_val.type=Variant::OBJECT;
+			mi.return_val.name="FuncRef";
 			return mi;
 
 		} break;
@@ -1231,6 +1234,7 @@ MethodInfo GDFunctions::get_info(Function p_func) {
 
 			MethodInfo mi("load",PropertyInfo(Variant::STRING,"path"));
 			mi.return_val.type=Variant::OBJECT;
+			mi.return_val.name="Resource";
 			return mi;
 		} break;
 		case INST2DICT: {

+ 10 - 4
modules/gdscript/gd_parser.cpp

@@ -2027,14 +2027,20 @@ void GDParser::_parse_class(ClassNode *p_class) {
 				}
 
 
-				if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) {
+				tokenizer->advance();
+				StringName name;
+
+				if (_get_completable_identifier(COMPLETION_VIRTUAL_FUNC,name)) {
+
+				}
+
+
+				if (name==StringName()) {
 
 					_set_error("Expected identifier after 'func' (syntax: 'func <identifier>([arguments]):' ).");
 					return;
 				}
 
-				StringName name = tokenizer->get_token_identifier(1);
-
 				for(int i=0;i<p_class->functions.size();i++) {
 					if (p_class->functions[i]->name==name) {
 						_set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->functions[i]->line)+").");
@@ -2045,7 +2051,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
 						_set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+").");
 					}
 				}
-				tokenizer->advance(2);
+
 
 				if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) {
 

+ 1 - 0
modules/gdscript/gd_parser.h

@@ -363,6 +363,7 @@ public:
 		COMPLETION_METHOD,
 		COMPLETION_CALL_ARGUMENTS,
 		COMPLETION_INDEX,
+		COMPLETION_VIRTUAL_FUNC
 	};
 
 

+ 2 - 2
modules/gridmap/grid_map_editor_plugin.cpp

@@ -1192,8 +1192,8 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
 	undo_redo=p_editor->get_undo_redo();
 
 	int mw = EDITOR_DEF("grid_map/palette_min_width",230);
-	EmptyControl *ec = memnew( EmptyControl);
-	ec->set_minsize(Size2(mw,0));
+	Control *ec = memnew( Control);
+	ec->set_custom_minimum_size(Size2(mw,0));
 	add_child(ec);
 
 

+ 4 - 0
modules/gridmap/register_types.cpp

@@ -27,16 +27,20 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "register_types.h"
+#ifndef _3D_DISABLED
 #include "object_type_db.h"
 #include "grid_map.h"
 #include "grid_map_editor_plugin.h"
+#endif
 
 void register_gridmap_types() {
 
+#ifndef _3D_DISABLED
 	ObjectTypeDB::register_type<GridMap>();
 #ifdef TOOLS_ENABLED
 	EditorPlugins::add_by_type<GridMapEditorPlugin>();
 #endif
+#endif
 }
 
 

+ 3 - 3
platform/android/detect.py

@@ -124,11 +124,11 @@ def configure(env):
 #	env['CCFLAGS'] = string.split('-DNO_THREADS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv5te -mtune=xscale -msoft-float  -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
 
 	if env['x86']=='yes':
-		env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__GLIBC__  -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+		env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__GLIBC__  -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
 	elif env["armv6"]!="no":
-		env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_6__ -D__GLIBC__  -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+		env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_6__ -D__GLIBC__  -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
 	else:
-		env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_7__ -D__GLIBC__  -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
+		env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__GLIBC__  -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED -DGLES1_ENABLED')
 
 	env.Append(LDPATH=[ld_path])
 	env.Append(LIBS=['OpenSLES'])

+ 1 - 1
platform/android/java/src/com/android/godot/Godot.java

@@ -358,7 +358,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 		GodotLib.initialize(this,io.needsReloadHooks(),command_line);
 		mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
 		mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
-		mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+		mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
 
 		result_callback = null;
 

文件差异内容过多而无法显示
+ 0 - 4
platform/iphone/detect.py


+ 1 - 0
platform/iphone/platform_config.h

@@ -30,3 +30,4 @@
 #define GLES2_INCLUDE_H <ES2/gl.h>
 #define GLES1_INCLUDE_H <ES1/gl.h>
 
+#define PLATFORM_REFCOUNT

+ 18 - 0
platform/iphone/platform_refcount.h

@@ -0,0 +1,18 @@
+#include "safe_refcount.h"
+
+#ifdef IPHONE_ENABLED
+
+#define REFCOUNT_T int
+#define REFCOUNT_GET_T int const volatile&
+
+#include <libkern/OSAtomic.h>
+
+inline int atomic_conditional_increment(volatile int* v) {
+	return (*v==0)? 0 : OSAtomicIncrement32(v);
+}
+
+inline int atomic_decrement(volatile int* v) {
+	return OSAtomicDecrement32(v);
+}
+
+#endif

+ 21 - 0
platform/windows/detect.py

@@ -135,6 +135,27 @@ def configure(env):
 		env.Append(LIBPATH=[DIRECTX_PATH+"/Lib/x86"])
 		env['ENV'] = os.environ;
 	else:
+
+		# Workaround for MinGW. See:
+		# http://www.scons.org/wiki/LongCmdLinesOnWin32
+		if (os.name=="nt"):
+			import subprocess
+			def mySpawn(sh, escape, cmd, args, env):
+				newargs = ' '.join(args[1:])
+				cmdline = cmd + " " + newargs
+				startupinfo = subprocess.STARTUPINFO()
+				startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+				proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+				    stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
+				data, err = proc.communicate()
+				rv = proc.wait()
+				if rv:
+					print "====="
+					print err
+					print "====="
+				return rv
+			env['SPAWN'] = mySpawn
+
 		#build using mingw
 		if (os.name=="nt"):
 			env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes

+ 37 - 0
platform/winrt/include/angle_windowsstore.h

@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// angle_windowsstore.h:
+
+#ifndef ANGLE_WINDOWSSTORE_H_
+#define ANGLE_WINDOWSSTORE_H_
+
+// The following properties can be set on the CoreApplication to support additional
+// ANGLE configuration options.
+//
+// The Visual Studio sample templates provided with this version of ANGLE have examples
+// of how to set these property values.
+
+//
+// Property: EGLNativeWindowTypeProperty
+// Type: IInspectable
+// Description: Set this property to specify the window type to use for creating a surface.
+//              If this property is missing, surface creation will fail.
+//
+const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
+
+//
+// Property: EGLRenderSurfaceSizeProperty
+// Type: Size
+// Description: Set this property to specify a preferred size in pixels of the render surface.
+//              The render surface size width and height must be greater than 0.
+//              If this property is set, then the render surface size is fixed.
+//              If this property is missing, a default behavior will be provided.
+//              The default behavior uses the window size if a CoreWindow is specified or
+//              the size of the SwapChainPanel control if one is specified.
+//
+const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty";
+
+#endif // ANGLE_WINDOWSSTORE_H_

+ 1 - 0
scene/2d/sample_player_2d.cpp

@@ -102,6 +102,7 @@ void SamplePlayer2D::_notification(int p_what) {
 void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary>& p_library) {
 
 	library=p_library;
+	_change_notify();
 }
 
 Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const {

+ 35 - 0
scene/3d/camera.cpp

@@ -86,6 +86,10 @@ bool Camera::_set(const StringName& p_name, const Variant& p_value) {
 		set_keep_aspect_mode(KeepAspect(int(p_value)));
 	else if (p_name=="vaspect")
 		set_keep_aspect_mode(p_value?KEEP_WIDTH:KEEP_HEIGHT);
+	else if (p_name=="h_offset")
+		h_offset=p_value;
+	else if (p_name=="v_offset")
+		v_offset=p_value;
 	else if (p_name=="current") {
 		if (p_value.operator bool()) {
 			make_current();
@@ -128,6 +132,10 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const {
 		}
 	} else if (p_name=="visible_layers") {
 		r_ret=get_visible_layers();
+	} else if (p_name=="h_offset") {
+		r_ret=get_h_offset();
+	} else if (p_name=="v_offset") {
+		r_ret=get_v_offset();
 	} else if (p_name=="environment") {
 		r_ret=get_environment();
 	} else
@@ -170,12 +178,16 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const {
 	p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) );
 	p_list->push_back( PropertyInfo( Variant::INT, "visible_layers",PROPERTY_HINT_ALL_FLAGS ) );
 	p_list->push_back( PropertyInfo( Variant::OBJECT, "environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment" ) );
+	p_list->push_back( PropertyInfo( Variant::REAL, "h_offset" ) );
+	p_list->push_back( PropertyInfo( Variant::REAL, "v_offset" ) );
 
 }
 
 void Camera::_update_camera() {
 
 	Transform tr = get_camera_transform();
+	tr.origin+=tr.basis.get_axis(1)*v_offset;
+	tr.origin+=tr.basis.get_axis(0)*h_offset;
 	VisualServer::get_singleton()->camera_set_transform( camera, tr );
 
 // here goes listener stuff
@@ -757,6 +769,27 @@ void Camera::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, cons
 
 }
 
+void Camera::set_v_offset(float p_offset) {
+
+	v_offset=p_offset;
+	_update_camera();;
+}
+
+float Camera::get_v_offset() const {
+
+	return v_offset;
+}
+
+void Camera::set_h_offset(float p_offset) {
+	h_offset=p_offset;
+	_update_camera();
+}
+
+float Camera::get_h_offset() const {
+
+	return h_offset;
+}
+
 
 Camera::Camera() {
 
@@ -772,6 +805,8 @@ Camera::Camera() {
 	set_perspective(60.0,0.1,100.0);
 	keep_aspect=KEEP_HEIGHT;
 	layers=0xfffff;
+	v_offset=0;
+	h_offset=0;
 	VisualServer::get_singleton()->camera_set_visible_layers(camera,layers);
 	//active=false;
 }

+ 8 - 0
scene/3d/camera.h

@@ -61,6 +61,8 @@ private:
 	float fov;
 	float size;
 	float near,far;
+	float v_offset;
+	float h_offset;
 	KeepAspect keep_aspect;
 	
 	RID camera;
@@ -140,6 +142,12 @@ public:
 	void look_at(const Vector3& p_target, const Vector3& p_up_normal);
 	void look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal);
 
+	void set_v_offset(float p_offset);
+	float get_v_offset() const;
+
+	void set_h_offset(float p_offset);
+	float get_h_offset() const;
+
 
 	Camera();	
 	~Camera();

+ 5 - 0
scene/3d/collision_object.cpp

@@ -47,6 +47,11 @@ void CollisionObject::_notification(int p_what) {
 
 		case NOTIFICATION_ENTER_WORLD: {
 
+			if (area)
+				PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform());
+			else
+				PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
+
 			RID space = get_world()->get_space();
 			if (area) {
 				PhysicsServer::get_singleton()->area_set_space(rid,space);

+ 1 - 1
scene/3d/immediate_geometry.cpp

@@ -127,7 +127,7 @@ void ImmediateGeometry::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_color","color"),&ImmediateGeometry::set_color);
 	ObjectTypeDB::bind_method(_MD("set_uv","uv"),&ImmediateGeometry::set_uv);
 	ObjectTypeDB::bind_method(_MD("set_uv2","uv"),&ImmediateGeometry::set_uv2);
-	ObjectTypeDB::bind_method(_MD("add_vertex","color"),&ImmediateGeometry::add_vertex);
+	ObjectTypeDB::bind_method(_MD("add_vertex","pos"),&ImmediateGeometry::add_vertex);
 	ObjectTypeDB::bind_method(_MD("add_sphere","lats","lons","radius"),&ImmediateGeometry::add_sphere);
 	ObjectTypeDB::bind_method(_MD("end"),&ImmediateGeometry::end);
 	ObjectTypeDB::bind_method(_MD("clear"),&ImmediateGeometry::clear);

+ 2 - 3
scene/3d/physics_body.cpp

@@ -852,6 +852,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) {
 		//motion recover
 		for(int i=0;i<get_shape_count();i++) {
 
+			if (is_shape_set_as_trigger(i))
+				continue;
 
 			if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),m,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) {
 				collided=true;
@@ -870,9 +872,6 @@ Vector3 KinematicBody::move(const Vector3& p_motion) {
 		for(int j=0;j<8;j++) {
 			for(int i=0;i<res_shapes;i++) {
 
-				if (is_shape_set_as_trigger(i))
-					continue;
-
 				Vector3 a = sr[i*2+0];
 				Vector3 b = sr[i*2+1];
 				//print_line(String()+a+" -> "+b);

+ 44 - 14
scene/3d/ray_cast.cpp

@@ -95,18 +95,6 @@ void RayCast::_notification(int p_what) {
 
 			if (enabled && !get_tree()->is_editor_hint()) {
 				set_fixed_process(true);
-				Node *p = get_parent();
-				while( p && p->cast_to<Spatial>() ) {
-
-					CollisionObject *co = p->cast_to<CollisionObject>();
-					if (co) {
-
-						exception=co->get_rid();
-						exceptions.insert(exception);
-					}
-
-					p=p->get_parent();
-				}
 			} else
 				set_fixed_process(false);
 
@@ -119,7 +107,6 @@ void RayCast::_notification(int p_what) {
 				set_fixed_process(false);
 			}
 
-			exceptions.erase(exception);
 
 		} break;
 		case NOTIFICATION_FIXED_PROCESS: {
@@ -143,7 +130,7 @@ void RayCast::_notification(int p_what) {
 
 			PhysicsDirectSpaceState::RayResult rr;
 
-			if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exceptions)) {
+			if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude)) {
 
 				collided=true;
 				against=rr.collider_id;
@@ -160,6 +147,41 @@ void RayCast::_notification(int p_what) {
 	}
 }
 
+void RayCast::add_exception_rid(const RID& p_rid) {
+
+	exclude.insert(p_rid);
+}
+
+void RayCast::add_exception(const Object* p_object){
+
+	ERR_FAIL_NULL(p_object);
+	CollisionObject *co=((Object*)p_object)->cast_to<CollisionObject>();
+	if (!co)
+		return;
+	add_exception_rid(co->get_rid());
+}
+
+void RayCast::remove_exception_rid(const RID& p_rid) {
+
+	exclude.erase(p_rid);
+}
+
+void RayCast::remove_exception(const Object* p_object){
+
+	ERR_FAIL_NULL(p_object);
+	CollisionObject *co=((Object*)p_object)->cast_to<CollisionObject>();
+	if (!co)
+		return;
+	remove_exception_rid(co->get_rid());
+}
+
+
+void RayCast::clear_exceptions(){
+
+	exclude.clear();
+}
+
+
 void RayCast::_bind_methods() {
 
 
@@ -176,6 +198,14 @@ void RayCast::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast::get_collision_point);
 	ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal);
 
+	ObjectTypeDB::bind_method(_MD("add_exception_rid","rid"),&RayCast::add_exception_rid);
+	ObjectTypeDB::bind_method(_MD("add_exception","node"),&RayCast::add_exception);
+
+	ObjectTypeDB::bind_method(_MD("remove_exception_rid","rid"),&RayCast::remove_exception_rid);
+	ObjectTypeDB::bind_method(_MD("remove_exception","node"),&RayCast::remove_exception);
+
+	ObjectTypeDB::bind_method(_MD("clear_exceptions"),&RayCast::clear_exceptions);
+
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
 }

+ 7 - 2
scene/3d/ray_cast.h

@@ -45,8 +45,7 @@ class RayCast : public Spatial {
 
 	Vector3 cast_to;
 
-	RID exception;
-	Set<RID> exceptions;
+	Set<RID> exclude;
 
 protected:
 
@@ -66,6 +65,12 @@ public:
 	Vector3 get_collision_point() const;
 	Vector3 get_collision_normal() const;
 
+	void add_exception_rid(const RID& p_rid);
+	void add_exception(const Object* p_object);
+	void remove_exception_rid(const RID& p_rid);
+	void remove_exception(const Object* p_object);
+	void clear_exceptions();
+
 	RayCast();
 };
 

+ 1 - 0
scene/3d/spatial_sample_player.cpp

@@ -103,6 +103,7 @@ void SpatialSamplePlayer::_notification(int p_what) {
 void SpatialSamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) {
 
 	library=p_library;
+	_change_notify();
 }
 
 Ref<SampleLibrary> SpatialSamplePlayer::get_sample_library() const {

+ 1 - 1
scene/3d/sprite_3d.cpp

@@ -497,7 +497,7 @@ void Sprite3D::set_frame(int p_frame) {
 
 	frame=p_frame;
 	_queue_update();
-	ADD_SIGNAL(MethodInfo("frame_changed"));
+	emit_signal(SceneStringNames::get_singleton()->frame_changed);
 
 }
 

+ 2 - 1
scene/animation/animation_tree_player.cpp

@@ -83,7 +83,8 @@ bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value)
 
 		ERR_FAIL_COND_V(nt==NODE_MAX,false);
 
-		add_node(nt,id);
+		if (nt!=NODE_OUTPUT)
+			add_node(nt,id);
 		node_set_pos(id,pos);
 
 

+ 1 - 0
scene/audio/sample_player.cpp

@@ -498,6 +498,7 @@ bool SamplePlayer::is_active() const {
 void SamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) {
 
 	library=p_library;
+	_change_notify();
 }
 
 Ref<SampleLibrary> SamplePlayer::get_sample_library() const {

+ 4 - 2
scene/gui/control.cpp

@@ -1126,6 +1126,7 @@ void Control::_window_input_event(InputEvent p_event) {
 				over = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform);
 			}
 
+
 			if (window->drag_data.get_type()==Variant::NIL && over && !window->modal_stack.empty()) {
 
 				Control *top = window->modal_stack.back()->get();
@@ -2267,6 +2268,7 @@ void Control::_window_sort_subwindows() {
 		return;
 
 	window->modal_stack.sort_custom<CComparator>();
+	window->subwindows.sort_custom<CComparator>();
 	window->subwindow_order_dirty=false;
 
 }
@@ -2682,8 +2684,8 @@ bool Control::is_stopping_mouse() const {
 Control *Control::get_focus_owner() const {
 
 	ERR_FAIL_COND_V(!is_inside_tree(),NULL);
-	ERR_FAIL_COND_V(!window,NULL);
-	return window->key_focus;
+	ERR_FAIL_COND_V(!data.window,NULL);
+	return data.window->window->key_focus;
 }
 
 void Control::_bind_methods() {

+ 0 - 59
scene/gui/empty_control.cpp

@@ -1,59 +0,0 @@
-/*************************************************************************/
-/*  empty_control.cpp                                                    */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                    http://www.godotengine.org                         */
-/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-#include "empty_control.h"
-
-Size2 EmptyControl::get_minimum_size() const {
-
-	return minsize;
-}
-
-void EmptyControl::set_minsize(const Size2& p_size) {
-
-	minsize=p_size;
-	minimum_size_changed();
-}
-
-Size2 EmptyControl::get_minsize() const {
-
-	return minsize;
-}
-
-
-void EmptyControl::_bind_methods() {
-
-
-	ObjectTypeDB::bind_method(_MD("set_minsize","minsize"),&EmptyControl::set_minsize);
-	ObjectTypeDB::bind_method(_MD("get_minsize"),&EmptyControl::get_minsize);
-
-	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"minsize"), _SCS("set_minsize"),_SCS("get_minsize") );
-}
-
-EmptyControl::EmptyControl()
-{
-}

+ 0 - 48
scene/gui/empty_control.h

@@ -1,48 +0,0 @@
-/*************************************************************************/
-/*  empty_control.h                                                      */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                    http://www.godotengine.org                         */
-/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-#ifndef EMPTY_CONTROL_H
-#define EMPTY_CONTROL_H
-
-#include "scene/gui/control.h"
-
-class EmptyControl : public Control {
-
-	OBJ_TYPE(EmptyControl,Control);
-	Size2 minsize;
-protected:
-	static void _bind_methods();
-public:
-	virtual Size2 get_minimum_size() const;
-	void set_minsize(const Size2& p_size);
-	Size2 get_minsize() const;
-
-	EmptyControl();
-};
-
-#endif // EMPTY_CONTROL_H

+ 517 - 0
scene/gui/graph_edit.cpp

@@ -0,0 +1,517 @@
+#include "graph_edit.h"
+
+bool GraphEditFilter::has_point(const Point2& p_point) const {
+
+	return ge->_filter_input(p_point);
+}
+
+
+GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
+
+	ge=p_edit;
+}
+
+
+Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) {
+
+	if (is_node_connected(p_from,p_from_port,p_to,p_to_port))
+		return OK;
+	Connection c;
+	c.from=p_from;
+	c.from_port=p_from_port;
+	c.to=p_to;
+	c.to_port=p_to_port;
+	connections.push_back(c);
+	top_layer->update();
+
+	return OK;
+}
+
+bool GraphEdit::is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) {
+
+	for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+		if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port)
+			return true;
+	}
+
+	return false;
+
+}
+
+void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port){
+
+
+	for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+		if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) {
+
+			connections.erase(E);
+			top_layer->update();
+			return;
+		}
+	}
+}
+
+void GraphEdit::get_connection_list(List<Connection> *r_connections) {
+
+	*r_connections=connections;
+}
+
+
+void GraphEdit::_scroll_moved(double) {
+
+
+	_update_scroll_offset();
+	top_layer->update();
+}
+
+void GraphEdit::_update_scroll_offset() {
+
+	for(int i=0;i<get_child_count();i++) {
+
+		GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+		if (!gn)
+			continue;
+
+		Point2 pos=gn->get_offset();
+		pos-=Point2(h_scroll->get_val(),v_scroll->get_val());
+		gn->set_pos(pos);
+	}
+
+}
+
+void GraphEdit::_update_scroll() {
+
+	if (updating)
+		return;
+
+	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>();
+		if (!gn)
+			continue;
+
+		Rect2 r;
+		r.pos=gn->get_offset();
+		r.size=gn->get_size();
+		screen = screen.merge(r);
+	}
+
+	h_scroll->set_min(screen.pos.x);
+	h_scroll->set_max(screen.pos.x+screen.size.x);
+	h_scroll->set_page(get_size().x);
+	if (h_scroll->get_max() - h_scroll->get_min() <= h_scroll->get_page())
+		h_scroll->hide();
+	else
+		h_scroll->show();
+
+	v_scroll->set_min(screen.pos.y);
+	v_scroll->set_max(screen.pos.y+screen.size.y);
+	v_scroll->set_page(get_size().y);
+
+	if (v_scroll->get_max() - v_scroll->get_min() <= v_scroll->get_page())
+		v_scroll->hide();
+	else
+		v_scroll->show();
+
+	_update_scroll_offset();
+	updating=false;
+}
+
+
+void GraphEdit::_graph_node_raised(Node* p_gn) {
+
+	GraphNode *gn=p_gn->cast_to<GraphNode>();
+	ERR_FAIL_COND(!gn);
+	gn->raise();
+	top_layer->raise();
+
+}
+
+
+void GraphEdit::_graph_node_moved(Node *p_gn) {
+
+	GraphNode *gn=p_gn->cast_to<GraphNode>();
+	ERR_FAIL_COND(!gn);
+
+	//gn->set_pos(gn->get_offset()+scroll_offset);
+
+	top_layer->update();
+}
+
+void GraphEdit::add_child_notify(Node *p_child) {
+
+	top_layer->call_deferred("raise"); //top layer always on top!
+	GraphNode *gn = p_child->cast_to<GraphNode>();
+	if (gn) {
+		gn->connect("offset_changed",this,"_graph_node_moved",varray(gn));
+		gn->connect("raise_request",this,"_graph_node_raised",varray(gn));
+		_graph_node_moved(gn);
+		gn->set_stop_mouse(false);
+	}
+}
+
+void GraphEdit::remove_child_notify(Node *p_child) {
+
+	top_layer->call_deferred("raise"); //top layer always on top!
+	GraphNode *gn = p_child->cast_to<GraphNode>();
+	if (gn) {
+		gn->disconnect("offset_changed",this,"_graph_node_moved");
+		gn->disconnect("raise_request",this,"_graph_node_raised");
+	}
+}
+
+void GraphEdit::_notification(int p_what) {
+
+	if (p_what==NOTIFICATION_READY) {
+		Size2 size = top_layer->get_size();
+		Size2 hmin = h_scroll->get_combined_minimum_size();
+		Size2 vmin = v_scroll->get_combined_minimum_size();
+
+		v_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,vmin.width);
+		v_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0);
+		v_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,0);
+		v_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0);
+
+		h_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,0);
+		h_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0);
+		h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height);
+		h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0);
+
+	}
+	if (p_what==NOTIFICATION_DRAW) {
+		VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+
+	}
+
+	if (p_what==NOTIFICATION_RESIZED) {
+		_update_scroll();
+		top_layer->update();
+	}
+}
+
+bool GraphEdit::_filter_input(const Point2& p_point) {
+
+	Ref<Texture> port =get_icon("port","GraphNode");
+
+	float grab_r=port->get_width()*0.5;
+	for(int i=get_child_count()-1;i>=0;i--) {
+
+		GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+		if (!gn)
+			continue;
+
+		for(int j=0;j<gn->get_connection_output_count();j++) {
+
+			Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
+			if (pos.distance_to(p_point)<grab_r)
+				return true;
+
+
+		}
+
+		for(int j=0;j<gn->get_connection_input_count();j++) {
+
+			Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
+			if (pos.distance_to(p_point)<grab_r)
+				return true;
+
+
+		}
+
+	}
+
+	return false;
+}
+
+void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
+
+	if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && p_ev.mouse_button.pressed) {
+
+		Ref<Texture> port =get_icon("port","GraphNode");
+		Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
+		float grab_r=port->get_width()*0.5;
+		for(int i=get_child_count()-1;i>=0;i--) {
+
+			GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+			if (!gn)
+				continue;
+
+			for(int j=0;j<gn->get_connection_output_count();j++) {
+
+				Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
+				if (pos.distance_to(mpos)<grab_r) {
+
+					connecting=true;
+					connecting_from=gn->get_name();
+					connecting_index=j;
+					connecting_out=true;
+					connecting_type=gn->get_connection_output_type(j);
+					connecting_color=gn->get_connection_output_color(j);
+					connecting_target=false;
+					connecting_to=pos;
+					return;
+				}
+
+
+			}
+
+			for(int j=0;j<gn->get_connection_input_count();j++) {
+
+				Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
+
+				if (pos.distance_to(mpos)<grab_r) {
+					connecting=true;
+					connecting_from=gn->get_name();
+					connecting_index=j;
+					connecting_out=false;
+					connecting_type=gn->get_connection_input_type(j);
+					connecting_color=gn->get_connection_input_color(j);
+					connecting_target=false;
+					connecting_to=pos;
+					return;
+				}
+
+
+			}
+		}
+	}
+
+	if (p_ev.type==InputEvent::MOUSE_MOTION && connecting) {
+
+		connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y);
+		connecting_target=false;
+		top_layer->update();
+
+		Ref<Texture> port =get_icon("port","GraphNode");
+		Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y);
+		float grab_r=port->get_width()*0.5;
+		for(int i=get_child_count()-1;i>=0;i--) {
+
+			GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+			if (!gn)
+				continue;
+
+			if (!connecting_out) {
+				for(int j=0;j<gn->get_connection_output_count();j++) {
+
+					Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos();
+					int type =gn->get_connection_output_type(j);
+					if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+
+						connecting_target=true;
+						connecting_to=pos;
+						connecting_target_to=gn->get_name();
+						connecting_target_index=j;
+						return;
+					}
+
+
+				}
+			} else {
+
+				for(int j=0;j<gn->get_connection_input_count();j++) {
+
+					Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
+					int type =gn->get_connection_input_type(j);
+					if (type==connecting_type && pos.distance_to(mpos)<grab_r) {
+						connecting_target=true;
+						connecting_to=pos;
+						connecting_target_to=gn->get_name();
+						connecting_target_index=j;
+						return;
+					}
+				}
+			}
+		}
+	}
+
+	if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && !p_ev.mouse_button.pressed) {
+
+		if (connecting && connecting_target) {
+
+			String from = connecting_from;
+			int from_slot = connecting_index;
+			String to =connecting_target_to;
+			int to_slot = connecting_target_index;
+
+			if (!connecting_out) {
+				SWAP(from,to);
+				SWAP(from_slot,to_slot);
+			}
+			emit_signal("connection_request",from,from_slot,to,to_slot);
+
+		}
+		connecting=false;
+		top_layer->update();
+
+	}
+
+
+
+}
+
+void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) {
+
+	static const int steps = 20;
+
+	Rect2 r;
+	r.pos=p_from;
+	r.expand_to(p_to);
+	Vector2 sign=Vector2((p_from.x < p_to.x) ? 1 : -1,(p_from.y < p_to.y) ? 1 : -1);
+	bool flip = sign.x * sign.y < 0;
+
+	Vector2 prev;
+	for(int i=0;i<=steps;i++) {
+
+		float d = i/float(steps);
+		float c=-Math::cos(d*Math_PI) * 0.5+0.5;
+		if (flip)
+			c=1.0-c;
+		Vector2 p = r.pos+Vector2(d*r.size.width,c*r.size.height);
+
+		if (i>0) {
+
+			top_layer->draw_line(prev,p,p_color,2);
+		}
+
+		prev=p;
+	}
+}
+
+void GraphEdit::_top_layer_draw() {
+
+	_update_scroll();
+
+	if (connecting) {
+
+		Node *fromn = get_node(connecting_from);
+		ERR_FAIL_COND(!fromn);
+		GraphNode *from = fromn->cast_to<GraphNode>();
+		ERR_FAIL_COND(!from);
+		Vector2 pos;
+		if (connecting_out)
+			pos=from->get_connection_output_pos(connecting_index);
+		else
+			pos=from->get_connection_input_pos(connecting_index);
+		pos+=from->get_pos();
+
+		Vector2 topos;
+		topos=connecting_to;
+
+		Color col=connecting_color;
+
+		if (connecting_target) {
+			col.r+=0.4;
+			col.g+=0.4;
+			col.b+=0.4;
+		}
+		_draw_cos_line(pos,topos,col);
+	}
+
+	List<List<Connection>::Element* > to_erase;
+	for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
+
+		NodePath fromnp(E->get().from);
+
+		Node * from = get_node(fromnp);
+		if (!from) {
+			to_erase.push_back(E);
+			continue;
+		}
+
+		GraphNode *gfrom = from->cast_to<GraphNode>();
+
+		if (!gfrom) {
+			to_erase.push_back(E);
+			continue;
+		}
+
+		NodePath tonp(E->get().to);
+		Node * to = get_node(tonp);
+		if (!to) {
+			to_erase.push_back(E);
+			continue;
+		}
+
+		GraphNode *gto = to->cast_to<GraphNode>();
+
+		if (!gto) {
+			to_erase.push_back(E);
+			continue;
+		}
+
+		Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos();
+		Color color = gfrom->get_connection_output_color(E->get().from_port);
+		Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos();
+		_draw_cos_line(frompos,topos,color);
+
+	}
+
+	while(to_erase.size()) {
+		connections.erase(to_erase.front()->get());
+		to_erase.pop_front();
+	}
+	//draw connections
+}
+
+void GraphEdit::_input_event(const InputEvent& p_ev) {
+
+	if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) {
+		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 );
+	}
+}
+
+void GraphEdit::clear_connections() {
+
+	connections.clear();
+	update();
+}
+
+
+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("_graph_node_moved"),&GraphEdit::_graph_node_moved);
+	ObjectTypeDB::bind_method(_MD("_graph_node_raised"),&GraphEdit::_graph_node_raised);
+
+	ObjectTypeDB::bind_method(_MD("_top_layer_input"),&GraphEdit::_top_layer_input);
+	ObjectTypeDB::bind_method(_MD("_top_layer_draw"),&GraphEdit::_top_layer_draw);
+	ObjectTypeDB::bind_method(_MD("_scroll_moved"),&GraphEdit::_scroll_moved);
+
+	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event);
+
+	ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
+
+}
+
+GraphEdit::GraphEdit() {
+	top_layer=NULL;
+	top_layer=memnew(GraphEditFilter(this));
+	add_child(top_layer);
+	top_layer->set_stop_mouse(false);
+	top_layer->set_area_as_parent_rect();
+	top_layer->connect("draw",this,"_top_layer_draw");
+	top_layer->set_stop_mouse(false);
+	top_layer->connect("input_event",this,"_top_layer_input");
+
+	h_scroll = memnew(HScrollBar);
+	h_scroll->set_name("_h_scroll");
+	top_layer->add_child(h_scroll);
+
+	v_scroll = memnew(VScrollBar);
+	v_scroll->set_name("_v_scroll");
+	top_layer->add_child(v_scroll);
+	updating=false;
+	connecting=false;
+
+	h_scroll->connect("value_changed", this,"_scroll_moved");
+	v_scroll->connect("value_changed", this,"_scroll_moved");
+}

+ 93 - 0
scene/gui/graph_edit.h

@@ -0,0 +1,93 @@
+#ifndef GRAPH_EDIT_H
+#define GRAPH_EDIT_H
+
+#include "scene/gui/graph_node.h"
+#include "scene/gui/scroll_bar.h"
+
+class GraphEdit;
+
+class GraphEditFilter : public Control {
+
+	OBJ_TYPE(GraphEditFilter,Control);
+
+friend class GraphEdit;
+	GraphEdit *ge;
+	virtual bool has_point(const Point2& p_point) const;
+
+public:
+
+
+	GraphEditFilter(GraphEdit *p_edit);
+};
+
+class GraphEdit : public Control {
+
+	OBJ_TYPE(GraphEdit,Control);
+public:
+
+	struct Connection {
+		StringName from;
+		StringName to;
+		int from_port;
+		int to_port;
+
+	};
+private:
+
+	HScrollBar* h_scroll;
+	VScrollBar* v_scroll;
+
+
+	bool connecting;
+	String connecting_from;
+	bool connecting_out;
+	int connecting_index;
+	int connecting_type;
+	Color connecting_color;
+	bool connecting_target;
+	Vector2 connecting_to;
+	String connecting_target_to;
+	int connecting_target_index;
+
+
+
+	bool updating;
+	List<Connection> connections;
+
+	void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color);
+
+	void _graph_node_raised(Node* p_gn);
+	void _graph_node_moved(Node *p_gn);
+
+	void _update_scroll();
+	void _scroll_moved(double);
+	void _input_event(const InputEvent& p_ev);
+
+	GraphEditFilter *top_layer;
+	void _top_layer_input(const InputEvent& p_ev);
+	void _top_layer_draw();
+	void _update_scroll_offset();
+
+friend class GraphEditFilter;
+	bool _filter_input(const Point2& p_point);
+protected:
+
+	static void _bind_methods();
+	virtual void add_child_notify(Node *p_child);
+	virtual void remove_child_notify(Node *p_child);
+	void _notification(int p_what);
+
+public:
+
+	Error connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
+	bool is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port);
+	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);
+
+
+	GraphEdit();
+};
+
+#endif // GRAPHEdit_H

+ 256 - 16
scene/gui/graph_node.cpp

@@ -76,7 +76,7 @@ void GraphNode::_get_property_list( List<PropertyInfo> *p_list) const{
 	int idx=0;
 	for(int i=0;i<get_child_count();i++) {
 		Control *c=get_child(i)->cast_to<Control>();
-		if (!c || c->is_set_as_toplevel() || !c->get_owner())
+		if (!c || c->is_set_as_toplevel() )
 			continue;
 
 		String base="slot/"+itos(idx)+"/";
@@ -122,6 +122,7 @@ void GraphNode::_resort() {
 
 	}
 
+
 	int vofs=0;
 	int w = get_size().x - sb->get_minimum_size().x;
 
@@ -131,7 +132,7 @@ void GraphNode::_resort() {
 		Control *c=get_child(i)->cast_to<Control>();
 		if (!c)
 			continue;
-		if (c->is_set_as_toplevel() || !c->get_owner())
+		if (c->is_set_as_toplevel())
 			continue;
 
 		Size2i size=c->get_combined_minimum_size();
@@ -150,6 +151,8 @@ void GraphNode::_resort() {
 
 	_change_notify();
 	update();
+	connpos_dirty=true;
+
 
 }
 
@@ -160,14 +163,34 @@ void GraphNode::_notification(int p_what) {
 
 		Ref<StyleBox> sb=get_stylebox("frame");
 		Ref<Texture> port =get_icon("port");
+		Ref<Texture> close =get_icon("close");
+		int close_offset = get_constant("close_offset");
+		Ref<Font> title_font = get_font("title_font");
+		int title_offset = get_constant("title_offset");
+		Color title_color = get_color("title_color");
 		Point2i icofs = -port->get_size()*0.5;
-		int edgeofs=3;
+		int edgeofs=get_constant("port_offset");
 		icofs.y+=sb->get_margin(MARGIN_TOP);
 		draw_style_box(sb,Rect2(Point2(),get_size()));
 
+		int w = get_size().width-sb->get_minimum_size().x;
+
+		if (show_close)
+			w-=close->get_width();
+
+		draw_string(title_font,Point2(sb->get_margin(MARGIN_LEFT),-title_font->get_height()+title_font->get_ascent()+title_offset),title,title_color,w);
+		if (show_close) {
+			Vector2 cpos = Point2(w+sb->get_margin(MARGIN_LEFT),-close->get_height()+close_offset);
+			draw_texture(close,cpos);
+			close_rect.pos=cpos;
+			close_rect.size=close->get_size();
+		} else {
+			close_rect=Rect2();
+		}
+
 		for (Map<int,Slot>::Element *E=slot_info.front();E;E=E->next()) {
 
-			if (E->key()>cache_y.size())
+			if (E->key() < 0 || E->key()>=cache_y.size())
 				continue;
 			if (!slot_info.has(E->key()))
 				continue;
@@ -180,6 +203,7 @@ void GraphNode::_notification(int p_what) {
 
 		}
 	}
+
 	if (p_what==NOTIFICATION_SORT_CHILDREN) {
 
 		_resort();
@@ -187,16 +211,6 @@ void GraphNode::_notification(int p_what) {
 
 }
 
-void GraphNode::set_title(const String& p_title) {
-
-	title=p_title;
-	update();
-}
-
-String GraphNode::get_title() const {
-
-	return title;
-}
 
 void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) {
 
@@ -216,17 +230,23 @@ void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Colo
 	s.color_right=p_color_right;
 	slot_info[p_idx]=s;
 	update();
+	connpos_dirty=true;
+
 }
 
 void GraphNode::clear_slot(int p_idx){
 
 	slot_info.erase(p_idx);
 	update();
+	connpos_dirty=true;
+
 }
 void GraphNode::clear_all_slots(){
 
 	slot_info.clear();
 	update();
+	connpos_dirty=true;
+
 }
 bool GraphNode::is_slot_enabled_left(int p_idx) const{
 
@@ -280,18 +300,26 @@ Color GraphNode::get_slot_color_right(int p_idx) const{
 
 Size2 GraphNode::get_minimum_size() const {
 
+	Ref<Font> title_font = get_font("title_font");
+
 	int sep=get_constant("separation");
 	Ref<StyleBox> sb=get_stylebox("frame");
 	bool first=true;
 
 	Size2 minsize;
+	minsize.x=title_font->get_string_size(title).x;
+	if (show_close) {
+		Ref<Texture> close =get_icon("close");
+		minsize.x+=sep+close->get_width();
+	}
+
 
 	for(int i=0;i<get_child_count();i++) {
 
 		Control *c=get_child(i)->cast_to<Control>();
 		if (!c)
 			continue;
-		if (c->is_set_as_toplevel() || !c->get_owner())
+		if (c->is_set_as_toplevel())
 			continue;
 
 		Size2i size=c->get_combined_minimum_size();
@@ -308,13 +336,225 @@ Size2 GraphNode::get_minimum_size() const {
 	return minsize+sb->get_minimum_size();
 }
 
+void GraphNode::set_title(const String& p_title) {
+
+	title=p_title;
+	minimum_size_changed();
+	update();
+
+}
+
+String GraphNode::get_title() const{
+
+	return title;
+}
+
+void GraphNode::set_offset(const Vector2& p_offset) {
+
+	offset=p_offset;
+	emit_signal("offset_changed");
+	update();
+}
+
+Vector2 GraphNode::get_offset() const {
+
+	return offset;
+}
+
+
+
+void GraphNode::set_show_close_button(bool p_enable){
+
+	show_close=p_enable;
+	update();
+}
+bool GraphNode::is_close_button_visible() const{
+
+	return show_close;
+}
+
+void GraphNode::_connpos_update() {
+
+
+	int edgeofs=get_constant("port_offset");
+	int sep=get_constant("separation");
+
+	Ref<StyleBox> sb=get_stylebox("frame");
+	Ref<Texture> port =get_icon("port");
+	conn_input_cache.clear();
+	conn_output_cache.clear();
+	int vofs=0;
+
+	int idx=0;
+
+	for(int i=0;i<get_child_count();i++) {
+		Control *c=get_child(i)->cast_to<Control>();
+		if (!c)
+			continue;
+		if (c->is_set_as_toplevel())
+			continue;
+
+		Size2i size=c->get_combined_minimum_size();
+
+		int y = sb->get_margin(MARGIN_TOP)+vofs;
+		int h = size.y;
+
+
+		if (slot_info.has(idx)) {
+
+			if (slot_info[idx].enable_left) {
+				ConnCache cc;
+				cc.pos=Point2i(edgeofs,y+h/2);
+				cc.type=slot_info[idx].type_left;
+				cc.color=slot_info[idx].color_left;
+				conn_input_cache.push_back(cc);
+			}
+			if (slot_info[idx].enable_right) {
+				ConnCache cc;
+				cc.pos=Point2i(get_size().width-edgeofs,y+h/2);
+				cc.type=slot_info[idx].type_right;
+				cc.color=slot_info[idx].color_right;
+				conn_output_cache.push_back(cc);
+			}
+		}
+
+		if (vofs>0)
+			vofs+=sep;
+		vofs+=size.y;
+		idx++;
+
+	}
+
+
+	connpos_dirty=false;
+}
+
+int GraphNode::get_connection_input_count()  {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	return conn_input_cache.size();
+
+}
+int GraphNode::get_connection_output_count() {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	return conn_output_cache.size();
+
+}
+
+
+Vector2 GraphNode::get_connection_input_pos(int p_idx) {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Vector2());
+	return conn_input_cache[p_idx].pos;
+}
+
+int GraphNode::get_connection_input_type(int p_idx) {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),0);
+	return conn_input_cache[p_idx].type;
+}
+
+Color GraphNode::get_connection_input_color(int p_idx) {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Color());
+	return conn_input_cache[p_idx].color;
+}
+
+Vector2 GraphNode::get_connection_output_pos(int p_idx){
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Vector2());
+	return conn_output_cache[p_idx].pos;
+
+}
+
+int GraphNode::get_connection_output_type(int p_idx) {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),0);
+	return conn_output_cache[p_idx].type;
+}
+
+Color GraphNode::get_connection_output_color(int p_idx) {
+
+	if (connpos_dirty)
+		_connpos_update();
+
+	ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Color());
+	return conn_output_cache[p_idx].color;
+}
+
+void GraphNode::_input_event(const InputEvent& p_ev) {
+
+	if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+
+		Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
+		if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
+			emit_signal("close_request");
+			return;
+		}
+
+		drag_from=get_offset();
+		drag_accum=Vector2();
+		dragging=true;
+		emit_signal("raise_request");
+
+	}
+
+	if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+
+		dragging=false;
+		emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
+	}
+
+	if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
+
+		drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
+		set_offset(drag_from+drag_accum);
+	}
+
+}
+
 
 void GraphNode::_bind_methods() {
 
+	ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title);
+	ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title);
+	ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event);
+
+	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);
 
+	ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible"));
+
+	ADD_SIGNAL(MethodInfo("offset_changed"));
+	ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to")));
+	ADD_SIGNAL(MethodInfo("raise_request"));
+	ADD_SIGNAL(MethodInfo("close_request"));
 }
 
 GraphNode::GraphNode() {
 
-
+	dragging=false;
+	show_close=false;
+	connpos_dirty=true;
 }

+ 43 - 3
scene/gui/graph_node.h

@@ -8,7 +8,7 @@ class GraphNode : public Container {
 	OBJ_TYPE(GraphNode,Container);
 
 
-	String title;
+
 	struct Slot {
 		bool enable_left;
 		int type_left;
@@ -21,13 +21,36 @@ class GraphNode : public Container {
 		Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); };
 	};
 
+	String title;
+	bool show_close;
+	Vector2 offset;
+
+	Rect2 close_rect;
+
 	Vector<int> cache_y;
 
+	struct ConnCache {
+		Vector2 pos;
+		int type;
+		Color color;
+	};
+
+	Vector<ConnCache> conn_input_cache;
+	Vector<ConnCache> conn_output_cache;
+
 	Map<int,Slot> slot_info;
 
+	bool connpos_dirty;
+
+	void _connpos_update();
 	void _resort();
+
+	Vector2 drag_from;
+	Vector2 drag_accum;
+	bool dragging;
 protected:
 
+	void _input_event(const InputEvent& p_ev);
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -39,8 +62,6 @@ public:
 
 
 
-	void set_title(const String& p_title);
-	String get_title() const;
 
 	void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right);
 	void clear_slot(int p_idx);
@@ -52,6 +73,25 @@ public:
 	int get_slot_type_right(int p_idx) const;
 	Color get_slot_color_right(int p_idx) const;
 
+	void set_title(const String& p_title);
+	String get_title() const;
+
+	void set_offset(const Vector2& p_offset);
+	Vector2 get_offset() const;
+
+	void set_show_close_button(bool p_enable);
+	bool is_close_button_visible() const;
+
+	int get_connection_input_count() ;
+	int get_connection_output_count() ;
+	Vector2 get_connection_input_pos(int p_idx);
+	int get_connection_input_type(int p_idx);
+	Color get_connection_input_color(int p_idx);
+	Vector2 get_connection_output_pos(int p_idx);
+	int get_connection_output_type(int p_idx);
+	Color get_connection_output_color(int p_idx);
+
+
 	virtual Size2 get_minimum_size() const;
 
 	GraphNode();

+ 1 - 0
scene/gui/menu_button.cpp

@@ -84,6 +84,7 @@ void MenuButton::pressed() {
 	popup->set_parent_rect( Rect2(Point2(gp-popup->get_global_pos()),get_size()));
 	popup->popup();
 	popup->call_deferred("grab_click_focus");
+	popup->set_invalidate_click_until_motion();
 	
 }
 

+ 14 - 1
scene/gui/popup.cpp

@@ -51,11 +51,18 @@ void Popup::_fix_size() {
 	
 	Control *window = get_window();
 	ERR_FAIL_COND(!window);
-	
+
+#if 0
 	Point2 pos = get_pos();
 	Size2 size = get_size();		
 	Point2 window_size = window==this ? get_parent_area_size()  :window->get_size();
+#else
+
+	Point2 pos = get_global_pos();
+	Size2 size = get_size();
+	Point2 window_size = get_viewport_rect().size;
 
+#endif
 	if (pos.x+size.width > window_size.width)
 		pos.x=window_size.width-size.width;
 	if (pos.x<0)
@@ -65,8 +72,14 @@ void Popup::_fix_size() {
 		pos.y=window_size.height-size.height;
 	if (pos.y<0)
 		pos.y=0;
+#if 0
 	if (pos!=get_pos())
 		set_pos(pos);
+#else
+	if (pos!=get_pos())
+		set_global_pos(pos);
+
+#endif
 
 }
 

+ 18 - 1
scene/gui/popup_menu.cpp

@@ -30,6 +30,7 @@
 #include "print_string.h"
 #include "os/keyboard.h"
 #include "translation.h"
+#include "os/input.h"
 
 String PopupMenu::_get_accel_text(uint32_t p_accel) const {
 
@@ -318,6 +319,10 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
 
 					int over=_get_mouse_over(Point2(b.x,b.y));
 
+					if (invalidated_click) {
+						invalidated_click=false;
+						break;
+					}
 					if (over<0 || items[over].separator || items[over].disabled)
 						break; //non-activable
 
@@ -336,6 +341,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
 		case InputEvent::MOUSE_MOTION: {
 	
 
+			if (invalidated_click) {
+				moved+=Vector2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y);
+				if (moved.length()>4)
+					invalidated_click=false;
+
+			}
+
 			const InputEventMouseMotion &m=p_event.mouse_motion;
 			for(List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) {
 
@@ -893,12 +905,17 @@ void PopupMenu::_bind_methods() {
 
 }
 	
+
+void PopupMenu::set_invalidate_click_until_motion() {
+	moved=Vector2();
+	invalidated_click=true;
+}
+
 PopupMenu::PopupMenu() {
 
 	idcount=0;
 	mouse_over=-1;
 	
-
 	set_focus_mode(FOCUS_ALL);
 	set_as_toplevel(true);
 

+ 4 - 0
scene/gui/popup_menu.h

@@ -70,6 +70,8 @@ class PopupMenu : public Popup {
 	void _activate_submenu(int over);
 	void _submenu_timeout();
 
+	bool invalidated_click;
+	Vector2 moved;
 
 	Array _get_items() const;
 	void _set_items(const Array& p_items);
@@ -134,6 +136,8 @@ public:
 	void add_autohide_area(const Rect2& p_area);
 	void clear_autohide_areas();
 
+	void set_invalidate_click_until_motion();
+
 	PopupMenu();	
 	~PopupMenu();
 

+ 33 - 0
scene/gui/tab_container.cpp

@@ -602,6 +602,39 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const {
 }
 
 
+Size2 TabContainer::get_minimum_size() const {
+
+	Size2 ms;
+
+	for(int i=0;i<get_child_count();i++) {
+
+		Control *c = get_child(i)->cast_to<Control>();
+		if (!c)
+			continue;
+		if (c->is_set_as_toplevel())
+			continue;
+
+		if (!c->has_meta("_tab_name"))
+			continue;
+
+		if (!c->is_visible())
+			continue;
+
+		Size2 cms = c->get_minimum_size();
+		ms.x=MAX(ms.x,cms.x);
+		ms.y=MAX(ms.y,cms.y);
+	}
+
+	Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
+	Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
+	Ref<Font> font = get_font("font");
+
+	ms.y+=MAX(tab_bg->get_minimum_size().y,tab_fg->get_minimum_size().y);
+	ms.y+=font->get_height();
+
+	return ms;
+}
+
 void TabContainer::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_input_event"),&TabContainer::_input_event);

+ 2 - 0
scene/gui/tab_container.h

@@ -85,6 +85,8 @@ public:
 	void set_current_tab(int p_current);
 	int get_current_tab() const;
 
+	virtual Size2 get_minimum_size() const;
+
 	virtual void get_translatable_strings(List<String> *p_strings) const;
 
 	TabContainer();

文件差异内容过多而无法显示
+ 400 - 400
scene/gui/text_edit.cpp


+ 1 - 0
scene/gui/text_edit.h

@@ -63,6 +63,7 @@ class TextEdit : public Control  {
 		int from_line,from_column;
 		int to_line,to_column;
 
+		bool shiftclick_left;
 
 	} selection;
 

+ 65 - 16
scene/gui/texture_button.cpp

@@ -31,28 +31,37 @@
 
 Size2 TextureButton::get_minimum_size() const {
 
+	Size2 rscale;
 	if (normal.is_null()) {
 		if (pressed.is_null()) {
 			if (hover.is_null())
 				if (click_mask.is_null())
-					return Size2();
+					rscale= Size2();
 				else
-					return click_mask->get_size();
+					rscale= click_mask->get_size();
 			else
-				return hover->get_size();
+				rscale= hover->get_size();
 		} else
-			return pressed->get_size();
+			rscale= pressed->get_size()*scale;
 
 	} else
-		return normal->get_size();
+		rscale= normal->get_size();
+
+	return rscale*scale;
 }
 
 
 bool TextureButton::has_point(const Point2& p_point) const {
 
+	if (scale[0] <= 0 || scale[1] <= 0) {
+		return false;
+	}
+
+	Point2 ppos = p_point/scale;
+
 	if (click_mask.is_valid()) {
 
-		Point2i p =p_point;
+		Point2i p =ppos;
 		if (p.x<0 || p.x>=click_mask->get_size().width || p.y<0 || p.y>=click_mask->get_size().height)
 			return false;
 
@@ -71,46 +80,57 @@ void TextureButton::_notification(int p_what) {
 			DrawMode draw_mode = get_draw_mode();
 //			if (normal.is_null())
 //				break;
+
+			Ref<Texture> texdraw;
+
 			switch (draw_mode) {
 				case DRAW_NORMAL: {
 
 					if (normal.is_valid())
-						normal->draw(canvas_item,Point2());
+						texdraw=normal;
 				} break;
 				case DRAW_PRESSED: {
 
 					if (pressed.is_null()) {
 						if (hover.is_null()) {
 							if (normal.is_valid())
-								normal->draw(canvas_item,Point2());
+								texdraw=normal;
 						} else
-							hover->draw(canvas_item,Point2());
+							texdraw=hover;
 
 					} else
-						pressed->draw(canvas_item,Point2());
+						texdraw=pressed;
 				} break;
 				case DRAW_HOVER: {
 
 					if (hover.is_null()) {
 						if (pressed.is_valid() && is_pressed())
-							pressed->draw(canvas_item,Point2());
+							texdraw=pressed;
 						else if (normal.is_valid())
-							normal->draw(canvas_item,Point2());
+							texdraw=normal;
 					} else
-						hover->draw(canvas_item,Point2());
+						texdraw=hover;
 				} break;
 				case DRAW_DISABLED: {
 
 					if (disabled.is_null()) {
 						if (normal.is_valid())
-							normal->draw(canvas_item,Point2());
+							texdraw=normal;
 					} else
-						disabled->draw(canvas_item,Point2());
+						texdraw=disabled;
 				} break;
 			}
+
+			if (texdraw.is_valid()) {
+				Rect2 drect(Point2(),texdraw->get_size()*scale);
+				draw_texture_rect(texdraw,drect,false,modulate);
+
+			}
 			if (has_focus() && focused.is_valid()) {
 
-				focused->draw(canvas_item, Point2());
+				Rect2 drect(Point2(),focused->get_size()*scale);
+				draw_texture_rect(focused,drect,false,modulate);
+
 			};
 
 		} break;
@@ -125,6 +145,8 @@ void TextureButton::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_disabled_texture","texture:Texture"),&TextureButton::set_disabled_texture);
 	ObjectTypeDB::bind_method(_MD("set_focused_texture","texture:Texture"),&TextureButton::set_focused_texture);
 	ObjectTypeDB::bind_method(_MD("set_click_mask","mask:BitMap"),&TextureButton::set_click_mask);
+	ObjectTypeDB::bind_method(_MD("set_scale","scale"),&TextureButton::set_scale);
+	ObjectTypeDB::bind_method(_MD("set_modulate","color"),&TextureButton::set_modulate);
 
 	ObjectTypeDB::bind_method(_MD("get_normal_texture:Texture"),&TextureButton::get_normal_texture);
 	ObjectTypeDB::bind_method(_MD("get_pressed_texture:Texture"),&TextureButton::get_pressed_texture);
@@ -132,6 +154,8 @@ void TextureButton::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_disabled_texture:Texture"),&TextureButton::get_disabled_texture);
 	ObjectTypeDB::bind_method(_MD("get_focused_texture:Texture"),&TextureButton::get_focused_texture);
 	ObjectTypeDB::bind_method(_MD("get_click_mask:BitMap"),&TextureButton::get_click_mask);
+	ObjectTypeDB::bind_method(_MD("get_scale"),&TextureButton::get_scale);
+	ObjectTypeDB::bind_method(_MD("get_modulate"),&TextureButton::get_modulate);
 
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_normal_texture"), _SCS("get_normal_texture"));
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_pressed_texture"), _SCS("get_pressed_texture"));
@@ -139,6 +163,8 @@ void TextureButton::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/disabled",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_disabled_texture"), _SCS("get_disabled_texture"));
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/focused",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_focused_texture"), _SCS("get_focused_texture"));
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/click_mask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"), _SCS("set_click_mask"), _SCS("get_click_mask")) ;
+	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"params/scale",PROPERTY_HINT_RANGE,"0.01,1024,0.01"), _SCS("set_scale"), _SCS("get_scale"));
+	ADD_PROPERTY(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
 
 }
 
@@ -206,6 +232,29 @@ void TextureButton::set_focused_texture(const Ref<Texture>& p_focused) {
 	focused = p_focused;
 };
 
+void TextureButton::set_scale(Size2 p_scale) {
+
+	scale=p_scale;
+	minimum_size_changed();
+	update();
+}
+
+Size2 TextureButton::get_scale() const{
+
+	return scale;
+}
+
+void TextureButton::set_modulate(const Color& p_modulate) {
+	modulate=p_modulate;
+	update();
+}
+
+Color TextureButton::get_modulate() const {
+	return modulate;
+}
+
 
 TextureButton::TextureButton() {
+	scale=Size2(1.0, 1.0);
+	modulate=Color(1,1,1);
 }

+ 7 - 0
scene/gui/texture_button.h

@@ -41,6 +41,8 @@ class TextureButton : public BaseButton {
 	Ref<Texture> disabled;
 	Ref<Texture> focused;
 	Ref<BitMap> click_mask;
+	Size2 scale;
+	Color modulate;
 
 
 protected:
@@ -66,6 +68,11 @@ public:
 	Ref<Texture> get_focused_texture() const;
 	Ref<BitMap> get_click_mask() const;
 
+	void set_scale(Size2 p_scale);
+	Size2 get_scale() const;
+
+	void set_modulate(const Color& p_modulate);
+	Color get_modulate() const;
 
 	TextureButton();
 };

+ 5 - 0
scene/main/node.cpp

@@ -382,6 +382,8 @@ bool Node::can_process() const {
 
 	if (get_tree()->is_paused()) {
 
+		if (data.pause_mode==PAUSE_MODE_STOP)
+			return false;
 		if (data.pause_mode==PAUSE_MODE_PROCESS)
 			return true;
 		if (data.pause_mode==PAUSE_MODE_INHERIT) {
@@ -391,6 +393,9 @@ bool Node::can_process() const {
 
 			if (data.pause_owner->data.pause_mode==PAUSE_MODE_PROCESS)
 				return true;
+
+			if (data.pause_owner->data.pause_mode==PAUSE_MODE_STOP)
+				return false;
 		}
 
 	}

+ 15 - 5
scene/register_scene_types.cpp

@@ -39,7 +39,6 @@
 #include "scene/main/viewport.h"
 #include "scene/gui/control.h"
 #include "scene/gui/texture_progress.h"
-#include "scene/gui/empty_control.h"
 #include "scene/gui/button.h"
 #include "scene/gui/button_array.h"
 #include "scene/gui/button_group.h"
@@ -76,6 +75,7 @@
 #include "scene/gui/video_player.h"
 #include "scene/gui/reference_frame.h"
 #include "scene/gui/graph_node.h"
+#include "scene/gui/graph_edit.h"
 #include "scene/resources/video_stream.h"
 #include "scene/2d/particles_2d.h"
 #include "scene/2d/path_2d.h"
@@ -153,6 +153,8 @@
 #include "scene/resources/mesh.h"
 #include "scene/resources/room.h"
 
+#include "scene/resources/shader_graph.h"
+
 #include "scene/resources/world.h"
 #include "scene/resources/world_2d.h"
 #include "scene/resources/volume.h"
@@ -269,7 +271,8 @@ void register_scene_types() {
 	OS::get_singleton()->yield(); //may take time to init
 
 	ObjectTypeDB::register_type<Control>();
-	ObjectTypeDB::register_type<EmptyControl>();
+//	ObjectTypeDB::register_type<EmptyControl>();
+	ObjectTypeDB::add_compatibility_type("EmptyControl","control");
 	ObjectTypeDB::register_type<Button>();
 	ObjectTypeDB::register_type<Label>();
 	ObjectTypeDB::register_type<HScrollBar>();
@@ -305,6 +308,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<HSplitContainer>();
 	ObjectTypeDB::register_type<VSplitContainer>();
 	ObjectTypeDB::register_type<GraphNode>();
+	ObjectTypeDB::register_type<GraphEdit>();
 
 	OS::get_singleton()->yield(); //may take time to init
 
@@ -496,11 +500,17 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<Mesh>();
 	ObjectTypeDB::register_virtual_type<Material>();
 	ObjectTypeDB::register_type<FixedMaterial>();
-	ObjectTypeDB::register_type<ParticleSystemMaterial>();
-	ObjectTypeDB::register_type<UnshadedMaterial>();
+	//ObjectTypeDB::register_type<ParticleSystemMaterial>();
+	//ObjectTypeDB::register_type<UnshadedMaterial>();
 	ObjectTypeDB::register_type<ShaderMaterial>();
 	ObjectTypeDB::register_type<RoomBounds>();
-	ObjectTypeDB::register_type<Shader>();
+	ObjectTypeDB::register_virtual_type<Shader>();
+	ObjectTypeDB::register_virtual_type<ShaderGraph>();
+	ObjectTypeDB::register_type<MaterialShaderGraph>();
+	ObjectTypeDB::register_type<MaterialShader>();
+	ObjectTypeDB::add_compatibility_type("Shader","MaterialShader");
+	ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedMaterial");
+	ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedMaterial");
 	ObjectTypeDB::register_type<MultiMesh>();
 	ObjectTypeDB::register_type<MeshLibrary>();
 

+ 7 - 1
scene/resources/default_theme/default_theme.cpp

@@ -417,12 +417,18 @@ void make_default_theme() {
 	t->set_constant("hseparation","PopupMenu",2);
 	t->set_constant("vseparation","PopupMenu",1);
 
-	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,21,6,5,16,21,16,5);
+	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
 	//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
 	//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
 	t->set_stylebox("frame","GraphNode", graphsb );
 	t->set_constant("separation","GraphNode", 1 );
 	t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
+	t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
+	t->set_font("title_font","GraphNode", default_font );
+	t->set_color("title_color","GraphNode", Color(0,0,0,1));
+	t->set_constant("title_offset","GraphNode", 18);
+	t->set_constant("close_offset","GraphNode", 18);
+	t->set_constant("port_offset","GraphNode", 3);
 
 
 	t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) );

二进制
scene/resources/default_theme/graph_node_close.png


文件差异内容过多而无法显示
+ 5 - 0
scene/resources/default_theme/theme_data.h


+ 1 - 1
scene/resources/material.cpp

@@ -501,7 +501,7 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const {
 
 void ShaderMaterial::_get_property_list( List<PropertyInfo> *p_list) const {
 
-	p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"Shader" ) );
+	p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"MaterialShader,MaterialShaderGraph" ) );
 
 	if (!shader.is_null()) {
 

+ 3 - 10
scene/resources/shader.cpp

@@ -33,12 +33,6 @@
 #include "scene/scene_string_names.h"
 
 
-void Shader::set_mode(Mode p_mode) {
-
-	ERR_FAIL_INDEX(p_mode,2);
-	VisualServer::get_singleton()->shader_set_mode(shader,VisualServer::ShaderMode(p_mode));
-	emit_signal(SceneStringNames::get_singleton()->changed);
-}
 
 Shader::Mode Shader::get_mode() const {
 
@@ -176,7 +170,6 @@ void Shader::get_default_texture_param_list(List<StringName>* r_textures) const{
 
 void Shader::_bind_methods() {
 
-	ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode);
 	ObjectTypeDB::bind_method(_MD("get_mode"),&Shader::get_mode);
 
 	ObjectTypeDB::bind_method(_MD("set_code","vcode","fcode","lcode","fofs","lofs"),&Shader::set_code,DEFVAL(0),DEFVAL(0));
@@ -203,9 +196,9 @@ void Shader::_bind_methods() {
 
 }
 
-Shader::Shader() {
+Shader::Shader(Mode p_mode) {
 
-	shader = VisualServer::get_singleton()->shader_create();
+	shader = VisualServer::get_singleton()->shader_create(VS::ShaderMode(p_mode));
 	params_cache_dirty=true;
 }
 
@@ -237,7 +230,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin
 	String base_path = p_path.get_base_dir();
 
 
-	Ref<Shader> shader( memnew( Shader ) );
+	Ref<Shader> shader;//( memnew( Shader ) );
 
 	int line=0;
 

+ 15 - 3
scene/resources/shader.h

@@ -50,6 +50,8 @@ class Shader : public Resource {
 	mutable Map<StringName,StringName> params_cache; //map a shader param to a material param..
 	Map<StringName,Ref<Texture> > default_textures;
 
+
+
 protected:
 
 
@@ -59,10 +61,11 @@ public:
 
 		MODE_MATERIAL,
 		MODE_CANVAS_ITEM,
-		MODE_POST_PROCESS
+		MODE_POST_PROCESS,
+		MODE_MAX
 	};
 
-	void set_mode(Mode p_mode);
+	//void set_mode(Mode p_mode);
 	Mode get_mode() const;
 
 	void set_code( const String& p_vertex, const String& p_fragment, const String& p_light,int p_fragment_ofs=0,int p_light_ofs=0);
@@ -79,13 +82,22 @@ public:
 
 	virtual RID get_rid() const;
 
-	Shader();
+	Shader(Mode p_mode);
 	~Shader();
 
 };
 
 VARIANT_ENUM_CAST( Shader::Mode );
 
+class MaterialShader : public Shader {
+
+	OBJ_TYPE(MaterialShader,Shader);
+
+public:
+
+	MaterialShader() : Shader(MODE_MATERIAL) {};
+};
+
 
 
 class ResourceFormatLoaderShader : public ResourceFormatLoader {

+ 1507 - 760
scene/resources/shader_graph.cpp

@@ -30,118 +30,249 @@
 
 
 
-# if 0
-void ShaderGraph::_set(const String& p_name, const Variant& p_value) {
+Array ShaderGraph::_get_node_list(ShaderType p_type) const {
 
-	if (p_name.begins_with("nodes/")) {
-		int idx=p_name.get_slice("/",1).to_int();
-		Dictionary data=p_value;
+	List<int> nodes;
+	get_node_list(p_type,&nodes);
+	Array arr(true);
+	for (List<int>::Element *E=nodes.front();E;E=E->next())
+		arr.push_back(E->get());
+	return arr;
+}
+Array ShaderGraph::_get_connections(ShaderType p_type) const {
 
-		ERR_FAIL_COND(!data.has("type"));
-		String type=data["type"];
+	List<Connection> connections;
+	get_node_connections(p_type,&connections);
+	Array arr(true);
+	for (List<Connection>::Element *E=connections.front();E;E=E->next()) {
 
-		VS::NodeType node_type=VS::NODE_TYPE_MAX;
-		for(int i=0;i<NODE_TYPE_MAX;i++) {
+		Dictionary d(true);
+		d["src_id"]=E->get().src_id;
+		d["src_slot"]=E->get().src_slot;
+		d["dst_id"]=E->get().dst_id;
+		d["dst_slot"]=E->get().dst_slot;
+		arr.push_back(d);
 
-			if (type==VisualServer::shader_node_get_type_info((VS::NodeType)i).name)
-				node_type=(VS::NodeType)i;
-		}
+	}
+	return arr;
+}
 
-		ERR_FAIL_COND(node_type==VS::NODE_TYPE_MAX);
+void ShaderGraph::_bind_methods() {
 
-		node_add( (NodeType)node_type, idx );
-		if (data.has("param"))
-			node_set_param(idx,data["param"]);
-		if (data.has("pos"))
-			node_set_pos(idx,data["pos"]);
-	}
+	ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
 
-	if (p_name.begins_with("conns/")) {
-		Dictionary data=p_value;
-		ERR_FAIL_COND( !data.has("src_id") );
-		ERR_FAIL_COND( !data.has("src_slot") );
-		ERR_FAIL_COND( !data.has("dst_id") );
-		ERR_FAIL_COND( !data.has("dst_slot") );
+	ObjectTypeDB::bind_method(_MD("node_add","shader_type","node_type","id"),&ShaderGraph::node_add);
+	ObjectTypeDB::bind_method(_MD("node_remove","shader_type","id"),&ShaderGraph::node_remove);
+	ObjectTypeDB::bind_method(_MD("node_set_pos","shader_type","id","pos"),&ShaderGraph::node_set_pos);
+	ObjectTypeDB::bind_method(_MD("node_get_pos","shader_type","id"),&ShaderGraph::node_get_pos);
 
-		connect(data["src_id"],data["src_slot"],data["dst_id"],data["dst_slot"]);
-	}
+	ObjectTypeDB::bind_method(_MD("node_get_type","shader_type","id"),&ShaderGraph::node_get_type);
 
-	return false;
-}
-Variant ShaderGraph::_get(const String& p_name) const {
+	ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
 
-	if (p_name.begins_with("nodes/")) {
-		int idx=p_name.get_slice("/",1).to_int();
-		Dictionary data;
-		data["type"]=VisualServer::shader_node_get_type_info((VS::NodeType)node_get_type(idx)).name;
-		data["pos"]=node_get_pos(idx);
-		data["param"]=node_get_param(idx);
-		return data;
-	}
-	if (p_name.begins_with("conns/")) {
-		int idx=p_name.get_slice("/",1).to_int();
-		Dictionary data;
-
-		List<Connection> connections;
-		get_connections(&connections);
-		ERR_FAIL_INDEX_V( idx,connections.size(), Variant() );
-		Connection c = connections[idx];
-
-		data["src_id"]=c.src_id;
-		data["src_slot"]=c.src_slot;
-		data["dst_id"]=c.dst_id;
-		data["dst_slot"]=c.dst_slot;
-		return data;
-	}
+	ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
+	ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_set_value);
 
-	return Variant();
-}
-void ShaderGraph::_get_property_list( List<PropertyInfo> *p_list) const {
+	ObjectTypeDB::bind_method(_MD("vec_const_node_set_value","shader_type","id","value"),&ShaderGraph::vec_const_node_set_value);
+	ObjectTypeDB::bind_method(_MD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_set_value);
 
-	List<int> nodes;
-	get_node_list(&nodes);
+	ObjectTypeDB::bind_method(_MD("rgb_const_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_const_node_set_value);
+	ObjectTypeDB::bind_method(_MD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_set_value);
 
-	for(List<int>::Element *E=nodes.front();E;E=E->next()) {
+	ObjectTypeDB::bind_method(_MD("xform_const_node_set_value","shader_type","id","value"),&ShaderGraph::xform_const_node_set_value);
+	ObjectTypeDB::bind_method(_MD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_set_value);
 
-		int idx=E->get();
-		p_list->push_back(PropertyInfo( Variant::DICTIONARY , "nodes/"+itos(idx),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) );
-	}
 
-	List<Connection> connections;
-	get_connections(&connections);
-	int idx=0;
-	for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
-		p_list->push_back(PropertyInfo( Variant::DICTIONARY , "conns/"+itos(idx++),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) );
-	}
+//	void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
 
-}
+	ObjectTypeDB::bind_method(_MD("texture_node_set_filter_size","shader_type","id","filter_size"),&ShaderGraph::texture_node_set_filter_size);
+	ObjectTypeDB::bind_method(_MD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_set_filter_size);
 
-#endif
-#if 0
-Array ShaderGraph::_get_connections_helper() const {
+	ObjectTypeDB::bind_method(_MD("texture_node_set_filter_strength","shader_type","id","filter_strength"),&ShaderGraph::texture_node_set_filter_strength);
+	ObjectTypeDB::bind_method(_MD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_set_filter_strength);
 
-	Array connections_ret;
-	List<Connection> connections;
-	get_connections(&connections);
-	connections_ret.resize(connections.size());
-
-	int idx=0;
-	for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
-
-		Connection c = E->get();
-		Dictionary data;
-		data["src_id"]=c.src_id;
-		data["src_slot"]=c.src_slot;
-		data["dst_id"]=c.dst_id;
-		data["dst_slot"]=c.dst_slot;
-		connections_ret.set(idx++,data);
-	}
+	ObjectTypeDB::bind_method(_MD("scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::scalar_op_node_set_op);
+	ObjectTypeDB::bind_method(_MD("scalar_op_node_get_op","shader_type","id"),&ShaderGraph::scalar_op_node_get_op);
 
-	return connections_ret;
-}
+	ObjectTypeDB::bind_method(_MD("vec_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_op_node_set_op);
+	ObjectTypeDB::bind_method(_MD("vec_op_node_get_op","shader_type","id"),&ShaderGraph::vec_op_node_get_op);
 
-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_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);
+
+	ObjectTypeDB::bind_method(_MD("scalar_func_node_set_function","shader_type","id","func"),&ShaderGraph::scalar_func_node_set_function);
+	ObjectTypeDB::bind_method(_MD("scalar_func_node_get_function","shader_type","id"),&ShaderGraph::scalar_func_node_get_function);
+
+	ObjectTypeDB::bind_method(_MD("vec_func_node_set_function","shader_type","id","func"),&ShaderGraph::vec_func_node_set_function);
+	ObjectTypeDB::bind_method(_MD("vec_func_node_get_function","shader_type","id"),&ShaderGraph::vec_func_node_get_function);
+
+	ObjectTypeDB::bind_method(_MD("input_node_set_name","shader_type","id","name"),&ShaderGraph::input_node_set_name);
+	ObjectTypeDB::bind_method(_MD("input_node_get_name","shader_type","id"),&ShaderGraph::input_node_get_name);
+
+	ObjectTypeDB::bind_method(_MD("scalar_input_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_input_node_set_value);
+	ObjectTypeDB::bind_method(_MD("scalar_input_node_get_value","shader_type","id"),&ShaderGraph::scalar_input_node_get_value);
+
+	ObjectTypeDB::bind_method(_MD("vec_input_node_set_value","shader_type","id","value"),&ShaderGraph::vec_input_node_set_value);
+	ObjectTypeDB::bind_method(_MD("vec_input_node_get_value","shader_type","id"),&ShaderGraph::vec_input_node_get_value);
+
+	ObjectTypeDB::bind_method(_MD("rgb_input_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_input_node_set_value);
+	ObjectTypeDB::bind_method(_MD("rgb_input_node_get_value","shader_type","id"),&ShaderGraph::rgb_input_node_get_value);
+
+	ObjectTypeDB::bind_method(_MD("xform_input_node_set_value","shader_type","id","value"),&ShaderGraph::xform_input_node_set_value);
+	ObjectTypeDB::bind_method(_MD("xform_input_node_get_value","shader_type","id"),&ShaderGraph::xform_input_node_get_value);
+
+	ObjectTypeDB::bind_method(_MD("texture_input_node_set_value","shader_type","id","value:Texture"),&ShaderGraph::texture_input_node_set_value);
+	ObjectTypeDB::bind_method(_MD("texture_input_node_get_value:Texture","shader_type","id"),&ShaderGraph::texture_input_node_get_value);
+
+	ObjectTypeDB::bind_method(_MD("cubemap_input_node_set_value","shader_type","id","value:CubeMap"),&ShaderGraph::cubemap_input_node_set_value);
+	ObjectTypeDB::bind_method(_MD("cubemap_input_node_get_value:CubeMap","shader_type","id"),&ShaderGraph::cubemap_input_node_get_value);
 
+	ObjectTypeDB::bind_method(_MD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text);
+	ObjectTypeDB::bind_method(_MD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text);
+
+	ObjectTypeDB::bind_method(_MD("connect_node:Error","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node);
+	ObjectTypeDB::bind_method(_MD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected);
+	ObjectTypeDB::bind_method(_MD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node);
+	ObjectTypeDB::bind_method(_MD("get_node_connections","shader_type"),&ShaderGraph::_get_connections);
+
+	ObjectTypeDB::bind_method(_MD("clear","shader_type"),&ShaderGraph::clear);
+
+	ObjectTypeDB::bind_method(_MD("node_set_state","shader_type","id","state"),&ShaderGraph::node_set_state);
+	ObjectTypeDB::bind_method(_MD("node_get_state:var","shader_type","id"),&ShaderGraph::node_get_state);
+
+	//void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
+
+
+	BIND_CONSTANT( NODE_INPUT ); // all inputs (shader type dependent)
+	BIND_CONSTANT( NODE_SCALAR_CONST ); //scalar constant
+	BIND_CONSTANT( NODE_VEC_CONST ); //vec3 constant
+	BIND_CONSTANT( NODE_RGB_CONST ); //rgb constant (shows a color picker instead)
+	BIND_CONSTANT( NODE_XFORM_CONST ); // 4x4 matrix constant
+	BIND_CONSTANT( NODE_TIME ); // time in seconds
+	BIND_CONSTANT( NODE_SCREEN_TEX ); // screen texture sampler (takes UV) (only usable in fragment shader)
+	BIND_CONSTANT( NODE_SCALAR_OP ); // scalar vs scalar op (mul ); add ); div ); etc)
+	BIND_CONSTANT( NODE_VEC_OP ); // vec3 vs vec3 op (mul );ad );div );crossprod );etc)
+	BIND_CONSTANT( NODE_VEC_SCALAR_OP ); // vec3 vs scalar op (mul ); add ); div ); etc)
+	BIND_CONSTANT( NODE_RGB_OP ); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc.
+	BIND_CONSTANT( NODE_XFORM_MULT ); // mat4 x mat4
+	BIND_CONSTANT( NODE_XFORM_VEC_MULT ); // mat4 x vec3 mult (with no-translation option)
+	BIND_CONSTANT( NODE_XFORM_VEC_INV_MULT ); // mat4 x vec3 inverse mult (with no-translation option)
+	BIND_CONSTANT( NODE_SCALAR_FUNC ); // scalar function (sin ); cos ); etc)
+	BIND_CONSTANT( NODE_VEC_FUNC ); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc)
+	BIND_CONSTANT( NODE_VEC_LEN ); // vec3 length
+	BIND_CONSTANT( NODE_DOT_PROD ); // vec3 . vec3 (dot product -> scalar output)
+	BIND_CONSTANT( NODE_VEC_TO_SCALAR ); // 1 vec3 input ); 3 scalar outputs
+	BIND_CONSTANT( NODE_SCALAR_TO_VEC ); // 3 scalar input ); 1 vec3 output
+	BIND_CONSTANT( NODE_VEC_TO_XFORM ); // 3 vec input ); 1 xform output
+	BIND_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output
+	BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve)
+	BIND_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation  (with optional curve)
+	BIND_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material)
+	BIND_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material)
+	BIND_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material)
+	BIND_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material)
+	BIND_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material)
+	BIND_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material)
+	BIND_CONSTANT( NODE_OUTPUT ); // output (shader type dependent)
+	BIND_CONSTANT( NODE_COMMENT ); // comment
+	BIND_CONSTANT( NODE_TYPE_MAX );
+
+	BIND_CONSTANT( SLOT_TYPE_SCALAR );
+	BIND_CONSTANT( SLOT_TYPE_VEC );
+	BIND_CONSTANT( SLOT_TYPE_XFORM );
+	BIND_CONSTANT( SLOT_TYPE_TEXTURE );
+	BIND_CONSTANT( SLOT_MAX );
+
+	BIND_CONSTANT( SHADER_TYPE_VERTEX );
+	BIND_CONSTANT( SHADER_TYPE_FRAGMENT );
+	BIND_CONSTANT( SHADER_TYPE_LIGHT );
+	BIND_CONSTANT( SHADER_TYPE_MAX );
+
+
+	BIND_CONSTANT( SLOT_IN );
+	BIND_CONSTANT( SLOT_OUT );
+
+	BIND_CONSTANT( GRAPH_OK );
+	BIND_CONSTANT( GRAPH_ERROR_CYCLIC  );
+	BIND_CONSTANT( GRAPH_ERROR_MISSING_CONNECTIONS );
+
+	BIND_CONSTANT( SCALAR_OP_ADD );
+	BIND_CONSTANT( SCALAR_OP_SUB );
+	BIND_CONSTANT( SCALAR_OP_MUL );
+	BIND_CONSTANT( SCALAR_OP_DIV );
+	BIND_CONSTANT( SCALAR_OP_MOD );
+	BIND_CONSTANT( SCALAR_OP_POW );
+	BIND_CONSTANT( SCALAR_OP_MAX );
+	BIND_CONSTANT( SCALAR_OP_MIN );
+	BIND_CONSTANT( SCALAR_OP_ATAN2 );
+	BIND_CONSTANT( SCALAR_MAX_OP );
+
+	BIND_CONSTANT( VEC_OP_ADD );
+	BIND_CONSTANT( VEC_OP_SUB );
+	BIND_CONSTANT( VEC_OP_MUL );
+	BIND_CONSTANT( VEC_OP_DIV );
+	BIND_CONSTANT( VEC_OP_MOD );
+	BIND_CONSTANT( VEC_OP_POW );
+	BIND_CONSTANT( VEC_OP_MAX );
+	BIND_CONSTANT( VEC_OP_MIN );
+	BIND_CONSTANT( VEC_OP_CROSS );
+	BIND_CONSTANT( VEC_MAX_OP );
+
+	BIND_CONSTANT( VEC_SCALAR_OP_MUL );
+	BIND_CONSTANT( VEC_SCALAR_OP_DIV );
+	BIND_CONSTANT( VEC_SCALAR_OP_POW );
+	BIND_CONSTANT( VEC_SCALAR_MAX_OP );
+
+	BIND_CONSTANT( RGB_OP_SCREEN );
+	BIND_CONSTANT( RGB_OP_DIFFERENCE );
+	BIND_CONSTANT( RGB_OP_DARKEN );
+	BIND_CONSTANT( RGB_OP_LIGHTEN );
+	BIND_CONSTANT( RGB_OP_OVERLAY );
+	BIND_CONSTANT( RGB_OP_DODGE );
+	BIND_CONSTANT( RGB_OP_BURN );
+	BIND_CONSTANT( RGB_OP_SOFT_LIGHT );
+	BIND_CONSTANT( RGB_OP_HARD_LIGHT );
+	BIND_CONSTANT( RGB_MAX_OP );
+
+	BIND_CONSTANT( SCALAR_FUNC_SIN );
+	BIND_CONSTANT( SCALAR_FUNC_COS );
+	BIND_CONSTANT( SCALAR_FUNC_TAN );
+	BIND_CONSTANT( SCALAR_FUNC_ASIN );
+	BIND_CONSTANT( SCALAR_FUNC_ACOS );
+	BIND_CONSTANT( SCALAR_FUNC_ATAN );
+	BIND_CONSTANT( SCALAR_FUNC_SINH );
+	BIND_CONSTANT( SCALAR_FUNC_COSH );
+	BIND_CONSTANT( SCALAR_FUNC_TANH );
+	BIND_CONSTANT( SCALAR_FUNC_LOG );
+	BIND_CONSTANT( SCALAR_FUNC_EXP );
+	BIND_CONSTANT( SCALAR_FUNC_SQRT );
+	BIND_CONSTANT( SCALAR_FUNC_ABS );
+	BIND_CONSTANT( SCALAR_FUNC_SIGN );
+	BIND_CONSTANT( SCALAR_FUNC_FLOOR );
+	BIND_CONSTANT( SCALAR_FUNC_ROUND );
+	BIND_CONSTANT( SCALAR_FUNC_CEIL );
+	BIND_CONSTANT( SCALAR_FUNC_FRAC );
+	BIND_CONSTANT( SCALAR_FUNC_SATURATE );
+	BIND_CONSTANT( SCALAR_FUNC_NEGATE );
+	BIND_CONSTANT( SCALAR_MAX_FUNC );
+
+	BIND_CONSTANT( VEC_FUNC_NORMALIZE );
+	BIND_CONSTANT( VEC_FUNC_SATURATE );
+	BIND_CONSTANT( VEC_FUNC_NEGATE );
+	BIND_CONSTANT( VEC_FUNC_RECIPROCAL );
+	BIND_CONSTANT( VEC_FUNC_RGB2HSV );
+	BIND_CONSTANT( VEC_FUNC_HSV2RGB );
+	BIND_CONSTANT( VEC_MAX_FUNC );
+
+
+#if 0
 	ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add );
 	ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove );
 	ObjectTypeDB::bind_method(_MD("node_set_param"),&ShaderGraph::node_set_param );
@@ -212,73 +343,154 @@ void ShaderGraph::_bind_methods() {
 	BIND_CONSTANT( NODE_TEXTURE_2D_PARAMETER );
 	BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER );
 	BIND_CONSTANT( NODE_TYPE_MAX );
+#endif
 }
 
-void ShaderGraph::node_add(NodeType p_type,int p_id) {
 
+String ShaderGraph::_find_unique_name(ShaderType p_which, const String& p_base) {
+
+
+
+	int idx=1;
+	while(true) {
+		String tocmp=p_base;
+		if (idx>1) {
+			tocmp+="_"+itos(idx);
+		}
+		bool valid=true;
+		for (Map<int,Node>::Element *E=shader[p_which].node_map.front();E;E=E->next()) {
+			if (E->get().type!=NODE_SCALAR_INPUT && E->get().type!=NODE_VEC_INPUT && E->get().type==NODE_RGB_INPUT && E->get().type==NODE_XFORM_INPUT && E->get().type==NODE_TEXTURE_INPUT && E->get().type==NODE_CUBEMAP_INPUT)
+				continue;
+			String name = E->get().param1;
+			if (name==tocmp) {
+				valid=false;
+				break;
+			}
+
+		}
+
+		if (!valid) {
+			idx++;
+			continue;
+		}
+		return tocmp;
+	}
+	return String();
+}
 
-	ERR_FAIL_COND( node_map.has(p_id ) );
-	ERR_FAIL_INDEX( p_type, NODE_TYPE_MAX );
+void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
+
+	ERR_FAIL_INDEX(p_type,3);
+	ERR_FAIL_COND(p_id==0);
+	ERR_FAIL_COND(p_node_type==NODE_OUTPUT); //can't create output
+	ERR_FAIL_COND( shader[p_type].node_map.has(p_id ) );
+	ERR_FAIL_INDEX( p_node_type, NODE_TYPE_MAX );
 	Node node;
 
-	node.type=p_type;
+	if (p_node_type==NODE_INPUT) {
+		//see if it already exists
+		for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+			if (E->get().type==NODE_INPUT) {
+				ERR_EXPLAIN("Only one input node can be added to the graph.");
+				ERR_FAIL_COND(E->get().type==NODE_INPUT);
+			}
+		}
+	}
+	node.type=p_node_type;
 	node.id=p_id;
-	node.x=0;
-	node.y=0;
 
-	node_map[p_id]=node;
+	switch(p_node_type) {
+		case NODE_INPUT: {} break; // all inputs (shader type dependent)
+		case NODE_SCALAR_CONST: { node.param1=0;} break; //scalar constant
+		case NODE_VEC_CONST: {node.param1=Vector3();} break; //vec3 constant
+		case NODE_RGB_CONST: {node.param1=Color();} break; //rgb constant (shows a color picker instead)
+		case NODE_XFORM_CONST: {node.param1=Transform();} break; // 4x4 matrix constant
+		case NODE_TIME: {} break; // time in seconds
+		case NODE_SCREEN_TEX: {Array arr; arr.push_back(0); arr.push_back(0); node.param2=arr;} break; // screen texture sampler (takes UV) (only usable in fragment shader)
+		case NODE_SCALAR_OP: {node.param1=SCALAR_OP_ADD;} break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
+		case NODE_VEC_OP: {node.param1=VEC_OP_ADD;} break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc)
+		case NODE_VEC_SCALAR_OP: {node.param1=VEC_SCALAR_OP_MUL;} break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc)
+		case NODE_RGB_OP: {node.param1=RGB_OP_SCREEN;} break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc.
+		case NODE_XFORM_MULT: {} break; // mat4 x mat4
+		case NODE_XFORM_VEC_MULT: {} break; // mat4 x vec3 mult (with no-translation option)
+		case NODE_XFORM_VEC_INV_MULT: {} break; // mat4 x vec3 inverse mult (with no-translation option)
+		case NODE_SCALAR_FUNC: {node.param1=SCALAR_FUNC_SIN;} break; // scalar function (sin: {} break; cos: {} break; etc)
+		case NODE_VEC_FUNC: {node.param1=VEC_FUNC_NORMALIZE;} break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc)
+		case NODE_VEC_LEN: {} break; // vec3 length
+		case NODE_DOT_PROD: {} break; // vec3 . vec3 (dot product -> scalar output)
+		case NODE_VEC_TO_SCALAR: {} break; // 1 vec3 input: {} break; 3 scalar outputs
+		case NODE_SCALAR_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
+		case NODE_VEC_TO_XFORM: {} break; // 3 scalar input: {} break; 1 vec3 output
+		case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output
+		case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve)
+		case NODE_VEC_INTERP: {} break; // vec3 interpolation  (with optional curve)
+		case NODE_SCALAR_INPUT: {node.param1=_find_unique_name(p_type,"Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
+		case NODE_VEC_INPUT: {node.param1=_find_unique_name(p_type,"Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
+		case NODE_RGB_INPUT: {node.param1=_find_unique_name(p_type,"Color");node.param2=Color();} break; // color uniform (assignable in material)
+		case NODE_XFORM_INPUT: {node.param1=_find_unique_name(p_type,"XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
+		case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name(p_type,"Tex"); } break; // texture input (assignable in material)
+		case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name(p_type,"Cube"); } break; // cubemap input (assignable in material)
+		case NODE_OUTPUT: {} break; // output (shader type dependent)
+		case NODE_COMMENT: {} break; // comment
+		case NODE_TYPE_MAX: {};
+	}
 
+	shader[p_type].node_map[p_id]=node;
+	_request_update();
 }
 
-void ShaderGraph::node_set_pos(int p_id, const Vector2& p_pos) {
+void ShaderGraph::node_set_pos(ShaderType p_type,int p_id, const Vector2& p_pos) {
+	ERR_FAIL_INDEX(p_type,3);
+
+	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+	shader[p_type].node_map[p_id].pos=p_pos;
+	_request_update();
 
-	ERR_FAIL_COND(!node_map.has(p_id));
-	node_map[p_id].x=p_pos.x;
-	node_map[p_id].y=p_pos.y;
 }
-Vector2 ShaderGraph::node_get_pos(int p_id) const {
+Vector2 ShaderGraph::node_get_pos(ShaderType p_type,int p_id) const {
+	ERR_FAIL_INDEX_V(p_type,3,Vector2());
 
-	ERR_FAIL_COND_V(!node_map.has(p_id),Vector2());
-	return Vector2(node_map[p_id].x,node_map[p_id].y);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector2());
+	return shader[p_type].node_map[p_id].pos;
 }
 
 
-void ShaderGraph::node_remove(int p_id) {
+void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
+
+	ERR_FAIL_COND(p_id==0);
+	ERR_FAIL_INDEX(p_type,3);
 
-	ERR_FAIL_COND(!node_map.has(p_id));
+	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 
 	//erase connections associated with node
-	List<Connection>::Element *N,*E=connections.front();
-	while(E) {
-		N=E->next();
-		const Connection &c = E->get();
-		if (c.src_id==p_id || c.dst_id==p_id) {
+	for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+		if (E->key()==p_id)
+			continue; //no self
 
-			connections.erase(E);
-		}
-		E=N;
-	}
+		for (Map<int,SourceSlot>::Element *F=E->get().connections.front();F;) {
+			Map<int,SourceSlot>::Element *N=F->next();
 
-	node_map.erase(p_id);
-}
+			if (F->get().id==p_id) {
+				E->get().connections.erase(F);
+			}
 
-void ShaderGraph::node_change_type(int p_id, NodeType p_type) {
+			F=N;
+		}
+	}
 
-	ERR_FAIL_COND(!node_map.has(p_id));
-	node_map[p_id].type=p_type;
-	node_map[p_id].param=Variant();
+	shader[p_type].node_map.erase(p_id);
+	print_line("erased node, amount left: "+itos(shader[p_type].node_map.size()));
+	_request_update();
 
 }
 
-void ShaderGraph::node_set_param(int p_id, const Variant& p_value) {
 
-	ERR_FAIL_COND(!node_map.has(p_id));
-	node_map[p_id].param=p_value;
-}
 
-void ShaderGraph::get_node_list(List<int> *p_node_list) const {
+void ShaderGraph::get_node_list(ShaderType p_type,List<int> *p_node_list) const {
+
+	ERR_FAIL_INDEX(p_type,3);
 
-	Map<int,Node>::Element *E = node_map.front();
+	Map<int,Node>::Element *E = shader[p_type].node_map.front();
 
 	while(E) {
 
@@ -288,740 +500,1275 @@ void ShaderGraph::get_node_list(List<int> *p_node_list) const {
 }
 
 
-ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const {
+ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const {
 
-	ERR_FAIL_COND_V(!node_map.has(p_id),NODE_TYPE_MAX);
-	return node_map[p_id].type;
-}
+	ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX);
 
-Variant ShaderGraph::node_get_param(int p_id) const {
-
-	ERR_FAIL_COND_V(!node_map.has(p_id),Variant());
-	return node_map[p_id].param;
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),NODE_TYPE_MAX);
+	return shader[p_type].node_map[p_id].type;
 }
 
 
-Error ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+Error ShaderGraph::connect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+	ERR_FAIL_INDEX_V(p_type,3,ERR_INVALID_PARAMETER);
 
 	ERR_FAIL_COND_V(p_src_id==p_dst_id, ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(!node_map.has(p_src_id), ERR_INVALID_PARAMETER);
-	ERR_FAIL_COND_V(!node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
-	NodeType type_src=node_map[p_src_id].type;
-	NodeType type_dst=node_map[p_dst_id].type;
-	//ERR_FAIL_INDEX_V( p_src_slot, VisualServer::shader_get_output_count(type_src), ERR_INVALID_PARAMETER );
-	//ERR_FAIL_INDEX_V( p_dst_slot, VisualServer::shader_get_input_count(type_dst), ERR_INVALID_PARAMETER );
-	//ERR_FAIL_COND_V(VisualServer::shader_is_output_vector(type_src,p_src_slot) != VisualServer::shader_is_input_vector(type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER);
+	NodeType type_src=shader[p_type].node_map[p_src_id].type;
+	NodeType type_dst=shader[p_type].node_map[p_dst_id].type;
+	ERR_FAIL_INDEX_V( p_src_slot, get_node_output_slot_count(get_mode(),p_type,type_src), ERR_INVALID_PARAMETER );
+	ERR_FAIL_INDEX_V( p_dst_slot, get_node_input_slot_count(get_mode(),p_type,type_dst), ERR_INVALID_PARAMETER );
+	ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(),p_type,type_src,p_src_slot) != get_node_input_slot_type(get_mode(),p_type,type_dst,p_dst_slot), ERR_INVALID_PARAMETER );
 
 
-	List<Connection>::Element *E=connections.front();
-	while(E) {
-		const Connection &c = E->get();
-		ERR_FAIL_COND_V(c.dst_slot==p_dst_slot && c.dst_id == p_dst_id, ERR_ALREADY_EXISTS);
+	SourceSlot ts;
+	ts.id=p_src_id;
+	ts.slot=p_src_slot;
+	shader[p_type].node_map[p_dst_id].connections[p_dst_slot]=ts;
+	_request_update();
 
-		E=E->next();
-	}
+	return OK;
+}
 
-	Connection c;
-	c.src_slot=p_src_slot;
-	c.src_id=p_src_id;
-	c.dst_slot=p_dst_slot;
-	c.dst_id=p_dst_id;
+bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
 
-	connections.push_back(c);
+	ERR_FAIL_INDEX_V(p_type,3,false);
 
-	return OK;
+	SourceSlot ts;
+	ts.id=p_src_id;
+	ts.slot=p_src_slot;
+	return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
+		shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts;
 }
 
-bool ShaderGraph::is_connected(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const {
+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);
 
-	const List<Connection>::Element *E=connections.front();
-	while(E) {
-		const Connection &c = E->get();
-		if (c.dst_slot==p_dst_slot && c.dst_id == p_dst_id && c.src_slot==p_src_slot && c.src_id == p_src_id)
-			return true;
+	print_line("** dsisconnect");
+	SourceSlot ts;
+	ts.id=p_src_id;
+	ts.slot=p_src_slot;
+	if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) &&
+		shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts) {
+		shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot);
 
-		E=E->next();
 	}
+	_request_update();
 
-	return false;
 }
 
-void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_connections) const {
 
-	List<Connection>::Element *N,*E=connections.front();
-	while(E) {
-		N=E->next();
-		const Connection &c = E->get();
-		if (c.src_slot==p_src_slot && c.src_id==p_src_id && c.dst_slot==p_dst_slot && c.dst_id == p_dst_id) {
+	ERR_FAIL_INDEX(p_type,3);
 
-			connections.erase(E);
+	for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+		for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+			Connection c;
+			c.dst_id=E->key();
+			c.dst_slot=F->key();
+			c.src_id=F->get().id;
+			c.src_slot=F->get().slot;
+			p_connections->push_back(c);
 		}
-		E=N;
 	}
+}
+
+
+void ShaderGraph::clear(ShaderType p_type) {
 
+	ERR_FAIL_INDEX(p_type,3);
+	shader[p_type].node_map.clear();
+	Node out;
+	out.pos=Vector2(300,300);
+	out.type=NODE_OUTPUT;
+	shader[p_type].node_map.insert(0,out);
+
+	_request_update();
 
 }
 
-void ShaderGraph::get_connections(List<Connection> *p_connections) const {
 
-	const List<Connection>::Element*E=connections.front();
-	while(E) {
-		p_connections->push_back(E->get());
-		E=E->next();
-	}
+void ShaderGraph::scalar_const_node_set_value(ShaderType p_type,int p_id,float p_value) {
 
+	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_SCALAR_CONST);
+	n.param1=p_value;
+	_request_update();
 
 }
 
+float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int 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_SCALAR_CONST,0);
+	return n.param1;
+}
+
+void ShaderGraph::vec_const_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
+
+	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_VEC_CONST);
+	n.param1=p_value;
+	_request_update();
 
-void ShaderGraph::clear() {
 
-	connections.clear();
-	node_map.clear();
 }
+Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type,int p_id) const{
 
+	ERR_FAIL_INDEX_V(p_type,3,Vector3());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_VEC_CONST,Vector3());
+	return n.param1;
 
-#if 0
-void ShaderGraph::node_add(NodeType p_type,int p_id) {
+}
+
+void ShaderGraph::rgb_const_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
+
+	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_CONST);
+	n.param1=p_value;
+	_request_update();
+
+}
+Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Color());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_RGB_CONST,Color());
+	return n.param1;
 
-	ShaderNode sn;
-	sn.type=p_type;
-	nodes[p_id]=sn;
-	version++;
 }
-void ShaderGraph::node_remove(int p_id) {
 
-	nodes.erase(p_id);
+void ShaderGraph::xform_const_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
+
+	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_XFORM_CONST);
+	n.param1=p_value;
+	_request_update();
 
 }
-void ShaderGraph::node_set_param( int p_id, const Variant& p_value) {
+Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Transform());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_XFORM_CONST,Transform());
+	return n.param1;
 
-	VisualServer::get_singleton()->shader_node_set_param(shader,p_id,p_value);
-	version++;
 }
 
-void ShaderGraph::get_node_list(List<int> *p_node_list) const {
+void ShaderGraph::texture_node_set_filter_size(ShaderType p_type,int p_id,int p_size){
+
+	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_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
+	Array arr = n.param2;
+	arr[0]=p_size;
+	n.param2=arr;
+	_request_update();
 
-	VisualServer::get_singleton()->shader_get_node_list(shader,p_node_list);
 }
-ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const {
+int ShaderGraph::texture_node_get_filter_size(ShaderType p_type,int 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_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
+	Array arr = n.param2;
+	return arr[0];
 
-	return (NodeType)VisualServer::get_singleton()->shader_node_get_type(shader,p_id);
 }
-Variant ShaderGraph::node_get_param(int p_id) const {
 
-	return VisualServer::get_singleton()->shader_node_get_param(shader,p_id);
+void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type,float p_id,float p_strength){
+
+	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_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX);
+	Array arr = n.param2;
+	arr[1]=p_strength;
+	n.param2=arr;
+	_request_update();
+
+}
+float ShaderGraph::texture_node_get_filter_strength(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_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0);
+	Array arr = n.param2;
+	return arr[1];
 }
 
-void ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
 
-	VisualServer::get_singleton()->shader_connect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot);
-	version++;
+void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp 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_SCALAR_OP);
+	n.param1=p_op;
+	_request_update();
+
 }
-void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
+ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type,float p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_OP);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_OP);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_SCALAR_OP,SCALAR_MAX_OP);
+	int op = n.param1;
+	return ScalarOp(op);
 
-	VisualServer::get_singleton()->shader_disconnect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot);
-	version++;
 }
 
-void ShaderGraph::get_connections(List<Connection> *p_connections) const {
 
-	List<VS::ShaderGraphConnection> connections;
-	VisualServer::get_singleton()->shader_get_connections(shader,&connections);
-	for( List<VS::ShaderGraphConnection>::Element *E=connections.front();E;E=E->next()) {
+void ShaderGraph::vec_op_node_set_op(ShaderType p_type,float p_id,VecOp 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_VEC_OP);
+	n.param1=p_op;
+	_request_update();
 
-		Connection c;
-		c.src_id=E->get().src_id;
-		c.src_slot=E->get().src_slot;
-		c.dst_id=E->get().dst_id;
-		c.dst_slot=E->get().dst_slot;
-		p_connections->push_back(c);
-	}
 }
+ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type,float p_id) const{
 
-void ShaderGraph::node_set_pos(int p_id,const Point2& p_pos) {
+	ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_OP);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_OP);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_VEC_OP,VEC_MAX_OP);
+	int op = n.param1;
+	return VecOp(op);
 
-#ifdef TOOLS_ENABLED
-	ERR_FAIL_COND(!positions.has(p_id));
-	positions[p_id]=p_pos;
-#endif
 }
 
-Point2 ShaderGraph::node_get_pos(int p_id) const {
-#ifdef TOOLS_ENABLED
-	ERR_FAIL_COND_V(!positions.has(p_id),Point2());
-	return positions[p_id];
-#endif
+
+void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type,float p_id,VecScalarOp 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_VEC_SCALAR_OP);
+	n.param1=p_op;
+	_request_update();
+
 }
+ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type,float p_id) const{
 
-void ShaderGraph::clear() {
+	ERR_FAIL_INDEX_V(p_type,3,VEC_SCALAR_MAX_OP);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_SCALAR_MAX_OP);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_VEC_SCALAR_OP,VEC_SCALAR_MAX_OP);
+	int op = n.param1;
+	return VecScalarOp(op);
 
-	VisualServer::get_singleton()->shader_clear(shader);
-	version++;
 }
-#endif
 
-ShaderGraph::ShaderGraph() {
+void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op,float p_c){
+
+	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();
 
-	//shader = VisualServer::get_singleton()->shader_create();
-	version = 1;
 }
+ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id) const{
 
-ShaderGraph::~ShaderGraph() {
+	ERR_FAIL_INDEX_V(p_type,3,RGB_MAX_OP);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),RGB_MAX_OP);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,RGB_MAX_OP);
+	int op = n.param1;
+	return RGBOp(op);
 
-	//VisualServer::get_singleton()->free(shader);
 }
+float ShaderGraph::rgb_op_node_get_c(ShaderType p_type,float p_id) const{
 
-#if 0
-void ShaderGraph::shader_get_default_input_nodes(Mode p_type,List<PropertyInfo> *p_inputs) {
-
-	switch(p_type) {
-
-		case SHADER_VERTEX: {
-
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
-			p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
-		} break;
-		case SHADER_FRAGMENT: {
-
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"position") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
-			p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
-
-		} break;
-		case SHADER_POST_PROCESS: {
-			p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
-			p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
-		} break;
+	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){
+
+	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_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT);
+	n.param1=p_no_translation;
+	_request_update();
 
 }
-void ShaderGraph::shader_get_default_output_nodes(ShaderGraphType p_type,List<PropertyInfo> *p_outputs) {
+bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type,int p_id) const{
 
-	switch(p_type) {
+	ERR_FAIL_INDEX_V(p_type,3,false);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),false);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT,false);
+	return n.param1;
 
-		case SHADER_VERTEX: {
+}
 
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
-		} break;
-		case SHADER_FRAGMENT: {
+void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,ScalarFunc p_func){
 
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"diffuse") );
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"specular") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"emission") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"spec_exp") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"glow") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha_discard") );
+	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_SCALAR_FUNC);
+	n.param1=p_func;
+	_request_update();
 
-		} break;
-		case SHADER_POST_PROCESS: {
-			p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") );
-			p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") );
-		} break;
+}
+ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_FUNC);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_FUNC);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_SCALAR_FUNC,SCALAR_MAX_FUNC);
+	int func = n.param1;
+	return ScalarFunc(func);
+}
 
-	}
+void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
+
+	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_VEC_FUNC);
+	n.param1=p_func;
+
+	_request_update();
+
+}
+ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_FUNC);
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_FUNC);
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_VEC_FUNC,VEC_MAX_FUNC);
+	int func = n.param1;
+	return VecFunc(func);
+}
+
+void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){
+
+	ERR_FAIL_INDEX(p_type,3);
+	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+	ERR_FAIL_COND(!p_name.is_valid_identifier());
+	Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT);
+	n.param1="";
+	n.param1=_find_unique_name(p_type,p_name);
+	_request_update();
+
+}
+String ShaderGraph::input_node_get_name(ShaderType p_type,int p_id){
+
+	ERR_FAIL_INDEX_V(p_type,3,String());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT,String());
+	return n.param1;
+}
+
+
+void ShaderGraph::scalar_input_node_set_value(ShaderType p_type,int p_id,float p_value) {
+
+	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_SCALAR_INPUT);
+	n.param2=p_value;
+	_request_update();
 
 }
 
+float ShaderGraph::scalar_input_node_get_value(ShaderType p_type,int p_id) const{
 
-PropertyInfo ShaderGraph::shader_node_get_type_info(NodeType p_type) {
-
-	switch(p_type) {
-
-		case NODE_IN: return PropertyInfo(Variant::STRING,"in");
-		case NODE_OUT: return PropertyInfo(Variant::STRING,"out");
-		case NODE_CONSTANT: return PropertyInfo(Variant::REAL,"const");
-		case NODE_PARAMETER: return PropertyInfo(Variant::STRING,"param");
-		case NODE_ADD: return PropertyInfo(Variant::NIL,"add");
-		case NODE_SUB: return PropertyInfo(Variant::NIL,"sub");
-		case NODE_MUL: return PropertyInfo(Variant::NIL,"mul");
-		case NODE_DIV: return PropertyInfo(Variant::NIL,"div");
-		case NODE_MOD: return PropertyInfo(Variant::NIL,"rem");
-		case NODE_SIN: return PropertyInfo(Variant::NIL,"sin");
-		case NODE_COS: return PropertyInfo(Variant::NIL,"cos");
-		case NODE_TAN: return PropertyInfo(Variant::NIL,"tan");
-		case NODE_ARCSIN: return PropertyInfo(Variant::NIL,"arcsin");
-		case NODE_ARCCOS: return PropertyInfo(Variant::NIL,"arccos");
-		case NODE_ARCTAN: return PropertyInfo(Variant::NIL,"arctan");
-		case NODE_POW: return PropertyInfo(Variant::NIL,"pow");
-		case NODE_LOG: return PropertyInfo(Variant::NIL,"log");
-		case NODE_MAX: return PropertyInfo(Variant::NIL,"max");
-		case NODE_MIN: return PropertyInfo(Variant::NIL,"min");
-		case NODE_COMPARE: return PropertyInfo(Variant::NIL,"cmp");
-		case NODE_TEXTURE: return PropertyInfo(Variant::_RID,"texture1D",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
-		case NODE_TIME: return PropertyInfo(Variant::NIL,"time");
-		case NODE_NOISE: return PropertyInfo(Variant::NIL,"noise");
-		case NODE_PASS: return PropertyInfo(Variant::NIL,"pass");
-		case NODE_VEC_IN: return PropertyInfo(Variant::STRING,"vin");
-		case NODE_VEC_OUT: return PropertyInfo(Variant::STRING,"vout");
-		case NODE_VEC_CONSTANT: return PropertyInfo(Variant::VECTOR3,"vconst");
-		case NODE_VEC_PARAMETER: return PropertyInfo(Variant::STRING,"vparam");
-		case NODE_VEC_ADD: return PropertyInfo(Variant::NIL,"vadd");
-		case NODE_VEC_SUB: return PropertyInfo(Variant::NIL,"vsub");
-		case NODE_VEC_MUL: return PropertyInfo(Variant::NIL,"vmul");
-		case NODE_VEC_DIV: return PropertyInfo(Variant::NIL,"vdiv");
-		case NODE_VEC_MOD: return PropertyInfo(Variant::NIL,"vrem");
-		case NODE_VEC_CROSS: return PropertyInfo(Variant::NIL,"cross");
-		case NODE_VEC_DOT: return PropertyInfo(Variant::NIL,"dot");
-		case NODE_VEC_POW: return PropertyInfo(Variant::NIL,"vpow");
-		case NODE_VEC_NORMALIZE: return PropertyInfo(Variant::NIL,"normalize");
-		case NODE_VEC_INTERPOLATE: return PropertyInfo(Variant::NIL,"mix");
-		case NODE_VEC_SCREEN_TO_UV: return PropertyInfo(Variant::NIL,"scrn2uv");
-		case NODE_VEC_TRANSFORM3: return PropertyInfo(Variant::NIL,"xform3");
-		case NODE_VEC_TRANSFORM4: return PropertyInfo(Variant::NIL,"xform4");
-		case NODE_VEC_COMPARE: return PropertyInfo(Variant::_RID,"vcmp",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
-		case NODE_VEC_TEXTURE_2D: return PropertyInfo(Variant::_RID,"texture2D",PROPERTY_HINT_RESOURCE_TYPE,"Texture");
-		case NODE_VEC_TEXTURE_CUBE: return PropertyInfo(Variant::NIL,"texcube");
-		case NODE_VEC_NOISE:	return PropertyInfo(Variant::NIL,"vec_noise");
-		case NODE_VEC_0: return PropertyInfo(Variant::NIL,"vec_0");
-		case NODE_VEC_1: return PropertyInfo(Variant::NIL,"vec_1");
-		case NODE_VEC_2: return PropertyInfo(Variant::NIL,"vec_2");
-		case NODE_VEC_BUILD: return PropertyInfo(Variant::NIL,"vbuild");
-		case NODE_VEC_PASS: return PropertyInfo(Variant::NIL,"vpass");
-		case NODE_COLOR_CONSTANT: return PropertyInfo(Variant::COLOR,"color_const");
-		case NODE_COLOR_PARAMETER: return PropertyInfo(Variant::STRING,"color_param");
-		case NODE_TEXTURE_PARAMETER:  return PropertyInfo(Variant::STRING,"tex1D_param");
-		case NODE_TEXTURE_2D_PARAMETER:  return PropertyInfo(Variant::STRING,"tex2D_param");
-		case NODE_TEXTURE_CUBE_PARAMETER:  return PropertyInfo(Variant::STRING,"texcube_param");
-		case NODE_TRANSFORM_CONSTANT:  return PropertyInfo(Variant::TRANSFORM,"xform_const");
-		case NODE_TRANSFORM_PARAMETER: return PropertyInfo(Variant::STRING,"xform_param");
-		case NODE_LABEL: return PropertyInfo(Variant::STRING,"label");
-
-		default: {}
+	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_SCALAR_INPUT,0);
+
+	return n.param2;
+}
+
+void ShaderGraph::vec_input_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){
+
+	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_VEC_INPUT);
+
+	n.param2=p_value;
+	_request_update();
+
+}
+Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Vector3());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_VEC_INPUT,Vector3());
+	return n.param2;
+}
+
+void ShaderGraph::rgb_input_node_set_value(ShaderType p_type,int p_id,const Color& p_value){
+
+	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_INPUT);
+	n.param2=p_value;
+	_request_update();
+
+}
+Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Color());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_RGB_INPUT,Color());
+	return n.param2;
+}
+
+void ShaderGraph::xform_input_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){
+
+	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_XFORM_INPUT);
+	n.param2=p_value;
+	_request_update();
+
+}
+Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Transform());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_XFORM_INPUT,Transform());
+	return n.param2;
+}
+
+
+void ShaderGraph::texture_input_node_set_value(ShaderType p_type,int p_id,const Ref<Texture>& p_texture) {
+
+	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_TEXTURE_INPUT);
+	n.param2=p_texture;
+	_request_update();
+
+}
 
+Ref<Texture> ShaderGraph::texture_input_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Ref<Texture>());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<Texture>());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT,Ref<Texture>());
+	return n.param2;
+}
+
+void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type,int p_id,const Ref<CubeMap>& p_cubemap){
+
+	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_CUBEMAP_INPUT);
+	n.param2=p_cubemap;
+	_request_update();
+
+}
+
+Ref<CubeMap> ShaderGraph::cubemap_input_node_get_value(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,Ref<CubeMap>());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<CubeMap>());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_CUBEMAP_INPUT,Ref<CubeMap>());
+	return n.param2;
+
+}
+
+
+void ShaderGraph::comment_node_set_text(ShaderType p_type,int p_id,const String& p_comment) {
+
+	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_COMMENT);
+	n.param1=p_comment;
+
+}
+
+String ShaderGraph::comment_node_get_text(ShaderType p_type,int p_id) const{
+
+	ERR_FAIL_INDEX_V(p_type,3,String());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String());
+	const Node& n = shader[p_type].node_map[p_id];
+	ERR_FAIL_COND_V(n.type!=NODE_COMMENT,String());
+	return n.param1;
+
+}
+
+void ShaderGraph::_request_update() {
+
+	if (_pending_update_shader)
+		return;
+
+	_pending_update_shader=true;
+	call_deferred("_update_shader");
+
+}
+
+Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
+
+	ERR_FAIL_INDEX_V(p_type,3,Variant());
+	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Variant());
+	const Node& n = shader[p_type].node_map[p_id];
+	Dictionary s;
+	s["pos"]=n.pos;
+	s["param1"]=n.param1;
+	s["param2"]=n.param2;
+	return s;
+
+}
+void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_state) {
+
+	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];
+	Dictionary d = p_state;
+	ERR_FAIL_COND(!d.has("pos"));
+	ERR_FAIL_COND(!d.has("param1"));
+	ERR_FAIL_COND(!d.has("param2"));
+	n.pos=d["pos"];
+	n.param1=d["param1"];
+	n.param2=d["param2"];
+
+}
+
+ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
+
+	//shader = VisualServer::get_singleton()->shader_create();
+	_pending_update_shader=false;
+	Node out;
+	out.id=0;
+	out.pos=Vector2(250,20);
+	out.type=NODE_OUTPUT;
+	for(int i=0;i<3;i++) {
+
+		shader[i].node_map.insert(0,out);
 	}
+}
 
-	ERR_FAIL_V( PropertyInfo(Variant::NIL,"error") );
-}
-int ShaderGraph::shader_get_input_count(NodeType p_type) {
-
-	switch(p_type) {
-		case NODE_IN: return 0;
-		case NODE_OUT: return 1;
-		case NODE_CONSTANT: return 0;
-		case NODE_PARAMETER: return 0;
-		case NODE_ADD: return 2;
-		case NODE_SUB: return 2;
-		case NODE_MUL: return 2;
-		case NODE_DIV: return 2;
-		case NODE_MOD: return 2;
-		case NODE_SIN: return 1;
-		case NODE_COS: return 1;
-		case NODE_TAN: return 1;
-		case NODE_ARCSIN: return 1;
-		case NODE_ARCCOS: return 1;
-		case NODE_ARCTAN: return 1;
-		case NODE_POW: return 2;
-		case NODE_LOG: return 1;
-		case NODE_MAX: return 2;
-		case NODE_MIN: return 2;
-		case NODE_COMPARE: return 4;
-		case NODE_TEXTURE: return 1;  ///< param  0: texture
-		case NODE_TIME: return 1;  ///< param  0: interval length
-		case NODE_NOISE: return 0;
-		case NODE_PASS: return 1;
-		case NODE_VEC_IN: return 0;  ///< param 0: name
-		case NODE_VEC_OUT: return 1;  ///< param 0: name
-		case NODE_VEC_CONSTANT: return 0;  ///< param  0: value
-		case NODE_VEC_PARAMETER: return 0;  ///< param  0: name
-		case NODE_VEC_ADD: return 2;
-		case NODE_VEC_SUB: return 2;
-		case NODE_VEC_MUL: return 2;
-		case NODE_VEC_DIV: return 2;
-		case NODE_VEC_MOD: return 2;
-		case NODE_VEC_CROSS: return 2;
-		case NODE_VEC_DOT: return 2;
-		case NODE_VEC_POW: return 2;
-		case NODE_VEC_NORMALIZE: return 1;
-		case NODE_VEC_INTERPOLATE: return 3;
-		case NODE_VEC_SCREEN_TO_UV: return 1;
-		case NODE_VEC_TRANSFORM3: return 4;
-		case NODE_VEC_TRANSFORM4: return 5;
-		case NODE_VEC_COMPARE: return 4;
-		case NODE_VEC_TEXTURE_2D: return 1;
-		case NODE_VEC_TEXTURE_CUBE: return 1;
-		case NODE_VEC_NOISE: return 0;
-		case NODE_VEC_0: return 1;
-		case NODE_VEC_1: return 1;
-		case NODE_VEC_2: return 1;
-		case NODE_VEC_BUILD: return 3;
-		case NODE_VEC_PASS: return 1;
-		case NODE_COLOR_CONSTANT: return 0;
-		case NODE_COLOR_PARAMETER: return 0;
-		case NODE_TEXTURE_PARAMETER:  return 1;
-		case NODE_TEXTURE_2D_PARAMETER:  return 1;
-		case NODE_TEXTURE_CUBE_PARAMETER:  return 1;
-		case NODE_TRANSFORM_CONSTANT: return 1;
-		case NODE_TRANSFORM_PARAMETER: return 1;
-		case NODE_LABEL: return 0;
-		default: {}
+ShaderGraph::~ShaderGraph() {
+
+	//VisualServer::get_singleton()->free(shader);
+}
+
+
+const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
+	//material vertex in
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","SRC_VERTEX",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","SRC_NORMAL",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","SRC_TANGENT",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"BinormalF","SRC_BINORMALF",SLOT_TYPE_SCALAR,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX",SLOT_TYPE_XFORM,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"InvCameraMatrix","INV_CAMERA_MATRIX",SLOT_TYPE_XFORM,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX",SLOT_TYPE_XFORM,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"ModelviewMatrix","MODELVIEW_MATRIX",SLOT_TYPE_XFORM,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"InstanceID","INSTANCE_ID",SLOT_TYPE_SCALAR,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Time","TIME",SLOT_TYPE_SCALAR,SLOT_IN},
+	//material vertex out
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","VERTEX",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","NORMAL",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","TANGENT",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Binormal","BINORMAL",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","UV",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","COLOR.rgb",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","COLOR.a",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"SpecExp","SPEC_EXP",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{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,"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},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","UV",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","UV2",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","SCREEN_UV",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a",SLOT_TYPE_SCALAR,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"InvCameraMatrix","INV_CAMERA_MATRIX",SLOT_TYPE_XFORM,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Time","TIME",SLOT_TYPE_SCALAR,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb",SLOT_TYPE_VEC,SLOT_IN},
+	//pixel vertex out
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPECULAR",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","NORMAL",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH",SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Discard","DISCARD",SLOT_TYPE_SCALAR,SLOT_OUT},
+	//end
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
+
+};
+
+void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType  p_type, List<SlotInfo> *r_slots) {
+
+	const InOutParamInfo* iop = &inout_param_info[0];
+	while(iop->name) {
+		if (p_mode==iop->shader_mode && p_type==iop->shader_type) {
+
+			SlotInfo si;
+			si.dir=iop->dir;
+			si.name=iop->name;
+			si.type=iop->slot_type;
+			r_slots->push_back(si);
+		}
+		iop++;
 	}
-	ERR_FAIL_V( 0 );
-}
-int ShaderGraph::shader_get_output_count(NodeType p_type) {
-
-	switch(p_type) {
-		case NODE_IN: return 1;
-		case NODE_OUT: return 0;
-		case NODE_CONSTANT: return 1;
-		case NODE_PARAMETER: return 1;
-		case NODE_ADD: return 1;
-		case NODE_SUB: return 1;
-		case NODE_MUL: return 1;
-		case NODE_DIV: return 1;
-		case NODE_MOD: return 1;
-		case NODE_SIN: return 1;
-		case NODE_COS: return 1;
-		case NODE_TAN: return 1;
-		case NODE_ARCSIN: return 1;
-		case NODE_ARCCOS: return 1;
-		case NODE_ARCTAN: return 1;
-		case NODE_POW: return 1;
-		case NODE_LOG: return 1;
-		case NODE_MAX: return 1;
-		case NODE_MIN: return 1;
-		case NODE_COMPARE: return 2;
-		case NODE_TEXTURE: return 3;  ///< param  0: texture
-		case NODE_TIME: return 1;  ///< param  0: interval length
-		case NODE_NOISE: return 1;
-		case NODE_PASS: return 1;
-		case NODE_VEC_IN: return 1;  ///< param 0: name
-		case NODE_VEC_OUT: return 0;  ///< param 0: name
-		case NODE_VEC_CONSTANT: return 1;  ///< param  0: value
-		case NODE_VEC_PARAMETER: return 1;  ///< param  0: name
-		case NODE_VEC_ADD: return 1;
-		case NODE_VEC_SUB: return 1;
-		case NODE_VEC_MUL: return 1;
-		case NODE_VEC_DIV: return 1;
-		case NODE_VEC_MOD: return 1;
-		case NODE_VEC_CROSS: return 1;
-		case NODE_VEC_DOT: return 1;
-		case NODE_VEC_POW: return 1;
-		case NODE_VEC_NORMALIZE: return 1;
-		case NODE_VEC_INTERPOLATE: return 1;
-		case NODE_VEC_SCREEN_TO_UV: return 1;
-		case NODE_VEC_TRANSFORM3: return 1;
-		case NODE_VEC_TRANSFORM4: return 1;
-		case NODE_VEC_COMPARE: return 2;
-		case NODE_VEC_TEXTURE_2D: return 3;
-		case NODE_VEC_TEXTURE_CUBE: return 3;
-		case NODE_VEC_NOISE: return 1;
-		case NODE_VEC_0: return 1;
-		case NODE_VEC_1: return 1;
-		case NODE_VEC_2: return 1;
-		case NODE_VEC_BUILD: return 1;
-		case NODE_VEC_PASS: return 1;
-		case NODE_COLOR_CONSTANT: return 2;
-		case NODE_COLOR_PARAMETER: return 2;
-		case NODE_TEXTURE_PARAMETER:  return 3;
-		case NODE_TEXTURE_2D_PARAMETER:  return 3;
-		case NODE_TEXTURE_CUBE_PARAMETER:  return 3;
-		case NODE_TRANSFORM_CONSTANT: return 1;
-		case NODE_TRANSFORM_PARAMETER: return 1;
-		case NODE_LABEL: return 0;
-
-		default: {}
+}
+
+
+const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
+
+		{NODE_SCALAR_CONST,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, //scalar constant
+		{NODE_VEC_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //vec3 constant
+		{NODE_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //rgb constant (shows a color picker instead)
+		{NODE_XFORM_CONST,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // 4x4 matrix constant
+		{NODE_TIME,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // time in seconds
+		{NODE_SCREEN_TEX,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // screen texture sampler (takes UV) (only usable in fragment shader)
+		{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_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_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
+		{NODE_SCALAR_FUNC,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc)
+		{NODE_VEC_FUNC,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc)
+		{NODE_VEC_LEN,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 length
+		{NODE_DOT_PROD,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 . vec3 (dot product -> scalar output)
+		{NODE_VEC_TO_SCALAR,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR}}, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs
+		{NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output
+		{NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve)
+		{NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation  (with optional curve)
+		{NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material)
+		{NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material)
+		{NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // color uniform (assignable in material)
+		{NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material)
+		{NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material)
+		{NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
+		{NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment
+		{NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}}
+};
+
+int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType  p_shader_type,NodeType p_type) {
+
+	if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+		const InOutParamInfo* iop = &inout_param_info[0];
+		int pc=0;
+		while(iop->name) {
+			if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+				if (iop->dir==SLOT_OUT)
+					pc++;
+			}
+			iop++;
+		}
+		return pc;
+	} else if (p_type==NODE_VEC_TO_XFORM){
+		return 4;
+	} else if (p_type==NODE_XFORM_TO_VEC){
+		return 1;
+	} else {
+
+		const NodeSlotInfo*nsi=&node_slot_info[0];
+		while(nsi->type!=NODE_TYPE_MAX) {
+
+			if (nsi->type==p_type) {
+				int pc=0;
+				for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
+					if (nsi->ins[i]==SLOT_MAX)
+						break;
+					pc++;
+				}
+				return pc;
+			}
+
+			nsi++;
+		}
+
+		return 0;
+
+	}
+}
+
+int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType  p_shader_type,NodeType p_type){
+
+	if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+		const InOutParamInfo* iop = &inout_param_info[0];
+		int pc=0;
+		while(iop->name) {
+			if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+				if (iop->dir==SLOT_IN)
+					pc++;
+			}
+			iop++;
+		}
+		return pc;
+	} else if (p_type==NODE_VEC_TO_XFORM){
+		return 1;
+	} else if (p_type==NODE_XFORM_TO_VEC){
+		return 4;
+	} else {
+
+		const NodeSlotInfo*nsi=&node_slot_info[0];
+		while(nsi->type!=NODE_TYPE_MAX) {
+
+			if (nsi->type==p_type) {
+				int pc=0;
+				for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
+					if (nsi->outs[i]==SLOT_MAX)
+						break;
+					pc++;
+				}
+				return pc;
+			}
+
+			nsi++;
+		}
+
+		return 0;
+
 	}
-	ERR_FAIL_V( 0 );
-
-}
-
-#define RET2(m_a,m_b)	if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else return "";
-#define RET3(m_a,m_b,m_c)	if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c;  else return "";
-#define RET4(m_a,m_b,m_c,m_d)	if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else return "";
-
-#define RET5(m_a,m_b,m_c,m_d,m_e)	if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else if (p_idx==4) return m_e; else return "";
-
-String ShaderGraph::shader_get_input_name(NodeType p_type,int p_idx) {
-
-	switch(p_type) {
-
-		case NODE_IN: return "";
-		case NODE_OUT: return "out";
-		case NODE_CONSTANT: return "";
-		case NODE_PARAMETER: return "";
-		case NODE_ADD: RET2("a","b");
-		case NODE_SUB: RET2("a","b");
-		case NODE_MUL: RET2("a","b");
-		case NODE_DIV: RET2("a","b");
-		case NODE_MOD: RET2("a","b");
-		case NODE_SIN: return "rad";
-		case NODE_COS: return "rad";
-		case NODE_TAN: return "rad";
-		case NODE_ARCSIN: return "in";
-		case NODE_ARCCOS: return "in";
-		case NODE_ARCTAN: return "in";
-		case NODE_POW: RET2("in","exp");
-		case NODE_LOG: return "in";
-		case NODE_MAX: return "in";
-		case NODE_MIN: return "in";
-		case NODE_COMPARE: RET4("a","b","ret1","ret2");
-		case NODE_TEXTURE: return "u";
-		case NODE_TIME: return "";
-		case NODE_NOISE: return "";
-		case NODE_PASS: return "in";
-		case NODE_VEC_IN: return "";
-		case NODE_VEC_OUT: return "out";
-		case NODE_VEC_CONSTANT: return "";
-		case NODE_VEC_PARAMETER: return "";
-		case NODE_VEC_ADD: RET2("a","b");
-		case NODE_VEC_SUB: RET2("a","b");
-		case NODE_VEC_MUL: RET2("a","b");
-		case NODE_VEC_DIV: RET2("a","b");
-		case NODE_VEC_MOD: RET2("a","b");
-		case NODE_VEC_CROSS: RET2("a","b");
-		case NODE_VEC_DOT: RET2("a","b");
-		case NODE_VEC_POW: RET2("a","b");
-		case NODE_VEC_NORMALIZE: return "vec";
-		case NODE_VEC_INTERPOLATE: RET3("a","b","c");
-		case NODE_VEC_SCREEN_TO_UV: return "scr";
-		case NODE_VEC_TRANSFORM3: RET4("in","col0","col1","col2");
-		case NODE_VEC_TRANSFORM4: RET5("in","col0","col1","col2","col3");
-		case NODE_VEC_COMPARE: RET4("a","b","ret1","ret2");
-		case NODE_VEC_TEXTURE_2D: return "uv";
-		case NODE_VEC_TEXTURE_CUBE: return "uvw";
-		case NODE_VEC_NOISE: return "";
-		case NODE_VEC_0: return "vec";
-		case NODE_VEC_1: return "vec";
-		case NODE_VEC_2: return "vec";
-		case NODE_VEC_BUILD: RET3("x/r","y/g","z/b");
-		case NODE_VEC_PASS: return "in";
-		case NODE_COLOR_CONSTANT: return "";
-		case NODE_COLOR_PARAMETER: return "";
-		case NODE_TEXTURE_PARAMETER:  return "u";
-		case NODE_TEXTURE_2D_PARAMETER:  return "uv";
-		case NODE_TEXTURE_CUBE_PARAMETER:  return "uvw";
-		case NODE_TRANSFORM_CONSTANT: return "in";
-		case NODE_TRANSFORM_PARAMETER: return "in";
-		case NODE_LABEL: return "";
-
-		default: {}
+}
+ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType  p_shader_type,NodeType p_type,int p_idx){
+
+	if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+		const InOutParamInfo* iop = &inout_param_info[0];
+		int pc=0;
+		while(iop->name) {
+			if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+				if (iop->dir==SLOT_OUT) {
+					if (pc==p_idx)
+						return iop->slot_type;
+					pc++;
+				}
+			}
+			iop++;
+		}
+		ERR_FAIL_V(SLOT_MAX);
+	} else if (p_type==NODE_VEC_TO_XFORM){
+		return SLOT_TYPE_VEC;
+	} else if (p_type==NODE_XFORM_TO_VEC){
+		return SLOT_TYPE_XFORM;
+	} else {
+
+		const NodeSlotInfo*nsi=&node_slot_info[0];
+		while(nsi->type!=NODE_TYPE_MAX) {
+
+			if (nsi->type==p_type) {
+				for(int i=0;i<NodeSlotInfo::MAX_INS;i++) {
+					if (nsi->ins[i]==SLOT_MAX)
+						break;
+					if (i==p_idx)
+						return nsi->ins[i];
+				}
+			}
+
+			nsi++;
+		}
+
+		ERR_FAIL_V(SLOT_MAX);
+
 	}
+}
+ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType  p_shader_type,NodeType p_type,int p_idx){
+
+	if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) {
+
+		const InOutParamInfo* iop = &inout_param_info[0];
+		int pc=0;
+		while(iop->name) {
+			if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) {
+
+				if (iop->dir==SLOT_IN) {
+					if (pc==p_idx)
+						return iop->slot_type;
+					pc++;
+				}
+			}
+			iop++;
+		}
+		ERR_FAIL_V(SLOT_MAX);
+	} else if (p_type==NODE_VEC_TO_XFORM){
+		return SLOT_TYPE_XFORM;
+	} else if (p_type==NODE_XFORM_TO_VEC){
+		return SLOT_TYPE_VEC;
+	} else {
+
+		const NodeSlotInfo*nsi=&node_slot_info[0];
+		while(nsi->type!=NODE_TYPE_MAX) {
+
+			if (nsi->type==p_type) {
+				for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) {
+					if (nsi->outs[i]==SLOT_MAX)
+						break;
+					if (i==p_idx)
+						return nsi->outs[i];
+				}
+			}
+
+			nsi++;
+		}
 
-	ERR_FAIL_V("");
-}
-String ShaderGraph::shader_get_output_name(NodeType p_type,int p_idx) {
-
-	switch(p_type) {
-
-		case NODE_IN: return "in";
-		case NODE_OUT: return "";
-		case NODE_CONSTANT: return "out";
-		case NODE_PARAMETER: return "out";
-		case NODE_ADD: return "sum";
-		case NODE_SUB: return "dif";
-		case NODE_MUL: return "prod";
-		case NODE_DIV: return "quot";
-		case NODE_MOD: return "rem";
-		case NODE_SIN: return "out";
-		case NODE_COS: return "out";
-		case NODE_TAN: return "out";
-		case NODE_ARCSIN: return "rad";
-		case NODE_ARCCOS: return "rad";
-		case NODE_ARCTAN: return "rad";
-		case NODE_POW: RET2("in","exp");
-		case NODE_LOG: return "out";
-		case NODE_MAX: return "out";
-		case NODE_MIN: return "out";
-		case NODE_COMPARE: RET2("a/b","a/b");
-		case NODE_TEXTURE: RET3("rgb","a","v");
-		case NODE_TIME: return "out";
-		case NODE_NOISE: return "out";
-		case NODE_PASS: return "out";
-		case NODE_VEC_IN: return "in";
-		case NODE_VEC_OUT: return "";
-		case NODE_VEC_CONSTANT: return "out";
-		case NODE_VEC_PARAMETER: return "out";
-		case NODE_VEC_ADD: return "sum";
-		case NODE_VEC_SUB: return "sub";
-		case NODE_VEC_MUL: return "mul";
-		case NODE_VEC_DIV: return "div";
-		case NODE_VEC_MOD: return "rem";
-		case NODE_VEC_CROSS: return "crs";
-		case NODE_VEC_DOT: return "prod";
-		case NODE_VEC_POW: return "out";
-		case NODE_VEC_NORMALIZE: return "norm";
-		case NODE_VEC_INTERPOLATE: return "out";
-		case NODE_VEC_SCREEN_TO_UV: return "uv";
-		case NODE_VEC_TRANSFORM3: return "prod";
-		case NODE_VEC_TRANSFORM4: return "prod";
-		case NODE_VEC_COMPARE: RET2("a/b","a/b");
-		case NODE_VEC_TEXTURE_2D: RET3("rgb","a","v");
-		case NODE_VEC_TEXTURE_CUBE: RET3("rgb","a","v");
-		case NODE_VEC_NOISE: return "out";
-		case NODE_VEC_0: return "x/r";
-		case NODE_VEC_1: return "y/g";
-		case NODE_VEC_2: return "z/b";
-		case NODE_VEC_BUILD: return "vec";
-		case NODE_VEC_PASS: return "out";
-		case NODE_COLOR_CONSTANT: RET2("rgb","a");
-		case NODE_COLOR_PARAMETER: RET2("rgb","a");
-		case NODE_TEXTURE_PARAMETER:  RET3("rgb","a","v");
-		case NODE_TEXTURE_2D_PARAMETER:  RET3("rgb","a","v");
-		case NODE_TEXTURE_CUBE_PARAMETER:  RET3("rgb","a","v");
-		case NODE_TRANSFORM_CONSTANT: return "out";
-		case NODE_TRANSFORM_PARAMETER: return "out";
-		case NODE_LABEL: return "";
-
-		default: {}
+		ERR_FAIL_V(SLOT_MAX);
 	}
+}
+
 
-	ERR_FAIL_V("");
-}
-bool ShaderGraph::shader_is_input_vector(NodeType p_type,int p_input) {
-
-	switch(p_type) {
-
-		case NODE_IN: return false;
-		case NODE_OUT: return false;
-		case NODE_CONSTANT: return false;
-		case NODE_PARAMETER: return false;
-		case NODE_ADD: return false;
-		case NODE_SUB: return false;
-		case NODE_MUL: return false;
-		case NODE_DIV: return false;
-		case NODE_MOD: return false;
-		case NODE_SIN: return false;
-		case NODE_COS: return false;
-		case NODE_TAN: return false;
-		case NODE_ARCSIN: return false;
-		case NODE_ARCCOS: return false;
-		case NODE_ARCTAN: return false;
-		case NODE_POW: return false;
-		case NODE_LOG: return false;
-		case NODE_MAX: return false;
-		case NODE_MIN: return false;
-		case NODE_COMPARE: return false;
-		case NODE_TEXTURE: return false;
-		case NODE_TIME: return false;
-		case NODE_NOISE: return false;
-		case NODE_PASS: return false;
-		case NODE_VEC_IN: return false;
-		case NODE_VEC_OUT: return true;
-		case NODE_VEC_CONSTANT: return false;
-		case NODE_VEC_PARAMETER: return false;
-		case NODE_VEC_ADD: return true;
-		case NODE_VEC_SUB: return true;
-		case NODE_VEC_MUL: return true;
-		case NODE_VEC_DIV: return true;
-		case NODE_VEC_MOD: return true;
-		case NODE_VEC_CROSS: return true;
-		case NODE_VEC_DOT: return true;
-		case NODE_VEC_POW: return (p_input==0)?true:false;
-		case NODE_VEC_NORMALIZE: return true;
-		case NODE_VEC_INTERPOLATE: return (p_input<2)?true:false;
-		case NODE_VEC_SCREEN_TO_UV: return true;
-		case NODE_VEC_TRANSFORM3: return true;
-		case NODE_VEC_TRANSFORM4: return true;
-		case NODE_VEC_COMPARE: return (p_input<2)?false:true;
-		case NODE_VEC_TEXTURE_2D: return true;
-		case NODE_VEC_TEXTURE_CUBE: return true;
-		case NODE_VEC_NOISE: return false;
-		case NODE_VEC_0: return true;
-		case NODE_VEC_1: return true;
-		case NODE_VEC_2: return true;
-		case NODE_VEC_BUILD: return false;
-		case NODE_VEC_PASS: return true;
-		case NODE_COLOR_CONSTANT: return false;
-		case NODE_COLOR_PARAMETER: return false;
-		case NODE_TEXTURE_PARAMETER:  return false;
-		case NODE_TEXTURE_2D_PARAMETER:  return true;
-		case NODE_TEXTURE_CUBE_PARAMETER:  return true;
-		case NODE_TRANSFORM_CONSTANT: return true;
-		case NODE_TRANSFORM_PARAMETER: return true;
-		case NODE_LABEL: return false;
-
-		default: {}
+
+
+
+void ShaderGraph::_update_shader() {
+
+
+	String code[3];
+
+	for(int i=0;i<3;i++) {
+
+		int idx=0;
+		for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+			E->get().sort_order=idx++;
+		}
+		//simple method for graph solving using bubblesort derived algorithm
+		int iters=0;
+		int iter_max=shader[i].node_map.size()*shader[i].node_map.size();
+
+		while(true) {
+			if (iters>iter_max)
+				break;
+
+			int swaps=0;
+			for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+				for(Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+					//this is kinda slow, could be sped up
+					Map<int,Node>::Element *G = shader[i].node_map.find(F->get().id);
+					ERR_FAIL_COND(!G);
+					if (G->get().sort_order > E->get().sort_order) {
+
+						SWAP(G->get().sort_order,E->get().sort_order);
+						swaps++;
+					}
+				}
+			}
+
+			iters++;
+			if (swaps==0) {
+				iters=0;
+				break;
+			}
+		}
+
+		if (iters>0) {
+
+			shader[i].error=GRAPH_ERROR_CYCLIC;
+			continue;
+		}
+
+		Vector<Node*> order;
+		order.resize(shader[i].node_map.size());
+
+		for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) {
+
+			order[E->get().sort_order]=&E->get();
+		}
+
+		//generate code for the ordered graph
+		bool failed=false;
+
+		if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+			code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);";
+			code[i]+="float ALPHA_OUT=0;";
+		}
+
+		Map<String,String> inputs_xlate;
+		Set<String> inputs_used;
+
+		for(int j=0;j<order.size();j++) {
+
+			Node *n=order[j];
+			if (n->type==NODE_INPUT) {
+
+				const InOutParamInfo* iop = &inout_param_info[0];
+				int idx=0;
+				while(iop->name) {
+					if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_IN==iop->dir) {
+
+						const char *typestr[4]={"float","vec3","mat4","texture"};
+
+						String vname=("nd"+itos(n->id)+"sl"+itos(idx));
+						inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n";
+						idx++;
+					}
+					iop++;
+				}
+
+			} else if (n->type==NODE_OUTPUT) {
+
+
+				bool use_alpha=false;
+				const InOutParamInfo* iop = &inout_param_info[0];
+				int idx=0;
+				while(iop->name) {
+					if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_OUT==iop->dir) {
+
+						if (n->connections.has(idx)) {
+							String iname=("nd"+itos(n->connections[idx].id)+"sl"+itos(n->connections[idx].slot));
+							if (node_get_type(ShaderType(i),n->connections[idx].id)==NODE_INPUT)
+								inputs_used.insert(iname);
+							code[i]+=String(iop->variable)+"="+iname+";\n";
+							if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha")
+								use_alpha=true;
+						}
+						idx++;
+					}
+					iop++;
+				}
+
+				if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+
+					if (use_alpha) {
+						code[i]+="DIFFUSE_ALPHA.rgb=DIFFUSE_OUT;\n";
+						code[i]+="DIFFUSE_ALPHA.a=ALPHA_OUT;\n";
+					} else {
+						code[i]+="DIFFUSE=DIFFUSE_OUT;\n";
+					}
+				}
+
+			} else {
+				Vector<String> inputs;
+				int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
+				for(int k=0;k<max;k++) {
+					if (!n->connections.has(k)) {
+						shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS;
+						failed=true;
+						break;
+					}
+					String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
+					inputs.push_back(iname);
+					if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT)
+						inputs_used.insert(iname);
+
+				}
+
+				if (failed)
+					break;
+				_add_node_code(ShaderType(i),n,inputs,code[i]);
+			}
+
+		}
+
+		if (failed)
+			continue;
+
+		for(Set<String>::Element *E=inputs_used.front();E;E=E->next()) {
+
+			ERR_CONTINUE( !inputs_xlate.has(E->get()));
+			code[i]=inputs_xlate[E->get()]+code[i];
+		}
+		shader[i].error=GRAPH_OK;
+		print_line("ShADER: "+code[i]);
 	}
 
-	ERR_FAIL_V(false);
-}
-bool ShaderGraph::shader_is_output_vector(NodeType p_type,int p_input) {
-
-	switch(p_type) {
-
-		case NODE_IN: return false;
-		case NODE_OUT: return false ;
-		case NODE_CONSTANT: return false;
-		case NODE_PARAMETER: return false;
-		case NODE_ADD: return false;
-		case NODE_SUB: return false;
-		case NODE_MUL: return false;
-		case NODE_DIV: return false;
-		case NODE_MOD: return false;
-		case NODE_SIN: return false;
-		case NODE_COS: return false;
-		case NODE_TAN: return false;
-		case NODE_ARCSIN: return false;
-		case NODE_ARCCOS: return false;
-		case NODE_ARCTAN: return false;
-		case NODE_POW: return false;
-		case NODE_LOG: return false;
-		case NODE_MAX: return false;
-		case NODE_MIN: return false;
-		case NODE_COMPARE: return false;
-		case NODE_TEXTURE: return false;
-		case NODE_TIME: return false;
-		case NODE_NOISE: return false;
-		case NODE_PASS: return false;
-		case NODE_VEC_IN: return true;
-		case NODE_VEC_OUT: return false;
-		case NODE_VEC_CONSTANT: return true;
-		case NODE_VEC_PARAMETER: return true;
-		case NODE_VEC_ADD: return true;
-		case NODE_VEC_SUB: return true;
-		case NODE_VEC_MUL: return true;
-		case NODE_VEC_DIV: return true;
-		case NODE_VEC_MOD: return true;
-		case NODE_VEC_CROSS: return true;
-		case NODE_VEC_DOT: return false;
-		case NODE_VEC_POW: return true;
-		case NODE_VEC_NORMALIZE: return true;
-		case NODE_VEC_INTERPOLATE: return true;
-		case NODE_VEC_SCREEN_TO_UV: return true;
-		case NODE_VEC_TRANSFORM3: return true;
-		case NODE_VEC_TRANSFORM4: return true;
-		case NODE_VEC_COMPARE: return true;
-		case NODE_VEC_TEXTURE_2D: return (p_input==0)?true:false;
-		case NODE_VEC_TEXTURE_CUBE: return (p_input==0)?true:false;
-		case NODE_VEC_NOISE: return true;
-		case NODE_VEC_0: return false;
-		case NODE_VEC_1: return false;
-		case NODE_VEC_2: return false;
-		case NODE_VEC_BUILD: return true;
-		case NODE_VEC_PASS: return true;
-		case NODE_COLOR_CONSTANT: return (p_input==0)?true:false;
-		case NODE_COLOR_PARAMETER: return (p_input==0)?true:false;
-		case NODE_TEXTURE_PARAMETER:  return (p_input==0)?true:false;
-		case NODE_TEXTURE_2D_PARAMETER:  return (p_input==0)?true:false;
-		case NODE_TEXTURE_CUBE_PARAMETER:  return (p_input==0)?true:false;
-		case NODE_TRANSFORM_CONSTANT: return true;
-		case NODE_TRANSFORM_PARAMETER: return true;
-		case NODE_LABEL: return false;
-
-		default: {}
+	bool all_ok=true;
+	for(int i=0;i<3;i++) {
+		if (shader[i].error!=GRAPH_OK)
+			all_ok=false;
 	}
 
-	ERR_FAIL_V("");
+	if (all_ok) {
+		set_code(code[0],code[1],code[2]);
+	}
+	//do shader here
+	print_line("UPDATING SHADER");
+	_pending_update_shader=false;
 }
 
-#endif
-#endif
+void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
+
+
+	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)))
+
+	switch(p_node->type) {
+
+		case NODE_INPUT: {
+
+
+		}break;
+		case NODE_SCALAR_CONST: {
+
+			double scalar = p_node->param1;
+			code+=OUTNAME(p_node->id,0)+"="+rtos(scalar)+";\n";
+		}break;
+		case NODE_VEC_CONST: {
+			Vector3 vec = p_node->param1;
+			code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(vec.x)+","+rtos(vec.y)+","+rtos(vec.z)+");\n";
+		}break;
+		case NODE_RGB_CONST: {
+			Color col = p_node->param1;
+			code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";
+		}break;
+		case NODE_XFORM_CONST: {
+
+			Transform xf = p_node->param1;
+			code+=OUTNAME(p_node->id,0)+"=mat4(\n";
+			code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";
+			code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";
+			code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";
+			code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";
+			code+=");";
+
+		}break;
+		case NODE_TIME: {
+			code+=OUTNAME(p_node->id,0)+"=TIME;\n";
+		}break;
+		case NODE_SCREEN_TEX: {
+			code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+");\n";
+		}break;
+		case NODE_SCALAR_OP: {
+			int op = p_node->param1;
+			String optxt;
+			switch(op) {
+
+				case SCALAR_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
+				case SCALAR_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
+				case SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+				case SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+				case SCALAR_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case SCALAR_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case SCALAR_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case SCALAR_OP_ATAN2: optxt = "atan2("+p_inputs[0]+","+p_inputs[1]+");"; break;
+
+			}
+			code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";;
+
+		}break;
+		case NODE_VEC_OP: {
+			int op = p_node->param1;
+			String optxt;
+			switch(op) {
+				case VEC_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break;
+				case VEC_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break;
+				case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+				case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+				case VEC_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case VEC_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case VEC_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break;
+				case VEC_OP_CROSS: optxt = "cross("+p_inputs[0]+","+p_inputs[1]+");"; break;
+			}
+			code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
+
+		}break;
+		case NODE_VEC_SCALAR_OP: {
+			int op = p_node->param1;
+			String optxt;
+			switch(op) {
+				case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+				case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+				case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
+			}
+			code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
+
+		}break;
+		case NODE_RGB_OP: {
+
+
+		}break;
+		case NODE_XFORM_MULT: {
+
+			code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
+
+		}break;
+		case NODE_XFORM_VEC_MULT: {
+
+			bool no_translation = p_node->param1;
+			if (no_translation) {
+				code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*vec4("+p_inputs[1]+",0);\n";
+			} else {
+				code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*vec4("+p_inputs[1]+",1);\n";
+			}
+
+		}break;
+		case NODE_XFORM_VEC_INV_MULT: {
+			bool no_translation = p_node->param1;
+			if (no_translation) {
+				code += OUTNAME(p_node->id,0)+"="+p_inputs[1]+"*vec4("+p_inputs[0]+",0);\n";
+			} else {
+				code += OUTNAME(p_node->id,0)+"="+p_inputs[1]+"*vec4("+p_inputs[0]+",1);\n";
+			}
+		}break;
+		case NODE_SCALAR_FUNC: {
+
+
+		}break;
+		case NODE_VEC_FUNC: {
+
+		}break;
+		case NODE_VEC_LEN: {
+
+			code += OUTNAME(p_node->id,0)+"=length("+p_inputs[1]+");\n";
+
+		}break;
+		case NODE_DOT_PROD: {
+			code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
+
+		}break;
+		case NODE_VEC_TO_SCALAR: {
+			code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
+			code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
+			code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
+
+		}break;
+		case NODE_SCALAR_TO_VEC: {
+			code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
+
+		}break;
+		case NODE_VEC_TO_XFORM: {
+			code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n";
+
+		}break;
+		case NODE_XFORM_TO_VEC: {
+			code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
+			code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
+			code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
+			code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n";
+		}break;
+		case NODE_SCALAR_INTERP: {
+
+			code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
+
+		}break;
+		case NODE_VEC_INTERP: {
+			code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
+
+		}break;
+		case NODE_SCALAR_INPUT: {
+			String name = p_node->param1;
+			float dv=p_node->param2;
+			code +="uniform float "+name+"="+rtos(dv)+";\n";
+			code += OUTNAME(p_node->id,0)+"="+name+";\n";
+		}break;
+		case NODE_VEC_INPUT: {
+
+			String name = p_node->param1;
+			Vector3 dv=p_node->param2;
+			code +="uniform float "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
+			code += OUTNAME(p_node->id,0)+"="+name+";\n";
+		}break;
+		case NODE_RGB_INPUT: {
+
+			String name = p_node->param1;
+			Color dv= p_node->param2;
+
+			code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.g)+","+rtos(dv.a)+");\n";
+			code += OUTNAME(p_node->id,0)+"="+name+".rgb;\n";
+
+		}break;
+		case NODE_XFORM_INPUT: {
+
+			String name = p_node->param1;
+			Transform dv= p_node->param2;
+
+			code +="uniform mat4 "+name+"=mat4(\n";
+			code+="\tvec4(vec3("+rtos(dv.basis.get_axis(0).x)+","+rtos(dv.basis.get_axis(0).y)+","+rtos(dv.basis.get_axis(0).z)+"),0),\n";
+			code+="\tvec4(vec3("+rtos(dv.basis.get_axis(1).x)+","+rtos(dv.basis.get_axis(1).y)+","+rtos(dv.basis.get_axis(1).z)+"),0),\n";
+			code+="\tvec4(vec3("+rtos(dv.basis.get_axis(2).x)+","+rtos(dv.basis.get_axis(2).y)+","+rtos(dv.basis.get_axis(2).z)+"),0),\n";
+			code+="\tvec4(vec3("+rtos(dv.origin.x)+","+rtos(dv.origin.y)+","+rtos(dv.origin.z)+"),1)\n";
+			code+=");";
+
+			code += OUTNAME(p_node->id,0)+"="+name+";\n";
+
+		}break;
+		case NODE_TEXTURE_INPUT: {
+			String name = p_node->param1;
+			String rname="_read_tex"+itos(p_node->id);
+			code +="uniform texture "+name+";";
+			code +="vec4 "+rname+"=tex("+name+","+p_inputs[0]+".xy);\n";
+			code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+			code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
+
+		}break;
+		case NODE_CUBEMAP_INPUT: {
+
+			String name = p_node->param1;
+			code +="uniform cubemap "+name+";";
+			String rname="_read_tex"+itos(p_node->id);
+			code +="vec4 "+rname+"=texcube("+name+","+p_inputs[0]+".xy);\n";
+			code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n";
+			code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
+		}break;
+		case NODE_OUTPUT: {
+
+
+		}break;
+		case NODE_COMMENT: {
+
+		}break;
+		case NODE_TYPE_MAX: {
+
+		}
+	}
+}

+ 306 - 101
scene/resources/shader_graph.h

@@ -29,87 +29,54 @@
 #ifndef SHADER_GRAPH_H
 #define SHADER_GRAPH_H
 
-#if 0
+
 
 #include "map.h"
 #include "scene/resources/shader.h"
 
-class ShaderGraph : public Resource {
+class ShaderGraph : public Shader {
 
-	OBJ_TYPE( ShaderGraph, Resource );
+	OBJ_TYPE( ShaderGraph, Shader );
 	RES_BASE_EXTENSION("sgp");
 
 public:
 
 	enum NodeType {
-		NODE_IN, ///< param 0: name
-		NODE_OUT, ///< param 0: name
-		NODE_CONSTANT, ///< param 0: value
-		NODE_PARAMETER, ///< param 0: name
-		NODE_ADD,
-		NODE_SUB,
-		NODE_MUL,
-		NODE_DIV,
-		NODE_MOD,
-		NODE_SIN,
-		NODE_COS,
-		NODE_TAN,
-		NODE_ARCSIN,
-		NODE_ARCCOS,
-		NODE_ARCTAN,
-		NODE_POW,
-		NODE_LOG,
-		NODE_MAX,
-		NODE_MIN,
-		NODE_COMPARE,
-		NODE_TEXTURE, ///< param  0: texture
-		NODE_TIME, ///< param  0: interval length
-		NODE_NOISE,
-		NODE_PASS,
-		NODE_VEC_IN, ///< param 0: name
-		NODE_VEC_OUT, ///< param 0: name
-		NODE_VEC_CONSTANT, ///< param  0: value
-		NODE_VEC_PARAMETER, ///< param  0: name
-		NODE_VEC_ADD,
-		NODE_VEC_SUB,
-		NODE_VEC_MUL,
-		NODE_VEC_DIV,
-		NODE_VEC_MOD,
-		NODE_VEC_CROSS,
-		NODE_VEC_DOT,
-		NODE_VEC_POW,
-		NODE_VEC_NORMALIZE,
-		NODE_VEC_INTERPOLATE,
-		NODE_VEC_SCREEN_TO_UV,
-		NODE_VEC_TRANSFORM3,
-		NODE_VEC_TRANSFORM4,
-		NODE_VEC_COMPARE,
-		NODE_VEC_TEXTURE_2D,
-		NODE_VEC_TEXTURE_CUBE,
-		NODE_VEC_NOISE,
-		NODE_VEC_0,
-		NODE_VEC_1,
-		NODE_VEC_2,
-		NODE_VEC_BUILD,
-		NODE_VEC_PASS,
-		NODE_COLOR_CONSTANT,
-		NODE_COLOR_PARAMETER,
-		NODE_TEXTURE_PARAMETER,
-		NODE_TEXTURE_2D_PARAMETER,
-		NODE_TEXTURE_CUBE_PARAMETER,
-		NODE_TRANSFORM_CONSTANT,
-		NODE_TRANSFORM_PARAMETER,
-		NODE_LABEL,
+		NODE_INPUT, // all inputs (shader type dependent)
+		NODE_SCALAR_CONST, //scalar constant
+		NODE_VEC_CONST, //vec3 constant
+		NODE_RGB_CONST, //rgb constant (shows a color picker instead)
+		NODE_XFORM_CONST, // 4x4 matrix constant
+		NODE_TIME, // time in seconds
+		NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader)
+		NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc)
+		NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc)
+		NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc)
+		NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc.
+		NODE_XFORM_MULT, // mat4 x mat4
+		NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option)
+		NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option)
+		NODE_SCALAR_FUNC, // scalar function (sin, cos, etc)
+		NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc)
+		NODE_VEC_LEN, // vec3 length
+		NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output)
+		NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs
+		NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output
+		NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output
+		NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output
+		NODE_SCALAR_INTERP, // scalar interpolation (with optional curve)
+		NODE_VEC_INTERP, // vec3 interpolation  (with optional curve)
+		NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
+		NODE_VEC_INPUT, // vec3 uniform (assignable in material)
+		NODE_RGB_INPUT, // color uniform (assignable in material)
+		NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
+		NODE_TEXTURE_INPUT, // texture input (assignable in material)
+		NODE_CUBEMAP_INPUT, // cubemap input (assignable in material)
+		NODE_OUTPUT, // output (shader type dependent)
+		NODE_COMMENT, // comment
 		NODE_TYPE_MAX
 	};
 
-	enum ShaderType {
-		SHADER_VERTEX,
-		SHADER_FRAGMENT,
-		SHADER_LIGHT
-	};
-
-private:
 
 	struct Connection {
 
@@ -119,70 +86,287 @@ private:
 		int dst_slot;
 	};
 
+	enum SlotType {
+
+		SLOT_TYPE_SCALAR,
+		SLOT_TYPE_VEC,
+		SLOT_TYPE_XFORM,
+		SLOT_TYPE_TEXTURE,
+		SLOT_MAX
+	};
+
+	enum ShaderType {
+		SHADER_TYPE_VERTEX,
+		SHADER_TYPE_FRAGMENT,
+		SHADER_TYPE_LIGHT,
+		SHADER_TYPE_MAX
+	};
+
+	enum SlotDir {
+		SLOT_IN,
+		SLOT_OUT
+	};
+
+	enum GraphError {
+		GRAPH_OK,
+		GRAPH_ERROR_CYCLIC,
+		GRAPH_ERROR_MISSING_CONNECTIONS
+	};
+
+private:
+
+	String _find_unique_name(ShaderType p_which, const String& p_base);
+
+	struct SourceSlot {
+
+		int id;
+		int slot;
+		bool operator==(const SourceSlot& p_slot) const {
+			return id==p_slot.id && slot==p_slot.slot;
+		}
+	};
+
 	struct Node {
 
-		int16_t x,y;
+		Vector2 pos;
 		NodeType type;
-		Variant param;
+		Variant param1;
+		Variant param2;
 		int id;
 		mutable int order; // used for sorting
-		mutable bool out_valid;
-		mutable bool in_valid;
+		int sort_order;
+		Map<int,SourceSlot> connections;
+
 	};
 
 	struct ShaderData {
 		Map<int,Node> node_map;
-		List<Connection> connections;
+		GraphError error;
 	} shader[3];
-	uint64_t version;
 
-protected:
 
-/*	bool _set(const StringName& p_name, const Variant& p_value);
-	bool _get(const StringName& p_name,Variant &r_ret) const;
-	void _get_property_list( List<PropertyInfo> *p_list) const;*/
 
-	static void _bind_methods();
+	struct InOutParamInfo {
+		Mode shader_mode;
+		ShaderType shader_type;
+		const char *name;
+		const char *variable;
+		SlotType slot_type;
+		SlotDir dir;
+	};
+
+	static const InOutParamInfo inout_param_info[];
+
+	struct NodeSlotInfo {
+
+		enum { MAX_INS=3, MAX_OUTS=3 };
+		NodeType type;
+		const SlotType ins[MAX_INS];
+		const SlotType outs[MAX_OUTS];
+	};
+
+	static const NodeSlotInfo node_slot_info[];
+
+	bool _pending_update_shader;
+	void _update_shader();
+	void _request_update();
+
+	void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code);
+
+	Array _get_node_list(ShaderType p_type) const;
+	Array _get_connections(ShaderType p_type) const;
+protected:
 
-	Array _get_connections_helper() const;
+	static void _bind_methods();
 
 public:
 
 
-	void node_add(ShaderType p_which, NodeType p_type,int p_id);
+	void node_add(ShaderType p_type, NodeType p_node_type, int p_id);
 	void node_remove(ShaderType p_which,int p_id);
-	void node_set_param(ShaderType p_which, int p_id, const Variant& p_value);
 	void node_set_pos(ShaderType p_which,int p_id,const Point2& p_pos);
-	void node_change_type(ShaderType p_which,int p_id, NodeType p_type);
 	Point2 node_get_pos(ShaderType p_which,int p_id) const;
 
 	void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
 	NodeType node_get_type(ShaderType p_which,int p_id) const;
-	Variant node_get_param(ShaderType p_which,int p_id) const;
 
-	Error connect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
-	bool is_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
-	void disconnect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+	void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value);
+	float scalar_const_node_get_value(ShaderType p_which,int p_id) const;
 
-	void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
+	void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
+	Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const;
 
-	void clear();
+	void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
+	Color rgb_const_node_get_value(ShaderType p_which,int p_id) const;
 
-	uint64_t get_version() const { return version; }
+	void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
+	Transform xform_const_node_get_value(ShaderType p_which,int p_id) const;
 
-	static void get_default_input_nodes(Mode p_type,List<PropertyInfo> *p_inputs);
-	static void get_default_output_nodes(Mode p_type,List<PropertyInfo> *p_outputs);
+	void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size);
+	int texture_node_get_filter_size(ShaderType p_which,int p_id) const;
 
-	static PropertyInfo node_get_type_info(NodeType p_type);
-	static int get_input_count(NodeType p_type);
-	static int get_output_count(NodeType p_type);
-	static String get_input_name(NodeType p_type,int p_input);
-	static String get_output_name(NodeType p_type,int p_output);
-	static bool is_input_vector(NodeType p_type,int p_input);
-	static bool is_output_vector(NodeType p_type,int p_input);
+	void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
+	float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
 
+	enum ScalarOp {
+		SCALAR_OP_ADD,
+		SCALAR_OP_SUB,
+		SCALAR_OP_MUL,
+		SCALAR_OP_DIV,
+		SCALAR_OP_MOD,
+		SCALAR_OP_POW,
+		SCALAR_OP_MAX,
+		SCALAR_OP_MIN,
+		SCALAR_OP_ATAN2,
+		SCALAR_MAX_OP
+	};
+
+	void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op);
+	ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const;
+
+	enum  VecOp {
+		VEC_OP_ADD,
+		VEC_OP_SUB,
+		VEC_OP_MUL,
+		VEC_OP_DIV,
+		VEC_OP_MOD,
+		VEC_OP_POW,
+		VEC_OP_MAX,
+		VEC_OP_MIN,
+		VEC_OP_CROSS,
+		VEC_MAX_OP
+	};
 
-	ShaderGraph();
+	void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op);
+	VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const;
+
+	enum VecScalarOp {
+		VEC_SCALAR_OP_MUL,
+		VEC_SCALAR_OP_DIV,
+		VEC_SCALAR_OP_POW,
+		VEC_SCALAR_MAX_OP
+	};
+
+	void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op);
+	VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const;
+
+	enum RGBOp {
+		RGB_OP_SCREEN,
+		RGB_OP_DIFFERENCE,
+		RGB_OP_DARKEN,
+		RGB_OP_LIGHTEN,
+		RGB_OP_OVERLAY,
+		RGB_OP_DODGE,
+		RGB_OP_BURN,
+		RGB_OP_SOFT_LIGHT,
+		RGB_OP_HARD_LIGHT,
+		RGB_MAX_OP
+	};
+
+	void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op,float p_c);
+	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;
+
+	enum ScalarFunc {
+		SCALAR_FUNC_SIN,
+		SCALAR_FUNC_COS,
+		SCALAR_FUNC_TAN,
+		SCALAR_FUNC_ASIN,
+		SCALAR_FUNC_ACOS,
+		SCALAR_FUNC_ATAN,
+		SCALAR_FUNC_SINH,
+		SCALAR_FUNC_COSH,
+		SCALAR_FUNC_TANH,
+		SCALAR_FUNC_LOG,
+		SCALAR_FUNC_EXP,
+		SCALAR_FUNC_SQRT,
+		SCALAR_FUNC_ABS,
+		SCALAR_FUNC_SIGN,
+		SCALAR_FUNC_FLOOR,
+		SCALAR_FUNC_ROUND,
+		SCALAR_FUNC_CEIL,
+		SCALAR_FUNC_FRAC,
+		SCALAR_FUNC_SATURATE,
+		SCALAR_FUNC_NEGATE,
+		SCALAR_MAX_FUNC
+	};
+
+	void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func);
+	ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const;
+
+	enum VecFunc {
+		VEC_FUNC_NORMALIZE,
+		VEC_FUNC_SATURATE,
+		VEC_FUNC_NEGATE,
+		VEC_FUNC_RECIPROCAL,
+		VEC_FUNC_RGB2HSV,
+		VEC_FUNC_HSV2RGB,
+		VEC_MAX_FUNC
+	};
+
+	void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
+	VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
+
+	void input_node_set_name(ShaderType p_which,int p_id,const String& p_name);
+	String input_node_get_name(ShaderType p_which,int p_id);
+
+	void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value);
+	float scalar_input_node_get_value(ShaderType p_which,int p_id) const;
+
+	void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value);
+	Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const;
+
+	void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value);
+	Color rgb_input_node_get_value(ShaderType p_which,int p_id) const;
+
+	void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value);
+	Transform xform_input_node_get_value(ShaderType p_which,int p_id) const;
+
+	void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref<Texture>& p_texture);
+	Ref<Texture> texture_input_node_get_value(ShaderType p_which,int p_id) const;
+
+	void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref<CubeMap>& p_cubemap);
+	Ref<CubeMap> cubemap_input_node_get_value(ShaderType p_which,int p_id) const;
+
+	void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment);
+	String comment_node_get_text(ShaderType p_which,int p_id) const;
+
+	Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+	bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const;
+	void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot);
+
+	void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
+
+	void clear(ShaderType p_which);
+
+	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);
+
+	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);
+	static SlotType get_type_output_type(NodeType p_type,int p_idx);
+	static bool is_type_valid(Mode p_mode,ShaderType p_type);
+
+
+	struct SlotInfo {
+		String name;
+		SlotType type;
+		SlotDir dir;
+	};
+
+	static void get_input_output_node_slot_info(Mode p_mode, ShaderType  p_type, List<SlotInfo> *r_slots);
+
+	static int get_node_input_slot_count(Mode p_mode, ShaderType  p_shader_type,NodeType p_type);
+	static int get_node_output_slot_count(Mode p_mode, ShaderType  p_shader_type,NodeType p_type);
+	static SlotType get_node_input_slot_type(Mode p_mode, ShaderType  p_shader_type,NodeType p_type,int p_idx);
+	static SlotType get_node_output_slot_type(Mode p_mode, ShaderType  p_shader_type,NodeType p_type,int p_idx);
+
+
+	ShaderGraph(Mode p_mode);
 	~ShaderGraph();
 };
 
@@ -192,6 +376,27 @@ public:
 
 
 VARIANT_ENUM_CAST( ShaderGraph::NodeType );
+VARIANT_ENUM_CAST( ShaderGraph::ShaderType );
+VARIANT_ENUM_CAST( ShaderGraph::SlotType );
+VARIANT_ENUM_CAST( ShaderGraph::ScalarOp );
+VARIANT_ENUM_CAST( ShaderGraph::VecOp );
+VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
+VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
+VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
+VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
+
+
+class MaterialShaderGraph : public ShaderGraph {
+
+	OBJ_TYPE( MaterialShaderGraph, ShaderGraph );
+	RES_BASE_EXTENSION("sgp");
+
+public:
+
+
+	MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) {
+
+	}
+};
 
-#endif
 #endif // SHADER_GRAPH_H

+ 2 - 2
scene/resources/surface_tool.cpp

@@ -650,8 +650,8 @@ void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fv
 	Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData);
 	Vector2 v = varr[iFace*3+iVert]->get().uv;
 	fvTexcOut[0]=v.x;
-	//fvTexcOut[1]=v.y;
-	fvTexcOut[1]=1.0-v.y;
+	fvTexcOut[1]=v.y;
+	//fvTexcOut[1]=1.0-v.y;
 
 }
 void SurfaceTool::mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){

+ 1 - 1
servers/physics/physics_server_sw.cpp

@@ -770,7 +770,7 @@ void PhysicsServerSW::body_remove_collision_exception(RID p_body, RID p_body_b)
 	BodySW *body = body_owner.get(p_body);
 	ERR_FAIL_COND(!body);
 
-	body->remove_exception(p_body);
+	body->remove_exception(p_body_b);
 
 };
 

+ 0 - 3
servers/visual/shader_graph.h

@@ -26,8 +26,6 @@
 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
-#ifndef SHADER_GRAPH_H
-#define SHADER_GRAPH_H
 
 #if 0
 
@@ -109,4 +107,3 @@ public:
 
 };
 #endif
-#endif

+ 10 - 7
tools/SCsub

@@ -5,13 +5,16 @@ env.add_source_files(env.tool_sources,"*.cpp")
 
 Export('env')
 
-SConscript('editor/SCsub');
-#SConscript('scintilla/SCsub');
-SConscript('collada/SCsub');
-SConscript('docdump/SCsub');
-SConscript('freetype/SCsub');
-SConscript('doc/SCsub');
-SConscript('pck/SCsub');
+if (env["tools"]!="no"):
+	SConscript('editor/SCsub');
+	#SConscript('scintilla/SCsub');
+	SConscript('collada/SCsub');
+	SConscript('docdump/SCsub');
+	SConscript('freetype/SCsub');
+	SConscript('doc/SCsub')
+	SConscript('pck/SCsub')
+	
+
 
 lib = env.Library("tool",env.tool_sources)
 

+ 4 - 2
tools/doc/doc_data.cpp

@@ -186,8 +186,10 @@ void DocData::generate(bool p_basic_types) {
 					arginfo=E->get().return_val;
 					if (arginfo.type==Variant::NIL)
 						continue;
-
-					method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type);
+					if (m && m->get_return_type()!=StringName())
+						method.return_type=m->get_return_type();
+					else
+						method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type);
 
 				} else {
 

+ 5 - 5
tools/editor/animation_editor.cpp

@@ -2909,11 +2909,11 @@ void AnimationKeyEditor::set_anim_pos(float p_pos) {
 
 void AnimationKeyEditor::_pane_drag(const Point2& p_delta) {
 
-	Size2 ecs = ec->get_minsize();
+	Size2 ecs = ec->get_custom_minimum_size();
 	ecs.y-=p_delta.y;
 	if (ecs.y<100)
 		ecs.y=100;
-	ec->set_minsize(ecs);;
+	ec->set_custom_minimum_size(ecs);;
 
 }
 
@@ -3238,7 +3238,7 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
 	move_down_button->connect("pressed",this,"_menu_track",make_binds(TRACK_MENU_MOVE_DOWN));
 	move_down_button->set_focus_mode(FOCUS_NONE);
 	move_down_button->set_disabled(true);
-	move_down_button->set_tooltip("Move current track dosn.");
+	move_down_button->set_tooltip("Move current track down.");
 
 	remove_button = memnew( ToolButton );
 	hb->add_child(remove_button);
@@ -3296,8 +3296,8 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
 
 //	menu->get_popup()->connect("item_pressed",this,"_menu_callback");
 
-	ec = memnew (EmptyControl);
-	ec->set_minsize(Size2(0,50));
+	ec = memnew (Control);
+	ec->set_custom_minimum_size(Size2(0,50));
 	add_child(ec);
 	ec->set_v_size_flags(SIZE_EXPAND_FILL);
 

+ 2 - 2
tools/editor/animation_editor.h

@@ -37,7 +37,7 @@
 #include "scene/gui/scroll_bar.h"
 #include "scene/gui/tool_button.h"
 #include "scene/gui/file_dialog.h"
-#include "scene/gui/empty_control.h"
+
 #include "scene/resources/animation.h"
 #include "scene/animation/animation_cache.h"
 #include "scene_tree_editor.h"
@@ -157,7 +157,7 @@ class AnimationKeyEditor : public VBoxContainer  {
 	PopupMenu *track_menu;
 	PopupMenu *type_menu;
 
-	EmptyControl *ec;
+	Control *ec;
 	TextureFrame *zoomicon;
 	HSlider *zoom;
 	//MenuButton *menu;

+ 13 - 1
tools/editor/code_editor.cpp

@@ -599,7 +599,19 @@ CodeTextEditor::CodeTextEditor() {
 	add_child(text_editor);
 	text_editor->set_area_as_parent_rect();
 	text_editor->set_margin(MARGIN_BOTTOM,20);
-	text_editor->add_font_override("font",get_font("source","Fonts"));
+
+	String editor_font = EDITOR_DEF("text_editor/font", "");
+	bool font_overrode = false;
+	if (editor_font!="") {
+		Ref<Font> fnt = ResourceLoader::load(editor_font);
+		if (fnt.is_valid()) {
+			text_editor->add_font_override("font",fnt);
+			font_overrode = true;
+		}
+	}
+
+	if (!font_overrode)
+		text_editor->add_font_override("font",get_font("source","Fonts"));
 	text_editor->set_show_line_numbers(true);
 	text_editor->set_brace_matching(true);
 

+ 2 - 2
tools/editor/editor_help.cpp

@@ -1361,8 +1361,8 @@ EditorHelp::EditorHelp(EditorNode *p_editor) {
 
 	Separator *hs = memnew( VSeparator );
 	panel_hb->add_child(hs);
-	EmptyControl *ec = memnew( EmptyControl );
-	ec->set_minsize(Size2(200,1));
+	Control *ec = memnew( Control );
+	ec->set_custom_minimum_size(Size2(200,1));
 	panel_hb->add_child(ec);
 	search = memnew( LineEdit );
 	ec->add_child(search);

+ 10 - 2
tools/editor/editor_import_export.cpp

@@ -292,7 +292,11 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const
 			_add_filter_to_list(exported,"*");
 		} else {
 			_add_to_list(EditorFileSystem::get_singleton()->get_filesystem(),exported);
-			_add_filter_to_list(exported,EditorImportExport::get_singleton()->get_export_custom_filter());
+			String cf = EditorImportExport::get_singleton()->get_export_custom_filter();
+			if (cf!="")
+				cf+=",";
+			cf+="*.flags";
+			_add_filter_to_list(exported,cf);
 
 		}
 
@@ -361,8 +365,12 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const
 				}
 			}
 		}
+		String cf = EditorImportExport::get_singleton()->get_export_custom_filter();
+		if (cf!="")
+			cf+=",";
+		cf+="*.flags";
+		_add_filter_to_list(exported,cf);
 
-		_add_filter_to_list(exported,EditorImportExport::get_singleton()->get_export_custom_filter());
 
 	}
 

+ 2 - 2
tools/editor/editor_log.cpp

@@ -203,9 +203,9 @@ EditorLog::EditorLog() {
 	tb->connect("pressed",this,"_close_request");
 
 
-	ec = memnew( EmptyControl);
+	ec = memnew( Control);
 	vb->add_child(ec);
-	ec->set_minsize(Size2(0,100));
+	ec->set_custom_minimum_size(Size2(0,100));
 	ec->set_v_size_flags(SIZE_EXPAND_FILL);
 
 

+ 2 - 2
tools/editor/editor_log.h

@@ -33,7 +33,7 @@
 #include "scene/gui/label.h"
 #include "scene/gui/rich_text_label.h"
 #include "scene/gui/texture_button.h"
-#include "scene/gui/empty_control.h"
+//#include "scene/gui/empty_control.h"
 #include "scene/gui/box_container.h"
 #include "scene/gui/panel_container.h"
 #include "scene/gui/texture_frame.h"
@@ -50,7 +50,7 @@ class EditorLog : public PanelContainer {
 	TextureButton *tb;
 	HBoxContainer *title_hb;
 //	PaneDrag *pd;
-	EmptyControl *ec;
+	Control *ec;
 
 	static void _error_handler(void *p_self, const char*p_func, const char*p_file,int p_line, const char*p_error,const char*p_errorexp,ErrorHandlerType p_type);
 

+ 11 - 9
tools/editor/editor_node.cpp

@@ -75,6 +75,7 @@
 #include "plugins/tile_map_editor_plugin.h"
 #include "plugins/cube_grid_theme_editor_plugin.h"
 #include "plugins/shader_editor_plugin.h"
+#include "plugins/shader_graph_editor_plugin.h"
 #include "plugins/path_editor_plugin.h"
 #include "plugins/rich_text_editor_plugin.h"
 #include "plugins/collision_polygon_editor_plugin.h"
@@ -3245,7 +3246,7 @@ EditorNode::EditorNode() {
 	gui_base->set_area_as_parent_rect();
 
 
-	Ref<Theme> theme( memnew( Theme ) );
+	theme = Ref<Theme>( memnew( Theme ) );
 	gui_base->set_theme( theme );
 	editor_register_icons(theme);
 	editor_register_fonts(theme);
@@ -3308,13 +3309,13 @@ EditorNode::EditorNode() {
 	main_editor_tabs->connect("tab_changed",this,"_editor_select");
 	HBoxContainer *srth = memnew( HBoxContainer );
 	srt->add_child( srth );
-	EmptyControl *tec = memnew( EmptyControl );
-	tec->set_minsize(Size2(100,0));
+	Control *tec = memnew( Control );
+	tec->set_custom_minimum_size(Size2(100,0));
 	tec->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	srth->add_child(tec);
 	srth->add_child(main_editor_tabs);
-	tec = memnew( EmptyControl );
-	tec->set_minsize(Size2(100,0));
+	tec = memnew( Control );
+	tec->set_custom_minimum_size(Size2(100,0));
 	srth->add_child(tec);
 	tec->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 
@@ -3674,8 +3675,8 @@ EditorNode::EditorNode() {
 	top_pallete->add_child(resources_dock);
 	top_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 
-	EmptyControl *editor_spacer = memnew( EmptyControl );
-	editor_spacer->set_minsize(Size2(260,200));
+	Control *editor_spacer = memnew( Control );
+	editor_spacer->set_custom_minimum_size(Size2(260,200));
 	editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	editor_vsplit->add_child( editor_spacer );
 	editor_spacer->add_child( top_pallete );
@@ -3686,8 +3687,8 @@ EditorNode::EditorNode() {
 
 	prop_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 
-	editor_spacer = memnew( EmptyControl );
-	editor_spacer->set_minsize(Size2(260,200));
+	editor_spacer = memnew( Control );
+	editor_spacer->set_custom_minimum_size(Size2(260,200));
 	editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	editor_vsplit->add_child( editor_spacer );
 	editor_spacer->add_child( prop_pallete );
@@ -4016,6 +4017,7 @@ EditorNode::EditorNode() {
 	add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
 	add_editor_plugin( memnew( EditorHelpPlugin(this) ) );
 	add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) );
+	add_editor_plugin( memnew( ShaderGraphEditorPlugin(this) ) );
 	add_editor_plugin( memnew( ShaderEditorPlugin(this) ) );
 	add_editor_plugin( memnew( CameraEditorPlugin(this) ) );
 	add_editor_plugin( memnew( SampleEditorPlugin(this) ) );

+ 4 - 0
tools/editor/editor_node.h

@@ -212,6 +212,7 @@ class EditorNode : public Node {
 	AcceptDialog *load_error_dialog;
 
 	Control *scene_root_base;
+	Ref<Theme> theme;
 
 	PopupMenu *recent_scenes;
 	Button *property_back;
@@ -472,6 +473,9 @@ public:
 
 	void stop_child_process();
 
+	Ref<Theme> get_editor_theme() const { return theme; }
+
+
 	Error export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after=false);
 
 	static void register_editor_types();

+ 3 - 0
tools/editor/editor_settings.cpp

@@ -419,6 +419,8 @@ void EditorSettings::_load_defaults() {
 
 	set("3d_editor/navigation_scheme",0);
 	hints["3d_editor/navigation_scheme"]=PropertyInfo(Variant::INT,"3d_editor/navigation_scheme",PROPERTY_HINT_ENUM,"Godot,Maya,Modo");
+	set("3d_editor/zoom_style",0);
+	hints["3d_editor/zoom_style"]=PropertyInfo(Variant::INT,"3d_editor/zoom_style",PROPERTY_HINT_ENUM,"Vertical, Horizontal");
 	set("3d_editor/orbit_modifier",0);
 	hints["3d_editor/orbit_modifier"]=PropertyInfo(Variant::INT,"3d_editor/orbit_modifier",PROPERTY_HINT_ENUM,"None,Shift,Alt,Meta,Ctrl");
 	set("3d_editor/pan_modifier",1);
@@ -444,6 +446,7 @@ void EditorSettings::_load_defaults() {
 	set("animation/confirm_insert_track",true);
 
 	set("property_editor/texture_preview_width",48);
+	set("property_editor/auto_refresh_interval",0.3);
 	set("help/doc_path","");
 
 	set("import/ask_save_before_reimport",false);

二进制
tools/editor/icons/icon_canvas_item_shader.png


二进制
tools/editor/icons/icon_canvas_item_shader_graph.png


二进制
tools/editor/icons/icon_material_shader.png


部分文件因为文件数量过多而无法显示