Răsfoiți Sursa

-Work in progress visual shader editor *DOES NOT WORK YET*

Juan Linietsky 10 ani în urmă
părinte
comite
fbdd925d9b
51 a modificat fișierele cu 4356 adăugiri și 1960 ștergeri
  1. 1 0
      core/method_bind.h
  2. 12 0
      core/object_type_db.cpp
  3. 2 0
      core/object_type_db.h
  4. 3 0
      demos/2d/platformer/player.gd
  5. 99 72
      demos/2d/platformer/player.xml
  6. 2 2
      drivers/builtin_openssl2/openssl/md5.h
  7. 1 2
      drivers/gles2/rasterizer_gles2.cpp
  8. 5 3
      drivers/mpc/audio_stream_mpc.cpp
  9. 7 3
      drivers/theoraplayer/SCsub
  10. 1 0
      drivers/theoraplayer/src/TheoraVideoClip.cpp
  11. 4 2
      drivers/theoraplayer/video_stream_theoraplayer.cpp
  12. 3 5
      drivers/unix/memory_pool_static_malloc.cpp
  13. 1 1
      drivers/webp/dsp/dsp.h
  14. 1 0
      drivers/webp/utils/bit_reader.h
  15. 4 0
      modules/gdscript/gd_functions.cpp
  16. 0 4
      platform/iphone/detect.py
  17. 1 0
      platform/iphone/platform_config.h
  18. 18 0
      platform/iphone/platform_refcount.h
  19. 37 0
      platform/winrt/include/angle_windowsstore.h
  20. 5 0
      scene/3d/collision_object.cpp
  21. 44 14
      scene/3d/ray_cast.cpp
  22. 7 2
      scene/3d/ray_cast.h
  23. 517 0
      scene/gui/graph_edit.cpp
  24. 93 0
      scene/gui/graph_edit.h
  25. 256 16
      scene/gui/graph_node.cpp
  26. 43 3
      scene/gui/graph_node.h
  27. 1 0
      scene/gui/menu_button.cpp
  28. 18 1
      scene/gui/popup_menu.cpp
  29. 4 0
      scene/gui/popup_menu.h
  30. 13 3
      scene/register_scene_types.cpp
  31. 7 1
      scene/resources/default_theme/default_theme.cpp
  32. BIN
      scene/resources/default_theme/graph_node_close.png
  33. 5 0
      scene/resources/default_theme/theme_data.h
  34. 1 1
      scene/resources/material.cpp
  35. 3 10
      scene/resources/shader.cpp
  36. 15 3
      scene/resources/shader.h
  37. 1507 760
      scene/resources/shader_graph.cpp
  38. 306 101
      scene/resources/shader_graph.h
  39. 0 3
      servers/visual/shader_graph.h
  40. 10 7
      tools/SCsub
  41. 4 2
      tools/doc/doc_data.cpp
  42. 3 1
      tools/editor/editor_node.cpp
  43. 4 0
      tools/editor/editor_node.h
  44. BIN
      tools/editor/icons/icon_canvas_item_shader.png
  45. BIN
      tools/editor/icons/icon_canvas_item_shader_graph.png
  46. BIN
      tools/editor/icons/icon_material_shader.png
  47. BIN
      tools/editor/icons/icon_material_shader_graph.png
  48. 2 0
      tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp
  49. 1193 848
      tools/editor/plugins/shader_graph_editor_plugin.cpp
  50. 85 86
      tools/editor/plugins/shader_graph_editor_plugin.h
  51. 8 4
      tools/editor/property_editor.cpp

+ 1 - 0
core/method_bind.h

@@ -178,6 +178,7 @@ public:
 #ifdef DEBUG_METHODS_ENABLED
 #ifdef DEBUG_METHODS_ENABLED
 
 
 	_FORCE_INLINE_ void set_return_type(const StringName& p_type) { ret_type=p_type; }
 	_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 {
 	_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,ObjectTypeDB::TypeInfo,StringNameHasher> ObjectTypeDB::types;
 HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::resource_base_extensions;
 HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::resource_base_extensions;
+HashMap<StringName,StringName,StringNameHasher> ObjectTypeDB::compat_types;
 
 
 ObjectTypeDB::TypeInfo::TypeInfo() {
 ObjectTypeDB::TypeInfo::TypeInfo() {
 
 
@@ -263,12 +264,22 @@ bool ObjectTypeDB::type_exists(const String &p_type) {
 	return types.has(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) {
 Object *ObjectTypeDB::instance(const String &p_type) {
 	
 	
 	TypeInfo *ti;
 	TypeInfo *ti;
 	{
 	{
 		OBJTYPE_LOCK;
 		OBJTYPE_LOCK;
 		ti=types.getptr(p_type);
 		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,NULL);
 		ERR_FAIL_COND_V(ti->disabled,NULL);
 		ERR_FAIL_COND_V(ti->disabled,NULL);
 		ERR_FAIL_COND_V(!ti->creation_func,NULL);
 		ERR_FAIL_COND_V(!ti->creation_func,NULL);
@@ -914,6 +925,7 @@ void ObjectTypeDB::cleanup() {
 	}	
 	}	
 	types.clear();
 	types.clear();
 	resource_base_extensions.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 Mutex *lock;
 	static HashMap<StringName,TypeInfo,StringNameHasher> types;
 	static HashMap<StringName,TypeInfo,StringNameHasher> types;
 	static HashMap<StringName,StringName,StringNameHasher> resource_base_extensions;
 	static HashMap<StringName,StringName,StringNameHasher> resource_base_extensions;
+	static HashMap<StringName,StringName,StringNameHasher> compat_types;
 
 
 #ifdef DEBUG_METHODS_ENABLED
 #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);
 	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_resource_base_extensions(List<String> *p_extensions);
 	static void get_extensions_for_type(const StringName& p_type,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 init();
 	static void cleanup();
 	static void cleanup();
 };
 };

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

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

Fișier diff suprimat deoarece este prea mare
+ 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;
 	unsigned int num;
 	} MD5_CTX;
 	} MD5_CTX;
 
 
-#ifdef OPENSSL_FIPS
+//#ifdef OPENSSL_FIPS
 int private_MD5_Init(MD5_CTX *c);
 int private_MD5_Init(MD5_CTX *c);
-#endif
+//#endif
 
 
 //#define MD5_Init _SSL_MD5_Init
 //#define MD5_Init _SSL_MD5_Init
 #define MD5_Final _SSL_MD5_Final
 #define MD5_Final _SSL_MD5_Final

+ 1 - 2
drivers/gles2/rasterizer_gles2.cpp

@@ -969,7 +969,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;
 		texture->has_alpha=true;
 	}
 	}
 
 
@@ -4224,7 +4224,6 @@ void RasterizerGLES2::capture_viewport(Image* r_capture) {
 	}
 	}
 
 
 	w=DVector<uint8_t>::Write();
 	w=DVector<uint8_t>::Write();
-
 	r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels);
 	r_capture->create(viewport.width,viewport.height,0,Image::FORMAT_RGBA,pixels);
 	//r_capture->flip_y();
 	//r_capture->flip_y();
 
 

+ 5 - 3
drivers/mpc/audio_stream_mpc.cpp

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

+ 7 - 3
drivers/theoraplayer/SCsub

@@ -61,13 +61,17 @@ src/YUV/C/yuv420_rgb_c.c
 src/TheoraVideoFrame.cpp
 src/TheoraVideoFrame.cpp
 """)
 """)
 
 
