瀏覽代碼

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

Juan Linietsky 10 年之前
父節點
當前提交
4b8745ad63
共有 100 個文件被更改,包括 1868 次插入531 次删除
  1. 46 0
      SConstruct
  2. 1 1
      core/globals.cpp
  3. 21 21
      core/io/file_access_memory.cpp
  4. 3 1
      core/io/file_access_pack.cpp
  5. 3 2
      core/io/resource_format_xml.cpp
  6. 36 8
      core/io/resource_loader.cpp
  7. 4 3
      core/math/math_funcs.cpp
  8. 1 1
      core/method_bind.h
  9. 17 0
      core/object.cpp
  10. 1 0
      core/object.h
  11. 8 3
      core/ustring.cpp
  12. 253 3
      core/variant.cpp
  13. 2 1
      core/variant.h
  14. 二進制
      demos/2d/isometric/bastiles.res
  15. 二進制
      demos/2d/isometric/dungeon.scn
  16. 二進制
      demos/2d/isometric/tileset.scn
  17. 二進制
      demos/2d/isometric/troll.scn
  18. 二進制
      demos/2d/isometric_light/cubio.scn
  19. 1 0
      demos/2d/isometric_light/engine.cfg
  20. 二進制
      demos/2d/isometric_light/map.scn
  21. 二進制
      demos/2d/isometric_light/tileset.res
  22. 二進制
      demos/2d/kinematic_char/circle.png
  23. 二進制
      demos/2d/kinematic_char/colworld.scn
  24. 二進制
      demos/2d/kinematic_char/long_obstacle.png
  25. 29 11
      demos/2d/kinematic_char/player.gd
  26. 1 1
      demos/2d/platformer/enemy.gd
  27. 二進制
      demos/2d/platformer/one_way_platform.png
  28. 220 0
      demos/2d/platformer/one_way_platform.xml
  29. 0 1
      demos/2d/platformer/player.gd
  30. 18 13
      demos/2d/platformer/stage.xml
  31. 1 0
      demos/2d/tetris/grid.gd
  32. 二進制
      demos/3d/navmesh/navmesh.scn
  33. 二進制
      demos/3d/platformer/coin.scn
  34. 1 1
      demos/3d/platformer/enemy.gd
  35. 二進制
      demos/3d/platformer/enemy.scn
  36. 二進制
      demos/3d/shader_materials/shader_materials.scn
  37. 1 0
      demos/3d/truck_town/engine.cfg
  38. 1 0
      demos/gui/rich_text_bbcode/engine.cfg
  39. 9 1
      demos/misc/window_management/control.gd
  40. 1 1
      demos/misc/window_management/engine.cfg
  41. 二進制
      demos/misc/window_management/window_management.scn
  42. 2 2
      doc/base/classes.xml
  43. 94 91
      drivers/SCsub
  44. 2 2
      drivers/chibi/cp_player_data_control.cpp
  45. 1 0
      drivers/convex_decomp/b2Polygon.cpp
  46. 57 4
      drivers/gles2/shader_compiler_gles2.cpp
  47. 7 0
      drivers/gles2/shader_compiler_gles2.h
  48. 1 0
      drivers/mpc/mpc_reader.c
  49. 6 6
      drivers/pvr/ColorRgba.h
  50. 225 133
      drivers/rtaudio/RtAudio.cpp
  51. 2 1
      drivers/rtaudio/RtAudio.h
  52. 1 1
      drivers/theoraplayer/video_stream_theoraplayer.cpp
  53. 1 1
      drivers/vorbis/psy.c
  54. 20 17
      drivers/windows/dir_access_windows.cpp
  55. 13 6
      main/main.cpp
  56. 24 0
      modules/gdscript/gd_functions.cpp
  57. 1 0
      modules/gdscript/gd_functions.h
  58. 1 1
      modules/gdscript/gd_tokenizer.cpp
  59. 1 1
      platform/android/android_native_app_glue.h
  60. 32 5
      platform/android/export/export.cpp
  61. 二進制
      platform/android/java/res/drawable/icon.png
  62. 17 2
      platform/osx/os_osx.mm
  63. 6 0
      platform/windows/SCsub
  64. 1 1
      platform/windows/detect.py
  65. 25 82
      platform/windows/godot_win.cpp
  66. 6 5
      platform/windows/os_windows.cpp
  67. 2 2
      platform/x11/os_x11.cpp
  68. 33 1
      scene/2d/area_2d.cpp
  69. 8 0
      scene/2d/area_2d.h
  70. 1 2
      scene/2d/camera_2d.cpp
  71. 35 3
      scene/2d/navigation2d.cpp
  72. 2 0
      scene/2d/navigation2d.h
  73. 47 1
      scene/2d/physics_body_2d.cpp
  74. 14 0
      scene/2d/physics_body_2d.h
  75. 27 5
      scene/2d/tile_map.cpp
  76. 7 2
      scene/2d/tile_map.h
  77. 14 1
      scene/3d/navigation.cpp
  78. 2 0
      scene/3d/navigation.h
  79. 1 1
      scene/3d/sprite_3d.cpp
  80. 205 11
      scene/animation/tween.cpp
  81. 21 0
      scene/animation/tween.h
  82. 6 6
      scene/animation/tween_interpolaters.cpp
  83. 2 0
      scene/gui/button.cpp
  84. 1 1
      scene/gui/check_box.cpp
  85. 0 1
      scene/gui/file_dialog.cpp
  86. 56 32
      scene/gui/label.cpp
  87. 2 1
      scene/gui/label.h
  88. 1 1
      scene/gui/line_edit.cpp
  89. 13 1
      scene/gui/rich_text_label.cpp
  90. 8 5
      scene/gui/text_edit.cpp
  91. 36 0
      scene/main/node.cpp
  92. 2 0
      scene/main/node.h
  93. 60 9
      scene/main/timer.cpp
  94. 14 0
      scene/main/timer.h
  95. 2 2
      scene/resources/animation.cpp
  96. 2 0
      scene/resources/packed_scene.cpp
  97. 2 2
      scene/resources/shader_graph.cpp
  98. 13 5
      scene/resources/theme.cpp
  99. 3 1
      servers/physics/collision_object_sw.h
  100. 1 1
      servers/physics/physics_server_sw.cpp

