Browse Source

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

Anton Yabchinskiy 10 years ago
parent
commit
b6c5cb1064
87 changed files with 1831 additions and 410 deletions
  1. 1 0
      .gitignore
  2. 20 0
      bin/tests/test_gdscript.cpp
  3. 1 1
      core/bind/core_bind.cpp
  4. 1 1
      core/color.cpp
  5. 1 1
      core/int_types.h
  6. 100 2
      core/os/keyboard.cpp
  7. 27 29
      drivers/gles2/rasterizer_gles2.cpp
  8. 2 1
      drivers/gles2/rasterizer_gles2.h
  9. 3 0
      drivers/gles2/shader_compiler_gles2.cpp
  10. 2 2
      drivers/png/resource_saver_png.cpp
  11. 1 1
      drivers/theoraplayer/SCsub
  12. 1 1
      modules/gdscript/gd_compiler.cpp
  13. 1 1
      modules/gdscript/gd_script.cpp
  14. 3 3
      modules/gridmap/grid_map_editor_plugin.cpp
  15. 1 1
      platform/osx/detect.py
  16. 2 0
      platform/osx/os_osx.h
  17. 96 2
      platform/osx/os_osx.mm
  18. 25 9
      scene/2d/area_2d.cpp
  19. 7 3
      scene/2d/area_2d.h
  20. 53 0
      scene/2d/physics_body_2d.cpp
  21. 12 0
      scene/2d/physics_body_2d.h
  22. 73 4
      scene/gui/graph_edit.cpp
  23. 8 1
      scene/gui/graph_edit.h
  24. 27 4
      scene/gui/graph_node.cpp
  25. 89 87
      scene/gui/text_edit.cpp
  26. 3 3
      scene/resources/curve.cpp
  27. 5 2
      scene/resources/shader.cpp
  28. 391 105
      scene/resources/shader_graph.cpp
  29. 9 3
      scene/resources/shader_graph.h
  30. 2 2
      scene/resources/world_2d.cpp
  31. 1 0
      scene/scene_string_names.cpp
  32. 1 0
      scene/scene_string_names.h
  33. 61 1
      servers/physics/body_pair_sw.cpp
  34. 1 0
      servers/physics/body_pair_sw.h
  35. 6 3
      servers/physics_2d/area_2d_sw.cpp
  36. 7 3
      servers/physics_2d/area_2d_sw.h
  37. 41 4
      servers/physics_2d/body_2d_sw.cpp
  38. 11 3
      servers/physics_2d/body_2d_sw.h
  39. 1 1
      servers/physics_2d/body_pair_2d_sw.cpp
  40. 1 4
      servers/physics_2d/space_2d_sw.cpp
  41. 1 2
      servers/physics_2d/space_2d_sw.h
  42. 14 5
      servers/physics_2d_server.cpp
  43. 8 4
      servers/physics_2d_server.h
  44. 27 4
      servers/visual/shader_language.cpp
  45. 2 4
      tools/SCsub
  46. 23 5
      tools/editor/editor_node.cpp
  47. 2 0
      tools/editor/editor_node.h
  48. BIN
      tools/editor/icons/icon_graph_comment.png
  49. BIN
      tools/editor/icons/icon_graph_cube_uniform.png
  50. BIN
      tools/editor/icons/icon_graph_input.png
  51. BIN
      tools/editor/icons/icon_graph_rgb.png
  52. BIN
      tools/editor/icons/icon_graph_rgb_op.png
  53. BIN
      tools/editor/icons/icon_graph_rgb_uniform.png
  54. BIN
      tools/editor/icons/icon_graph_scalar.png
  55. BIN
      tools/editor/icons/icon_graph_scalar_interp.png
  56. BIN
      tools/editor/icons/icon_graph_scalar_op.png
  57. BIN
      tools/editor/icons/icon_graph_scalar_uniform.png
  58. BIN
      tools/editor/icons/icon_graph_scalars_to_vec.png
  59. BIN
      tools/editor/icons/icon_graph_texscreen.png
  60. BIN
      tools/editor/icons/icon_graph_texture_uniform.png
  61. BIN
      tools/editor/icons/icon_graph_time.png
  62. BIN
      tools/editor/icons/icon_graph_vec_dp.png
  63. BIN
      tools/editor/icons/icon_graph_vec_interp.png
  64. BIN
      tools/editor/icons/icon_graph_vec_length.png
  65. BIN
      tools/editor/icons/icon_graph_vec_op.png
  66. BIN
      tools/editor/icons/icon_graph_vec_scalar_op.png
  67. BIN
      tools/editor/icons/icon_graph_vec_to_scalars.png
  68. BIN
      tools/editor/icons/icon_graph_vecs_to_xform.png
  69. BIN
      tools/editor/icons/icon_graph_vector.png
  70. BIN
      tools/editor/icons/icon_graph_vector_uniform.png
  71. BIN
      tools/editor/icons/icon_graph_xform.png
  72. BIN
      tools/editor/icons/icon_graph_xform_mult.png
  73. BIN
      tools/editor/icons/icon_graph_xform_scalar_func.png
  74. BIN
      tools/editor/icons/icon_graph_xform_to_vecs.png
  75. BIN
      tools/editor/icons/icon_graph_xform_uniform.png
  76. BIN
      tools/editor/icons/icon_graph_xform_vec_func.png
  77. BIN
      tools/editor/icons/icon_graph_xform_vec_imult.png
  78. BIN
      tools/editor/icons/icon_graph_xform_vec_mult.png
  79. 1 1
      tools/editor/plugins/canvas_item_editor_plugin.cpp
  80. 1 1
      tools/editor/plugins/script_editor_plugin.cpp
  81. 154 63
      tools/editor/plugins/shader_graph_editor_plugin.cpp
  82. 4 1
      tools/editor/plugins/shader_graph_editor_plugin.h
  83. 6 6
      tools/editor/plugins/spatial_editor_plugin.cpp
  84. 2 2
      tools/editor/project_manager.cpp
  85. 0 2
      tools/editor/script_editor_debugger.cpp
  86. 439 0
      tools/export/blender25/godot_export_manager.py
  87. 49 22
      tools/export/blender25/io_scene_dae/export_dae.py

+ 1 - 0
.gitignore

@@ -12,6 +12,7 @@ drivers/gles2/shaders/*.h
 modules/register_module_types.cpp
 core/version.h
 core/method_bind.inc
+core/method_bind_ext.inc
 core/script_encryption_key.cpp
 core/global_defaults.cpp
 tools/editor/register_exporters.cpp

+ 20 - 0
bin/tests/test_gdscript.cpp

@@ -738,6 +738,26 @@ static void _disassemble_class(const Ref<GDScript>& p_class,const Vector<String>
 					incr=4+argc;
 
 				} break;
+				case GDFunction::OPCODE_YIELD: {
+
+					txt+=" yield ";
+					incr=1;
+
+				} break;
+				case GDFunction::OPCODE_YIELD_SIGNAL: {
+
+					txt+=" yield_signal ";
+					txt+=DADDR(1);
+					txt+=",";
+					txt+=DADDR(2);
+					incr=3;
+				} break;
+				case GDFunction::OPCODE_YIELD_RESUME: {
+
+					txt+=" yield resume: ";
+					txt+=DADDR(1);
+					incr=2;
+				} break;
 				case GDFunction::OPCODE_JUMP: {
 
 					txt+=" jump ";

+ 1 - 1
core/bind/core_bind.cpp

@@ -642,7 +642,7 @@ void _OS::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("has_touchscreen_ui_hint"),&_OS::has_touchscreen_ui_hint);
 
-
+	ObjectTypeDB::bind_method(_MD("set_window_title","title"),&_OS::set_window_title);
 
 	ObjectTypeDB::bind_method(_MD("set_low_processor_usage_mode","enable"),&_OS::set_low_processor_usage_mode);
 	ObjectTypeDB::bind_method(_MD("is_in_low_processor_usage_mode"),&_OS::is_in_low_processor_usage_mode);

+ 1 - 1
core/color.cpp

@@ -225,7 +225,7 @@ Color Color::inverted() const {
 Color Color::contrasted() const {
 
 	Color c=*this;
-	c.contrasted();
+	c.contrast();
 	return c;
 }
 

+ 1 - 1
core/int_types.h

@@ -48,7 +48,7 @@ typedef signed short    int16_t;
 typedef unsigned int    uint32_t;
 typedef signed int      int32_t;
 typedef long long	int64_t;
-typedef unsigned long long int64_t;
+typedef unsigned long long uint64_t;
 #else
 #include <stdint.h>
 #endif

+ 100 - 2
core/os/keyboard.cpp

@@ -27,7 +27,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "keyboard.h"
-
+#include "os/os.h"
 
 struct _KeyCodeText {
 	int code;
@@ -354,7 +354,105 @@ int find_keycode(const String& p_code) {
 
 }
 
-int latin_keyboard_keycode_convert(int p_keycode){
+
+
+
+struct _KeyCodeReplace {
+	int from;
+	int to;
+};
+
+static const _KeyCodeReplace _keycode_replace_qwertz[]={
+{KEY_Y,KEY_Z},
+{KEY_Z,KEY_Y},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_azerty[]={
+{KEY_W,KEY_Z},
+{KEY_Z,KEY_W},
+{KEY_A,KEY_Q},
+{KEY_Q,KEY_A},
+{KEY_SEMICOLON,KEY_M},
+{KEY_M,KEY_SEMICOLON},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_qzerty[]={
+{KEY_W,KEY_Z},
+{KEY_Z,KEY_W},
+{KEY_SEMICOLON,KEY_M},
+{KEY_M,KEY_SEMICOLON},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_dvorak[]={
+{KEY_UNDERSCORE,KEY_BRACELEFT},
+{KEY_EQUAL,KEY_BRACERIGHT},
+{KEY_Q,KEY_APOSTROPHE},
+{KEY_W,KEY_COMMA},
+{KEY_E,KEY_PERIOD},
+{KEY_R,KEY_P},
+{KEY_T,KEY_Y},
+{KEY_Y,KEY_F},
+{KEY_U,KEY_G},
+{KEY_I,KEY_C},
+{KEY_O,KEY_R},
+{KEY_P,KEY_L},
+{KEY_BRACELEFT,KEY_SLASH},
+{KEY_BRACERIGHT,KEY_EQUAL},
+{KEY_A,KEY_A},
+{KEY_S,KEY_O},
+{KEY_D,KEY_E},
+{KEY_F,KEY_U},
+{KEY_G,KEY_I},
+{KEY_H,KEY_D},
+{KEY_J,KEY_H},
+{KEY_K,KEY_T},
+{KEY_L,KEY_N},
+{KEY_SEMICOLON,KEY_S},
+{KEY_APOSTROPHE,KEY_UNDERSCORE},
+{KEY_Z,KEY_SEMICOLON},
+{KEY_X,KEY_Q},
+{KEY_C,KEY_J},
+{KEY_V,KEY_K},
+{KEY_B,KEY_X},
+{KEY_N,KEY_B},
+{KEY_M,KEY_M},
+{KEY_COMMA,KEY_W},
+{KEY_PERIOD,KEY_V},
+{KEY_SLASH,KEY_Z},
+{0,0}
+};
+
+static const _KeyCodeReplace _keycode_replace_neo[]={
+{0,0}
+};
+
+
+int latin_keyboard_keycode_convert(int p_keycode) {
+
+	const _KeyCodeReplace *kcr=NULL;
+	switch(OS::get_singleton()->get_latin_keyboard_variant()) {
+
+		case OS::LATIN_KEYBOARD_QWERTY: return p_keycode; break;
+		case OS::LATIN_KEYBOARD_QWERTZ: kcr=_keycode_replace_qwertz; break;
+		case OS::LATIN_KEYBOARD_AZERTY: kcr=_keycode_replace_azerty; break;
+		case OS::LATIN_KEYBOARD_QZERTY: kcr=_keycode_replace_qzerty; break;
+		case OS::LATIN_KEYBOARD_DVORAK: kcr=_keycode_replace_dvorak; break;
+		case OS::LATIN_KEYBOARD_NEO: kcr=_keycode_replace_neo; break;
+		default: return p_keycode;
+	}
+
+	if (!kcr) {
+		return p_keycode;
+	}
+
+	while(kcr->from) {
+		if (kcr->from==p_keycode)
+			return kcr->to;
+		kcr++;
+	}
 
 	return p_keycode;
 }

+ 27 - 29
drivers/gles2/rasterizer_gles2.cpp

@@ -1545,13 +1545,15 @@ void RasterizerGLES2::shader_set_default_texture_param(RID p_shader, const Strin
 
 	Shader *shader=shader_owner.get(p_shader);
 	ERR_FAIL_COND(!shader);
-	ERR_FAIL_COND(!texture_owner.owns(p_texture));
+	ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture));
 
 	if (p_texture.is_valid())
 		shader->default_textures[p_name]=p_texture;
 	else
 		shader->default_textures.erase(p_name);
 
+	_shader_make_dirty(shader);
+
 }
 
 RID RasterizerGLES2::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{
@@ -1606,6 +1608,7 @@ void RasterizerGLES2::material_set_param(RID p_material, const StringName& p_par
 			material->shader_version=0; //get default!
 		} else {
 			E->get().value=p_value;
+			E->get().inuse=true;
 		}
 	} else {
 
@@ -1613,6 +1616,7 @@ void RasterizerGLES2::material_set_param(RID p_material, const StringName& p_par
 		ud.index=-1;
 		ud.value=p_value;
 		ud.istexture=p_value.get_type()==Variant::_RID; /// cache it being texture
+		ud.inuse=true;
 		material->shader_params[p_param]=ud; //may be got at some point, or erased
 
 	}
@@ -1644,7 +1648,7 @@ Variant RasterizerGLES2::material_get_param(RID p_material, const StringName& p_
 	}
 
 
-	if (material->shader_params.has(p_param))
+	if (material->shader_params.has(p_param) && material->shader_params[p_param].inuse)
 		return material->shader_params[p_param].value;
 	else
 		return Variant();
@@ -4876,31 +4880,46 @@ _FORCE_INLINE_ void RasterizerGLES2::_update_material_shader_params(Material *p_
 
 		Material::UniformData ud;
 
-		bool keep=true;
+		bool keep=true; //keep material value
+		bool has_old = old_mparams.has(E->key());
+		bool old_inuse=has_old && old_mparams[E->key()].inuse;
 
-		if (!old_mparams.has(E->key()))
+		if (!has_old || !old_inuse)
 			keep=false;
 		else if (old_mparams[E->key()].value.get_type()!=E->value().default_value.get_type()) {
-
-			if (old_mparams[E->key()].value.get_type()==Variant::OBJECT) {
+			//type changed between old and new
+			/*if (old_mparams[E->key()].value.get_type()==Variant::OBJECT) {
 				if (E->value().default_value.get_type()!=Variant::_RID) //hackfor textures
 					keep=false;
 			} else if (!old_mparams[E->key()].value.is_num() || !E->value().default_value.get_type())
+				keep=false;*/
+
+			//value is invalid because type differs and default is not null
+			if (E->value().default_value.get_type()!=Variant::NIL)
 				keep=false;
 		}
 
+		ud.istexture=(E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP);
+
 		if (keep) {
 			ud.value=old_mparams[E->key()].value;
+
 			//print_line("KEEP: "+String(E->key()));
 		} else {
-			ud.value=E->value().default_value;
+			if (ud.istexture && p_material->shader_cache->default_textures.has(E->key()))
+				ud.value=p_material->shader_cache->default_textures[E->key()];
+			else
+				ud.value=E->value().default_value;
+			old_inuse=false; //if reverted to default, obviously did not work
+
 			//print_line("NEW: "+String(E->key())+" because: hasold-"+itos(old_mparams.has(E->key())));
 			//if (old_mparams.has(E->key()))
 			//	print_line(" told "+Variant::get_type_name(old_mparams[E->key()].value.get_type())+" tnew "+Variant::get_type_name(E->value().default_value.get_type()));
 		}
 
-		ud.istexture=(E->get().type==ShaderLanguage::TYPE_TEXTURE || E->get().type==ShaderLanguage::TYPE_CUBEMAP);
+
 		ud.index=idx++;
+		ud.inuse=old_inuse;
 		mparams[E->key()]=ud;
 	}
 
@@ -5021,23 +5040,8 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
 						E->get().value=RID(); //nullify, invalid texture
 						rid=RID();
 					}