+env_theora = env.Clone()
+
 if env["platform"] == "iphone":
 if env["platform"] == "iphone":
 	sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm")
 	sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm")
 	env.Append(LINKFLAGS=['-framework', 'CoreVideo', '-framework', 'CoreMedia', '-framework', 'AVFoundation'])
 	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":
 if env["platform"] == "iphone":
 	env_theora.Append(CPPFLAGS=["-D__AVFOUNDATION"])
 	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)
 	if (nPop > 0)
     {
     {
+#define _DEBUG
 #ifdef _DEBUG
 #ifdef _DEBUG
         std::string log = getName() + ": dropped frame ";
         std::string log = getName() + ": dropped frame ";
     
     

+ 4 - 2
drivers/theoraplayer/video_stream_theoraplayer.cpp

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

+ 3 - 5
drivers/unix/memory_pool_static_malloc.cpp

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

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

@@ -33,7 +33,7 @@ extern "C" {
 #define WEBP_ANDROID_NEON  // Android targets that might support NEON
 #define WEBP_ANDROID_NEON  // Android targets that might support NEON
 #endif
 #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
 #define WEBP_USE_NEON
 #endif
 #endif
 
 

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

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

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

Fișier diff suprimat deoarece este prea mare
+ 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 GLES2_INCLUDE_H <ES2/gl.h>
 #define GLES1_INCLUDE_H <ES1/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

+ 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_

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

@@ -47,6 +47,11 @@ void CollisionObject::_notification(int p_what) {
 
 
 		case NOTIFICATION_ENTER_WORLD: {
 		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();
 			RID space = get_world()->get_space();
 			if (area) {
 			if (area) {
 				PhysicsServer::get_singleton()->area_set_space(rid,space);
 				PhysicsServer::get_singleton()->area_set_space(rid,space);

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

@@ -95,18 +95,6 @@ void RayCast::_notification(int p_what) {
 
 
 			if (enabled && !get_tree()->is_editor_hint()) {
 			if (enabled && !get_tree()->is_editor_hint()) {
 				set_fixed_process(true);
 				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
 			} else
 				set_fixed_process(false);
 				set_fixed_process(false);
 
 
@@ -119,7 +107,6 @@ void RayCast::_notification(int p_what) {
 				set_fixed_process(false);
 				set_fixed_process(false);
 			}
 			}
 
 
-			exceptions.erase(exception);
 
 
 		} break;
 		} break;
 		case NOTIFICATION_FIXED_PROCESS: {
 		case NOTIFICATION_FIXED_PROCESS: {
@@ -143,7 +130,7 @@ void RayCast::_notification(int p_what) {
 
 
 			PhysicsDirectSpaceState::RayResult rr;
 			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;
 				collided=true;
 				against=rr.collider_id;
 				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() {
 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_point"),&RayCast::get_collision_point);
 	ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal);
 	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::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
 	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;
 	Vector3 cast_to;
 
 
-	RID exception;
-	Set<RID> exceptions;
+	Set<RID> exclude;
 
 
 protected:
 protected:
 
 
@@ -66,6 +65,12 @@ public:
 	Vector3 get_collision_point() const;
 	Vector3 get_collision_point() const;
 	Vector3 get_collision_normal() 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();
 	RayCast();
 };
 };
 
 

+ 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;
 	int idx=0;
 	for(int i=0;i<get_child_count();i++) {
 	for(int i=0;i<get_child_count();i++) {
 		Control *c=get_child(i)->cast_to<Control>();
 		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;
 			continue;
 
 
 		String base="slot/"+itos(idx)+"/";
 		String base="slot/"+itos(idx)+"/";
@@ -122,6 +122,7 @@ void GraphNode::_resort() {
 
 
 	}
 	}
 
 
+
 	int vofs=0;
 	int vofs=0;
 	int w = get_size().x - sb->get_minimum_size().x;
 	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>();
 		Control *c=get_child(i)->cast_to<Control>();
 		if (!c)
 		if (!c)
 			continue;
 			continue;
-		if (c->is_set_as_toplevel() || !c->get_owner())
+		if (c->is_set_as_toplevel())
 			continue;
 			continue;
 
 
 		Size2i size=c->get_combined_minimum_size();
 		Size2i size=c->get_combined_minimum_size();
@@ -150,6 +151,8 @@ void GraphNode::_resort() {
 
 
 	_change_notify();
 	_change_notify();
 	update();
 	update();
+	connpos_dirty=true;
+
 
 
 }
 }
 
 
@@ -160,14 +163,34 @@ void GraphNode::_notification(int p_what) {
 
 
 		Ref<StyleBox> sb=get_stylebox("frame");
 		Ref<StyleBox> sb=get_stylebox("frame");
 		Ref<Texture> port =get_icon("port");
 		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;
 		Point2i icofs = -port->get_size()*0.5;
-		int edgeofs=3;
+		int edgeofs=get_constant("port_offset");
 		icofs.y+=sb->get_margin(MARGIN_TOP);
 		icofs.y+=sb->get_margin(MARGIN_TOP);
 		draw_style_box(sb,Rect2(Point2(),get_size()));
 		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()) {
 		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;
 				continue;
 			if (!slot_info.has(E->key()))
 			if (!slot_info.has(E->key()))
 				continue;
 				continue;
@@ -180,6 +203,7 @@ void GraphNode::_notification(int p_what) {
 
 
 		}
 		}
 	}
 	}
+
 	if (p_what==NOTIFICATION_SORT_CHILDREN) {
 	if (p_what==NOTIFICATION_SORT_CHILDREN) {
 
 
 		_resort();
 		_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) {
 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;
 	s.color_right=p_color_right;
 	slot_info[p_idx]=s;
 	slot_info[p_idx]=s;
 	update();
 	update();
+	connpos_dirty=true;
+
 }
 }
 
 
 void GraphNode::clear_slot(int p_idx){
 void GraphNode::clear_slot(int p_idx){
 
 
 	slot_info.erase(p_idx);
 	slot_info.erase(p_idx);
 	update();
 	update();
+	connpos_dirty=true;
+
 }
 }
 void GraphNode::clear_all_slots(){
 void GraphNode::clear_all_slots(){
 
 
 	slot_info.clear();
 	slot_info.clear();
 	update();
 	update();
+	connpos_dirty=true;
+
 }
 }
 bool GraphNode::is_slot_enabled_left(int p_idx) const{
 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 {
 Size2 GraphNode::get_minimum_size() const {
 
 
+	Ref<Font> title_font = get_font("title_font");
+
 	int sep=get_constant("separation");
 	int sep=get_constant("separation");
 	Ref<StyleBox> sb=get_stylebox("frame");
 	Ref<StyleBox> sb=get_stylebox("frame");
 	bool first=true;
 	bool first=true;
 
 
 	Size2 minsize;
 	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++) {
 	for(int i=0;i<get_child_count();i++) {
 
 
 		Control *c=get_child(i)->cast_to<Control>();
 		Control *c=get_child(i)->cast_to<Control>();
 		if (!c)
 		if (!c)
 			continue;
 			continue;
-		if (c->is_set_as_toplevel() || !c->get_owner())
+		if (c->is_set_as_toplevel())
 			continue;
 			continue;
 
 
 		Size2i size=c->get_combined_minimum_size();
 		Size2i size=c->get_combined_minimum_size();
@@ -308,13 +336,225 @@ Size2 GraphNode::get_minimum_size() const {
 	return minsize+sb->get_minimum_size();
 	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() {
 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() {
 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);
 	OBJ_TYPE(GraphNode,Container);
 
 
 
 
-	String title;
+
 	struct Slot {
 	struct Slot {
 		bool enable_left;
 		bool enable_left;
 		int type_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); };
 		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;
 	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;
 	Map<int,Slot> slot_info;
 
 
+	bool connpos_dirty;
+
+	void _connpos_update();
 	void _resort();
 	void _resort();
+
+	Vector2 drag_from;
+	Vector2 drag_accum;
+	bool dragging;
 protected:
 protected:
 
 
+	void _input_event(const InputEvent& p_ev);
 	void _notification(int p_what);
 	void _notification(int p_what);
 	static void _bind_methods();
 	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 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);
 	void clear_slot(int p_idx);
@@ -52,6 +73,25 @@ public:
 	int get_slot_type_right(int p_idx) const;
 	int get_slot_type_right(int p_idx) const;
 	Color get_slot_color_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;
 	virtual Size2 get_minimum_size() const;
 
 
 	GraphNode();
 	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->set_parent_rect( Rect2(Point2(gp-popup->get_global_pos()),get_size()));
 	popup->popup();
 	popup->popup();
 	popup->call_deferred("grab_click_focus");
 	popup->call_deferred("grab_click_focus");
+	popup->set_invalidate_click_until_motion();
 	
 	
 }
 }
 
 

+ 18 - 1
scene/gui/popup_menu.cpp

@@ -30,6 +30,7 @@
 #include "print_string.h"
 #include "print_string.h"
 #include "os/keyboard.h"
 #include "os/keyboard.h"
 #include "translation.h"
 #include "translation.h"
+#include "os/input.h"
 
 
 String PopupMenu::_get_accel_text(uint32_t p_accel) const {
 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));
 					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)
 					if (over<0 || items[over].separator || items[over].disabled)
 						break; //non-activable
 						break; //non-activable
 
 
@@ -336,6 +341,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
 		case InputEvent::MOUSE_MOTION: {
 		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;
 			const InputEventMouseMotion &m=p_event.mouse_motion;
 			for(List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) {
 			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() {
 PopupMenu::PopupMenu() {
 
 
 	idcount=0;
 	idcount=0;
 	mouse_over=-1;
 	mouse_over=-1;
 	
 	
-
 	set_focus_mode(FOCUS_ALL);
 	set_focus_mode(FOCUS_ALL);
 	set_as_toplevel(true);
 	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 _activate_submenu(int over);
 	void _submenu_timeout();
 	void _submenu_timeout();
 
 
+	bool invalidated_click;
+	Vector2 moved;
 
 
 	Array _get_items() const;
 	Array _get_items() const;
 	void _set_items(const Array& p_items);
 	void _set_items(const Array& p_items);
@@ -134,6 +136,8 @@ public:
 	void add_autohide_area(const Rect2& p_area);
 	void add_autohide_area(const Rect2& p_area);
 	void clear_autohide_areas();
 	void clear_autohide_areas();
 
 
+	void set_invalidate_click_until_motion();
+
 	PopupMenu();	
 	PopupMenu();	
 	~PopupMenu();
 	~PopupMenu();
 
 

+ 13 - 3
scene/register_scene_types.cpp

@@ -76,6 +76,7 @@
 #include "scene/gui/video_player.h"
 #include "scene/gui/video_player.h"
 #include "scene/gui/reference_frame.h"
 #include "scene/gui/reference_frame.h"
 #include "scene/gui/graph_node.h"
 #include "scene/gui/graph_node.h"
+#include "scene/gui/graph_edit.h"
 #include "scene/resources/video_stream.h"
 #include "scene/resources/video_stream.h"
 #include "scene/2d/particles_2d.h"
 #include "scene/2d/particles_2d.h"
 #include "scene/2d/path_2d.h"
 #include "scene/2d/path_2d.h"
@@ -153,6 +154,8 @@
 #include "scene/resources/mesh.h"
 #include "scene/resources/mesh.h"
 #include "scene/resources/room.h"
 #include "scene/resources/room.h"
 
 
+#include "scene/resources/shader_graph.h"
+
 #include "scene/resources/world.h"
 #include "scene/resources/world.h"
 #include "scene/resources/world_2d.h"
 #include "scene/resources/world_2d.h"
 #include "scene/resources/volume.h"
 #include "scene/resources/volume.h"
@@ -305,6 +308,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<HSplitContainer>();
 	ObjectTypeDB::register_type<HSplitContainer>();
 	ObjectTypeDB::register_type<VSplitContainer>();
 	ObjectTypeDB::register_type<VSplitContainer>();
 	ObjectTypeDB::register_type<GraphNode>();
 	ObjectTypeDB::register_type<GraphNode>();
+	ObjectTypeDB::register_type<GraphEdit>();
 
 
 	OS::get_singleton()->yield(); //may take time to init
 	OS::get_singleton()->yield(); //may take time to init
 
 
@@ -496,11 +500,17 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<Mesh>();
 	ObjectTypeDB::register_type<Mesh>();
 	ObjectTypeDB::register_virtual_type<Material>();
 	ObjectTypeDB::register_virtual_type<Material>();
 	ObjectTypeDB::register_type<FixedMaterial>();
 	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<ShaderMaterial>();
 	ObjectTypeDB::register_type<RoomBounds>();
 	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<MultiMesh>();
 	ObjectTypeDB::register_type<MeshLibrary>();
 	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("hseparation","PopupMenu",2);
 	t->set_constant("vseparation","PopupMenu",1);
 	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_LEFT,10);
 	//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
 	//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
 	t->set_stylebox("frame","GraphNode", graphsb );
 	t->set_stylebox("frame","GraphNode", graphsb );
 	t->set_constant("separation","GraphNode", 1 );
 	t->set_constant("separation","GraphNode", 1 );
 	t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
 	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) );
 	t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) );

BIN
scene/resources/default_theme/graph_node_close.png


Fișier diff suprimat deoarece este prea mare
+ 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 {
 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()) {
 	if (!shader.is_null()) {
 
 

+ 3 - 10
scene/resources/shader.cpp

@@ -33,12 +33,6 @@
 #include "scene/scene_string_names.h"
 #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 {
 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() {
 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("get_mode"),&Shader::get_mode);
 
 
 	ObjectTypeDB::bind_method(_MD("set_code","vcode","fcode","lcode","fofs","lofs"),&Shader::set_code,DEFVAL(0),DEFVAL(0));
 	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;
 	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();
 	String base_path = p_path.get_base_dir();
 
 
 
 
-	Ref<Shader> shader( memnew( Shader ) );
+	Ref<Shader> shader;//( memnew( Shader ) );
 
 
 	int line=0;
 	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..
 	mutable Map<StringName,StringName> params_cache; //map a shader param to a material param..
 	Map<StringName,Ref<Texture> > default_textures;
 	Map<StringName,Ref<Texture> > default_textures;
 
 
+
+
 protected:
 protected:
 
 
 
 
@@ -59,10 +61,11 @@ public:
 
 
 		MODE_MATERIAL,
 		MODE_MATERIAL,
 		MODE_CANVAS_ITEM,
 		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;
 	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);
 	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;
 	virtual RID get_rid() const;
 
 
-	Shader();
+	Shader(Mode p_mode);
 	~Shader();
 	~Shader();
 
 
 };
 };
 
 
 VARIANT_ENUM_CAST( Shader::Mode );
 VARIANT_ENUM_CAST( Shader::Mode );
 
 
+class MaterialShader : public Shader {
+
+	OBJ_TYPE(MaterialShader,Shader);
+
+public:
+
+	MaterialShader() : Shader(MODE_MATERIAL) {};
+};
+
 
 
 
 
 class ResourceFormatLoaderShader : public ResourceFormatLoader {
 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_add"),&ShaderGraph::node_add );
 	ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove );
 	ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove );
 	ObjectTypeDB::bind_method(_MD("node_set_param"),&ShaderGraph::node_set_param );
 	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_2D_PARAMETER );
 	BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER );
 	BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER );
 	BIND_CONSTANT( NODE_TYPE_MAX );
 	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 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.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
 	//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) {
 	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(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
 #ifndef SHADER_GRAPH_H
 #define SHADER_GRAPH_H
 #define SHADER_GRAPH_H
 
 
-#if 0
+
 
 
 #include "map.h"
 #include "map.h"
 #include "scene/resources/shader.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");
 	RES_BASE_EXTENSION("sgp");
 
 
 public:
 public:
 
 
 	enum NodeType {
 	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
 		NODE_TYPE_MAX
 	};
 	};
 
 
-	enum ShaderType {
-		SHADER_VERTEX,
-		SHADER_FRAGMENT,
-		SHADER_LIGHT
-	};
-
-private:
 
 
 	struct Connection {
 	struct Connection {
 
 
@@ -119,70 +86,287 @@ private:
 		int dst_slot;
 		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 {
 	struct Node {
 
 
-		int16_t x,y;
+		Vector2 pos;
 		NodeType type;
 		NodeType type;
-		Variant param;
+		Variant param1;
+		Variant param2;
 		int id;
 		int id;
 		mutable int order; // used for sorting
 		mutable int order; // used for sorting
-		mutable bool out_valid;
-		mutable bool in_valid;
+		int sort_order;
+		Map<int,SourceSlot> connections;
+
 	};
 	};
 
 
 	struct ShaderData {
 	struct ShaderData {
 		Map<int,Node> node_map;
 		Map<int,Node> node_map;
-		List<Connection> connections;
+		GraphError error;
 	} shader[3];
 	} 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:
 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_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_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;
 	Point2 node_get_pos(ShaderType p_which,int p_id) const;
 
 
 	void get_node_list(ShaderType p_which,List<int> *p_node_list) 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;
 	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();
 	~ShaderGraph();
 };
 };
 
 
@@ -192,6 +376,27 @@ public:
 
 
 
 
 VARIANT_ENUM_CAST( ShaderGraph::NodeType );
 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
 #endif // SHADER_GRAPH_H

+ 0 - 3
servers/visual/shader_graph.h

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

+ 10 - 7
tools/SCsub

@@ -5,13 +5,16 @@ env.add_source_files(env.tool_sources,"*.cpp")
 
 
 Export('env')
 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)
 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;
 					arginfo=E->get().return_val;
 					if (arginfo.type==Variant::NIL)
 					if (arginfo.type==Variant::NIL)
 						continue;
 						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 {
 				} else {
 
 

+ 3 - 1
tools/editor/editor_node.cpp

@@ -75,6 +75,7 @@
 #include "plugins/tile_map_editor_plugin.h"
 #include "plugins/tile_map_editor_plugin.h"
 #include "plugins/cube_grid_theme_editor_plugin.h"
 #include "plugins/cube_grid_theme_editor_plugin.h"
 #include "plugins/shader_editor_plugin.h"
 #include "plugins/shader_editor_plugin.h"
+#include "plugins/shader_graph_editor_plugin.h"
 #include "plugins/path_editor_plugin.h"
 #include "plugins/path_editor_plugin.h"
 #include "plugins/rich_text_editor_plugin.h"
 #include "plugins/rich_text_editor_plugin.h"
 #include "plugins/collision_polygon_editor_plugin.h"
 #include "plugins/collision_polygon_editor_plugin.h"
@@ -3245,7 +3246,7 @@ EditorNode::EditorNode() {
 	gui_base->set_area_as_parent_rect();
 	gui_base->set_area_as_parent_rect();
 
 
 
 
-	Ref<Theme> theme( memnew( Theme ) );
+	theme = Ref<Theme>( memnew( Theme ) );
 	gui_base->set_theme( theme );
 	gui_base->set_theme( theme );
 	editor_register_icons(theme);
 	editor_register_icons(theme);
 	editor_register_fonts(theme);
 	editor_register_fonts(theme);
@@ -4016,6 +4017,7 @@ EditorNode::EditorNode() {
 	add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
 	add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
 	add_editor_plugin( memnew( EditorHelpPlugin(this) ) );
 	add_editor_plugin( memnew( EditorHelpPlugin(this) ) );
 	add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) );
 	add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) );