+ 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('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('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('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
 # add platform specific options
 
 
@@ -177,6 +178,25 @@ if selected_platform in platform_list:
 	else:
 	else:
 		env = env_base.Clone()
 		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=""
 	env.extra_suffix=""
 	
 	
 	if env["extra_suffix"] != '' :
 	if env["extra_suffix"] != '' :
@@ -330,6 +350,32 @@ if selected_platform in platform_list:
 	SConscript("main/SCsub")
 	SConscript("main/SCsub")
 
 
 	SConscript("platform/"+selected_platform+"/SCsub"); # build selected platform
 	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:
 else:
 
 

+ 1 - 1
core/globals.cpp

@@ -1381,7 +1381,7 @@ Globals::Globals() {
 
 
 	set("application/name","" );
 	set("application/name","" );
 	set("application/main_scene","");
 	set("application/main_scene","");
-	custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"xml,res,scn,xscn");
+	custom_prop_info["application/main_scene"]=PropertyInfo(Variant::STRING,"application/main_scene",PROPERTY_HINT_FILE,"scn,res,xscn,xml");
 	set("application/disable_stdout",false);
 	set("application/disable_stdout",false);
 	set("application/use_shared_user_dir",true);
 	set("application/use_shared_user_dir",true);
 
 

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

+ 3 - 1
core/io/file_access_pack.cpp

@@ -92,7 +92,9 @@ void PackedData::add_path(const String& pkg_path, const String& path, uint64_t o
 
 
 void PackedData::add_pack_source(PackSource *p_source) {
 void PackedData::add_pack_source(PackSource *p_source) {
 
 
-	sources.push_back(p_source);
+	if (p_source != NULL) {
+		sources.push_back(p_source);
+	}
 };
 };
 
 
 PackedData *PackedData::singleton=NULL;
 PackedData *PackedData::singleton=NULL;

+ 3 - 2
core/io/resource_format_xml.cpp

@@ -309,6 +309,7 @@ Error ResourceInteractiveLoaderXML::_parse_array_element(Vector<char> &buff,bool
 
 
 				buff_max++;
 				buff_max++;
 				buff.resize(buff_max);
 				buff.resize(buff_max);
+				buffptr=buff.ptr();
 
 
 			}
 			}
 
 
@@ -1849,7 +1850,7 @@ void ResourceFormatSaverXMLInstance::escape(String& p_str) {
 	p_str=p_str.replace(">","&lt;");
 	p_str=p_str.replace(">","&lt;");
 	p_str=p_str.replace("'","&apos;");
 	p_str=p_str.replace("'","&apos;");
 	p_str=p_str.replace("\"","&quot;");
 	p_str=p_str.replace("\"","&quot;");
-	for (int i=1;i<32;i++) {
+	for (char i=1;i<32;i++) {
 
 
 		char chr[2]={i,0};
 		char chr[2]={i,0};
 		const char hexn[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
 		const char hexn[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
@@ -2563,7 +2564,7 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
 
 
 		List<PropertyInfo> property_list;
 		List<PropertyInfo> property_list;
 		res->get_property_list(&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()) {
 		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) {
 RES ResourceFormatLoader::load(const String &p_path,const String& p_original_path) {
 
 
+	String path=p_path;
 
 
 	//or this must be implemented
 	//or this must be implemented
 	Ref<ResourceInteractiveLoader> ril = load_interactive(p_path);
 	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) {
 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());
 	ERR_FAIL_COND_V(local_path=="",RES());
 
 
 	if (!p_no_cache && ResourceCache::has(local_path)) {
 	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) {
 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();
 	String extension=p_path.extension();
 	bool found=false;
 	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>());
 	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) {
 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 remapped_path = PathRemap::get_singleton()->get_remap(local_path);
 
 
 	String extension=remapped_path.extension();
 	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 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);
 	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 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 remapped_path = PathRemap::get_singleton()->get_remap(local_path);
 	String extension=remapped_path.extension();
 	String extension=remapped_path.extension();
 
 

+ 4 - 3
core/math/math_funcs.cpp

@@ -36,8 +36,9 @@ uint32_t Math::default_seed=1;
 
 
 #define PHI 0x9e3779b9
 #define PHI 0x9e3779b9
 
 
-static uint32_t Q[4096], c = 362436;
-
+#if 0
+static uint32_t Q[4096];
+#endif
 
 
 uint32_t Math::rand_from_seed(uint32_t *seed) {
 uint32_t Math::rand_from_seed(uint32_t *seed) {
 
 
@@ -269,7 +270,7 @@ bool Math::is_inf(double p_val) {
 
 
 uint32_t Math::larger_prime(uint32_t p_val) {
 uint32_t Math::larger_prime(uint32_t p_val) {
 
 
-	static const int primes[] = {
+	static const uint32_t primes[] = {
 		5,
 		5,
 		13,
 		13,
 		23,
 		23,

+ 1 - 1
core/method_bind.h

@@ -98,7 +98,7 @@ struct VariantCaster<m_enum> {\
 #define CHECK_ARG(m_arg)\
 #define CHECK_ARG(m_arg)\
 	if ((m_arg-1)<p_arg_count) {\
 	if ((m_arg-1)<p_arg_count) {\
 		Variant::Type argtype=get_argument_type(m_arg-1);\
 		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.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\
 			r_error.argument=m_arg-1;\
 			r_error.argument=m_arg-1;\
 			r_error.expected=argtype;\
 			r_error.expected=argtype;\

+ 17 - 0
core/object.cpp

@@ -1282,6 +1282,23 @@ void Object::get_signal_list(List<MethodInfo> *p_signals ) const {
 	}
 	}
 }
 }
 
 
+
+void Object::get_all_signal_connections(List<Connection> *p_connections) const {
+
+	const StringName *S=NULL;
+
+	while((S=signal_map.next(S))) {
+
+		const Signal *s=&signal_map[*S];
+
+		for(int i=0;i<s->slot_map.size();i++) {
+
+			p_connections->push_back(s->slot_map.getv(i).conn);
+		}
+	}
+
+}
+
 void Object::get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const {
 void Object::get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const {
 
 
 	const Signal *s=signal_map.getptr(p_signal);
 	const Signal *s=signal_map.getptr(p_signal);

+ 1 - 0
core/object.h

@@ -574,6 +574,7 @@ public:
 	void emit_signal(const StringName& p_name,VARIANT_ARG_LIST);
 	void emit_signal(const StringName& p_name,VARIANT_ARG_LIST);
 	void get_signal_list(List<MethodInfo> *p_signals ) const;
 	void get_signal_list(List<MethodInfo> *p_signals ) const;
 	void get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const;
 	void get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const;
+	void get_all_signal_connections(List<Connection> *p_connections) const;
 
 
 	Error connect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method,const Vector<Variant>& p_binds=Vector<Variant>(),uint32_t p_flags=0);
 	Error connect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method,const Vector<Variant>& p_binds=Vector<Variant>(),uint32_t p_flags=0);
 	void disconnect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method);
 	void disconnect(const StringName& p_signal, Object *p_to_object, const StringName& p_to_method);

+ 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 src=this->replace("\\","/").get_base_dir();
 	String dst=p_path.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 {
 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 src_begin=src.get_slice("/",0);
 		String dst_begin=dst.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;
 		base=src_begin;
 		src=src.substr(src_begin.length(),src.length());
 		src=src.substr(src_begin.length(),src.length());
 		dst=dst.substr(dst_begin.length(),dst.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: {
 		case MATRIX32: {
 
 
 
 
-			static const Type invalid[]={
+			static const Type valid[]={
 				TRANSFORM,
 				TRANSFORM,
 				NIL
 				NIL
 			};
 			};
 
 
-			invalid_types=invalid;
+			valid_types=valid;
 		} break;
 		} break;
 		case QUAT: {
 		case QUAT: {
 
 
@@ -299,6 +299,256 @@ bool Variant::can_convert(Variant::Type p_type_from,Variant::Type p_type_to) {
 
 
 		} break;		
 		} 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: {
 		case COLOR: {
 
 
 			static const Type valid[] = {
 			static const Type valid[] = {
@@ -532,7 +782,7 @@ bool Variant::is_zero() const {
 		} break;
 		} break;
 		case QUAT: {
 		case QUAT: {
 
 
-			*reinterpret_cast<const Quat*>(_data._mem)==Quat();
+			return *reinterpret_cast<const Quat*>(_data._mem)==Quat();
 
 
 		} break;
 		} break;
 		case MATRIX3: {
 		case MATRIX3: {

+ 2 - 1
core/variant.h

@@ -165,7 +165,8 @@ public:
 
 
 	_FORCE_INLINE_ Type get_type() const { return type; }
 	_FORCE_INLINE_ Type get_type() const { return type; }
 	static String get_type_name(Variant::Type p_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);
 
 
 
 
 
 

二進制
demos/2d/isometric/bastiles.res


二進制
demos/2d/isometric/dungeon.scn


二進制
demos/2d/isometric/tileset.scn


二進制
demos/2d/isometric/troll.scn


二進制
demos/2d/isometric_light/cubio.scn


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

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

二進制
demos/2d/isometric_light/map.scn


二進制
demos/2d/isometric_light/tileset.res


二進制
demos/2d/kinematic_char/circle.png


二進制
demos/2d/kinematic_char/colworld.scn


二進制
demos/2d/kinematic_char/long_obstacle.png


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

@@ -21,6 +21,9 @@ const STOP_FORCE = 1300
 const JUMP_SPEED = 200
 const JUMP_SPEED = 200
 const JUMP_MAX_AIRBORNE_TIME=0.2
 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 velocity = Vector2()
 var on_air_time=100
 var on_air_time=100
 var jumping=false
 var jumping=false
@@ -31,8 +34,6 @@ func _fixed_process(delta):
 
 
 	#create forces
 	#create forces
 	var force = Vector2(0,GRAVITY)
 	var force = Vector2(0,GRAVITY)
-
-	var stop = velocity.x!=0.0
 	
 	
 	var walk_left = Input.is_action_pressed("move_left")
 	var walk_left = Input.is_action_pressed("move_left")
 	var walk_right = Input.is_action_pressed("move_right")
 	var walk_right = Input.is_action_pressed("move_right")
@@ -86,25 +87,42 @@ func _fixed_process(delta):
 			#char is on floor
 			#char is on floor
 			on_air_time=0
 			on_air_time=0
 			floor_velocity=get_collider_velocity()
 			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_velocity!=Vector2()):
 		#if floor moves, move with floor
 		#if floor moves, move with floor
 		move(floor_velocity*delta)
 		move(floor_velocity*delta)
 
 
 	if (jumping and velocity.y>0):
 	if (jumping and velocity.y>0):
+		#if falling, no longer jumping
 		jumping=false
 		jumping=false
 		
 		
 	if (on_air_time<JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping):	
 	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	
 		velocity.y=-JUMP_SPEED	
 		jumping=true
 		jumping=true
 		
 		

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

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

二進制
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>

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

@@ -33,7 +33,6 @@ var shooting=false
 var WALK_ACCEL = 800.0
 var WALK_ACCEL = 800.0
 var WALK_DEACCEL= 800.0
 var WALK_DEACCEL= 800.0
 var WALK_MAX_VELOCITY= 200.0
 var WALK_MAX_VELOCITY= 200.0
-var GRAVITY = 700.0
 var AIR_ACCEL = 200.0
 var AIR_ACCEL = 200.0
 var AIR_DEACCEL= 200.0
 var AIR_DEACCEL= 200.0
 var JUMP_VELOCITY=460
 var JUMP_VELOCITY=460

文件差異過大導致無法顯示
+ 18 - 13
demos/2d/platformer/stage.xml


+ 1 - 0
demos/2d/tetris/grid.gd

@@ -143,6 +143,7 @@ func restart_pressed():
 		cells.clear()
 		cells.clear()
 		get_node("gameover").set_text("")		
 		get_node("gameover").set_text("")		
 		piece_active=true
 		piece_active=true
+		get_node("../restart").release_focus()
 		update()
 		update()
 		
 		
 		
 		

二進制
demos/3d/navmesh/navmesh.scn


二進制
demos/3d/platformer/coin.scn


+ 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)
 				state.set_angular_velocity( -dp.cross(up).normalized() *33.0)
 				get_node("AnimationPlayer").play("impact")
 				get_node("AnimationPlayer").play("impact")
 				get_node("AnimationPlayer").queue("explode")
 				get_node("AnimationPlayer").queue("explode")
-				set_friction(true)
+				set_friction(1)
 				cc.disabled=true
 				cc.disabled=true
 				get_node("sound").play("hit")
 				get_node("sound").play("hit")
 				return
 				return

二進制
demos/3d/platformer/enemy.scn


二進制
demos/3d/shader_materials/shader_materials.scn


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

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

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

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

+ 9 - 1
demos/misc/window_management/control.gd

@@ -1,6 +1,8 @@
 
 
 extends Control
 extends Control
 
 
+var mousepos
+
 func _fixed_process(delta):
 func _fixed_process(delta):
 
 
 	var modetext = "Mode:\n"
 	var modetext = "Mode:\n"
@@ -31,7 +33,7 @@ func _fixed_process(delta):
 	
 	
 	get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) )
 	get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) )
 	
 	
-	get_node("Label_MousePosition").set_text(str("Mouse Position:\n", Input.get_mouse_pos() ) )
+	get_node("Label_MousePosition").set_text(str("Mouse Position:\n", mousepos ) )
 	
 	
 	get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) )
 	get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) )
 	
 	
@@ -126,6 +128,12 @@ func check_wm_api():
 func _ready():
 func _ready():
 	if( check_wm_api() ):
 	if( check_wm_api() ):
 		set_fixed_process(true)
 		set_fixed_process(true)
+		set_process_input(true)
+
+
+func _input(ev):
+	if (ev.type==InputEvent.MOUSE_MOTION):
+		mousepos = ev.pos
 
 
 
 
 func _on_Button_MoveTo_pressed():
 func _on_Button_MoveTo_pressed():

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

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

二進制
demos/misc/window_management/window_management.scn


+ 2 - 2
doc/base/classes.xml

@@ -19442,7 +19442,7 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="body_set_user_mask"  >
+		<method name="body_set_collision_mask"  >
 			<argument index="0" name="body" type="RID">
 			<argument index="0" name="body" type="RID">
 			</argument>
 			</argument>
 			<argument index="1" name="mask" type="int">
 			<argument index="1" name="mask" type="int">
@@ -19450,7 +19450,7 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="body_get_user_mask" qualifiers="const" >
+		<method name="body_get_collision_mask" qualifiers="const" >
 			<return type="int">
 			<return type="int">
 			</return>
 			</return>
 			<argument index="0" name="body" type="RID">
 			<argument index="0" name="body" type="RID">

+ 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* 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) {
 		if (nTri < 1) {
             //Still no luck?  Oh well...
             //Still no luck?  Oh well...
+            delete[] triangulated;
             return -1;
             return -1;
         }
         }
         int32 nPolys = PolygonizeTriangles(triangulated, nTri, results, maxPolys);
         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="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";
 						//code="(texture2D( screen_texture, ("+dump_node_code(onode->arguments[1],p_level)+").xy).rgb";
 						break;
 						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 {
 					} else {
 
 
@@ -634,6 +670,9 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
 	r_flags.use_var2_interp=false;
 	r_flags.use_var2_interp=false;
 	r_flags.uses_normalmap=false;
 	r_flags.uses_normalmap=false;
 	r_flags.uses_normal=false;
 	r_flags.uses_normal=false;
+	sinh_used=false;
+	tanh_used=false;
+	cosh_used=false;
 
 
 	String error;
 	String error;
 	int errline,errcol;
 	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_flags.uses_shadow_color=uses_shadow_color;
 	r_code_line=code;
 	r_code_line=code;
 	r_globals_line=global_code;
 	r_globals_line=global_code;
-
 	return OK;
 	return OK;
 }
 }
 
 
 ShaderCompilerGLES2::ShaderCompilerGLES2() {
 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["bool"]= "bool";
 	replace_table["float" ]=  "float";
 	replace_table["float" ]=  "float";
 	replace_table["vec2"  ]= "vec2";
 	replace_table["vec2"  ]= "vec2";
@@ -686,9 +731,17 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	replace_table["acos" ]= "acos";
 	replace_table["acos" ]= "acos";
 	replace_table["atan" ]= "atan";
 	replace_table["atan" ]= "atan";
 	replace_table["atan2"]= "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["pow"  ]= "pow";
 	replace_table["exp" ]=  "exp";
 	replace_table["exp" ]=  "exp";
 	replace_table["log" ]=  "log";
 	replace_table["log" ]=  "log";

+ 7 - 0
drivers/gles2/shader_compiler_gles2.h

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

+ 1 - 0
drivers/mpc/mpc_reader.c

@@ -36,6 +36,7 @@
 #include <mpc/reader.h>
 #include <mpc/reader.h>
 #include "internal.h"
 #include "internal.h"
 #include <stdio.h>
 #include <stdio.h>
+#include <string.h> // memset()
 
 
 #define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value...
 #define STDIO_MAGIC 0xF34B963C ///< Just a random safe-check value...
 typedef struct mpc_reader_stdio_t {
 typedef struct mpc_reader_stdio_t {

+ 6 - 6
drivers/pvr/ColorRgba.h

@@ -11,21 +11,21 @@ public:
     
     
 
 
     ColorRgb()
     ColorRgb()
-        : r(0)
+        : b(0)
         , g(0)
         , g(0)
-        , b(0) {
+        , r(0) {
     }
     }
 
 
     ColorRgb(T red, T green, T blue)
     ColorRgb(T red, T green, T blue)
-        : r(red)
+        : b(blue)
         , g(green)
         , g(green)
-        , b(blue) {
+        , r(red) {
     }
     }
 
 
     ColorRgb(const ColorRgb<T> &x)
     ColorRgb(const ColorRgb<T> &x)
-        : r(x.r)
+        : b(x.b)
         , g(x.g)
         , g(x.g)
-        , b(x.b) {
+        , r(x.r) {
     }
     }
 
 
     ColorRgb<int> operator *(int x) {
     ColorRgb<int> operator *(int x) {

+ 225 - 133
drivers/rtaudio/RtAudio.cpp

@@ -46,6 +46,7 @@
 #include <cstdlib>
 #include <cstdlib>
 #include <cstring>
 #include <cstring>
 #include <climits>
 #include <climits>
+#include <algorithm>
 
 
 // Static variable definitions.
 // Static variable definitions.
 const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
 const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
@@ -63,6 +64,22 @@ const unsigned int RtApi::SAMPLE_RATES[] = {
   #define MUTEX_DESTROY(A)    DeleteCriticalSection(A)
   #define MUTEX_DESTROY(A)    DeleteCriticalSection(A)
   #define MUTEX_LOCK(A)       EnterCriticalSection(A)
   #define MUTEX_LOCK(A)       EnterCriticalSection(A)
   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
   #define MUTEX_UNLOCK(A)     LeaveCriticalSection(A)
+
+  #include "tchar.h"
+
+  static std::string convertCharPointerToStdString(const char *text)
+  {
+    return std::string(text);
+  }
+
+  static std::string convertCharPointerToStdString(const wchar_t *text)
+  {
+    int length = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
+    std::string s( length-1, '\0' );
+    WideCharToMultiByte(CP_UTF8, 0, text, -1, &s[0], length, NULL, NULL);
+    return s;
+  }
+
 #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
 #elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
   // pthread API
   // pthread API
   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
   #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
@@ -184,7 +201,7 @@ RtAudio :: RtAudio( RtAudio::Api api )
   getCompiledApi( apis );
   getCompiledApi( apis );
   for ( unsigned int i=0; i<apis.size(); i++ ) {
   for ( unsigned int i=0; i<apis.size(); i++ ) {
     openRtApi( apis[i] );
     openRtApi( apis[i] );
-    if ( rtapi_->getDeviceCount() ) break;
+    if ( rtapi_ && rtapi_->getDeviceCount() ) break;
   }
   }
 
 
   if ( rtapi_ ) return;
   if ( rtapi_ ) return;
@@ -766,9 +783,14 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
   bool haveValueRange = false;
   bool haveValueRange = false;
   info.sampleRates.clear();
   info.sampleRates.clear();
   for ( UInt32 i=0; i<nRanges; i++ ) {
   for ( UInt32 i=0; i<nRanges; i++ ) {
-    if ( rangeList[i].mMinimum == rangeList[i].mMaximum )
-      info.sampleRates.push_back( (unsigned int) rangeList[i].mMinimum );
-    else {
+    if ( rangeList[i].mMinimum == rangeList[i].mMaximum ) {
+      unsigned int tmpSr = (unsigned int) rangeList[i].mMinimum;
+      info.sampleRates.push_back( tmpSr );
+
+      if ( !info.preferredSampleRate || ( tmpSr <= 48000 && tmpSr > info.preferredSampleRate ) )
+        info.preferredSampleRate = tmpSr;
+
+    } else {
       haveValueRange = true;
       haveValueRange = true;
       if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;
       if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;
       if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;
       if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;
@@ -777,8 +799,12 @@ RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
 
 
   if ( haveValueRange ) {
   if ( haveValueRange ) {
     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
-      if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate )
+      if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) {
         info.sampleRates.push_back( SAMPLE_RATES[k] );
         info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+        if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+          info.preferredSampleRate = SAMPLE_RATES[k];
+      }
     }
     }
   }
   }
 
 
@@ -1385,6 +1411,18 @@ void RtApiCore :: closeStream( void )
 
 
   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
   CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
   if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+    if (handle) {
+      AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+
+      property.mSelector = kAudioDeviceProcessorOverload;
+      property.mScope = kAudioObjectPropertyScopeGlobal;
+      if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) {
+        errorText_ = "RtApiCore::closeStream(): error removing property listener!";
+        error( RtAudioError::WARNING );
+      }
+    }
     if ( stream_.state == STREAM_RUNNING )
     if ( stream_.state == STREAM_RUNNING )
       AudioDeviceStop( handle->id[0], callbackHandler );
       AudioDeviceStop( handle->id[0], callbackHandler );
 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
@@ -1396,6 +1434,18 @@ void RtApiCore :: closeStream( void )
   }
   }
 
 
   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
   if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
+    if (handle) {
+      AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
+        kAudioObjectPropertyScopeGlobal,
+        kAudioObjectPropertyElementMaster };
+
+      property.mSelector = kAudioDeviceProcessorOverload;
+      property.mScope = kAudioObjectPropertyScopeGlobal;
+      if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) {
+        errorText_ = "RtApiCore::closeStream(): error removing property listener!";
+        error( RtAudioError::WARNING );
+      }
+    }
     if ( stream_.state == STREAM_RUNNING )
     if ( stream_.state == STREAM_RUNNING )
       AudioDeviceStop( handle->id[1], callbackHandler );
       AudioDeviceStop( handle->id[1], callbackHandler );
 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
 #if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
@@ -1989,7 +2039,9 @@ RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
 
 
   // Get the current jack server sample rate.
   // Get the current jack server sample rate.
   info.sampleRates.clear();
   info.sampleRates.clear();
-  info.sampleRates.push_back( jack_get_sample_rate( client ) );
+
+  info.preferredSampleRate = jack_get_sample_rate( client );
+  info.sampleRates.push_back( info.preferredSampleRate );
 
 
   // Count the available ports containing the client name as device
   // Count the available ports containing the client name as device
   // channels.  Jack "input ports" equal RtAudio output channels.
   // channels.  Jack "input ports" equal RtAudio output channels.
@@ -2769,8 +2821,12 @@ RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
   info.sampleRates.clear();
   info.sampleRates.clear();
   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
     result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
-    if ( result == ASE_OK )
+    if ( result == ASE_OK ) {
       info.sampleRates.push_back( SAMPLE_RATES[i] );
       info.sampleRates.push_back( SAMPLE_RATES[i] );
+
+      if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
+        info.preferredSampleRate = SAMPLE_RATES[i];
+    }
   }
   }
 
 
   // Determine supported data types ... just check first channel and assume rest are the same.
   // Determine supported data types ... just check first channel and assume rest are the same.
@@ -2829,9 +2885,12 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
                                    unsigned int firstChannel, unsigned int sampleRate,
                                    unsigned int firstChannel, unsigned int sampleRate,
                                    RtAudioFormat format, unsigned int *bufferSize,
                                    RtAudioFormat format, unsigned int *bufferSize,
                                    RtAudio::StreamOptions *options )
                                    RtAudio::StreamOptions *options )
-{
+{////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+  bool isDuplexInput =  mode == INPUT && stream_.mode == OUTPUT;
+
   // For ASIO, a duplex stream MUST use the same driver.
   // For ASIO, a duplex stream MUST use the same driver.
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] != device ) {
+  if ( isDuplexInput && stream_.device[0] != device ) {
     errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";
     errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";
     return FAILURE;
     return FAILURE;
   }
   }
@@ -2845,7 +2904,7 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   }
   }
 
 
   // Only load the driver once for duplex stream.
   // Only load the driver once for duplex stream.
-  if ( mode != INPUT || stream_.mode != OUTPUT ) {
+  if ( !isDuplexInput ) {
     // The getDeviceInfo() function will not work when a stream is open
     // The getDeviceInfo() function will not work when a stream is open
     // because ASIO does not allow multiple devices to run at the same
     // because ASIO does not allow multiple devices to run at the same
     // time.  Thus, we'll probe the system before opening a stream and
     // time.  Thus, we'll probe the system before opening a stream and
@@ -2866,22 +2925,26 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     }
     }
   }
   }
 
 
+  // keep them before any "goto error", they are used for error cleanup + goto device boundary checks
+  bool buffersAllocated = false;
+  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+  unsigned int nChannels;
+
+
   // Check the device channel count.
   // Check the device channel count.
   long inputChannels, outputChannels;
   long inputChannels, outputChannels;
   result = ASIOGetChannels( &inputChannels, &outputChannels );
   result = ASIOGetChannels( &inputChannels, &outputChannels );
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
     errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
 
 
   if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||
   if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||
        ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {
        ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
   stream_.nDeviceChannels[mode] = channels;
   stream_.nDeviceChannels[mode] = channels;
   stream_.nUserChannels[mode] = channels;
   stream_.nUserChannels[mode] = channels;
@@ -2890,30 +2953,27 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   // Verify the sample rate is supported.
   // Verify the sample rate is supported.
   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
   result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
 
 
   // Get the current sample rate
   // Get the current sample rate
   ASIOSampleRate currentRate;
   ASIOSampleRate currentRate;
   result = ASIOGetSampleRate( &currentRate );
   result = ASIOGetSampleRate( &currentRate );
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
 
 
   // Set the sample rate only if necessary
   // Set the sample rate only if necessary
   if ( currentRate != sampleRate ) {
   if ( currentRate != sampleRate ) {
     result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
     result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
     if ( result != ASE_OK ) {
     if ( result != ASE_OK ) {
-      drivers.removeCurrentDriver();
       errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
       errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
       errorText_ = errorStream_.str();
       errorText_ = errorStream_.str();
-      return FAILURE;
+      goto error;
     }
     }
   }
   }
 
 
@@ -2924,10 +2984,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   else channelInfo.isInput = true;
   else channelInfo.isInput = true;
   result = ASIOGetChannelInfo( &channelInfo );
   result = ASIOGetChannelInfo( &channelInfo );
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
 
 
   // Assuming WINDOWS host is always little-endian.
   // Assuming WINDOWS host is always little-endian.
@@ -2956,10 +3015,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   }
   }
 
 
   if ( stream_.deviceFormat[mode] == 0 ) {
   if ( stream_.deviceFormat[mode] == 0 ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
 
 
   // Set the buffer size.  For a duplex stream, this will end up
   // Set the buffer size.  For a duplex stream, this will end up
@@ -2968,49 +3026,63 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   long minSize, maxSize, preferSize, granularity;
   long minSize, maxSize, preferSize, granularity;
   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
   result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
-    drivers.removeCurrentDriver();
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
-    return FAILURE;
+    goto error;
   }
   }
 
 
-  if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
-  else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
-  else if ( granularity == -1 ) {
-    // Make sure bufferSize is a power of two.
-    int log2_of_min_size = 0;
-    int log2_of_max_size = 0;
+  if ( isDuplexInput ) {
+    // When this is the duplex input (output was opened before), then we have to use the same
+    // buffersize as the output, because it might use the preferred buffer size, which most
+    // likely wasn't passed as input to this. The buffer sizes have to be identically anyway,
+    // So instead of throwing an error, make them equal. The caller uses the reference
+    // to the "bufferSize" param as usual to set up processing buffers.
 
 
-    for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
-      if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
-      if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
-    }
+    *bufferSize = stream_.bufferSize;
 
 
-    long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
-    int min_delta_num = log2_of_min_size;
+  } else {
+    if ( *bufferSize == 0 ) *bufferSize = preferSize;
+    else if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
+    else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
+    else if ( granularity == -1 ) {
+      // Make sure bufferSize is a power of two.
+      int log2_of_min_size = 0;
+      int log2_of_max_size = 0;
 
 
-    for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
-      long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
-      if (current_delta < min_delta) {
-        min_delta = current_delta;
-        min_delta_num = i;
+      for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
+        if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
+        if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
       }
       }
-    }
 
 
-    *bufferSize = ( (unsigned int)1 << min_delta_num );
-    if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
-    else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
-  }
-  else if ( granularity != 0 ) {
-    // Set to an even multiple of granularity, rounding up.
-    *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;
+      long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
+      int min_delta_num = log2_of_min_size;
+
+      for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
+        long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
+        if (current_delta < min_delta) {
+          min_delta = current_delta;
+          min_delta_num = i;
+        }
+      }
+
+      *bufferSize = ( (unsigned int)1 << min_delta_num );
+      if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
+      else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
+    }
+    else if ( granularity != 0 ) {
+      // Set to an even multiple of granularity, rounding up.
+      *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;
+    }
   }
   }
 
 
