Преглед изворни кода

Merge pull request #6 from okamstudio/master

Sync
Ricardo Pérez пре 10 година
родитељ
комит
7bb53831d8
59 измењених фајлова са 1342 додато и 356 уклоњено
  1. 46 0
      SConstruct
  2. 21 21
      core/io/file_access_memory.cpp
  3. 2 1
      core/io/resource_format_xml.cpp
  4. 36 8
      core/io/resource_loader.cpp
  5. 1 1
      core/method_bind.h
  6. 8 3
      core/ustring.cpp
  7. 253 3
      core/variant.cpp
  8. 2 1
      core/variant.h
  9. 1 0
      demos/2d/isometric_light/engine.cfg
  10. BIN
      demos/2d/kinematic_char/circle.png
  11. BIN
      demos/2d/kinematic_char/colworld.scn
  12. BIN
      demos/2d/kinematic_char/long_obstacle.png
  13. 29 9
      demos/2d/kinematic_char/player.gd
  14. 1 1
      demos/2d/platformer/enemy.gd
  15. BIN
      demos/2d/platformer/one_way_platform.png
  16. 220 0
      demos/2d/platformer/one_way_platform.xml
  17. 18 13
      demos/2d/platformer/stage.xml
  18. 1 1
      demos/3d/platformer/enemy.gd
  19. 1 0
      demos/3d/truck_town/engine.cfg
  20. 1 0
      demos/gui/rich_text_bbcode/engine.cfg
  21. 1 1
      demos/misc/window_management/engine.cfg
  22. 94 91
      drivers/SCsub
  23. 2 2
      drivers/chibi/cp_player_data_control.cpp
  24. 1 0
      drivers/convex_decomp/b2Polygon.cpp
  25. 57 4
      drivers/gles2/shader_compiler_gles2.cpp
  26. 7 0
      drivers/gles2/shader_compiler_gles2.h
  27. 1 1
      drivers/theoraplayer/video_stream_theoraplayer.cpp
  28. 1 0
      drivers/windows/dir_access_windows.cpp
  29. 1 1
      platform/android/android_native_app_glue.h
  30. 6 0
      platform/windows/SCsub
  31. 25 82
      platform/windows/godot_win.cpp
  32. 6 5
      platform/windows/os_windows.cpp
  33. 16 0
      scene/2d/physics_body_2d.cpp
  34. 5 0
      scene/2d/physics_body_2d.h
  35. 1 1
      scene/3d/sprite_3d.cpp
  36. 205 11
      scene/animation/tween.cpp
  37. 21 0
      scene/animation/tween.h
  38. 0 1
      scene/gui/file_dialog.cpp
  39. 56 32
      scene/gui/label.cpp
  40. 2 1
      scene/gui/label.h
  41. 3 1
      scene/gui/rich_text_label.cpp
  42. 6 3
      scene/gui/text_edit.cpp
  43. 1 0
      scene/main/node.h
  44. 2 2
      scene/resources/animation.cpp
  45. 2 0
      scene/resources/packed_scene.cpp
  46. 2 2
      scene/resources/shader_graph.cpp
  47. 13 5
      scene/resources/theme.cpp
  48. 1 0
      servers/physics_2d/body_2d_sw.cpp
  49. 7 1
      servers/physics_2d/body_2d_sw.h
  50. 53 0
      servers/physics_2d/body_pair_2d_sw.cpp
  51. 37 30
      servers/physics_2d/space_2d_sw.cpp
  52. 2 0
      servers/physics_2d/space_2d_sw.h
  53. 1 0
      tools/editor/editor_import_export.cpp
  54. 1 0
      tools/editor/editor_node.cpp
  55. 1 1
      tools/editor/editor_settings.cpp
  56. 5 2
      tools/editor/io_plugins/editor_font_import_plugin.cpp
  57. 51 13
      tools/editor/plugins/script_editor_plugin.cpp
  58. 4 0
      tools/editor/plugins/script_editor_plugin.h
  59. 1 1
      version.py

+ 46 - 0
SConstruct

@@ -123,6 +123,7 @@ opts.Add('disable_3d', 'Disable 3D nodes for smaller executable (yes/no)', "no")
 opts.Add('disable_advanced_gui', 'Disable advance 3D gui nodes and behaviors (yes/no)', "no")
 opts.Add('colored', 'Enable colored output for the compilation (yes/no)', 'no')
 opts.Add('extra_suffix', 'Custom extra suffix added to the base filename of all generated binary files.', '')
+opts.Add('vsproj', 'Generate Visual Studio Project. (yes/no)', 'no')
 
 # add platform specific options
 
@@ -177,6 +178,25 @@ if selected_platform in platform_list:
 	else:
 		env = env_base.Clone()
 
+	if env['vsproj']=="yes":
+		env.vs_incs = []
+		env.vs_srcs = []
+		
+		def AddToVSProject( sources ):
+			for x in sources:
+				if type(x) == type(""):
+					fname = env.File(x).path
+				else:
+					fname = env.File(x)[0].path
+				pieces =  fname.split(".")
+				if len(pieces)>0:
+					basename = pieces[0]
+					basename = basename.replace('\\\\','/')
+					env.vs_srcs = env.vs_srcs + [basename + ".cpp"]
+					env.vs_incs = env.vs_incs + [basename + ".h"]					
+					#print basename	
+		env.AddToVSProject = AddToVSProject				
+		
 	env.extra_suffix=""
 	
 	if env["extra_suffix"] != '' :
@@ -330,6 +350,32 @@ if selected_platform in platform_list:
 	SConscript("main/SCsub")
 
 	SConscript("platform/"+selected_platform+"/SCsub"); # build selected platform
+	
+	# Microsoft Visual Studio Project Generation			
+	if (env['vsproj'])=="yes":		
+	
+		AddToVSProject(env.core_sources)
+		AddToVSProject(env.main_sources)
+		AddToVSProject(env.modules_sources)	
+		AddToVSProject(env.scene_sources)
+		AddToVSProject(env.servers_sources)
+		AddToVSProject(env.tool_sources)
+			
+		debug_variants = ['Debug|Win32']+['Debug|x64']
+		release_variants = ['Release|Win32']+['Release|x64']
+		release_debug_variants = ['Release_Debug|Win32']+['Release_Debug|x64']
+		variants = debug_variants + release_variants + release_debug_variants
+		debug_targets = ['Debug']+['Debug']
+		release_targets = ['Release']+['Release']
+		release_debug_targets = ['ReleaseDebug']+['ReleaseDebug']
+		targets = debug_targets + release_targets + release_debug_targets
+		msvproj = env.MSVSProject(target = ['#godot' + env['MSVSPROJECTSUFFIX'] ],
+								incs = env.vs_incs,
+								srcs = env.vs_srcs, 
+								runfile = targets, 
+								buildtarget = targets, 
+								auto_build_solution=1, 
+								variant = variants) 		
 
 else:
 

+ 21 - 21
core/io/file_access_memory.cpp

@@ -39,7 +39,7 @@ void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
 
 	if (!files) {
 		files = memnew((Map<String, Vector<uint8_t> >));
-	};
+	}
 
 	String name;
 	if (Globals::get_singleton())
@@ -49,7 +49,7 @@ void FileAccessMemory::register_file(String p_name, Vector<uint8_t> p_data) {
 	name = DirAccess::normalize_path(name);
 
 	(*files)[name] = p_data;
-};
+}
 
 void FileAccessMemory::cleanup() {
 
@@ -57,13 +57,13 @@ void FileAccessMemory::cleanup() {
 		return;
 
 	memdelete(files);
-};
+}
 
 
 FileAccess* FileAccessMemory::create() {
 
 	return memnew(FileAccessMemory);
-};
+}
 
 bool FileAccessMemory::file_exists(const String& p_name) {
 
@@ -71,7 +71,7 @@ bool FileAccessMemory::file_exists(const String& p_name) {
 	name = DirAccess::normalize_path(name);
 
 	return files && (files->find(name) != NULL);
-};
+}
 
 
 Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
@@ -89,57 +89,57 @@ Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
 	pos = 0;
 
 	return OK;
-};
+}
 
 void FileAccessMemory::close() {
 
 	data = NULL;
-};
+}
 
 bool FileAccessMemory::is_open() const {
 
 	return data != NULL;
-};
+}
 
 void FileAccessMemory::seek(size_t p_position) {
 
 	ERR_FAIL_COND(!data);
 	pos = p_position;
-};
+}
 
 void FileAccessMemory::seek_end(int64_t p_position) {
 
 	ERR_FAIL_COND(!data);
 	pos = length + p_position;
-};
+}
 
 size_t FileAccessMemory::get_pos() const {
 
 	ERR_FAIL_COND_V(!data, 0);
 	return pos;
-};
+}
 
 size_t FileAccessMemory::get_len() const {
 
 	ERR_FAIL_COND_V(!data, 0);
 	return length;
-};
+}
 
 bool FileAccessMemory::eof_reached() const {
 
 	return pos >= length;
-};
+}
 
 uint8_t FileAccessMemory::get_8() const {
 
-	uint8_t ret;
+	uint8_t ret = 0;
 	if (pos < length) {
 		ret = data[pos];
-	};
+	}
 	++pos;
 
 	return ret;