-				} else {
-
-
-				}
-
-				if (!rid.is_valid()) {
-					//use from default textures
-					Map<StringName,RID>::Element *F=p_material->shader_cache->default_textures.find(E->key());
-					if (F) {
-						t=texture_owner.get(F->get());
-						if (!t) {
-							p_material->shader_cache->default_textures.erase(E->key());
-						}
-					}
 				}
 
-
 				glActiveTexture(GL_TEXTURE0+texcoord);
 				glUniform1i(loc,texcoord); //TODO - this could happen automatically on compile...
 				if (t) {
@@ -5061,12 +5065,6 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
 
 		}
 
-		for (Map<StringName,RID>::Element *E=p_material->shader_cache->default_textures.front();E;E=E->next()) {
-			if (p_material->shader_params.has(E->key()))
-				continue;
-
-
-		}
 
 		if (p_material->shader_cache->has_texscreen && framebuffer.active) {
 			material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));

+ 2 - 1
drivers/gles2/rasterizer_gles2.h

@@ -241,8 +241,9 @@ class RasterizerGLES2 : public Rasterizer {
 
 		struct UniformData {
 
+			bool inuse;
 			bool istexture;
-			Variant value;
+			Variant value;			
 			int index;
 		};
 

+ 3 - 0
drivers/gles2/shader_compiler_gles2.cpp

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

+ 2 - 2
drivers/png/resource_saver_png.cpp

@@ -64,10 +64,10 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
 			text+=bool(texture->get_flags()&Texture::FLAG_FILTER)?"filter=true\n":"filter=false\n";
 		}
 		if (global_mipmaps!=bool(texture->get_flags()&Texture::FLAG_MIPMAPS)) {
-			text+=bool(texture->get_flags()&Texture::FLAG_FILTER)?"gen_mipmaps=true\n":"gen_mipmaps=false\n";
+			text+=bool(texture->get_flags()&Texture::FLAG_MIPMAPS)?"gen_mipmaps=true\n":"gen_mipmaps=false\n";
 		}
 		if (global_repeat!=bool(texture->get_flags()&Texture::FLAG_REPEAT)) {
-			text+=bool(texture->get_flags()&Texture::FLAG_FILTER)?"repeat=true\n":"repeat=false\n";
+			text+=bool(texture->get_flags()&Texture::FLAG_REPEAT)?"repeat=true\n":"repeat=false\n";
 		}
 		if (bool(texture->get_flags()&Texture::FLAG_ANISOTROPIC_FILTER)) {
 			text+="anisotropic=true\n";

+ 1 - 1
drivers/theoraplayer/SCsub

@@ -70,7 +70,7 @@ if env["platform"] == "iphone":
 		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.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_LIBYUV"])
 #env_theora.Append(CPPFLAGS=["-D_YUV_C"])
 
 if env["platform"] == "iphone":

+ 1 - 1
modules/gdscript/gd_compiler.cpp

@@ -528,7 +528,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
 						int ret = _parse_expression(codegen,on->arguments[i],slevel);
 						if (ret<0)
 							return ret;
-						if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) {
+						if (ret&(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)) {
 							slevel++;
 							codegen.alloc_stack(slevel);
 						}

+ 1 - 1
modules/gdscript/gd_script.cpp

@@ -820,7 +820,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
 				gdfs->state.stack.resize(alloca_size);
 				//copy variant stack
 				for(int i=0;i<_stack_size;i++) {
-					memnew_placement(&stack[sizeof(Variant)*i],Variant(stack[i]));
+					memnew_placement(&gdfs->state.stack[sizeof(Variant)*i],Variant(stack[i]));
 				}
 				gdfs->state.stack_size=_stack_size;
 				gdfs->state.self=self;

+ 3 - 3
modules/gridmap/grid_map_editor_plugin.cpp

@@ -1222,9 +1222,9 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
 	options->get_popup()->add_item("Cursor Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_A);
 	options->get_popup()->add_item("Cursor Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_S);
 	options->get_popup()->add_item("Cursor Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_D);
-	options->get_popup()->add_item("Cursor Back Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_ALT+KEY_A);
-	options->get_popup()->add_item("Cursor Back Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_ALT+KEY_S);
-	options->get_popup()->add_item("Cursor Back Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_ALT+KEY_D);
+	options->get_popup()->add_item("Cursor Back Rotate X",MENU_OPTION_CURSOR_ROTATE_X,KEY_MASK_SHIFT+KEY_A);
+	options->get_popup()->add_item("Cursor Back Rotate Y",MENU_OPTION_CURSOR_ROTATE_Y,KEY_MASK_SHIFT+KEY_S);
+	options->get_popup()->add_item("Cursor Back Rotate Z",MENU_OPTION_CURSOR_ROTATE_Z,KEY_MASK_SHIFT+KEY_D);
 	options->get_popup()->add_item("Cursor Clear Rotation",MENU_OPTION_CURSOR_CLEAR_ROTATION,KEY_W);
 	options->get_popup()->add_separator();
 	options->get_popup()->add_check_item("Duplicate Selects",MENU_OPTION_DUPLICATE_SELECTS);

+ 1 - 1
platform/osx/detect.py

@@ -78,7 +78,7 @@ def configure(env):
 	env.Append(LIBS=['pthread'])
 	#env.Append(CPPFLAGS=['-F/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-mmacosx-version-min=10.4'])
 	#env.Append(LINKFLAGS=['-mmacosx-version-min=10.4', '-isysroot', '/Developer/SDKs/MacOSX10.4u.sdk', '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.4u.sdk'])
-	env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz'])
+	env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit','-lz'])
 
 	if (env["CXX"]=="clang++"):
 		env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND'])

+ 2 - 0
platform/osx/os_osx.h

@@ -156,6 +156,8 @@ public:
 
 	virtual String get_executable_path() const;
 
+	virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
 	virtual void move_window_to_foreground();
 
 	void run();

+ 96 - 2
platform/osx/os_osx.mm

@@ -27,6 +27,8 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #import <Cocoa/Cocoa.h>
+
+#include <Carbon/Carbon.h>
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOCFPlugIn.h>
 #include <IOKit/hid/IOHIDLib.h>
@@ -694,7 +696,7 @@ static int translateKey(unsigned int key)
     ev.type=InputEvent::KEY;
     ev.key.pressed=true;
     ev.key.mod=translateFlags([event modifierFlags]);
-    ev.key.scancode = translateKey([event keyCode]);
+    ev.key.scancode = latin_keyboard_keycode_convert(translateKey([event keyCode]));
     ev.key.echo = [event isARepeat];
 
     NSString* characters = [event characters];
@@ -740,7 +742,7 @@ static int translateKey(unsigned int key)
 	ev.type=InputEvent::KEY;
 	ev.key.pressed=false;
 	ev.key.mod=translateFlags([event modifierFlags]);
-	ev.key.scancode = translateKey([event keyCode]);
+	ev.key.scancode = latin_keyboard_keycode_convert(translateKey([event keyCode]));
 	OS_OSX::singleton->push_input(ev);
 
 
@@ -835,11 +837,24 @@ void OS_OSX::initialize_core() {
 
 }
 
+static bool keyboard_layout_dirty = true;
+static void keyboardLayoutChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
+	keyboard_layout_dirty = true;
+}
+
 void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
 
 	/*** OSX INITIALIZATION ***/
 	/*** OSX INITIALIZATION ***/
 	/*** OSX INITIALIZATION ***/
+
+	keyboard_layout_dirty = true;
+
+	// Register to be notified on keyboard layout changes
+	CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(),
+									NULL, keyboardLayoutChanged,
+									kTISNotifySelectedKeyboardInputSourceChanged, NULL,
+									CFNotificationSuspensionBehaviorDeliverImmediately);
     
 	window_delegate = [[GodotWindowDelegate alloc] init];
 
@@ -1007,6 +1022,8 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
 }
 void OS_OSX::finalize() {
 
+	CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
+
 }
 
 void OS_OSX::set_main_loop( MainLoop * p_main_loop ) {
@@ -1241,6 +1258,83 @@ String OS_OSX::get_executable_path() const {
 
 }
 
+// Returns string representation of keys, if they are printable.
+//
+static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) {
+
+	TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
+	if (!currentKeyboard)
+		return nil;
+
+	CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
+	if (!layoutData)
+		return nil;
+
+	const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+
+	OSStatus err;
+	CFMutableStringRef output = CFStringCreateMutable(NULL, 0);
+
+	for (int i=0; i<length; ++i) {
+
+		UInt32 keysDown = 0;
+		UniChar chars[4];
+		UniCharCount realLength;
+
+		err = UCKeyTranslate(keyboardLayout,
+					   keyCode[i],
+					   kUCKeyActionDisplay,
+					   0,
+					   LMGetKbdType(),
+					   kUCKeyTranslateNoDeadKeysBit,
+					   &keysDown,
+					   sizeof(chars) / sizeof(chars[0]),
+					   &realLength,
+					   chars);
+
+		if (err != noErr) {
+			CFRelease(output);
+			return nil;
+		}
+
+		CFStringAppendCharacters(output, chars, 1);
+	}
+
+	//CFStringUppercase(output, NULL);
+
+	return (NSString *)output;
+}
+OS::LatinKeyboardVariant OS_OSX::get_latin_keyboard_variant() const {
+
+	static LatinKeyboardVariant layout = LATIN_KEYBOARD_QWERTY;
+
+	if (keyboard_layout_dirty) {
+
+		layout = LATIN_KEYBOARD_QWERTY;
+
+		CGKeyCode keys[] = {kVK_ANSI_Q, kVK_ANSI_W, kVK_ANSI_E, kVK_ANSI_R, kVK_ANSI_T, kVK_ANSI_Y};
+		NSString *test = createStringForKeys(keys, 6);
+
+		if ([test isEqualToString:@"qwertz"]) {
+			layout = LATIN_KEYBOARD_QWERTZ;
+		} else if ([test isEqualToString:@"azerty"]) {
+			layout = LATIN_KEYBOARD_AZERTY;
+		} else if ([test isEqualToString:@"qzerty"]) {
+			layout = LATIN_KEYBOARD_QZERTY;
+		} else if ([test isEqualToString:@"',.pyf"]) {
+			layout = LATIN_KEYBOARD_DVORAK;
+		} else if ([test isEqualToString:@"xvlcwk"]) {
+			layout = LATIN_KEYBOARD_NEO;
+		}
+
+		[test release];
+
+		keyboard_layout_dirty = false;
+		return layout;
+	}
+
+	return layout;
+}
 
 void OS_OSX::process_events() {
 

+ 25 - 9
scene/2d/area_2d.cpp

@@ -73,14 +73,25 @@ real_t Area2D::get_gravity() const{
 	return gravity;
 }
 
-void Area2D::set_density(real_t p_density){
+void Area2D::set_linear_damp(real_t p_linear_damp){
 
-	density=p_density;
-	Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_DENSITY,p_density);
+	linear_damp=p_linear_damp;
+	Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_LINEAR_DAMP,p_linear_damp);
 }
-real_t Area2D::get_density() const{
+real_t Area2D::get_linear_damp() const{
 
-	return density;
+	return linear_damp;
+}
+
+void Area2D::set_angular_damp(real_t p_angular_damp){
+
+	angular_damp=p_angular_damp;
+	Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_ANGULAR_DAMP,p_angular_damp);
+}
+
+real_t Area2D::get_angular_damp() const{
+
+	return angular_damp;
 }
 
 void Area2D::set_priority(real_t p_priority){
@@ -314,8 +325,11 @@ void Area2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area2D::set_gravity);
 	ObjectTypeDB::bind_method(_MD("get_gravity"),&Area2D::get_gravity);
 
-	ObjectTypeDB::bind_method(_MD("set_density","density"),&Area2D::set_density);
-	ObjectTypeDB::bind_method(_MD("get_density"),&Area2D::get_density);
+	ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&Area2D::set_linear_damp);
+	ObjectTypeDB::bind_method(_MD("get_linear_damp"),&Area2D::get_linear_damp);
+
+	ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&Area2D::set_angular_damp);
+	ObjectTypeDB::bind_method(_MD("get_angular_damp"),&Area2D::get_angular_damp);
 
 	ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority);
 	ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority);
@@ -337,7 +351,8 @@ void Area2D::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity"));
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
 
@@ -349,7 +364,8 @@ Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_crea
 	set_gravity(98);;
 	set_gravity_vector(Vector2(0,1));
 	gravity_is_point=false;
-	density=0.1;
+	linear_damp=0.1;
+	angular_damp=1;
 	locked=false;
 	priority=0;
 	monitoring=false;

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

@@ -49,7 +49,8 @@ private:
 	Vector2 gravity_vec;
 	real_t gravity;
 	bool gravity_is_point;
-	real_t density;
+	real_t linear_damp;
+	real_t angular_damp;
 	int priority;
 	bool monitoring;
 	bool locked;
@@ -104,8 +105,11 @@ public:
 	void set_gravity(real_t p_gravity);
 	real_t get_gravity() const;
 
-	void set_density(real_t p_density);
-	real_t get_density() const;
+	void set_linear_damp(real_t p_linear_damp);
+	real_t get_linear_damp() const;
+
+	void set_angular_damp(real_t p_angular_damp);
+	real_t get_angular_damp() const;
 
 	void set_priority(real_t p_priority);
 	real_t get_priority() const;

+ 53 - 0
scene/2d/physics_body_2d.cpp

@@ -496,6 +496,42 @@ real_t RigidBody2D::get_bounce() const{
 	return bounce;
 }
 
+
+void RigidBody2D::set_gravity_scale(real_t p_gravity_scale){
+
+	gravity_scale=p_gravity_scale;
+	Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_GRAVITY_SCALE,gravity_scale);
+
+}
+real_t RigidBody2D::get_gravity_scale() const{
+
+	return gravity_scale;
+}
+
+void RigidBody2D::set_linear_damp(real_t p_linear_damp){
+
+	ERR_FAIL_COND(p_linear_damp<-1);
+	linear_damp=p_linear_damp;
+	Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_LINEAR_DAMP,linear_damp);
+
+}
+real_t RigidBody2D::get_linear_damp() const{
+
+	return linear_damp;
+}
+
+void RigidBody2D::set_angular_damp(real_t p_angular_damp){
+
+	ERR_FAIL_COND(p_angular_damp<-1);
+	angular_damp=p_angular_damp;
+	Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_ANGULAR_DAMP,angular_damp);
+
+}
+real_t RigidBody2D::get_angular_damp() const{
+
+	return angular_damp;
+}
+
 void RigidBody2D::set_axis_velocity(const Vector2& p_axis) {
 
 	Vector2 v = state? state->get_linear_velocity() : linear_velocity;
@@ -683,6 +719,15 @@ void RigidBody2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&RigidBody2D::set_bounce);
 	ObjectTypeDB::bind_method(_MD("get_bounce"),&RigidBody2D::get_bounce);
 
+	ObjectTypeDB::bind_method(_MD("set_gravity_scale","gravity_scale"),&RigidBody2D::set_gravity_scale);
+	ObjectTypeDB::bind_method(_MD("get_gravity_scale"),&RigidBody2D::get_gravity_scale);
+
+	ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&RigidBody2D::set_linear_damp);
+	ObjectTypeDB::bind_method(_MD("get_linear_damp"),&RigidBody2D::get_linear_damp);
+
+	ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&RigidBody2D::set_angular_damp);
+	ObjectTypeDB::bind_method(_MD("get_angular_damp"),&RigidBody2D::get_angular_damp);
+
 	ObjectTypeDB::bind_method(_MD("set_linear_velocity","linear_velocity"),&RigidBody2D::set_linear_velocity);
 	ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&RigidBody2D::get_linear_velocity);
 