+	add_editor_plugin( memnew( ShaderGraphEditorPlugin(this) ) );
 	add_editor_plugin( memnew( ShaderEditorPlugin(this) ) );
 	add_editor_plugin( memnew( ShaderEditorPlugin(this) ) );
 	add_editor_plugin( memnew( CameraEditorPlugin(this) ) );
 	add_editor_plugin( memnew( CameraEditorPlugin(this) ) );
 	add_editor_plugin( memnew( SampleEditorPlugin(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;
 	AcceptDialog *load_error_dialog;
 
 
 	Control *scene_root_base;
 	Control *scene_root_base;
+	Ref<Theme> theme;
 
 
 	PopupMenu *recent_scenes;
 	PopupMenu *recent_scenes;
 	Button *property_back;
 	Button *property_back;
@@ -472,6 +473,9 @@ public:
 
 
 	void stop_child_process();
 	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);
 	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();
 	static void register_editor_types();

BIN
tools/editor/icons/icon_canvas_item_shader.png


BIN
tools/editor/icons/icon_canvas_item_shader_graph.png


BIN
tools/editor/icons/icon_material_shader.png


BIN
tools/editor/icons/icon_material_shader_graph.png


+ 2 - 0
tools/editor/plugins/collision_polygon_2d_editor_plugin.cpp

@@ -398,11 +398,13 @@ CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) {
 	add_child(button_create);
 	add_child(button_create);
 	button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
 	button_create->connect("pressed",this,"_menu_option",varray(MODE_CREATE));
 	button_create->set_toggle_mode(true);
 	button_create->set_toggle_mode(true);
+	button_create->set_tooltip("Create a new polygon from scratch");
 
 
 	button_edit = memnew( ToolButton );
 	button_edit = memnew( ToolButton );
 	add_child(button_edit);
 	add_child(button_edit);
 	button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
 	button_edit->connect("pressed",this,"_menu_option",varray(MODE_EDIT));
 	button_edit->set_toggle_mode(true);
 	button_edit->set_toggle_mode(true);
+	button_edit->set_tooltip("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point.");
 
 
 	//add_constant_override("separation",0);
 	//add_constant_override("separation",0);
 
 

+ 1193 - 848
tools/editor/plugins/shader_graph_editor_plugin.cpp

@@ -28,1082 +28,1427 @@
 /*************************************************************************/
 /*************************************************************************/
 #include "shader_graph_editor_plugin.h"
 #include "shader_graph_editor_plugin.h"
 
 
-#if 0
+
 #include "scene/gui/menu_button.h"
 #include "scene/gui/menu_button.h"
 #include "scene/gui/panel.h"
 #include "scene/gui/panel.h"
+#include "spatial_editor_plugin.h"
+
+////cbacks
+///
+void ShaderGraphView::_scalar_const_changed(double p_value,int p_id) {
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Scalar Constant",true);
+	ur->add_do_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,p_value);
+	ur->add_undo_method(graph.ptr(),"scalar_const_node_set_value",type,p_id,graph->scalar_const_node_get_value(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+}
 
 
-class _ShaderTester : public ShaderCodeGenerator {
-public:
-
-	Set<int> *_set;
-
-	virtual void begin() {}
-	virtual Error add_node(VS::ShaderNodeType p_type,int p_node_pos,int p_id,const Variant& p_param,const Vector<int>& p_in_connections,const Vector<int>& p_out_connections,const Vector<int>& p_out_connection_outputs) { if (_set) _set->insert(p_id); return OK; }
-	virtual void end() {}
-
-	_ShaderTester() { _set=NULL; }
-};
+void ShaderGraphView::_vec_const_changed(double p_value, int p_id,Array p_arr){
 
 
+	Vector3 val;
+	for(int i=0;i<p_arr.size();i++) {
+		val[i]=p_arr[i].call("get_val");
+	}
 
 
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Vec Constant",true);
+	ur->add_do_method(graph.ptr(),"vec_const_node_set_value",type,p_id,val);
+	ur->add_undo_method(graph.ptr(),"vec_const_node_set_value",type,p_id,graph->vec_const_node_get_value(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
-void ShaderEditor::edit(Ref<Shader> p_shader) {
+}
+void ShaderGraphView::_rgb_const_changed(const Color& p_color, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change RGB Constant",true);
+	ur->add_do_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,p_color);
+	ur->add_undo_method(graph.ptr(),"rgb_const_node_set_value",type,p_id,graph->rgb_const_node_get_value(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
+}
+void ShaderGraphView::_scalar_op_changed(int p_op, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Scalar Operator");
+	ur->add_do_method(graph.ptr(),"scalar_op_node_set_op",type,p_id,p_op);
+	ur->add_undo_method(graph.ptr(),"scalar_op_node_set_op",type,p_id,graph->scalar_op_node_get_op(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
-	shader=p_shader;
+}
+void ShaderGraphView::_vec_op_changed(int p_op, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Vec Operator");
+	ur->add_do_method(graph.ptr(),"vec_op_node_set_op",type,p_id,p_op);
+	ur->add_undo_method(graph.ptr(),"vec_op_node_set_op",type,p_id,graph->vec_op_node_get_op(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+}
+void ShaderGraphView::_vec_scalar_op_changed(int p_op, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change VecxScalar Operator");
+	ur->add_do_method(graph.ptr(),"vec_scalar_op_node_set_op",type,p_id,p_op);
+	ur->add_undo_method(graph.ptr(),"vec_scalar_op_node_set_op",type,p_id,graph->vec_scalar_op_node_get_op(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
-	if (shader.is_null())
-		hide();
-	else {
-		_read_shader_graph();
-	}
+}
+void ShaderGraphView::_rgb_op_changed(int p_op, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change RGB Operator");
+	ur->add_do_method(graph.ptr(),"rgb_op_node_set_op",type,p_id,p_op);
+	ur->add_undo_method(graph.ptr(),"rgb_op_node_set_op",type,p_id,graph->rgb_op_node_get_op(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+}
+void ShaderGraphView::_xform_inv_rev_changed(bool p_enabled, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Toggle Rot Only");
+	ur->add_do_method(graph.ptr(),"xform_vec_mult_node_set_no_translation",type,p_id,p_enabled);
+	ur->add_undo_method(graph.ptr(),"xform_vec_mult_node_set_no_translation",type,p_id,graph->xform_vec_mult_node_get_no_translation(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+}
+void ShaderGraphView::_scalar_func_changed(int p_func, int p_id){
+
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Scalar Function");
+	ur->add_do_method(graph.ptr(),"scalar_func_node_set_function",type,p_id,p_func);
+	ur->add_undo_method(graph.ptr(),"scalar_func_node_set_function",type,p_id,graph->scalar_func_node_get_function(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+}
+void ShaderGraphView::_vec_func_changed(int p_func, int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Vec Function");
+	ur->add_do_method(graph.ptr(),"vec_func_node_set_function",type,p_id,p_func);
+	ur->add_undo_method(graph.ptr(),"vec_func_node_set_function",type,p_id,graph->vec_func_node_get_function(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
 }
 }
+void ShaderGraphView::_scalar_input_changed(double p_value,int p_id){
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Scalar Uniform",true);
+	ur->add_do_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,p_value);
+	ur->add_undo_method(graph.ptr(),"scalar_input_node_set_value",type,p_id,graph->scalar_input_node_get_value(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
-Size2 ShaderEditor::_get_maximum_size() {
+}
+void ShaderGraphView::_vec_input_changed(double p_value, int p_id,Array p_arr){
 
 
-	Size2 max;
+	Vector3 val;
+	for(int i=0;i<p_arr.size();i++) {
+		val[i]=p_arr[i].call("get_val");
+	}
 
 
-	for(List<int>::Element *E=order.front();E;E=E->next()) {
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Vec Uniform",true);
+	ur->add_do_method(graph.ptr(),"vec_input_node_set_value",type,p_id,val);
+	ur->add_undo_method(graph.ptr(),"vec_input_node_set_value",type,p_id,graph->vec_input_node_get_value(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
-		Point2 pos = Point2( shader_graph.node_get_pos_x(E->get()), shader_graph.node_get_pos_y(E->get()) );
+}
+void ShaderGraphView::_xform_input_changed(int p_id, Node *p_button){
 
 
-		if (click_type==CLICK_NODE && click_node==E->get()) {
+	print_line("XFIC");
+	ToolButton *tb = p_button->cast_to<ToolButton>();
+	ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
+	ped_popup->set_size(tb->get_size());
+	edited_id=p_id;
+	ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_input_node_get_value(type,p_id),PROPERTY_HINT_NONE,"");
+	ped_popup->popup();
 
 
-			pos+=click_motion-click_pos;
-		}
-		pos+=get_node_size(E->get());
-		if (pos.x>max.x)
-			max.x=pos.x;
-		if (pos.y>max.y)
-			max.y=pos.y;
+}
+void ShaderGraphView::_xform_const_changed(int p_id, Node *p_button){
 
 
-	}
+	ToolButton *tb = p_button->cast_to<ToolButton>();
+	ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
+	ped_popup->set_size(tb->get_size());
+	edited_id=p_id;
+	ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_const_node_get_value(type,p_id),PROPERTY_HINT_NONE,"");
+	ped_popup->popup();
 
 
-	return max;
 }
 }
 
 
-Size2 ShaderEditor::get_node_size(int p_node) const {
+void ShaderGraphView::_rgb_input_changed(const Color& p_color, int p_id){
 
 
-	VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node);
-	Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
-	Ref<Font> font = get_font("font","PopupMenu");
-	Color font_color = get_color("font_color","PopupMenu");
 
 
-	Size2 size = style->get_minimum_size();
-
-	int count=1; // title
-	count += VisualServer::shader_get_input_count( type) + VisualServer::shader_get_output_count( type);
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change RGB Uniform",true);
+	ur->add_do_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,p_color);
+	ur->add_undo_method(graph.ptr(),"rgb_input_node_set_value",type,p_id,graph->rgb_input_node_get_value(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+}
+void ShaderGraphView::_tex_input_change(int p_id, Node *p_button){
 
 
-	float max_w=font->get_string_size( VisualServer::shader_node_get_type_info(type).name ).width;
 
 
-	for(int i=0;i<VisualServer::shader_get_input_count(type);i++)
-		max_w = MAX( max_w, font->get_string_size( VisualServer::shader_get_input_name(type,i) ).width );
+}
+void ShaderGraphView::_cube_input_change(int p_id){
 
 
 
 
-	for(int i=0;i<VisualServer::shader_get_output_count(type);i++)
-		max_w = MAX( max_w, font->get_string_size( VisualServer::shader_get_output_name(type,i) ).width );
+}
 
 
+void ShaderGraphView::_variant_edited() {
 
 
+	if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_CONST) {
 
 
+		UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+		ur->create_action("Change XForm Uniform");
+		ur->add_do_method(graph.ptr(),"xform_const_node_set_value",type,edited_id,ped_popup->get_variant());
+		ur->add_undo_method(graph.ptr(),"xform_const_node_set_value",type,edited_id,graph->xform_const_node_get_value(type,edited_id));
+		ur->add_do_method(this,"_update_graph");
+		ur->add_undo_method(this,"_update_graph");
+		ur->commit_action();
+	}
 
 
-	switch(type) {
 
 
-		case VS::NODE_IN:
-		case VS::NODE_OUT:
-		case VS::NODE_VEC_IN:
-		case VS::NODE_VEC_OUT:
-		case VS::NODE_PARAMETER:
-		case VS::NODE_VEC_PARAMETER:
-		case VS::NODE_COLOR_PARAMETER:
-		case VS::NODE_TEXTURE_PARAMETER:
-		case VS::NODE_TEXTURE_2D_PARAMETER:
-		case VS::NODE_TEXTURE_CUBE_PARAMETER:
-		case VS::NODE_TRANSFORM_PARAMETER:
-		case VS::NODE_LABEL: {
+	if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_INPUT) {
 
 
-			max_w=MAX( max_w, font->get_string_size( shader_graph.node_get_param(p_node) ).width );
-			count++;
-		} break;
-		case VS::NODE_TIME:
-		case VS::NODE_CONSTANT:
-		case VS::NODE_VEC_CONSTANT:
-		case VS::NODE_COLOR_CONSTANT:
-		case VS::NODE_TRANSFORM_CONSTANT: {
-			count++;
-		} break;
-		case VS::NODE_TEXTURE:
-		case VS::NODE_VEC_TEXTURE_2D:
-		case VS::NODE_VEC_TEXTURE_CUBE: {
+		UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+		ur->create_action("Change XForm Uniform");
+		ur->add_do_method(graph.ptr(),"xform_input_node_set_value",type,edited_id,ped_popup->get_variant());
+		ur->add_undo_method(graph.ptr(),"xform_input_node_set_value",type,edited_id,graph->xform_input_node_get_value(type,edited_id));
+		ur->add_do_method(this,"_update_graph");
+		ur->add_undo_method(this,"_update_graph");
+		ur->commit_action();
+	}
 
 
-			RefPtr res = shader_graph.node_get_param(p_node);
-			Ref<Texture> texture = res;
-			if (texture.is_null() || texture->get_width()==0) {
+	if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_TEXTURE_INPUT) {
 
 
-				size.y+=max_w;
-			} else {
+		UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+		ur->create_action("Change Texture Uniform");
+		ur->add_do_method(graph.ptr(),"texture_input_node_set_value",type,edited_id,ped_popup->get_variant());
+		ur->add_undo_method(graph.ptr(),"texture_input_node_set_value",type,edited_id,graph->texture_input_node_get_value(type,edited_id));
+		ur->add_do_method(this,"_update_graph");
+		ur->add_undo_method(this,"_update_graph");
+		ur->commit_action();
+	}
 
 
-				size.y+=max_w * texture->get_height() / texture->get_width();
-			}
-		} break;
-		default: {}
+	if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_CUBEMAP_INPUT) {
 
 
+		UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+		ur->create_action("Change Cubemap Uniform");
+		ur->add_do_method(graph.ptr(),"cubemap_input_node_set_value",type,edited_id,ped_popup->get_variant());
+		ur->add_undo_method(graph.ptr(),"cubemap_input_node_set_value",type,edited_id,graph->cubemap_input_node_get_value(type,edited_id));
+		ur->add_do_method(this,"_update_graph");
+		ur->add_undo_method(this,"_update_graph");
+		ur->commit_action();
 	}
 	}
 
 
-	size.x+=max_w;
-	size.y+=count*(font->get_height()+get_constant("vseparation","PopupMenu"));
-
-	return size;
 }
 }
 
 
+void ShaderGraphView::_comment_edited(int p_id,Node* p_button) {
 
 
-Error ShaderEditor::validate_graph() {
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	TextEdit *te=p_button->cast_to<TextEdit>();
+	ur->create_action("Change Comment",true);
+	ur->add_do_method(graph.ptr(),"comment_node_set_text",type,p_id,te->get_text());
+	ur->add_undo_method(graph.ptr(),"comment_node_set_text",type,p_id,graph->comment_node_get_text(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
 
 
-	_ShaderTester st;
-	active_nodes.clear();
-	st._set=&active_nodes;
-	return shader_graph.generate(&st);
 }
 }
 
 
-void ShaderEditor::_draw_node(int p_node) {
 
 
-	VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node);
-	Ref<StyleBox> style = active_nodes.has(p_node)?get_stylebox("panel","PopupMenu"):get_stylebox("panel_disabled","PopupMenu");
-	Ref<Font> font = get_font("font","PopupMenu");
-	Color font_color = get_color("font_color","PopupMenu");
-	Color font_color_title = get_color("font_color_hover","PopupMenu");
-	Size2 size=get_node_size(p_node);
-	Point2 pos = Point2( shader_graph.node_get_pos_x(p_node), shader_graph.node_get_pos_y(p_node) )-offset;
+void ShaderGraphView::_input_name_changed(const String& p_name, int p_id, Node *p_line_edit) {
 
 
-	if (click_type==CLICK_NODE && click_node==p_node) {
+	LineEdit *le=p_line_edit->cast_to<LineEdit>();
+	ERR_FAIL_COND(!le);
 
 
-		pos+=click_motion-click_pos;
-	}
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Change Input Name");
+	ur->add_do_method(graph.ptr(),"input_node_set_name",type,p_id,p_name);
+	ur->add_undo_method(graph.ptr(),"input_node_set_name",type,p_id,graph->input_node_get_name(type,p_id));
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	block_update=true;
+	ur->commit_action();
+	block_update=false;
+	le->set_text(graph->input_node_get_name(type,p_id));
+}
 
 
-	RID ci = get_canvas_item();
-	style->draw(ci,Rect2(pos,size));
+void ShaderGraphView::_tex_edited(int p_id,Node* p_button) {
 
 
-	Point2 ofs=style->get_offset()+pos;
-	Point2 ascent=Point2(0,font->get_ascent());
-	float w = size.width-style->get_minimum_size().width;
-	float h = font->get_height()+get_constant("vseparation","PopupMenu");
+	ToolButton *tb = p_button->cast_to<ToolButton>();
+	ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
+	ped_popup->set_size(tb->get_size());
+	edited_id=p_id;
+	ped_popup->edit(NULL,"",Variant::OBJECT,graph->texture_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"Texture");
+}
 
 
-	font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, VisualServer::shader_node_get_type_info(type).name,font_color_title);
-	ofs.y+=h;
+void ShaderGraphView::_cube_edited(int p_id,Node* p_button) {
 
 
-	Ref<Texture> vec_icon = get_icon("NodeVecSlot","EditorIcons");
-	Ref<Texture> real_icon = get_icon("NodeRealSlot","EditorIcons");
-	float icon_h_ofs = Math::floor(( font->get_height()-vec_icon->get_height())/2.0 )+1;
+	ToolButton *tb = p_button->cast_to<ToolButton>();
+	ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
+	ped_popup->set_size(tb->get_size());
+	edited_id=p_id;
+	ped_popup->edit(NULL,"",Variant::OBJECT,graph->cubemap_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"CubeMap");
+}
 
 
 
 
-	for(int i=0;i<VisualServer::shader_get_input_count(type);i++) {
+//////////////view/////////////
 
 
-		String name = VisualServer::shader_get_input_name(type,i);
-		font->draw_halign( ci, ofs+ascent, HALIGN_LEFT,w, name,font_color);
-		Ref<Texture> icon = VisualServer::shader_is_input_vector(type,i)?vec_icon:real_icon;
-		icon->draw(ci,ofs+Point2(-real_icon->get_width(),icon_h_ofs));
-		ofs.y+=h;
-	}
 
 
-	for(int i=0;i<VisualServer::shader_get_output_count(type);i++) {
+void ShaderGraphView::_connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot) {
 
 
-		String name = VisualServer::shader_get_output_name(type,i);
-		font->draw_halign( ci, ofs+ascent, HALIGN_RIGHT,w, name,font_color);
-		Ref<Texture> icon = VisualServer::shader_is_output_vector(type,i)?vec_icon:real_icon;
-		icon->draw(ci,ofs+Point2(w,icon_h_ofs));
-		ofs.y+=h;
-	}
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
 
 
-	switch(type) {
-
-		case VS::NODE_IN:
-		case VS::NODE_OUT:
-		case VS::NODE_PARAMETER:
-		case VS::NODE_VEC_IN:
-		case VS::NODE_COLOR_PARAMETER:
-		case VS::NODE_VEC_OUT:
-		case VS::NODE_TEXTURE_PARAMETER:
-		case VS::NODE_TEXTURE_2D_PARAMETER:
-		case VS::NODE_TEXTURE_CUBE_PARAMETER:
-		case VS::NODE_TRANSFORM_CONSTANT:
-		case VS::NODE_TRANSFORM_PARAMETER:
-		case VS::NODE_VEC_PARAMETER:
-		case VS::NODE_LABEL: {
-			String text = shader_graph.node_get_param(p_node);
-			font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color);
-		} break;
-		case VS::NODE_TIME:
-		case VS::NODE_CONSTANT: {
-			String text = rtos(shader_graph.node_get_param(p_node));
-			font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color);
-
-		} break;
-		case VS::NODE_VEC_CONSTANT: {
-			String text = Vector3(shader_graph.node_get_param(p_node));
-			font->draw_halign( ci, ofs+ascent, HALIGN_CENTER,w, text,font_color);
-		} break;
-		case VS::NODE_COLOR_CONSTANT: {
-
-			Color color = shader_graph.node_get_param(p_node);
-			Rect2 r(ofs,Size2(w,h));
-			VisualServer::get_singleton()->canvas_item_add_rect(ci,r,color);
-		} break;
-		case VS::NODE_TEXTURE:
-		case VS::NODE_VEC_TEXTURE_2D:
-		case VS::NODE_VEC_TEXTURE_CUBE: {
-
-			Rect2 r(ofs,Size2(w,(pos.y+size.y-style->get_margin(MARGIN_BOTTOM))-ofs.y));
-			Vector<Point2> points;
-			Vector<Point2> uvs;
-			points.resize(4);
-			uvs.resize(4);
-			points[0]=r.pos;
-			points[1]=r.pos+Point2(r.size.x,0);
-			points[2]=r.pos+r.size;
-			points[3]=r.pos+Point2(0,r.size.y);
-			uvs[0]=Point2(0,0);
-			uvs[1]=Point2(1,0);
-			uvs[2]=Point2(1,1);
-			uvs[3]=Point2(0,1);
-
-			Ref<Texture> texture = shader_graph.node_get_param(p_node).operator RefPtr();
-			if (texture.is_null() || texture->get_width()==0) {
-				texture=get_icon("Click2Edit","EditorIcons");
-			}
+	int from_idx=-1;
+	int to_idx=-1;
+	for (Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
 
 
-			VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector<Color>(),uvs,texture->get_rid());
-		} break;
-		default: {}
+		if (p_from==E->get()->get_name())
+			from_idx=E->key();
+		if (p_to==E->get()->get_name())
+			to_idx=E->key();
 	}
 	}
-}
-
-void ShaderEditor::_node_param_changed() {
-
-	shader_graph.node_set_param( click_node,property_editor->get_variant() );
-	update();
-	_write_shader_graph();
-}
-
-ShaderEditor::ClickType ShaderEditor::_locate_click(const Point2& p_click,int *p_node_id,int *p_slot_index) const {
-
-	Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
-	Ref<Texture> real_icon = get_icon("NodeRealSlot","EditorIcons");
-	Ref<Font> font = get_font("font","PopupMenu");
-	float h = font->get_height()+get_constant("vseparation","PopupMenu");
-	float extra_left=MAX( real_icon->get_width()-style->get_margin(MARGIN_LEFT), 0 );
-	float extra_right=MAX( real_icon->get_width()-style->get_margin(MARGIN_RIGHT), 0 );
 
 
+	ERR_FAIL_COND(from_idx==-1);
+	ERR_FAIL_COND(to_idx==-1);
 
 
-	for(const List<int>::Element *E=order.back();E;E=E->prev()) {
+	ur->create_action("Connect Graph Nodes");
 
 
-		Size2 size=get_node_size(E->get());
-		size.width+=extra_left+extra_right;
-		Point2 pos = Point2( shader_graph.node_get_pos_x(E->get()), shader_graph.node_get_pos_y(E->get()) )-offset;
-		pos.x-=extra_left;
+	List<ShaderGraph::Connection> conns;
 
 
-		Rect2 rect( pos, size );
-		if (!rect.has_point(p_click))
-			continue;
-		VisualServer::ShaderNodeType type=shader_graph.node_get_type(E->get());
-		if (p_node_id)
-			*p_node_id=E->get();
-		float y=p_click.y-(pos.y+style->get_margin(MARGIN_TOP));
-		if (y<h)
-			return CLICK_NODE;
-		y-=h;
-
-		for(int i=0;i<VisualServer::shader_get_input_count(type);i++) {
-
-			if (y<h) {
-				if (p_slot_index)
-					*p_slot_index=i;
-				return CLICK_INPUT_SLOT;
-			}
-			y-=h;
-		}
+	graph->get_node_connections(type,&conns);
+	//disconnect/reconnect dependencies
+	ur->add_undo_method(graph.ptr(),"disconnect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+	for(List<ShaderGraph::Connection>::Element *E=conns.front();E;E=E->next()) {
 
 
-		for(int i=0;i<VisualServer::shader_get_output_count(type);i++) {
-
-			if (y<h) {
-				if (p_slot_index)
-					*p_slot_index=i;
-				return CLICK_OUTPUT_SLOT;
-			}
-			y-=h;
+		if (E->get().dst_id==to_idx && E->get().dst_slot==p_to_slot) {
+			ur->add_do_method(graph.ptr(),"disconnect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot);
+			ur->add_undo_method(graph.ptr(),"connect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot);
 		}
 		}
-
-		if (p_click.y<(rect.pos.y+rect.size.height-style->get_margin(MARGIN_BOTTOM)))
-			return CLICK_PARAMETER;
-		else
-			return CLICK_NODE;
-
 	}
 	}
+	ur->add_do_method(graph.ptr(),"connect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	ur->commit_action();
 
 
-	return CLICK_NONE;
 
 
 }
 }
 
 
-Point2 ShaderEditor::_get_slot_pos(int p_node_id,bool p_input,int p_slot) {
+void ShaderGraphView::_node_removed(int p_id) {
 
 
-	Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
-	float w = get_node_size(p_node_id).width;
-	Ref<Font> font = get_font("font","PopupMenu");
-	float h = font->get_height()+get_constant("vseparation","PopupMenu");
-	Ref<Texture> vec_icon = get_icon("NodeVecSlot","EditorIcons");
-	Point2 pos = Point2( shader_graph.node_get_pos_x(p_node_id), shader_graph.node_get_pos_y(p_node_id) )-offset;
-	pos+=style->get_offset();
-	pos.y+=h;
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Remove Shader Graph Node");
 
 
-	if(p_input) {
+	ur->add_do_method(graph.ptr(),"node_remove",type,p_id);
+	ur->add_undo_method(graph.ptr(),"node_add",type,graph->node_get_type(type,p_id),p_id);
+	ur->add_undo_method(graph.ptr(),"node_set_state",type,p_id,graph->node_get_state(type,p_id));
+	List<ShaderGraph::Connection> conns;
 
 
-		pos.y+=p_slot*h;
-		pos+=Point2( -vec_icon->get_width()/2.0, h/2.0).floor();
-		return pos;
-	} else {
+	graph->get_node_connections(type,&conns);
+	for(List<ShaderGraph::Connection>::Element *E=conns.front();E;E=E->next()) {
 
 
-		pos.y+=VisualServer::shader_get_input_count( shader_graph.node_get_type(p_node_id ) )*h;
+		if (E->get().dst_id==p_id || E->get().src_id==p_id) {
+			ur->add_undo_method(graph.ptr(),"connect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot);
+		}
 	}
 	}
-
-	pos.y+=p_slot*h;
-	pos+=Point2( w-style->get_minimum_size().width+vec_icon->get_width()/2.0, h/2.0).floor();
-
-	return pos;
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	ur->commit_action();
 
 
 }
 }
 
 
-void ShaderEditor::_node_edit_property(int p_node) {
-
-	Ref<StyleBox> style = get_stylebox("panel","PopupMenu");
-	Size2 size = get_node_size(p_node);
-	Point2 pos = Point2( shader_graph.node_get_pos_x(p_node), shader_graph.node_get_pos_y(p_node) )-offset;
-
-	VisualServer::ShaderNodeType type=shader_graph.node_get_type(p_node);
-
-	PropertyInfo ph = VisualServer::get_singleton()->shader_node_get_type_info(type);
-	if (ph.type==Variant::NIL)
-		return;
-	if (ph.type==Variant::_RID)
-		ph.type=Variant::OBJECT;
-
-	property_editor->edit(NULL,ph.name,ph.type,shader_graph.node_get_param(p_node),ph.hint,ph.hint_string);
-
-	Point2 popup_pos=Point2( pos.x+(size.width-property_editor->get_size().width)/2.0,pos.y+(size.y-style->get_margin(MARGIN_BOTTOM))).floor();
-	popup_pos+=get_global_pos();
-	property_editor->set_pos(popup_pos);
-
-	property_editor->popup();
+void ShaderGraphView::_node_moved(const Vector2& p_from, const Vector2& p_to,int p_id) {
 
 
+	print_line("moved from "+p_from+" to "+p_to);
+	ERR_FAIL_COND(!node_map.has(p_id));
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Move Shader Graph Node");
+	ur->add_do_method(this,"_move_node",p_id,p_to);
+	ur->add_undo_method(this,"_move_node",p_id,p_from);
+	ur->commit_action();
 }
 }
 
 
-bool ShaderEditor::has_point(const Point2& p_point) const {
-
-	int n,si;
+void ShaderGraphView::_move_node(int p_id,const Vector2& p_to) {
 
 
-	return _locate_click(p_point,&n,&si)!=CLICK_NONE;
+	ERR_FAIL_COND(!node_map.has(p_id));
+	node_map[p_id]->set_offset(p_to);
+	graph->node_set_pos(type,p_id,p_to);
 }
 }
 
 
-void ShaderEditor::_input_event(InputEvent p_event) {
-
-	switch(p_event.type) {
-
-		case InputEvent::MOUSE_BUTTON: {
-
-			if (p_event.mouse_button.pressed) {
-
-
-				if (p_event.mouse_button.button_index==1) {
-					click_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
-					click_motion=click_pos;
-					click_type = _locate_click(click_pos,&click_node,&click_slot);
-					if( click_type!=CLICK_NONE) {
-
-						order.erase(click_node);
-						order.push_back(click_node);
-						update();
-					}
-					switch(click_type) {
-						case CLICK_INPUT_SLOT: {
-							click_pos=_get_slot_pos(click_node,true,click_slot);
-						} break;
-						case CLICK_OUTPUT_SLOT: {
-							click_pos=_get_slot_pos(click_node,false,click_slot);
-						} break;
-						case CLICK_PARAMETER: {
-							//open editor
-							_node_edit_property(click_node);
-						} break;
-					}
-				}
-				if (p_event.mouse_button.button_index==2) {
-
-					if (click_type!=CLICK_NONE) {
-						click_type=CLICK_NONE;
-						update();
-					} else {
-						// try to disconnect/remove
-
-						Point2 rclick_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
-						rclick_type = _locate_click(rclick_pos,&rclick_node,&rclick_slot);
-						if (rclick_type==CLICK_INPUT_SLOT || rclick_type==CLICK_OUTPUT_SLOT) {
 
 
-							node_popup->clear();
-							node_popup->add_item("Disconnect",NODE_DISCONNECT);
-							node_popup->set_pos(rclick_pos);
-							node_popup->popup();
+void ShaderGraphView::_create_node(int p_id) {
 
 
-						}
 
 
-						if (rclick_type==CLICK_NODE) {
-							node_popup->clear();
-							node_popup->add_item("Remove",NODE_ERASE);
-							node_popup->set_pos(rclick_pos);
-							node_popup->popup();
-						}
+	GraphNode *gn = memnew( GraphNode );
+	gn->set_show_close_button(true);
+	Color typecol[4]={
+		Color(0.2,1,0.2),
+		Color(0.7,0.1,1),
+		Color(1,0.2,0.2),
+		Color(0,1,1)
+	};
 
 
 
 
-					}
-				}
-			} else {
-
-				if (p_event.mouse_button.button_index==1 && click_type!=CLICK_NONE) {
-
-					switch(click_type) {
-						case CLICK_INPUT_SLOT:
-						case CLICK_OUTPUT_SLOT: {
-
-							Point2 dst_click_pos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
-							int id;
-							int slot;
-							ClickType dst_click_type = _locate_click(dst_click_pos,&id,&slot);
-							if (dst_click_type==CLICK_INPUT_SLOT && click_type==CLICK_OUTPUT_SLOT) {
-
-								shader_graph.connect(click_node,click_slot,id,slot);
-
-								Error err = validate_graph();
-								if (err==ERR_CYCLIC_LINK)
-									shader_graph.disconnect(click_node,click_slot,id,slot);
-								_write_shader_graph();
+	switch(graph->node_get_type(type,p_id)) {
 
 
-							}
-							if (click_type==CLICK_INPUT_SLOT && dst_click_type==CLICK_OUTPUT_SLOT) {
+		case ShaderGraph::NODE_INPUT: {
 
 
-								shader_graph.connect(id,slot,click_node,click_slot);
+			gn->set_title("Input");
 
 
-								Error err = validate_graph();
-								if (err==ERR_CYCLIC_LINK)
-									shader_graph.disconnect(id,slot,click_node,click_slot);
-								_write_shader_graph();
-							}
+			List<ShaderGraph::SlotInfo> si;
+			ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si);
 
 
-						} break;
-						case CLICK_NODE: {
-							int new_x=shader_graph.node_get_pos_x(click_node)+(click_motion.x-click_pos.x);
-							int new_y=shader_graph.node_get_pos_y(click_node)+(click_motion.y-click_pos.y);
-							shader_graph.node_set_pos(click_node,new_x,new_y);
-							_write_shader_graph();
+			int idx=0;
+			for (List<ShaderGraph::SlotInfo>::Element *E=si.front();E;E=E->next()) {
+				ShaderGraph::SlotInfo& s=E->get();
+				if (s.dir==ShaderGraph::SLOT_IN) {
 
 
-						} break;
-					}
-
-					click_type=CLICK_NONE;
-					update();
+					Label *l= memnew( Label );
+					l->set_text(s.name);
+					l->set_align(Label::ALIGN_RIGHT);
+					gn->add_child(l);
+					gn->set_slot(idx,false,0,Color(),true,s.type,typecol[s.type]);
+					idx++;
 				}
 				}
 			}
 			}
 
 
-		}
-
-		case InputEvent::MOUSE_MOTION: {
-
-			if (p_event.mouse_motion.button_mask&1 && click_type!=CLICK_NONE) {
+		} break; // all inputs (case Shader type dependent)
+		case ShaderGraph::NODE_SCALAR_CONST: {
+			gn->set_title("Scalar");
+			SpinBox *sb = memnew( SpinBox );
+			sb->set_min(-100000);
+			sb->set_max(100000);
+			sb->set_step(0.001);
+			sb->set_val(graph->scalar_const_node_get_value(type,p_id));
+			sb->connect("value_changed",this,"_scalar_const_changed",varray(p_id));
+			gn->add_child(sb);
+			gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; //scalar constant
+		case ShaderGraph::NODE_VEC_CONST: {
+
+			gn->set_title("Vector");
+			Array v3p(true);
+			for(int i=0;i<3;i++) {
+				HBoxContainer *hbc = memnew( HBoxContainer );
+				Label *l = memnew( Label );
+				l->set_text(String::chr('X'+i));
+				hbc->add_child(l);
+				SpinBox *sb = memnew( SpinBox );
+				sb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+				sb->set_min(-100000);
+				sb->set_max(100000);
+				sb->set_step(0.001);
+				sb->set_val(graph->vec_const_node_get_value(type,p_id)[i]);
+				sb->connect("value_changed",this,"_vec_const_changed",varray(p_id,v3p));
+				v3p.push_back(sb);
+				hbc->add_child(sb);
+				gn->add_child(hbc);
+			}
+			gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+		} break; //vec3 constant
+		case ShaderGraph::NODE_RGB_CONST: {
+
+			gn->set_title("Color");
+			ColorPickerButton *cpb = memnew( ColorPickerButton );
+			cpb->set_color(graph->rgb_const_node_get_value(type,p_id));
+			cpb->connect("color_changed",this,"_rgb_const_changed",varray(p_id));
+			gn->add_child(cpb);
+			Label *l = memnew( Label );
+			l->set_text("RGB");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+			l = memnew( Label );
+			l->set_text("Alpha");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+
+			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; //rgb constant (shows a color picker instead)
+		case ShaderGraph::NODE_XFORM_CONST: {
+			gn->set_title("XForm");
+			ToolButton *edit = memnew( ToolButton );
+			edit->set_text("edit..");
+			edit->connect("pressed",this,"_xform_const_changed",varray(p_id,edit));
+			gn->add_child(edit);
+			gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+
+		} break; // 4x4 matrix constant
+		case ShaderGraph::NODE_TIME: {
+
+			gn->set_title("Time");
+			Label *l = memnew( Label );
+			l->set_text("(s)");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+			gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; // time in seconds
+		case ShaderGraph::NODE_SCREEN_TEX: {
+
+			gn->set_title("ScreenTex");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("UV")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("RGB")));
+			gn->add_child(hbc);
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+		} break; // screen texture sampler (takes UV) (only usable in fragment case Shader)
+		case ShaderGraph::NODE_SCALAR_OP: {
+
+			gn->set_title("ScalarOp");
+			static const char* op_name[ShaderGraph::SCALAR_MAX_OP]={
+				"Add",
+				"Sub",
+				"Mul",
+				"Div",
+				"Mod",
+				"Pow",
+				"Max",
+				"Min",
+				"Atan2"
+			};
+
+			OptionButton *ob = memnew( OptionButton );
+			for(int i=0;i<ShaderGraph::SCALAR_MAX_OP;i++) {
+
+				ob->add_item(op_name[i],i);
+			}
 
 
-				click_motion=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
-				update();
+			ob->select(graph->scalar_op_node_get_op(type,p_id));
+			ob->connect("item_selected",this,"_scalar_op_changed",varray(p_id));
+			gn->add_child(ob);
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+
+
+		} break; // scalar vs scalar op (mul: { } break; add: { } break; div: { } break; etc)
+		case ShaderGraph::NODE_VEC_OP: {
+
+			gn->set_title("VecOp");
+			static const char* op_name[ShaderGraph::VEC_MAX_OP]={
+				"Add",
+				"Sub",
+				"Mul",
+				"Div",
+				"Mod",
+				"Pow",
+				"Max",
+				"Min",
+				"Cross"
+			};
+
+			OptionButton *ob = memnew( OptionButton );
+			for(int i=0;i<ShaderGraph::VEC_MAX_OP;i++) {
+
+				ob->add_item(op_name[i],i);
 			}
 			}
 
 
-		} break;
-	}
-}
+			ob->select(graph->vec_op_node_get_op(type,p_id));
+			ob->connect("item_selected",this,"_vec_op_changed",varray(p_id));
+			gn->add_child(ob);
 
 
-void ShaderEditor::_notification(int p_what) {
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
 
 
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
 
 
-	switch(p_what) {
 
 
-		case NOTIFICATION_DRAW: {
+		} break; // vec3 vs vec3 op (mul: { } break;ad: { } break;div: { } break;crossprod: { } break;etc)
+		case ShaderGraph::NODE_VEC_SCALAR_OP: {
 
 
-			_update_scrollbars();
-			//VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(Point2(),get_size()),Color(0,0,0,1));
+			gn->set_title("VecScalarOp");
+			static const char* op_name[ShaderGraph::VEC_SCALAR_MAX_OP]={
+				"Mul",
+				"Div",
+				"Pow",
+			};
 
 
-			for(List<int>::Element *E=order.front();E;E=E->next()) {
+			OptionButton *ob = memnew( OptionButton );
+			for(int i=0;i<ShaderGraph::VEC_SCALAR_MAX_OP;i++) {
 
 
-				_draw_node(E->get());
+				ob->add_item(op_name[i],i);
 			}
 			}
 
 
-			if (click_type==CLICK_INPUT_SLOT || click_type==CLICK_OUTPUT_SLOT) {
+			ob->select(graph->vec_scalar_op_node_get_op(type,p_id));
+			ob->connect("item_selected",this,"_vec_scalar_op_changed",varray(p_id));
+			gn->add_child(ob);
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+
+
+		} break; // vec3 vs scalar op (mul: { } break; add: { } break; div: { } break; etc)
+		case ShaderGraph::NODE_RGB_OP: {
+
+			gn->set_title("RGB Op");
+			static const char* op_name[ShaderGraph::RGB_MAX_OP]={
+				"Screen",
+				"Difference",
+				"Darken",
+				"Lighten",
+				"Overlay",
+				"Dodge",
+				"Burn",
+				"SoftLight",
+				"HardLight"
+			};
+
+			OptionButton *ob = memnew( OptionButton );
+			for(int i=0;i<ShaderGraph::RGB_MAX_OP;i++) {
+
+				ob->add_item(op_name[i],i);
+			}
 
 
-				VisualServer::get_singleton()->canvas_item_add_line(get_canvas_item(),click_pos,click_motion,Color(0.5,1,0.5,0.8),2);
+			ob->select(graph->rgb_op_node_get_op(type,p_id));
+			ob->connect("item_selected",this,"_rgb_op_changed",varray(p_id));
+			gn->add_child(ob);
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+
+		} break; // vec3 vs vec3 rgb op (with scalar amount): { } break; like brighten: { } break; darken: { } break; burn: { } break; dodge: { } break; multiply: { } break; etc.
+		case ShaderGraph::NODE_XFORM_MULT: {
+
+			gn->set_title("XFMult");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],false,0,Color());
+
+
+		} break; // mat4 x mat4
+		case ShaderGraph::NODE_XFORM_VEC_MULT:
+		case ShaderGraph::NODE_XFORM_VEC_INV_MULT: {
+
+			if (graph->node_get_type(type,p_id)==ShaderGraph::NODE_XFORM_VEC_INV_MULT)
+				gn->set_title("XFVecMult");
+			else
+				gn->set_title("XFVecInvMult");
+
+
+			Button *button = memnew( Button("RotOnly"));
+			button->set_toggle_mode(true);
+			button->set_pressed(graph->xform_vec_mult_node_get_no_translation(type,p_id));
+			button->connect("toggled",this,"_xform_inv_rev_changed",varray(p_id));
+
+			gn->add_child(button);
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("xf")));
+			hbc->add_spacer();
+			Label *l = memnew(Label("out"));
+			l->set_align(Label::ALIGN_RIGHT);
+			hbc->add_child( l);
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("vec")));
+
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+
+
+		} break; // mat4 x vec3 inverse mult (with no-translation option)
+		case ShaderGraph::NODE_SCALAR_FUNC: {
+
+			gn->set_title("ScalarFunc");
+			static const char* func_name[ShaderGraph::SCALAR_MAX_FUNC]={
+				"Sin",
+				"Cos",
+				"Tan",
+				"ASin",
+				"ACos",
+				"ATan",
+				"SinH",
+				"CosH",
+				"TanH",
+				"Log",
+				"Exp",
+				"Sqrt",
+				"Abs",
+				"Sign",
+				"Floor",
+				"Round",
+				"Ceil",
+				"Frac",
+				"Satr",
+				"Neg"
+			};
+
+			OptionButton *ob = memnew( OptionButton );
+			for(int i=0;i<ShaderGraph::SCALAR_MAX_FUNC;i++) {
+
+				ob->add_item(func_name[i],i);
 			}
 			}
 
 
-			List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
-			for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
+			ob->select(graph->scalar_func_node_get_function(type,p_id));
+			ob->connect("item_selected",this,"_scalar_func_changed",varray(p_id));
+			gn->add_child(ob);
 
 
-				const ShaderGraph::Connection &c=E->get();
-				Point2 source = _get_slot_pos(c.src_id,false,c.src_slot);
-				Point2 dest = _get_slot_pos(c.dst_id,true,c.dst_slot);
-				bool vec = VisualServer::shader_is_input_vector( shader_graph.node_get_type(c.dst_id), c.dst_slot );
-				Color col = vec?Color(1,0.5,0.5,0.8):Color(1,1,0.5,0.8);
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_child( memnew(Label("in")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
 
 
-				if (click_type==CLICK_NODE && click_node==c.src_id) {
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
 
 
-					source+=click_motion-click_pos;
-				}
 
 
-				if (click_type==CLICK_NODE && click_node==c.dst_id) {
+		} break; // scalar function (sin: { } break; cos: { } break; etc)
+		case ShaderGraph::NODE_VEC_FUNC: {
 
 
-					dest+=click_motion-click_pos;
-				}
 
 
-				VisualServer::get_singleton()->canvas_item_add_line(get_canvas_item(),source,dest,col,2);
-
-			}
-		} break;
-	}
-
-}
 
 
-void ShaderEditor::_update_scrollbars() {
+			gn->set_title("VecFunc");
+			static const char* func_name[ShaderGraph::VEC_MAX_FUNC]={
+				"Normalize",
+				"Saturate",
+				"Negate",
+				"Reciprocal",
+				"RGB to HSV",
+				"HSV to RGB",
+			};
 
 
-	Size2 size = get_size();
-	Size2 hmin = h_scroll->get_minimum_size();
-	Size2 vmin = v_scroll->get_minimum_size();
+			OptionButton *ob = memnew( OptionButton );
+			for(int i=0;i<ShaderGraph::VEC_MAX_FUNC;i++) {
 
 
-	v_scroll->set_begin( Point2(size.width - vmin.width, 0) );
-	v_scroll->set_end( Point2(size.width, size.height) );
-
-	h_scroll->set_begin( Point2( 0, size.height - hmin.height) );
-	h_scroll->set_end( Point2(size.width-vmin.width, size.height) );
-
-
-	Size2 min = _get_maximum_size();
+				ob->add_item(func_name[i],i);
+			}
 
 
-	if (min.height < size.height - hmin.height) {
+			ob->select(graph->vec_func_node_get_function(type,p_id));
+			ob->connect("item_selected",this,"_vec_func_changed",varray(p_id));
+			gn->add_child(ob);
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("in")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("out")));
+			gn->add_child(hbc);
+
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+		} break; // vector function (normalize: { } break; negate: { } break; reciprocal: { } break; rgb2hsv: { } break; hsv2rgb: { } break; etc: { } break; etc)
+		case ShaderGraph::NODE_VEC_LEN: {
+			gn->set_title("VecLength");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_child( memnew(Label("in")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("len")));
+			gn->add_child(hbc);
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; // vec3 length
+		case ShaderGraph::NODE_DOT_PROD: {
+
+			gn->set_title("DotProduct");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("dp")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+
+		} break; // vec3 . vec3 (dot product -> scalar output)
+		case ShaderGraph::NODE_VEC_TO_SCALAR: {
+
+			gn->set_title("Vec2Scalar");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("vec")));
+			hbc->add_spacer();
+			Label *l=memnew(Label("x"));
+			l->set_align(Label::ALIGN_RIGHT);
+			hbc->add_child( l);
+			gn->add_child(hbc);
+			l=memnew(Label("y"));
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child( l );
+			l=memnew(Label("z"));
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child( l);
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+			gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+
+
+
+		} break; // 1 vec3 input: { } break; 3 scalar outputs
+		case ShaderGraph::NODE_SCALAR_TO_VEC: {
+
+			gn->set_title("Scalar2Vec");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_child( memnew(Label("x")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("vec")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("y")));
+			gn->add_child( memnew(Label("z")));
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+
+		} break; // 3 scalar input: { } break; 1 vec3 output
+		case ShaderGraph::NODE_VEC_TO_XFORM: {
+
+			gn->set_title("Vec2XForm");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("x")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("xf")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("y")));
+			gn->add_child( memnew(Label("z")));
+			gn->add_child( memnew(Label("ofs")));
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+			gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+
+		} break; // 3 vec input: { } break; 1 xform output
+		case ShaderGraph::NODE_XFORM_TO_VEC: {
+
+			gn->set_title("XForm2Vec");
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("xf")));
+			hbc->add_spacer();
+			Label *l=memnew(Label("x"));
+			l->set_align(Label::ALIGN_RIGHT);
+			hbc->add_child( l);
+			gn->add_child(hbc);
+			l=memnew(Label("y"));
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child( l );
+			l=memnew(Label("z"));
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child( l);
+			l=memnew(Label("ofs"));
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child( l);
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+		} break; // 3 vec input: { } break; 1 xform output
+		case ShaderGraph::NODE_SCALAR_INTERP: {
+
+			gn->set_title("ScalarInterp");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("interp")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+			gn->add_child( memnew(Label("c")));
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+
+
+		} break; // scalar interpolation (with optional curve)
+		case ShaderGraph::NODE_VEC_INTERP: {
+
+			gn->set_title("VecInterp");
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_child( memnew(Label("a")));
+			hbc->add_spacer();
+			hbc->add_child( memnew(Label("interp")));
+			gn->add_child(hbc);
+			gn->add_child( memnew(Label("b")));
+			gn->add_child( memnew(Label("c")));
+
+			gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+
+		} break; // vec3 interpolation  (with optional curve)
+		case ShaderGraph::NODE_SCALAR_INPUT: {
+
+			gn->set_title("ScalarUniform");
+			LineEdit *le = memnew( LineEdit );
+			gn->add_child(le);
+			le->set_text(graph->input_node_get_name(type,p_id));
+			le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+			SpinBox *sb = memnew( SpinBox );
+			sb->set_min(-100000);
+			sb->set_max(100000);
+			sb->set_step(0.001);
+			sb->set_val(graph->scalar_input_node_get_value(type,p_id));
+			sb->connect("value_changed",this,"_scalar_input_changed",varray(p_id));
+			gn->add_child(sb);
+			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; // scalar uniform (assignable in material)
+		case ShaderGraph::NODE_VEC_INPUT: {
+
+			gn->set_title("VectorUniform");
+			LineEdit *le = memnew( LineEdit );
+			gn->add_child(le);
+			le->set_text(graph->input_node_get_name(type,p_id));
+			le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+			Array v3p(true);
+			for(int i=0;i<3;i++) {
+				HBoxContainer *hbc = memnew( HBoxContainer );
+				Label *l = memnew( Label );
+				l->set_text(String::chr('X'+i));
+				hbc->add_child(l);
+				SpinBox *sb = memnew( SpinBox );
+				sb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+				sb->set_min(-100000);
+				sb->set_max(100000);
+				sb->set_step(0.001);
+				sb->set_val(graph->vec_input_node_get_value(type,p_id)[i]);
+				sb->connect("value_changed",this,"_vec_input_changed",varray(p_id,v3p));
+				v3p.push_back(sb);
+				hbc->add_child(sb);
+				gn->add_child(hbc);
+			}
+			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+		} break; // vec3 uniform (assignable in material)
+		case ShaderGraph::NODE_RGB_INPUT: {
+
+			gn->set_title("ColorUniform");
+			LineEdit *le = memnew( LineEdit );
+			gn->add_child(le);
+			le->set_text(graph->input_node_get_name(type,p_id));
+			le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+			ColorPickerButton *cpb = memnew( ColorPickerButton );
+			cpb->set_color(graph->rgb_input_node_get_value(type,p_id));
+			cpb->connect("color_changed",this,"_rgb_input_changed",varray(p_id));
+			gn->add_child(cpb);
+			Label *l = memnew( Label );
+			l->set_text("RGB");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+			l = memnew( Label );
+			l->set_text("Alpha");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+
+			gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+
+		} break; // color uniform (assignable in material)
+		case ShaderGraph::NODE_XFORM_INPUT: {
+			gn->set_title("XFUniform");
+			LineEdit *le = memnew( LineEdit );
+			gn->add_child(le);
+			le->set_text(graph->input_node_get_name(type,p_id));
+			le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+			ToolButton *edit = memnew( ToolButton );
+			edit->set_text("edit..");
+			edit->connect("pressed",this,"_xform_input_changed",varray(p_id,edit));
+			gn->add_child(edit);
+			gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+
+		} break; // mat4 uniform (assignable in material)
+		case ShaderGraph::NODE_TEXTURE_INPUT: {
+
+			gn->set_title("TexUniform");
+			LineEdit *le = memnew( LineEdit );
+			gn->add_child(le);
+			le->set_text(graph->input_node_get_name(type,p_id));
+			le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+			TextureFrame *tex = memnew( TextureFrame );
+			tex->set_expand(true);
+			tex->set_custom_minimum_size(Size2(80,80));
+			gn->add_child(tex);
+			tex->set_texture(graph->texture_input_node_get_value(type,p_id));
+			ToolButton *edit = memnew( ToolButton );
+			edit->set_text("edit..");
+			edit->connect("pressed",this,"_tex_edited",varray(p_id,edit));
+			gn->add_child(edit);
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("UV")));
+			hbc->add_spacer();
+			Label *l=memnew(Label("RGB"));
+			l->set_align(Label::ALIGN_RIGHT);
+			hbc->add_child(l);
+			gn->add_child(hbc);
+			l = memnew( Label );
+			l->set_text("Alpha");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+
+			gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(4,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; // texture input (assignable in material)
+		case ShaderGraph::NODE_CUBEMAP_INPUT: {
+
+			gn->set_title("TexUniform");
+			LineEdit *le = memnew( LineEdit );
+			gn->add_child(le);
+			le->set_text(graph->input_node_get_name(type,p_id));
+			le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+
+			ToolButton *edit = memnew( ToolButton );
+			edit->set_text("edit..");
+			edit->connect("pressed",this,"_cube_edited",varray(p_id,edit));
+			gn->add_child(edit);
+
+
+			HBoxContainer *hbc = memnew( HBoxContainer );
+			hbc->add_constant_override("separation",0);
+			hbc->add_child( memnew(Label("UV")));
+			hbc->add_spacer();
+			Label *l=memnew(Label("RGB"));
+			l->set_align(Label::ALIGN_RIGHT);
+			hbc->add_child(l);
+			gn->add_child(hbc);
+			l = memnew( Label );
+			l->set_text("Alpha");
+			l->set_align(Label::ALIGN_RIGHT);
+			gn->add_child(l);
+
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+			gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+		} break; // cubemap input (assignable in material)
+		case ShaderGraph::NODE_OUTPUT: {
+			gn->set_title("Output");
+
+			List<ShaderGraph::SlotInfo> si;
+			ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si);
+
+			int idx=0;
+			for (List<ShaderGraph::SlotInfo>::Element *E=si.front();E;E=E->next()) {
+				ShaderGraph::SlotInfo& s=E->get();
+				if (s.dir==ShaderGraph::SLOT_OUT) {
+
+					Label *l= memnew( Label );
+					l->set_text(s.name);
+					l->set_align(Label::ALIGN_LEFT);
+					gn->add_child(l);
+					gn->set_slot(idx,true,s.type,typecol[s.type],false,0,Color());
+					idx++;
+				}
+			}
 
 
-		v_scroll->hide();
-		offset.y=0;
-	} else {
+		} break; // output (case Shader type dependent)
+		case ShaderGraph::NODE_COMMENT: {
+			gn->set_title("Comment");
+			TextEdit *te = memnew(TextEdit);
+			te->set_custom_minimum_size(Size2(100,100));
+			gn->add_child(te);
+			te->set_text(graph->comment_node_get_text(type,p_id));
+			te->connect("text_changed",this,"_comment_edited",varray(p_id,te));
 
 
-		v_scroll->show();
-		v_scroll->set_max(min.height);
-		v_scroll->set_page(size.height - hmin.height);
-		offset.y=v_scroll->get_val();
-	}
+		} break; // comment
 
 
-	if (min.width < size.width - vmin.width) {
 
 
-		h_scroll->hide();
-		offset.x=0;
-	} else {
 
 
-		h_scroll->show();
-		h_scroll->set_max(min.width);
-		h_scroll->set_page(size.width - vmin.width);
-		offset.x=h_scroll->get_val();
 	}
 	}
-}
 
 
-void ShaderEditor::_scroll_moved() {
+	gn->connect("dragged",this,"_node_moved",varray(p_id));
+	gn->connect("close_request",this,"_node_removed",varray(p_id),CONNECT_DEFERRED);
+	graph_edit->add_child(gn);
+	node_map[p_id]=gn;
+	gn->set_offset(graph->node_get_pos(type,p_id));
+	print_line("NODE "+itos(p_id)+" OFS "+gn->get_offset());
 
 
-	offset.x=h_scroll->get_val();
-	offset.y=v_scroll->get_val();
-	update();
 }
 }
 
 
-void ShaderEditor::_bind_methods() {
+void ShaderGraphView::_update_graph() {
 
 
-	ObjectTypeDB::bind_method( "_node_menu_item", &ShaderEditor::_node_menu_item );
-	ObjectTypeDB::bind_method( "_node_add_callback", &ShaderEditor::_node_add_callback );
-	ObjectTypeDB::bind_method( "_input_event", &ShaderEditor::_input_event );
-	ObjectTypeDB::bind_method( "_node_param_changed", &ShaderEditor::_node_param_changed );
-	ObjectTypeDB::bind_method( "_scroll_moved", &ShaderEditor::_scroll_moved );
-	ObjectTypeDB::bind_method( "_vertex_item", &ShaderEditor::_vertex_item );
-	ObjectTypeDB::bind_method( "_fragment_item", &ShaderEditor::_fragment_item );
-	ObjectTypeDB::bind_method( "_post_item", &ShaderEditor::_post_item );
-}
-
-void ShaderEditor::_read_shader_graph() {
 
 
-	shader_graph.clear();;
-	order.clear();
-	List<int> nodes;
-	shader->get_node_list(&nodes);
-	int larger_id=0;
-	for(List<int>::Element *E=nodes.front();E;E=E->next()) {
+	if (block_update)
+		return;
 
 
-		if (E->get() > larger_id)
-			larger_id = E->get();
+	for (Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
 
 
-		shader_graph.node_add( (VS::ShaderNodeType)shader->node_get_type(E->get()), E->get() );
-		shader_graph.node_set_param( E->get(), shader->node_get_param( E->get() ) );
-		Point2 pos = shader->node_get_pos(E->get());
-		shader_graph.node_set_pos( E->get(), pos.x,pos.y );
-		order.push_back(E->get());
+		memdelete(E->get());
 	}
 	}
 
 
-	last_id=larger_id+1;
+	node_map.clear();
 
 
-	List<Shader::Connection> connections;
-	shader->get_connections(&connections);
-
-	for(List<Shader::Connection>::Element *E=connections.front();E;E=E->next()) {
-
-		Shader::Connection &c=E->get();
-		shader_graph.connect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
-	}
-
-	validate_graph();
-	update();
-}
+	if (!graph.is_valid())
+		return;
 
 
-void ShaderEditor::_write_shader_graph() {
 
 
-	shader->clear();
-	List<int> nodes;
-	shader_graph.get_node_list(&nodes);
-	for(List<int>::Element *E=nodes.front();E;E=E->next()) {
+	List<int> nl;
+	graph->get_node_list(type,&nl);
+	print_line("graph nodes: "+itos(nl.size()));
+	for(List<int>::Element *E=nl.front();E;E=E->next()) {
 
 
-		shader->node_add((Shader::NodeType)shader_graph.node_get_type(E->get()),E->get());
-		shader->node_set_param(E->get(),shader_graph.node_get_param(E->get()));
-		shader->node_set_pos(E->get(),Point2( shader_graph.node_get_pos_x(E->get()),shader_graph.node_get_pos_y(E->get()) ) );
+		_create_node(E->get());
 	}
 	}
+	graph_edit->clear_connections();
 
 
-	List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
+	List<ShaderGraph::Connection> connections;
+	graph->get_node_connections(type,&connections);
 	for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
 	for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
 
 
-		const ShaderGraph::Connection &c=E->get();
-		shader->connect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
+		ERR_CONTINUE(!node_map.has(E->get().src_id) || !node_map.has(E->get().dst_id));
+		graph_edit->connect_node(node_map[E->get().src_id]->get_name(),E->get().src_slot,node_map[E->get().dst_id]->get_name(),E->get().dst_slot);
 	}
 	}
-}
-
-void ShaderEditor::_add_node_from_text(const String& p_text) {
 
 
-	ERR_FAIL_COND( p_text.get_slice_count(" ") != 3 );
-	bool input = p_text.get_slice(" ",0)=="In:";
-	String name = p_text.get_slice(" ",1);
-	bool vec = p_text.get_slice(" ",2)=="(vec3)";
 
 
-	_node_add( input?
-		( vec? VisualServer::NODE_VEC_IN : VisualServer::NODE_IN ) :
-		( vec? VisualServer::NODE_VEC_OUT : VisualServer::NODE_OUT ) );
 
 
-	shader_graph.node_set_param( last_id-1,name );
-	_write_shader_graph();
 }
 }
 
 
-void ShaderEditor::_vertex_item(int p_item) {
+void ShaderGraphView::set_graph(Ref<ShaderGraph> p_graph){
 
 
-	_add_node_from_text(vertex_popup->get_item_text(p_item));
-}
-void ShaderEditor::_fragment_item(int p_item) {
-
-	_add_node_from_text(fragment_popup->get_item_text(p_item));
-}
-void ShaderEditor::_post_item(int p_item) {
+	print_line("GRAPH EDIT: "+itos(p_graph.is_valid()));
+	graph=p_graph;
+	_update_graph();
 
 
-	_add_node_from_text(post_popup->get_item_text(p_item));
 }
 }
 
 
+void ShaderGraphView::_notification(int p_what) {
 
 
-void ShaderEditor::_node_menu_item(int p_item) {
-
-	switch(p_item) {
-
-		case GRAPH_ADD_NODE: {
-			add_popup->popup_centered_ratio();
-			validate_graph();
-		} break;
-		case NODE_DISCONNECT: {
-
-			if (rclick_type==CLICK_INPUT_SLOT) {
-
-				List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
-				for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
-
-					const ShaderGraph::Connection &c=E->get();
-					if( c.dst_id==rclick_node && c.dst_slot==rclick_slot) {
-
-						shader_graph.disconnect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
-					}
-				}
-				update();
-				_write_shader_graph();
-				validate_graph();
-			}
-
-			if (rclick_type==CLICK_OUTPUT_SLOT) {
-
-				List<ShaderGraph::Connection> connections = shader_graph.get_connection_list();
-				for(List<ShaderGraph::Connection>::Element *E=connections.front();E;E=E->next()) {
-
-					const ShaderGraph::Connection &c=E->get();
-					if( c.src_id==rclick_node && c.src_slot==rclick_slot) {
-
-						shader_graph.disconnect(c.src_id,c.src_slot,c.dst_id,c.dst_slot);
-					}
-				}
-				update();
-				_write_shader_graph();
-				validate_graph();
-			}
+	if (p_what==NOTIFICATION_ENTER_TREE) {
 
 
-		} break;
-		case NODE_ERASE: {
-
-			order.erase(rclick_node);
-			shader_graph.node_remove(rclick_node);
-			update();
-			_write_shader_graph();
-			validate_graph();
-		} break;
-		case GRAPH_CLEAR: {
-
-			order.clear();
-			shader_graph.clear();
-			last_id=1;
-			last_x=20;
-			last_y=20;
-			update();
-			_write_shader_graph();
-			validate_graph();
-
-		} break;
+		ped_popup->connect("variant_changed",this,"_variant_edited");
 	}
 	}
-}
-
-void ShaderEditor::_node_add(VisualServer::ShaderNodeType p_type) {
-
-	shader_graph.node_add(p_type,last_id );
-	shader_graph.node_set_pos(last_id ,last_x,last_y);
-	String test_param;
-
-	switch(p_type) {
-		case VS::NODE_PARAMETER: {
-
-			test_param="param";
-		} break;
-		case VS::NODE_VEC_PARAMETER: {
-
-			test_param="vec";
-		} break;
-		case VS::NODE_COLOR_PARAMETER: {
-
-			test_param="color";
-		} break;
-		case VS::NODE_TEXTURE_PARAMETER: {
-
-			test_param="tex";
-		} break;
-		case VS::NODE_TEXTURE_2D_PARAMETER: {
-
-			test_param="tex2D";
-		} break;
-		case VS::NODE_TEXTURE_CUBE_PARAMETER: {
-
-			test_param="cubemap";
-		} break;
-		case VS::NODE_TRANSFORM_PARAMETER: {
-			test_param="xform";
-		} break;
-		case VS::NODE_LABEL: {
-
-			test_param="label";
-		} break;
+ }
+
+void ShaderGraphView::add_node(int p_type) {
+
+	List<int> existing;
+	graph->get_node_list(type,&existing);
+	existing.sort();
+	int newid=1;
+	for(List<int>::Element *E=existing.front();E;E=E->next()) {
+		if (!E->next() || (E->get()+1!=E->next()->get())){
+			newid=E->get()+1;
+			break;
+		}
 	}
 	}
 
 
-	if(test_param!="") {
-
-		int iter=0;
-		List<int> l;
-
-		shader_graph.get_node_list(&l);
-
-		bool found;
-		String test;
-		do {
-			iter++;
-			test=test_param;
-			if (iter>1)
-				test+="_"+itos(iter);
-			found=false;
-			for(List<int>::Element *E=l.front();E;E=E->next()) {
-
+	Vector2 init_ofs(20,20);
+	while(true) {
+		bool valid=true;
+		for(List<int>::Element *E=existing.front();E;E=E->next()) {
+			Vector2 pos = graph->node_get_pos(type,E->get());
+			if (init_ofs==pos) {
+				init_ofs+=Vector2(20,20);
+				valid=false;
+				break;
 
 
-				String param = shader_graph.node_get_param( E->get() );
-				if (param==test) {
-					found=true;
-					break;
-				}
 			}
 			}
+		}
 
 
-		} while (found);
-
-
-		shader_graph.node_set_param(last_id,test);
-
+		if (valid)
+			break;
 	}
 	}
-	order.push_back(last_id);
-	last_x+=10;
-	last_y+=10;
-	last_id++;
-	last_x=last_x % (int)get_size().width;
-	last_y=last_y % (int)get_size().height;
-	update();
-	add_popup->hide();;
-	_write_shader_graph();
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+	ur->create_action("Add Shader Graph Node");
+	ur->add_do_method(graph.ptr(),"node_add",type,p_type,newid);
+	ur->add_do_method(graph.ptr(),"node_set_pos",type,newid,init_ofs);
+	ur->add_undo_method(graph.ptr(),"node_remove",type,newid);
+	ur->add_do_method(this,"_update_graph");
+	ur->add_undo_method(this,"_update_graph");
+	ur->commit_action();
 
 
 }
 }
 
 
-void ShaderEditor::_node_add_callback() {
+void ShaderGraphView::_bind_methods() {
+
+	ObjectTypeDB::bind_method("_update_graph",&ShaderGraphView::_update_graph);
+	ObjectTypeDB::bind_method("_node_moved",&ShaderGraphView::_node_moved);
+	ObjectTypeDB::bind_method("_move_node",&ShaderGraphView::_move_node);
+	ObjectTypeDB::bind_method("_node_removed",&ShaderGraphView::_node_removed);
+	ObjectTypeDB::bind_method("_connection_request",&ShaderGraphView::_connection_request);
+
+	ObjectTypeDB::bind_method("_scalar_const_changed",&ShaderGraphView::_scalar_const_changed);
+	ObjectTypeDB::bind_method("_vec_const_changed",&ShaderGraphView::_vec_const_changed);
+	ObjectTypeDB::bind_method("_rgb_const_changed",&ShaderGraphView::_rgb_const_changed);
+	ObjectTypeDB::bind_method("_xform_const_changed",&ShaderGraphView::_xform_const_changed);
+	ObjectTypeDB::bind_method("_scalar_op_changed",&ShaderGraphView::_scalar_op_changed);
+	ObjectTypeDB::bind_method("_vec_op_changed",&ShaderGraphView::_vec_op_changed);
+	ObjectTypeDB::bind_method("_vec_scalar_op_changed",&ShaderGraphView::_vec_scalar_op_changed);
+	ObjectTypeDB::bind_method("_rgb_op_changed",&ShaderGraphView::_rgb_op_changed);
+	ObjectTypeDB::bind_method("_xform_inv_rev_changed",&ShaderGraphView::_xform_inv_rev_changed);
+	ObjectTypeDB::bind_method("_scalar_func_changed",&ShaderGraphView::_scalar_func_changed);
+	ObjectTypeDB::bind_method("_vec_func_changed",&ShaderGraphView::_vec_func_changed);
+	ObjectTypeDB::bind_method("_scalar_input_changed",&ShaderGraphView::_scalar_input_changed);
+	ObjectTypeDB::bind_method("_vec_input_changed",&ShaderGraphView::_vec_input_changed);
+	ObjectTypeDB::bind_method("_xform_input_changed",&ShaderGraphView::_xform_input_changed);
+	ObjectTypeDB::bind_method("_rgb_input_changed",&ShaderGraphView::_rgb_input_changed);
+	ObjectTypeDB::bind_method("_tex_input_change",&ShaderGraphView::_tex_input_change);
+	ObjectTypeDB::bind_method("_cube_input_change",&ShaderGraphView::_cube_input_change);
+	ObjectTypeDB::bind_method("_input_name_changed",&ShaderGraphView::_input_name_changed);
+	ObjectTypeDB::bind_method("_tex_edited",&ShaderGraphView::_tex_edited);
+	ObjectTypeDB::bind_method("_variant_edited",&ShaderGraphView::_variant_edited);
+	ObjectTypeDB::bind_method("_cube_edited",&ShaderGraphView::_cube_edited);
+	ObjectTypeDB::bind_method("_comment_edited",&ShaderGraphView::_comment_edited);
 
 
-	TreeItem * item = add_types->get_selected();
-	ERR_FAIL_COND(!item);
-	_node_add((VisualServer::ShaderNodeType)(int)item->get_metadata(0));
-	add_popup->hide() ;
 }
 }
 
 
-ShaderEditor::ShaderEditor() {
-
-	set_focus_mode(FOCUS_ALL);
-
-	Panel* menu_panel = memnew( Panel );
-	menu_panel->set_anchor( MARGIN_RIGHT, Control::ANCHOR_END );
-	menu_panel->set_end( Point2(0,22) );
-
-	add_child( menu_panel );
-
-	PopupMenu *p;
-	List<PropertyInfo> defaults;
-
-	MenuButton* node_menu = memnew( MenuButton );
-	node_menu->set_text("Graph");
-	node_menu->set_pos( Point2( 5,0) );
-	menu_panel->add_child( node_menu );
-
-	p=node_menu->get_popup();
-	p->add_item("Add Node",GRAPH_ADD_NODE);
-	p->add_separator();
-	p->add_item("Clear",GRAPH_CLEAR);
-	p->connect("item_pressed", this,"_node_menu_item");
+ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
 
 
-	MenuButton* vertex_menu = memnew( MenuButton );
-	vertex_menu->set_text("Vertex");
-	vertex_menu->set_pos( Point2( 49,0) );
-	menu_panel->add_child( vertex_menu );
+	type=p_type;
+	graph_edit = memnew( GraphEdit );
+	block_update=false;
+	ped_popup = memnew( CustomPropertyEditor );
+	graph_edit->add_child(ped_popup);
 
 
-	p=vertex_menu->get_popup();
-	defaults.clear();
-	VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_VERTEX,&defaults);
 
 
-	int id=0;
-	for(int i=0;i<defaults.size();i++) {
-
-		p->add_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
-	}
-	p->add_separator();
-	id++;
-
-	defaults.clear();
-	VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_VERTEX,&defaults);
-
-	for(int i=0;i<defaults.size();i++) {
-
-		p->add_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
-	}
+}
 
 
-	vertex_popup=p;
-	vertex_popup->connect("item_pressed", this,"_vertex_item");
-	MenuButton* fragment_menu = memnew( MenuButton );
-	fragment_menu->set_text("Fragment");
-	fragment_menu->set_pos( Point2( 95 ,0) );
-	menu_panel->add_child( fragment_menu );
 
 
-	p=fragment_menu->get_popup();
-	defaults.clear();
-	VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_FRAGMENT,&defaults);
-	id=0;
-	for(int i=0;i<defaults.size();i++) {
+//////////////edit//////////////
+void ShaderGraphEditor::edit(Ref<ShaderGraph> p_shader) {
 
 
-		p->add_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
-	}
-	p->add_separator();
-	id++;
-	defaults.clear();
-	VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_FRAGMENT,&defaults);
-
-	for(int i=0;i<defaults.size();i++) {
-
-		p->add_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
+	for(int i=0;i<ShaderGraph::SHADER_TYPE_MAX;i++) {
+		graph_edits[i]->set_graph(p_shader);
 	}
 	}