-  if ( mode == INPUT && stream_.mode == OUTPUT && stream_.bufferSize != *bufferSize ) {
-    drivers.removeCurrentDriver();
+  /*
+  // we don't use it anymore, see above!
+  // Just left it here for the case...
+  if ( isDuplexInput && stream_.bufferSize != *bufferSize ) {
     errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";
     errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";
-    return FAILURE;
+    goto error;
   }
   }
+  */
 
 
   stream_.bufferSize = *bufferSize;
   stream_.bufferSize = *bufferSize;
   stream_.nBuffers = 2;
   stream_.nBuffers = 2;
@@ -3022,16 +3094,13 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   stream_.deviceInterleaved[mode] = false;
   stream_.deviceInterleaved[mode] = false;
 
 
   // Allocate, if necessary, our AsioHandle structure for the stream.
   // Allocate, if necessary, our AsioHandle structure for the stream.
-  AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
   if ( handle == 0 ) {
   if ( handle == 0 ) {
     try {
     try {
       handle = new AsioHandle;
       handle = new AsioHandle;
     }
     }
     catch ( std::bad_alloc& ) {
     catch ( std::bad_alloc& ) {
-      //if ( handle == NULL ) {    
-      drivers.removeCurrentDriver();
       errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";
       errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";
-      return FAILURE;
+      goto error;
     }
     }
     handle->bufferInfos = 0;
     handle->bufferInfos = 0;
 
 
@@ -3046,15 +3115,14 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   // Create the ASIO internal buffers.  Since RtAudio sets up input
   // Create the ASIO internal buffers.  Since RtAudio sets up input
   // and output separately, we'll have to dispose of previously
   // and output separately, we'll have to dispose of previously
   // created output buffers for a duplex stream.
   // created output buffers for a duplex stream.
-  long inputLatency, outputLatency;
   if ( mode == INPUT && stream_.mode == OUTPUT ) {
   if ( mode == INPUT && stream_.mode == OUTPUT ) {
     ASIODisposeBuffers();
     ASIODisposeBuffers();
     if ( handle->bufferInfos ) free( handle->bufferInfos );
     if ( handle->bufferInfos ) free( handle->bufferInfos );
   }
   }
 
 
   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
   // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
-  bool buffersAllocated = false;
-  unsigned int i, nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+  unsigned int i;
+  nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
   handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
   handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
   if ( handle->bufferInfos == NULL ) {
   if ( handle->bufferInfos == NULL ) {
     errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";
     errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";
@@ -3075,18 +3143,37 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     infos->buffers[0] = infos->buffers[1] = 0;
     infos->buffers[0] = infos->buffers[1] = 0;
   }
   }
 
 
+  // prepare for callbacks
+  stream_.sampleRate = sampleRate;
+  stream_.device[mode] = device;
+  stream_.mode = isDuplexInput ? DUPLEX : mode;
+
+  // store this class instance before registering callbacks, that are going to use it
+  asioCallbackInfo = &stream_.callbackInfo;
+  stream_.callbackInfo.object = (void *) this;
+
   // Set up the ASIO callback structure and create the ASIO data buffers.
   // Set up the ASIO callback structure and create the ASIO data buffers.
   asioCallbacks.bufferSwitch = &bufferSwitch;
   asioCallbacks.bufferSwitch = &bufferSwitch;
   asioCallbacks.sampleRateDidChange = &sampleRateChanged;
   asioCallbacks.sampleRateDidChange = &sampleRateChanged;
   asioCallbacks.asioMessage = &asioMessages;
   asioCallbacks.asioMessage = &asioMessages;
   asioCallbacks.bufferSwitchTimeInfo = NULL;
   asioCallbacks.bufferSwitchTimeInfo = NULL;
   result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
   result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
+  if ( result != ASE_OK ) {
+    // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges
+    // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver
+    // in that case, let's be naïve and try that instead
+    *bufferSize = preferSize;
+    stream_.bufferSize = *bufferSize;
+    result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
+  }
+
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";
     errorText_ = errorStream_.str();
     errorText_ = errorStream_.str();
     goto error;
     goto error;
   }
   }
-  buffersAllocated = true;
+  buffersAllocated = true;  
+  stream_.state = STREAM_STOPPED;
 
 
   // Set flags for buffer conversion.
   // Set flags for buffer conversion.
   stream_.doConvertBuffer[mode] = false;
   stream_.doConvertBuffer[mode] = false;
@@ -3109,11 +3196,9 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
 
 
     bool makeBuffer = true;
     bool makeBuffer = true;
     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
     bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
-    if ( mode == INPUT ) {
-      if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
-        unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
-        if ( bufferBytes <= bytesOut ) makeBuffer = false;
-      }
+    if ( isDuplexInput && stream_.deviceBuffer ) {
+      unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+      if ( bufferBytes <= bytesOut ) makeBuffer = false;
     }
     }
 
 
     if ( makeBuffer ) {
     if ( makeBuffer ) {
@@ -3127,18 +3212,8 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
     }
     }
   }
   }
 
 
-  stream_.sampleRate = sampleRate;
-  stream_.device[mode] = device;
-  stream_.state = STREAM_STOPPED;
-  asioCallbackInfo = &stream_.callbackInfo;
-  stream_.callbackInfo.object = (void *) this;
-  if ( stream_.mode == OUTPUT && mode == INPUT )
-    // We had already set up an output stream.
-    stream_.mode = DUPLEX;
-  else
-    stream_.mode = mode;
-
   // Determine device latencies
   // Determine device latencies
+  long inputLatency, outputLatency;
   result = ASIOGetLatencies( &inputLatency, &outputLatency );
   result = ASIOGetLatencies( &inputLatency, &outputLatency );
   if ( result != ASE_OK ) {
   if ( result != ASE_OK ) {
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";
     errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";
@@ -3158,32 +3233,38 @@ bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne
   return SUCCESS;
   return SUCCESS;
 
 
  error:
  error:
-  if ( buffersAllocated )
-    ASIODisposeBuffers();
-  drivers.removeCurrentDriver();
+  if ( !isDuplexInput ) {
+    // the cleanup for error in the duplex input, is done by RtApi::openStream
+    // So we clean up for single channel only
 
 
-  if ( handle ) {
-    CloseHandle( handle->condition );
-    if ( handle->bufferInfos )
-      free( handle->bufferInfos );
-    delete handle;
-    stream_.apiHandle = 0;
-  }
+    if ( buffersAllocated )
+      ASIODisposeBuffers();
 
 
-  for ( int i=0; i<2; i++ ) {
-    if ( stream_.userBuffer[i] ) {
-      free( stream_.userBuffer[i] );
-      stream_.userBuffer[i] = 0;
+    drivers.removeCurrentDriver();
+
+    if ( handle ) {
+      CloseHandle( handle->condition );
+      if ( handle->bufferInfos )
+        free( handle->bufferInfos );
+
+      delete handle;
+      stream_.apiHandle = 0;
     }
     }
-  }
 
 
-  if ( stream_.deviceBuffer ) {
-    free( stream_.deviceBuffer );
-    stream_.deviceBuffer = 0;
+
+    if ( stream_.userBuffer[mode] ) {
+      free( stream_.userBuffer[mode] );
+      stream_.userBuffer[mode] = 0;
+    }
+
+    if ( stream_.deviceBuffer ) {
+      free( stream_.deviceBuffer );
+      stream_.deviceBuffer = 0;
+    }
   }
   }
 
 
   return FAILURE;
   return FAILURE;
-}
+}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 void RtApiAsio :: closeStream()
 void RtApiAsio :: closeStream()
 {
 {
@@ -3635,12 +3716,12 @@ public:
       outIndex_( 0 ) {}
       outIndex_( 0 ) {}
 
 
   ~WasapiBuffer() {
   ~WasapiBuffer() {
-    delete buffer_;
+    free( buffer_ );
   }
   }
 
 
   // sets the length of the internal ring buffer
   // sets the length of the internal ring buffer
   void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {
   void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {
-    delete buffer_;
+    free( buffer_ );
 
 
     buffer_ = ( char* ) calloc( bufferSize, formatBytes );
     buffer_ = ( char* ) calloc( bufferSize, formatBytes );
 
 
@@ -3799,7 +3880,7 @@ void convertBufferWasapi( char* outBuffer,
   float sampleStep = 1.0f / sampleRatio;
   float sampleStep = 1.0f / sampleRatio;
   float inSampleFraction = 0.0f;
   float inSampleFraction = 0.0f;
 
 
-  outSampleCount = ( unsigned int ) ( inSampleCount * sampleRatio );
+  outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio );
 
 
   // frame-by-frame, copy each relative input sample into it's corresponding output sample
   // frame-by-frame, copy each relative input sample into it's corresponding output sample
   for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
   for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
@@ -3945,7 +4026,6 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
   RtAudio::DeviceInfo info;
   RtAudio::DeviceInfo info;
   unsigned int captureDeviceCount = 0;
   unsigned int captureDeviceCount = 0;
   unsigned int renderDeviceCount = 0;
   unsigned int renderDeviceCount = 0;
-  std::wstring deviceName;
   std::string defaultDeviceName;
   std::string defaultDeviceName;
   bool isCaptureDevice = false;
   bool isCaptureDevice = false;
 
 
@@ -4048,8 +4128,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
     goto Exit;
     goto Exit;
   }
   }
 
 
-  deviceName = defaultDeviceNameProp.pwszVal;
-  defaultDeviceName = std::string( deviceName.begin(), deviceName.end() );
+  defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal);
 
 
   // name
   // name
   hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
   hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
@@ -4066,8 +4145,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
     goto Exit;
     goto Exit;
   }
   }
 
 