@@ -726,6 +771,7 @@ void RigidBody2D::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"weight",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01",PROPERTY_USAGE_EDITOR),_SCS("set_weight"),_SCS("get_weight"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_scale",PROPERTY_HINT_RANGE,"-128,128,0.01"),_SCS("set_gravity_scale"),_SCS("get_gravity_scale"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"custom_integrator"),_SCS("set_use_custom_integrator"),_SCS("is_using_custom_integrator"));
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"continuous_cd",PROPERTY_HINT_ENUM,"Disabled,Cast Ray,Cast Shape"),_SCS("set_continuous_collision_detection_mode"),_SCS("get_continuous_collision_detection_mode"));
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported"));
@@ -734,6 +780,8 @@ void RigidBody2D::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"can_sleep"),_SCS("set_can_sleep"),_SCS("is_able_to_sleep"));
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"velocity/angular"),_SCS("set_angular_velocity"),_SCS("get_angular_velocity"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/linear",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_linear_damp"),_SCS("get_linear_damp"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/angular",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
 
 	ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape")));
 	ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape")));
@@ -758,6 +806,11 @@ RigidBody2D::RigidBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_RIGID) {
 	bounce=0;
 	mass=1;
 	friction=1;
+
+	gravity_scale=1;
+	linear_damp=-1;
+	angular_damp=-1;
+
 	max_contacts_reported=0;
 	state=NULL;
 

+ 12 - 0
scene/2d/physics_body_2d.h

@@ -119,6 +119,9 @@ private:
 	real_t bounce;
 	real_t mass;
 	real_t friction;
+	real_t gravity_scale;
+	real_t linear_damp;
+	real_t angular_damp;
 
 	Vector2 linear_velocity;
 	real_t angular_velocity;
@@ -198,6 +201,15 @@ public:
 	void set_bounce(real_t p_bounce);
 	real_t get_bounce() const;
 
+	void set_gravity_scale(real_t p_gravity_scale);
+	real_t get_gravity_scale() const;
+
+	void set_linear_damp(real_t p_linear_damp);
+	real_t get_linear_damp() const;
+
+	void set_angular_damp(real_t p_angular_damp);
+	real_t get_angular_damp() const;
+
 	void set_linear_velocity(const Vector2& p_velocity);
 	Vector2 get_linear_velocity() const;
 

+ 73 - 4
scene/gui/graph_edit.cpp

@@ -1,5 +1,6 @@
 #include "graph_edit.h"
-
+#include "os/input.h"
+#include "os/keyboard.h"
 bool GraphEditFilter::has_point(const Point2& p_point) const {
 
 	return ge->_filter_input(p_point);
@@ -53,7 +54,7 @@ void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const
 	}
 }
 
-void GraphEdit::get_connection_list(List<Connection> *r_connections) {
+void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
 
 	*r_connections=connections;
 }
@@ -88,7 +89,6 @@ void GraphEdit::_update_scroll() {
 
 	updating=true;
 	Rect2 screen;
-	screen.size=get_size();
 	for(int i=0;i<get_child_count();i++) {
 
 		GraphNode *gn=get_child(i)->cast_to<GraphNode>();
@@ -101,6 +101,10 @@ void GraphEdit::_update_scroll() {
 		screen = screen.merge(r);
 	}
 
+	screen.pos-=get_size();
+	screen.size+=get_size()*2.0;
+
+
 	h_scroll->set_min(screen.pos.x);
 	h_scroll->set_max(screen.pos.x+screen.size.x);
 	h_scroll->set_page(get_size().x);
@@ -265,6 +269,37 @@ void GraphEdit::_top_layer_input(const InputEvent& p_ev) {
 				Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos();
 
 				if (pos.distance_to(mpos)<grab_r) {
+
+					if (right_disconnects) {
+						//check disconnect
+						for (List<Connection>::Element*E=connections.front();E;E=E->next()) {
+
+							if (E->get().to==gn->get_name() && E->get().to_port==j) {
+
+								Node*fr = get_node(String(E->get().from));
+								if (fr && fr->cast_to<GraphNode>()) {
+
+									connecting_from=E->get().from;
+									connecting_index=E->get().from_port;
+									connecting_out=true;
+									connecting_type=fr->cast_to<GraphNode>()->get_connection_output_type(E->get().from_port);
+									connecting_color=fr->cast_to<GraphNode>()->get_connection_output_color(E->get().from_port);
+									connecting_target=false;
+									connecting_to=pos;
+
+									emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port);
+									fr = get_node(String(connecting_from)); //maybe it was erased
+									if (fr && fr->cast_to<GraphNode>()) {
+										connecting=true;
+									}
+									return;
+								}
+
+							}
+						}
+					}
+
+
 					connecting=true;
 					connecting_from=gn->get_name();
 					connecting_index=j;
@@ -461,7 +496,7 @@ void GraphEdit::_top_layer_draw() {
 
 void GraphEdit::_input_event(const InputEvent& p_ev) {
 
-	if (p_ev.type==InputEvent::MOUSE_MOTION && p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE) {
+	if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
 		h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x );
 		v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y );
 	}
@@ -474,11 +509,41 @@ void GraphEdit::clear_connections() {
 }
 
 
+void GraphEdit::set_right_disconnects(bool p_enable) {
+
+	right_disconnects=p_enable;
+}
+
+bool GraphEdit::is_right_disconnects_enabled() const{
+
+	return right_disconnects;
+}
+
+Array GraphEdit::_get_connection_list() const {
+
+	List<Connection> conns;
+	get_connection_list(&conns);
+	Array arr;
+	for(List<Connection>::Element *E=conns.front();E;E=E->next()) {
+		Dictionary d;
+		d["from"]=E->get().from;
+		d["from_port"]=E->get().from_port;
+		d["to"]=E->get().to;
+		d["to_port"]=E->get().to_port;
+		arr.push_back(d);
+	}
+	return arr;
+}
 void GraphEdit::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("connect_node:Error","from","from_port","to","to_port"),&GraphEdit::connect_node);
 	ObjectTypeDB::bind_method(_MD("is_node_connected","from","from_port","to","to_port"),&GraphEdit::is_node_connected);
 	ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node);
+	ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list);
+
+	ObjectTypeDB::bind_method(_MD("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects);
+	ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled);
+
 	ObjectTypeDB::bind_method(_MD("_graph_node_moved"),&GraphEdit::_graph_node_moved);
 	ObjectTypeDB::bind_method(_MD("_graph_node_raised"),&GraphEdit::_graph_node_raised);
 
@@ -489,9 +554,12 @@ void GraphEdit::_bind_methods() {
 	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")));
+	ADD_SIGNAL(MethodInfo("disconnection_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));
@@ -511,6 +579,7 @@ GraphEdit::GraphEdit() {
 	top_layer->add_child(v_scroll);
 	updating=false;
 	connecting=false;
+	right_disconnects=false;
 
 	h_scroll->connect("value_changed", this,"_scroll_moved");
 	v_scroll->connect("value_changed", this,"_scroll_moved");

+ 8 - 1
scene/gui/graph_edit.h

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

+ 27 - 4
scene/gui/graph_node.cpp

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

+ 89 - 87
scene/gui/text_edit.cpp

@@ -1293,106 +1293,108 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
 					break;
 
 				bool valid=true;
-				if (k.mod.command || k.mod.alt || k.mod.meta)
+				if (k.mod.command || k.mod.meta)
 					valid=false;
 				
 				if (valid) {
 					
-					if (k.scancode==KEY_UP) {
-						
-						if (completion_index>0) {
-							completion_index--;
+					if (!k.mod.alt) {
+						if (k.scancode==KEY_UP) {
+
+							if (completion_index>0) {
+								completion_index--;
+								completion_current=completion_options[completion_index];
+								update();
+							}
+							accept_event();
+							return;
+						}
+
+
+						if (k.scancode==KEY_DOWN) {
+
+							if (completion_index<completion_options.size()-1) {
+								completion_index++;
+								completion_current=completion_options[completion_index];
+								update();
+							}
+							accept_event();
+							return;
+						}
+
+						if (k.scancode==KEY_PAGEUP) {
+
+							completion_index-=get_constant("completion_lines");
+							if (completion_index<0)
+								completion_index=0;
 							completion_current=completion_options[completion_index];
 							update();
+							accept_event();
+							return;
 						}
-						accept_event();
-						return;
-					}
-					
-					
-					if (k.scancode==KEY_DOWN) {
-						
-						if (completion_index<completion_options.size()-1) {
-							completion_index++;
+
+
+						if (k.scancode==KEY_PAGEDOWN) {
+
+							completion_index+=get_constant("completion_lines");
+							if (completion_index>=completion_options.size())
+								completion_index=completion_options.size()-1;
 							completion_current=completion_options[completion_index];
 							update();
+							accept_event();
+							return;
 						}
-						accept_event();
-						return;
-					}
-					
-					if (k.scancode==KEY_PAGEUP) {
-						
-						completion_index-=get_constant("completion_lines");
-						if (completion_index<0)
+
+						if (k.scancode==KEY_HOME) {
+
 							completion_index=0;
-						completion_current=completion_options[completion_index];
-						update();
-						accept_event();
-						return;
-					}
-					
-					
-					if (k.scancode==KEY_PAGEDOWN) {
-						
-						completion_index+=get_constant("completion_lines");
-						if (completion_index>=completion_options.size())
+							completion_current=completion_options[completion_index];
+							update();
+							accept_event();
+							return;
+						}
+
+						if (k.scancode==KEY_END) {
+
 							completion_index=completion_options.size()-1;
-						completion_current=completion_options[completion_index];
-						update();
-						accept_event();
-						return;
-					}
-					
-					if (k.scancode==KEY_HOME) {
-						
-						completion_index=0;
-						completion_current=completion_options[completion_index];
-						update();
-						accept_event();
-						return;
-					}
-					
-					if (k.scancode==KEY_END) {
-						
-						completion_index=completion_options.size()-1;
-						completion_current=completion_options[completion_index];
-						update();
-						accept_event();
-						return;
-					}
-					
-					
-					if (k.scancode==KEY_DOWN) {
-						
-						if (completion_index<completion_options.size()-1) {
-							completion_index++;
 							completion_current=completion_options[completion_index];
 							update();
+							accept_event();
+							return;
+						}
+
+
+						if (k.scancode==KEY_DOWN) {
+
+							if (completion_index<completion_options.size()-1) {
+								completion_index++;
+								completion_current=completion_options[completion_index];
+								update();
+							}
+							accept_event();
+							return;
+						}
+
+						if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) {
+
+							_confirm_completion();
+							accept_event();
+							return;
+						}
+
+						if (k.scancode==KEY_BACKSPACE) {
+
+							backspace_at_cursor();
+							_update_completion_candidates();
+							accept_event();
+							return;
+						}
+
+
+						if (k.scancode==KEY_SHIFT) {
+							accept_event();
+							return;
 						}
-						accept_event();
-						return;
-					}
-					
-					if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) {
-						
-						_confirm_completion();
-						accept_event();
-						return;
-					}
-					
-					if (k.scancode==KEY_BACKSPACE) {
-						
-						backspace_at_cursor();
-						_update_completion_candidates();
-						accept_event();
-						return;
-					}
-					
-					
-					if (k.scancode==KEY_SHIFT) {
-						accept_event();
-						return;
 					}
 					
 					if (k.unicode>32) {
@@ -1972,7 +1974,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
 				} break;
 					
 				case KEY_U:{
-					if (!k.mod.command || k.mod.shift || k.mod.alt) {
+					if (!k.mod.command || k.mod.shift) {
 						scancode_handled=false;
 						break;
 					}
@@ -2018,7 +2020,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
 		}
 	    }
 */
-			if (!scancode_handled && !k.mod.command && !k.mod.alt) { //for german kbds
+			if (!scancode_handled && !k.mod.command) { //for german kbds
 				
 				if (k.unicode>=32) {
 					

+ 3 - 3
scene/resources/curve.cpp

@@ -134,7 +134,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const {
 Vector2 Curve2D::interpolatef(real_t p_findex) const {
 
 
-	if (p_findex>0)
+	if (p_findex<0)
 		p_findex=0;
 	else if (p_findex>=points.size())
 		p_findex=points.size();
@@ -485,7 +485,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const {
 Vector2 Curve2D::interpolatef(real_t p_findex) const {
 
 
-	if (p_findex>0)
+	if (p_findex<0)
 		p_findex=0;
 	else if (p_findex>=points.size())
 		p_findex=points.size();
@@ -956,7 +956,7 @@ Vector3 Curve3D::interpolate(int p_index, float p_offset) const {
 Vector3 Curve3D::interpolatef(real_t p_findex) const {
 
 
-	if (p_findex>0)
+	if (p_findex<0)
 		p_findex=0;
 	else if (p_findex>=points.size())
 		p_findex=points.size();

+ 5 - 2
scene/resources/shader.cpp

@@ -144,10 +144,13 @@ void Shader::_set_code(const Dictionary& p_string) {
 
 void Shader::set_default_texture_param(const StringName& p_param,const Ref<Texture>& p_texture) {
 
-	if (p_texture.is_valid())
+	if (p_texture.is_valid()) {
 		default_textures[p_param]=p_texture;
-	else
+		VS::get_singleton()->shader_set_default_texture_param(shader,p_param,p_texture->get_rid());
+	} else {
 		default_textures.erase(p_param);
+		VS::get_singleton()->shader_set_default_texture_param(shader,p_param,RID());
+	}
 }
 
 Ref<Texture> Shader::get_default_texture_param(const StringName& p_param) const{

+ 391 - 105
scene/resources/shader_graph.cpp

@@ -27,8 +27,10 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 #include "shader_graph.h"
-
-
+#include "scene/scene_string_names.h"
+//todo
+//-RGB ops
+//-mostrar error de conexion
 
 Array ShaderGraph::_get_node_list(ShaderType p_type) const {
 
@@ -57,6 +59,91 @@ Array ShaderGraph::_get_connections(ShaderType p_type) const {
 	return arr;
 }
 
+void ShaderGraph::_set_data(const Dictionary &p_data) {
+
+	Dictionary d=p_data;
+	ERR_FAIL_COND(!d.has("shaders"));
+	Array sh=d["shaders"];
+	ERR_FAIL_COND(sh.size()!=3);
+
+	for(int t=0;t<3;t++) {
+		Array data=sh[t];
+		ERR_FAIL_COND((data.size()%6)!=0);
+		shader[t].node_map.clear();
+		for(int i=0;i<data.size();i+=6) {
+
+			Node n;
+			n.id=data[i+0];
+			n.type=NodeType(int(data[i+1]));
+			n.pos=data[i+2];
+			n.param1=data[i+3];
+			n.param2=data[i+4];
+
+			Array conns=data[i+5];
+			ERR_FAIL_COND((conns.size()%3)!=0);
+
+			for(int j=0;j<conns.size();j+=3) {
+
+				SourceSlot ss;
+				int ls=conns[j+0];
+				ss.id=conns[j+1];
+				ss.slot=conns[j+2];
+				n.connections[ls]=ss;
+			}
+			shader[t].node_map[n.id]=n;
+
+		}
+	}
+
+	_update_shader();
+
+}
+
+Dictionary ShaderGraph::_get_data() const {
+
+	Array sh;
+	for(int i=0;i<3;i++) {
+		Array data;
+		int ec = shader[i].node_map.size();
+		data.resize(ec*6);
+		int idx=0;
+		for (Map<int,Node>::Element*E=shader[i].node_map.front();E;E=E->next()) {
+
+			data[idx+0]=E->key();
+			data[idx+1]=E->get().type;
+			data[idx+2]=E->get().pos;
+			data[idx+3]=E->get().param1;
+			data[idx+4]=E->get().param2;
+
+			Array conns;
+			conns.resize(E->get().connections.size()*3);
+			int idx2=0;
+			for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
+
+				conns[idx2+0]=F->key();
+				conns[idx2+1]=F->get().id;
+				conns[idx2+2]=F->get().slot;
+				idx2+=3;
+			}
+			data[idx+5]=conns;
+			idx+=6;
+		}
+		sh.push_back(data);
+	}
+
+	Dictionary data;
+	data["shaders"]=sh;
+	return data;
+}
+
+
+
+ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
+
+	ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK);
+	return shader[p_type].error;
+}
+
 void ShaderGraph::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
@@ -100,9 +187,9 @@ void ShaderGraph::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op);
 	ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op);
 
-	ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op","c"),&ShaderGraph::rgb_op_node_set_op);
+	ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op);
 	ObjectTypeDB::bind_method(_MD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op);
-	ObjectTypeDB::bind_method(_MD("rgb_op_node_get_c","shader_type","id"),&ShaderGraph::rgb_op_node_get_c);
+
 
 	ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation);
 	ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation);
@@ -147,6 +234,11 @@ void ShaderGraph::_bind_methods() {
 	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);
 
+	ObjectTypeDB::bind_method(_MD("_set_data"),&ShaderGraph::_set_data);
+	ObjectTypeDB::bind_method(_MD("_get_data"),&ShaderGraph::_get_data);
+
+	ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"),_SCS("_get_data"));
+
 	//void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
 
 
@@ -271,6 +363,8 @@ void ShaderGraph::_bind_methods() {
 	BIND_CONSTANT( VEC_FUNC_HSV2RGB );
 	BIND_CONSTANT( VEC_MAX_FUNC );
 
+	ADD_SIGNAL(MethodInfo("updated"));
+
 
 #if 0
 	ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add );
@@ -347,7 +441,7 @@ void ShaderGraph::_bind_methods() {
 }
 
 
-String ShaderGraph::_find_unique_name(ShaderType p_which, const String& p_base) {
+String ShaderGraph::_find_unique_name(const String& p_base) {
 
 
 
@@ -358,15 +452,19 @@ String ShaderGraph::_find_unique_name(ShaderType p_which, const String& p_base)
 			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;
+		for(int i=0;i<3;i++) {
+			if (!valid)
 				break;
-			}
+			for (Map<int,Node>::Element *E=shader[i].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) {
@@ -424,12 +522,12 @@ void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
 		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_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material)
+		case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material)
+		case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
+		case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
+		case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
+		case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
 		case NODE_OUTPUT: {} break; // output (shader type dependent)
 		case NODE_COMMENT: {} break; // comment
 		case NODE_TYPE_MAX: {};
@@ -479,7 +577,7 @@ void ShaderGraph::node_remove(ShaderType p_type,int p_id) {
 	}
 
 	shader[p_type].node_map.erase(p_id);
-	print_line("erased node, amount left: "+itos(shader[p_type].node_map.size()));
+
 	_request_update();
 
 }
@@ -545,7 +643,6 @@ bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slo
 void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) {
 	ERR_FAIL_INDEX(p_type,3);
 
-	print_line("** dsisconnect");
 	SourceSlot ts;
 	ts.id=p_src_id;
 	ts.slot=p_src_slot;
@@ -782,14 +879,14 @@ ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_typ
 
 }
 
-void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op,float p_c){
+void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){
 
 	ERR_FAIL_INDEX(p_type,3);
 	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 	Node& n = shader[p_type].node_map[p_id];
 	ERR_FAIL_COND(n.type!=NODE_RGB_OP);
 	n.param1=p_op;
-	n.param2=p_c;
+
 	_request_update();
 
 }
@@ -803,15 +900,7 @@ ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id)
 	return RGBOp(op);
 
 }
-float ShaderGraph::rgb_op_node_get_c(ShaderType p_type,float p_id) const{
-
-	ERR_FAIL_INDEX_V(p_type,3,0);
-	ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0);
-	const Node& n = shader[p_type].node_map[p_id];
-	ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,0);
-	return n.param2;
 
-}
 
 void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){
 
@@ -839,7 +928,9 @@ void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,Scala
 	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 	Node& n = shader[p_type].node_map[p_id];
 	ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC);
-	n.param1=p_func;
+	int func = p_func;
+	ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+	n.param1=func;
 	_request_update();
 
 }
@@ -859,7 +950,9 @@ void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc
 	ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
 	Node& n = shader[p_type].node_map[p_id];
 	ERR_FAIL_COND(n.type!=NODE_VEC_FUNC);
-	n.param1=p_func;
+	int func = p_func;
+	ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+	n.param1=func;
 
 	_request_update();
 
@@ -881,8 +974,9 @@ void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p
 	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);
+	n.param1=_find_unique_name(p_name);
 	_request_update();
 
 }
@@ -1097,59 +1191,74 @@ ShaderGraph::~ShaderGraph() {
 
 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},
+	{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,"Color","SRC_COLOR","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","SRC_ALPHA","",SLOT_TYPE_SCALAR,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","SRC_UV2","",SLOT_TYPE_VEC,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},
+
 	//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},
+	{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",".xy",SLOT_TYPE_VEC,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",".xy",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},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0);","",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,"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},
+	{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",">0.5",SLOT_TYPE_SCALAR,SLOT_OUT},
+	//light in
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDir","LIGHT_DIR","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDiffuse","LIGHT_DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightSpecular","LIGHT_SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"EyeVec","EYE_VEC","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Diffuse","DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"SpecExp","SPECULAR_EXP","",SLOT_TYPE_SCALAR,SLOT_IN},
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN},
+	//light out
+	{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
 	//end
-	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
+	{MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT},
 
 };
 
@@ -1174,17 +1283,17 @@ 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_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,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_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc)
 		{NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4
 		{NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option)
-		{NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
+		{NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option)
 		{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
@@ -1315,6 +1424,7 @@ ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderT
 
 			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)
@@ -1381,6 +1491,14 @@ void ShaderGraph::_update_shader() {
 
 	String code[3];
 
+	List<StringName> names;
+	get_default_texture_param_list(&names);
+
+	for (List<StringName>::Element *E=names.front();E;E=E->next()) {
+		set_default_texture_param(E->get(),Ref<Texture>());
+	}
+
+
 	for(int i=0;i<3;i++) {
 
 		int idx=0;
@@ -1437,11 +1555,13 @@ void ShaderGraph::_update_shader() {
 		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;";
+			code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);\n";
+			code[i]+="float ALPHA_OUT=0;\n";
 		}
 
+
 		Map<String,String> inputs_xlate;
+		Map<String,String> input_names_xlate;
 		Set<String> inputs_used;
 
 		for(int j=0;j<order.size();j++) {
@@ -1458,6 +1578,7 @@ void ShaderGraph::_update_shader() {
 
 						String vname=("nd"+itos(n->id)+"sl"+itos(idx));
 						inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n";
+						input_names_xlate[vname]=iop->variable;
 						idx++;
 					}
 					iop++;
@@ -1476,7 +1597,7 @@ void ShaderGraph::_update_shader() {
 							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";
+							code[i]+=String(iop->variable)+"="+iname+String(iop->postfix)+";\n";
 							if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha")
 								use_alpha=true;
 						}
@@ -1488,8 +1609,7 @@ void ShaderGraph::_update_shader() {
 				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";
+						code[i]+="DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n";
 					} else {
 						code[i]+="DIFFUSE=DIFFUSE_OUT;\n";
 					}
@@ -1506,13 +1626,19 @@ void ShaderGraph::_update_shader() {
 					}
 					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)
+					if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
 						inputs_used.insert(iname);
+					}
 
 				}
 
 				if (failed)
 					break;
+
+				if (n->type==NODE_TEXTURE_INPUT || n->type==NODE_CUBEMAP_INPUT) {
+
+					set_default_texture_param(n->param1,n->param2);
+				}
 				_add_node_code(ShaderType(i),n,inputs,code[i]);
 			}
 