+}
 
 
-	fragment_popup=p;
-	fragment_popup->connect("item_pressed", this,"_fragment_item");
+void ShaderGraphEditor::_add_node(int p_type) {
 
 
-	MenuButton* post_menu = memnew( MenuButton );
-	post_menu->set_text("Post");
-	post_menu->set_pos( Point2( 161,0) );
-	menu_panel->add_child( post_menu );
+	ShaderGraph::ShaderType shader_type=ShaderGraph::ShaderType(tabs->get_current_tab());
 
 
-	p=post_menu->get_popup();
-	defaults.clear();
-	VisualServer::shader_get_default_input_nodes(VisualServer::SHADER_POST_PROCESS,&defaults);
-	id=0;
-	for(int i=0;i<defaults.size();i++) {
+	graph_edits[shader_type]->add_node(p_type);
+}
 
 
-		p->add_item("In: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
-	}
-	p->add_separator();
-	id++;
 
 
-	defaults.clear();
-	VisualServer::shader_get_default_output_nodes(VisualServer::SHADER_POST_PROCESS,&defaults);
+void ShaderGraphEditor::_notification(int p_what) {
+	if (p_what==NOTIFICATION_ENTER_TREE) {
+		menu->get_popup()->connect("item_pressed",this,"_add_node");
 
 
-	for(int i=0;i<defaults.size();i++) {
 
 
-		p->add_item("Out: "+defaults[i].name+(defaults[i].type==Variant::VECTOR3?" (vec3)":" (real)"),id++);
 	}
 	}
+}
 
 
-	post_popup=p;
-	post_popup->connect("item_pressed", this,"_post_item");
-
+void ShaderGraphEditor::_bind_methods() {
 
 
-	/* add popup */
+	ObjectTypeDB::bind_method("_add_node",&ShaderGraphEditor::_add_node);
 
 
-	add_popup = memnew( Popup );
-	add_child(add_popup);
-	add_popup->set_as_toplevel(true);
-	Panel *add_panel = memnew( Panel );
-	add_popup->add_child(add_panel);
-	add_panel->set_area_as_parent_rect();
+}
 
 
-	Label *add_label = memnew (Label );
-	add_label->set_pos(Point2(5,5));
-	add_label->set_text("Available Nodes:");
-	add_panel->add_child(add_label);
 
 
+const char* ShaderGraphEditor::node_names[ShaderGraph::NODE_TYPE_MAX]={
+	"Input", // all inputs (shader type dependent)
+	"Scalar Constant", //scalar constant
+	"Vector Constant", //vec3 constant
+	"RGB Constant", //rgb constant (shows a color picker instead)
+	"XForm Constant", // 4x4 matrix constant
+	"Time:", // time in seconds
+	"Screen Sample", // screen texture sampler (takes uv) (only usable in fragment shader)
+	"Scalar Operator", // scalar vs scalar op (mul", add", div", etc)
+	"Vector Operator", // vec3 vs vec3 op (mul",ad",div",crossprod",etc)
+	"Scalar+Vector Operator", // vec3 vs scalar op (mul", add", div", etc)
+	"RGB Operator:", // vec3 vs vec3 rgb op (with scalar amount)", like brighten", darken", burn", dodge", multiply", etc.
+	"XForm Multiply", // mat4 x mat4
+	"XForm+Vector Multiply", // mat4 x vec3 mult (with no-translation option)
+	"XForm+Vector InvMultiply:", // mat4 x vec3 inverse mult (with no-translation option)
+	"Scalar Function", // scalar function (sin", cos", etc)
+	"Vector Function", // vector function (normalize", negate", reciprocal", rgb2hsv", hsv2rgb", etc", etc)
+	"Vector Length", // vec3 length
+	"Dot Product:", // vec3 . vec3 (dot product -> scalar output)
+	"Vector -> Scalars", // 1 vec3 input", 3 scalar outputs
+	"Scalars -> Vector", // 3 scalar input", 1 vec3 output
+	"XForm -> Vectors", // 3 vec input", 1 xform output
+	"Vectors -> XForm:", // 3 vec input", 1 xform output
+	"Scalar Interpolate", // scalar interpolation (with optional curve)
+	"Vector Interpolate:", // vec3 interpolation  (with optional curve)
+	"Scalar Uniform", // scalar uniform (assignable in material)
+	"Vector Uniform", // vec3 uniform (assignable in material)
+	"RGB Uniform", // color uniform (assignable in material)
+	"XForm Uniform", // mat4 uniform (assignable in material)
+	"Texture Uniform", // texture input (assignable in material)
+	"CubeMap Uniform:", // cubemap input (assignable in material)
+	"Output", // output (shader type dependent)
+	"Comment", // comment
 
 
-	add_types = memnew( Tree );
-	add_types->set_anchor( MARGIN_RIGHT, ANCHOR_END );
-	add_types->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
-	add_types->set_begin( Point2( 20,25 ) );
-	add_types->set_end( Point2( 10, 30 ) );
-	add_types->set_hide_root(true);
-	add_types->set_columns(4);
-	add_types->set_select_mode(Tree::SELECT_ROW);
 
 
+};
+ShaderGraphEditor::ShaderGraphEditor() {
 
 
-	TreeItem *add_types_root = add_types->create_item(NULL);
-	TreeItem *info_item = add_types->create_item(add_types_root);
+	HBoxContainer *hbc = memnew( HBoxContainer );
+	menu = memnew( MenuButton );
+	menu->set_text("Add..");
+	hbc->add_child(menu);
+	add_child(hbc);
+	for(int i=0;i<ShaderGraph::NODE_TYPE_MAX;i++) {
 
 
-	for(int i=0;i<VisualServer::NODE_TYPE_MAX;i++) {
+		if (i==ShaderGraph::NODE_OUTPUT)
+			continue;
+		String v = node_names[i];
+		bool addsep=false;
+		if (v.ends_with(":")) {
+			addsep=true;
+			v=v.substr(0,v.length()-1);
+		}
+		menu->get_popup()->add_item(v,i);
+		if (addsep)
+			menu->get_popup()->add_separator();
+	}
 
 
-		TreeItem *item = add_types->create_item(add_types_root);
-		PropertyInfo prop = VisualServer::shader_node_get_type_info((VisualServer::ShaderNodeType)i);
-		item->set_text(0,prop.name);
-		item->set_text(1,itos(VisualServer::shader_get_input_count((VisualServer::ShaderNodeType)i)));
-		item->set_text(2,itos(VisualServer::shader_get_output_count((VisualServer::ShaderNodeType)i)));
-		String hint = (prop.type==Variant::_RID)?prop.hint_string:Variant::get_type_name(prop.type);
-		item->set_text(3,hint);
-		item->set_metadata(0,i);
+	tabs = memnew(TabContainer);
+	tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+	add_child(tabs);
+	const char* sname[ShaderGraph::SHADER_TYPE_MAX]={
+		"Vertex",
+		"Fragment",
+		"Light"
+	};
+	for(int i=0;i<ShaderGraph::SHADER_TYPE_MAX;i++) {
+
+		graph_edits[i]= memnew( ShaderGraphView(ShaderGraph::ShaderType(i)) );
+		add_child(graph_edits[i]);
+		graph_edits[i]->get_graph_edit()->set_name(sname[i]);
+		tabs->add_child(graph_edits[i]->get_graph_edit());
+		graph_edits[i]->get_graph_edit()->connect("connection_request",graph_edits[i],"_connection_request");
 	}
 	}
-	info_item->set_text(0,"::NODE::");
-	info_item->set_custom_color(0,Color(0.6,0.1,0.1));
-	info_item->set_text(1,"::INPUTS::");
-	info_item->set_custom_color(1,Color(0.6,0.1,0.1));
-	info_item->set_text(2,"::OUTPUTS::");
-	info_item->set_custom_color(2,Color(0.6,0.1,0.1));
-	info_item->set_text(3,"::PARAM::");
-	info_item->set_custom_color(3,Color(0.6,0.1,0.1));
-	info_item->set_selectable(0,false);
-	info_item->set_selectable(1,false);
-	info_item->set_selectable(2,false);
-	info_item->set_selectable(3,false);
-
-	add_panel->add_child(add_types);
-
-	add_confirm = memnew( Button );
-	add_confirm->set_anchor( MARGIN_LEFT, ANCHOR_END );
-	add_confirm->set_anchor( MARGIN_TOP, ANCHOR_END );
-	add_confirm->set_anchor( MARGIN_RIGHT, ANCHOR_END );
-	add_confirm->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
-	add_confirm->set_begin( Point2( 75, 29 ) );
-	add_confirm->set_end( Point2( 10, 15 ) );
-	add_confirm->set_text("Add");
-	add_panel->add_child(add_confirm);
-	add_confirm->connect("pressed", this,"_node_add_callback");
-
-	last_id=1;
-	last_x=20;
-	last_y=20;
-
-	property_editor = memnew( CustomPropertyEditor );
-	add_child(property_editor);
-	property_editor->connect("variant_changed", this,"_node_param_changed");
-
-	h_scroll = memnew( HScrollBar );
-	v_scroll = memnew( VScrollBar );
-
-	add_child(h_scroll);
-	add_child(v_scroll);
-
-	h_scroll->connect("value_changed", this,"_scroll_moved");
-	v_scroll->connect("value_changed", this,"_scroll_moved");
-
-	node_popup= memnew(PopupMenu );
-	add_child(node_popup);
-	node_popup->set_as_toplevel(true);
-
-	node_popup->connect("item_pressed", this,"_node_menu_item");
 
 
+	set_custom_minimum_size(Size2(100,300));
 }
 }
 
 
 
 