-  deviceName = deviceNameProp.pwszVal;
-  info.name = std::string( deviceName.begin(), deviceName.end() );
+  info.name =convertCharPointerToStdString(deviceNameProp.pwszVal);
 
 
   // is default
   // is default
   if ( isCaptureDevice ) {
   if ( isCaptureDevice ) {
@@ -4110,6 +4188,7 @@ RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
   for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
   for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
     info.sampleRates.push_back( SAMPLE_RATES[i] );
     info.sampleRates.push_back( SAMPLE_RATES[i] );
   }
   }
+  info.preferredSampleRate = deviceFormat->nSamplesPerSec;
 
 
   // native format
   // native format
   info.nativeFormats = 0;
   info.nativeFormats = 0;
@@ -5245,14 +5324,11 @@ unsigned int RtApiDs :: getDeviceCount( void )
     error( RtAudioError::WARNING );
     error( RtAudioError::WARNING );
   }
   }
 
 
-  // Clean out any devices that may have disappeared.
-  std::vector< int > indices;
-  for ( unsigned int i=0; i<dsDevices.size(); i++ )
-    if ( dsDevices[i].found == false ) indices.push_back( i );
-  //unsigned int nErased = 0;
-  for ( unsigned int i=0; i<indices.size(); i++ )
-    dsDevices.erase( dsDevices.begin()+indices[i] );
-  //dsDevices.erase( dsDevices.begin()-nErased++ );
+  // Clean out any devices that may have disappeared (code update submitted by Eli Zehngut).
+  for ( unsigned int i=0; i<dsDevices.size(); ) {
+    if ( dsDevices[i].found == false ) dsDevices.erase( dsDevices.begin() + i );
+    else i++;
+  }
 
 
   return static_cast<unsigned int>(dsDevices.size());
   return static_cast<unsigned int>(dsDevices.size());
 }
 }
@@ -5308,8 +5384,12 @@ RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
   info.sampleRates.clear();
   info.sampleRates.clear();
   for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
   for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
     if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&
     if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&
-         SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate )
+         SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {
       info.sampleRates.push_back( SAMPLE_RATES[k] );
       info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+      if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+        info.preferredSampleRate = SAMPLE_RATES[k];
+    }
   }
   }
 
 
   // Get format information.
   // Get format information.
@@ -6264,6 +6344,7 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {
       if ( FAILED( result ) ) {
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
         errorText_ = errorStream_.str();
         errorText_ = errorStream_.str();
+        MUTEX_UNLOCK( &stream_.mutex );
         error( RtAudioError::SYSTEM_ERROR );
         error( RtAudioError::SYSTEM_ERROR );
         return;
         return;
       }
       }
@@ -6271,6 +6352,7 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {
       if ( FAILED( result ) ) {
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
         errorText_ = errorStream_.str();
         errorText_ = errorStream_.str();
+        MUTEX_UNLOCK( &stream_.mutex );
         error( RtAudioError::SYSTEM_ERROR );
         error( RtAudioError::SYSTEM_ERROR );
         return;
         return;
       }
       }
@@ -6279,6 +6361,7 @@ void RtApiDs :: callbackEvent()
         if ( FAILED( result ) ) {
         if ( FAILED( result ) ) {
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
           errorText_ = errorStream_.str();
           errorText_ = errorStream_.str();
+          MUTEX_UNLOCK( &stream_.mutex );
           error( RtAudioError::SYSTEM_ERROR );
           error( RtAudioError::SYSTEM_ERROR );
           return;
           return;
         }
         }
@@ -6286,6 +6369,7 @@ void RtApiDs :: callbackEvent()
         if ( FAILED( result ) ) {
         if ( FAILED( result ) ) {
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
           errorText_ = errorStream_.str();
           errorText_ = errorStream_.str();
+          MUTEX_UNLOCK( &stream_.mutex );
           error( RtAudioError::SYSTEM_ERROR );
           error( RtAudioError::SYSTEM_ERROR );
           return;
           return;
         }
         }
@@ -6307,6 +6391,7 @@ void RtApiDs :: callbackEvent()
       if ( FAILED( result ) ) {
       if ( FAILED( result ) ) {
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
         errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
         errorText_ = errorStream_.str();
         errorText_ = errorStream_.str();
+        MUTEX_UNLOCK( &stream_.mutex );
         error( RtAudioError::SYSTEM_ERROR );
         error( RtAudioError::SYSTEM_ERROR );
         return;
         return;
       }
       }
@@ -6399,6 +6484,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
       errorText_ = errorStream_.str();
       errorText_ = errorStream_.str();
+      MUTEX_UNLOCK( &stream_.mutex );
       error( RtAudioError::SYSTEM_ERROR );
       error( RtAudioError::SYSTEM_ERROR );
       return;
       return;
     }
     }
@@ -6412,6 +6498,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
       errorText_ = errorStream_.str();
       errorText_ = errorStream_.str();
+      MUTEX_UNLOCK( &stream_.mutex );
       error( RtAudioError::SYSTEM_ERROR );
       error( RtAudioError::SYSTEM_ERROR );
       return;
       return;
     }
     }
@@ -6448,6 +6535,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
       errorText_ = errorStream_.str();
       errorText_ = errorStream_.str();
+      MUTEX_UNLOCK( &stream_.mutex );
       error( RtAudioError::SYSTEM_ERROR );
       error( RtAudioError::SYSTEM_ERROR );
       return;
       return;
     }
     }
@@ -6509,6 +6597,7 @@ void RtApiDs :: callbackEvent()
         if ( FAILED( result ) ) {
         if ( FAILED( result ) ) {
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
           errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
           errorText_ = errorStream_.str();
           errorText_ = errorStream_.str();
+          MUTEX_UNLOCK( &stream_.mutex );
           error( RtAudioError::SYSTEM_ERROR );
           error( RtAudioError::SYSTEM_ERROR );
           return;
           return;
         }
         }
@@ -6523,6 +6612,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
       errorText_ = errorStream_.str();
       errorText_ = errorStream_.str();
+      MUTEX_UNLOCK( &stream_.mutex );
       error( RtAudioError::SYSTEM_ERROR );
       error( RtAudioError::SYSTEM_ERROR );
       return;
       return;
     }
     }
@@ -6544,6 +6634,7 @@ void RtApiDs :: callbackEvent()
     if ( FAILED( result ) ) {
     if ( FAILED( result ) ) {
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
       errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
       errorText_ = errorStream_.str();
       errorText_ = errorStream_.str();
+      MUTEX_UNLOCK( &stream_.mutex );
       error( RtAudioError::SYSTEM_ERROR );
       error( RtAudioError::SYSTEM_ERROR );
       return;
       return;
     }
     }
@@ -6582,21 +6673,6 @@ static unsigned __stdcall callbackHandler( void *ptr )
   return 0;
   return 0;
 }
 }
 
 
-#include "tchar.h"
-
-static std::string convertTChar( LPCTSTR name )
-{
-#if defined( UNICODE ) || defined( _UNICODE )
-  int length = WideCharToMultiByte(CP_UTF8, 0, name, -1, NULL, 0, NULL, NULL);
-  std::string s( length-1, '\0' );
-  WideCharToMultiByte(CP_UTF8, 0, name, -1, &s[0], length, NULL, NULL);
-#else
-  std::string s( name );
-#endif
-
-  return s;
-}
-
 static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
 static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
                                           LPCTSTR description,
                                           LPCTSTR description,
                                           LPCTSTR /*module*/,
                                           LPCTSTR /*module*/,
@@ -6638,7 +6714,7 @@ static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
   }
   }
 
 
   // If good device, then save its name and guid.
   // If good device, then save its name and guid.
-  std::string name = convertTChar( description );
+  std::string name = convertCharPointerToStdString( description );
   //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
   //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
   if ( lpguid == NULL )
   if ( lpguid == NULL )
     name = "Default Device";
     name = "Default Device";
@@ -6820,6 +6896,7 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
 
 
   // Count cards and devices
   // Count cards and devices
   card = -1;
   card = -1;
+  subdevice = -1;
   snd_card_next( &card );
   snd_card_next( &card );
   while ( card >= 0 ) {
   while ( card >= 0 ) {
     sprintf( name, "hw:%d", card );
     sprintf( name, "hw:%d", card );
@@ -7033,8 +7110,12 @@ RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
   // Test our discrete set of sample rate values.
   // Test our discrete set of sample rate values.
   info.sampleRates.clear();
   info.sampleRates.clear();
   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
   for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
-    if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 )
+    if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 ) {
       info.sampleRates.push_back( SAMPLE_RATES[i] );
       info.sampleRates.push_back( SAMPLE_RATES[i] );
+
+      if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
+        info.preferredSampleRate = SAMPLE_RATES[i];
+    }
   }
   }
   if ( info.sampleRates.size() == 0 ) {
   if ( info.sampleRates.size() == 0 ) {
     snd_pcm_close( phandle );
     snd_pcm_close( phandle );
@@ -7959,6 +8040,8 @@ void RtApiAlsa :: callbackEvent()
             errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";
             errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";
             errorText_ = errorStream_.str();
             errorText_ = errorStream_.str();
           }
           }
+          else
+            errorText_ =  "RtApiAlsa::callbackEvent: audio write error, underrun.";
         }
         }
         else {
         else {
           errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
           errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
@@ -8067,6 +8150,7 @@ RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
   for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )
   for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )
     info.sampleRates.push_back( *sr );
     info.sampleRates.push_back( *sr );
 
 
+  info.preferredSampleRate = 48000;
   info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;
   info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;
 
 
   return info;
   return info;
@@ -8429,7 +8513,7 @@ bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
   pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
   pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
 
 
   int error;
   int error;
-  if ( !options->streamName.empty() ) streamName = options->streamName;
+  if ( options && !options->streamName.empty() ) streamName = options->streamName;
   switch ( mode ) {
   switch ( mode ) {
   case INPUT:
   case INPUT:
     pa_buffer_attr buffer_attr;
     pa_buffer_attr buffer_attr;
@@ -8635,6 +8719,10 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
       for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
       for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
         if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {
         if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {
           info.sampleRates.push_back( SAMPLE_RATES[k] );
           info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+          if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+            info.preferredSampleRate = SAMPLE_RATES[k];
+
           break;
           break;
         }
         }
       }
       }
@@ -8643,8 +8731,12 @@ RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
   else {
   else {
     // Check min and max rate values;
     // Check min and max rate values;
     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
     for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
-      if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] )
+      if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) {
         info.sampleRates.push_back( SAMPLE_RATES[k] );
         info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+        if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+          info.preferredSampleRate = SAMPLE_RATES[k];
+      }
     }
     }
   }
   }
 
 

+ 2 - 1
drivers/rtaudio/RtAudio.h

@@ -310,12 +310,13 @@ class RtAudio
     bool isDefaultOutput;         /*!< true if this is the default output device. */
     bool isDefaultOutput;         /*!< true if this is the default output device. */
     bool isDefaultInput;          /*!< true if this is the default input device. */
     bool isDefaultInput;          /*!< true if this is the default input device. */
     std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
     std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
+    unsigned int preferredSampleRate; /*!< Preferred sample rate, eg. for WASAPI the system sample rate. */
     RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
     RtAudioFormat nativeFormats;  /*!< Bit mask of supported data formats. */
 
 
     // Default constructor.
     // Default constructor.
     DeviceInfo()
     DeviceInfo()
       :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
       :probed(false), outputChannels(0), inputChannels(0), duplexChannels(0),
-       isDefaultOutput(false), isDefaultInput(false), nativeFormats(0) {}
+       isDefaultOutput(false), isDefaultInput(false), preferredSampleRate(0), nativeFormats(0) {}
   };
   };
 
 
   //! The structure for specifying input or ouput stream parameters.
   //! The structure for specifying input or ouput stream parameters.

+ 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();
 		DVector<uint8_t>::Write wr = data.write();
 		uint8_t* ptr = wr.ptr();
 		uint8_t* ptr = wr.ptr();
-		memcpy(ptr, f->getBuffer(), imgsize);
+		copymem(ptr, f->getBuffer(), imgsize);
 	}
 	}
     /*
     /*
     for (int i=0; i<h; i++) {
     for (int i=0; i<h; i++) {

+ 1 - 1
drivers/vorbis/psy.c

@@ -1160,7 +1160,7 @@ void _vp_couple_quantize_normalize(int blobno,
                     However, this is a temporary patch.
                     However, this is a temporary patch.
                     by Aoyumi @ 2004/04/18
                     by Aoyumi @ 2004/04/18
                 */
                 */