@@ -1521,13 +1647,33 @@ void ShaderGraph::_update_shader() {
 		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];
+			String name=input_names_xlate[E->get()];
+
+			if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_MATERIAL) {
+				if (name==("SRC_COLOR"))
+					code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i];
+				if (name==("SRC_ALPHA"))
+					code[i]="float SRC_ALPHA=COLOR.a;\n"+code[i];
+				if (name==("SRC_UV"))
+					code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i];
+				if (name==("SRC_UV2"))
+					code[i]="float SRC_UV2=vec3(UV2,0);\n"+code[i];
+			} else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) {
+				if (name==("IN_NORMAL"))
+					code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i];
+			}
+
 		}
+
+
+
 		shader[i].error=GRAPH_OK;
-		print_line("ShADER: "+code[i]);
+
 	}
 
 	bool all_ok=true;
@@ -1540,8 +1686,9 @@ void ShaderGraph::_update_shader() {
 		set_code(code[0],code[1],code[2]);
 	}
 	//do shader here
-	print_line("UPDATING SHADER");
+
 	_pending_update_shader=false;
+	emit_signal(SceneStringNames::get_singleton()->updated);
 }
 
 void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) {
@@ -1549,6 +1696,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 	const char *typestr[4]={"float","vec3","mat4","texture"};
 #define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot)))
+#define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot))
 
 	switch(p_node->type) {
 
@@ -1568,6 +1716,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 		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";
+			code+=OUTNAME(p_node->id,1)+"="+rtos(col.a)+";\n";
 		}break;
 		case NODE_XFORM_CONST: {
 
@@ -1626,16 +1775,94 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 			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;
+				case VEC_SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break;
+				case VEC_SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break;
+				case VEC_SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break;
 			}
 			code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";
 
 		}break;
 		case NODE_RGB_OP: {
 
+			int op = p_node->param1;
+			static const char*axisn[3]={"x","y","z"};
+			switch(op) {
+				case RGB_OP_SCREEN: {
+
+					code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n";
+				} break;
+				case RGB_OP_DIFFERENCE: {
+
+					code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
+
+				} break;
+				case RGB_OP_DARKEN: {
+
+					code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n";
+				} break;
+				case RGB_OP_LIGHTEN: {
+
+					code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n";
+
+				} break;
+				case RGB_OP_OVERLAY: {
+
+					code += OUTNAME(p_node->id,0)+";\n";
+					for(int i=0;i<3;i++) {
+						code += "{\n";
+						code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+						code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+						code += "\tif (base < 0.5) {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n";
+						code += "\t} else {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n";
+						code += "\t}\n";
+						code += "}\n";
+					}
+
+				} break;
+				case RGB_OP_DODGE: {
+
+					code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n";
+
+				} break;
+				case RGB_OP_BURN: {
+
+					code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n";
+				} break;
+				case RGB_OP_SOFT_LIGHT: {
+
+					code += OUTNAME(p_node->id,0)+";\n";
+					for(int i=0;i<3;i++) {
+						code += "{\n";
+						code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+						code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+						code += "\tif (base < 0.5) {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n";
+						code += "\t} else {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n";
+						code += "\t}\n";
+						code += "}\n";
+					}
 
+				} break;
+				case RGB_OP_HARD_LIGHT: {
+
+					code += OUTNAME(p_node->id,0)+";\n";
+					for(int i=0;i<3;i++) {
+						code += "{\n";
+						code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n";
+						code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n";
+						code += "\tif (base < 0.5) {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n";
+						code += "\t} else {\n";
+						code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n";
+						code += "\t}\n";
+						code += "}\n";
+					}
+
+				} break;
+			}
 		}break;
 		case NODE_XFORM_MULT: {
 
@@ -1646,26 +1873,85 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 			bool no_translation = p_node->param1;
 			if (no_translation) {
-				code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*vec4("+p_inputs[1]+",0);\n";
+				code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",0)).xyz;\n";
 			} else {
-				code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*vec4("+p_inputs[1]+",1);\n";
+				code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",1)).xyz;\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";
+				code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
 			} else {
-				code += OUTNAME(p_node->id,0)+"="+p_inputs[1]+"*vec4("+p_inputs[0]+",1);\n";
+				code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",1)).xyz;\n";
 			}
 		}break;
 		case NODE_SCALAR_FUNC: {
-
-
-		}break;
+			static const char*scalar_func_id[SCALAR_MAX_FUNC]={
+				"sin($)",
+				"cos($)",
+				"tan($)",
+				"asin($)",
+				"acos($)",
+				"atan($)",
+				"sinh($)",
+				"cosh($)",
+				"tanh($)",
+				"log($)",
+				"exp($)",
+				"sqrt($)",
+				"abs($)",
+				"sign($)",
+				"floor($)",
+				"round($)",
+				"ceil($)",
+				"frac($)",
+				"min(max($,0),1)",
+				"-($)",
+			};
+
+			int func = p_node->param1;
+			ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC);
+			code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n";
+
+		} break;
 		case NODE_VEC_FUNC: {
+			static const char*vec_func_id[VEC_MAX_FUNC]={
+				"normalize($)",
+				"max(min($,vec3(1,1,1)),vec3(0,0,0))",
+				"-($)",
+				"1.0/($)",
+				"",
+				"",
+			};
+
+
+			int func = p_node->param1;
+			ERR_FAIL_INDEX(func,VEC_MAX_FUNC);
+			if (func==VEC_FUNC_RGB2HSV) {
+				code += OUTNAME(p_node->id,0)+";\n";
+				code+="{\n";
+				code+="\tvec3 c = "+p_inputs[0]+";\n";
+				code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n";
+				code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n";
+				code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n";
+				code+="\tfloat d = q.x - min(q.w, q.y);\n";
+				code+="\tfloat e = 1.0e-10;\n";
+				code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n";
+				code+="}\n";
+			} else if (func==VEC_FUNC_HSV2RGB) {
+				code += OUTNAME(p_node->id,0)+";\n";;
+				code+="{\n";
+				code+="\tvec3 c = "+p_inputs[0]+";\n";
+				code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n";
+				code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n";
+				code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n";
+				code+="}\n";
 
+			} else {
+				code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n";
+			}
 		}break;
 		case NODE_VEC_LEN: {
 
@@ -1744,7 +2030,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 		}break;
 		case NODE_TEXTURE_INPUT: {
 			String name = p_node->param1;
-			String rname="_read_tex"+itos(p_node->id);
+			String rname="rt_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";
@@ -1755,7 +2041,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 			String name = p_node->param1;
 			code +="uniform cubemap "+name+";";
-			String rname="_read_tex"+itos(p_node->id);
+			String rname="rt_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";

+ 9 - 3
scene/resources/shader_graph.h

@@ -115,7 +115,7 @@ public:
 
 private:
 
-	String _find_unique_name(ShaderType p_which, const String& p_base);
+	String _find_unique_name(const String& p_base);
 
 	struct SourceSlot {
 
@@ -151,6 +151,7 @@ private:
 		ShaderType shader_type;
 		const char *name;
 		const char *variable;
+		const char *postfix;
 		SlotType slot_type;
 		SlotDir dir;
 	};
@@ -175,6 +176,9 @@ private:
 
 	Array _get_node_list(ShaderType p_type) const;
 	Array _get_connections(ShaderType p_type) const;
+
+	void _set_data(const Dictionary& p_data);
+	Dictionary _get_data() const;
 protected:
 
 	static void _bind_methods();
@@ -263,9 +267,8 @@ public:
 		RGB_MAX_OP
 	};
 
-	void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op,float p_c);
+	void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op);
 	RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const;
-	float rgb_op_node_get_c(ShaderType p_which,float p_id) const;
 
 	void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation);
 	bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const;
@@ -345,6 +348,8 @@ public:
 	Variant node_get_state(ShaderType p_type, int p_node) const;
 	void node_set_state(ShaderType p_type, int p_id, const Variant& p_state);
 
+	GraphError get_graph_error(ShaderType p_type) const;
+
 	static int get_type_input_count(NodeType p_type);
 	static int get_type_output_count(NodeType p_type);
 	static SlotType get_type_input_type(NodeType p_type,int p_idx);
@@ -384,6 +389,7 @@ VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp );
 VARIANT_ENUM_CAST( ShaderGraph::RGBOp );
 VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc );
 VARIANT_ENUM_CAST( ShaderGraph::VecFunc );
+VARIANT_ENUM_CAST( ShaderGraph::GraphError );
 
 
 class MaterialShaderGraph : public ShaderGraph {

+ 2 - 2
scene/resources/world_2d.cpp

@@ -364,12 +364,12 @@ World2D::World2D() {
 	Physics2DServer::get_singleton()->space_set_active(space,true);
 	Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY,GLOBAL_DEF("physics_2d/default_gravity",98));
 	Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,GLOBAL_DEF("physics_2d/default_gravity_vector",Vector2(0,1)));
-	Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_DENSITY,GLOBAL_DEF("physics_2d/default_density",0.1));
+	Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_LINEAR_DAMP,GLOBAL_DEF("physics_2d/default_density",0.1));
+	Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_ANGULAR_DAMP,GLOBAL_DEF("physics_2d/default_density",1));
 	Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS,1.0);
 	Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION,1.5);
 	Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,0.3);
 	Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD,2);
-	Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,20);
 	Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,0.2);
 
 	indexer = memnew( SpatialIndexer2D );

+ 1 - 0
scene/scene_string_names.cpp

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

+ 1 - 0
scene/scene_string_names.h

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

+ 61 - 1
servers/physics/body_pair_sw.cpp

@@ -172,6 +172,53 @@ void BodyPairSW::validate_contacts() {
 	}
 }
 