-void ShaderEditorPlugin::edit(Object *p_object) {
+void ShaderGraphEditorPlugin::edit(Object *p_object) {
 
 
-	shader_editor->edit(p_object->cast_to<Shader>());
+	shader_editor->edit(p_object->cast_to<ShaderGraph>());
 }
 }
 
 
-bool ShaderEditorPlugin::handles(Object *p_object) const {
+bool ShaderGraphEditorPlugin::handles(Object *p_object) const {
 
 
-	return p_object->is_type("Shader");
+	return p_object->is_type("ShaderGraph");
 }
 }
 
 
-void ShaderEditorPlugin::make_visible(bool p_visible) {
+void ShaderGraphEditorPlugin::make_visible(bool p_visible) {
 
 
 	if (p_visible) {
 	if (p_visible) {
 		shader_editor->show();
 		shader_editor->show();
-		shader_editor->set_process(true);
 	} else {
 	} else {
 
 
 		shader_editor->hide();
 		shader_editor->hide();
-		shader_editor->set_process(false);
 	}
 	}
 
 
 }
 }
 
 
-ShaderEditorPlugin::ShaderEditorPlugin(EditorNode *p_node) {
+ShaderGraphEditorPlugin::ShaderGraphEditorPlugin(EditorNode *p_node) {
 
 
 	editor=p_node;
 	editor=p_node;
-	shader_editor = memnew( ShaderEditor );
-	editor->get_viewport()->add_child(shader_editor);
-	shader_editor->set_area_as_parent_rect();
+	shader_editor = memnew( ShaderGraphEditor );
 	shader_editor->hide();
 	shader_editor->hide();
+	SpatialEditor::get_singleton()->get_shader_split()->add_child(shader_editor);
 
 
 
 
+//	editor->get_viewport()->add_child(shader_editor);
+//	shader_editor->set_area_as_parent_rect();
+//	shader_editor->hide();
 
 
 }
 }
 
 
 
 