-                /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit)));
+                /*float derate = (1.0 - de*((float)(j-limit+i) / (float)(n-limit))); */
                 /* elliptical 
                 /* elliptical 
                 if(reM[j]+reA[j]<0){
                 if(reM[j]+reA[j]<0){
                   reM[j] = - (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate);
                   reM[j] = - (qeM[j] = (fabs(reM[j])+fabs(reA[j]))*derate*derate);

+ 20 - 17
drivers/windows/dir_access_windows.cpp

@@ -167,6 +167,7 @@ Error DirAccessWindows::change_dir(String p_dir) {
 
 
 	if (worked) {
 	if (worked) {
 
 
+
 		GetCurrentDirectoryW(2048,real_current_dir_name);
 		GetCurrentDirectoryW(2048,real_current_dir_name);
 		current_dir=real_current_dir_name; // TODO, utf8 parser
 		current_dir=real_current_dir_name; // TODO, utf8 parser
 		current_dir=current_dir.replace("\\","/");
 		current_dir=current_dir.replace("\\","/");
@@ -190,9 +191,9 @@ Error DirAccessWindows::make_dir(String p_dir) {
 
 
 #else
 #else
 
 
-	//p_dir=fix_path(p_dir);
+	p_dir=fix_path(p_dir);
 	
 	
-	p_dir.replace("/","\\");
+	//p_dir.replace("/","\\");
 
 
 	bool success;
 	bool success;
 	int err;
 	int err;
@@ -249,14 +250,14 @@ bool DirAccessWindows::file_exists(String p_file) {
 
 
 	p_file=fix_path(p_file);
 	p_file=fix_path(p_file);
 	
 	
-	p_file.replace("/","\\");
+	//p_file.replace("/","\\");
 
 
-	WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
+	//WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
 
 
 	DWORD fileAttr;
 	DWORD fileAttr;
 
 
-	fileAttr = GetFileAttributesExW(p_file.c_str(), GetFileExInfoStandard, &fileInfo);
-	if (0 == fileAttr)
+	fileAttr = GetFileAttributesW(p_file.c_str());
+	if (INVALID_FILE_ATTRIBUTES == fileAttr)
 		return false;
 		return false;
 
 
 	return !(fileAttr&FILE_ATTRIBUTE_DIRECTORY);
 	return !(fileAttr&FILE_ATTRIBUTE_DIRECTORY);
@@ -272,17 +273,16 @@ bool DirAccessWindows::dir_exists(String p_dir) {
 	else
 	else
 		p_dir=fix_path(p_dir);
 		p_dir=fix_path(p_dir);
 
 
-	p_dir.replace("/","\\");
+	//p_dir.replace("/","\\");
 
 
-	WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
+	//WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
 
 
 
 
 	DWORD fileAttr;
 	DWORD fileAttr;
 
 
-	fileAttr = GetFileAttributesExW(p_dir.c_str(), GetFileExInfoStandard, &fileInfo);
-	if (0 == fileAttr)
-		return false;
-
+	fileAttr = GetFileAttributesW(p_dir.c_str());
+	if (INVALID_FILE_ATTRIBUTES == fileAttr)
+		    return false;
 	return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
 	return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
 
 
 }
 }
@@ -313,12 +313,15 @@ Error DirAccessWindows::remove(String p_path)  {
 	p_path=fix_path(p_path);
 	p_path=fix_path(p_path);
 	
 	
 	printf("erasing %s\n",p_path.utf8().get_data());
 	printf("erasing %s\n",p_path.utf8().get_data());
-	WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
-	DWORD fileAttr = GetFileAttributesExW(p_path.c_str(), GetFileExInfoStandard, &fileInfo);
-	if (fileAttr == INVALID_FILE_ATTRIBUTES)
-		return FAILED;
+	//WIN32_FILE_ATTRIBUTE_DATA    fileInfo;
+	//DWORD fileAttr = GetFileAttributesExW(p_path.c_str(), GetFileExInfoStandard, &fileInfo);
+
+	DWORD fileAttr;
 
 
-	if (fileAttr & FILE_ATTRIBUTE_DIRECTORY)
+	fileAttr = GetFileAttributesW(p_path.c_str());
+	if (INVALID_FILE_ATTRIBUTES == fileAttr)
+		    return FAILED;
+	if ((fileAttr&FILE_ATTRIBUTE_DIRECTORY))
 		return ::_wrmdir(p_path.c_str())==0?OK:FAILED;
 		return ::_wrmdir(p_path.c_str())==0?OK:FAILED;
 	else
 	else
 		return ::_wunlink(p_path.c_str())==0?OK:FAILED;
 		return ::_wunlink(p_path.c_str())==0?OK:FAILED;

+ 13 - 6
main/main.cpp

@@ -251,7 +251,14 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
 		packed_data = memnew(PackedData);
 		packed_data = memnew(PackedData);
 
 
 #ifdef MINIZIP_ENABLED
 #ifdef MINIZIP_ENABLED
+	
+	//XXX: always get_singleton() == 0x0
 	zip_packed_data = ZipArchive::get_singleton();
 	zip_packed_data = ZipArchive::get_singleton();
+	//TODO: remove this temporary fix
+	if (!zip_packed_data) {
+		zip_packed_data = memnew(ZipArchive);
+	}
+
 	packed_data->add_pack_source(zip_packed_data);
 	packed_data->add_pack_source(zip_packed_data);
 #endif
 #endif
 
 
@@ -748,12 +755,12 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
 	if (file_access_network_client)
 	if (file_access_network_client)
 		memdelete(file_access_network_client);
 		memdelete(file_access_network_client);
 
 
-	if (packed_data)
-		memdelete( packed_data );
-#ifdef MINIZIP_ENABLED
-	if (zip_packed_data)
-		memdelete( zip_packed_data );
-#endif
+// Note 1: *zip_packed_data live into *packed_data
+// Note 2: PackedData::~PackedData destroy this.
+//#ifdef MINIZIP_ENABLED
+//	if (zip_packed_data)
+//		memdelete( zip_packed_data );
+//#endif
 
 
 
 
 	unregister_core_types();
 	unregister_core_types();

+ 24 - 0
modules/gdscript/gd_functions.cpp

@@ -88,6 +88,7 @@ const char *GDFunctions::get_func_name(Function p_func) {
 		"str",
 		"str",
 		"print",
 		"print",
 		"printt",
 		"printt",
+		"prints",
 		"printerr",
 		"printerr",
 		"printraw",
 		"printraw",
 		"var2str",
 		"var2str",
@@ -561,6 +562,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
 			r_ret=Variant();
 			r_ret=Variant();
 
 
 
 
+		} break;
+		case TEXT_PRINT_SPACED: {
+
+			String str;
+			for(int i=0;i<p_arg_count;i++) {
+
+				if (i)
+					str+=" ";
+				str+=p_args[i]->operator String();
+			}
+
+			//str+="\n";
+			print_line(str);
+			r_ret=Variant();
+
+
 		} break;
 		} break;
 
 
 		case TEXT_PRINTERR: {
 		case TEXT_PRINTERR: {
@@ -1251,6 +1268,13 @@ MethodInfo GDFunctions::get_info(Function p_func) {
 			mi.return_val.type=Variant::NIL;
 			mi.return_val.type=Variant::NIL;
 			return mi;
 			return mi;
 
 
+		} break;
+		case TEXT_PRINT_SPACED: {
+
+			MethodInfo mi("prints",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"..."));
+			mi.return_val.type=Variant::NIL;
+			return mi;
+
 		} break;
 		} break;
 		case TEXT_PRINTERR: {
 		case TEXT_PRINTERR: {
 
 

+ 1 - 0
modules/gdscript/gd_functions.h

@@ -84,6 +84,7 @@ public:
 		TEXT_STR,
 		TEXT_STR,
 		TEXT_PRINT,
 		TEXT_PRINT,
 		TEXT_PRINT_TABBED,
 		TEXT_PRINT_TABBED,
+		TEXT_PRINT_SPACED,
 		TEXT_PRINTERR,
 		TEXT_PRINTERR,
 		TEXT_PRINTRAW,
 		TEXT_PRINTRAW,
 		VAR_TO_STR,
 		VAR_TO_STR,

+ 1 - 1
modules/gdscript/gd_tokenizer.cpp

@@ -1036,7 +1036,7 @@ void GDTokenizerText::advance(int p_amount) {
 
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
-#define BYTECODE_VERSION 3
+#define BYTECODE_VERSION 4
 
 
 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
 
 

+ 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     */
 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 /*************************************************************************/
- * 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");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.

+ 32 - 5
platform/android/export/export.cpp

@@ -225,6 +225,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 
 
 	static void _device_poll_thread(void *ud);
 	static void _device_poll_thread(void *ud);
 
 
+	String get_package_name();
+
 	String get_project_name() const;
 	String get_project_name() const;
 	void _fix_manifest(Vector<uint8_t>& p_manifest);
 	void _fix_manifest(Vector<uint8_t>& p_manifest);
 	void _fix_resources(Vector<uint8_t>& p_manifest);
 	void _fix_resources(Vector<uint8_t>& p_manifest);
@@ -756,7 +758,7 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
 					if (tname=="manifest" && attrname=="package") {
 					if (tname=="manifest" && attrname=="package") {
 
 
 						print_line("FOUND PACKAGE");
 						print_line("FOUND PACKAGE");
-						string_table[attr_value]=package;
+						string_table[attr_value]=get_package_name();
 					}
 					}
 
 
 					//print_line("tname: "+tname);
 					//print_line("tname: "+tname);
@@ -1169,7 +1171,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
 
 
 		if (apk_expansion) {
 		if (apk_expansion) {
 
 
-			String apkfname="main."+itos(version_code)+"."+package+".obb";
+			String apkfname="main."+itos(version_code)+"."+get_package_name()+".obb";
 			String fullpath=p_path.get_base_dir().plus_file(apkfname);
 			String fullpath=p_path.get_base_dir().plus_file(apkfname);
 			FileAccess *pf = FileAccess::open(fullpath,FileAccess::WRITE);
 			FileAccess *pf = FileAccess::open(fullpath,FileAccess::WRITE);
 			if (!pf) {
 			if (!pf) {
@@ -1514,7 +1516,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 		args.push_back("-s");
 		args.push_back("-s");
 		args.push_back(devices[p_device].id);
 		args.push_back(devices[p_device].id);
 		args.push_back("uninstall");
 		args.push_back("uninstall");
-		args.push_back(package);
+		args.push_back(get_package_name());
 
 
 		err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
 		err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
 #if 0
 #if 0
@@ -1552,7 +1554,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 	args.push_back("-a");
 	args.push_back("-a");
 	args.push_back("android.intent.action.MAIN");
 	args.push_back("android.intent.action.MAIN");
 	args.push_back("-n");
 	args.push_back("-n");
-	args.push_back(package+"/com.android.godot.Godot");
+	args.push_back(get_package_name()+"/com.android.godot.Godot");
 
 
 	err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
 	err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
 	if (err || rv!=0) {
 	if (err || rv!=0) {
@@ -1564,12 +1566,37 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 	return OK;
 	return OK;
 }
 }
 
 
+String EditorExportPlatformAndroid::get_package_name() {
+
+	String pname = package;
+	String basename = Globals::get_singleton()->get("application/name");
+	basename=basename.to_lower();
+
+	String name;
+	bool first=true;
+	for(int i=0;i<basename.length();i++) {
+		CharType c = basename[i];
+		if (c>='0' && c<='9' && first) {
+			continue;
+		}
+		if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9')) {
+			name+=String::chr(c);
+			first=false;
+		}
+	}
+	if (name=="")
+		name="noname";
+
+	pname=pname.replace("$genname",name);
+	return pname;
+
+}
 
 
 EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
 EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
 
 
 	version_code=1;
 	version_code=1;
 	version_name="1.0";
 	version_name="1.0";
-	package="com.android.noname";
+	package="org.godotengine.$genname";
 	name="";
 	name="";
 	_signed=true;
 	_signed=true;
 	apk_expansion=false;
 	apk_expansion=false;

二進制
platform/android/java/res/drawable/icon.png


+ 17 - 2
platform/osx/os_osx.mm

@@ -966,8 +966,10 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
 
 
 	[NSApp activateIgnoringOtherApps:YES];
 	[NSApp activateIgnoringOtherApps:YES];
 
 
-	 [window_object makeKeyAndOrderFront:nil];
+	[window_object makeKeyAndOrderFront:nil];
 
 
+	if (p_desired.fullscreen)
+		zoomed = true;
 
 
 	/*** END OSX INITIALIZATION ***/
 	/*** END OSX INITIALIZATION ***/
 	/*** END OSX INITIALIZATION ***/
 	/*** END OSX INITIALIZATION ***/
@@ -1310,14 +1312,22 @@ void OS_OSX::set_window_size(const Size2 p_size) {
 
 
 void OS_OSX::set_window_fullscreen(bool p_enabled) {
 void OS_OSX::set_window_fullscreen(bool p_enabled) {
 
 
-	[window_object performZoom:nil];
+	if (zoomed != p_enabled) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+		[window_object toggleFullScreen:nil];
+#else
+		[window_object performZoom:nil];
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
+	}
 	zoomed = p_enabled;
 	zoomed = p_enabled;
 };
 };
 
 
 bool OS_OSX::is_window_fullscreen() const {
 bool OS_OSX::is_window_fullscreen() const {
 
 
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
 	if ( [window_object respondsToSelector:@selector(isZoomed)] )
 	if ( [window_object respondsToSelector:@selector(isZoomed)] )
 		return [window_object isZoomed];
 		return [window_object isZoomed];
+#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
 
 
 	return zoomed;
 	return zoomed;
 };
 };
@@ -1509,6 +1519,11 @@ void OS_OSX::run() {
 
 
 	main_loop->init();
 	main_loop->init();
 
 
+	if (zoomed) {
+		zoomed = false;
+		set_window_fullscreen(true);
+	}
+
 //	uint64_t last_ticks=get_ticks_usec();
 //	uint64_t last_ticks=get_ticks_usec();
 
 
 //	int frames=0;
 //	int frames=0;

+ 6 - 0
platform/windows/SCsub

@@ -12,3 +12,9 @@ common_win=[
 ]
 ]
 
 
 env.Program('#bin/godot',['godot_win.cpp']+common_win,PROGSUFFIX=env["PROGSUFFIX"])
 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]

+ 1 - 1
platform/windows/detect.py

@@ -204,7 +204,7 @@ def configure(env):
 
 
 		elif (env["target"]=="debug"):
 		elif (env["target"]=="debug"):
 
 
-			env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DDEBUG_MEMORY_ENABLED','/DD3D_DEBUG_INFO','/O1'])
+			env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DDEBUG_MEMORY_ENABLED','/DD3D_DEBUG_INFO','/Od'])
 			env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
 			env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
 			env.Append(LINKFLAGS=['/DEBUG'])
 			env.Append(LINKFLAGS=['/DEBUG'])
 
 

+ 25 - 82
platform/windows/godot_win.cpp

@@ -115,29 +115,24 @@ PCHAR*
         return argv;
         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];
 	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;
 	ubuf[ulen] = 0;
 	return ubuf;
 	return ubuf;
 }
 }
 
 
-int main(int argc, char** argv) {
+int widechar_main(int argc, wchar_t** argv) {
 
 
 	OS_Windows os(NULL);
 	OS_Windows os(NULL);
 
 
 	setlocale(LC_CTYPE, "");
 	setlocale(LC_CTYPE, "");
 
 
 	char ** argv_utf8 = new char*[argc];
 	char ** argv_utf8 = new char*[argc];
+
 	for(int i=0; i<argc; ++i) {
 	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]);
 	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();
 	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 {
 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 "";
 	return "";
-};
+}
 
 
 String OS_Windows::get_stdin_string(bool p_block) {
 String OS_Windows::get_stdin_string(bool p_block) {
 
 

+ 2 - 2
platform/x11/os_x11.cpp

@@ -317,8 +317,8 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
 	/* set the name and class hints for the window manager to use */
 	/* set the name and class hints for the window manager to use */
 	classHint = XAllocClassHint();
 	classHint = XAllocClassHint();
 	if (classHint) {
 	if (classHint) {
-		classHint->res_name = "Godot";
-		classHint->res_class = "Godot";
+		classHint->res_name = (char *)"Godot";
+		classHint->res_class = (char *)"Godot";
 	}
 	}
 	XSetClassHint(x11_display, x11_window, classHint);
 	XSetClassHint(x11_display, x11_window, classHint);
 	XFree(classHint);
 	XFree(classHint);

+ 33 - 1
scene/2d/area_2d.cpp

@@ -512,6 +512,29 @@ bool Area2D::overlaps_body(Node* p_body) const{
 
 
 }
 }
 
 
+void Area2D::set_collision_mask(uint32_t p_mask) {
+
+	collision_mask=p_mask;
+	Physics2DServer::get_singleton()->area_set_collision_mask(get_rid(),p_mask);
+}
+
+uint32_t Area2D::get_collision_mask() const {
+
+	return collision_mask;
+}
+
+
+void Area2D::set_layer_mask(uint32_t p_mask) {
+
+	layer_mask=p_mask;
+	Physics2DServer::get_singleton()->area_set_layer_mask(get_rid(),p_mask);
+}
+
+uint32_t Area2D::get_layer_mask() const {
+
+	return layer_mask;
+}
+
 
 
 void Area2D::_bind_methods() {
 void Area2D::_bind_methods() {
 
 
@@ -542,6 +565,12 @@ void Area2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority);
 	ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority);
 	ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority);
 	ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority);
 
 
+	ObjectTypeDB::bind_method(_MD("set_collision_mask","collision_mask"),&Area2D::set_collision_mask);
+	ObjectTypeDB::bind_method(_MD("get_collision_mask"),&Area2D::get_collision_mask);
+
+	ObjectTypeDB::bind_method(_MD("set_layer_mask","layer_mask"),&Area2D::set_layer_mask);
+	ObjectTypeDB::bind_method(_MD("get_layer_mask"),&Area2D::get_layer_mask);
+
 	ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring);
 	ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring);
 	ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled);
 	ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled);
 
 
@@ -578,6 +607,8 @@ void Area2D::_bind_methods() {
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority"));
 	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"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
 
 
 }
 }
 
 
@@ -593,9 +624,10 @@ Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_crea
 	priority=0;
 	priority=0;
 	monitoring=false;
 	monitoring=false;
 	monitorable=false;
 	monitorable=false;