-};
+}
 
 int FileAccessMemory::get_buffer(uint8_t *p_dst,int p_length) const {
 
@@ -156,19 +156,19 @@ int FileAccessMemory::get_buffer(uint8_t *p_dst,int p_length) const {
 	pos += p_length;
 
 	return read;
-};
+}
 
 Error FileAccessMemory::get_error() const {
 
 	return pos >= length ? ERR_FILE_EOF : OK;
-};
+}
 
 void FileAccessMemory::store_8(uint8_t p_byte) {
 
 	ERR_FAIL_COND(!data);
 	ERR_FAIL_COND(pos >= length);
 	data[pos++] = p_byte;
-};
+}
 
 void FileAccessMemory::store_buffer(const uint8_t *p_src,int p_length) {
 
@@ -176,11 +176,11 @@ void FileAccessMemory::store_buffer(const uint8_t *p_src,int p_length) {
 	int write = MIN(p_length, left);
 	if (write < p_length) {
 		WARN_PRINT("Writing less data than requested");
-	};
+	}
 
 	copymem(&data[pos], p_src, write);
 	pos += p_length;
-};
+}
 
 FileAccessMemory::FileAccessMemory() {
 

+ 2 - 1
core/io/resource_format_xml.cpp

@@ -309,6 +309,7 @@ Error ResourceInteractiveLoaderXML::_parse_array_element(Vector<char> &buff,bool
 
 				buff_max++;
 				buff.resize(buff_max);
+				buffptr=buff.ptr();
 
 			}
 
@@ -2563,7 +2564,7 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
 
 		List<PropertyInfo> property_list;
 		res->get_property_list(&property_list);
-		property_list.sort();
+//		property_list.sort();
 		for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
 
 

+ 36 - 8
core/io/resource_loader.cpp

@@ -117,6 +117,7 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const Stri
 
 RES ResourceFormatLoader::load(const String &p_path,const String& p_original_path) {
 
+	String path=p_path;
 
 	//or this must be implemented
 	Ref<ResourceInteractiveLoader> ril = load_interactive(p_path);
@@ -150,9 +151,13 @@ void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p
 
 RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_no_cache) {
 
-	String local_path = Globals::get_singleton()->localize_path(p_path);
+	String local_path;
+	if (p_path.is_rel_path())
+		local_path="res://"+p_path;
+	else
+		local_path = Globals::get_singleton()->localize_path(p_path);
 
-	local_path=find_complete_path(p_path,p_type_hint);
+	local_path=find_complete_path(local_path,p_type_hint);
 	ERR_FAIL_COND_V(local_path=="",RES());
 
 	if (!p_no_cache && ResourceCache::has(local_path)) {
@@ -209,7 +214,11 @@ RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_n
 Ref<ResourceImportMetadata> ResourceLoader::load_import_metadata(const String &p_path) {
 
 
-	String local_path = Globals::get_singleton()->localize_path(p_path);
+	String local_path;
+	if (p_path.is_rel_path())
+		local_path="res://"+p_path;
+	else
+		local_path = Globals::get_singleton()->localize_path(p_path);
 
 	String extension=p_path.extension();
 	bool found=false;
@@ -283,9 +292,13 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
 
 
 
-	String local_path = Globals::get_singleton()->localize_path(p_path);
+	String local_path;
+	if (p_path.is_rel_path())
+		local_path="res://"+p_path;
+	else
+		local_path = Globals::get_singleton()->localize_path(p_path);
 
-	local_path=find_complete_path(p_path,p_type_hint);
+	local_path=find_complete_path(local_path,p_type_hint);
 	ERR_FAIL_COND_V(local_path=="",Ref<ResourceInteractiveLoader>());
 
 
@@ -340,7 +353,13 @@ void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_l
 
 void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) {
 
-	String local_path = Globals::get_singleton()->localize_path(p_path);
+
+	String local_path;
+	if (p_path.is_rel_path())
+		local_path="res://"+p_path;
+	else
+		local_path = Globals::get_singleton()->localize_path(p_path);
+
 	String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
 
 	String extension=remapped_path.extension();
@@ -359,7 +378,11 @@ void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_depen
 
 String ResourceLoader::guess_full_filename(const String &p_path,const String& p_type) {
 
-	String local_path = Globals::get_singleton()->localize_path(p_path);
+	String local_path;
+	if (p_path.is_rel_path())
+		local_path="res://"+p_path;
+	else
+		local_path = Globals::get_singleton()->localize_path(p_path);
 
 	return find_complete_path(local_path,p_type);
 
@@ -367,7 +390,12 @@ String ResourceLoader::guess_full_filename(const String &p_path,const String& p_
 
 String ResourceLoader::get_resource_type(const String &p_path) {
 
-	String local_path = Globals::get_singleton()->localize_path(p_path);
+	String local_path;
+	if (p_path.is_rel_path())
+		local_path="res://"+p_path;
+	else
+		local_path = Globals::get_singleton()->localize_path(p_path);
+
 	String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
 	String extension=remapped_path.extension();
 

+ 1 - 1
core/method_bind.h

@@ -98,7 +98,7 @@ struct VariantCaster<m_enum> {\
 #define CHECK_ARG(m_arg)\
 	if ((m_arg-1)<p_arg_count) {\
 		Variant::Type argtype=get_argument_type(m_arg-1);\
-		if (!Variant::can_convert(p_args[m_arg-1]->get_type(),argtype)) {\
+		if (!Variant::can_convert_strict(p_args[m_arg-1]->get_type(),argtype)) {\
 			r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\
 			r_error.argument=m_arg-1;\
 			r_error.expected=argtype;\

+ 8 - 3
core/ustring.cpp

@@ -3297,8 +3297,11 @@ String String::path_to_file(const String& p_path) const {
 
 	String src=this->replace("\\","/").get_base_dir();
 	String dst=p_path.replace("\\","/").get_base_dir();
-
-	return src.path_to(dst)+p_path.get_file();
+	String rel = src.path_to(dst);
+	if (rel==dst) // failed
+		return p_path;
+	else
+		return rel+p_path.get_file();
 }
 
 String String::path_to(const String& p_path) const {
@@ -3333,7 +3336,9 @@ String String::path_to(const String& p_path) const {
 		String src_begin=src.get_slice("/",0);
 		String dst_begin=dst.get_slice("/",0);
 
-		ERR_FAIL_COND_V(src_begin!=dst_begin,p_path); //return dst absolute path
+		if (src_begin!=dst_begin)
+			return p_path; //impossible to do this
+
 		base=src_begin;
 		src=src.substr(src_begin.length(),src.length());
 		dst=dst.substr(dst_begin.length(),dst.length());

+ 253 - 3
core/variant.cpp

@@ -258,12 +258,12 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) {
 		case MATRIX32: {
 
 
-			static const Type invalid[]={
+			static const Type valid[]={
 				TRANSFORM,
 				NIL
 			};
 
-			invalid_types=invalid;
+			valid_types=valid;
 		} break;
 		case QUAT: {
 
@@ -299,6 +299,256 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) {
 
 		} break;		
 
+		case COLOR: {
+
+			static const Type valid[] = {
+				//STRING,
+				//INT,
+				NIL,
+			};
+
+			valid_types = valid;
+
+		} break;
+
+		case _RID: {
+
+			static const Type valid[]={
+				OBJECT,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case OBJECT: {
+
+			static const Type valid[]={
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case NODE_PATH: {
+
+			static const Type valid[]={
+				STRING,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case ARRAY: {
+
+
+			static const Type valid[]={
+				RAW_ARRAY,
+				INT_ARRAY,
+				STRING_ARRAY,
+				REAL_ARRAY,
+				COLOR_ARRAY,
+				VECTOR2_ARRAY,
+				VECTOR3_ARRAY,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+			// arrays
+		case RAW_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case INT_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+			valid_types=valid;
+		} break;
+		case REAL_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case STRING_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+			valid_types=valid;
+		} break;
+		case VECTOR2_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+			valid_types=valid;
+
+		} break;
+		case VECTOR3_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+			valid_types=valid;
+
+		} break;
+		case COLOR_ARRAY: {
+
+			static const Type valid[]={
+				ARRAY,
+				NIL
+			};
+
+			valid_types=valid;
+
+		} break;
+		default: {}
+	}
+
+
+	if (valid_types) {
+
+		int i=0;
+		while(valid_types[i]!=NIL) {
+
+			if (p_type_from==valid_types[i])
+				return true;
+			i++;
+		}
+	} else if (invalid_types) {
+
+
+		int i=0;
+		while(invalid_types[i]!=NIL) {
+
+			if (p_type_from==invalid_types[i])
+				return false;
+			i++;
+		}
+	}
+
+	return false;
+
+}
+
+bool Variant::can_convert_strict(Variant::Type p_type_from,Variant::Type p_type_to) {
+
+	if (p_type_from==p_type_to)
+		return true;
+	if (p_type_to==NIL && p_type_from!=NIL) //nil can convert to anything
+		return true;
+
+	if (p_type_from == NIL) {
+		return (p_type_to == OBJECT);
+	};
+
+	const Type *valid_types=NULL;
+	const Type *invalid_types=NULL;
+
+	switch(p_type_to) {
+		case BOOL: {
+
+			static const Type valid[]={
+				INT,
+				REAL,
+				//STRING,
+				NIL,
+			};
+
+			valid_types=valid;
+		} break;
+		case INT: {
+
+			static const Type valid[]={
+				BOOL,
+				REAL,
+				//STRING,
+				NIL,
+			};
+
+			valid_types=valid;
+
+		} break;
+		case REAL: {
+
+			static const Type valid[]={
+				BOOL,
+				INT,
+				//STRING,
+				NIL,
+			};
+
+			valid_types=valid;
+
+		} break;
+		case STRING: {
+
+
+			static const Type valid[]={
+				NODE_PATH,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case MATRIX32: {
+
+
+			static const Type valid[]={
+				TRANSFORM,
+				NIL
+			};
+
+			valid_types=valid;
+		} break;
+		case QUAT: {
+
+			static const Type valid[]={
+				MATRIX3,
+				NIL
+			};
+
+			valid_types=valid;
+
+		} break;
+		case MATRIX3: {
+
+			static const Type valid[]={
+				QUAT,
+				NIL
+			};
+
+			valid_types=valid;
+
+
+		} break;
+		case TRANSFORM: {
+
+			static const Type valid[]={
+				MATRIX32,
+				QUAT,
+				MATRIX3,
+				NIL
+			};
+
+			valid_types=valid;
+
+		} break;
+
 		case COLOR: {
 
 			static const Type valid[] = {
@@ -532,7 +782,7 @@ bool Variant::is_zero() const {
 		} break;
 		case QUAT: {
 
-			*reinterpret_cast<const Quat*>(_data._mem)==Quat();
+			return *reinterpret_cast<const Quat*>(_data._mem)==Quat();
 
 		} break;
 		case MATRIX3: {

+ 2 - 1
core/variant.h

@@ -165,7 +165,8 @@ public:
 
 	_FORCE_INLINE_ Type get_type() const { return type; }
 	static String get_type_name(Variant::Type p_type);
-	static bool can_convert(Type p_type_from,Type p_type_to);
+	static bool can_convert(Type p_type_from, Type p_type_to);
+	static bool can_convert_strict(Type p_type_from, Type p_type_to);
 
 
 

+ 1 - 0
demos/2d/isometric_light/engine.cfg

@@ -1,5 +1,6 @@
 [application]
 
+name="Isometric 2D + Lighting"
 main_scene="res://map.scn"
 
 [input]

BIN
demos/2d/kinematic_char/circle.png


BIN
demos/2d/kinematic_char/colworld.scn


BIN
demos/2d/kinematic_char/long_obstacle.png


+ 29 - 9
demos/2d/kinematic_char/player.gd

@@ -21,6 +21,9 @@ const STOP_FORCE = 1300
 const JUMP_SPEED = 200
 const JUMP_MAX_AIRBORNE_TIME=0.2
 
+const SLIDE_STOP_VELOCITY=1.0 #one pixel per second
+const SLIDE_STOP_MIN_TRAVEL=1.0 #one pixel
+
 var velocity = Vector2()
 var on_air_time=100
 var jumping=false
@@ -86,25 +89,42 @@ func _fixed_process(delta):
 			#char is on floor
 			on_air_time=0
 			floor_velocity=get_collider_velocity()
-			#velocity.y=0 
 			
-		#But we were moving and our motion was interrupted, 
-		#so try to complete the motion by "sliding"
-		#by the normal
-		motion = n.slide(motion)
-		velocity = n.slide(velocity)
-		
-		#then move again
-		move(motion)
+
+		if (on_air_time==0 and force.x==0 and get_travel().length() < SLIDE_STOP_MIN_TRAVEL and abs(velocity.x) < SLIDE_STOP_VELOCITY and get_collider_velocity()==Vector2()):
+			#Since this formula will always slide the character around, 
+			#a special case must be considered to to stop it from moving 
+			#if standing on an inclined floor. Conditions are:
+			# 1) Standing on floor (on_air_time==0)
+			# 2) Did not move more than one pixel (get_travel().length() < SLIDE_STOP_MIN_TRAVEL)
+			# 3) Not moving horizontally (abs(velocity.x) < SLIDE_STOP_VELOCITY)
+			# 4) Collider is not moving
+						
+			revert_motion()
+			velocity.y=0.0
+
+		else:
+			#For every other case of motion,our motion was interrupted.
+			#Try to complete the motion by "sliding"
+			#by the normal				
+			
+			motion = n.slide(motion)
+			velocity = n.slide(velocity)		
+			#then move again
+			move(motion)
 
 	if (floor_velocity!=Vector2()):
 		#if floor moves, move with floor
 		move(floor_velocity*delta)
 
 	if (jumping and velocity.y>0):
+		#if falling, no longer jumping
 		jumping=false
 		
 	if (on_air_time<JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping):	
+		# Jump must also be allowed to happen if the
+		# character left the floor a little bit ago.
+		# Makes controls more snappy.
 		velocity.y=-JUMP_SPEED	
 		jumping=true
 		

+ 1 - 1
demos/2d/platformer/enemy.gd

@@ -56,7 +56,7 @@ func _integrate_forces(s):
 					state=STATE_DYING
 					#lv=s.get_contact_local_normal(i)*400
 					s.set_angular_velocity(sign(dp.x)*33.0)
-					set_friction(true)
+					set_friction(1)
 					cc.disable()
 					get_node("sound").play("hit")
 					

BIN
demos/2d/platformer/one_way_platform.png


+ 220 - 0
demos/2d/platformer/one_way_platform.xml

@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<resource_file type="PackedScene" subresource_count="3" version="1.1" version_name="Godot Engine v1.1.rc1.custom_build">
+	<ext_resource path="res://one_way_platform.png" type="Texture"></ext_resource>
+	<resource type="RectangleShape2D" path="local://1">
+		<real name="custom_solver_bias"> 0 </real>
+		<vector2 name="extents"> 100, 10 </vector2>
+
+	</resource>
+	<main_resource>
+		<dictionary name="_bundled" shared="false">
+			<string> "conn_count" </string>
+			<int> 0 </int>
+			<string> "conns" </string>
+			<int_array  len="0"> 				 </int_array>
+			<string> "names" </string>
+			<string_array  len="42">
+				<string> "one_way_platform" </string>
+				<string> "StaticBody2D" </string>
+				<string> "_import_path" </string>
+				<string> "visibility/visible" </string>
+				<string> "visibility/opacity" </string>
+				<string> "visibility/self_opacity" </string>
+				<string> "visibility/light_mask" </string>
+				<string> "transform/pos" </string>
+				<string> "transform/rot" </string>
+				<string> "transform/scale" </string>
+				<string> "z/z" </string>
+				<string> "z/relative" </string>
+				<string> "input/pickable" </string>
+				<string> "shape_count" </string>
+				<string> "shapes/0/shape" </string>
+				<string> "shapes/0/transform" </string>
+				<string> "shapes/0/trigger" </string>
+				<string> "collision/layers" </string>
+				<string> "collision/mask" </string>
+				<string> "one_way_collision/direction" </string>
+				<string> "one_way_collision/max_depth" </string>
+				<string> "constant_linear_velocity" </string>
+				<string> "constant_angular_velocity" </string>
+				<string> "friction" </string>
+				<string> "bounce" </string>
+				<string> "__meta__" </string>
+				<string> "sprite" </string>
+				<string> "Sprite" </string>
+				<string> "texture" </string>
+				<string> "centered" </string>
+				<string> "offset" </string>
+				<string> "flip_h" </string>
+				<string> "flip_v" </string>
+				<string> "vframes" </string>
+				<string> "hframes" </string>
+				<string> "frame" </string>
+				<string> "modulate" </string>
+				<string> "region" </string>
+				<string> "region_rect" </string>
+				<string> "CollisionShape2D" </string>
+				<string> "shape" </string>
+				<string> "trigger" </string>
+			</string_array>
+			<string> "node_count" </string>
+			<int> 3 </int>
+			<string> "nodes" </string>
+			<int_array  len="135"> 				-1, -1, 1, 0, -1, 24, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 1, 12, 8, 13, 3, 14, 9, 15, 10, 16, 8, 17, 3, 18, 3, 19, 11, 20, 12, 21, 4, 22, 5, 23, 2, 24, 5, 25, 13, 0, 0, 0, 27, 26, -1, 21, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 1, 28, 14, 29, 1, 30, 4, 31, 8, 32, 8, 33, 3, 34, 3, 35, 7, 36, 15, 37, 8, 38, 16, 0, 0, 0, 39, 39, -1, 12, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 17, 8, 5, 9, 6, 10, 7, 11, 1, 40, 9, 41, 8, 0 </int_array>
+			<string> "variants" </string>
+			<array  len="18" shared="false">
+				<node_path> "" </node_path>
+				<bool> True </bool>
+				<real> 1 </real>
+				<int> 1 </int>
+				<vector2> 0, 0 </vector2>
+				<real> 0 </real>
+				<vector2> 1, 1 </vector2>
+				<int> 0 </int>
+				<bool> False </bool>
+				<resource  resource_type="Shape2D" path="local://1">  </resource>
+				<matrix32> 1, -0, 0, 1, 1.46304, -13.1672 </matrix32>
+				<vector2> 0, 1 </vector2>
+				<real> 20 </real>
+				<dictionary  shared="false">
+					<string> "__editor_plugin_screen__" </string>
+					<string> "2D" </string>
+					<string> "__editor_plugin_states__" </string>
+					<dictionary  shared="false">
+						<string> "2D" </string>
+						<dictionary  shared="false">
+							<string> "ofs" </string>
+							<vector2> -133.699, -110.553 </vector2>
+							<string> "snap_grid" </string>
+							<bool> False </bool>
+							<string> "snap_offset" </string>
+							<vector2> 0, 0 </vector2>
+							<string> "snap_pixel" </string>
+							<bool> False </bool>
+							<string> "snap_relative" </string>
+							<bool> False </bool>
+							<string> "snap_rotation" </string>
+							<bool> False </bool>
+							<string> "snap_rotation_offset" </string>
+							<real> 0 </real>
+							<string> "snap_rotation_step" </string>
+							<real> 0.261799 </real>
+							<string> "snap_show_grid" </string>
+							<bool> False </bool>
+							<string> "snap_step" </string>
+							<vector2> 10, 10 </vector2>
+							<string> "zoom" </string>
+							<real> 2.050546 </real>
+						</dictionary>
+						<string> "3D" </string>
+						<dictionary  shared="false">
+							<string> "ambient_light_color" </string>
+							<color> 0.15, 0.15, 0.15, 1 </color>
+							<string> "default_light" </string>
+							<bool> True </bool>
+							<string> "default_srgb" </string>
+							<bool> False </bool>
+							<string> "deflight_rot_x" </string>
+							<real> 0.942478 </real>
+							<string> "deflight_rot_y" </string>
+							<real> 0.628319 </real>
+							<string> "fov" </string>
+							<real> 45 </real>
+							<string> "show_grid" </string>
+							<bool> True </bool>
+							<string> "show_origin" </string>
+							<bool> True </bool>
+							<string> "viewport_mode" </string>
+							<int> 1 </int>
+							<string> "viewports" </string>
+							<array  len="4" shared="false">
+								<dictionary  shared="false">
+									<string> "distance" </string>
+									<real> 4 </real>
+									<string> "listener" </string>
+									<bool> True </bool>
+									<string> "pos" </string>
+									<vector3> 0, 0, 0 </vector3>
+									<string> "use_environment" </string>
+									<bool> False </bool>
+									<string> "use_orthogonal" </string>
+									<bool> False </bool>
+									<string> "x_rot" </string>
+									<real> 0 </real>
+									<string> "y_rot" </string>
+									<real> 0 </real>
+								</dictionary>
+								<dictionary  shared="false">
+									<string> "distance" </string>
+									<real> 4 </real>
+									<string> "listener" </string>
+									<bool> False </bool>
+									<string> "pos" </string>
+									<vector3> 0, 0, 0 </vector3>
+									<string> "use_environment" </string>
+									<bool> False </bool>
+									<string> "use_orthogonal" </string>
+									<bool> False </bool>
+									<string> "x_rot" </string>
+									<real> 0 </real>
+									<string> "y_rot" </string>
+									<real> 0 </real>
+								</dictionary>
+								<dictionary  shared="false">
+									<string> "distance" </string>
+									<real> 4 </real>
+									<string> "listener" </string>
+									<bool> False </bool>
+									<string> "pos" </string>
+									<vector3> 0, 0, 0 </vector3>
+									<string> "use_environment" </string>
+									<bool> False </bool>
+									<string> "use_orthogonal" </string>
+									<bool> False </bool>
+									<string> "x_rot" </string>
+									<real> 0 </real>
+									<string> "y_rot" </string>
+									<real> 0 </real>
+								</dictionary>
+								<dictionary  shared="false">
+									<string> "distance" </string>
+									<real> 4 </real>
+									<string> "listener" </string>
+									<bool> False </bool>
+									<string> "pos" </string>
+									<vector3> 0, 0, 0 </vector3>
+									<string> "use_environment" </string>
+									<bool> False </bool>
+									<string> "use_orthogonal" </string>
+									<bool> False </bool>
+									<string> "x_rot" </string>
+									<real> 0 </real>
+									<string> "y_rot" </string>
+									<real> 0 </real>
+								</dictionary>
+							</array>
+							<string> "zfar" </string>
+							<real> 500 </real>
+							<string> "znear" </string>
+							<real> 0.1 </real>
+						</dictionary>
+					</dictionary>
+					<string> "__editor_run_settings__" </string>
+					<dictionary  shared="false">
+						<string> "custom_args" </string>
+						<string> "-l $scene" </string>
+						<string> "run_mode" </string>
+						<int> 0 </int>
+					</dictionary>
+				</dictionary>
+				<resource  resource_type="Texture" path="res://one_way_platform.png">  </resource>
+				<color> 1, 1, 1, 1 </color>
+				<rect2> 0, 0, 0, 0 </rect2>
+				<vector2> 1.46304, -13.1672 </vector2>
+			</array>
+			<string> "version" </string>
+			<int> 1 </int>
+		</dictionary>
+
+	</main_resource>
+</resource_file>

Разлика између датотеке није приказан због своје велике величине
+ 18 - 13
demos/2d/platformer/stage.xml


+ 1 - 1
demos/3d/platformer/enemy.gd

@@ -45,7 +45,7 @@ func _integrate_forces(state):
 				state.set_angular_velocity( -dp.cross(up).normalized() *33.0)
 				get_node("AnimationPlayer").play("impact")
 				get_node("AnimationPlayer").queue("explode")
-				set_friction(true)
+				set_friction(1)
 				cc.disabled=true
 				get_node("sound").play("hit")
 				return

+ 1 - 0
demos/3d/truck_town/engine.cfg

@@ -1,5 +1,6 @@
 [application]
 
+name="Truck Town"
 main_scene="res://car_select.scn"
 
 [display]

+ 1 - 0
demos/gui/rich_text_bbcode/engine.cfg

@@ -1,3 +1,4 @@
 [application]
 
+name="Rich Text Label (BBCode)"
 main_scene="res://rich_text_bbcode.scn"

+ 1 - 1
demos/misc/window_management/engine.cfg

@@ -1,6 +1,6 @@
 [application]
 
-name="window_management"
+name="Window Management"
 main_scene="res://window_management.scn"
 icon="icon.png"
 

+ 94 - 91
drivers/SCsub

@@ -1,91 +1,94 @@
-Import('env')
-
-env.drivers_sources=[]
-#env.add_source_files(env.drivers_sources,"*.cpp")
-env.Append(CPPPATH=["vorbis"])
-Export('env')
-
-SConscript('unix/SCsub');
-SConscript('alsa/SCsub');
-SConscript('pulseaudio/SCsub');
-SConscript('windows/SCsub');
-SConscript('gles2/SCsub');
-SConscript('gl_context/SCsub');
-SConscript('openssl/SCsub');
-
-if (env["png"]=="yes"):
-	SConscript("png/SCsub");
-if (env["jpg"]=="yes"):
-	SConscript("jpg/SCsub");
-if (env["webp"]=="yes"):
-	SConscript("webp/SCsub");
-SConscript("dds/SCsub");
-SConscript("pvr/SCsub");
-SConscript("etc1/SCsub")
-if (env["builtin_zlib"]=="yes"):
-	SConscript("builtin_zlib/SCsub");
-if (env["openssl"]=="builtin"):
-	SConscript("builtin_openssl2/SCsub");
-
-SConscript("rtaudio/SCsub");
-SConscript("nedmalloc/SCsub");
-SConscript("trex/SCsub");
-SConscript("chibi/SCsub");
-if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"):
-        SConscript("ogg/SCsub");
-if (env["vorbis"]=="yes"):
-        SConscript("vorbis/SCsub");
-if (env["tools"]=="yes"):
-	SConscript("convex_decomp/SCsub");
-
-if env["theora"]=="yes":
-	SConscript("theoraplayer/SCsub")
-if (env["theora"]=="yes"):
-	SConscript("theora/SCsub");
-if (env['speex']=='yes'):
-	SConscript("speex/SCsub");
-if (env['musepack']=='yes'):
-	SConscript("mpc/SCsub");
-if (env["squish"]=="yes" and env["tools"]=="yes"):
-	SConscript("squish/SCsub");
-
-num = 0
-cur_base = ""
-total = len(env.drivers_sources)
-max_src = 64
-list = []
-lib_list = []
-
-import string
-
-for f in env.drivers_sources:
-	fname = ""
-	if type(f) == type(""):
-		fname = env.File(f).path
-	else:
-		fname = env.File(f)[0].path
-	#base = string.join(fname.split("/")[:-1], "/")
-	fname = fname.replace("\\", "/")
-	base = string.join(fname.split("/")[:2], "/")
-	if base != cur_base and len(list) > max_src:
-		lib = env.Library("drivers"+str(num), list)
-		lib_list.append(lib)
-		list = []
-		num = num+1
-	cur_base = base
-	list.append(f)
-
-if len(list) > 0:
-	lib = env.Library("drivers"+str(num), list)
-	lib_list.append(lib)
-
-
-drivers_base=[]
-env.add_source_files(drivers_base,"*.cpp")
-lib_list.insert(0, env.Library("drivers", drivers_base))
-
-env.Prepend(LIBS=lib_list)
-
-#lib = env.Library("drivers",env.drivers_sources)
-#env.Prepend(LIBS=[lib])
-
+Import('env')
+
+env.drivers_sources=[]
+#env.add_source_files(env.drivers_sources,"*.cpp")
+env.Append(CPPPATH=["vorbis"])
+Export('env')
+
+SConscript('unix/SCsub');
+SConscript('alsa/SCsub');
+SConscript('pulseaudio/SCsub');
+SConscript('windows/SCsub');
+SConscript('gles2/SCsub');
+SConscript('gl_context/SCsub');
+SConscript('openssl/SCsub');
+
+if (env["png"]=="yes"):
+	SConscript("png/SCsub");
+if (env["jpg"]=="yes"):
+	SConscript("jpg/SCsub");
+if (env["webp"]=="yes"):
+	SConscript("webp/SCsub");
+SConscript("dds/SCsub");
+SConscript("pvr/SCsub");
+SConscript("etc1/SCsub")
+if (env["builtin_zlib"]=="yes"):
+	SConscript("builtin_zlib/SCsub");
+if (env["openssl"]=="builtin"):
+	SConscript("builtin_openssl2/SCsub");
+
+SConscript("rtaudio/SCsub");
+SConscript("nedmalloc/SCsub");
+SConscript("trex/SCsub");
+SConscript("chibi/SCsub");
+if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"):
+        SConscript("ogg/SCsub");
+if (env["vorbis"]=="yes"):
+        SConscript("vorbis/SCsub");
+if (env["tools"]=="yes"):
+	SConscript("convex_decomp/SCsub");
+
+if env["theora"]=="yes":
+	SConscript("theoraplayer/SCsub")
+if (env["theora"]=="yes"):
+	SConscript("theora/SCsub");
+if (env['speex']=='yes'):
+	SConscript("speex/SCsub");
+if (env['musepack']=='yes'):
+	SConscript("mpc/SCsub");
+if (env["squish"]=="yes" and env["tools"]=="yes"):
+	SConscript("squish/SCsub");
+
+num = 0
+cur_base = ""
+total = len(env.drivers_sources)
+max_src = 64
+list = []
+lib_list = []
+
+import string
+
+if env['vsproj']=="yes":
+	env.AddToVSProject(env.drivers_sources)
+
+for f in env.drivers_sources:
+	fname = ""
+	if type(f) == type(""):
+		fname = env.File(f).path
+	else:
+		fname = env.File(f)[0].path
+	#base = string.join(fname.split("/")[:-1], "/")
+	fname = fname.replace("\\", "/")
+	base = string.join(fname.split("/")[:2], "/")
+	if base != cur_base and len(list) > max_src:
+		lib = env.Library("drivers"+str(num), list)
+		lib_list.append(lib)
+		list = []
+		num = num+1
+	cur_base = base
+	list.append(f)
+
+if len(list) > 0:
+	lib = env.Library("drivers"+str(num), list)
+	lib_list.append(lib)
+
+
+drivers_base=[]
+env.add_source_files(drivers_base,"*.cpp")
+lib_list.insert(0, env.Library("drivers", drivers_base))
+
+env.Prepend(LIBS=lib_list)
+
+#lib = env.Library("drivers",env.drivers_sources)
+#env.Prepend(LIBS=[lib])
+

+ 2 - 2
drivers/chibi/cp_player_data_control.cpp

@@ -233,7 +233,7 @@ int CPPlayer::get_channel_voice(int p_channel) {
 
 const char* CPPlayer::get_voice_sample_name(int p_voice) {
 
-	const char *name;
+	const char *name = NULL;
 
 
 
@@ -302,7 +302,7 @@ const char * CPPlayer::get_voice_instrument_name(int p_voice) {
 
 
 
-	const char *name;
+	const char *name = NULL;
 
 
 

+ 1 - 0
drivers/convex_decomp/b2Polygon.cpp

@@ -970,6 +970,7 @@ int32 DecomposeConvex(b2Polygon* p, b2Polygon* results, int32 maxPolys) {
 		}
 		if (nTri < 1) {
             //Still no luck?  Oh well...
+            delete[] triangulated;
             return -1;
         }
         int32 nPolys = PolygonizeTriangles(triangulated, nTri, results, maxPolys);

+ 57 - 4
drivers/gles2/shader_compiler_gles2.cpp

@@ -431,6 +431,42 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 //						code="get_texpos(gl_ProjectionMatrixInverse * texture2D( depth_texture, clamp(("+dump_node_code(onode->arguments[1],p_level)+").xy,vec2(0.0),vec2(1.0))*gl_LightSource[5].specular.zw+gl_LightSource[5].specular.xy)";
 						//code="(texture2D( screen_texture, ("+dump_node_code(onode->arguments[1],p_level)+").xy).rgb";
 						break;
+					} else if (custom_h && callfunc=="cosh_custom") {
+
+						if (!cosh_used) {
+							global_code=	"float cosh_custom(float val)\n"\
+									"{\n"\
+									"    float tmp = exp(val);\n"\
+									"    float cosH = (tmp + 1.0 / tmp) / 2.0;\n"\
+									"    return cosH;\n"\
+									"}\n"+global_code;
+							cosh_used=true;
+						}
+						code="cosh_custom("+dump_node_code(onode->arguments[1],p_level)+"";
+					} else if (custom_h && callfunc=="sinh_custom") {
+
+						if (!sinh_used) {
+							global_code=	"float sinh_custom(float val)\n"\
+									"{\n"\
+									"    float tmp = exp(val);\n"\
+									"    float sinH = (tmp - 1.0 / tmp) / 2.0;\n"\
+									"    return sinH;\n"\
+									"}\n"+global_code;
+							sinh_used=true;
+						}
+						code="sinh_custom("+dump_node_code(onode->arguments[1],p_level)+"";
+					} else if (custom_h && callfunc=="tanh_custom") {
+
+						if (!tanh_used) {
+							global_code=	"float tanh_custom(float val)\n"\
+									"{\n"\
+									"    float tmp = exp(val);\n"\
+									"    float tanH = (tmp - 1.0 / tmp) / (tmp + 1.0 / tmp);\n"\
+									"    return tanH;\n"\
+									"}\n"+global_code;
+							tanh_used=true;
+						}
+						code="tanh_custom("+dump_node_code(onode->arguments[1],p_level)+"";
 
 					} else {
 
@@ -634,6 +670,9 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.use_var2_interp=false;
 	r_flags.uses_normalmap=false;
 	r_flags.uses_normal=false;
+	sinh_used=false;
+	tanh_used=false;
+	cosh_used=false;
 
 	String error;
 	int errline,errcol;
@@ -662,12 +701,18 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.uses_shadow_color=uses_shadow_color;
 	r_code_line=code;
 	r_globals_line=global_code;
-
 	return OK;
 }
 
 ShaderCompilerGLES2::ShaderCompilerGLES2() {
 
+#ifdef GLEW_ENABLED
+	//use custom functions because they are not supported in GLSL120
+	custom_h=true;
+#else
+	custom_h=false;
+#endif
+
 	replace_table["bool"]= "bool";
 	replace_table["float" ]=  "float";
 	replace_table["vec2"  ]= "vec2";
@@ -686,9 +731,17 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	replace_table["acos" ]= "acos";
 	replace_table["atan" ]= "atan";
 	replace_table["atan2"]= "atan";
-	replace_table["sinh" ]= "sinh";
-	replace_table["cosh" ]= "cosh";
-	replace_table["tanh" ]= "tanh";
+
+	if (custom_h) {
+		replace_table["sinh" ]= "sinh_custom";
+		replace_table["cosh" ]= "cosh_custom";
+		replace_table["tanh" ]= "tanh_custom";
+	} else {
+		replace_table["sinh" ]= "sinh";
+		replace_table["cosh" ]= "cosh";
+		replace_table["tanh" ]= "tanh";
+	}
+
 	replace_table["pow"  ]= "pow";
 	replace_table["exp" ]=  "exp";
 	replace_table["log" ]=  "log";

+ 7 - 0
drivers/gles2/shader_compiler_gles2.h

@@ -56,6 +56,13 @@ private:
 	bool uses_worldvec;
 	bool vertex_code_writes_vertex;
 	bool uses_shadow_color;
+
+	bool sinh_used;
+	bool tanh_used;
+	bool cosh_used;
+
+	bool custom_h;
+
 	Flags *flags;
 
 	StringName vname_discard;

+ 1 - 1
drivers/theoraplayer/video_stream_theoraplayer.cpp

@@ -388,7 +388,7 @@ void VideoStreamTheoraplayer::pop_frame(Ref<ImageTexture> p_tex) {
 	{
 		DVector<uint8_t>::Write wr = data.write();
 		uint8_t* ptr = wr.ptr();
-		memcpy(ptr, f->getBuffer(), imgsize);
+		copymem(ptr, f->getBuffer(), imgsize);
 	}
     /*
     for (int i=0; i<h; i++) {

+ 1 - 0
drivers/windows/dir_access_windows.cpp

@@ -167,6 +167,7 @@ Error DirAccessWindows::change_dir(String p_dir) {
 
 	if (worked) {
 
+
 		GetCurrentDirectoryW(2048,real_current_dir_name);
 		current_dir=real_current_dir_name; // TODO, utf8 parser
 		current_dir=current_dir.replace("\\","/");

+ 1 - 1
platform/android/android_native_app_glue.h

@@ -26,7 +26,7 @@
 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
- * Copyright (C) 2010 The Android Open Source Project
+/* Copyright (C) 2010 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.

+ 6 - 0
platform/windows/SCsub

@@ -12,3 +12,9 @@ common_win=[
 ]
 
 env.Program('#bin/godot',['godot_win.cpp']+common_win,PROGSUFFIX=env["PROGSUFFIX"])
+
+# Microsoft Visual Studio Project Generation			
+if (env['vsproj'])=="yes":
+	env.vs_srcs = env.vs_srcs + ["platform/windows/godot_win.cpp"]
+	for x in common_win:
+		env.vs_srcs = env.vs_srcs + ["platform/windows/" + x]

+ 25 - 82
platform/windows/godot_win.cpp

@@ -115,29 +115,24 @@ PCHAR*
         return argv;
     }
 
-char* mb_to_utf8(const char* mbs) {
-
-	int wlen = MultiByteToWideChar(CP_ACP,0,mbs,-1,NULL,0); // returns 0 if failed
-	wchar_t *wbuf = new wchar_t[wlen + 1];
-	MultiByteToWideChar(CP_ACP,0,mbs,-1,wbuf,wlen);
-	wbuf[wlen]=0;
-
-	int ulen = WideCharToMultiByte(CP_UTF8,0,wbuf,-1,NULL,0,NULL,NULL);
+char* wc_to_utf8(const wchar_t* wc) {
+	int ulen = WideCharToMultiByte(CP_UTF8,0,wc,-1,NULL,0,NULL,NULL);
 	char * ubuf = new char[ulen + 1];
-	WideCharToMultiByte(CP_UTF8,0,wbuf,-1,ubuf,ulen,NULL,NULL);
+	WideCharToMultiByte(CP_UTF8,0,wc,-1,ubuf,ulen,NULL,NULL);
 	ubuf[ulen] = 0;
 	return ubuf;
 }
 
-int main(int argc, char** argv) {
+int widechar_main(int argc, wchar_t** argv) {
 
 	OS_Windows os(NULL);
 
 	setlocale(LC_CTYPE, "");
 
 	char ** argv_utf8 = new char*[argc];
+
 	for(int i=0; i<argc; ++i) {
-		argv_utf8[i] = mb_to_utf8(argv[i]);
+		argv_utf8[i] = wc_to_utf8(argv[i]);
 	}
 
 	Main::setup(argv_utf8[0], argc - 1, &argv_utf8[1]);
@@ -154,82 +149,30 @@ int main(int argc, char** argv) {
 	return os.get_exit_code();
 };
 
-HINSTANCE godot_hinstance = NULL;
-
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)	{
-
-    int    argc;
-    char** argv;
-
-    char*  arg;
-    int    index;
-    int    result;
-
-    // count the arguments
-
-    argc = 1;
-    arg  = lpCmdLine;
-
-    while (arg[0] != 0) {
-
-        while (arg[0] != 0 && arg[0] == ' ') {
-            arg++;
-        }
-
-        if (arg[0] != 0) {
-
-            argc++;
-
-            while (arg[0] != 0 && arg[0] != ' ') {
-                arg++;
-            }
-
-        }
-
-    }
-
-    // tokenize the arguments
-
-    argv = (char**)malloc(argc * sizeof(char*));
-
-    arg = lpCmdLine;
-    index = 1;
-
-    while (arg[0] != 0) {
-
-        while (arg[0] != 0 && arg[0] == ' ') {
-            arg++;
-        }
-
-        if (arg[0] != 0) {
-
-            argv[index] = arg;
-            index++;
-
-            while (arg[0] != 0 && arg[0] != ' ') {
-                arg++;
-            }
-
-            if (arg[0] != 0) {
-                arg[0] = 0;
-                arg++;
-            }
-
-        }
+int main(int _argc, char** _argv) {
+	// _argc and _argv are ignored
+	// we are going to use the WideChar version of them instead
 
-    }
+	LPWSTR *wc_argv;
+	int    argc;
+	int    result;
 
-    // put the program name into argv[0]
+	wc_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
 
-    char filename[_MAX_PATH];
+	if( NULL == wc_argv )	{
+		wprintf(L"CommandLineToArgvW failed\n");
+		return 0;
+	}
 
-    GetModuleFileName(NULL, filename, _MAX_PATH);
-    argv[0] = filename;
+	result = widechar_main(argc, wc_argv);
 
-    // call the user specified main function
+	LocalFree(wc_argv);
+	return result;
+}
 
-    result = main(argc, argv);
+HINSTANCE godot_hinstance = NULL;
 
-    free(argv);
-    return result;
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)	{
+	godot_hinstance = hInstance;
+	return main(0,NULL); 
 }

+ 6 - 5
platform/windows/os_windows.cpp

@@ -2117,12 +2117,13 @@ bool OS_Windows::has_environment(const String& p_var) const {
 
 String OS_Windows::get_environment(const String& p_var) const {
 
-	char* val = getenv(p_var.utf8().get_data());
-	if (val)
-		return val;
-
+	wchar_t wval[0x7Fff]; // MSDN says 32767 char is the maximum
+	int wlen = GetEnvironmentVariableW(p_var.c_str(),wval,0x7Fff);
+	if ( wlen > 0 ) {
+		return wval;
+	}
 	return "";
-};
+}
 
 String OS_Windows::get_stdin_string(bool p_block) {
 

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

@@ -925,6 +925,19 @@ Variant KinematicBody2D::_get_collider() const {
 	return obj;
 }
 
+void KinematicBody2D::revert_motion() {
+
+	Matrix32 gt = get_global_transform();
+	gt.elements[2]-=travel;
+	travel=Vector2();
+	set_global_transform(gt);
+
+}
+
+Vector2 KinematicBody2D::get_travel() const {
+
+	return travel;
+}
 
 Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 
@@ -942,6 +955,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 	Matrix32 gt = get_global_transform();
 	gt.elements[2]+=result.motion;
 	set_global_transform(gt);
+	travel=result.motion;
 	return result.remainder;
 
 #else
@@ -1173,6 +1187,8 @@ void KinematicBody2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to);
 
 	ObjectTypeDB::bind_method(_MD("test_move","rel_vec"),&KinematicBody2D::test_move);
+	ObjectTypeDB::bind_method(_MD("get_travel"),&KinematicBody2D::get_travel);
+	ObjectTypeDB::bind_method(_MD("revert_motion"),&KinematicBody2D::revert_motion);
 
 	ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody2D::is_colliding);
 

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

@@ -280,6 +280,7 @@ class KinematicBody2D : public PhysicsBody2D {
 	ObjectID collider;
 	int collider_shape;
 	Variant collider_metadata;
+	Vector2 travel;
 
 	Variant _get_collider() const;
 
@@ -294,6 +295,10 @@ public:
 
 	bool test_move(const Vector2& p_motion);
 	bool is_colliding() const;
+
+	Vector2 get_travel() const;
+	void revert_motion();
+
 	Vector2 get_collision_pos() const;
 	Vector2 get_collision_normal() const;
 	Vector2 get_collider_velocity() const;

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

@@ -292,7 +292,7 @@ SpriteBase3D::SpriteBase3D() {
 	parent_sprite=NULL;
 	pI=NULL;
 
-	for(int i=0;i<4;i++)
+	for(int i=0;i<FLAG_MAX;i++)
 		flags[i]=i==FLAG_TRANSPARENT;
 
 	axis=Vector3::AXIS_Z;

+ 205 - 11
scene/animation/tween.cpp

@@ -29,6 +29,81 @@
 #include "tween.h"
 #include "method_bind_ext.inc"
 
+void Tween::_add_pending_command(StringName p_key
+	,const Variant& p_arg1 ,const Variant& p_arg2 ,const Variant& p_arg3 ,const Variant& p_arg4 ,const Variant& p_arg5
+	,const Variant& p_arg6 ,const Variant& p_arg7 ,const Variant& p_arg8 ,const Variant& p_arg9 ,const Variant& p_arg10
+) {
+
+	pending_commands.push_back(PendingCommand());
+	PendingCommand& cmd = pending_commands.back()->get();
+
+	cmd.key = p_key;
+	int& count = cmd.args;
+	if(p_arg10.get_type() != Variant::NIL)
+		count = 10;
+	else if(p_arg9.get_type() != Variant::NIL)
+		count = 9;
+	else if(p_arg8.get_type() != Variant::NIL)
+		count = 8;
+	else if(p_arg7.get_type() != Variant::NIL)
+		count = 7;
+	else if(p_arg6.get_type() != Variant::NIL)
+		count = 6;
+	else if(p_arg5.get_type() != Variant::NIL)
+		count = 5;
+	else if(p_arg4.get_type() != Variant::NIL)
+		count = 4;
+	else if(p_arg3.get_type() != Variant::NIL)
+		count = 3;
+	else if(p_arg2.get_type() != Variant::NIL)
+		count = 2;
+	else if(p_arg1.get_type() != Variant::NIL)
+		count = 1;
+	if(count > 0)
+		cmd.arg[0] = p_arg1;
+	if(count > 1)
+		cmd.arg[1] = p_arg2;
+	if(count > 2)
+		cmd.arg[2] = p_arg3;
+	if(count > 3)
+		cmd.arg[3] = p_arg4;
+	if(count > 4)
+		cmd.arg[4] = p_arg5;
+	if(count > 5)
+		cmd.arg[5] = p_arg6;
+	if(count > 6)
+		cmd.arg[6] = p_arg7;
+	if(count > 7)
+		cmd.arg[7] = p_arg8;
+	if(count > 8)
+		cmd.arg[8] = p_arg9;
+	if(count > 9)
+		cmd.arg[9] = p_arg10;
+}
+
+void Tween::_process_pending_commands() {
+
+	for(List<PendingCommand>::Element *E=pending_commands.front();E;E=E->next()) {
+
+		PendingCommand& cmd = E->get();
+		Variant::CallError err;
+		Variant *arg[10] = {
+			&cmd.arg[0],
+			&cmd.arg[1],
+			&cmd.arg[2],
+			&cmd.arg[3],
+			&cmd.arg[4],
+			&cmd.arg[5],
+			&cmd.arg[6],
+			&cmd.arg[7],
+			&cmd.arg[8],
+			&cmd.arg[9],
+		};
+		this->call(cmd.key, (const Variant **) arg, cmd.args, err);
+	}
+	pending_commands.clear();
+}
+
 bool Tween::_set(const StringName& p_name, const Variant& p_value) {
 
 	String name=p_name;
@@ -456,6 +531,8 @@ bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
 
 void Tween::_tween_process(float p_delta) {
 
+	_process_pending_commands();
+
 	if (speed_scale == 0)
 		return;
 	p_delta *= speed_scale;
@@ -551,8 +628,12 @@ void Tween::_tween_process(float p_delta) {
 
 		_apply_tween_value(data, result);
 
-		if(data.finish)
+		if (data.finish) {
 			emit_signal("tween_complete",object,data.key);
+			// not repeat mode, remove completed action
+			if (!repeat)
+				call_deferred("remove", object, data.key);
+		}
 	}
 	pending_update --;
 }
@@ -734,7 +815,10 @@ bool Tween::resume_all() {
 
 bool Tween::remove(Object *p_object, String p_key) {
 
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		call_deferred("remove", p_object, p_key);
+		return true;
+	}
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
@@ -751,7 +835,10 @@ bool Tween::remove(Object *p_object, String p_key) {
 
 bool Tween::remove_all() {
 
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		call_deferred("remove_all");
+		return true;
+	}
 	set_active(false);
 	_set_process(false);
 	interpolates.clear();
@@ -940,7 +1027,19 @@ bool Tween::interpolate_property(Object *p_object
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("interpolate_property"
+			, p_object
+			, p_property
+			, p_initial_val
+			, p_final_val
+			, p_times_in_sec
+			, p_trans_type
+			, p_ease_type
+			, p_delay
+		);
+		return true;
+	}
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
@@ -987,7 +1086,19 @@ bool Tween::interpolate_method(Object *p_object
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("interpolate_method"
+			, p_object
+			, p_method
+			, p_initial_val
+			, p_final_val
+			, p_times_in_sec
+			, p_trans_type
+			, p_ease_type
+			, p_delay
+		);
+		return true;
+	}
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
@@ -999,6 +1110,7 @@ bool Tween::interpolate_method(Object *p_object
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
+	ERR_EXPLAIN("Object has no method named: %s" + p_method);
 	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 
 	InterpolateData data;
@@ -1029,10 +1141,23 @@ bool Tween::interpolate_callback(Object *p_object
 	, VARIANT_ARG_DECLARE
 ) {
 
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("interpolate_callback"
+			, p_object
+			, p_times_in_sec
+			, p_callback
+			, p_arg1
+			, p_arg2
+			, p_arg3
+			, p_arg4
+			, p_arg5
+		);
+		return true;
+	}
 	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec < 0, false);
 
+	ERR_EXPLAIN("Object has no callback named: %s" + p_callback);
 	ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
 
 	InterpolateData data;
@@ -1080,10 +1205,23 @@ bool Tween::interpolate_deferred_callback(Object *p_object
 	, VARIANT_ARG_DECLARE
 ) {
 
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("interpolate_deferred_callback"
+			, p_object
+			, p_times_in_sec
+			, p_callback
+			, p_arg1
+			, p_arg2
+			, p_arg3
+			, p_arg4
+			, p_arg5
+		);
+		return true;
+	}
 	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec < 0, false);
 
+	ERR_EXPLAIN("Object has no callback named: %s" + p_callback);
 	ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
 
 	InterpolateData data;
@@ -1135,7 +1273,20 @@ bool Tween::follow_property(Object *p_object
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("follow_property"
+			, p_object
+			, p_property
+			, p_initial_val
+			, p_target
+			, p_target_property
+			, p_times_in_sec
+			, p_trans_type
+			, p_ease_type
+			, p_delay
+		);
+		return true;
+	}
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 
@@ -1188,7 +1339,20 @@ bool Tween::follow_method(Object *p_object
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("follow_method"
+			, p_object
+			, p_method
+			, p_initial_val
+			, p_target
+			, p_target_method
+			, p_times_in_sec
+			, p_trans_type
+			, p_ease_type
+			, p_delay
+		);
+		return true;
+	}
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 
@@ -1199,7 +1363,9 @@ bool Tween::follow_method(Object *p_object
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
+	ERR_EXPLAIN("Object has no method named: %s" + p_method);
 	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
+	ERR_EXPLAIN("Target has no method named: %s" + p_target_method);
 	ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false);
 
 	Variant::CallError error;
@@ -1240,7 +1406,20 @@ bool Tween::targeting_property(Object *p_object
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("targeting_property"
+			, p_object
+			, p_property
+			, p_initial
+			, p_initial_property
+			, p_final_val
+			, p_times_in_sec
+			, p_trans_type
+			, p_ease_type
+			, p_delay
+		);
+		return true;
+	}
 	// convert INT to REAL is better for interpolaters
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
@@ -1298,7 +1477,20 @@ bool Tween::targeting_method(Object *p_object
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
-	ERR_FAIL_COND_V(pending_update != 0, false);
+	if(pending_update != 0) {
+		_add_pending_command("targeting_method"
+			, p_object
+			, p_method
+			, p_initial
+			, p_initial_method
+			, p_final_val
+			, p_times_in_sec
+			, p_trans_type
+			, p_ease_type
+			, p_delay
+		);
+		return true;
+	}
 	// convert INT to REAL is better for interpolaters
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
@@ -1309,7 +1501,9 @@ bool Tween::targeting_method(Object *p_object
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
+	ERR_EXPLAIN("Object has no method named: %s" + p_method);
 	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
+	ERR_EXPLAIN("Initial Object has no method named: %s" + p_initial_method);
 	ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false);
 
 	Variant::CallError error;

+ 21 - 0
scene/animation/tween.h

@@ -110,6 +110,27 @@ private:
 
 	List<InterpolateData> interpolates;
 
+	struct PendingCommand {
+		StringName key;
+		int args;
+		Variant arg[10];
+	};
+	List<PendingCommand> pending_commands;
+
+	void _add_pending_command(StringName p_key
+		,const Variant& p_arg1=Variant()
+		,const Variant& p_arg2=Variant()
+		,const Variant& p_arg3=Variant()
+		,const Variant& p_arg4=Variant()
+		,const Variant& p_arg5=Variant()
+		,const Variant& p_arg6=Variant()
+		,const Variant& p_arg7=Variant()
+		,const Variant& p_arg8=Variant()
+		,const Variant& p_arg9=Variant()
+		,const Variant& p_arg10=Variant()
+	);
+	void _process_pending_commands();
+
 	typedef real_t (*interpolater)(real_t t, real_t b, real_t c, real_t d);
 	static interpolater interpolaters[TRANS_COUNT][EASE_COUNT];
 

+ 0 - 1
scene/gui/file_dialog.cpp

@@ -92,7 +92,6 @@ void FileDialog::_file_entered(const String& p_file) {
 }
 
 void FileDialog::_save_confirm_pressed() {
-	
 	String f=dir_access->get_current_dir().plus_file(file->get_text());
 	emit_signal("file_selected",f);
 	hide();		

+ 56 - 32
scene/gui/label.cpp

@@ -99,7 +99,7 @@ void Label::_notification(int p_what) {
 		int chars_total=0;
 
 		int vbegin=0,vsep=0;
-
+		
 		if (lines_total && lines_total < lines_visible) {
 
 
@@ -136,10 +136,9 @@ void Label::_notification(int p_what) {
 		if (!wc)
 			return;
 		
-
+		int c = 0;
 		int line=0;
 		while(wc) {
-			
 		/* handle lines not meant to be drawn quickly */
 			if  (line>line_to)
 				break;
@@ -170,8 +169,8 @@ void Label::_notification(int p_what) {
 			while(to && to->char_pos>=0) {
 				
 				taken+=to->pixel_width;
-				if (to!=from) {
-					spaces++;
+				if (to!=from && to->space_count) {
+					spaces+=to->space_count;
 				}
 				to=to->next;
 			}
@@ -212,15 +211,15 @@ void Label::_notification(int p_what) {
 					ERR_PRINT("BUG");
 					return;
 				}
-				if (from!=wc) {
+				if (from->space_count) {
 				/* spacing */
-					x_ofs+=space_w;
+					x_ofs+=space_w*from->space_count;
 					if (can_fill && align==ALIGN_FILL && spaces) {
-						
+
 						x_ofs+=int((size.width-(taken+space_w*spaces))/spaces);
 					}
-					
-					
+
+
 				}
 				
 				
@@ -253,7 +252,7 @@ void Label::_notification(int p_what) {
 					
 				}
 				for (int i=0;i<from->word_len;i++) {
-					
+
 					if (visible_chars < 0 || chars_total<visible_chars) {
 						CharType c = text[i+pos];
 						CharType n = text[i+pos+1];
@@ -361,11 +360,12 @@ void Label::regenerate_word_cache() {
 	
 	int width=autowrap?get_size().width:get_longest_line_width();
 	Ref<Font> font = get_font("font");
-	
+
 	int current_word_size=0;
 	int word_pos=0;
 	int line_width=0;
-	int last_width=0;
+	int space_count=0;
+	int space_width=font->get_char_size(' ').width;
 	line_count=1;
 	total_char_cache=0;
 	
@@ -374,16 +374,17 @@ void Label::regenerate_word_cache() {
 	for (int i=0;i<text.size()+1;i++) {
 		
 		CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works
-		
+
 		if (uppercase)
 			current=String::char_uppercase(current);
 
+		bool not_latin = current>=33 && (current < 65||current >90) && (current<97||current>122) && (current<48||current>57);
 		bool insert_newline=false;
-		
+		int char_width;
+
 		if (current<33) {
-			
+
 			if (current_word_size>0) {
-				
 				WordCache *wc = memnew( WordCache );
 				if (word_cache) {
 					last->next=wc;
@@ -391,14 +392,16 @@ void Label::regenerate_word_cache() {
 					word_cache=wc;
 				}
 				last=wc;
-				
+
 				wc->pixel_width=current_word_size;
 				wc->char_pos=word_pos;
 				wc->word_len=i-word_pos;
+				wc->space_count = space_count;
 				current_word_size=0;
-				
+				space_count=0;
+
 			}
-			
+
 
 			if (current=='\n') {
 				insert_newline=true;
@@ -408,26 +411,49 @@ void Label::regenerate_word_cache() {
 
 			if (i<text.length() && text[i] == ' ') {
 				total_char_cache--;  // do not count spaces
+				if (line_width > 0 || last==NULL || last->char_pos!=WordCache::CHAR_WRAPLINE) {
+					space_count++;
+					line_width+=space_width;
+				}else {
+					space_count=0;
+				}
 			}
 
 
 		} else {
-			
+			// latin characters
 			if (current_word_size==0) {
-				if (line_width>0) // add a space before the new word if a word existed before
-					line_width+=font->get_char_size(' ').width;
 				word_pos=i;
 			}
 			
-			int char_width=font->get_char_size(current).width;
+			char_width=font->get_char_size(current).width;
 			current_word_size+=char_width;
 			line_width+=char_width;
 			total_char_cache++;
 			
 		}
-		
-		if ((autowrap && line_width>=width && last_width<width) || insert_newline) {
-			
+
+		if ((autowrap && line_width>=width && (last &&  last->char_pos >= 0 || not_latin)) || insert_newline) {
+			if (not_latin) {
+				if (current_word_size>0) {
+					WordCache *wc = memnew( WordCache );
+					if (word_cache) {
+						last->next=wc;
+					} else {
+						word_cache=wc;
+					}
+					last=wc;
+
+					wc->pixel_width=current_word_size-char_width;
+					wc->char_pos=word_pos;
+					wc->word_len=i-word_pos;
+					wc->space_count = space_count;
+					current_word_size=char_width;
+					space_count=0;
+					word_pos=i;
+				}
+			}
+
 			WordCache *wc = memnew( WordCache );
 			if (word_cache) {
 				last->next=wc;
@@ -435,18 +461,16 @@ void Label::regenerate_word_cache() {
 				word_cache=wc;
 			}
 			last=wc;
-			
+
 			wc->pixel_width=0;
 			wc->char_pos=insert_newline?WordCache::CHAR_NEWLINE:WordCache::CHAR_WRAPLINE;
 
 			line_width=current_word_size;
 			line_count++;
+			space_count=0;
 
-			
 		}
 		
-		last_width=line_width;
-		
 	}
 	
 	//total_char_cache -= line_count + 1; // do not count new lines (including the first one)
@@ -465,7 +489,7 @@ void Label::regenerate_word_cache() {
 	set_max(line_count);
 	
 	word_cache_dirty=false;
-		
+
 }
 
 

+ 2 - 1
scene/gui/label.h

@@ -75,8 +75,9 @@ private:
 		int char_pos; // if -1, then newline
 		int word_len;
 		int pixel_width;
+		int space_count;
 		WordCache *next;
-		WordCache() { char_pos=0; word_len=0; pixel_width=0; next=0; }
+		WordCache() { char_pos=0; word_len=0; pixel_width=0; next=0; space_count=0;}
 	};	
 	
 	bool word_cache_dirty;

+ 3 - 1
scene/gui/rich_text_label.cpp

@@ -268,7 +268,9 @@ if (m_height > line_height) {\
 						}
 
 						if (found_space) {
-							fw+=l.offset_caches[line]/l.space_caches[line];
+							int ln = MIN(l.offset_caches.size()-1,line);
+
+							fw+=l.offset_caches[ln]/l.space_caches[ln];
 						}
 
 					}

+ 6 - 3
scene/gui/text_edit.cpp

@@ -489,7 +489,7 @@ void TextEdit::_notification(int p_what) {
 								
 								CharType cc = text[i][j];
 								//ignore any brackets inside a string
-								if (cc== '"' | cc == '\'') {
+								if (cc== '"' || cc == '\'') {
 									CharType quotation = cc;
 									do {
 										j++;
@@ -560,7 +560,7 @@ void TextEdit::_notification(int p_what) {
 								
 								CharType cc = text[i][j];
 								//ignore any brackets inside a string
-								if (cc== '"' | cc == '\'') {
+								if (cc== '"' || cc == '\'') {
 									CharType quotation = cc;
 									do {
 										j--;
@@ -1249,7 +1249,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
 					}
 					
 					
-					if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) {
+					if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600 && cursor.line==prev_line) {
 						//tripleclick select line
 						select(cursor.line,0,cursor.line,text[cursor.line].length());
 						last_dblclk=0;
@@ -3494,6 +3494,9 @@ void TextEdit::set_line(int line, String new_text)
 		return;
 	_remove_text(line, 0, line, text[line].length());
 	_insert_text(line, 0, new_text);
+	if (cursor.line==line) {
+		cursor.column=MIN(cursor.column,new_text.length());
+	}
 }
 
 void TextEdit::insert_at(const String &p_text, int at)

+ 1 - 0
scene/main/node.h

@@ -170,6 +170,7 @@ public:
 		NOTIFICATION_PROCESS = 17,
 		NOTIFICATION_PARENTED=18,
 		NOTIFICATION_UNPARENTED=19,
+		NOTIFICATION_INSTANCED=20,
 	};
 			
 	/* NODE/TREE */			

+ 2 - 2
scene/resources/animation.cpp

@@ -1216,8 +1216,8 @@ T Animation::_interpolate( const Vector< TKey<T> >& p_keys, float p_time,  Inter
 	
 	if (p_ok)
 		*p_ok=true;
-	
-	int next;
+
+	int next=0;
 	float c=0;	
 	// prepare for all cases of interpolation
 	

+ 2 - 0
scene/resources/packed_scene.cpp

@@ -182,6 +182,8 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
 
 	if (get_path()!="" && get_path().find("::")==-1)
 		s->set_filename(get_path());
+
+	s->notification(Node::NOTIFICATION_INSTANCED);
 	return ret_nodes[0];
 
 }

+ 2 - 2
scene/resources/shader_graph.cpp

@@ -2160,7 +2160,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 				"floor($)",
 				"round($)",
 				"ceil($)",
-				"frac($)",
+				"fract($)",
 				"min(max($,0),1)",
 				"-($)",
 			};
@@ -2378,7 +2378,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
 
 			String name = p_node->param1;
 			Vector3 dv=p_node->param2;
-			code +="uniform float "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
+			code +="uniform vec3 "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n";
 			code += OUTNAME(p_node->id,0)+"="+name+";\n";
 		}break;
 		case NODE_RGB_INPUT: {

+ 13 - 5
scene/resources/theme.cpp

@@ -105,6 +105,9 @@ bool Theme::_get(const StringName& p_name,Variant &r_ret) const {
 
 void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
+
+	List<PropertyInfo> list;
+
 	const StringName *key=NULL;
 	
 	while((key=icon_map.next(key))) {
@@ -113,7 +116,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 		while((key2=icon_map[*key].next(key2))) {
 
-			p_list->push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/icons/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture" ) );
+			list.push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/icons/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture" ) );
 		}
 	}
 	
@@ -125,7 +128,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 		while((key2=style_map[*key].next(key2))) {
 		
-			p_list->push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/styles/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox" ) );
+			list.push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/styles/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox" ) );
 		}
 	}
 	
@@ -138,7 +141,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 		while((key2=font_map[*key].next(key2))) {
 		
-			p_list->push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/fonts/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Font" ) );
+			list.push_back( PropertyInfo( Variant::OBJECT, String()+*key+"/fonts/"+*key2, PROPERTY_HINT_RESOURCE_TYPE, "Font" ) );
 		}
 	}
 	
@@ -150,7 +153,7 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 		while((key2=color_map[*key].next(key2))) {
 		
-			p_list->push_back( PropertyInfo( Variant::COLOR, String()+*key+"/colors/"+*key2 ) );
+			list.push_back( PropertyInfo( Variant::COLOR, String()+*key+"/colors/"+*key2 ) );
 		}
 	}
 	
@@ -162,9 +165,14 @@ void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 		while((key2=constant_map[*key].next(key2))) {
 		
-			p_list->push_back( PropertyInfo( Variant::INT, String()+*key+"/constants/"+*key2 ) );
+			list.push_back( PropertyInfo( Variant::INT, String()+*key+"/constants/"+*key2 ) );
 		}
 	}
+
+	list.sort();
+	for(List<PropertyInfo>::Element *E=list.front();E;E=E->next()) {
+		p_list->push_back(E->get());
+	}
 	
 }
 

+ 1 - 0
servers/physics_2d/body_2d_sw.cpp

@@ -657,6 +657,7 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti
 	area_linear_damp=0;
 	contact_count=0;
 	gravity_scale=1.0;
+	using_one_way_cache=false;
 	one_way_collision_max_depth=0.1;
 
 	still_time=0;

+ 7 - 1
servers/physics_2d/body_2d_sw.h

@@ -81,6 +81,7 @@ class Body2DSW : public CollisionObject2DSW {
 	bool active;
 	bool can_sleep;
 	bool first_time_kinematic;
+	bool using_one_way_cache;
 	void _update_inertia();
 	virtual void _shapes_changed();
 	Matrix32 new_transform;
@@ -229,12 +230,17 @@ public:
 	_FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode=p_mode; }
 	_FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; }
 
-	void set_one_way_collision_direction(const Vector2& p_dir) { one_way_collision_direction=p_dir; }
+	void set_one_way_collision_direction(const Vector2& p_dir) {
+		one_way_collision_direction=p_dir;
+		using_one_way_cache=one_way_collision_direction!=Vector2();
+	}
 	Vector2 get_one_way_collision_direction() const { return one_way_collision_direction; }
 
 	void set_one_way_collision_max_depth(float p_depth) { one_way_collision_max_depth=p_depth; }
 	float get_one_way_collision_max_depth() const { return one_way_collision_max_depth; }
 
+	_FORCE_INLINE_ bool is_using_one_way_collision() const { return using_one_way_cache; }
+
 	void set_space(Space2DSW *p_space);
 
 	void update_inertias();

+ 53 - 0
servers/physics_2d/body_pair_2d_sw.cpp

@@ -265,6 +265,8 @@ bool BodyPair2DSW::setup(float p_step) {
 	} 
 	//faster to set than to check..
 
+	bool prev_collided=collided;
+
 	collided = CollisionSolver2DSW::solve(shape_A_ptr,xform_A,motion_A,shape_B_ptr,xform_B,motion_B,_add_contact,this,&sep_axis);
 	if (!collided) {
 
@@ -285,6 +287,57 @@ bool BodyPair2DSW::setup(float p_step) {
 
 	}
 
+	if (!prev_collided) {
+
+		if (A->is_using_one_way_collision()) {
+			Vector2 direction = A->get_one_way_collision_direction();
+			bool valid=false;
+			for(int i=0;i<contact_count;i++) {
+				Contact& c = contacts[i];
+
+				if (c.normal.dot(direction)<0)
+					continue;
+				if (B->get_linear_velocity().dot(direction)<0)
+					continue;
+
+				if (!c.reused) {
+					continue;
+				}
+
+				valid=true;
+			}
+
+			if (!valid) {
+				collided=false;
+				return false;
+			}
+		}
+
+		if (B->is_using_one_way_collision()) {
+			Vector2 direction = B->get_one_way_collision_direction();
+			bool valid=false;
+			for(int i=0;i<contact_count;i++) {
+
+				Contact& c = contacts[i];
+
+				if (c.normal.dot(direction)<0)
+					continue;
+				if (A->get_linear_velocity().dot(direction)<0)
+					continue;
+
+				if (!c.reused) {
+					continue;
+				}
+
+				valid=true;
+			}
+			if (!valid) {
+				collided=false;
+				return false;
+			}
+		}
+	}
+
 	real_t max_penetration = space->get_contact_max_allowed_penetration();
 
 	float bias = 0.3f;

+ 37 - 30
servers/physics_2d/space_2d_sw.cpp

@@ -555,38 +555,10 @@ Physics2DDirectSpaceStateSW::Physics2DDirectSpaceStateSW() {
 
 
 
+int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body,const Rect2& p_aabb) {
 
-bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p_margin,Physics2DServer::MotionResult *r_result) {
-
-	//give me back regular physics engine logic
-	//this is madness
-	//and most people using this function will think
-	//what it does is simpler than using physics
-	//this took about a week to get right..
-	//but is it right? who knows at this point..
-
-	Rect2 body_aabb;
-
-	for(int i=0;i<p_body->get_shape_count();i++) {
-
-		if (i==0)
-			body_aabb=p_body->get_shape_aabb(i);
-		else
-			body_aabb=body_aabb.merge(p_body->get_shape_aabb(i));
-	}
-
-	body_aabb=body_aabb.grow(p_margin);
-
-	{
-		//add motion
 
-		Rect2 motion_aabb=body_aabb;
-		motion_aabb.pos+=p_motion;
-		body_aabb=body_aabb.merge(motion_aabb);
-	}
-
-
-	int amount = broadphase->cull_aabb(body_aabb,intersection_query_results,INTERSECTION_QUERY_MAX,intersection_query_subindex_results);
+	int amount = broadphase->cull_aabb(p_aabb,intersection_query_results,INTERSECTION_QUERY_MAX,intersection_query_subindex_results);
 
 	for(int i=0;i<amount;i++) {
 
@@ -617,6 +589,31 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
 		}
 	}
 
+	return amount;
+}
+
+bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p_margin,Physics2DServer::MotionResult *r_result) {
+
+	//give me back regular physics engine logic
+	//this is madness
+	//and most people using this function will think
+	//what it does is simpler than using physics
+	//this took about a week to get right..
+	//but is it right? who knows at this point..
+
+	Rect2 body_aabb;
+
+	for(int i=0;i<p_body->get_shape_count();i++) {
+
+		if (i==0)
+			body_aabb=p_body->get_shape_aabb(i);
+		else
+			body_aabb=body_aabb.merge(p_body->get_shape_aabb(i));
+	}
+
+	body_aabb=body_aabb.grow(p_margin);
+
+
 	Matrix32 body_transform = p_body->get_transform();
 
 	{
@@ -642,6 +639,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
 
 			bool collided=false;
 
+			int amount = _cull_aabb_for_body(p_body,body_aabb);
 
 			for(int j=0;j<p_body->get_shape_count();j++) {
 				if (p_body->is_shape_set_as_trigger(j))
@@ -694,6 +692,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
 			}
 
 			body_transform.elements[2]+=recover_motion;
+			body_aabb.pos+=recover_motion;
 
 			recover_attempts--;
 
@@ -709,7 +708,11 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
 	{
 		// STEP 2 ATTEMPT MOTION
 
+		Rect2 motion_aabb=body_aabb;
+		motion_aabb.pos+=p_motion;
+		motion_aabb=motion_aabb.merge(body_aabb);
 
+		int amount = _cull_aabb_for_body(p_body,motion_aabb);
 
 		for(int j=0;j<p_body->get_shape_count();j++) {
 
@@ -847,6 +850,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
 		Matrix32 body_shape_xform = ugt * p_body->get_shape_transform(best_shape);
 		Shape2DSW *body_shape = p_body->get_shape(best_shape);
 
+		body_aabb.pos+=p_motion*unsafe;
+
+		int amount = _cull_aabb_for_body(p_body,body_aabb);
+
 
 		for(int i=0;i<amount;i++) {
 

+ 2 - 0
servers/physics_2d/space_2d_sw.h

@@ -101,6 +101,8 @@ class Space2DSW {
 	int active_objects;
 	int collision_pairs;
 
+	int _cull_aabb_for_body(Body2DSW *p_body,const Rect2& p_aabb);
+
 friend class Physics2DDirectSpaceStateSW;
 
 public:

+ 1 - 0
tools/editor/editor_import_export.cpp

@@ -47,6 +47,7 @@ String EditorImportPlugin::validate_source_path(const String& p_path) {
 	String rp = Globals::get_singleton()->get_resource_path();
 	if (!rp.ends_with("/"))
 		rp+="/";
+
 	return rp.path_to_file(gp);
 }
 

+ 1 - 0
tools/editor/editor_node.cpp

@@ -3509,6 +3509,7 @@ EditorNode::EditorNode() {
 	p=file_menu->get_popup();
 	p->add_item("New Scene",FILE_NEW_SCENE);
 	p->add_item("Open Scene..",FILE_OPEN_SCENE,KEY_MASK_CMD+KEY_O);
+	p->add_separator();
 	p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);
 	p->add_item("Save Scene As..",FILE_SAVE_AS_SCENE,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_S);
 	p->add_separator();

+ 1 - 1
tools/editor/editor_settings.cpp

@@ -408,7 +408,7 @@ void EditorSettings::_load_defaults() {
 
 	set("text_editor/idle_parse_delay",2);
 	set("text_editor/create_signal_callbacks",true);
-	set("text_editor/autosave_interval_seconds",60);
+	set("text_editor/autosave_interval_secs",0);
 	set("text_editor/font","");
 	hints["text_editor/font"]=PropertyInfo(Variant::STRING,"text_editor/font",PROPERTY_HINT_GLOBAL_FILE,"*.fnt");
 	set("text_editor/auto_brace_complete", false);

+ 5 - 2
tools/editor/io_plugins/editor_font_import_plugin.cpp

@@ -406,7 +406,10 @@ class EditorFontImportDialog : public ConfirmationDialog {
 			imd->set_option(opt,v);
 		}
 
-		imd->add_source(EditorImportPlugin::validate_source_path(source->get_line_edit()->get_text()));
+		String src_path = EditorImportPlugin::validate_source_path(source->get_line_edit()->get_text());
+		//print_line("pre src path "+source->get_line_edit()->get_text());
+		//print_line("src path "+src_path);
+		imd->add_source(src_path);
 		imd->set_option("font/size",font_size->get_val());
 
 		return imd;
@@ -1018,7 +1021,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 		int h = slot->bitmap.rows;
 		int p = slot->bitmap.pitch;
 
-		print_line("W: "+itos(w)+" P: "+itos(slot->bitmap.pitch));
+		//print_line("W: "+itos(w)+" P: "+itos(slot->bitmap.pitch));
 
 		if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
 

+ 51 - 13
tools/editor/plugins/script_editor_plugin.cpp

@@ -130,6 +130,7 @@ void ScriptEditorQuickOpen::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("_confirmed"),&ScriptEditorQuickOpen::_confirmed);
 	ObjectTypeDB::bind_method(_MD("_sbox_input"),&ScriptEditorQuickOpen::_sbox_input);
 
+
 	ADD_SIGNAL(MethodInfo("goto_line",PropertyInfo(Variant::INT,"line")));
 
 }
@@ -815,11 +816,11 @@ void ScriptEditor::_menu_option(int p_option) {
             if (scr.is_null())
                 return;
 
-            int begin, end;
-            begin = tx->get_selection_from_line();
+
             if (tx->is_selection_active())
             {
-                end = tx->get_selection_to_line();
+		int begin = tx->get_selection_from_line();
+		int end = tx->get_selection_to_line();
                 for (int i = begin; i <= end; i++)
                 {
                     String line_text = tx->get_line(i);
@@ -839,7 +840,7 @@ void ScriptEditor::_menu_option(int p_option) {
             }
             else
             {
-                begin = tx->cursor_get_line();
+		int begin = tx->cursor_get_line();
                 String line_text = tx->get_line(begin);
                 // begins with tab
                 if (line_text.begins_with("\t"))
@@ -865,11 +866,10 @@ void ScriptEditor::_menu_option(int p_option) {
             if (scr.is_null())
                 return;
 
-            int begin, end;
-            begin = tx->get_selection_from_line();
             if (tx->is_selection_active())
             {
-                end = tx->get_selection_to_line();
+		int begin = tx->get_selection_from_line();
+		int end = tx->get_selection_to_line();
                 for (int i = begin; i <= end; i++)
                 {
                     String line_text = tx->get_line(i);
@@ -879,7 +879,7 @@ void ScriptEditor::_menu_option(int p_option) {
             }
             else
             {
-                begin = tx->cursor_get_line();
+		int begin = tx->cursor_get_line();
                 String line_text = tx->get_line(begin);
                 line_text = '\t' + line_text;
                 tx->set_line(begin, line_text);
@@ -912,11 +912,12 @@ void ScriptEditor::_menu_option(int p_option) {
             if (scr.is_null())
                 return;
 
-            int begin, end;
-            begin = tx->get_selection_from_line();
+
+
             if (tx->is_selection_active())
             {
-                end = tx->get_selection_to_line();
+		int begin = tx->get_selection_from_line();
+		int end = tx->get_selection_to_line();
                 for (int i = begin; i <= end; i++)
                 {
                     String line_text = tx->get_line(i);
@@ -930,7 +931,7 @@ void ScriptEditor::_menu_option(int p_option) {
             }
             else
             {
-                begin = tx->cursor_get_line();
+		int begin = tx->cursor_get_line();
                 String line_text = tx->get_line(begin);
 
                 if (line_text.begins_with("#"))
@@ -1089,6 +1090,18 @@ void ScriptEditor::_notification(int p_what) {
 		editor->connect("stop_pressed",this,"_editor_stop");
 		editor->connect("script_add_function_request",this,"_add_callback");
 		editor->connect("resource_saved",this,"_res_saved_callback");
+		autosave_timer->connect("timeout",this,"_autosave_scripts");
+		{
+			float autosave_time = EditorSettings::get_singleton()->get("text_editor/autosave_interval_secs");
+			if (autosave_time>0) {
+				autosave_timer->set_wait_time(autosave_time);
+				autosave_timer->start();
+			} else {
+				autosave_timer->stop();
+			}
+		}
+
+		EditorSettings::get_singleton()->connect("settings_changed",this,"_editor_settings_changed");
 
 
 	}
@@ -1339,7 +1352,8 @@ void ScriptEditor::_bind_methods() {
 	ObjectTypeDB::bind_method("_breaked",&ScriptEditor::_breaked);
 	ObjectTypeDB::bind_method("_show_debugger",&ScriptEditor::_show_debugger);
 	ObjectTypeDB::bind_method("_get_debug_tooltip",&ScriptEditor::_get_debug_tooltip);
-
+	ObjectTypeDB::bind_method("_autosave_scripts",&ScriptEditor::_autosave_scripts);
+	ObjectTypeDB::bind_method("_editor_settings_changed",&ScriptEditor::_editor_settings_changed);
 }
 
 
@@ -1568,6 +1582,25 @@ void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const
 
 }
 
+void ScriptEditor::_editor_settings_changed() {
+
+	print_line("settings changed");
+	float autosave_time = EditorSettings::get_singleton()->get("text_editor/autosave_interval_secs");
+	if (autosave_time>0) {
+		autosave_timer->set_wait_time(autosave_time);
+		autosave_timer->start();
+	} else {
+		autosave_timer->stop();
+	}
+
+}
+
+void ScriptEditor::_autosave_scripts() {
+
+	print_line("autosaving");
+	save_external_data();
+}
+
 ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 
 	editor=p_editor;
@@ -1718,6 +1751,11 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 
 	v_split->add_child(debugger);
 	debugger->connect("breaked",this,"_breaked");
+
+	autosave_timer = memnew( Timer );
+	autosave_timer->set_one_shot(false);
+	add_child(autosave_timer);
+
 //	debugger_gui->hide();
 
 }

+ 4 - 0
tools/editor/plugins/script_editor_plugin.h

@@ -154,6 +154,7 @@ class ScriptEditor : public VBoxContainer {
 	MenuButton *window_menu;
 	MenuButton *debug_menu;
 	MenuButton *help_menu;
+	Timer *autosave_timer;
 	uint64_t idle;
 
 	TabContainer *tab_container;
@@ -195,6 +196,9 @@ class ScriptEditor : public VBoxContainer {
 	void _show_debugger(bool p_show);
 	void _update_window_menu();
 
+	void _editor_settings_changed();
+	void _autosave_scripts();
+
 	static ScriptEditor *script_editor;
 protected:
 	void _notification(int p_what);

+ 1 - 1
version.py

@@ -2,6 +2,6 @@ short_name="godot"
 name="Godot Engine"
 major=1
 minor=1
-status="rc1"
+status="rc2"
 
 

Неке датотеке нису приказане због велике количине промена