-ShaderEditorPlugin::~ShaderEditorPlugin()
+ShaderGraphEditorPlugin::~ShaderGraphEditorPlugin()
 {
 {
 }
 }
 
 
 
 
-#endif
+

+ 85 - 86
tools/editor/plugins/shader_graph_editor_plugin.h

@@ -29,122 +29,121 @@
 #ifndef SHADER_GRAPH_EDITOR_PLUGIN_H
 #ifndef SHADER_GRAPH_EDITOR_PLUGIN_H
 #define SHADER_GRAPH_EDITOR_PLUGIN_H
 #define SHADER_GRAPH_EDITOR_PLUGIN_H
 
 
-#if 0
+
 #include "tools/editor/editor_plugin.h"
 #include "tools/editor/editor_plugin.h"
 #include "tools/editor/editor_node.h"
 #include "tools/editor/editor_node.h"
 #include "scene/resources/shader.h"
 #include "scene/resources/shader.h"
 #include "servers/visual/shader_graph.h"
 #include "servers/visual/shader_graph.h"
 #include "scene/gui/tree.h"
 #include "scene/gui/tree.h"
 #include "scene/gui/button.h"
 #include "scene/gui/button.h"
+#include "scene/gui/graph_edit.h"
 #include "scene/gui/popup.h"
 #include "scene/gui/popup.h"
 #include "tools/editor/property_editor.h"
 #include "tools/editor/property_editor.h"