+
+bool BodyPairSW::_test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transform& p_xform_A,BodySW *p_B, int p_shape_B,const Transform& p_xform_B) {
+
+
+
+	Vector3 motion = p_A->get_linear_velocity()*p_step;
+	real_t mlen = motion.length();
+	if (mlen<CMP_EPSILON)
+		return false;
+
+	Vector3 mnormal = motion / mlen;
+
+	real_t min,max;
+	p_A->get_shape(p_shape_A)->project_range(mnormal,p_xform_A,min,max);
+	bool fast_object = mlen > (max-min)*0.3; //going too fast in that direction
+
+	if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
+		return false;
+	}
+
+	//cast a segment from support in motion normal, in the same direction of motion by motion length
+	//support is the worst case collision point, so real collision happened before
+	int a;
+	Vector3 s=p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform(mnormal).normalized());
+	Vector3 from = p_xform_A.xform(s);
+	Vector3 to = from + motion;
+
+	Transform from_inv = p_xform_B.affine_inverse();
+
+	Vector3 local_from = from_inv.xform(from-mnormal*mlen*0.1); //start from a little inside the bounding box
+	Vector3 local_to = from_inv.xform(to);
+
+	Vector3 rpos,rnorm;
+	if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from,local_to,rpos,rnorm)) {
+		return false;
+	}
+
+	//shorten the linear velocity so it does not hit, but gets close enough, next frame will hit softly or soft enough
+	Vector3 hitpos = p_xform_B.xform(rpos);
+
+	float newlen = hitpos.distance_to(from)-(max-min)*0.01;
+	p_A->set_linear_velocity((mnormal*newlen)/p_step);
+
+	return true;
+}
+
+
 bool BodyPairSW::setup(float p_step) {
 
 	//cannot collide
@@ -198,8 +245,21 @@ bool BodyPairSW::setup(float p_step) {
 	bool collided = CollisionSolverSW::solve_static(shape_A_ptr,xform_A,shape_B_ptr,xform_B,_contact_added_callback,this,&sep_axis);
 	this->collided=collided;
 
-	if (!collided)
+
+	if (!collided) {
+
+		//test ccd (currently just a raycast)
+
+		if (A->is_continuous_collision_detection_enabled() && A->get_mode()>PhysicsServer::BODY_MODE_KINEMATIC && B->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC) {
+			_test_ccd(p_step,A,shape_A,xform_A,B,shape_B,xform_B);
+		}
+
+		if (B->is_continuous_collision_detection_enabled() && B->get_mode()>PhysicsServer::BODY_MODE_KINEMATIC && A->get_mode()<=PhysicsServer::BODY_MODE_KINEMATIC) {
+			_test_ccd(p_step,B,shape_B,xform_B,A,shape_A,xform_A);
+		}
+
 		return false;
+	}
 
 
 

+ 1 - 0
servers/physics/body_pair_sw.h

@@ -82,6 +82,7 @@ class BodyPairSW : public ConstraintSW {
 	void contact_added_callback(const Vector3& p_point_A,const Vector3& p_point_B);
 
 	void validate_contacts();
+	bool _test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transform& p_xform_A,BodySW *p_B, int p_shape_B,const Transform& p_xform_B);
 
 	SpaceSW *space;
 

+ 6 - 3
servers/physics_2d/area_2d_sw.cpp

@@ -99,7 +99,8 @@ void Area2DSW::set_param(Physics2DServer::AreaParameter p_param, const Variant&
 		case Physics2DServer::AREA_PARAM_GRAVITY_VECTOR: gravity_vector=p_value; ; break;
 		case Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point=p_value; ; break;
 		case Physics2DServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION:  point_attenuation=p_value; ; break;
-		case Physics2DServer::AREA_PARAM_DENSITY: density=p_value; ; break;
+		case Physics2DServer::AREA_PARAM_LINEAR_DAMP: linear_damp=p_value; ; break;
+		case Physics2DServer::AREA_PARAM_ANGULAR_DAMP: angular_damp=p_value; ; break;
 		case Physics2DServer::AREA_PARAM_PRIORITY: priority=p_value; ; break;
 	}
 
@@ -114,7 +115,8 @@ Variant Area2DSW::get_param(Physics2DServer::AreaParameter p_param) const {
 		case Physics2DServer::AREA_PARAM_GRAVITY_VECTOR: return gravity_vector;
 		case Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
 		case Physics2DServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return  point_attenuation;
-		case Physics2DServer::AREA_PARAM_DENSITY: return density;
+		case Physics2DServer::AREA_PARAM_LINEAR_DAMP: return linear_damp;
+		case Physics2DServer::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
 		case Physics2DServer::AREA_PARAM_PRIORITY: return priority;
 	}
 
@@ -181,7 +183,8 @@ Area2DSW::Area2DSW() : CollisionObject2DSW(TYPE_AREA), monitor_query_list(this),
 	gravity_is_point=false;
 	point_attenuation=1;
 
-	density=0.1;
+	angular_damp=1.0;
+	linear_damp=0.1;
 	priority=0;
 	monitor_callback_id=0;
 

+ 7 - 3
servers/physics_2d/area_2d_sw.h

@@ -47,7 +47,8 @@ class Area2DSW : public CollisionObject2DSW{
 	Vector2 gravity_vector;
 	bool gravity_is_point;
 	float point_attenuation;
-	float density;
+	float linear_damp;
+	float angular_damp;
 	int priority;
 
 	ObjectID monitor_callback_id;
@@ -128,8 +129,11 @@ public:
 	_FORCE_INLINE_ void set_point_attenuation(float p_point_attenuation) { point_attenuation=p_point_attenuation; }
 	_FORCE_INLINE_ float get_point_attenuation() const { return point_attenuation; }
 
-	_FORCE_INLINE_ void set_density(float p_density) { density=p_density; }
-	_FORCE_INLINE_ float get_density() const { return density; }
+	_FORCE_INLINE_ void set_linear_damp(float p_linear_damp) { linear_damp=p_linear_damp; }
+	_FORCE_INLINE_ float get_linear_damp() const { return linear_damp; }
+
+	_FORCE_INLINE_ void set_angular_damp(float p_angular_damp) { angular_damp=p_angular_damp; }
+	_FORCE_INLINE_ float get_angular_damp() const { return angular_damp; }
 
 	_FORCE_INLINE_ void set_priority(int p_priority) { priority=p_priority; }
 	_FORCE_INLINE_ int get_priority() const { return priority; }

+ 41 - 4
servers/physics_2d/body_2d_sw.cpp

@@ -156,6 +156,17 @@ void Body2DSW::set_param(Physics2DServer::BodyParameter p_param, float p_value)
 			_update_inertia();
 
 		} break;
+		case Physics2DServer::BODY_PARAM_GRAVITY_SCALE: {
+			gravity_scale=p_value;
+		} break;
+		case Physics2DServer::BODY_PARAM_LINEAR_DAMP: {
+
+			linear_damp=p_value;
+		} break;
+		case Physics2DServer::BODY_PARAM_ANGULAR_DAMP: {
+
+			angular_damp=p_value;
+		} break;
 		default:{}
 	}
 }
@@ -174,6 +185,17 @@ float Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
 		case Physics2DServer::BODY_PARAM_MASS: {
 			return mass;
 		} break;
+		case Physics2DServer::BODY_PARAM_GRAVITY_SCALE: {
+			return gravity_scale;
+		} break;
+		case Physics2DServer::BODY_PARAM_LINEAR_DAMP: {
+
+			return linear_damp;
+		} break;
+		case Physics2DServer::BODY_PARAM_ANGULAR_DAMP: {
+
+			return angular_damp;
+		} break;
 		default:{}
 	}
 
@@ -362,6 +384,8 @@ void Body2DSW::_compute_area_gravity(const Area2DSW *p_area) {
 	} else {
 		gravity = p_area->get_gravity_vector() * p_area->get_gravity();
 	}