+	collision_mask=1;
+	layer_mask=1;
 	set_enable_monitoring(true);
 	set_enable_monitoring(true);
 	set_monitorable(true);
 	set_monitorable(true);
-
 }
 }
 
 
 Area2D::~Area2D() {
 Area2D::~Area2D() {

+ 8 - 0
scene/2d/area_2d.h

@@ -51,6 +51,8 @@ private:
 	bool gravity_is_point;
 	bool gravity_is_point;
 	real_t linear_damp;
 	real_t linear_damp;
 	real_t angular_damp;
 	real_t angular_damp;
+	uint32_t collision_mask;
+	uint32_t layer_mask;
 	int priority;
 	int priority;
 	bool monitoring;
 	bool monitoring;
 	bool monitorable;
 	bool monitorable;
@@ -151,6 +153,12 @@ public:
 	void set_monitorable(bool p_enable);
 	void set_monitorable(bool p_enable);
 	bool is_monitorable() const;
 	bool is_monitorable() const;
 
 
+	void set_collision_mask(uint32_t p_mask);
+	uint32_t get_collision_mask() const;
+
+	void set_layer_mask(uint32_t p_mask);
+	uint32_t get_layer_mask() const;
+
 	Array get_overlapping_bodies() const; //function for script
 	Array get_overlapping_bodies() const; //function for script
 	Array get_overlapping_areas() const; //function for script
 	Array get_overlapping_areas() const; //function for script
 
 

+ 1 - 2
scene/2d/camera_2d.cpp

@@ -132,8 +132,7 @@ Matrix32 Camera2D::get_camera_transform()  {
 	}
 	}
 
 
 
 
-	Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());;
-	screen_offset;
+	Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());
 
 
 	float angle = get_global_transform().get_rotation();
 	float angle = get_global_transform().get_rotation();
 	if(rotating){
 	if(rotating){

+ 35 - 3
scene/2d/navigation2d.cpp

@@ -32,6 +32,7 @@ void Navigation2D::_navpoly_link(int p_id) {
 		p.edges.resize(plen);
 		p.edges.resize(plen);
 
 
 		Vector2 center;
 		Vector2 center;
+		float sum=0;
 
 
 		for(int j=0;j<plen;j++) {
 		for(int j=0;j<plen;j++) {
 
 
@@ -46,8 +47,23 @@ void Navigation2D::_navpoly_link(int p_id) {
 			center+=ep;
 			center+=ep;
 			e.point=_get_point(ep);
 			e.point=_get_point(ep);
 			p.edges[j]=e;
 			p.edges[j]=e;
+
+
+			int idxn = indices[(j+1)%plen];
+			if (idxn<0 || idxn>=len) {
+				valid=false;
+				break;
+			}
+
+			Vector2 epn = nm.xform.xform(r[idxn]);
+
+			sum+=(epn.x-ep.x)*(epn.y+ep.y);
+
+
 		}
 		}
 
 
+		p.clockwise=sum>0;
+
 		if (!valid) {
 		if (!valid) {
 			nm.polygons.pop_back();
 			nm.polygons.pop_back();
 			ERR_CONTINUE(!valid);
 			ERR_CONTINUE(!valid);
@@ -493,17 +509,30 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 					left = _get_vertex(p->edges[prev].point);
 					left = _get_vertex(p->edges[prev].point);
 					right = _get_vertex(p->edges[prev_n].point);
 					right = _get_vertex(p->edges[prev_n].point);
 
 
-					if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){
+					if (p->clockwise) {
 						SWAP(left,right);
 						SWAP(left,right);
 					}
 					}
+					/*if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5) < 0){
+						SWAP(left,right);
+					}*/
 				}
 				}
 
 
 				bool skip=false;
 				bool skip=false;
 
 
+			/*	print_line("-----\nAPEX: "+(apex_point-end_point));
+				print_line("LEFT:");
+				print_line("\tPortal: "+(portal_left-end_point));
+				print_line("\tPoint: "+(left-end_point));
+				print_line("\tFree: "+itos(CLOCK_TANGENT(apex_point,portal_left,left) >= 0));
+				print_line("RIGHT:");
+				print_line("\tPortal: "+(portal_right-end_point));
+				print_line("\tPoint: "+(right-end_point));
+				print_line("\tFree: "+itos(CLOCK_TANGENT(apex_point,portal_right,right) <= 0));
+*/
 
 
 				if (CLOCK_TANGENT(apex_point,portal_left,left) >= 0){
 				if (CLOCK_TANGENT(apex_point,portal_left,left) >= 0){
 					//process
 					//process
-					if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right) > 0) {
+					if (portal_left.distance_squared_to(apex_point)<CMP_EPSILON || CLOCK_TANGENT(apex_point,left,portal_right) > 0) {
 						left_poly=p;
 						left_poly=p;
 						portal_left=left;
 						portal_left=left;
 					} else {
 					} else {
@@ -519,12 +548,13 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 						if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
 						if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
 							path.push_back(apex_point);
 							path.push_back(apex_point);
 						skip=true;
 						skip=true;
+						//print_line("addpoint left");
 					}
 					}
 				}
 				}
 
 
 				if (!skip && CLOCK_TANGENT(apex_point,portal_right,right) <= 0){
 				if (!skip && CLOCK_TANGENT(apex_point,portal_right,right) <= 0){
 					//process
 					//process
-					if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left) < 0) {
+					if (portal_right.distance_squared_to(apex_point)<CMP_EPSILON || CLOCK_TANGENT(apex_point,right,portal_left) < 0) {
 						right_poly=p;
 						right_poly=p;
 						portal_right=right;
 						portal_right=right;
 					} else {
 					} else {
@@ -539,6 +569,8 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
 						portal_left=apex_point;
 						portal_left=apex_point;
 						if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
 						if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
 							path.push_back(apex_point);
 							path.push_back(apex_point);
+						//print_line("addpoint right");
+
 					}
 					}
 				}
 				}
 
 

+ 2 - 0
scene/2d/navigation2d.h

@@ -60,6 +60,8 @@ class Navigation2D : public Node2D {
 		float distance;
 		float distance;
 		int prev_edge;
 		int prev_edge;
 
 
+		bool clockwise;
+
 		NavMesh *owner;
 		NavMesh *owner;
 	};
 	};
 
 

+ 47 - 1
scene/2d/physics_body_2d.cpp

@@ -68,17 +68,34 @@ float PhysicsBody2D::get_one_way_collision_max_depth() const{
 }
 }
 
 
 
 
+void PhysicsBody2D::_set_layers(uint32_t p_mask) {
+
+	set_layer_mask(p_mask);
+	set_collision_mask(p_mask);
+}
+
+uint32_t PhysicsBody2D::_get_layers() const{
+
+	return get_layer_mask();
+}
+
 void PhysicsBody2D::_bind_methods() {
 void PhysicsBody2D::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody2D::set_layer_mask);
 	ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody2D::set_layer_mask);
 	ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody2D::get_layer_mask);
 	ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody2D::get_layer_mask);
+	ObjectTypeDB::bind_method(_MD("set_collision_mask","mask"),&PhysicsBody2D::set_collision_mask);
+	ObjectTypeDB::bind_method(_MD("get_collision_mask"),&PhysicsBody2D::get_collision_mask);
+	ObjectTypeDB::bind_method(_MD("_set_layers","mask"),&PhysicsBody2D::_set_layers);
+	ObjectTypeDB::bind_method(_MD("_get_layers"),&PhysicsBody2D::_get_layers);
 	ObjectTypeDB::bind_method(_MD("set_one_way_collision_direction","dir"),&PhysicsBody2D::set_one_way_collision_direction);
 	ObjectTypeDB::bind_method(_MD("set_one_way_collision_direction","dir"),&PhysicsBody2D::set_one_way_collision_direction);
 	ObjectTypeDB::bind_method(_MD("get_one_way_collision_direction"),&PhysicsBody2D::get_one_way_collision_direction);
 	ObjectTypeDB::bind_method(_MD("get_one_way_collision_direction"),&PhysicsBody2D::get_one_way_collision_direction);
 	ObjectTypeDB::bind_method(_MD("set_one_way_collision_max_depth","depth"),&PhysicsBody2D::set_one_way_collision_max_depth);
 	ObjectTypeDB::bind_method(_MD("set_one_way_collision_max_depth","depth"),&PhysicsBody2D::set_one_way_collision_max_depth);
 	ObjectTypeDB::bind_method(_MD("get_one_way_collision_max_depth"),&PhysicsBody2D::get_one_way_collision_max_depth);
 	ObjectTypeDB::bind_method(_MD("get_one_way_collision_max_depth"),&PhysicsBody2D::get_one_way_collision_max_depth);
 	ObjectTypeDB::bind_method(_MD("add_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::add_collision_exception_with);
 	ObjectTypeDB::bind_method(_MD("add_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::add_collision_exception_with);
 	ObjectTypeDB::bind_method(_MD("remove_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::remove_collision_exception_with);
 	ObjectTypeDB::bind_method(_MD("remove_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::remove_collision_exception_with);
-	ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS,"",0),_SCS("_set_layers"),_SCS("_get_layers")); //for backwards compat
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
 	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"one_way_collision/direction"),_SCS("set_one_way_collision_direction"),_SCS("get_one_way_collision_direction"));
 	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"one_way_collision/direction"),_SCS("set_one_way_collision_direction"),_SCS("get_one_way_collision_direction"));
 	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"one_way_collision/max_depth"),_SCS("set_one_way_collision_max_depth"),_SCS("get_one_way_collision_max_depth"));
 	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"one_way_collision/max_depth"),_SCS("set_one_way_collision_max_depth"),_SCS("get_one_way_collision_max_depth"));
 }
 }
@@ -94,9 +111,22 @@ uint32_t PhysicsBody2D::get_layer_mask() const {
 	return mask;
 	return mask;
 }
 }
 
 
+void PhysicsBody2D::set_collision_mask(uint32_t p_mask) {
+
+	collision_mask=p_mask;
+	Physics2DServer::get_singleton()->body_set_collision_mask(get_rid(),p_mask);
+}
+
+uint32_t PhysicsBody2D::get_collision_mask() const {
+
+	return collision_mask;
+}
+
+
 PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) {
 PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) {
 
 
 	mask=1;
 	mask=1;
+	collision_mask=1;
 	set_one_way_collision_max_depth(0);
 	set_one_way_collision_max_depth(0);
 	set_pickable(false);
 	set_pickable(false);
 
 
@@ -909,6 +939,19 @@ Variant KinematicBody2D::_get_collider() const {
 	return obj;
 	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) {
 Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 
 
@@ -926,6 +969,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 	Matrix32 gt = get_global_transform();
 	Matrix32 gt = get_global_transform();
 	gt.elements[2]+=result.motion;
 	gt.elements[2]+=result.motion;
 	set_global_transform(gt);
 	set_global_transform(gt);
+	travel=result.motion;
 	return result.remainder;
 	return result.remainder;
 
 
 #else
 #else
@@ -1157,6 +1201,8 @@ void KinematicBody2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody2D::move_to);
 	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("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);
 	ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody2D::is_colliding);
 
 

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

@@ -39,8 +39,14 @@ class PhysicsBody2D : public CollisionObject2D {
 	OBJ_TYPE(PhysicsBody2D,CollisionObject2D);
 	OBJ_TYPE(PhysicsBody2D,CollisionObject2D);
 
 
 	uint32_t mask;
 	uint32_t mask;
+	uint32_t collision_mask;
 	Vector2 one_way_collision_direction;
 	Vector2 one_way_collision_direction;
 	float one_way_collision_max_depth;
 	float one_way_collision_max_depth;
+
+
+	void _set_layers(uint32_t p_mask);
+	uint32_t _get_layers() const;
+
 protected:
 protected:
 
 
 	void _notification(int p_what);
 	void _notification(int p_what);
@@ -52,6 +58,9 @@ public:
 	void set_layer_mask(uint32_t p_mask);
 	void set_layer_mask(uint32_t p_mask);
 	uint32_t get_layer_mask() const;
 	uint32_t get_layer_mask() const;
 
 
+	void set_collision_mask(uint32_t p_mask);
+	uint32_t get_collision_mask() const;
+
 	void add_collision_exception_with(Node* p_node); //must be physicsbody
 	void add_collision_exception_with(Node* p_node); //must be physicsbody
 	void remove_collision_exception_with(Node* p_node);
 	void remove_collision_exception_with(Node* p_node);
 
 
@@ -276,6 +285,7 @@ class KinematicBody2D : public PhysicsBody2D {
 	ObjectID collider;
 	ObjectID collider;
 	int collider_shape;
 	int collider_shape;
 	Variant collider_metadata;
 	Variant collider_metadata;
+	Vector2 travel;
 
 
 	Variant _get_collider() const;
 	Variant _get_collider() const;
 
 
@@ -290,6 +300,10 @@ public:
 
 
 	bool test_move(const Vector2& p_motion);
 	bool test_move(const Vector2& p_motion);
 	bool is_colliding() const;
 	bool is_colliding() const;
+
+	Vector2 get_travel() const;
+	void revert_motion();
+
 	Vector2 get_collision_pos() const;
 	Vector2 get_collision_pos() const;
 	Vector2 get_collision_normal() const;
 	Vector2 get_collision_normal() const;
 	Vector2 get_collider_velocity() const;
 	Vector2 get_collider_velocity() const;

+ 27 - 5
scene/2d/tile_map.cpp

@@ -519,6 +519,7 @@ Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const
 	q.body=Physics2DServer::get_singleton()->body_create(use_kinematic?Physics2DServer::BODY_MODE_KINEMATIC:Physics2DServer::BODY_MODE_STATIC);
 	q.body=Physics2DServer::get_singleton()->body_create(use_kinematic?Physics2DServer::BODY_MODE_KINEMATIC:Physics2DServer::BODY_MODE_STATIC);
 	Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body,get_instance_ID());
 	Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body,get_instance_ID());
 	Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer);
 	Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer);
+	Physics2DServer::get_singleton()->body_set_collision_mask(q.body,collision_mask);
 	Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,friction);
 	Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,friction);
 	Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,bounce);
 	Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,bounce);
 
 
@@ -790,7 +791,7 @@ Rect2 TileMap::get_item_rect() const {
 	return rect_cache;
 	return rect_cache;
 }
 }
 
 
-void TileMap::set_collision_layer_mask(uint32_t p_layer) {
+void TileMap::set_collision_layer(uint32_t p_layer) {
 
 
 	collision_layer=p_layer;
 	collision_layer=p_layer;
 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
 	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
@@ -800,6 +801,16 @@ void TileMap::set_collision_layer_mask(uint32_t p_layer) {
 	}
 	}
 }
 }
 
 