+#include "scene/resources/shader_graph.h"
 /**
 /**
 	@author Juan Linietsky <[email protected]>
 	@author Juan Linietsky <[email protected]>
 */
 */
 
 
-class ShaderEditor : public Control {
-
-	OBJ_TYPE(ShaderEditor, Control );
-
-	enum MenuAction {
-
-		GRAPH_ADD_NODE,
-		GRAPH_CLEAR,
-		NODE_DISCONNECT,
-		NODE_ERASE,
-
-	};
-
-	enum ClickType {
-		CLICK_NONE,
-		CLICK_NODE,
-		CLICK_INPUT_SLOT,
-		CLICK_OUTPUT_SLOT,
-		CLICK_PARAMETER
-	};
-
-	PopupMenu *node_popup;
-	Popup *add_popup;
-	PopupMenu *vertex_popup;
-	PopupMenu *fragment_popup;
-	PopupMenu *post_popup;
-	Tree *add_types;
-	Button *add_confirm;
-	HScrollBar *h_scroll;
-	VScrollBar *v_scroll;
-
-	Ref<Shader> shader;
-	List<int> order;
-	Set<int> active_nodes;
-	ShaderGraph shader_graph;
-	int last_x,last_y;
-	uint32_t last_id;
-
-	CustomPropertyEditor *property_editor;
-
-	Point2 offset;
-	ClickType click_type;
-	Point2 click_pos;
-	int click_node;
-	int click_slot;
-	Point2 click_motion;
-	ClickType rclick_type;
-	int rclick_node;
-	int rclick_slot;
-
-	Size2 _get_maximum_size();
-	Size2 get_node_size(int p_node) const;
-	void _draw_node(int p_node);
-
-	void _add_node_from_text(const String& p_text);
-	void _update_scrollbars();
-	void _scroll_moved();
-	void _node_param_changed();
-	void _node_add_callback();
-	void _node_add(VisualServer::ShaderNodeType p_type);
-	void _node_edit_property(int p_node);
-	void _node_menu_item(int p_item);
-	void _vertex_item(int p_item);
-	void _fragment_item(int p_item);
-	void _post_item(int p_item);
-
-	ClickType _locate_click(const Point2& p_click,int *p_node_id,int *p_slot_index) const;
-	Point2 _get_slot_pos(int p_node_id,bool p_input,int p_slot);
-
-	Error validate_graph();
-
-	void _read_shader_graph();
-	void _write_shader_graph();
-
-	virtual bool has_point(const Point2& p_point) const;
+
+class ShaderGraphView : public Node {
+
+	OBJ_TYPE(ShaderGraphView,Node);
+
+
+
+	CustomPropertyEditor *ped_popup;
+	bool block_update;
+
+	GraphEdit *graph_edit;
+	Ref<ShaderGraph> graph;
+	int edited_id;
+
+	ShaderGraph::ShaderType type;
+
+	void _update_graph();
+	void _create_node(int p_id);
+
+
+
+	void _connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot);
+	void _node_removed(int p_id);
+	void _node_moved(const Vector2& p_from, const Vector2& p_to,int p_id);
+	void _move_node(int p_id,const Vector2& p_to);
+
+	void _scalar_const_changed(double p_value,int p_id);
+	void _vec_const_changed(double p_value, int p_id, Array p_arr);
+	void _rgb_const_changed(const Color& p_color, int p_id);
+	void _xform_const_changed(int p_id,Node* p_button);
+	void _scalar_op_changed(int p_op, int p_id);
+	void _vec_op_changed(int p_op, int p_id);
+	void _vec_scalar_op_changed(int p_op, int p_id);
+	void _rgb_op_changed(int p_op, int p_id);
+	void _xform_inv_rev_changed(bool p_enabled, int p_id);
+	void _scalar_func_changed(int p_func, int p_id);
+	void _vec_func_changed(int p_func, int p_id);
+	void _scalar_input_changed(double p_value,int p_id);
+	void _vec_input_changed(double p_value, int p_id, Array p_arr);
+	void _xform_input_changed(int p_id,Node* p_button);
+	void _rgb_input_changed(const Color& p_color, int p_id);
+	void _tex_input_change(int p_id,Node* p_button);
+	void _cube_input_change(int p_id);
+	void _input_name_changed(const String& p_name,int p_id,Node* p_line_edit);
+	void _tex_edited(int p_id,Node* p_button);
+	void _cube_edited(int p_id,Node* p_button);
+	void _variant_edited();
+	void _comment_edited(int p_id,Node* p_button);
+
+
+	Map<int,GraphNode*> node_map;
 protected:
 protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
-	void _input_event(InputEvent p_event);
 	static void _bind_methods();
 	static void _bind_methods();
 public:
 public:
 
 
-	void edit(Ref<Shader> p_shader);
-	ShaderEditor();
+	void add_node(int p_type);
+	GraphEdit *get_graph_edit() { return graph_edit; }
+	void set_graph(Ref<ShaderGraph> p_graph);
+
+	ShaderGraphView(ShaderGraph::ShaderType p_type=ShaderGraph::SHADER_TYPE_FRAGMENT);
 };
 };
 
 