+
+	gravity*=gravity_scale;
 }
 
 void Body2DSW::integrate_forces(real_t p_step) {
@@ -385,7 +409,16 @@ void Body2DSW::integrate_forces(real_t p_step) {
 	}
 
 	_compute_area_gravity(current_area);
-	density=current_area->get_density();
+
+	if (angular_damp>=0)
+		area_angular_damp=angular_damp;
+	else
+		area_angular_damp=current_area->get_angular_damp();
+
+	if (linear_damp>=0)
+		area_linear_damp=linear_damp;
+	else
+		area_linear_damp=current_area->get_linear_damp();
 
 	Vector2 motion;
 	bool do_motion=false;
@@ -414,12 +447,12 @@ void Body2DSW::integrate_forces(real_t p_step) {
 			force+=applied_force;
 			real_t torque=applied_torque;
 
-			real_t damp = 1.0 - p_step * density;
+			real_t damp = 1.0 - p_step * area_linear_damp;
 
 			if (damp<0) // reached zero in the given time
 				damp=0;
 
-			real_t angular_damp = 1.0 - p_step * density * get_space()->get_body_angular_velocity_damp_ratio();
+			real_t angular_damp = 1.0 - p_step * area_angular_damp;
 
 			if (angular_damp<0) // reached zero in the given time
 				angular_damp=0;
@@ -608,8 +641,12 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti
 	island_list_next=NULL;
 	_set_static(false);
 	first_time_kinematic=false;
-	density=0;
+	linear_damp=-1;
+	angular_damp=-1;
+	area_angular_damp=0;
+	area_linear_damp=0;
 	contact_count=0;
+	gravity_scale=1.0;
 
 	still_time=0;
 	continuous_cd_mode=Physics2DServer::CCD_MODE_DISABLED;

+ 11 - 3
servers/physics_2d/body_2d_sw.h

@@ -47,6 +47,10 @@ class Body2DSW : public CollisionObject2DSW {
 	Vector2 linear_velocity;
 	real_t angular_velocity;
 
+	real_t linear_damp;
+	real_t angular_damp;
+	real_t gravity_scale;
+
 	real_t mass;
 	real_t bounce;
 	real_t friction;
@@ -55,7 +59,8 @@ class Body2DSW : public CollisionObject2DSW {
 	real_t _inv_inertia;
 
 	Vector2 gravity;
-	real_t density;
+	real_t area_linear_damp;
+	real_t area_angular_damp;
 
 	real_t still_time;
 
@@ -219,8 +224,10 @@ public:
 	_FORCE_INLINE_ real_t get_inv_inertia() const { return _inv_inertia; }
 	_FORCE_INLINE_ real_t get_friction() const { return friction; }
 	_FORCE_INLINE_ Vector2 get_gravity() const { return gravity; }
-	_FORCE_INLINE_ real_t get_density() const { return density; }
 	_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
+	_FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
+	_FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
+
 
 	void integrate_forces(real_t p_step);
 	void integrate_velocities(real_t p_step);
@@ -306,7 +313,8 @@ public:
 	real_t step;
 
 	virtual Vector2 get_total_gravity() const {  return body->get_gravity();  } // get gravity vector working on this body space/area
-	virtual float get_total_density() const {  return body->get_density();  } // get density of this body space/area
+	virtual float get_total_angular_damp() const {  return body->get_angular_damp();  } // get density of this body space/area
+	virtual float get_total_linear_damp() const {  return body->get_linear_damp();  } // get density of this body space/area
 
 	virtual float get_inverse_mass() const {  return body->get_inv_mass();  } // get the mass
 	virtual real_t get_inverse_inertia() const { return body->get_inv_inertia();   } // get density of this body space

+ 1 - 1
servers/physics_2d/body_pair_2d_sw.cpp

@@ -190,7 +190,7 @@ bool BodyPair2DSW::_test_ccd(float p_step,Body2DSW *p_A, int p_shape_A,const Mat
 	p_A->get_shape(p_shape_A)->project_rangev(mnormal,p_xform_A,min,max);
 	bool fast_object = mlen > (max-min)*0.3; //going too fast in that direction
 
-	if (fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
+	if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis
 		return false;
 	}
 

+ 1 - 4
servers/physics_2d/space_2d_sw.cpp

@@ -606,8 +606,7 @@ void Space2DSW::set_param(Physics2DServer::SpaceParameter p_param, real_t p_valu
 		case Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration=p_value; break;
 		case Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: body_linear_velocity_sleep_treshold=p_value; break;
 		case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: body_angular_velocity_sleep_treshold=p_value; break;
-		case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep=p_value; break;
-		case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio=p_value; break;
+		case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep=p_value; break;		
 		case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias=p_value; break;
 	}
 }
@@ -622,7 +621,6 @@ real_t Space2DSW::get_param(Physics2DServer::SpaceParameter p_param) const {
 		case Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: return body_linear_velocity_sleep_treshold;
 		case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: return body_angular_velocity_sleep_treshold;
 		case Physics2DServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
-		case Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio;
 		case Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
 	}
 	return 0;
@@ -664,7 +662,6 @@ Space2DSW::Space2DSW() {
 	body_linear_velocity_sleep_treshold=0.01;
 	body_angular_velocity_sleep_treshold=(8.0 / 180.0 * Math_PI);
 	body_time_to_sleep=0.5;
-	body_angular_velocity_damp_ratio=15;
 
 
 	broadphase = BroadPhase2DSW::create_func();

+ 1 - 2
servers/physics_2d/space_2d_sw.h

@@ -93,7 +93,6 @@ class Space2DSW {
 	float body_linear_velocity_sleep_treshold;
 	float body_angular_velocity_sleep_treshold;
 	float body_time_to_sleep;
-	float body_angular_velocity_damp_ratio;
 
 	bool locked;
 
@@ -142,7 +141,7 @@ public:
 	_FORCE_INLINE_ real_t get_body_linear_velocity_sleep_treshold() const { return body_linear_velocity_sleep_treshold; }
 	_FORCE_INLINE_ real_t get_body_angular_velocity_sleep_treshold() const { return body_angular_velocity_sleep_treshold; }
 	_FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
-	_FORCE_INLINE_ real_t get_body_angular_velocity_damp_ratio() const { return body_angular_velocity_damp_ratio; }
+
 
 
 	void update();

+ 14 - 5
servers/physics_2d_server.cpp

@@ -39,20 +39,24 @@ void Physics2DDirectBodyState::integrate_forces() {
 
 	real_t av = get_angular_velocity();
 
-	float damp = 1.0 - step * get_total_density();
+	float damp = 1.0 - step * get_total_linear_damp();
 
 	if (damp<0) // reached zero in the given time
 		damp=0;
 
 	lv*=damp;
+
+	damp = 1.0 - step * get_total_angular_damp();
+
+	if (damp<0) // reached zero in the given time
+		damp=0;
+
 	av*=damp;
 
 	set_linear_velocity(lv);
 	set_angular_velocity(av);
 
 
-
-
 }
 
 Object* Physics2DDirectBodyState::get_contact_collider_object(int p_contact_idx) const {
@@ -70,7 +74,8 @@ Physics2DServer * Physics2DServer::get_singleton() {
 void Physics2DDirectBodyState::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("get_total_gravity"),&Physics2DDirectBodyState::get_total_gravity);
-	ObjectTypeDB::bind_method(_MD("get_total_density"),&Physics2DDirectBodyState::get_total_density);
+	ObjectTypeDB::bind_method(_MD("get_total_linear_damp"),&Physics2DDirectBodyState::get_total_linear_damp);
+	ObjectTypeDB::bind_method(_MD("get_total_angular_damp"),&Physics2DDirectBodyState::get_total_angular_damp);
 
 	ObjectTypeDB::bind_method(_MD("get_inverse_mass"),&Physics2DDirectBodyState::get_inverse_mass);
 	ObjectTypeDB::bind_method(_MD("get_inverse_inertia"),&Physics2DDirectBodyState::get_inverse_inertia);
@@ -538,7 +543,8 @@ void Physics2DServer::_bind_methods() {
 	BIND_CONSTANT( AREA_PARAM_GRAVITY_VECTOR );
 	BIND_CONSTANT( AREA_PARAM_GRAVITY_IS_POINT );
 	BIND_CONSTANT( AREA_PARAM_GRAVITY_POINT_ATTENUATION );
-	BIND_CONSTANT( AREA_PARAM_DENSITY );
+	BIND_CONSTANT( AREA_PARAM_LINEAR_DAMP);
+	BIND_CONSTANT( AREA_PARAM_ANGULAR_DAMP);
 	BIND_CONSTANT( AREA_PARAM_PRIORITY );
 
 	BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE );
@@ -553,6 +559,9 @@ void Physics2DServer::_bind_methods() {
 	BIND_CONSTANT( BODY_PARAM_BOUNCE );
 	BIND_CONSTANT( BODY_PARAM_FRICTION );
 	BIND_CONSTANT( BODY_PARAM_MASS );
+	BIND_CONSTANT( BODY_PARAM_GRAVITY_SCALE );
+	BIND_CONSTANT( BODY_PARAM_LINEAR_DAMP);
+	BIND_CONSTANT( BODY_PARAM_ANGULAR_DAMP);
 	BIND_CONSTANT( BODY_PARAM_MAX );
 
 	BIND_CONSTANT( BODY_STATE_TRANSFORM );

+ 8 - 4
servers/physics_2d_server.h

@@ -43,7 +43,8 @@ protected:
 public:
 
 	virtual Vector2 get_total_gravity() const=0; // get gravity vector working on this body space/area
-	virtual float get_total_density() const=0; // get density of this body space/area
+	virtual float get_total_linear_damp() const=0; // get density of this body space/area
+	virtual float get_total_angular_damp() const=0; // get density of this body space/area
 
 	virtual float get_inverse_mass() const=0; // get the mass
 	virtual real_t get_inverse_inertia() const=0; // get density of this body space
@@ -277,7 +278,6 @@ public:
 		SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD,
 		SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD,
 		SPACE_PARAM_BODY_TIME_TO_SLEEP,
-		SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,
 		SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,
 	};
 
@@ -301,7 +301,8 @@ public:
 		AREA_PARAM_GRAVITY_VECTOR,
 		AREA_PARAM_GRAVITY_IS_POINT,
 		AREA_PARAM_GRAVITY_POINT_ATTENUATION,
-		AREA_PARAM_DENSITY,
+		AREA_PARAM_LINEAR_DAMP,
+		AREA_PARAM_ANGULAR_DAMP,
 		AREA_PARAM_PRIORITY
 	};
 
@@ -401,6 +402,9 @@ public:
 		BODY_PARAM_BOUNCE,
 		BODY_PARAM_FRICTION,
 		BODY_PARAM_MASS, ///< unused for static, always infinite
+		BODY_PARAM_GRAVITY_SCALE,
+		BODY_PARAM_LINEAR_DAMP,
+		BODY_PARAM_ANGULAR_DAMP,
 		BODY_PARAM_MAX,
 	};
 
@@ -414,7 +418,7 @@ public:
 		BODY_STATE_LINEAR_VELOCITY,
 		BODY_STATE_ANGULAR_VELOCITY,
 		BODY_STATE_SLEEPING,
-		BODY_STATE_CAN_SLEEP
+		BODY_STATE_CAN_SLEEP,
 	};
 
 	virtual void body_set_state(RID p_body, BodyState p_state, const Variant& p_variant)=0;

+ 27 - 4
servers/visual/shader_language.cpp

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

+ 2 - 4
tools/SCsub

@@ -13,11 +13,9 @@ if (env["tools"]!="no"):
 	SConscript('freetype/SCsub');
 	SConscript('doc/SCsub')
 	SConscript('pck/SCsub')
-	
 
+	lib = env.Library("tool",env.tool_sources)
 
-lib = env.Library("tool",env.tool_sources)
-
-env.Prepend(LIBS=[lib])
+	env.Prepend(LIBS=[lib])
 
 

+ 23 - 5
tools/editor/editor_node.cpp

@@ -978,6 +978,15 @@ void EditorNode::_dialog_action(String p_file) {
 			}
 
 		} break;
+
+		case FILE_SAVE_AND_RUN: {
+			if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
+
+				_save_scene(p_file);
+				_run(false);
+			}
+		} break;
+
 		case FILE_EXPORT_MESH_LIBRARY: {
 
 			Ref<MeshLibrary> ml;
@@ -1391,13 +1400,10 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
 		}
 
 		if (scene->get_filename()=="") {
-
-
 			current_option=-1;
 			//accept->get_cancel()->hide();
-			accept->get_ok()->set_text("I see..");
-			accept->set_text("Scene has never been saved. Save before running!");
-			accept->popup_centered(Size2(300,70));;
+			/**/
+			_menu_option_confirm(FILE_SAVE_BEFORE_RUN, false);
 			return;
 
 		}
@@ -1664,6 +1670,18 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
 			
 		} break;
 
+		case FILE_SAVE_BEFORE_RUN: {
+			if (!p_confirmed) {
+				accept->get_ok()->set_text("Yes");
+				accept->set_text("This scene has never been saved. Save before running?");
+				accept->popup_centered(Size2(300, 70));
+				break;
+			}
+
+			_menu_option(FILE_SAVE_AS_SCENE);
+			_menu_option_confirm(FILE_SAVE_AND_RUN, true);
+		} break;
+
 		case FILE_DUMP_STRINGS: {
 
 			Node *scene = edited_scene;

+ 2 - 0
tools/editor/editor_node.h

@@ -108,6 +108,8 @@ class EditorNode : public Node {
 		FILE_OPEN_SCENE,
 		FILE_SAVE_SCENE,
 		FILE_SAVE_AS_SCENE,
+		FILE_SAVE_BEFORE_RUN,
+		FILE_SAVE_AND_RUN,
 		FILE_IMPORT_SUBSCENE,
 		FILE_EXPORT_PROJECT,
 		FILE_EXPORT_MESH_LIBRARY,

BIN
tools/editor/icons/icon_graph_comment.png


BIN
tools/editor/icons/icon_graph_cube_uniform.png


BIN
tools/editor/icons/icon_graph_input.png


BIN
tools/editor/icons/icon_graph_rgb.png


BIN
tools/editor/icons/icon_graph_rgb_op.png


BIN
tools/editor/icons/icon_graph_rgb_uniform.png


BIN
tools/editor/icons/icon_graph_scalar.png


BIN
tools/editor/icons/icon_graph_scalar_interp.png


BIN
tools/editor/icons/icon_graph_scalar_op.png


BIN
tools/editor/icons/icon_graph_scalar_uniform.png


BIN
tools/editor/icons/icon_graph_scalars_to_vec.png


BIN
tools/editor/icons/icon_graph_texscreen.png


BIN
tools/editor/icons/icon_graph_texture_uniform.png


BIN
tools/editor/icons/icon_graph_time.png


BIN
tools/editor/icons/icon_graph_vec_dp.png


BIN
tools/editor/icons/icon_graph_vec_interp.png


BIN
tools/editor/icons/icon_graph_vec_length.png


BIN
tools/editor/icons/icon_graph_vec_op.png


BIN
tools/editor/icons/icon_graph_vec_scalar_op.png


BIN
tools/editor/icons/icon_graph_vec_to_scalars.png


BIN
tools/editor/icons/icon_graph_vecs_to_xform.png


BIN
tools/editor/icons/icon_graph_vector.png


BIN
tools/editor/icons/icon_graph_vector_uniform.png


BIN
tools/editor/icons/icon_graph_xform.png


BIN
tools/editor/icons/icon_graph_xform_mult.png


BIN
tools/editor/icons/icon_graph_xform_scalar_func.png


BIN
tools/editor/icons/icon_graph_xform_to_vecs.png


BIN
tools/editor/icons/icon_graph_xform_uniform.png


BIN
tools/editor/icons/icon_graph_xform_vec_func.png


BIN
tools/editor/icons/icon_graph_xform_vec_imult.png


BIN
tools/editor/icons/icon_graph_xform_vec_mult.png


+ 1 - 1
tools/editor/plugins/canvas_item_editor_plugin.cpp

@@ -2888,7 +2888,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
 	p->add_separator();
 	p->add_item("Copy Pose",ANIM_COPY_POSE);
 	p->add_item("Paste Pose",ANIM_PASTE_POSE);
-	p->add_item("Clear Pose",ANIM_CLEAR_POSE,KEY_MASK_ALT|KEY_K);
+	p->add_item("Clear Pose",ANIM_CLEAR_POSE,KEY_MASK_SHIFT|KEY_K);
 
 	value_dialog = memnew( AcceptDialog );
 	value_dialog->set_title("Set a Value");

+ 1 - 1
tools/editor/plugins/script_editor_plugin.cpp

@@ -1578,7 +1578,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 	menu_hb->add_child(file_menu);
 	file_menu->set_text("File");
 	file_menu->get_popup()->add_item("Open",FILE_OPEN);
-	file_menu->get_popup()->add_item("Save",FILE_SAVE,KEY_MASK_ALT|KEY_S);
+	file_menu->get_popup()->add_item("Save",FILE_SAVE,KEY_MASK_ALT|KEY_MASK_CMD|KEY_S);
 	file_menu->get_popup()->add_item("Save As..",FILE_SAVE_AS);
 	file_menu->get_popup()->add_item("Save All",FILE_SAVE_ALL,KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_S);
 	file_menu->get_popup()->connect("item_pressed", this,"_menu_option");

+ 154 - 63
tools/editor/plugins/shader_graph_editor_plugin.cpp

@@ -200,7 +200,7 @@ void ShaderGraphView::_vec_input_changed(double p_value, int p_id,Array p_arr){
 }
 void ShaderGraphView::_xform_input_changed(int p_id, Node *p_button){
 
-	print_line("XFIC");
+
 	ToolButton *tb = p_button->cast_to<ToolButton>();
 	ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
 	ped_popup->set_size(tb->get_size());
@@ -383,6 +383,41 @@ void ShaderGraphView::_connection_request(const String& p_from, int p_from_slot,
 	ur->commit_action();
 
 
+}
+
+void ShaderGraphView::_disconnection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot) {
+
+	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+
+	int from_idx=-1;
+	int to_idx=-1;
+	for (Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
+
+		if (p_from==E->get()->get_name())
+			from_idx=E->key();
+		if (p_to==E->get()->get_name())
+			to_idx=E->key();
+	}
+
+	ERR_FAIL_COND(from_idx==-1);
+	ERR_FAIL_COND(to_idx==-1);
+
+	if (!graph->is_node_connected(type,from_idx,p_from_slot,to_idx,p_to_slot))
+		return; //nothing to disconnect
+
+	ur->create_action("Disconnect Graph Nodes");
+
+	List<ShaderGraph::Connection> conns;
+
+	graph->get_node_connections(type,&conns);
+	//disconnect/reconnect dependencies
+	ur->add_do_method(graph.ptr(),"disconnect_node",type,from_idx,p_from_slot,to_idx,p_to_slot);
+	ur->add_undo_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();
+
+
 }
 
 void ShaderGraphView::_node_removed(int p_id) {
@@ -410,7 +445,7 @@ void ShaderGraphView::_node_removed(int p_id) {
 
 void ShaderGraphView::_node_moved(const Vector2& p_from, const Vector2& p_to,int p_id) {
 
-	print_line("moved from "+p_from+" to "+p_to);
+
 	ERR_FAIL_COND(!node_map.has(p_id));
 	UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
 	ur->create_action("Move Shader Graph Node");
@@ -433,8 +468,8 @@ void ShaderGraphView::_create_node(int p_id) {
 	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(0.9,0.4,1),
+		Color(0.8,1,0.2),
 		Color(1,0.2,0.2),
 		Color(0,1,1)
 	};
@@ -710,14 +745,9 @@ void ShaderGraphView::_create_node(int p_id) {
 
 
 		} 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");
+		case ShaderGraph::NODE_XFORM_VEC_MULT: {
 
+			gn->set_title("XFVecMult");
 
 			Button *button = memnew( Button("RotOnly"));
 			button->set_toggle_mode(true);
@@ -739,6 +769,32 @@ void ShaderGraphView::_create_node(int p_id) {
 			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;
+		case ShaderGraph::NODE_XFORM_VEC_INV_MULT: {
+
+			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);
+
+			gn->add_child( memnew(Label("vec")));
+			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->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
 
 		} break; // mat4 x vec3 inverse mult (with no-translation option)
 		case ShaderGraph::NODE_SCALAR_FUNC: {
@@ -967,7 +1023,7 @@ void ShaderGraphView::_create_node(int p_id) {
 
 			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());
+			gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
 
 		} break; // vec3 interpolation  (with optional curve)
 		case ShaderGraph::NODE_SCALAR_INPUT: {
@@ -1157,7 +1213,7 @@ void ShaderGraphView::_create_node(int p_id) {
 	graph_edit->add_child(gn);
 	node_map[p_id]=gn;
 	gn->set_offset(graph->node_get_pos(type,p_id));
-	print_line("NODE "+itos(p_id)+" OFS "+gn->get_offset());
+
 
 }
 
@@ -1180,7 +1236,7 @@ void ShaderGraphView::_update_graph() {
 
 	List<int> nl;
 	graph->get_node_list(type,&nl);
-	print_line("graph nodes: "+itos(nl.size()));
+
 	for(List<int>::Element *E=nl.front();E;E=E->next()) {
 
 		_create_node(E->get());
@@ -1199,11 +1255,29 @@ void ShaderGraphView::_update_graph() {
 
 }
 
+void ShaderGraphView::_sg_updated() {
+
+	if (!graph.is_valid())
+		return;
+	switch(graph->get_graph_error(type)) {
+		case ShaderGraph::GRAPH_OK: status->set_text(""); break;
+		case ShaderGraph::GRAPH_ERROR_CYCLIC: status->set_text("Error: Cyclic Connection Link"); break;
+		case ShaderGraph::GRAPH_ERROR_MISSING_CONNECTIONS: status->set_text("Error: Missing Input Connections"); break;
+	}
+}
+
 void ShaderGraphView::set_graph(Ref<ShaderGraph> p_graph){
 
-	print_line("GRAPH EDIT: "+itos(p_graph.is_valid()));
+
+	if (graph.is_valid()) {
+		graph->disconnect("updated",this,"_sg_updated");
+	}
 	graph=p_graph;
+	if (graph.is_valid()) {
+		graph->connect("updated",this,"_sg_updated");
+	}
 	_update_graph();
+	_sg_updated();
 
 }
 
@@ -1262,6 +1336,7 @@ void ShaderGraphView::_bind_methods() {
 	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("_disconnection_request",&ShaderGraphView::_disconnection_request);
 
 	ObjectTypeDB::bind_method("_scalar_const_changed",&ShaderGraphView::_scalar_const_changed);
 	ObjectTypeDB::bind_method("_vec_const_changed",&ShaderGraphView::_vec_const_changed);
@@ -1286,6 +1361,7 @@ void ShaderGraphView::_bind_methods() {
 	ObjectTypeDB::bind_method("_cube_edited",&ShaderGraphView::_cube_edited);
 	ObjectTypeDB::bind_method("_comment_edited",&ShaderGraphView::_comment_edited);
 
+	ObjectTypeDB::bind_method("_sg_updated",&ShaderGraphView::_sg_updated);
 }
 
 ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
@@ -1295,8 +1371,15 @@ ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
 	block_update=false;
 	ped_popup = memnew( CustomPropertyEditor );
 	graph_edit->add_child(ped_popup);
-
-
+	status = memnew( Label );
+	graph_edit->get_top_layer()->add_child(status);
+	status->set_pos(Vector2(5,5));
+	status->add_color_override("font_color_shadow",Color(0,0,0));
+	status->add_color_override("font_color",Color(1,0.4,0.3));
+	status->add_constant_override("shadow_as_outline",1);
+	status->add_constant_override("shadow_offset_x",2);
+	status->add_constant_override("shadow_offset_y",2);
+	status->set_text("");
 }
 
 
@@ -1318,6 +1401,22 @@ void ShaderGraphEditor::_add_node(int p_type) {
 
 void ShaderGraphEditor::_notification(int p_what) {
 	if (p_what==NOTIFICATION_ENTER_TREE) {
+
+		for(int i=0;i<ShaderGraph::NODE_TYPE_MAX;i++) {
+
+			if (i==ShaderGraph::NODE_OUTPUT)
+				continue;
+			String nn = node_names[i];
+			String ic = nn.get_slice(":",0);
+			String v = nn.get_slice(":",1);
+			bool addsep=false;
+			if (nn.ends_with(":")) {
+				addsep=true;
+			}
+			menu->get_popup()->add_icon_item(get_icon(ic,"EditorIcons"),v,i);
+			if (addsep)
+				menu->get_popup()->add_separator();
+		}
 		menu->get_popup()->connect("item_pressed",this,"_add_node");
 
 
@@ -1332,38 +1431,38 @@ void ShaderGraphEditor::_bind_methods() {
 
 
 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)
+	"GraphInput:Input", // all inputs (shader type dependent)
+	"GraphScalar:Scalar Constant", //scalar constant
+	"GraphVector:Vector Constant", //vec3 constant
+	"GraphRgb:RGB Constant", //rgb constant (shows a color picker instead)
+	"GraphXform:XForm Constant", // 4x4 matrix constant
+	"GraphTime:Time:", // time in seconds
+	"GraphTexscreen:Screen Sample", // screen texture sampler (takes uv) (only usable in fragment shader)
+	"GraphScalarOp:Scalar Operator", // scalar vs scalar op (mul", add", div", etc)
+	"GraphVecOp:Vector Operator", // vec3 vs vec3 op (mul",ad",div",crossprod",etc)
+	"GraphVecScalarOp:Scalar+Vector Operator", // vec3 vs scalar op (mul", add", div", etc)
+	"GraphRgbOp:RGB Operator:", // vec3 vs vec3 rgb op (with scalar amount)", like brighten", darken", burn", dodge", multiply", etc.
+	"GraphXformMult:XForm Multiply", // mat4 x mat4
+	"GraphXformVecMult:XForm+Vector Multiply", // mat4 x vec3 mult (with no-translation option)
+	"GraphXformVecImult:Form+Vector InvMultiply:", // mat4 x vec3 inverse mult (with no-translation option)
+	"GraphXformScalarFunc:Scalar Function", // scalar function (sin", cos", etc)
+	"GraphXformVecFunc:Vector Function", // vector function (normalize", negate", reciprocal", rgb2hsv", hsv2rgb", etc", etc)
+	"GraphVecLength:Vector Length", // vec3 length
+	"GraphVecDp:Dot Product:", // vec3 . vec3 (dot product -> scalar output)
+	"GraphVecToScalars:Vector -> Scalars", // 1 vec3 input", 3 scalar outputs
+	"GraphScalarsToVec:Scalars -> Vector", // 3 scalar input", 1 vec3 output
+	"GraphXformToVecs:XForm -> Vectors", // 3 vec input", 1 xform output
+	"GraphVecsToXform:Vectors -> XForm:", // 3 vec input", 1 xform output
+	"GraphScalarInterp:Scalar Interpolate", // scalar interpolation (with optional curve)
+	"GraphVecInterp:Vector Interpolate:", // vec3 interpolation  (with optional curve)
+	"GraphScalarUniform:Scalar Uniform", // scalar uniform (assignable in material)
+	"GraphVectorUniform:Vector Uniform", // vec3 uniform (assignable in material)
+	"GraphRgbUniform:RGB Uniform", // color uniform (assignable in material)
+	"GraphXformUniform:XForm Uniform", // mat4 uniform (assignable in material)
+	"GraphTextureUniform:Texture Uniform", // texture input (assignable in material)
+	"GraphCubeUniform:CubeMap Uniform:", // cubemap input (assignable in material)
 	"Output", // output (shader type dependent)
-	"Comment", // comment
+	"GraphComment:Comment", // comment
 
 
 };
@@ -1371,23 +1470,10 @@ ShaderGraphEditor::ShaderGraphEditor() {
 
 	HBoxContainer *hbc = memnew( HBoxContainer );
 	menu = memnew( MenuButton );
-	menu->set_text("Add..");
+	menu->set_text("Add Node..");
 	hbc->add_child(menu);
 	add_child(hbc);
-	for(int i=0;i<ShaderGraph::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();
-	}
+
 
 	tabs = memnew(TabContainer);
 	tabs->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1404,8 +1490,13 @@ ShaderGraphEditor::ShaderGraphEditor() {
 		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");
+		graph_edits[i]->get_graph_edit()->connect("disconnection_request",graph_edits[i],"_disconnection_request");
+		graph_edits[i]->get_graph_edit()->set_right_disconnects(true);
+
 	}
 
+	tabs->set_current_tab(1);
+
 	set_custom_minimum_size(Size2(100,300));
 }
 

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

@@ -54,6 +54,7 @@ class ShaderGraphView : public Node {
 	CustomPropertyEditor *ped_popup;
 	bool block_update;
 
+	Label *status;
 	GraphEdit *graph_edit;
 	Ref<ShaderGraph> graph;
 	int edited_id;
@@ -66,6 +67,8 @@ class ShaderGraphView : public Node {
 
 
 	void _connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot);
+	void _disconnection_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);
@@ -93,7 +96,7 @@ class ShaderGraphView : public Node {
 	void _variant_edited();
 	void _comment_edited(int p_id,Node* p_button);
 
-
+	void _sg_updated();
 	Map<int,GraphNode*> node_map;
 protected:
 	void _notification(int p_what);

+ 6 - 6
tools/editor/plugins/spatial_editor_plugin.cpp

@@ -3650,12 +3650,12 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
 	p->add_check_item("Use Default sRGB",MENU_VIEW_USE_DEFAULT_SRGB);
 	p->add_separator();
 
-	p->add_check_item("1 Viewport",MENU_VIEW_USE_1_VIEWPORT,KEY_MASK_ALT+KEY_1);
-	p->add_check_item("2 Viewports",MENU_VIEW_USE_2_VIEWPORTS,KEY_MASK_ALT+KEY_2);
-	p->add_check_item("2 Viewports (Alt)",MENU_VIEW_USE_2_VIEWPORTS_ALT,KEY_MASK_SHIFT+KEY_MASK_ALT+KEY_2);
-	p->add_check_item("3 Viewports",MENU_VIEW_USE_3_VIEWPORTS,KEY_MASK_ALT+KEY_3);
-	p->add_check_item("3 Viewports (Alt)",MENU_VIEW_USE_3_VIEWPORTS_ALT,KEY_MASK_SHIFT+KEY_MASK_ALT+KEY_3);
-	p->add_check_item("4 Viewports",MENU_VIEW_USE_4_VIEWPORTS,KEY_MASK_ALT+KEY_4);
+	p->add_check_item("1 Viewport",MENU_VIEW_USE_1_VIEWPORT,KEY_MASK_CMD+KEY_1);
+	p->add_check_item("2 Viewports",MENU_VIEW_USE_2_VIEWPORTS,KEY_MASK_CMD+KEY_2);
+	p->add_check_item("2 Viewports (Alt)",MENU_VIEW_USE_2_VIEWPORTS_ALT,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_2);
+	p->add_check_item("3 Viewports",MENU_VIEW_USE_3_VIEWPORTS,KEY_MASK_CMD+KEY_3);
+	p->add_check_item("3 Viewports (Alt)",MENU_VIEW_USE_3_VIEWPORTS_ALT,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_3);
+	p->add_check_item("4 Viewports",MENU_VIEW_USE_4_VIEWPORTS,KEY_MASK_CMD+KEY_4);
 	p->add_separator();
 
 	p->add_check_item("Display Normal",MENU_VIEW_DISPLAY_NORMAL);

+ 2 - 2
tools/editor/project_manager.cpp

@@ -65,7 +65,7 @@ class NewProjectDialog : public ConfirmationDialog {
 		error->set_text("");
 		get_ok()->set_disabled(true);
 		DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-		if (d->change_dir(project_path->get_text())!=OK) {
+		if (project_path->get_text() != "" && d->change_dir(project_path->get_text())!=OK) {
 			error->set_text("Invalid Path for Project, Path Must Exist!");
 			memdelete(d);
 			return false;
@@ -82,7 +82,7 @@ class NewProjectDialog : public ConfirmationDialog {
 
 		} else {
 
-			if (!d->file_exists("engine.cfg")) {
+			if (project_path->get_text() != "" && !d->file_exists("engine.cfg")) {
 
 				error->set_text("Invalid Project Path (engine.cfg must exist).");
 				memdelete(d);

+ 0 - 2
tools/editor/script_editor_debugger.cpp

@@ -478,8 +478,6 @@ void ScriptEditorDebugger::_notification(int p_what) {
 			if (!connection->is_connected()) {
 				stop();
 				editor->notify_child_process_exited(); //somehow, exited
-				msgdialog->set_text("Process being debugged exited.");
-				msgdialog->popup_centered(Size2(250,100));
 				break;
 			};
 

+ 439 - 0
tools/export/blender25/godot_export_manager.py

@@ -0,0 +1,439 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# Script copyright (c) Andreas Esau
+
+bl_info = {
+    "name": "Godot Export Manager",
+    "author": "Andreas Esau",
+    "version": (1, 0),
+    "blender": (2, 7, 0),
+    "location": "Scene Properties > Godot Export Manager",
+    "description": "Godot Export Manager uses the Better Collada Exporter to manage Export Groups and automatically export the objects groups to Collada Files.",
+    "warning": "",
+    "wiki_url": ("http://www.godotengine.org"),
+    "tracker_url": "",
+    "category": "Import-Export"}
+
+import bpy
+from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, IntProperty, CollectionProperty, PointerProperty
+import os
+from bpy.app.handlers import persistent
+from mathutils import Vector, Matrix
+
+class godot_export_manager(bpy.types.Panel):
+    bl_label = "Godot Export Manager"
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = "scene"
+    
+    bpy.types.Scene.godot_export_on_save = BoolProperty(default=False)
+        
+    ### draw function for all ui elements
+    def draw(self, context):
+        layout = self.layout
+        split = self.layout.split()
+        scene = bpy.data.scenes[0]
+        ob = context.object
+        scene = context.scene
+        
+        row = layout.row()
+        col = row.column()
+        col.prop(scene,"godot_export_on_save",text="Export Groups on save")
+        
+        row = layout.row()
+        col = row.column(align=True)
+        op = col.operator("scene.godot_add_objects_to_group",text="Add selected objects to Group",icon="COPYDOWN")
+        
+        op = col.operator("scene.godot_delete_objects_from_group",text="Delete selected objects from Group",icon="PASTEDOWN")
+        
+        
+        
+        row = layout.row()
+        col = row.column()
+        col.label(text="Export Groups:")
+        
+        
+        row = layout.row()
+        col = row.column()
+        
+        col.template_list("UI_List_Godot","dummy",scene, "godot_export_groups", scene, "godot_export_groups_index",rows=1,maxrows=10,type='DEFAULT')
+        
+        col = row.column(align=True)
+        col.operator("scene.godot_add_export_group",text="",icon="ZOOMIN")
+        col.operator("scene.godot_delete_export_group",text="",icon="ZOOMOUT")
+        col.operator("scene.godot_export_all_groups",text="",icon="EXPORT")
+        
+        if len(scene.godot_export_groups) > 0:        
+            row = layout.row()
+            col = row.column()
+            group = scene.godot_export_groups[scene.godot_export_groups_index]
+            col.prop(group,"name",text="Group Name")
+            col.prop(group,"export_name",text="Export Name")
+            col.prop(group,"export_path",text="Export Filepath")
+            
+            row = layout.row()
+            col = row.column()
+            row = layout.row()
+            col = row.column()
+            col.label(text="Export Settings:")
+            
+            col = col.row(align=True)
+            col.prop(group,"apply_loc",toggle=True,icon="MAN_TRANS")
+            col.prop(group,"apply_rot",toggle=True,icon="MAN_ROT")
+            col.prop(group,"apply_scale",toggle=True,icon="MAN_SCALE")
+            
+            row = layout.row()
+            col = row.column()
+            
+            col.prop(group,"use_mesh_modifiers")
+            col.prop(group,"use_tangent_arrays")
+            col.prop(group,"use_triangles")
+            col.prop(group,"use_copy_images")
+            col.prop(group,"use_active_layers")
+            col.prop(group,"use_exclude_ctrl_bones")
+            col.prop(group,"use_anim")
+            col.prop(group,"use_anim_action_all")
+            col.prop(group,"use_anim_skip_noexp")
+            col.prop(group,"use_anim_optimize")
+            col.prop(group,"anim_optimize_precision")
+            col.prop(group,"use_metadata")
+
+### Custom template_list look
+class UI_List_Godot(bpy.types.UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        ob = data
+        slot = item
+        col = layout.row(align=True)
+        
+        col.label(text=item.name,icon="GROUP")
+        col.prop(item,"active",text="")
+        
+        op = col.operator("scene.godot_select_group_objects",text="",emboss=False,icon="RESTRICT_SELECT_OFF")
+        op.idx = index
+        op = col.operator("scene.godot_export_group",text="",emboss=False,icon="EXPORT")
+        op.idx = index
+              
+class add_objects_to_group(bpy.types.Operator):
+    bl_idname = "scene.godot_add_objects_to_group"
+    bl_label = "Add Objects to Group"
+    bl_description = "Adds the selected Objects to the active group below."
+    
+    def execute(self,context):
+        scene = context.scene
+        
+        objects_str = ""
+        if len(scene.godot_export_groups) > 0:
+            for i,object in enumerate(context.selected_objects):
+                if object.name not in scene.godot_export_groups[scene.godot_export_groups_index].nodes:
+                    node = scene.godot_export_groups[scene.godot_export_groups_index].nodes.add()
+                    node.name = object.name
+                    if i == 0:
+                        objects_str += object.name
+                    else:
+                        objects_str += ", "+object.name    
+        
+        
+            self.report({'INFO'}, objects_str + " added to group." )
+            bpy.ops.ed.undo_push(message="Objects added to group")
+        else:
+            self.report({'WARNING'}, "Create a group first." )   
+        return{'FINISHED'}
+
+class del_objects_from_group(bpy.types.Operator):
+    bl_idname = "scene.godot_delete_objects_from_group"
+    bl_label = "Delete Objects from Group"
+    bl_description = "Delets the selected Objects from the active group below."
+    
+    def execute(self,context):
+        scene = context.scene
+        
+        if len(scene.godot_export_groups) > 0:
+                
+            selected_objects = []
+            for object in context.selected_objects:
+                selected_objects.append(object.name)
+            
+            objects_str = ""
+            j = 0
+            for i,node in enumerate(scene.godot_export_groups[scene.godot_export_groups_index].nodes):
+                if node.name in selected_objects:
+                    scene.godot_export_groups[scene.godot_export_groups_index].nodes.remove(i)
+
+                    
+                    if j == 0:
+                            objects_str += object.name
+                    else:
+                        objects_str += ", "+object.name 
+                    j+=1
+                    
+                    
+            self.report({'INFO'}, objects_str + " deleted from group." )                    
+            bpy.ops.ed.undo_push(message="Objects deleted from group")
+        else:
+            self.report({'WARNING'}, "There is no group to delete from." ) 
+        return{'FINISHED'}
+
+class select_group_objects(bpy.types.Operator):
+    bl_idname = "scene.godot_select_group_objects"
+    bl_label = "Select Group Objects"
+    bl_description = "Will select all group Objects in the scene."
+    
+    idx = IntProperty()
+    
+    def execute(self,context):
+        scene = context.scene
+        for object in context.scene.objects:
+            object.select = False
+        for node in scene.godot_export_groups[self.idx].nodes:
+            if node.name in bpy.data.objects:
+                bpy.data.objects[node.name].select = True
+                context.scene.objects.active = bpy.data.objects[node.name]
+        return{'FINISHED'}
+      
+class export_groups_autosave(bpy.types.Operator):
+    bl_idname = "scene.godot_export_groups_autosave"
+    bl_label = "Export All Groups"
+    bl_description = "Exports all groups to Collada."
+    
+    def execute(self,context):
+        scene = context.scene
+        if scene.godot_export_on_save:
+            for i in range(len(scene.godot_export_groups)):
+                if scene.godot_export_groups[i].active:
+                    bpy.ops.scene.godot_export_group(idx=i)
+        self.report({'INFO'}, "All Groups exported." )
+        bpy.ops.ed.undo_push(message="Export all Groups")   
+        return{'FINISHED'}
+    
+class export_all_groups(bpy.types.Operator):
+    bl_idname = "scene.godot_export_all_groups"
+    bl_label = "Export All Groups"
+    bl_description = "Exports all groups to Collada."
+    
+    def execute(self,context):
+        scene = context.scene
+        for i in range(len(scene.godot_export_groups)):
+            if scene.godot_export_groups[i].active:
+                bpy.ops.scene.godot_export_group(idx=i)
+        self.report({'INFO'}, "All Groups exported." )
+        bpy.ops.ed.undo_push(message="Export all Groups")   
+        return{'FINISHED'}    
+        
+        
+class export_group(bpy.types.Operator):
+    bl_idname = "scene.godot_export_group"
+    bl_label = "Export Group"
+    bl_description = "Exports the active group to destination folder as Collada file."
+    
+    idx = IntProperty(default=0)
+    
+    def copy_object_recursive(self,ob,parent,single_user = True):
+        new_ob = bpy.data.objects[ob.name].copy()
+        if single_user or ob.type=="ARMATURE":
+            new_mesh_data = new_ob.data.copy()
+            new_ob.data = new_mesh_data
+        bpy.context.scene.objects.link(new_ob)
+        
+        if ob != parent:
+           new_ob.parent = parent
+        else:
+            new_ob.parent = None   
+             
+        for child in ob.children:        
+            self.copy_object_recursive(child,new_ob,single_user)
+        new_ob.select = True    
+        return new_ob
+    
+    def delete_object(self,ob):
+        if ob != None:
+            for child in ob.children:
+                self.delete_object(child)
+            bpy.context.scene.objects.unlink(ob)
+            bpy.data.objects.remove(ob) 
+    
+    def convert_group_to_node(self,group):
+        if group.dupli_group != None:
+            for object in group.dupli_group.objects:
+                if object.parent == None:
+                    object = self.copy_object_recursive(object,object,True)
+                    matrix = Matrix(object.matrix_local)
+                    object.matrix_local = Matrix()
+                    object.matrix_local *= group.matrix_local
+                    object.matrix_local *= matrix
+        
+            self.delete_object(group)   
+    
+    def execute(self,context):
+        scene = context.scene
+        group = context.scene.godot_export_groups
+        
+        path = group[self.idx].export_path
+        if (path.find("//")==0 or path.find("\\\\")==0):
+            #if relative, convert to absolute
+            path = bpy.path.abspath(path)
+            path = path.replace("\\","/")
+        
+        ### if path exists and group export name is set the group will be exported  
+        if os.path.exists(path) and  group[self.idx].export_name != "":
+            
+            context.scene.layers = [True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True]
+            
+            
+            if group[self.idx].export_name.endswith(".dae"):
+                path = os.path.join(path,group[self.idx].export_name)
+            else:    
+                path = os.path.join(path,group[self.idx].export_name+".dae")
+            
+            hide_select = []    
+            for object in context.scene.objects:
+                hide_select.append(object.hide_select)
+                object.hide_select = False
+                object.select = False
+            context.scene.objects.active = None
+            
+            for i,object in enumerate(group[self.idx].nodes):
+                
+                if object.name in bpy.data.objects:
+                    if bpy.data.objects[object.name].type == "EMPTY":
+                        self.convert_group_to_node(bpy.data.objects[object.name])
+                    else:    
+                        bpy.data.objects[object.name].select = True
+
+                else: # if object is not in the scene anymore it will be removed from the group
+                    group[self.idx].nodes.remove(i)        
+            bpy.ops.object.transform_apply(location=group[self.idx].apply_loc, rotation=group[self.idx].apply_rot, scale=group[self.idx].apply_scale)
+            bpy.ops.export_scene.dae(check_existing=True, filepath=path, filter_glob="*.dae", object_types=group[self.idx].object_types, use_export_selected=group[self.idx].use_export_selected, use_mesh_modifiers=group[self.idx].use_mesh_modifiers, use_tangent_arrays=group[self.idx].use_tangent_arrays, use_triangles=group[self.idx].use_triangles, use_copy_images=group[self.idx].use_copy_images, use_active_layers=group[self.idx].use_active_layers, use_exclude_ctrl_bones=group[self.idx].use_exclude_ctrl_bones, use_anim=group[self.idx].use_anim, use_anim_action_all=group[self.idx].use_anim_action_all, use_anim_skip_noexp=group[self.idx].use_anim_skip_noexp, use_anim_optimize=group[self.idx].use_anim_optimize, anim_optimize_precision=group[self.idx].anim_optimize_precision, use_metadata=group[self.idx].use_metadata)    
+          
+                      
+            self.report({'INFO'}, '"'+group[self.idx].name+'"' + " Group exported." )  
+            msg = "Export Group "+group[self.idx].name
+            bpy.ops.ed.undo_push(message="")
+            bpy.ops.ed.undo()
+            bpy.ops.ed.undo_push(message=msg)
+        else:
+            self.report({'INFO'}, "Define Export Name and Export Path." )  
+        return{'FINISHED'}
+
+class add_export_group(bpy.types.Operator):
+    bl_idname = "scene.godot_add_export_group"
+    bl_label = "Adds a new export Group"
+    bl_description = "Creates a new Export Group with the selected Objects assigned to it."
+    
+    def execute(self,context):
+        scene = context.scene
+        
+        item = scene.godot_export_groups.add()
+        item.name = "New Group"
+        for object in context.selected_objects:
+            node = item.nodes.add()
+            node.name = object.name
+        scene.godot_export_groups_index = len(scene.godot_export_groups)-1    
+        bpy.ops.ed.undo_push(message="Create New Export Group")
+        return{'FINISHED'}
+    
+class del_export_group(bpy.types.Operator):
+    bl_idname = "scene.godot_delete_export_group"
+    bl_label = "Delets the selected export Group"
+    bl_description = "Delets the active Export Group."
+    
+    def invoke(self, context, event):
+        wm = context.window_manager 
+        return wm.invoke_confirm(self,event)
+    
+    def execute(self,context):
+        scene = context.scene
+        
+        scene.godot_export_groups.remove(scene.godot_export_groups_index)
+        if scene.godot_export_groups_index > 0:
+            scene.godot_export_groups_index -= 1
+        bpy.ops.ed.undo_push(message="Delete Export Group")
+        return{'FINISHED'}    
+
+class godot_node_list(bpy.types.PropertyGroup):
+    name = StringProperty()
+    
+class godot_export_groups(bpy.types.PropertyGroup):
+    name = StringProperty(name="Group Name")
+    export_name = StringProperty(name="scene_name")
+    nodes = CollectionProperty(type=godot_node_list)
+    export_path = StringProperty(subtype="DIR_PATH")
+    active = BoolProperty(default=True,description="Export Group")
+    
+    object_types = EnumProperty(name="Object Types",options={'ENUM_FLAG'},items=(('EMPTY', "Empty", ""),('CAMERA', "Camera", ""),('LAMP', "Lamp", ""),('ARMATURE', "Armature", ""),('MESH', "Mesh", ""),('CURVE', "Curve", ""),),default={'EMPTY', 'CAMERA', 'LAMP', 'ARMATURE', 'MESH','CURVE'})
+    
+    apply_scale = BoolProperty(name="Apply Scale",description="Apply Scale before export.",default=False)
+    apply_rot = BoolProperty(name="Apply Rotation",description="Apply Rotation before export.",default=False)
+    apply_loc = BoolProperty(name="Apply Location",description="Apply Location before export.",default=False)
+    
+    use_export_selected = BoolProperty(name="Selected Objects",description="Export only selected objects (and visible in active layers if that applies).",default=True)
+    use_mesh_modifiers = BoolProperty(name="Apply Modifiers",description="Apply modifiers to mesh objects (on a copy!).",default=True)
+    use_tangent_arrays = BoolProperty(name="Tangent Arrays",description="Export Tangent and Binormal arrays (for normalmapping).",default=False)
+    use_triangles = BoolProperty(name="Triangulate",description="Export Triangles instead of Polygons.",default=False)
+
+    use_copy_images = BoolProperty(name="Copy Images",description="Copy Images (create images/ subfolder)",default=False)
+    use_active_layers = BoolProperty(name="Active Layers",description="Export only objects on the active layers.",default=True)
+    use_exclude_ctrl_bones = BoolProperty(name="Exclude Control Bones",description="Exclude skeleton bones with names that begin with 'ctrl'.",default=True)
+    use_anim = BoolProperty(name="Export Animation",description="Export keyframe animation",default=False)
+    use_anim_action_all = BoolProperty(name="All Actions",description=("Export all actions for the first armature found in separate DAE files"),default=False)
+    use_anim_skip_noexp = BoolProperty(name="Skip (-noexp) Actions",description="Skip exporting of actions whose name end in (-noexp). Useful to skip control animations.",default=True)
+    use_anim_optimize = BoolProperty(name="Optimize Keyframes",description="Remove double keyframes",default=True)
+
+    anim_optimize_precision = FloatProperty(name="Precision",description=("Tolerence for comparing double keyframes (higher for greater accuracy)"),min=1, max=16,soft_min=1, soft_max=16,default=6.0)
+
+    use_metadata = BoolProperty(name="Use Metadata",default=True,options={'HIDDEN'})
+
+def register():        
+    bpy.utils.register_class(godot_export_manager)
+    bpy.utils.register_class(godot_node_list)
+    bpy.utils.register_class(godot_export_groups)
+    bpy.utils.register_class(add_export_group)
+    bpy.utils.register_class(del_export_group)
+    bpy.utils.register_class(export_all_groups)
+    bpy.utils.register_class(export_groups_autosave)
+    bpy.utils.register_class(export_group)
+    bpy.utils.register_class(add_objects_to_group)
+    bpy.utils.register_class(del_objects_from_group)
+    bpy.utils.register_class(select_group_objects)
+    bpy.utils.register_class(UI_List_Godot)
+
+    bpy.types.Scene.godot_export_groups = CollectionProperty(type=godot_export_groups)
+    bpy.types.Scene.godot_export_groups_index = IntProperty(default=0,min=0)
+
+def unregister():
+    bpy.utils.unregister_class(godot_export_manager)
+    bpy.utils.unregister_class(godot_node_list)
+    bpy.utils.unregister_class(godot_export_groups)
+    bpy.utils.unregister_class(export_groups_autosave)
+    bpy.utils.unregister_class(add_export_group)
+    bpy.utils.unregister_class(del_export_group)
+    bpy.utils.unregister_class(export_all_groups)
+    bpy.utils.unregister_class(export_group)
+    bpy.utils.unregister_class(add_objects_to_group)
+    bpy.utils.unregister_class(del_objects_from_group)
+    bpy.utils.unlregister_class(select_group_objects)
+    bpy.utils.unregister_class(UI_List_Godot)
+
+@persistent
+def auto_export(dummy):
+    bpy.ops.scene.godot_export_groups_autosave()
+        
+bpy.app.handlers.save_post.append(auto_export)
+
+if __name__ == "__main__":
+    register()

+ 49 - 22
tools/export/blender25/io_scene_dae/export_dae.py

@@ -162,37 +162,61 @@ class DaeExporter:
 
 
 	def export_image(self,image):
-
 		if (image in self.image_cache):
 			return self.image_cache[image]
-
+			
 		imgpath = image.filepath
 		if (imgpath.find("//")==0 or imgpath.find("\\\\")==0):
 			#if relative, convert to absolute
 			imgpath = bpy.path.abspath(imgpath)
 
 		#path is absolute, now do something!
-
+		
 		if (self.config["use_copy_images"]):
 			#copy image
 			basedir = os.path.dirname(self.path)+"/images"
 			if (not os.path.isdir(basedir)):
 				os.makedirs(basedir)
-			dstfile=basedir+"/"+os.path.basename(imgpath)
-			if (not os.path.isfile(dstfile)):
-				shutil.copy(imgpath,dstfile)
-			imgpath="images/"+os.path.basename(imgpath)
+			
+			if os.path.isfile(imgpath):
+				dstfile=basedir+"/"+os.path.basename(imgpath)
+				
+				if (not os.path.isfile(dstfile)):
+					shutil.copy(imgpath,dstfile)
+					imgpath="images/"+os.path.basename(imgpath)
+			else:
+				### if file is not found save it as png file in the destination folder
+				img_tmp_path = image.filepath	
+				if img_tmp_path.endswith((".bmp",".rgb",".png",".jpeg",".jpg",".jp2",".tga",".cin",".dpx",".exr",".hdr",".tif")):
+					image.filepath = basedir+"/"+os.path.basename(img_tmp_path)
+				else:	
+					image.filepath = basedir+"/"+image.name+".png"
+					
+				dstfile=basedir+"/"+os.path.basename(image.filepath)
+				
+				if (not os.path.isfile(dstfile)):
+					
+					image.save()
+					imgpath="images/"+os.path.basename(image.filepath)
+				image.filepath = img_tmp_path
 
 		else:
 			#export relative, always, no one wants absolute paths.
 			try:
 				imgpath = os.path.relpath(imgpath,os.path.dirname(self.path)).replace("\\","/") # export unix compatible always
+				
 			except:
 				pass #fails sometimes, not sure why
-
-
+		
 
 		imgid = self.new_id("image")
+		
+		if (not os.path.isfile(imgpath)):
+			if img_tmp_path.endswith((".bmp",".rgb",".png",".jpeg",".jpg",".jp2",".tga",".cin",".dpx",".exr",".hdr",".tif")):
+				imgpath="images/"+os.path.basename(img_tmp_path)
+			else:
+				imgpath="images/"+image.name+".png"
+		
 		self.writel(S_IMGS,1,'<image id="'+imgid+'" name="'+image.name+'">')
 		self.writel(S_IMGS,2,'<init_from>'+imgpath+'</init_from>"/>')
 		self.writel(S_IMGS,1,'</image>')
@@ -1176,6 +1200,7 @@ class DaeExporter:
 	def export_node(self,node,il):
 		if (not node in self.valid_nodes):
 			return
+		prev_node = bpy.context.scene.objects.active
 		bpy.context.scene.objects.active = node
 
 		self.writel(S_NODES,il,'<node id="'+self.validate_id(node.name)+'" name="'+node.name+'" type="NODE">')
@@ -1199,6 +1224,7 @@ class DaeExporter:
 
 		il-=1
 		self.writel(S_NODES,il,'</node>')
+		bpy.context.scene.objects.active = prev_node #make previous node active again
 
 	def is_node_valid(self,node):
 		if (not node.type in self.config["object_types"]):
@@ -1441,12 +1467,13 @@ class DaeExporter:
 		return tcn
 
 	def export_animations(self):
-		tmp_mat = []												# workaround by ndee					
-		for s in self.skeletons:									# workaround by ndee
-			tmp_bone_mat = []										# workaround by ndee
-			for bone in s.pose.bones:								# workaround by ndee
-				tmp_bone_mat.append(Matrix(bone.matrix_basis))		# workaround by ndee
-			tmp_mat.append([Matrix(s.matrix_local),tmp_bone_mat])	# workaround by ndee -> stores skeleton and bone transformations
+		tmp_mat = []
+		for s in self.skeletons:
+			tmp_bone_mat = []
+			for bone in s.pose.bones:
+				tmp_bone_mat.append(Matrix(bone.matrix_basis))
+				bone.matrix_basis = Matrix()
+			tmp_mat.append([Matrix(s.matrix_local),tmp_bone_mat])
 			
 		self.writel(S_ANIM,0,'<library_animations>')
 
@@ -1481,7 +1508,7 @@ class DaeExporter:
 								bones.append(dp)
 
 				allowed_skeletons=[]
-				for i,y in enumerate(self.skeletons):				# workaround by ndee
+				for i,y in enumerate(self.skeletons):
 					if (y.animation_data):
 						for z in y.pose.bones:
 							if (z.bone.name in bones):
@@ -1489,9 +1516,9 @@ class DaeExporter:
 									allowed_skeletons.append(y)
 						y.animation_data.action=x;
 						
-						y.matrix_local = tmp_mat[i][0]				# workaround by ndee -> resets the skeleton transformation. 
-						for j,bone in enumerate(s.pose.bones):		# workaround by ndee
-							bone.matrix_basis = Matrix()			# workaround by ndee -> resets the bone transformations. Important if bones in follwing actions miss keyframes
+						y.matrix_local = tmp_mat[i][0]
+						for j,bone in enumerate(s.pose.bones):
+							bone.matrix_basis = Matrix()
 							
 
 				print("allowed skeletons "+str(allowed_skeletons))
@@ -1511,15 +1538,15 @@ class DaeExporter:
 
 			self.writel(S_ANIM_CLIPS,0,'</library_animation_clips>')
 
-			for i,s in enumerate(self.skeletons):					# workaround by ndee
+			for i,s in enumerate(self.skeletons):
 				if (s.animation_data==None):
 					continue
 				if s in cached_actions:
 					s.animation_data.action = bpy.data.actions[cached_actions[s]]
 				else:
 					s.animation_data.action = None
-					for j,bone in enumerate(s.pose.bones):			# workaround by ndee
-						bone.matrix_basis = tmp_mat[i][1][j]		# workaround by ndee  -> resets the bone transformation to what they were before exporting.
+					for j,bone in enumerate(s.pose.bones):
+						bone.matrix_basis = tmp_mat[i][1][j]
 		else:
 			self.export_animation(self.scene.frame_start,self.scene.frame_end)