+void TileMap::set_collision_mask(uint32_t p_mask) {
+
+	collision_mask=p_mask;
+	for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
+
+		Quadrant &q=E->get();
+		Physics2DServer::get_singleton()->body_set_collision_mask(q.body,collision_mask);
+	}
+}
+
 bool TileMap::get_collision_use_kinematic() const{
 bool TileMap::get_collision_use_kinematic() const{
 
 
 	return use_kinematic;
 	return use_kinematic;
@@ -844,11 +855,16 @@ float TileMap::get_collision_bounce() const{
 }
 }
 
 
 
 
-uint32_t TileMap::get_collision_layer_mask() const {
+uint32_t TileMap::get_collision_layer() const {
 
 
 	return collision_layer;
 	return collision_layer;
 }
 }
 
 
+uint32_t TileMap::get_collision_mask() const {
+
+	return collision_mask;
+}
+
 void TileMap::set_mode(Mode p_mode) {
 void TileMap::set_mode(Mode p_mode) {
 
 
 	_clear_quadrants();
 	_clear_quadrants();
@@ -1077,8 +1093,11 @@ void TileMap::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_collision_use_kinematic","use_kinematic"),&TileMap::set_collision_use_kinematic);
 	ObjectTypeDB::bind_method(_MD("set_collision_use_kinematic","use_kinematic"),&TileMap::set_collision_use_kinematic);
 	ObjectTypeDB::bind_method(_MD("get_collision_use_kinematic"),&TileMap::get_collision_use_kinematic);
 	ObjectTypeDB::bind_method(_MD("get_collision_use_kinematic"),&TileMap::get_collision_use_kinematic);
 
 
-	ObjectTypeDB::bind_method(_MD("set_collision_layer_mask","mask"),&TileMap::set_collision_layer_mask);
-	ObjectTypeDB::bind_method(_MD("get_collision_layer_mask"),&TileMap::get_collision_layer_mask);
+	ObjectTypeDB::bind_method(_MD("set_collision_layer","mask"),&TileMap::set_collision_layer);
+	ObjectTypeDB::bind_method(_MD("get_collision_layer"),&TileMap::get_collision_layer);
+
+	ObjectTypeDB::bind_method(_MD("set_collision_mask","mask"),&TileMap::set_collision_mask);
+	ObjectTypeDB::bind_method(_MD("get_collision_mask"),&TileMap::get_collision_mask);
 
 
 	ObjectTypeDB::bind_method(_MD("set_collision_friction","value"),&TileMap::set_collision_friction);
 	ObjectTypeDB::bind_method(_MD("set_collision_friction","value"),&TileMap::set_collision_friction);
 	ObjectTypeDB::bind_method(_MD("get_collision_friction"),&TileMap::get_collision_friction);
 	ObjectTypeDB::bind_method(_MD("get_collision_friction"),&TileMap::get_collision_friction);
@@ -1117,7 +1136,9 @@ void TileMap::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collision/use_kinematic",PROPERTY_HINT_NONE,""),_SCS("set_collision_use_kinematic"),_SCS("get_collision_use_kinematic"));
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"collision/use_kinematic",PROPERTY_HINT_NONE,""),_SCS("set_collision_use_kinematic"),_SCS("get_collision_use_kinematic"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_bounce"),_SCS("get_collision_bounce"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_bounce"),_SCS("get_collision_bounce"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_layer_mask"),_SCS("get_collision_layer_mask"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_layer"),_SCS("get_collision_layer"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
+
 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data"));
 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data"));
 
 
 	ADD_SIGNAL(MethodInfo("settings_changed"));
 	ADD_SIGNAL(MethodInfo("settings_changed"));
@@ -1146,6 +1167,7 @@ TileMap::TileMap() {
 	center_x=false;
 	center_x=false;
 	center_y=false;
 	center_y=false;
 	collision_layer=1;
 	collision_layer=1;
+	collision_mask=1;
 	friction=1;
 	friction=1;
 	bounce=0;
 	bounce=0;
 	mode=MODE_SQUARE;
 	mode=MODE_SQUARE;

+ 7 - 2
scene/2d/tile_map.h

@@ -146,6 +146,8 @@ private:
 	float friction;
 	float friction;
 	float bounce;
 	float bounce;
 	uint32_t collision_layer;
 	uint32_t collision_layer;
+	uint32_t collision_mask;
+
 	TileOrigin tile_origin;
 	TileOrigin tile_origin;
 
 
 	void _fix_cell_transform(Matrix32& xform, const Cell& p_cell, const Vector2 &p_offset, const Size2 &p_sc);
 	void _fix_cell_transform(Matrix32& xform, const Cell& p_cell, const Vector2 &p_offset, const Size2 &p_sc);
@@ -207,8 +209,11 @@ public:
 
 
 	Rect2 get_item_rect() const;
 	Rect2 get_item_rect() const;
 
 
-	void set_collision_layer_mask(uint32_t p_layer);
-	uint32_t get_collision_layer_mask() const;
+	void set_collision_layer(uint32_t p_layer);
+	uint32_t get_collision_layer() const;
+
+	void set_collision_mask(uint32_t p_mask);
+	uint32_t get_collision_mask() const;
 
 
 	void set_collision_use_kinematic(bool p_use_kinematic);
 	void set_collision_use_kinematic(bool p_use_kinematic);
 	bool get_collision_use_kinematic() const;
 	bool get_collision_use_kinematic() const;

+ 14 - 1
scene/3d/navigation.cpp

@@ -30,6 +30,7 @@ void Navigation::_navmesh_link(int p_id) {
 		p.edges.resize(plen);
 		p.edges.resize(plen);
 
 
 		Vector3 center;
 		Vector3 center;
+		float sum=0;
 
 
 		for(int j=0;j<plen;j++) {
 		for(int j=0;j<plen;j++) {
 
 
@@ -44,8 +45,19 @@ void Navigation::_navmesh_link(int p_id) {
 			center+=ep;
 			center+=ep;
 			e.point=_get_point(ep);
 			e.point=_get_point(ep);
 			p.edges[j]=e;
 			p.edges[j]=e;
+
+			if (j>=2) {
+				Vector3 epa = nm.xform.xform(r[indices[j-2]]);
+				Vector3 epb = nm.xform.xform(r[indices[j-1]]);
+
+				sum+=up.dot((epb-epa).cross(ep-epa));
+
+			}
+
 		}
 		}
 
 
+		p.clockwise=sum>0;
+
 		if (!valid) {
 		if (!valid) {
 			nm.polygons.pop_back();
 			nm.polygons.pop_back();
 			ERR_CONTINUE(!valid);
 			ERR_CONTINUE(!valid);
@@ -399,7 +411,8 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector
 					left = _get_vertex(p->edges[prev].point);
 					left = _get_vertex(p->edges[prev].point);
 					right = _get_vertex(p->edges[prev_n].point);
 					right = _get_vertex(p->edges[prev_n].point);
 
 
-					if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){
+					//if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){
+					if (p->clockwise) {
 						SWAP(left,right);
 						SWAP(left,right);
 					}
 					}
 				}
 				}

+ 2 - 0
scene/3d/navigation.h

@@ -59,6 +59,8 @@ class Navigation : public Spatial {
 
 
 		float distance;
 		float distance;
 		int prev_edge;
 		int prev_edge;
+		bool clockwise;
+
 
 
 		NavMesh *owner;
 		NavMesh *owner;
 	};
 	};

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

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

+ 205 - 11
scene/animation/tween.cpp

@@ -29,6 +29,81 @@
 #include "tween.h"
 #include "tween.h"
 #include "method_bind_ext.inc"
 #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) {
 bool Tween::_set(const StringName& p_name, const Variant& p_value) {
 
 
 	String name=p_name;
 	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) {
 void Tween::_tween_process(float p_delta) {
 
 
+	_process_pending_commands();
+
 	if (speed_scale == 0)
 	if (speed_scale == 0)
 		return;
 		return;
 	p_delta *= speed_scale;
 	p_delta *= speed_scale;
@@ -551,8 +628,12 @@ void Tween::_tween_process(float p_delta) {
 
 
 		_apply_tween_value(data, result);
 		_apply_tween_value(data, result);
 
 
-		if(data.finish)
+		if (data.finish) {
 			emit_signal("tween_complete",object,data.key);
 			emit_signal("tween_complete",object,data.key);
+			// not repeat mode, remove completed action
+			if (!repeat)
+				call_deferred("remove", object, data.key);
+		}
 	}
 	}
 	pending_update --;
 	pending_update --;
 }
 }
@@ -734,7 +815,10 @@ bool Tween::resume_all() {
 
 
 bool Tween::remove(Object *p_object, String p_key) {
 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()) {
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 
 		InterpolateData& data = E->get();
 		InterpolateData& data = E->get();
@@ -751,7 +835,10 @@ bool Tween::remove(Object *p_object, String p_key) {
 
 
 bool Tween::remove_all() {
 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_active(false);
 	_set_process(false);
 	_set_process(false);
 	interpolates.clear();
 	interpolates.clear();
@@ -940,7 +1027,19 @@ bool Tween::interpolate_property(Object *p_object
 	, EaseType p_ease_type
 	, EaseType p_ease_type
 	, real_t p_delay
 	, 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
 	// 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_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();
 	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
 	, EaseType p_ease_type
 	, real_t p_delay
 	, 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
 	// 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_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();
 	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_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, 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_FAIL_COND_V(!p_object->has_method(p_method), false);
 
 
 	InterpolateData data;
 	InterpolateData data;
@@ -1029,10 +1141,23 @@ bool Tween::interpolate_callback(Object *p_object
 	, VARIANT_ARG_DECLARE
 	, 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_object == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec < 0, 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);
 	ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
 
 
 	InterpolateData data;
 	InterpolateData data;
@@ -1080,10 +1205,23 @@ bool Tween::interpolate_deferred_callback(Object *p_object
 	, VARIANT_ARG_DECLARE
 	, 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_object == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec < 0, 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);
 	ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
 
 
 	InterpolateData data;
 	InterpolateData data;
@@ -1135,7 +1273,20 @@ bool Tween::follow_property(Object *p_object
 	, EaseType p_ease_type
 	, EaseType p_ease_type
 	, real_t p_delay
 	, 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
 	// 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_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
 	, EaseType p_ease_type
 	, real_t p_delay
 	, 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
 	// 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_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_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, 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_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);
 	ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false);
 
 
 	Variant::CallError error;
 	Variant::CallError error;
@@ -1240,7 +1406,20 @@ bool Tween::targeting_property(Object *p_object
 	, EaseType p_ease_type
 	, EaseType p_ease_type
 	, real_t p_delay
 	, 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
 	// 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();
 	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
 	, EaseType p_ease_type
 	, real_t p_delay
 	, 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
 	// 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();
 	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_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, 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_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);
 	ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false);
 
 
 	Variant::CallError error;
 	Variant::CallError error;

+ 21 - 0
scene/animation/tween.h

@@ -110,6 +110,27 @@ private:
 
 
 	List<InterpolateData> interpolates;
 	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);
 	typedef real_t (*interpolater)(real_t t, real_t b, real_t c, real_t d);
 	static interpolater interpolaters[TRANS_COUNT][EASE_COUNT];
 	static interpolater interpolaters[TRANS_COUNT][EASE_COUNT];
 
 

+ 6 - 6
scene/animation/tween_interpolaters.cpp

@@ -285,18 +285,18 @@ namespace cubic {
 namespace circ {
 namespace circ {
 	static real_t in(real_t t, real_t b, real_t c, real_t d)
 	static real_t in(real_t t, real_t b, real_t c, real_t d)
 	{
 	{
-		return -c * (sqrt(1 - (t /= d) * t) - 1) + b;
+		return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined
 	}
 	}
 
 
 	static real_t out(real_t t, real_t b, real_t c, real_t d)
 	static real_t out(real_t t, real_t b, real_t c, real_t d)
 	{
 	{
-		return c * sqrt(1 - (t = t / d - 1) * t) + b;
+		return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined
 	}
 	}
 
 
 	static real_t in_out(real_t t, real_t b, real_t c, real_t d)
 	static real_t in_out(real_t t, real_t b, real_t c, real_t d)
 	{
 	{
 		if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
 		if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b;
-		return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b;
+		return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined
 	}
 	}
 
 
 	static real_t out_in(real_t t, real_t b, real_t c, real_t d)
 	static real_t out_in(real_t t, real_t b, real_t c, real_t d)
@@ -364,15 +364,15 @@ namespace back {
 	static real_t out(real_t t, real_t b, real_t c, real_t d)
 	static real_t out(real_t t, real_t b, real_t c, real_t d)
 	{
 	{
         float s = 1.70158f;
         float s = 1.70158f;
-        return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b;
+        return c * ((t = t / d- 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined
 	}
 	}
 
 
 	static real_t in_out(real_t t, real_t b, real_t c, real_t d)
 	static real_t in_out(real_t t, real_t b, real_t c, real_t d)
 	{
 	{
 		float s = 1.70158f;
 		float s = 1.70158f;
-		if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b;
+		if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined
 		float postFix = t -= 2;
 		float postFix = t -= 2;
-		return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b;
+		return c / 2 * ((postFix) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined
 	}
 	}
 
 
 	static real_t out_in(real_t t, real_t b, real_t c, real_t d)
 	static real_t out_in(real_t t, real_t b, real_t c, real_t d)

+ 2 - 0
scene/gui/button.cpp

@@ -115,6 +115,8 @@ void Button::_notification(int p_what) {
 				text_ofs.y+=style->get_offset().y;
 				text_ofs.y+=style->get_offset().y;
 			} break;
 			} break;
 			case ALIGN_CENTER: {
 			case ALIGN_CENTER: {
+				if (text_ofs.x<0)
+					text_ofs.x=0;
 				text_ofs+=icon_ofs;
 				text_ofs+=icon_ofs;
 				text_ofs+=style->get_offset();
 				text_ofs+=style->get_offset();
 			} break;
 			} break;

+ 1 - 1
scene/gui/check_box.cpp

@@ -59,7 +59,7 @@ bool CheckBox::is_radio()
     Node* parent = this;
     Node* parent = this;
     do {
     do {
         parent = parent->get_parent();
         parent = parent->get_parent();
-        if (dynamic_cast< ButtonGroup* >(parent))
+	if (parent->cast_to<ButtonGroup>())
             break;
             break;
     } while (parent);
     } while (parent);
 
 

+ 0 - 1
scene/gui/file_dialog.cpp

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

+ 56 - 32
scene/gui/label.cpp

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

+ 2 - 1
scene/gui/label.h

@@ -75,8 +75,9 @@ private:
 		int char_pos; // if -1, then newline
 		int char_pos; // if -1, then newline
 		int word_len;
 		int word_len;
 		int pixel_width;
 		int pixel_width;
+		int space_count;
 		WordCache *next;
 		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;
 	bool word_cache_dirty;

+ 1 - 1
scene/gui/line_edit.cpp

@@ -272,7 +272,7 @@ void LineEdit::_input_event(InputEvent p_event) {
 
 
 							if (editable) {
 							if (editable) {
 								selection_delete();
 								selection_delete();
-								CharType ucodestr[2]={k.unicode,0};
+								CharType ucodestr[2]={(CharType)k.unicode,0};
 								append_at_cursor(ucodestr);
 								append_at_cursor(ucodestr);
 								emit_signal("text_changed",text);
 								emit_signal("text_changed",text);
 								_change_notify("text");
 								_change_notify("text");

+ 13 - 1
scene/gui/rich_text_label.cpp

@@ -235,6 +235,9 @@ if (m_height > line_height) {\
 					while (c[end]!=0 && !(end && c[end-1]==' ' && c[end]!=' ')) {
 					while (c[end]!=0 && !(end && c[end-1]==' ' && c[end]!=' ')) {
 
 
 						int cw = font->get_char_size(c[end],c[end+1]).width;
 						int cw = font->get_char_size(c[end],c[end+1]).width;
+						if (c[end]=='\t') {
+							cw=tab_size*font->get_char_size(' ').width;
+						}
 						w+=cw;
 						w+=cw;
 
 
 						if (c[end]==' ') {
 						if (c[end]==' ') {
@@ -268,7 +271,9 @@ if (m_height > line_height) {\
 						}
 						}
 
 
 						if (found_space) {
 						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];
 						}
 						}
 
 
 					}
 					}
@@ -290,6 +295,9 @@ if (m_height > line_height) {\
 
 
 
 
 								int cw=font->get_char_size(c[i],c[i+1]).x;
 								int cw=font->get_char_size(c[i],c[i+1]).x;
+								if (c[i]=='\t') {
+									cw=tab_size*font->get_char_size(' ').width;
+								}
 
 
 								if (p_click_pos.x-cw/2>pofs) {
 								if (p_click_pos.x-cw/2>pofs) {
 
 
@@ -330,6 +338,10 @@ if (m_height > line_height) {\
 									cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
 									cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
 								}
 								}
 
 
+								if (c[i]=='\t') {
+									cw=tab_size*font->get_char_size(' ').width;
+								}
+
 
 
 								//print_line("draw char: "+String::chr(c[i]));
 								//print_line("draw char: "+String::chr(c[i]));
 
 

+ 8 - 5
scene/gui/text_edit.cpp

@@ -489,7 +489,7 @@ void TextEdit::_notification(int p_what) {
 								
 								
 								CharType cc = text[i][j];
 								CharType cc = text[i][j];
 								//ignore any brackets inside a string
 								//ignore any brackets inside a string
-								if (cc== '"' | cc == '\'') {
+								if (cc== '"' || cc == '\'') {
 									CharType quotation = cc;
 									CharType quotation = cc;
 									do {
 									do {
 										j++;
 										j++;
@@ -560,7 +560,7 @@ void TextEdit::_notification(int p_what) {
 								
 								
 								CharType cc = text[i][j];
 								CharType cc = text[i][j];
 								//ignore any brackets inside a string
 								//ignore any brackets inside a string
-								if (cc== '"' | cc == '\'') {
+								if (cc== '"' || cc == '\'') {
 									CharType quotation = cc;
 									CharType quotation = cc;
 									do {
 									do {
 										j--;
 										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
 						//tripleclick select line
 						select(cursor.line,0,cursor.line,text[cursor.line].length());
 						select(cursor.line,0,cursor.line,text[cursor.line].length());
 						last_dblclk=0;
 						last_dblclk=0;
@@ -1440,7 +1440,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
 							
 							
 						} else {
 						} else {
 							//different char, go back
 							//different char, go back
-							const CharType chr[2] = {k.unicode, 0};
+							const CharType chr[2] = {(CharType)k.unicode, 0};
 							if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
 							if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
 								_consume_pair_symbol(chr[0]);
 								_consume_pair_symbol(chr[0]);
 							} else {
 							} else {
@@ -2062,7 +2062,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
 					if (readonly)
 					if (readonly)
 						break;
 						break;
 					
 					
-					const CharType chr[2] = {k.unicode, 0};
+					const CharType chr[2] = {(CharType)k.unicode, 0};
 					
 					
 					if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
 					if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
 						_consume_pair_symbol(chr[0]);
 						_consume_pair_symbol(chr[0]);
@@ -3494,6 +3494,9 @@ void TextEdit::set_line(int line, String new_text)
 		return;
 		return;
 	_remove_text(line, 0, line, text[line].length());
 	_remove_text(line, 0, line, text[line].length());
 	_insert_text(line, 0, new_text);
 	_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)
 void TextEdit::insert_at(const String &p_text, int at)

+ 36 - 0
scene/main/node.cpp

@@ -1417,6 +1417,41 @@ void Node::_duplicate_and_reown(Node* p_new_parent, const Map<Node*,Node*>& p_re
 
 
 }
 }
 
 
+
+void Node::_duplicate_signals(const Node* p_original,Node* p_copy) const {
+
+	if (this!=p_original && get_owner()!=p_original)
+		return;
+
+	List<Connection> conns;
+	get_all_signal_connections(&conns);
+
+	for (List<Connection>::Element *E=conns.front();E;E=E->next()) {
+
+		if (E->get().flags&CONNECT_PERSIST) {
+			//user connected
+			NodePath p = p_original->get_path_to(this);
+			Node *copy = p_copy->get_node(p);
+
+			Node *target = E->get().target->cast_to<Node>();
+			if (!target)
+				continue;
+			NodePath ptarget = p_original->get_path_to(target);
+			Node *copytarget = p_copy->get_node(ptarget);
+
+			if (copy && copytarget) {
+				copy->connect(E->get().signal,copytarget,E->get().method,E->get().binds,CONNECT_PERSIST);
+			}
+		}
+	}
+
+	for(int i=0;i<get_child_count();i++) {
+		get_child(i)->_duplicate_signals(p_original,p_copy);
+	}
+
+}
+
+
 Node *Node::duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const {
 Node *Node::duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const {
 
 
 
 
@@ -1455,6 +1490,7 @@ Node *Node::duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const {
 		get_child(i)->_duplicate_and_reown(node,p_reown_map);
 		get_child(i)->_duplicate_and_reown(node,p_reown_map);
 	}
 	}
 
 
+	_duplicate_signals(this,node);
 	return node;
 	return node;
 
 
 }
 }

+ 2 - 0
scene/main/node.h

@@ -126,6 +126,7 @@ private:
 	void _propagate_pause_owner(Node*p_owner);
 	void _propagate_pause_owner(Node*p_owner);
 	Array _get_node_and_resource(const NodePath& p_path);
 	Array _get_node_and_resource(const NodePath& p_path);
 
 
+	void _duplicate_signals(const Node* p_original,Node* p_copy) const;
 	void _duplicate_and_reown(Node* p_new_parent, const Map<Node*,Node*>& p_reown_map) const;
 	void _duplicate_and_reown(Node* p_new_parent, const Map<Node*,Node*>& p_reown_map) const;
 	Array _get_children() const;
 	Array _get_children() const;
 	Array _get_groups() const;
 	Array _get_groups() const;
@@ -170,6 +171,7 @@ public:
 		NOTIFICATION_PROCESS = 17,
 		NOTIFICATION_PROCESS = 17,
 		NOTIFICATION_PARENTED=18,
 		NOTIFICATION_PARENTED=18,
 		NOTIFICATION_UNPARENTED=19,
 		NOTIFICATION_UNPARENTED=19,
+		NOTIFICATION_INSTANCED=20,
 	};
 	};
 			
 			
 	/* NODE/TREE */			
 	/* NODE/TREE */			

+ 60 - 9
scene/main/timer.cpp

@@ -45,14 +45,14 @@ void Timer::_notification(int p_what) {
 			}
 			}
 		} break;
 		} break;
 		case NOTIFICATION_PROCESS: {
 		case NOTIFICATION_PROCESS: {
-
-			if (!is_processing())
+			if (timer_process_mode == TIMER_PROCESS_FIXED || !is_processing())
 				return;
 				return;
 			time_left -= get_process_delta_time();
 			time_left -= get_process_delta_time();
 
 
 			if (time_left<0) {
 			if (time_left<0) {
 				if (!one_shot)
 				if (!one_shot)
-					time_left=wait_time+time_left;
+					//time_left=wait_time+time_left;
+					time_left = wait_time;
 				else
 				else
 					stop();
 					stop();
 
 
@@ -60,13 +60,27 @@ void Timer::_notification(int p_what) {
 			}
 			}
 
 
 		} break;
 		} break;
+		case NOTIFICATION_FIXED_PROCESS: {
+			if (timer_process_mode == TIMER_PROCESS_IDLE || !is_fixed_processing())
+				return;
+			time_left -= get_fixed_process_delta_time();
+
+			if (time_left<0) {
+				if (!one_shot)
+					//time_left = wait_time + time_left;
+					time_left = wait_time;
+				else
+					stop();
+				emit_signal("timeout");
+			}
+
+		} break;
 	}
 	}
 }
 }
 
 
 
 
 
 
 void Timer::set_wait_time(float p_time) {
 void Timer::set_wait_time(float p_time) {
-
 	ERR_EXPLAIN("time should be greater than zero.");
 	ERR_EXPLAIN("time should be greater than zero.");
 	ERR_FAIL_COND(p_time<=0);
 	ERR_FAIL_COND(p_time<=0);
 	wait_time=p_time;
 	wait_time=p_time;
@@ -96,14 +110,13 @@ bool Timer::has_autostart() const {
 }
 }
 
 
 void Timer::start() {
 void Timer::start() {
-
 	time_left=wait_time;	
 	time_left=wait_time;	
-	set_process(true);	
+	_set_process(true);
 }
 }
 
 
 void Timer::stop() {
 void Timer::stop() {
 	time_left=-1;
 	time_left=-1;
-	set_process(false);
+	_set_process(false);
 	autostart=false;
 	autostart=false;
 }
 }
 
 
@@ -112,6 +125,41 @@ float Timer::get_time_left() const {
 	return time_left >0 ? time_left : 0;
 	return time_left >0 ? time_left : 0;
 }
 }
 
 
+void Timer::set_timer_process_mode(TimerProcessMode p_mode) {
+
+	if (timer_process_mode == p_mode)
+		return;
+
+	switch (timer_process_mode) {
+		case TIMER_PROCESS_FIXED:
+			if (is_fixed_processing()) {
+				set_fixed_process(false);
+				set_process(true);
+			}
+		break;
+		case TIMER_PROCESS_IDLE:
+			if (is_processing()) {
+				set_process(false);
+				set_fixed_process(true);
+			}
+		break;
+	}
+	timer_process_mode = p_mode;
+}
+
+Timer::TimerProcessMode Timer::get_timer_process_mode() const{
+
+	return timer_process_mode;
+}
+
+
+void Timer::_set_process(bool p_process, bool p_force) 
+{
+	switch (timer_process_mode) {
+		case TIMER_PROCESS_FIXED: set_fixed_process(p_process); break;
+		case TIMER_PROCESS_IDLE: set_process(p_process); break;
+	}
+}
 
 
 void Timer::_bind_methods() {
 void Timer::_bind_methods() {
 
 
@@ -129,8 +177,12 @@ void Timer::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("get_time_left"),&Timer::get_time_left);
 	ObjectTypeDB::bind_method(_MD("get_time_left"),&Timer::get_time_left);
 
 
+	ObjectTypeDB::bind_method(_MD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode);
+	ObjectTypeDB::bind_method(_MD("get_timer_process_mode"), &Timer::get_timer_process_mode);
+
 	ADD_SIGNAL( MethodInfo("timeout") );
 	ADD_SIGNAL( MethodInfo("timeout") );
 
 
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_timer_process_mode"), _SCS("get_timer_process_mode"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.01,4096,0.01" ), _SCS("set_wait_time"), _SCS("get_wait_time") );
 	ADD_PROPERTY( PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.01,4096,0.01" ), _SCS("set_wait_time"), _SCS("get_wait_time") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL, "one_shot" ), _SCS("set_one_shot"), _SCS("is_one_shot") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL, "one_shot" ), _SCS("set_one_shot"), _SCS("is_one_shot") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL, "autostart" ), _SCS("set_autostart"), _SCS("has_autostart") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL, "autostart" ), _SCS("set_autostart"), _SCS("has_autostart") );
@@ -138,8 +190,7 @@ void Timer::_bind_methods() {
 }
 }
 
 
 Timer::Timer() {
 Timer::Timer() {
-
-
+	timer_process_mode = TIMER_PROCESS_IDLE;
 	autostart=false;
 	autostart=false;
 	wait_time=1;
 	wait_time=1;
 	one_shot=false;
 	one_shot=false;

+ 14 - 0
scene/main/timer.h

@@ -46,6 +46,11 @@ protected:
 	static void _bind_methods();
 	static void _bind_methods();
 public:
 public:
 
 
+	enum TimerProcessMode {
+		TIMER_PROCESS_FIXED,
+		TIMER_PROCESS_IDLE,
+	};
+
 	void set_wait_time(float p_time);
 	void set_wait_time(float p_time);
 	float get_wait_time() const;
 	float get_wait_time() const;
 
 
@@ -60,7 +65,16 @@ public:
 
 
 	float get_time_left() const;
 	float get_time_left() const;
 
 
+	void set_timer_process_mode(TimerProcessMode p_mode);
+	TimerProcessMode get_timer_process_mode() const;
 	Timer();
 	Timer();
+
+private:
+	TimerProcessMode timer_process_mode;
+	void _set_process(bool p_process, bool p_force = false);
+
 };
 };
 
 
+VARIANT_ENUM_CAST(Timer::TimerProcessMode);
+
 #endif // TIMER_H
 #endif // TIMER_H

+ 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)
 	if (p_ok)
 		*p_ok=true;
 		*p_ok=true;
-	
-	int next;
+
+	int next=0;
 	float c=0;	
 	float c=0;	
 	// prepare for all cases of interpolation
 	// 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)
 	if (get_path()!="" && get_path().find("::")==-1)
 		s->set_filename(get_path());
 		s->set_filename(get_path());
+
+	s->notification(Node::NOTIFICATION_INSTANCED);
 	return ret_nodes[0];
 	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($)",
 				"floor($)",
 				"round($)",
 				"round($)",
 				"ceil($)",
 				"ceil($)",
-				"frac($)",
+				"fract($)",
 				"min(max($,0),1)",
 				"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;
 			String name = p_node->param1;
 			Vector3 dv=p_node->param2;
 			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";
 			code += OUTNAME(p_node->id,0)+"="+name+";\n";
 		}break;
 		}break;
 		case NODE_RGB_INPUT: {
 		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 {
 void Theme::_get_property_list( List<PropertyInfo> *p_list) const {
 	
 	
+
+	List<PropertyInfo> list;
+
 	const StringName *key=NULL;
 	const StringName *key=NULL;
 	
 	
 	while((key=icon_map.next(key))) {
 	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))) {
 		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))) {
 		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))) {
 		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))) {
 		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))) {
 		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());
+	}
 	
 	
 }
 }
 
 

+ 3 - 1
servers/physics/collision_object_sw.h

@@ -34,8 +34,10 @@
 #include "self_list.h"
 #include "self_list.h"
 #include "broad_phase_sw.h"
 #include "broad_phase_sw.h"
 
 
-#define MAX_OBJECT_DISTANCE 10000000
+#ifdef DEBUG_ENABLED
+#define MAX_OBJECT_DISTANCE 10000000.0
 #define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE*MAX_OBJECT_DISTANCE)
 #define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE*MAX_OBJECT_DISTANCE)
+#endif
 
 
 class SpaceSW;
 class SpaceSW;
 
 

+ 1 - 1
servers/physics/physics_server_sw.cpp

@@ -551,7 +551,7 @@ bool PhysicsServerSW::body_is_shape_set_as_trigger(RID p_body, int p_shape_idx)
 	ERR_FAIL_COND_V(!body,false);
 	ERR_FAIL_COND_V(!body,false);
 	ERR_FAIL_INDEX_V(p_shape_idx,body->get_shape_count(),false);
 	ERR_FAIL_INDEX_V(p_shape_idx,body->get_shape_count(),false);
 
 
-	body->is_shape_set_as_trigger(p_shape_idx);
+	return body->is_shape_set_as_trigger(p_shape_idx);
 }
 }
 
 
 
 

部分文件因文件數量過多而無法顯示