-class ShaderEditorPlugin : public EditorPlugin {
+class ShaderGraphEditor : public VBoxContainer {
 
 
-	OBJ_TYPE( ShaderEditorPlugin, EditorPlugin );
+	OBJ_TYPE(ShaderGraphEditor,VBoxContainer);
 
 
-	ShaderEditor *shader_editor;
+	MenuButton *menu;
+	TabContainer *tabs;
+	ShaderGraphView *graph_edits[ShaderGraph::SHADER_TYPE_MAX];
+	static const char* node_names[ShaderGraph::NODE_TYPE_MAX];
+
+	void _add_node(int p_type);
+protected:
+	void _notification(int p_what);
+	static void _bind_methods();
+public:
+
+	void edit(Ref<ShaderGraph> p_shader);
+	ShaderGraphEditor();
+};
+
+class ShaderGraphEditorPlugin : public EditorPlugin {
+
+	OBJ_TYPE( ShaderGraphEditorPlugin, EditorPlugin );
+
+	ShaderGraphEditor *shader_editor;
 	EditorNode *editor;
 	EditorNode *editor;
 
 
 public:
 public:
 
 
-	virtual String get_name() const { return "Shader"; }
+	virtual String get_name() const { return "ShaderGraph"; }
 	bool has_main_screen() const { return false; }
 	bool has_main_screen() const { return false; }
 	virtual void edit(Object *p_node);
 	virtual void edit(Object *p_node);
 	virtual bool handles(Object *p_node) const;
 	virtual bool handles(Object *p_node) const;
 	virtual void make_visible(bool p_visible);
 	virtual void make_visible(bool p_visible);
 
 
-	ShaderEditorPlugin(EditorNode *p_node);
-	~ShaderEditorPlugin();
+	ShaderGraphEditorPlugin(EditorNode *p_node);
+	~ShaderGraphEditorPlugin();
 
 
 };
 };
 #endif
 #endif
-#endif // SHADER_GRAPH_EDITOR_PLUGIN_H
+

+ 8 - 4
tools/editor/property_editor.cpp

@@ -142,7 +142,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
 					}
 					}
 
 
 					String orig_type = res_orig->get_type();
 					String orig_type = res_orig->get_type();
-					print_line("orig type: "+orig_type);
+
 					Object *inst = ObjectTypeDB::instance( orig_type );
 					Object *inst = ObjectTypeDB::instance( orig_type );
 
 
 					Ref<Resource> res = Ref<Resource>( inst->cast_to<Resource>() );
 					Ref<Resource> res = Ref<Resource>( inst->cast_to<Resource>() );
@@ -187,6 +187,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
 
 
 					ERR_FAIL_COND( inheritors_array.empty() );
 					ERR_FAIL_COND( inheritors_array.empty() );
 
 
+
 					String intype=inheritors_array[p_which-TYPE_BASE_ID];
 					String intype=inheritors_array[p_which-TYPE_BASE_ID];
 
 
 					Object *obj = ObjectTypeDB::instance(intype);
 					Object *obj = ObjectTypeDB::instance(intype);
@@ -603,6 +604,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
 
 
 
 
 			if (hint_text!="") {
 			if (hint_text!="") {
+				int idx=0;
 
 
 				for(int i=0;i<hint_text.get_slice_count(",");i++) {
 				for(int i=0;i<hint_text.get_slice_count(",");i++) {
 
 
@@ -620,19 +622,19 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
 						E=E->next();
 						E=E->next();
 					}
 					}
 
 
-					int idx=0;
 					for(Set<String>::Element *E=valid_inheritors.front();E;E=E->next()) {
 					for(Set<String>::Element *E=valid_inheritors.front();E;E=E->next()) {
 						String t = E->get();
 						String t = E->get();
 						if (!ObjectTypeDB::can_instance(t))
 						if (!ObjectTypeDB::can_instance(t))
 							continue;
 							continue;
 						inheritors_array.push_back(t);
 						inheritors_array.push_back(t);
 
 
+						int id = TYPE_BASE_ID+idx;
 						if (has_icon(t,"EditorIcons")) {
 						if (has_icon(t,"EditorIcons")) {
 
 
-							menu->add_icon_item(get_icon(t,"EditorIcons"),"New "+t,TYPE_BASE_ID+idx);
+							menu->add_icon_item(get_icon(t,"EditorIcons"),"New "+t,id);
 						} else {
 						} else {
 
 
-							menu->add_item("New "+t,TYPE_BASE_ID+idx);
+							menu->add_item("New "+t,id);
 						}
 						}
 
 
 						idx++;
 						idx++;
@@ -970,9 +972,11 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
 		
 		
 			if (p_which==0) {
 			if (p_which==0) {
 			
 			
+
 				ERR_FAIL_COND( inheritors_array.empty() );
 				ERR_FAIL_COND( inheritors_array.empty() );
 
 
 				String intype=inheritors_array[0];
 				String intype=inheritors_array[0];
+
 				
 				
 				if (hint==PROPERTY_HINT_RESOURCE_TYPE) {
 				if (hint==PROPERTY_HINT_RESOURCE_TYPE) {
 				
 				

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff