Prechádzať zdrojové kódy

Merge remote-tracking branch 'upstream/master'

Kostadin Damyanov 10 rokov pred
rodič
commit
cdf1ac7d58
100 zmenil súbory, kde vykonal 3390 pridanie a 2072 odobranie
  1. 7 4
      SConstruct
  2. 9 13
      bin/tests/test_string.cpp
  3. 106 0
      core/bind/core_bind.cpp
  4. 22 0
      core/bind/core_bind.h
  5. 10 1
      core/globals.cpp
  6. 1 0
      core/globals.h
  7. 4 4
      core/image.cpp
  8. 3 1
      core/io/file_access_encrypted.cpp
  9. 1 1
      core/io/http_client.cpp
  10. 1 1
      core/io/ip_address.cpp
  11. 1 1
      core/io/resource_format_binary.cpp
  12. 39 36
      core/io/resource_format_xml.cpp
  13. 2 2
      core/method_bind.cpp
  14. 5 2
      core/object.cpp
  15. 23 6
      core/object.h
  16. 14 8
      core/object_type_db.cpp
  17. 7 7
      core/object_type_db.h
  18. 3 1
      core/os/os.cpp
  19. 1 0
      core/os/os.h
  20. 1 0
      core/print_string.cpp
  21. 1 0
      core/print_string.h
  22. 8 8
      core/script_debugger_local.cpp
  23. 254 6
      core/script_debugger_remote.cpp
  24. 31 0
      core/script_debugger_remote.h
  25. 36 0
      core/script_language.h
  26. 2 2
      core/string_db.cpp
  27. 11 1
      core/string_db.h
  28. 27 0
      core/undo_redo.cpp
  29. 11 0
      core/undo_redo.h
  30. 44 6
      core/ustring.cpp
  31. 1 0
      core/ustring.h
  32. 57 0
      core/variant.cpp
  33. 1 0
      core/variant.h
  34. 5 3
      core/vector.h
  35. 157 191
      demos/2d/platformer/player.xml
  36. 1 1
      demos/2d/space_shooter/game_state.gd
  37. 0 1
      demos/2d/space_shooter/rail.gd
  38. 4 0
      demos/misc/regex/engine.cfg
  39. 22 0
      demos/misc/regex/regex.gd
  40. BIN
      demos/misc/regex/regex.scn
  41. 141 175
      doc/base/classes.xml
  42. 123 123
      doc/engine_classes.xml
  43. 1 1
      drivers/SCsub
  44. 64 0
      drivers/nrex/README.md
  45. 1 2
      drivers/nrex/SCsub
  46. 910 0
      drivers/nrex/nrex.cpp
  47. 144 0
      drivers/nrex/nrex.hpp
  48. 12 0
      drivers/nrex/nrex_config.h
  49. 114 0
      drivers/nrex/regex.cpp
  50. 8 11
      drivers/nrex/regex.h
  51. 4 1
      drivers/png/SCsub
  52. 1 1
      drivers/register_driver_types.cpp
  53. 1 1
      drivers/speex/audio_stream_speex.cpp
  54. 0 75
      drivers/trex/TRexpp.h
  55. 0 15
      drivers/trex/history.txt
  56. 0 171
      drivers/trex/readme.txt
  57. 0 163
      drivers/trex/regex.cpp
  58. 0 41
      drivers/trex/test.c
  59. 0 643
      drivers/trex/trex.c
  60. 0 70
      drivers/trex/trex.h
  61. 14 0
      drivers/unix/os_unix.cpp
  62. 1 0
      drivers/unix/os_unix.h
  63. 1 1
      drivers/vorbis/audio_stream_ogg_vorbis.cpp
  64. 9 6
      main/main.cpp
  65. 464 82
      modules/gdscript/gd_editor.cpp
  66. 27 9
      modules/gdscript/gd_parser.cpp
  67. 10 2
      modules/gdscript/gd_script.cpp
  68. 15 0
      modules/gdscript/gd_script.h
  69. 7 1
      modules/gdscript/gd_tokenizer.cpp
  70. 4 4
      modules/gridmap/grid_map.cpp
  71. 41 1
      platform/android/detect.py
  72. 20 15
      platform/android/export/export.cpp
  73. 4 4
      platform/bb10/export/export.cpp
  74. 23 0
      platform/iphone/app_delegate.mm
  75. 4 4
      platform/javascript/export/export.cpp
  76. 4 4
      platform/osx/export/export.cpp
  77. 6 0
      platform/windows/os_windows.cpp
  78. 2 1
      platform/windows/os_windows.h
  79. 1 0
      platform/x11/os_x11.cpp
  80. 4 4
      scene/2d/animated_sprite.cpp
  81. 9 8
      scene/2d/area_2d.cpp
  82. 6 6
      scene/2d/canvas_item.cpp
  83. 36 22
      scene/2d/collision_object_2d.cpp
  84. 5 5
      scene/2d/node_2d.cpp
  85. 18 18
      scene/2d/particles_2d.cpp
  86. 19 15
      scene/2d/sprite.cpp
  87. 5 0
      scene/2d/tile_map.cpp
  88. 2 0
      scene/2d/tile_map.h
  89. 2 2
      scene/3d/area.cpp
  90. 4 4
      scene/3d/collision_object.cpp
  91. 4 4
      scene/3d/skeleton.cpp
  92. 1 1
      scene/3d/spatial.cpp
  93. 12 9
      scene/animation/animation_player.cpp
  94. 1 1
      scene/audio/sample_player.cpp
  95. 3 3
      scene/gui/base_button.cpp
  96. 4 4
      scene/gui/button.cpp
  97. 4 4
      scene/gui/button_array.cpp
  98. 20 20
      scene/gui/control.cpp
  99. 5 5
      scene/gui/label.cpp
  100. 112 3
      scene/gui/tabs.cpp

+ 7 - 4
SConstruct

@@ -54,13 +54,16 @@ methods.save_active_platforms(active_platforms,active_platform_ids)
 
 custom_tools=['default']
 
+platform_arg = ARGUMENTS.get("platform", False)
+
 if (os.name=="posix"):
 	pass
 elif (os.name=="nt"):
-    if (os.getenv("VSINSTALLDIR")==None):
-	custom_tools=['mingw']
+    if (os.getenv("VSINSTALLDIR")==None or platform_arg=="android"):
+		custom_tools=['mingw']
 
 env_base=Environment(tools=custom_tools,ENV = {'PATH' : os.environ['PATH']});
+
 #env_base=Environment(tools=custom_tools);
 env_base.global_defaults=global_defaults
 env_base.android_source_modules=[]
@@ -363,8 +366,8 @@ if selected_platform in platform_list:
 		
 		#env['MSVS_VERSION']='9.0'
 		env['MSVSBUILDCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
-		env['MSVSREBUILDCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
-		env['MSVSCLEANCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
+		env['MSVSREBUILDCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes vsproj=true"
+		env['MSVSCLEANCOM'] = "scons --clean platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
 			
 		debug_variants = ['Debug|Win32']+['Debug|x64']
 		release_variants = ['Release|Win32']+['Release|x64']

+ 9 - 13
bin/tests/test_string.cpp

@@ -31,7 +31,7 @@
 //#include "math_funcs.h"
 #include <stdio.h>
 #include "os/os.h"
-#include "drivers/trex/regex.h"
+#include "drivers/nrex/regex.h"
 
 #include "test_string.h"
 
@@ -463,20 +463,16 @@ bool test_26() {
 
 	OS::get_singleton()->print("\n\nTest 26: RegEx\n");
 	RegEx regexp("(.*):(.*)");
-	List<String> captures;
 
-	bool match = regexp.match("name:password", &captures);
-	printf("\tmatch: %s\n", match?"true":"false");
+	int res = regexp.find("name:password");
+	printf("\tmatch: %s\n", (res>=0)?"true":"false");
 
-	printf("\t%i captures:\n", captures.size());
-	List<String>::Element *I = captures.front();
-	while (I) {
-
-		printf("%ls\n", I->get().c_str());
-
-		I = I->next();
-	};
-	return captures.size();
+	printf("\t%i captures:\n", regexp.get_capture_count());
+	for (int i = 0; i<regexp.get_capture_count(); i++)
+	{
+		printf("%ls\n", regexp.get_capture(i).c_str());
+	}
+	return res;
 };
 
 struct test_27_data {

+ 106 - 0
core/bind/core_bind.cpp

@@ -494,6 +494,10 @@ uint64_t _OS::get_unix_time() const {
 	return OS::get_singleton()->get_unix_time();
 };
 
+uint64_t _OS::get_system_time_msec() const {
+	return OS::get_singleton()->get_system_time_msec();
+}
+
 void _OS::delay_usec(uint32_t p_usec) const {
 
 	OS::get_singleton()->delay_usec(p_usec);
@@ -694,6 +698,17 @@ bool _OS::is_debug_build() const {
 
 }
 
+void _OS::set_screen_orientation(ScreenOrientation p_orientation) {
+
+	OS::get_singleton()->set_screen_orientation(OS::ScreenOrientation(p_orientation));
+}
+
+_OS::ScreenOrientation _OS::get_screen_orientation() const {
+
+	return ScreenOrientation(OS::get_singleton()->get_screen_orientation());
+}
+
+
 String _OS::get_system_dir(SystemDir p_dir) const {
 
 	return OS::get_singleton()->get_system_dir(OS::SystemDir(p_dir));
@@ -752,6 +767,9 @@ void _OS::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_window_maximized", "enabled"),&_OS::set_window_maximized);
 	ObjectTypeDB::bind_method(_MD("is_window_maximized"),&_OS::is_window_maximized);
 
+	ObjectTypeDB::bind_method(_MD("set_screen_orientation","orientation"),&_OS::set_screen_orientation);
+	ObjectTypeDB::bind_method(_MD("get_screen_orientation"),&_OS::get_screen_orientation);
+
 
 	ObjectTypeDB::bind_method(_MD("set_iterations_per_second","iterations_per_second"),&_OS::set_iterations_per_second);
 	ObjectTypeDB::bind_method(_MD("get_iterations_per_second"),&_OS::get_iterations_per_second);
@@ -787,6 +805,7 @@ void _OS::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_time","utc"),&_OS::get_time,DEFVAL(false));
 	ObjectTypeDB::bind_method(_MD("get_time_zone_info"),&_OS::get_time_zone_info);
 	ObjectTypeDB::bind_method(_MD("get_unix_time"),&_OS::get_unix_time);
+	ObjectTypeDB::bind_method(_MD("get_system_time_msec"), &_OS::get_system_time_msec);
 
 	ObjectTypeDB::bind_method(_MD("set_icon"),&_OS::set_icon);
 
@@ -863,6 +882,14 @@ void _OS::_bind_methods() {
 	BIND_CONSTANT( MONTH_NOVEMBER );
 	BIND_CONSTANT( MONTH_DECEMBER );
 
+	BIND_CONSTANT( SCREEN_ORIENTATION_LANDSCAPE );
+	BIND_CONSTANT( SCREEN_ORIENTATION_PORTRAIT );
+	BIND_CONSTANT( SCREEN_ORIENTATION_REVERSE_LANDSCAPE );
+	BIND_CONSTANT( SCREEN_ORIENTATION_REVERSE_PORTRAIT );
+	BIND_CONSTANT( SCREEN_ORIENTATION_SENSOR_LANDSCAPE );
+	BIND_CONSTANT( SCREEN_ORIENTATION_SENSOR_PORTRAIT );
+	BIND_CONSTANT( SCREEN_ORIENTATION_SENSOR );
+
 	BIND_CONSTANT( SYSTEM_DIR_DESKTOP);
 	BIND_CONSTANT( SYSTEM_DIR_DCIM );
 	BIND_CONSTANT( SYSTEM_DIR_DOCUMENTS );
@@ -1678,12 +1705,89 @@ Variant _Marshalls::base64_to_variant(const String& p_str) {
 	return v;
 };
 
+String _Marshalls::raw_to_base64(const DVector<uint8_t> &p_arr) {
+
+	int len = p_arr.size();
+	DVector<uint8_t>::Read r = p_arr.read();
+
+	int b64len = len / 3 * 4 + 4 + 1;
+	DVector<uint8_t> b64buff;
+	b64buff.resize(b64len);
+	DVector<uint8_t>::Write w64 = b64buff.write();
+
+	int strlen = base64_encode((char*)(&w64[0]), (char*)(&r[0]), len);
+	w64[strlen] = 0;
+	String ret = (char*)&w64[0];
+
+	return ret;
+};
+
+DVector<uint8_t> _Marshalls::base64_to_raw(const String &p_str) {
+
+	int strlen = p_str.length();
+	CharString cstr = p_str.ascii();
+
+	int arr_len;
+	DVector<uint8_t> buf;
+	{
+		buf.resize(strlen / 4 * 3 + 1);
+		DVector<uint8_t>::Write w = buf.write();
+
+		arr_len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen);
+	};
+	buf.resize(arr_len);
+
+	// conversion from DVector<uint8_t> to raw array?
+	return buf;
+};
+
+String _Marshalls::utf8_to_base64(const String& p_str) {
+
+	CharString cstr = p_str.utf8();
+	int len = cstr.length();
+
+	int b64len = len / 3 * 4 + 4 + 1;
+	DVector<uint8_t> b64buff;
+	b64buff.resize(b64len);
+	DVector<uint8_t>::Write w64 = b64buff.write();
+
+	int strlen = base64_encode((char*)(&w64[0]), (char*)cstr.get_data(), len);
+
+	w64[strlen] = 0;
+	String ret = (char*)&w64[0];
+
+	return ret;
+};
+
+String _Marshalls::base64_to_utf8(const String& p_str) {
+
+	int strlen = p_str.length();
+	CharString cstr = p_str.ascii();
+
+	DVector<uint8_t> buf;
+	buf.resize(strlen / 4 * 3 + 1 + 1);
+	DVector<uint8_t>::Write w = buf.write();
+
+	int len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen);
+
+	w[len] = 0;
+	String ret = String::utf8((char*)&w[0]);
+
+	return ret;
+};
+
 
 void _Marshalls::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("variant_to_base64:String","variant"),&_Marshalls::variant_to_base64);
 	ObjectTypeDB::bind_method(_MD("base64_to_variant:Variant","base64_str"),&_Marshalls::base64_to_variant);
 
+	ObjectTypeDB::bind_method(_MD("raw_to_base64:String","array"),&_Marshalls::raw_to_base64);
+	ObjectTypeDB::bind_method(_MD("base64_to_raw:RawArray","base64_str"),&_Marshalls::base64_to_raw);
+
+	ObjectTypeDB::bind_method(_MD("utf8_to_base64:String","utf8_str"),&_Marshalls::utf8_to_base64);
+	ObjectTypeDB::bind_method(_MD("base64_to_utf8:String","base64_str"),&_Marshalls::base64_to_utf8);
+
 };
 
 
@@ -1772,6 +1876,7 @@ void _Thread::_start_func(void *ud) {
 	memdelete(tud);
 	Variant::CallError ce;
 	const Variant* arg[1]={&t->userdata};
+
 	t->ret=t->target_instance->call(t->target_method,arg,1,ce);
 	if (ce.error!=Variant::CallError::CALL_OK) {
 
@@ -1796,6 +1901,7 @@ void _Thread::_start_func(void *ud) {
 			default: {}
 		}
 
+
 		ERR_EXPLAIN("Could not call function '"+t->target_method.operator String()+"'' starting thread ID: "+t->get_id()+" Reason: "+reason);
 		ERR_FAIL();
 	}

+ 22 - 0
core/bind/core_bind.h

@@ -208,6 +208,7 @@ public:
 	Dictionary get_time(bool utc) const;
 	Dictionary get_time_zone_info() const;
 	uint64_t get_unix_time() const;
+	uint64_t get_system_time_msec() const;
 
 	int get_static_memory_usage() const;
 	int get_static_memory_peak_usage() const;
@@ -239,11 +240,25 @@ public:
 		SYSTEM_DIR_RINGTONES,
 	};
 
+	enum ScreenOrientation {
+
+		SCREEN_ORIENTATION_LANDSCAPE,
+		SCREEN_ORIENTATION_PORTRAIT,
+		SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
+		SCREEN_ORIENTATION_REVERSE_PORTRAIT,
+		SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
+		SCREEN_ORIENTATION_SENSOR_PORTRAIT,
+		SCREEN_ORIENTATION_SENSOR,
+	};
+
 	String get_system_dir(SystemDir p_dir) const;
 
 
 	String get_data_dir() const;
 
+	void set_screen_orientation(ScreenOrientation p_orientation);
+	ScreenOrientation get_screen_orientation() const;
+
 	void set_time_scale(float p_scale);
 	float get_time_scale();
 
@@ -255,6 +270,7 @@ public:
 };
 
 VARIANT_ENUM_CAST(_OS::SystemDir);
+VARIANT_ENUM_CAST(_OS::ScreenOrientation);
 
 
 class _Geometry : public Object {
@@ -436,6 +452,12 @@ public:
 	String variant_to_base64(const Variant& p_var);
 	Variant base64_to_variant(const String& p_str);
 
+	String raw_to_base64(const DVector<uint8_t>& p_arr);
+	DVector<uint8_t> base64_to_raw(const String& p_str);
+
+	String utf8_to_base64(const String& p_str);
+	String base64_to_utf8(const String& p_str);
+
 	_Marshalls() {};
 };
 

+ 10 - 1
core/globals.cpp

@@ -1149,6 +1149,12 @@ Error Globals::_save_settings_text(const String& p_file,const Map<String,List<St
 
 	return OK;
 }
+
+Error Globals::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array?
+
+	return save_custom(p_file);
+};
+
 Error Globals::save_custom(const String& p_path,const CustomMap& p_custom,const Set<String>& p_ignore_masks) {
 
 	ERR_FAIL_COND_V(p_path=="",ERR_INVALID_PARAMETER);
@@ -1321,7 +1327,7 @@ Vector<String> Globals::get_optimizer_presets() const {
 
 		if (!E->get().name.begins_with("optimizer_presets/"))
 			continue;
-		names.push_back(E->get().name.get_slice("/",1));
+		names.push_back(E->get().name.get_slicec('/',1));
 	}
 
 	names.sort();
@@ -1361,6 +1367,9 @@ void Globals::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("has_singleton"),&Globals::has_singleton);
 	ObjectTypeDB::bind_method(_MD("get_singleton"),&Globals::get_singleton_object);
 	ObjectTypeDB::bind_method(_MD("load_resource_pack"),&Globals::_load_resource_pack);
+
+	ObjectTypeDB::bind_method(_MD("save_custom"),&Globals::_save_custom_bnd);
+
 }
 
 Globals::Globals() {

+ 1 - 0
core/globals.h

@@ -86,6 +86,7 @@ protected:
 
 	List<Singleton> singletons;
 
+	Error _save_custom_bnd(const String& p_file);
 
 	bool _load_resource_pack(const String& p_pack);
 

+ 4 - 4
core/image.cpp

@@ -1016,10 +1016,10 @@ void Image::create( const char ** p_xpm ) {
 			String line_str=line_ptr;
 			line_str.replace("\t"," ");
 			
-			size_width=line_str.get_slice(" ",0).to_int();
-			size_height=line_str.get_slice(" ",1).to_int();
-			colormap_size=line_str.get_slice(" ",2).to_int();
-			pixelchars=line_str.get_slice(" ",3).to_int();
+			size_width=line_str.get_slicec(' ',0).to_int();
+			size_height=line_str.get_slicec(' ',1).to_int();
+			colormap_size=line_str.get_slicec(' ',2).to_int();
+			pixelchars=line_str.get_slicec(' ',3).to_int();
 			ERR_FAIL_COND(colormap_size > 32766);
 			ERR_FAIL_COND(pixelchars > 5);
 			ERR_FAIL_COND(size_width > 32767);

+ 3 - 1
core/io/file_access_encrypted.cpp

@@ -5,10 +5,12 @@
 #include "print_string.h"
 #define COMP_MAGIC 0x43454447
 
+#include "core/variant.h"
+#include <stdio.h>
 
 Error FileAccessEncrypted::open_and_parse(FileAccess *p_base,const Vector<uint8_t>& p_key,Mode p_mode) {
 
-	print_line("open and parse!");
+	//print_line("open and parse!");
 	ERR_FAIL_COND_V(file!=NULL,ERR_ALREADY_IN_USE);
 	ERR_FAIL_COND_V(p_key.size()!=32,ERR_INVALID_PARAMETER);
 

+ 1 - 1
core/io/http_client.cpp

@@ -325,7 +325,7 @@ Error HTTPClient::poll(){
 
 						if (i==0 && responses[i].begins_with("HTTP")) {
 
-							String num = responses[i].get_slice(" ",1);
+							String num = responses[i].get_slicec(' ',1);
 							response_num=num.to_int();
 						} else {
 

+ 1 - 1
core/io/ip_address.cpp

@@ -47,7 +47,7 @@ IP_Address::IP_Address(const String& p_string) {
 	}
 	for(int i=0;i<4;i++) {
 
-		field[i]=p_string.get_slice(".",i).to_int();
+		field[i]=p_string.get_slicec('.',i).to_int();
 	}
 }
 

+ 1 - 1
core/io/resource_format_binary.cpp

@@ -1819,7 +1819,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
 					Property p;
 					p.name_idx=get_string_index(F->get().name);
 					p.value=E->get()->get(F->get().name);
-					if (F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())
+					if ((F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())||(F->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && p.value.is_one()) )
 						continue;
 					p.pi=F->get();										
 

+ 39 - 36
core/io/resource_format_xml.cpp

@@ -1207,47 +1207,47 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
 
 
 		r_v=Vector3(
-				data.get_slice(",",0).to_double(),
-				data.get_slice(",",1).to_double(),
-				data.get_slice(",",2).to_double()
+				data.get_slicec(',',0).to_double(),
+				data.get_slicec(',',1).to_double(),
+				data.get_slicec(',',2).to_double()
 			   );
 
 	} else if (type=="vector2") {
 
 
 		r_v=Vector2(
-				data.get_slice(",",0).to_double(),
-				data.get_slice(",",1).to_double()
+				data.get_slicec(',',0).to_double(),
+				data.get_slicec(',',1).to_double()
 			   );
 
 	} else if (type=="plane") {
 
 		r_v=Plane(
-				data.get_slice(",",0).to_double(),
-				data.get_slice(",",1).to_double(),
-				data.get_slice(",",2).to_double(),
-				data.get_slice(",",3).to_double()
+				data.get_slicec(',',0).to_double(),
+				data.get_slicec(',',1).to_double(),
+				data.get_slicec(',',2).to_double(),
+				data.get_slicec(',',3).to_double()
 			 );
 
 	} else if (type=="quaternion") {
 
 		r_v=Quat(
-				data.get_slice(",",0).to_double(),
-				data.get_slice(",",1).to_double(),
-				data.get_slice(",",2).to_double(),
-				data.get_slice(",",3).to_double()
+				data.get_slicec(',',0).to_double(),
+				data.get_slicec(',',1).to_double(),
+				data.get_slicec(',',2).to_double(),
+				data.get_slicec(',',3).to_double()
 			 );
 
 	} else if (type=="rect2") {
 
 		r_v=Rect2(
 			Vector2(
-				data.get_slice(",",0).to_double(),
-				data.get_slice(",",1).to_double()
+				data.get_slicec(',',0).to_double(),
+				data.get_slicec(',',1).to_double()
 			),
 			Vector2(
-				data.get_slice(",",2).to_double(),
-				data.get_slice(",",3).to_double()
+				data.get_slicec(',',2).to_double(),
+				data.get_slicec(',',3).to_double()
 			)
 		);
 
@@ -1256,14 +1256,14 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
 
 		r_v=AABB(
 			Vector3(
-				data.get_slice(",",0).to_double(),
-				data.get_slice(",",1).to_double(),
-				data.get_slice(",",2).to_double()
+				data.get_slicec(',',0).to_double(),
+				data.get_slicec(',',1).to_double(),
+				data.get_slicec(',',2).to_double()
 			),
 			Vector3(
-				data.get_slice(",",3).to_double(),
-				data.get_slice(",",4).to_double(),
-				data.get_slice(",",5).to_double()
+				data.get_slicec(',',3).to_double(),
+				data.get_slicec(',',4).to_double(),
+				data.get_slicec(',',5).to_double()
 			)
 		);
 
@@ -1272,7 +1272,7 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
 		Matrix32 m3;
 		for (int i=0;i<3;i++) {
 			for (int j=0;j<2;j++) {
-				m3.elements[i][j]=data.get_slice(",",i*2+j).to_double();
+				m3.elements[i][j]=data.get_slicec(',',i*2+j).to_double();
 			}
 		}
 		r_v=m3;
@@ -1282,7 +1282,7 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
 		Matrix3 m3;
 		for (int i=0;i<3;i++) {
 			for (int j=0;j<3;j++) {
-				m3.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+				m3.elements[i][j]=data.get_slicec(',',i*3+j).to_double();
 			}
 		}
 		r_v=m3;
@@ -1292,24 +1292,24 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
 		Transform tr;
 		for (int i=0;i<3;i++) {
 			for (int j=0;j<3;j++) {
-				tr.basis.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+				tr.basis.elements[i][j]=data.get_slicec(',',i*3+j).to_double();
 			}
 
 		}
 		tr.origin=Vector3(
-			     data.get_slice(",",9).to_double(),
-			     data.get_slice(",",10).to_double(),
-			     data.get_slice(",",11).to_double()
+			     data.get_slicec(',',9).to_double(),
+			     data.get_slicec(',',10).to_double(),
+			     data.get_slicec(',',11).to_double()
 			   );
 		r_v=tr;
 
 	} else if (type=="color") {
 
 		r_v=Color(
-			   data.get_slice(",",0).to_double(),
-			   data.get_slice(",",1).to_double(),
-			   data.get_slice(",",2).to_double(),
-			   data.get_slice(",",3).to_double()
+			   data.get_slicec(',',0).to_double(),
+			   data.get_slicec(',',1).to_double(),
+			   data.get_slicec(',',2).to_double(),
+			   data.get_slicec(',',3).to_double()
 			 );
 
 	} else if (type=="node_path") {
@@ -1674,8 +1674,8 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
 		ERR_FAIL();
 	}
 
-	int major = version.get_slice(".",0).to_int();
-	int minor = version.get_slice(".",1).to_int();
+	int major = version.get_slicec('.',0).to_int();
+	int minor = version.get_slicec('.',1).to_int();
 
 	if (major>VERSION_MAJOR) {
 
@@ -2607,9 +2607,12 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
 
 				String name = PE->get().name;
 				Variant value = res->get(name);
-				if (PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())
+
+
+				if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
 					continue;
 
+
 				write_property(name,value);
 			}
 

+ 2 - 2
core/method_bind.cpp

@@ -40,8 +40,8 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
 		PropertyInfo pi( get_argument_type(p_argument), name );
 		if ((pi.type==Variant::OBJECT) && name.find(":")!=-1) {
 			pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
-			pi.hint_string=name.get_slice(":",1);
-			pi.name=name.get_slice(":",0);
+			pi.hint_string=name.get_slicec(':',1);
+			pi.name=name.get_slicec(':',0);
 		}
 		return pi;
 

+ 5 - 2
core/object.cpp

@@ -258,12 +258,15 @@ bool Object::_predelete() {
 	
 	_predelete_ok=1;
 	notification(NOTIFICATION_PREDELETE,true);
+	if (_predelete_ok) {
+		_type_ptr=NULL; //must restore so destructors can access type ptr correctly
+	}
 	return _predelete_ok;
 
 }
 
 void Object::_postinitialize() {
-	
+	_type_ptr=_get_type_namev();
 	_initialize_typev();
 	notification(NOTIFICATION_POSTINITIALIZE);
 	
@@ -1707,7 +1710,7 @@ bool Object::is_edited() const {
 
 Object::Object() {
 	
-
+	_type_ptr=NULL;
 	_block_signals=false;
 	_predelete_ok=0;
 	_instance_ID=0;

+ 23 - 6
core/object.h

@@ -82,7 +82,8 @@ enum PropertyUsageFlags {
 	PROPERTY_USAGE_BUNDLE=128, //used for optimized bundles
 	PROPERTY_USAGE_CATEGORY=256,
 	PROPERTY_USAGE_STORE_IF_NONZERO=512, //only store if nonzero
-	PROPERTY_USAGE_NO_INSTANCE_STATE=1024,
+	PROPERTY_USAGE_STORE_IF_NONONE=1024, //only store if false
+	PROPERTY_USAGE_NO_INSTANCE_STATE=2048,
 
 	PROPERTY_USAGE_DEFAULT=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK,
 	PROPERTY_USAGE_DEFAULT_INTL=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_INTERNATIONALIZED,
@@ -97,6 +98,8 @@ enum PropertyUsageFlags {
 #define ADD_PROPERTYI( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), m_property, m_setter, m_getter, m_index )
 #define ADD_PROPERTYNZ( m_property, m_setter, m_getter ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), m_setter, m_getter )
 #define ADD_PROPERTYINZ( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), m_setter, m_getter, m_index )
+#define ADD_PROPERTYNO( m_property, m_setter, m_getter ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), m_setter, m_getter )
+#define ADD_PROPERTYINO( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), m_setter, m_getter, m_index )
 
 struct PropertyInfo {
 	
@@ -179,10 +182,10 @@ public:\
 virtual String get_type() const { \
 	return String(#m_type);\
 }\
-virtual StringName get_type_name() const { \
+virtual const StringName* _get_type_namev() const { \
 	if (!_type_name)\
 		_type_name=get_type_static();\
-	return _type_name;\
+	return &_type_name;\
 }\
 static _FORCE_INLINE_ void* get_type_ptr_static() { \
 	static int ptr;\
@@ -388,6 +391,8 @@ friend void postinitialize_handler(Object*);
 	ScriptInstance *script_instance;
 	RefPtr script;
 	Dictionary metadata;
+	mutable StringName _type_name;
+	mutable const StringName* _type_ptr;
 
 	void _add_user_signal(const String& p_name, const Array& p_pargs=Array());
 	bool _has_user_signal(const StringName& p_name) const;
@@ -445,7 +450,11 @@ protected:
 	Variant _call_deferred_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
 
 
-
+	virtual const StringName* _get_type_namev() const {
+		if (!_type_name)
+			_type_name=get_type_static();
+		return &_type_name;
+	}
 
 	DVector<String> _get_meta_list_bind() const;
 	Array _get_property_list_bind() const;
@@ -523,11 +532,19 @@ public:
 
 	virtual String get_type() const { return "Object"; }
 	virtual String get_save_type() const { return get_type(); } //type stored when saving
-	virtual StringName get_type_name() const { return StringName("Object"); }
+
+
+
 	virtual bool is_type(const String& p_type) const { return (p_type=="Object"); }
 	virtual bool is_type_ptr(void *p_ptr) const { return get_type_ptr_static()==p_ptr; }
 
-
+	_FORCE_INLINE_ const StringName& get_type_name() const {
+		if (!_type_ptr) {
+			return *_get_type_namev();
+		} else {
+			return *_type_ptr;
+		}
+	}
 	
 	/* IAPI */
 //	void set(const String& p_name, const Variant& p_value);

+ 14 - 8
core/object_type_db.cpp

@@ -205,7 +205,7 @@ ObjectTypeDB::TypeInfo::~TypeInfo() {
 }
 
 
-bool ObjectTypeDB::is_type(const String &p_type,const String& p_inherits) {
+bool ObjectTypeDB::is_type(const StringName &p_type,const StringName& p_inherits) {
 	
 	OBJTYPE_LOCK;
 	
@@ -220,7 +220,7 @@ bool ObjectTypeDB::is_type(const String &p_type,const String& p_inherits) {
 	
 	return false;
 }
-void ObjectTypeDB::get_type_list( List<String> *p_types) {
+void ObjectTypeDB::get_type_list( List<StringName> *p_types) {
 	
 	OBJTYPE_LOCK;
 	
@@ -235,7 +235,7 @@ void ObjectTypeDB::get_type_list( List<String> *p_types) {
 }
 
 
-void ObjectTypeDB::get_inheriters_from( const String& p_type,List<String> *p_types) {
+void ObjectTypeDB::get_inheriters_from( const StringName& p_type,List<StringName> *p_types) {
 
 	OBJTYPE_LOCK;
 	
@@ -249,7 +249,7 @@ void ObjectTypeDB::get_inheriters_from( const String& p_type,List<String> *p_typ
 
 }
 
-String ObjectTypeDB::type_inherits_from(const String& p_type) {
+StringName ObjectTypeDB::type_inherits_from(const StringName& p_type) {
 	
 	OBJTYPE_LOCK;
 	
@@ -258,7 +258,7 @@ String ObjectTypeDB::type_inherits_from(const String& p_type) {
 	return ti->inherits;
 }
 
-bool ObjectTypeDB::type_exists(const String &p_type) {
+bool ObjectTypeDB::type_exists(const StringName &p_type) {
 	
 	OBJTYPE_LOCK;
 	return types.has(p_type);	
@@ -269,7 +269,7 @@ void ObjectTypeDB::add_compatibility_type(const StringName& p_type,const StringN
 	compat_types[p_type]=p_fallback;
 }
 
-Object *ObjectTypeDB::instance(const String &p_type) {
+Object *ObjectTypeDB::instance(const StringName &p_type) {
 	
 	TypeInfo *ti;
 	{
@@ -287,7 +287,7 @@ Object *ObjectTypeDB::instance(const String &p_type) {
 
 	return ti->creation_func();
 }
-bool ObjectTypeDB::can_instance(const String &p_type) {
+bool ObjectTypeDB::can_instance(const StringName &p_type) {
 	
 	OBJTYPE_LOCK;
 	
@@ -650,7 +650,13 @@ bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, c
 				Variant index=psg->index;
 				const Variant* arg[2]={&index,&p_value};
 				Variant::CallError ce;
-				p_object->call(psg->setter,arg,2,ce);
+//				p_object->call(psg->setter,arg,2,ce);
+				if (psg->_setptr) {
+					psg->_setptr->call(p_object,arg,2,ce);
+				} else {
+					p_object->call(psg->setter,arg,2,ce);
+				}
+
 
 			} else {
 				const Variant* arg[1]={&p_value};

+ 7 - 7
core/object_type_db.h

@@ -228,13 +228,13 @@ public:
 		T::register_custom_data_to_otdb();
 	}
 
-	static void get_type_list( List<String> *p_types);
-	static void get_inheriters_from( const String& p_type,List<String> *p_types);
-	static String type_inherits_from(const String& p_type);
-	static bool type_exists(const String &p_type);
-	static bool is_type(const String &p_type,const String& p_inherits);
-	static bool can_instance(const String &p_type);	
-	static Object *instance(const String &p_type);
+	static void get_type_list( List<StringName> *p_types);
+	static void get_inheriters_from( const StringName& p_type,List<StringName> *p_types);
+	static StringName type_inherits_from(const StringName& p_type);
+	static bool type_exists(const StringName &p_type);
+	static bool is_type(const StringName &p_type,const StringName& p_inherits);
+	static bool can_instance(const StringName &p_type);
+	static Object *instance(const StringName &p_type);
 
 #if 0
 	template<class N, class M>

+ 3 - 1
core/os/os.cpp

@@ -50,7 +50,9 @@ uint64_t OS::get_unix_time() const {
 
 	return 0;
 };
-
+uint64_t OS::get_system_time_msec() const {
+	return 0;
+}
 void OS::debug_break() {
 
 	// something

+ 1 - 0
core/os/os.h

@@ -254,6 +254,7 @@ public:
 	virtual Time get_time(bool local=false) const=0;
 	virtual TimeZoneInfo get_time_zone_info() const=0;
 	virtual uint64_t get_unix_time() const;
+	virtual uint64_t get_system_time_msec() const;
 
 	virtual void delay_usec(uint32_t p_usec) const=0; 
 	virtual uint64_t get_ticks_usec() const=0;

+ 1 - 0
core/print_string.cpp

@@ -32,6 +32,7 @@
 
 static PrintHandlerList *print_handler_list=NULL;
 bool _print_line_enabled=true;
+bool _print_error_enabled = true;
 
 void add_print_handler(PrintHandlerList *p_handler) {
 

+ 1 - 0
core/print_string.h

@@ -52,6 +52,7 @@ void add_print_handler(PrintHandlerList *p_handler);
 void remove_print_handler(PrintHandlerList *p_handler);
 
 extern bool _print_line_enabled;
+extern bool _print_error_enabled;
 extern void print_line(String p_string);
 
 #endif

+ 8 - 8
core/script_debugger_local.cpp

@@ -60,7 +60,7 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
 			if (line.get_slice_count(" ")==1) {
 				print_line("*Frame "+itos(current_frame)+" - "+p_script->debug_get_stack_level_source(current_frame)+":"+itos(p_script->debug_get_stack_level_line(current_frame))+" in function '"+p_script->debug_get_stack_level_function(current_frame)+"'");
 			} else {
-				int frame = line.get_slice(" ",1).to_int();
+				int frame = line.get_slicec(' ',1).to_int();
 				if (frame<0 || frame >=total_frames) {
 					print_line("Error: Invalid frame.");
 				} else {
@@ -108,7 +108,7 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
 				print_line("Usage: print <expre>");
 			} else {
 
-				String expr = line.get_slice(" ",2);
+				String expr = line.get_slicec(' ',2);
 				String res = p_script->debug_parse_stack_level_expression(current_frame,expr);
 				print_line(res);
 			}
@@ -130,9 +130,9 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
 			} else {
 
 
-				String bppos=line.get_slice(" ",1);
-				String source=bppos.get_slice(":",0).strip_edges();
-				int line=bppos.get_slice(":",1).strip_edges().to_int();
+				String bppos=line.get_slicec(' ',1);
+				String source=bppos.get_slicec(':',0).strip_edges();
+				int line=bppos.get_slicec(':',1).strip_edges().to_int();
 
 				source = breakpoint_find_source(source);
 
@@ -147,9 +147,9 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
 				clear_breakpoints();
 			} else {
 
-				String bppos=line.get_slice(" ",1);
-				String source=bppos.get_slice(":",0).strip_edges();
-				int line=bppos.get_slice(":",1).strip_edges().to_int();
+				String bppos=line.get_slicec(' ',1);
+				String source=bppos.get_slicec(':',0).strip_edges();
+				int line=bppos.get_slicec(':',1).strip_edges().to_int();
 
 				source = breakpoint_find_source(source);
 

+ 254 - 6
core/script_debugger_remote.cpp

@@ -34,7 +34,11 @@
 Error ScriptDebuggerRemote::connect_to_host(const String& p_host,uint16_t p_port) {
 
 
-    IP_Address ip = IP::get_singleton()->resolve_hostname(p_host);
+    IP_Address ip;
+    if (p_host.is_valid_ip_address())
+	    ip=p_host;
+    else
+	    ip = IP::get_singleton()->resolve_hostname(p_host);
 
 
     int port = p_port;
@@ -127,7 +131,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
 			ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );
 
 			String command = cmd[0];
-			cmd.remove(0);
+
 
 
 			if (command=="get_stack_dump") {
@@ -150,7 +154,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
 
 			} else if (command=="get_stack_frame_vars") {
 
-
+				cmd.remove(0);
 				ERR_CONTINUE( cmd.size()!=1 );
 				int lv = cmd[0];
 
@@ -243,6 +247,17 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
 
 				if (request_scene_tree)
 					request_scene_tree(request_scene_tree_ud);
+
+			} else if (command=="breakpoint") {
+
+				bool set = cmd[3];
+				if (set)
+					insert_breakpoint(cmd[2],cmd[1]);
+				else
+					remove_breakpoint(cmd[2],cmd[1]);
+
+			} else {
+				_parse_live_edit(cmd);
 			}
 
 
@@ -287,6 +302,37 @@ void ScriptDebuggerRemote::_get_output() {
 		messages.pop_front();
 		locking=false;
 	}
+
+	while (errors.size()) {
+		locking=true;
+		packet_peer_stream->put_var("error");
+		OutputError oe = errors.front()->get();
+
+		packet_peer_stream->put_var(oe.callstack.size()+2);
+
+		Array error_data;
+
+		error_data.push_back(oe.hr);
+		error_data.push_back(oe.min);
+		error_data.push_back(oe.sec);
+		error_data.push_back(oe.msec);
+		error_data.push_back(oe.source_func);
+		error_data.push_back(oe.source_file);
+		error_data.push_back(oe.source_line);
+		error_data.push_back(oe.error);
+		error_data.push_back(oe.error_descr);
+		error_data.push_back(oe.warning);
+		packet_peer_stream->put_var(error_data);
+		packet_peer_stream->put_var(oe.callstack.size());
+		for(int i=0;i<oe.callstack.size();i++) {
+			packet_peer_stream->put_var(oe.callstack[i]);
+
+		}
+
+		errors.pop_front();
+		locking=false;
+
+	}
 	mutex->unlock();
 }
 
@@ -301,6 +347,160 @@ void ScriptDebuggerRemote::line_poll() {
 }
 
 
+void ScriptDebuggerRemote::_err_handler(void* ud,const char* p_func,const char*p_file,int p_line,const char *p_err, const char * p_descr,ErrorHandlerType p_type) {
+
+	if (p_type==ERR_HANDLER_SCRIPT)
+		return; //ignore script errors, those go through debugger
+
+	ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)ud;
+
+	OutputError oe;
+	oe.error=p_err;
+	oe.error_descr=p_descr;
+	oe.source_file=p_file;
+	oe.source_line=p_line;
+	oe.source_func=p_func;
+	oe.warning=p_type==ERR_HANDLER_WARNING;
+	uint64_t time = OS::get_singleton()->get_ticks_msec();
+	oe.hr=time/3600000;
+	oe.min=(time/60000)%60;
+	oe.sec=(time/1000)%60;
+	oe.msec=time%1000;
+	Array cstack;
+
+	Vector<ScriptLanguage::StackInfo> si;
+
+	for(int i=0;i<ScriptServer::get_language_count();i++) {
+		si=ScriptServer::get_language(i)->debug_get_current_stack_info();
+		if (si.size())
+			break;
+	}
+
+	cstack.resize(si.size()*2);
+	for(int i=0;i<si.size();i++) {
+		String path;
+		int line=0;
+		if (si[i].script.is_valid()) {
+			path=si[i].script->get_path();
+			line=si[i].line;
+		}
+		cstack[i*2+0]=path;
+		cstack[i*2+1]=line;
+	}
+
+	oe.callstack=cstack;
+
+
+	sdr->mutex->lock();
+
+	if (!sdr->locking && sdr->tcp_client->is_connected()) {
+
+		sdr->errors.push_back(oe);
+	}
+
+	sdr->mutex->unlock();
+}
+
+
+bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) {
+
+	String cmdstr = cmd[0];
+	if (!live_edit_funcs || !cmdstr.begins_with("live_"))
+		return false;
+
+
+	//print_line(Variant(cmd).get_construct_string());
+	if (cmdstr=="live_set_root") {
+
+		if (!live_edit_funcs->root_func)
+			return true;
+		//print_line("root: "+Variant(cmd).get_construct_string());
+		live_edit_funcs->root_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+
+	} else if (cmdstr=="live_node_path") {
+
+		if (!live_edit_funcs->node_path_func)
+			return true;
+		//print_line("path: "+Variant(cmd).get_construct_string());
+
+		live_edit_funcs->node_path_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+
+	} else if (cmdstr=="live_res_path") {
+
+		if (!live_edit_funcs->res_path_func)
+			return true;
+		live_edit_funcs->res_path_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+
+	} else if (cmdstr=="live_node_prop_res") {
+		if (!live_edit_funcs->node_set_res_func)
+			return true;
+
+		live_edit_funcs->node_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_node_prop") {
+
+		if (!live_edit_funcs->node_set_func)
+			return true;
+		live_edit_funcs->node_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_res_prop_res") {
+
+		if (!live_edit_funcs->res_set_res_func)
+			return true;
+		live_edit_funcs->res_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_res_prop") {
+
+		if (!live_edit_funcs->res_set_func)
+			return true;
+		live_edit_funcs->res_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_node_call") {
+
+		if (!live_edit_funcs->node_call_func)
+			return true;
+		live_edit_funcs->node_call_func(live_edit_funcs->udata,cmd[1],cmd[2],  cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]);
+
+	} else if (cmdstr=="live_res_call") {
+
+		if (!live_edit_funcs->res_call_func)
+			return true;
+		live_edit_funcs->res_call_func(live_edit_funcs->udata,cmd[1],cmd[2],  cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]);
+
+	} else if (cmdstr=="live_create_node") {
+
+		live_edit_funcs->tree_create_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_instance_node") {
+
+		live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_remove_node") {
+
+		live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata,cmd[1]);
+
+	} else if (cmdstr=="live_remove_and_keep_node") {
+
+		live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+	} else if (cmdstr=="live_restore_node") {
+
+		live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+	} else if (cmdstr=="live_duplicate_node") {
+
+		live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+	} else if (cmdstr=="live_reparent_node") {
+
+		live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3],cmd[4]);
+
+	} else {
+
+		return false;
+	}
+
+	return true;
+}
+
 void ScriptDebuggerRemote::_poll_events() {
 
 	while(packet_peer_stream->get_available_packet_count()>0) {
@@ -321,7 +521,7 @@ void ScriptDebuggerRemote::_poll_events() {
 		ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );
 
 		String command = cmd[0];
-		cmd.remove(0);
+		//cmd.remove(0);
 
 		if (command=="break") {
 
@@ -331,6 +531,15 @@ void ScriptDebuggerRemote::_poll_events() {
 
 			if (request_scene_tree)
 				request_scene_tree(request_scene_tree_ud);
+		} else if (command=="breakpoint") {
+
+			bool set = cmd[3];
+			if (set)
+				insert_breakpoint(cmd[2],cmd[1]);
+			else
+				remove_breakpoint(cmd[2],cmd[1]);
+		} else {
+			_parse_live_edit(cmd);
 		}
 
 	}
@@ -394,10 +603,35 @@ void ScriptDebuggerRemote::_print_handler(void *p_this,const String& p_string) {
 
 	ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)p_this;
 
+	uint64_t ticks = OS::get_singleton()->get_ticks_usec()/1000;
+	sdr->msec_count+=ticks-sdr->last_msec;
+	sdr->last_msec=ticks;
+
+	if (sdr->msec_count>1000) {
+		sdr->char_count=0;
+		sdr->msec_count=0;
+	}
+
+	String s = p_string;
+	int allowed_chars = MIN(MAX(sdr->max_cps - sdr->char_count,0), s.length());
+
+	if (allowed_chars==0)
+		return;
+
+	if (allowed_chars<s.length()) {
+		s=s.substr(0,allowed_chars);
+	}
+
+	sdr->char_count+=allowed_chars;
+
+	if (sdr->char_count>=sdr->max_cps) {
+		s+="\n[output overflow, print less text!]\n";
+	}
+
 	sdr->mutex->lock();
 	if (!sdr->locking && sdr->tcp_client->is_connected()) {
 
-		sdr->output_strings .push_back(p_string);
+		sdr->output_strings.push_back(s);
 	}
 	sdr->mutex->unlock();
 }
@@ -413,6 +647,11 @@ void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeM
 	request_scene_tree_ud=p_udata;
 }
 
+void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) {
+
+	live_edit_funcs=p_funcs;
+}
+
 ScriptDebuggerRemote::ScriptDebuggerRemote() {
 
 	tcp_client  = StreamPeerTCP::create_ref();
@@ -429,13 +668,22 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() {
 	last_perf_time=0;
 	poll_every=0;
 	request_scene_tree=NULL;
+	live_edit_funcs=NULL;
+	max_cps = GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048);
+	char_count=0;
+	msec_count=0;
+	last_msec=0;
+
+	eh.errfunc=_err_handler;
+	eh.userdata=this;
+	add_error_handler(&eh);
 
 }
 
 ScriptDebuggerRemote::~ScriptDebuggerRemote() {
 
 	remove_print_handler(&phl);
+	remove_error_handler(&eh);
 	memdelete(mutex);
 
-
 }

+ 31 - 0
core/script_debugger_remote.h

@@ -49,8 +49,31 @@ class ScriptDebuggerRemote : public ScriptDebugger {
 	Object *performance;
 	bool requested_quit;
 	Mutex *mutex;
+
+	struct OutputError {
+
+		int hr;
+		int min;
+		int sec;
+		int msec;
+		String source_file;
+		String source_func;
+		int source_line;
+		String error;
+		String error_descr;
+		bool warning;
+		Array callstack;
+
+	};
+
 	List<String> output_strings;
 	List<Message> messages;
+	List<OutputError> errors;
+
+	int max_cps;
+	int char_count;
+	uint64_t last_msec;
+	uint64_t msec_count;
 
 	bool locking; //hack to avoid a deadloop
 	static void _print_handler(void *p_this,const String& p_string);
@@ -62,9 +85,16 @@ class ScriptDebuggerRemote : public ScriptDebugger {
 	uint32_t poll_every;
 
 
+	bool _parse_live_edit(const Array &p_command);
+
 	RequestSceneTreeMessageFunc request_scene_tree;
 	void *request_scene_tree_ud;
 
+	LiveEditFuncs *live_edit_funcs;
+
+	ErrorHandlerList eh;
+	static void _err_handler(void*,const char*,const char*,int p_line,const char *, const char *,ErrorHandlerType p_type);
+
 
 public:
 
@@ -79,6 +109,7 @@ public:
 	virtual void send_message(const String& p_message, const Array& p_args);
 
 	virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata);
+	virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs);
 
 	ScriptDebuggerRemote();
 	~ScriptDebuggerRemote();

+ 36 - 0
core/script_language.h

@@ -176,6 +176,13 @@ public:
 	virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1)=0;
 	virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1)=0;
 
+	struct StackInfo {
+		Ref<Script> script;
+		int line;
+	};
+
+	virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); }
+
 	/* LOADER FUNCTIONS */
 
 	virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
@@ -238,6 +245,32 @@ public:
 
 	typedef void (*RequestSceneTreeMessageFunc)(void *);
 
+	struct LiveEditFuncs {
+
+		void *udata;
+		void (*node_path_func)(void *,const NodePath &p_path,int p_id);
+		void (*res_path_func)(void *,const String &p_path,int p_id);
+
+		void (*node_set_func)(void *,int p_id,const StringName& p_prop,const Variant& p_value);
+		void (*node_set_res_func)(void *,int p_id,const StringName& p_prop,const String& p_value);
+		void (*node_call_func)(void *,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE);
+		void (*res_set_func)(void *,int p_id,const StringName& p_prop,const Variant& p_value);
+		void (*res_set_res_func)(void *,int p_id,const StringName& p_prop,const String& p_value);
+		void (*res_call_func)(void *,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE);
+		void (*root_func)(void*, const NodePath& p_scene_path,const String& p_scene_from);
+
+		void (*tree_create_node_func)(void*,const NodePath& p_parent,const String& p_type,const String& p_name);
+		void (*tree_instance_node_func)(void*,const NodePath& p_parent,const String& p_path,const String& p_name);
+		void (*tree_remove_node_func)(void*,const NodePath& p_at);
+		void (*tree_remove_and_keep_node_func)(void*,const NodePath& p_at,ObjectID p_keep_id);
+		void (*tree_restore_node_func)(void*,ObjectID p_id,const NodePath& p_at,int p_at_pos);
+		void (*tree_duplicate_node_func)(void*,const NodePath& p_at,const String& p_new_name);
+		void (*tree_reparent_node_func)(void*,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos);
+
+	};
+
+
+
 	_FORCE_INLINE_ static ScriptDebugger * get_singleton() { return singleton; }
 	void set_lines_left(int p_left);
 	int get_lines_left() const;
@@ -252,10 +285,12 @@ public:
 	bool is_breakpoint_line(int p_line) const;
 	void clear_breakpoints();
 
+
 	virtual void debug(ScriptLanguage *p_script,bool p_can_continue=true)=0;
 	virtual void idle_poll();
 	virtual void line_poll();
 
+
 	void set_break_language(ScriptLanguage *p_lang);
 	ScriptLanguage* get_break_language() const;
 
@@ -265,6 +300,7 @@ public:
 	virtual void request_quit() {}
 
 	virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {}
+	virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {}
 
 	ScriptDebugger();
 	virtual ~ScriptDebugger() {singleton=NULL;}

+ 2 - 2
core/string_db.cpp

@@ -158,7 +158,7 @@ void StringName::operator=(const StringName& p_name) {
 		_data = p_name._data;		
 	}
 }
-
+/* was inlined
 StringName::operator String() const {
 	
 	if (_data)
@@ -166,7 +166,7 @@ StringName::operator String() const {
 	
 	return "";
 }
-
+*/
 StringName::StringName(const StringName& p_name) {
 	
 	ERR_FAIL_COND(!configured);

+ 11 - 1
core/string_db.h

@@ -114,7 +114,17 @@ public:
 	}
 	bool operator!=(const StringName& p_name) const;
 	
-	operator String() const;
+	_FORCE_INLINE_ operator String() const {
+
+		if (_data) {
+			if (_data->cname )
+				return String(_data->cname);
+			else
+				return _data->name;
+		}
+
+		return String();
+	}
 
 	static StringName search(const char *p_name);
 	static StringName search(const CharType *p_name);

+ 27 - 0
core/undo_redo.cpp

@@ -244,7 +244,12 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
 				Resource* res = obj->cast_to<Resource>();
 				if (res)
 					res->set_edited(true);
+
 #endif
+
+				if (method_callback) {
+					method_callback(method_callbck_ud,obj,op.name,VARIANT_ARGS_FROM_ARRAY(op.args));
+				}
 			} break;
 			case Operation::TYPE_PROPERTY: {
 
@@ -254,6 +259,9 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
 				if (res)
 					res->set_edited(true);
 #endif
+				if (property_callback) {
+					property_callback(prop_callback_ud,obj,op.name,op.args[0]);
+				}
 			} break;
 			case Operation::TYPE_REFERENCE: {
 				//do nothing
@@ -325,6 +333,19 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback,void*
 	callback_ud=p_ud;
 }
 
+void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud) {
+
+	method_callback=p_method_callback;
+	method_callbck_ud=p_ud;
+}
+
+void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud){
+
+	property_callback=p_property_callback;
+	prop_callback_ud=p_ud;
+}
+
+
 UndoRedo::UndoRedo() {
 
 	version=1;
@@ -334,6 +355,12 @@ UndoRedo::UndoRedo() {
 	merging=true;
 	callback=NULL;
 	callback_ud=NULL;
+
+	method_callbck_ud=NULL;
+	prop_callback_ud=NULL;
+	method_callback=NULL;
+	property_callback=NULL;
+
 }
 
 UndoRedo::~UndoRedo() {

+ 11 - 0
core/undo_redo.h

@@ -45,6 +45,9 @@ public:
 	Variant _add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
 	Variant _add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
 
+	typedef void (*MethodNotifyCallback)(void *p_ud,Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE);
+	typedef void (*PropertyNotifyCallback)(void *p_ud,Object*p_base,const StringName& p_property,const Variant& p_value);
+
 private:
 	struct Operation {
 
@@ -83,6 +86,11 @@ private:
 
 	CommitNotifyCallback callback;
 	void* callback_ud;
+	void* method_callbck_ud;
+	void* prop_callback_ud;
+
+	MethodNotifyCallback method_callback;
+	PropertyNotifyCallback property_callback;
 
 
 protected:
@@ -113,6 +121,9 @@ public:
 
 	void set_commit_notify_callback(CommitNotifyCallback p_callback,void* p_ud);
 
+	void set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud);
+	void set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud);
+
 	UndoRedo();
 	~UndoRedo();
 };

+ 44 - 6
core/ustring.cpp

@@ -67,11 +67,14 @@ void String::copy_from(const char *p_cstr) {
 		return;
 	}
 	
+
 	resize(len+1); // include 0
 	
-	for(int i=0;i<len+1;i++) {
-	
-		set(i,p_cstr[i]);
+	CharType *dst = this->ptr();
+
+	for (int i=0;i<len+1;i++) {
+
+		dst[i]=p_cstr[i];
 	}
 
 }
@@ -486,7 +489,7 @@ String String::capitalize() const {
 	String cap;
 	for (int i=0;i<aux.get_slice_count(" ");i++) {
 		
-		String slice=aux.get_slice(" ",i);
+		String slice=aux.get_slicec(' ',i);
 		if (slice.length()>0) {
 		
 			slice[0]=_find_upper(slice[0]);
@@ -577,6 +580,41 @@ String String::get_slice(String p_splitter, int p_slice) const {
 
 }
 
+String String::get_slicec(CharType p_splitter, int p_slice) const {
+
+	if (empty())
+		return String();
+
+	if (p_slice<0)
+		return String();
+
+	const CharType *c=this->ptr();
+	int i=0;
+	int prev=0;
+	int count=0;
+	while(true) {
+
+
+		if (c[i]==0 || c[i]==p_splitter) {
+
+			if (p_slice==count) {
+
+				return substr(prev,i-prev);
+			} else {
+				count++;
+				prev=i+1;
+			}
+
+		}
+
+		i++;
+
+	}
+
+	return String(); //no find!
+
+}
+
 
 Vector<String> String::split_spaces() const {
 
@@ -3333,8 +3371,8 @@ String String::path_to(const String& p_path) const {
 		//nothing
 	} else {
 		//dos style
-		String src_begin=src.get_slice("/",0);
-		String dst_begin=dst.get_slice("/",0);
+		String src_begin=src.get_slicec('/',0);
+		String dst_begin=dst.get_slicec('/',0);
 
 		if (src_begin!=dst_begin)
 			return p_path; //impossible to do this

+ 1 - 0
core/ustring.h

@@ -153,6 +153,7 @@ public:
 
 	int get_slice_count(String p_splitter) const;
 	String get_slice(String p_splitter,int p_slice) const;
+	String get_slicec(CharType splitter,int p_slice) const;
 
 	Vector<String> split(const String &p_splitter,bool p_allow_empty=true) const;
 	Vector<String> split_spaces() const;

+ 57 - 0
core/variant.cpp

@@ -878,6 +878,63 @@ bool Variant::is_zero() const {
 	return false;
 }
 
+
+bool Variant::is_one() const {
+
+	switch( type ) {
+		case NIL: {
+
+			return true;
+		} break;
+
+		// atomic types
+		case BOOL: {
+
+			return _data._bool==true;
+		} break;
+		case INT: {
+
+			return _data._int==1;
+
+		} break;
+		case REAL: {
+
+			return _data._real==1;
+
+		} break;
+		case VECTOR2: {
+
+			return *reinterpret_cast<const Vector2*>(_data._mem)==Vector2(1,1);
+
+		} break;
+		case RECT2: {
+
+			return *reinterpret_cast<const Rect2*>(_data._mem)==Rect2(1,1,1,1);
+
+		} break;
+		case VECTOR3: {
+
+			return *reinterpret_cast<const Vector3*>(_data._mem)==Vector3(1,1,1);
+
+		} break;
+		case PLANE: {
+
+			return *reinterpret_cast<const Plane*>(_data._mem)==Plane(1,1,1,1);
+
+		} break;
+		case COLOR: {
+
+			return *reinterpret_cast<const Color*>(_data._mem)==Color(1,1,1,1);
+
+		} break;
+
+		default: { return !is_zero(); }
+	}
+
+	return false;
+}
+
+
 void Variant::reference(const Variant& p_variant) {
 
 	

+ 1 - 0
core/variant.h

@@ -185,6 +185,7 @@ public:
 	_FORCE_INLINE_ bool is_array() const { return type>=ARRAY; };
 	bool is_shared() const;
 	bool is_zero() const;
+	bool is_one() const;
 
 	operator bool() const;
 	operator signed int() const;

+ 5 - 3
core/vector.h

@@ -340,12 +340,14 @@ template<class T>
 void Vector<T>::remove(int p_index) {
 
 	ERR_FAIL_INDEX(p_index, size());
-	for (int i=p_index; i<size()-1; i++) {
+	T*p=ptr();
+	int len=size();
+	for (int i=p_index; i<len-1; i++) {
 
-		set(i, get(i+1));
+		p[i]=p[i+1];
 	};
 
-	resize(size()-1);
+	resize(len-1);
 };
 
 template<class T>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 157 - 191
demos/2d/platformer/player.xml


+ 1 - 1
demos/2d/space_shooter/game_state.gd

@@ -8,12 +8,12 @@ var max_points = 0
 func _ready():
 	var f = File.new()
 	#load high score
+	
 	if (f.open("user://highscore",File.READ)==OK):
 		
 		max_points=f.get_var()
 
 
-
 func game_over():
 	if (points>max_points):
 		max_points=points

+ 0 - 1
demos/2d/space_shooter/rail.gd

@@ -14,7 +14,6 @@ var offset=0
 
 
 func _process(delta):
-	
 	offset+=delta*SPEED
 	set_pos(Vector2(offset,0))
 

+ 4 - 0
demos/misc/regex/engine.cfg

@@ -0,0 +1,4 @@
+[application]
+
+name="RegEx"
+main_scene="res://regex.scn"

+ 22 - 0
demos/misc/regex/regex.gd

@@ -0,0 +1,22 @@
+extends VBoxContainer
+
+var regex = RegEx.new()
+
+func update_expression():
+	regex.compile(get_node("Expression").get_text())
+	update_text()
+
+func update_text():
+	var text = get_node("Text").get_text()
+	regex.find(text)
+	var list = get_node("List")
+	for child in list.get_children():
+		child.queue_free()
+	for res in regex.get_captures():
+		var label = Label.new()
+		label.set_text(res)
+		list.add_child(label)
+
+func _ready():
+	get_node("Text").set_text("They asked me \"What's going on \\\"in the manor\\\"?\"")
+	update_expression()

BIN
demos/misc/regex/regex.scn


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 141 - 175
doc/base/classes.xml


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 123 - 123
doc/engine_classes.xml


+ 1 - 1
drivers/SCsub

@@ -30,7 +30,7 @@ if (env["openssl"]=="builtin"):
 
 SConscript("rtaudio/SCsub");
 SConscript("nedmalloc/SCsub");
-SConscript("trex/SCsub");
+SConscript("nrex/SCsub");
 SConscript("chibi/SCsub");
 if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"):
         SConscript("ogg/SCsub");

+ 64 - 0
drivers/nrex/README.md

@@ -0,0 +1,64 @@
+# NREX: Node RegEx
+
+Small node-based regular expression library. It only does text pattern
+matchhing, not replacement. To use add the files `nrex.hpp`, `nrex.cpp`
+and `nrex_config.h` to your project and follow the example:
+
+	nrex regex;
+	regex.compile("^(fo+)bar$");
+
+	nrex_result captures[regex.capture_size()];
+	if (regex.match("foobar", captures))
+	{
+		std::cout << captures[0].start << std::endl;
+		std::cout << captures[0].length << std::endl;
+	}
+
+More details about its use is documented in `nrex.hpp`
+
+Currently supported features:
+ * Capturing `()` and non-capturing `(?:)` groups
+ * Any character `.`
+ * Shorthand caracter classes `\w\W\s\S\d\D`
+ * User-defined character classes such as `[A-Za-z]`
+ * Simple quantifiers `?`, `*` and `+`
+ * Range quantifiers `{0,1}`
+ * Lazy (non-greedy) quantifiers `*?`
+ * Begining `^` and end `$` anchors
+ * Alternation `|`
+ * Backreferences `\1` to `\99`
+
+To do list:
+ * Unicode `\uFFFF` code points
+
+## License
+
+Copyright (c) 2015, Zher Huei Lee
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 1 - 2
drivers/trex/SCsub → drivers/nrex/SCsub

@@ -2,8 +2,7 @@
 Import('env')
 
 sources = [
-
-	'trex.c',
+	'nrex.cpp',
 	'regex.cpp',
 ]
 env.add_source_files(env.drivers_sources, sources)

+ 910 - 0
drivers/nrex/nrex.cpp

@@ -0,0 +1,910 @@
+//  NREX: Node RegEx
+//
+//  Copyright (c) 2015, Zher Huei Lee
+//  All rights reserved.
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any damages
+//  arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any purpose,
+//  including commercial applications, and to alter it and redistribute it
+//  freely, subject to the following restrictions:
+//
+//   1. The origin of this software must not be misrepresented; you must not
+//      claim that you wrote the original software. If you use this software
+//      in a product, an acknowledgment in the product documentation would
+//      be appreciated but is not required.
+//
+//   2. Altered source versions must be plainly marked as such, and must not
+//      be misrepresented as being the original software.
+//
+//   3. This notice may not be removed or altered from any source
+//      distribution.
+//
+
+#include "nrex.hpp"
+
+#ifdef NREX_UNICODE
+#include <wctype.h>
+#include <wchar.h>
+#define NREX_ISALPHANUM iswalnum
+#define NREX_STRLEN wcslen
+#else
+#include <ctype.h>
+#include <string.h>
+#define NREX_ISALPHANUM isalnum
+#define NREX_STRLEN strlen
+#endif
+
+#ifdef NREX_THROW_ERROR
+#define NREX_COMPILE_ERROR(M) throw nrex_compile_error(M)
+#else
+#define NREX_COMPILE_ERROR(M) reset(); return false
+#endif
+
+#ifndef NREX_NEW
+#define NREX_NEW(X) new X
+#define NREX_NEW_ARRAY(X, N) new X[N]
+#define NREX_DELETE(X) delete X
+#define NREX_DELETE_ARRAY(X) delete[] X
+#endif
+
+template<typename T>
+class nrex_array
+{
+    private:
+        T* _data;
+        unsigned int _reserved;
+        unsigned int _size;
+    public:
+        nrex_array()
+            : _data(NREX_NEW_ARRAY(T, 2))
+            , _reserved(2)
+            , _size(0)
+        {
+        }
+
+        ~nrex_array()
+        {
+            NREX_DELETE_ARRAY(_data);
+        }
+
+        unsigned int size() const
+        {
+            return _size;
+        }
+
+        void reserve(unsigned int size)
+        {
+            T* old = _data;
+            _data = NREX_NEW_ARRAY(T, size);
+            _reserved = size;
+            for (unsigned int i = 0; i < _size; ++i)
+            {
+                _data[i] = old[i];
+            }
+            NREX_DELETE_ARRAY(old);
+        }
+
+        void push(T item)
+        {
+            if (_size == _reserved)
+            {
+                reserve(_reserved * 2);
+            }
+            _data[_size] = item;
+            _size++;
+        }
+
+        T& top()
+        {
+            return _data[_size - 1];
+        }
+
+        const T& operator[] (unsigned int i) const
+        {
+            return _data[i];
+        }
+
+        void pop()
+        {
+            if (_size > 0)
+            {
+                --_size;
+            }
+        }
+};
+
+static nrex_char nrex_unescape(nrex_char repr)
+{
+    switch (repr)
+    {
+        case '^': return '^';
+        case '$': return '$';
+        case '(': return '(';
+        case ')': return ')';
+        case '\\': return '\\';
+        case '.': return '.';
+        case '+': return '+';
+        case '*': return '*';
+        case '?': return '?';
+        case '-': return '-';
+        case 'a': return '\a';
+        case 'e': return '\e';
+        case 'f': return '\f';
+        case 'n': return '\n';
+        case 'r': return '\r';
+        case 't': return '\t';
+        case 'v': return '\v';
+    }
+    return 0;
+}
+
+struct nrex_search
+{
+    public:
+        const nrex_char* str;
+        nrex_result* captures;
+        int end;
+        bool complete;
+
+        nrex_char at(int pos)
+        {
+            return str[pos];
+        }
+
+        nrex_search(const nrex_char* str, nrex_result* captures)
+            : str(str)
+            , captures(captures)
+            , end(0)
+        {
+        }
+};
+
+struct nrex_node
+{
+        nrex_node* next;
+        nrex_node* previous;
+        nrex_node* parent;
+        bool quantifiable;
+
+        nrex_node(bool quantify = false)
+            : next(NULL)
+            , previous(NULL)
+            , parent(NULL)
+            , quantifiable(quantify)
+        {
+        }
+
+        virtual ~nrex_node()
+        {
+            if (next)
+            {
+                NREX_DELETE(next);
+            }
+        }
+
+        virtual int test(nrex_search* s, int pos) const
+        {
+            return next ? next->test(s, pos) : -1;
+        }
+
+        virtual int test_parent(nrex_search* s, int pos) const
+        {
+            if (next)
+            {
+                pos = next->test(s, pos);
+            }
+            if (parent && pos >= 0)
+            {
+                pos = parent->test_parent(s, pos);
+            }
+            if (pos >= 0)
+            {
+                s->complete = true;
+            }
+            return pos;
+        }
+};
+
+struct nrex_node_group : public nrex_node
+{
+        int capturing;
+        bool negate;
+        nrex_array<nrex_node*> childset;
+        nrex_node* back;
+
+        nrex_node_group(int capturing)
+            : nrex_node(true)
+            , capturing(capturing)
+            , negate(false)
+            , back(NULL)
+        {
+        }
+
+        virtual ~nrex_node_group()
+        {
+            for (unsigned int i = 0; i < childset.size(); ++i)
+            {
+                NREX_DELETE(childset[i]);
+            }
+
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            if (capturing >= 0)
+            {
+                s->captures[capturing].start = pos;
+            }
+            for (unsigned int i = 0; i < childset.size(); ++i)
+            {
+                s->complete = false;
+                int res = childset[i]->test(s, pos);
+                if (s->complete)
+                {
+                    return res;
+                }
+                if (negate)
+                {
+                    if (res < 0)
+                    {
+                        res = pos + 1;
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                if (res >= 0)
+                {
+                    if (capturing >= 0)
+                    {
+                        s->captures[capturing].length = res - pos;
+                    }
+                    return next ? next->test(s, res) : res;
+                }
+            }
+            return -1;
+        }
+
+        virtual int test_parent(nrex_search* s, int pos) const
+        {
+            if (capturing >= 0)
+            {
+                s->captures[capturing].length = pos - s->captures[capturing].start;
+            }
+            return nrex_node::test_parent(s, pos);
+        }
+
+        void add_childset()
+        {
+            back = NULL;
+        }
+
+        void add_child(nrex_node* node)
+        {
+            node->parent = this;
+            node->previous = back;
+            if (back)
+            {
+                back->next = node;
+            }
+            else
+            {
+                childset.push(node);
+            }
+            back = node;
+        }
+
+        nrex_node* swap_back(nrex_node* node)
+        {
+            if (!back)
+            {
+                add_child(node);
+                return NULL;
+            }
+            nrex_node* old = back;
+            if (!old->previous)
+            {
+                childset.pop();
+            }
+            back = old->previous;
+            add_child(node);
+            return old;
+        }
+};
+
+struct nrex_node_char : public nrex_node
+{
+        nrex_char ch;
+
+        nrex_node_char(nrex_char c)
+            : nrex_node(true)
+            , ch(c)
+        {
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            if (s->end == pos || s->at(pos) != ch)
+            {
+                return -1;
+            }
+            return next ? next->test(s, pos + 1) : pos + 1;
+        }
+};
+
+struct nrex_node_range : public nrex_node
+{
+        nrex_char start;
+        nrex_char end;
+
+        nrex_node_range(nrex_char s, nrex_char e)
+            : nrex_node(true)
+            , start(s)
+            , end(e)
+        {
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            if (s->end == pos)
+            {
+                return -1;
+            }
+            nrex_char c = s->at(pos);
+            if (c < start || end < c)
+            {
+                return -1;
+            }
+            return next ? next->test(s, pos + 1) : pos + 1;
+        }
+};
+
+static bool nrex_is_whitespace(nrex_char repr)
+{
+    switch (repr)
+    {
+        case ' ':
+        case '\t':
+        case '\r':
+        case '\n':
+        case '\f':
+            return true;
+    }
+    return false;
+}
+
+static bool nrex_is_shorthand(nrex_char repr)
+{
+    switch (repr)
+    {
+        case 'W':
+        case 'w':
+        case 'D':
+        case 'd':
+        case 'S':
+        case 's':
+            return true;
+    }
+    return false;
+}
+
+struct nrex_node_shorthand : public nrex_node
+{
+        nrex_char repr;
+
+        nrex_node_shorthand(nrex_char c)
+            : nrex_node(true)
+            , repr(c)
+        {
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            if (s->end == pos)
+            {
+                return -1;
+            }
+            bool found = false;
+            bool invert = false;
+            nrex_char c = s->at(pos);
+            switch (repr)
+            {
+                case '.':
+                    found = true;
+                    break;
+                case 'W':
+                    invert = true;
+                case 'w':
+                    if (c == '_' || NREX_ISALPHANUM(c))
+                    {
+                        found = true;
+                    }
+                    break;
+                case 'D':
+                    invert = true;
+                case 'd':
+                    if ('0' <= c && c <= '9')
+                    {
+                        found = true;
+                    }
+                    break;
+                case 'S':
+                    invert = true;
+                case 's':
+                    if (nrex_is_whitespace(c))
+                    {
+                        found = true;
+                    }
+                    break;
+            }
+            if (found == invert)
+            {
+                return -1;
+            }
+            return next ? next->test(s, pos + 1) : pos + 1;
+        }
+};
+
+static bool nrex_is_quantifier(nrex_char repr)
+{
+    switch (repr)
+    {
+        case '?':
+        case '*':
+        case '+':
+        case '{':
+            return true;
+    }
+    return false;
+}
+
+struct nrex_node_quantifier : public nrex_node
+{
+        int min;
+        int max;
+        bool greedy;
+        nrex_node* child;
+
+        nrex_node_quantifier()
+            : nrex_node()
+            , min(0)
+            , max(0)
+            , greedy(true)
+            , child(NULL)
+        {
+        }
+
+        virtual ~nrex_node_quantifier()
+        {
+            if (child)
+            {
+                NREX_DELETE(child);
+            }
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            nrex_array<int> backtrack;
+            backtrack.push(pos);
+            while (backtrack.top() <= s->end)
+            {
+                if (max >= 1 && backtrack.size() > (unsigned int)max)
+                {
+                    break;
+                }
+                if (!greedy && (unsigned int)min < backtrack.size())
+                {
+                    int res = backtrack.top();
+                    if (next)
+                    {
+                        res = next->test(s, res);
+                    }
+                    if (s->complete)
+                    {
+                        return res;
+                    }
+                    if (res >= 0 && parent->test_parent(s, res) >= 0)
+                    {
+                        return res;
+                    }
+                }
+                int res = child->test(s, backtrack.top());
+                if (s->complete)
+                {
+                    return res;
+                }
+                if (res < 0 || res == backtrack.top())
+                {
+                    break;
+                }
+                backtrack.push(res);
+            }
+            while (greedy && (unsigned int) min < backtrack.size())
+            {
+                int res = backtrack.top();
+                if (next)
+                {
+                    res = next->test(s, res);
+                }
+                if (res >= 0 && parent->test_parent(s, res) >= 0)
+                {
+                    return res;
+                }
+                if (s->complete)
+                {
+                    return res;
+                }
+                backtrack.pop();
+            }
+            return -1;
+        }
+};
+
+struct nrex_node_anchor : public nrex_node
+{
+        bool end;
+
+        nrex_node_anchor(bool end)
+            : nrex_node()
+            , end(end)
+        {
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            if (!end && pos != 0)
+            {
+                return -1;
+            }
+            else if (end && pos != s->end)
+            {
+                return -1;
+            }
+            return next ? next->test(s, pos) : pos;
+        }
+};
+
+struct nrex_node_backreference : public nrex_node
+{
+        int ref;
+
+        nrex_node_backreference(int ref)
+            : nrex_node(true)
+            , ref(ref)
+        {
+        }
+
+        int test(nrex_search* s, int pos) const
+        {
+            nrex_result& r = s->captures[ref];
+            for (int i = 0; i < r.length; ++i)
+            {
+                if (pos + i >= s->end)
+                {
+                    return -1;
+                }
+                if (s->at(r.start + i) != s->at(pos + i))
+                {
+                    return -1;
+                }
+            }
+            return next ? next->test(s, pos + r.length) : pos + r.length;
+        }
+};
+
+nrex::nrex()
+    : _capturing(0)
+    , _root(NULL)
+{
+}
+
+nrex::~nrex()
+{
+    if (_root)
+    {
+        NREX_DELETE(_root);
+    }
+}
+
+bool nrex::valid() const
+{
+    return (_root != NULL);
+}
+
+void nrex::reset()
+{
+    _capturing = 0;
+    if (_root)
+    {
+        NREX_DELETE(_root);
+    }
+    _root = NULL;
+}
+
+int nrex::capture_size() const
+{
+    return _capturing + 1;
+}
+
+bool nrex::compile(const nrex_char* pattern)
+{
+    reset();
+    nrex_node_group* root = NREX_NEW(nrex_node_group(_capturing));
+    nrex_array<nrex_node_group*> stack;
+    stack.push(root);
+    _root = root;
+
+    for (const nrex_char* c = pattern; c[0] != '\0'; ++c)
+    {
+        if (c[0] == '(')
+        {
+            if (c[1] == '?')
+            {
+                if (c[2] == ':')
+                {
+                    c = &c[2];
+                    nrex_node_group* group = NREX_NEW(nrex_node_group(-1));
+                    stack.top()->add_child(group);
+                    stack.push(group);
+                }
+                else
+                {
+                    NREX_COMPILE_ERROR("unrecognised qualifier for parenthesis");
+                }
+            }
+            else if (_capturing < 99)
+            {
+                nrex_node_group* group = NREX_NEW(nrex_node_group(++_capturing));
+                stack.top()->add_child(group);
+                stack.push(group);
+            }
+            else
+            {
+                nrex_node_group* group = NREX_NEW(nrex_node_group(-1));
+                stack.top()->add_child(group);
+                stack.push(group);
+            }
+        }
+        else if (c[0] == ')')
+        {
+            if (stack.size() > 1)
+            {
+                stack.pop();
+            }
+            else
+            {
+                NREX_COMPILE_ERROR("unexpected ')'");
+            }
+        }
+        else if (c[0] == '[')
+        {
+            nrex_node_group* group = NREX_NEW(nrex_node_group(-1));
+            stack.top()->add_child(group);
+            if (c[1] == '^')
+            {
+                group->negate = true;
+                ++c;
+            }
+            while (true)
+            {
+                group->add_childset();
+                ++c;
+                if (c[0] == '\0')
+                {
+                    NREX_COMPILE_ERROR("unclosed character class '[]'");
+                }
+                if (c[0] == ']')
+                {
+                    break;
+                }
+                else if (c[0] == '\\')
+                {
+                    nrex_char unescaped = nrex_unescape(c[1]);
+                    if (unescaped)
+                    {
+                        group->add_child(NREX_NEW(nrex_node_char(unescaped)));
+                        ++c;
+                    }
+                    else if (nrex_is_shorthand(c[1]))
+                    {
+                        group->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
+                        ++c;
+                    }
+                    else
+                    {
+                        NREX_COMPILE_ERROR("escape token not recognised");
+                    }
+                }
+                else
+                {
+                    if (c[1] == '-' && c[2] != '\0')
+                    {
+                        bool range = false;
+                        if ('A' <= c[0] && c[0] <= 'Z' && 'A' <= c[2] && c[2] <= 'Z')
+                        {
+                            range = true;
+                        }
+                        if ('a' <= c[0] && c[0] <= 'z' && 'a' <= c[2] && c[2] <= 'z')
+                        {
+                            range = true;
+                        }
+                        if ('0' <= c[0] && c[0] <= '9' && '0' <= c[2] && c[2] <= '9')
+                        {
+                            range = true;
+                        }
+                        if (range)
+                        {
+                            group->add_child(NREX_NEW(nrex_node_range(c[0], c[2])));
+                            c = &c[2];
+                            continue;
+                        }
+                    }
+                    group->add_child(NREX_NEW(nrex_node_char(c[0])));
+                }
+
+            }
+        }
+        else if (nrex_is_quantifier(c[0]))
+        {
+            nrex_node_quantifier* quant = NREX_NEW(nrex_node_quantifier);
+            quant->child = stack.top()->swap_back(quant);
+            if (quant->child == NULL || !quant->child->quantifiable)
+            {
+                NREX_COMPILE_ERROR("element not quantifiable");
+            }
+            quant->child->previous = NULL;
+            quant->child->next = NULL;
+            quant->child->parent = quant;
+            if (c[0] == '?')
+            {
+                quant->min = 0;
+                quant->max = 1;
+            }
+            else if (c[0] == '+')
+            {
+                quant->min = 1;
+                quant->max = -1;
+            }
+            else if (c[0] == '*')
+            {
+                quant->min = 0;
+                quant->max = -1;
+            }
+            else if (c[0] == '{')
+            {
+                bool max_set = false;
+                quant->min = 0;
+                quant->max = -1;
+                while (true)
+                {
+                    ++c;
+                    if (c[0] == '\0')
+                    {
+                        NREX_COMPILE_ERROR("unclosed range quantifier '{}'");
+                    }
+                    else if (c[0] == '}')
+                    {
+                        break;
+                    }
+                    else if (c[0] == ',')
+                    {
+                        max_set = true;
+                        continue;
+                    }
+                    else if (c[0] < '0' || '9' < c[0])
+                    {
+                        NREX_COMPILE_ERROR("expected numeric digits, ',' or '}'");
+                    }
+                    if (max_set)
+                    {
+                        if (quant->max < 0)
+                        {
+                            quant->max = int(c[0] - '0');
+                        }
+                        else
+                        {
+                            quant->max = quant->max * 10 + int(c[0] - '0');
+                        }
+                    }
+                    else
+                    {
+                        quant->min = quant->min * 10 + int(c[0] - '0');
+                    }
+                }
+                if (!max_set)
+                {
+                    quant->max = quant->min;
+                }
+            }
+            if (c[1] == '?')
+            {
+                quant->greedy = false;
+                ++c;
+            }
+        }
+        else if (c[0] == '|')
+        {
+            stack.top()->add_childset();
+        }
+        else if (c[0] == '^' || c[0] == '$')
+        {
+            stack.top()->add_child(NREX_NEW(nrex_node_anchor((c[0] == '$'))));
+        }
+        else if (c[0] == '.')
+        {
+            stack.top()->add_child(NREX_NEW(nrex_node_shorthand('.')));
+        }
+        else if (c[0] == '\\')
+        {
+            nrex_char unescaped = nrex_unescape(c[1]);
+            if (unescaped)
+            {
+                stack.top()->add_child(NREX_NEW(nrex_node_char(unescaped)));
+                ++c;
+            }
+            else if (nrex_is_shorthand(c[1]))
+            {
+                stack.top()->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
+                ++c;
+            }
+            else if ('1' <= c[1] && c[1] <= '9')
+            {
+                int ref = 0;
+                if ('0' <= c[2] && c[2] <= '9')
+                {
+                    ref = int(c[1] - '0') * 10 + int(c[2] - '0');
+                    c = &c[2];
+                }
+                else
+                {
+                    ref = int(c[1] - '0');
+                    ++c;
+                }
+                if (ref > _capturing)
+                {
+                    NREX_COMPILE_ERROR("backreference to non-existent capture");
+                }
+                stack.top()->add_child(NREX_NEW(nrex_node_backreference(ref)));
+            }
+            else
+            {
+                NREX_COMPILE_ERROR("escape token not recognised");
+            }
+        }
+        else
+        {
+            stack.top()->add_child(NREX_NEW(nrex_node_char(c[0])));
+        }
+    }
+    return true;
+}
+
+bool nrex::match(const nrex_char* str, nrex_result* captures, int offset, int end) const
+{
+    nrex_search s(str, captures);
+    if (end >= offset)
+    {
+        s.end = end;
+    }
+    else
+    {
+        s.end = NREX_STRLEN(str);
+    }
+    for (int i = offset; i < s.end; ++i)
+    {
+        for (int c = 0; c <= _capturing; ++c)
+        {
+            captures[c].start = 0;
+            captures[c].length = 0;
+        }
+        if (_root->test(&s, i) >= 0)
+        {
+            return true;
+        }
+    }
+    return false;
+}

+ 144 - 0
drivers/nrex/nrex.hpp

@@ -0,0 +1,144 @@
+//  NREX: Node RegEx
+//
+//  Copyright (c) 2015, Zher Huei Lee
+//  All rights reserved.
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any damages
+//  arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any purpose,
+//  including commercial applications, and to alter it and redistribute it
+//  freely, subject to the following restrictions:
+//
+//   1. The origin of this software must not be misrepresented; you must not
+//      claim that you wrote the original software. If you use this software
+//      in a product, an acknowledgment in the product documentation would
+//      be appreciated but is not required.
+//
+//   2. Altered source versions must be plainly marked as such, and must not
+//      be misrepresented as being the original software.
+//
+//   3. This notice may not be removed or altered from any source
+//      distribution.
+//
+
+#ifndef NREX_HPP
+#define NREX_HPP
+
+#include "nrex_config.h"
+
+#ifdef NREX_UNICODE
+typedef wchar_t nrex_char;
+#else
+typedef char nrex_char;
+#endif
+
+/*!
+ * \brief Struct to contain the range of a capture result
+ *
+ * The range provided is relative to the begining of the searched string.
+ *
+ * \see nrex_node::match()
+ */
+struct nrex_result
+{
+    public:
+        int start; /*!< Start of text range */
+        int length; /*!< Length of text range */
+};
+
+class nrex_node;
+
+/*!
+ * \brief Holds the compiled regex pattern
+ */
+class nrex
+{
+    private:
+        int _capturing;
+        nrex_node* _root;
+    public:
+        nrex();
+        ~nrex();
+
+        /*!
+         * \brief Removes the compiled regex and frees up the memory
+         */
+        void reset();
+
+        /*!
+         * \brief Checks if there is a compiled regex being stored
+         * \return True if present, False if not present
+         */
+        bool valid() const;
+
+        /*!
+         * \brief Provides number of captures the compiled regex uses
+         *
+         * This is used to provide the array size of the captures needed for
+         * nrex::match() to work. The size is actually the number of capture
+         * groups + one for the matching of the entire pattern. The result is
+         * always capped at 100.
+         *
+         * \return The number of captures
+         */
+        int capture_size() const;
+
+        /*!
+         * \brief Compiles the provided regex pattern
+         *
+         * This automatically removes the existing compiled regex if already
+         * present.
+         *
+         * If the NREX_THROW_ERROR was defined it would automatically throw a
+         * runtime error nrex_compile_error if it encounters a problem when
+         * parsing the pattern.
+         *
+         * \param The regex pattern
+         * \return True if the pattern was succesfully compiled
+         */
+        bool compile(const nrex_char* pattern);
+
+        /*!
+         * \brief Uses the pattern to search through the provided string
+         * \param str       The text to search through. It only needs to be
+         *                  null terminated if the end point is not provided.
+         *                  This also determines the starting anchor.
+         * \param captures  The array of results to store the capture results.
+         *                  The size of that array needs to be the same as the
+         *                  size given in nrex::capture_size(). As it matches
+         *                  the function fills the array with the results. 0 is
+         *                  the result for the entire pattern, 1 and above
+         *                  corresponds to the regex capture group if present.
+         * \param offset    The starting point of the search. This does not move
+         *                  the starting anchor. Defaults to 0.
+         * \param end       The end point of the search. This also determines
+         *                  the ending anchor. If a number less than the offset
+         *                  is provided, the search would be done until null
+         *                  termination. Defaults to -1.
+         * \return          True if a match was found. False otherwise.
+         */
+        bool match(const nrex_char* str, nrex_result* captures, int offset = 0, int end = -1) const;
+};
+
+#ifdef NREX_THROW_ERROR
+
+#include <stdexcept>
+
+class nrex_compile_error : std::runtime_error
+{
+    public:
+        nrex_compile_error(const char* message)
+            : std::runtime_error(message)
+        {
+        }
+
+        ~nrex_compile_error() throw()
+        {
+        }
+};
+
+#endif
+
+#endif // NREX_HPP

+ 12 - 0
drivers/nrex/nrex_config.h

@@ -0,0 +1,12 @@
+// Godot-specific configuration
+// To use this, replace nrex_config.h
+
+#include "core/os/memory.h"
+
+#define NREX_UNICODE
+//#define NREX_THROW_ERROR
+
+#define NREX_NEW(X) memnew(X)
+#define NREX_NEW_ARRAY(X, N) memnew_arr(X, N)
+#define NREX_DELETE(X) memdelete(X)
+#define NREX_DELETE_ARRAY(X) memdelete_arr(X)

+ 114 - 0
drivers/nrex/regex.cpp

@@ -0,0 +1,114 @@
+/*************************************************/
+/*  regex.cpp                                    */
+/*************************************************/
+/*            This file is part of:              */
+/*                GODOT ENGINE                   */
+/*************************************************/
+/*       Source code within this file is:        */
+/*  (c) 2007-2010 Juan Linietsky, Ariel Manzur   */
+/*             All Rights Reserved.              */
+/*************************************************/
+
+#include "regex.h"
+#include "nrex.hpp"
+#include "core/os/memory.h"
+
+void RegEx::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile);
+	ObjectTypeDB::bind_method(_MD("find","text","start","end"),&RegEx::find, DEFVAL(0), DEFVAL(-1));
+	ObjectTypeDB::bind_method(_MD("clear"),&RegEx::clear);
+	ObjectTypeDB::bind_method(_MD("is_valid"),&RegEx::is_valid);
+	ObjectTypeDB::bind_method(_MD("get_capture_count"),&RegEx::get_capture_count);
+	ObjectTypeDB::bind_method(_MD("get_capture","capture"),&RegEx::get_capture);
+	ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures);
+
+};
+
+StringArray RegEx::_bind_get_captures() const {
+
+	StringArray ret;
+	int count = get_capture_count();
+	for (int i=0; i<count; i++) {
+
+		String c = get_capture(i);
+		ret.push_back(c);
+	};
+
+	return ret;
+
+};
+
+void RegEx::clear() {
+
+	text.clear();
+	captures.clear();
+	exp.reset();
+
+};
+
+bool RegEx::is_valid() const {
+
+	return exp.valid();
+
+};
+
+int RegEx::get_capture_count() const {
+	
+	return exp.capture_size();
+}
+
+String RegEx::get_capture(int capture) const {
+
+	ERR_FAIL_COND_V( get_capture_count() <= capture, String() );
+
+	return text.substr(captures[capture].start, captures[capture].length);
+
+}
+
+Error RegEx::compile(const String& p_pattern) {
+
+	clear();
+
+	exp.compile(p_pattern.c_str());
+
+	ERR_FAIL_COND_V( !exp.valid(), FAILED );
+
+	captures.resize(exp.capture_size());
+
+	return OK;
+
+};
+
+int RegEx::find(const String& p_text, int p_start, int p_end) const {
+
+	ERR_FAIL_COND_V( !exp.valid(), -1 );
+	ERR_FAIL_COND_V( p_text.length() < p_start, -1 );
+	ERR_FAIL_COND_V( p_text.length() < p_end, -1 );
+
+	bool res = exp.match(p_text.c_str(), &captures[0], p_start, p_end);
+
+	if (res) {
+		text = p_text;
+		return captures[0].start;
+	}
+	text.clear();
+	return -1;
+
+};
+
+RegEx::RegEx(const String& p_pattern) {
+
+	compile(p_pattern);
+
+};
+
+RegEx::RegEx() {
+
+};
+
+RegEx::~RegEx() {
+
+	clear();
+
+};

+ 8 - 11
drivers/trex/regex.h → drivers/nrex/regex.h

@@ -13,34 +13,31 @@
 #define REGEX_H
 
 #include "ustring.h"
-#include "list.h"
+#include "vector.h"
 #include "core/reference.h"
-struct TRex;
+#include "nrex.hpp"
 
 class RegEx : public Reference {
 
 	OBJ_TYPE(RegEx, Reference);
 
 	mutable String text;
-	TRex *exp;
+	mutable Vector<nrex_result> captures;
+	nrex exp;
 
 protected:
 
 	static void _bind_methods();
-
-	int _bind_find(const String& p_text, int p_start = 0, int p_end = -1) const;
 	StringArray _bind_get_captures() const;
+
 public:
 
 	void clear();
-
-	Error compile(const String& p_pattern);
 	bool is_valid() const;
-	bool match(const String& p_text, List<String>* p_captures = NULL, int p_start = 0, int p_end = -1) const;
-	bool find(const String& p_text, int& p_rstart, int &p_rend, List<String>* p_captures = NULL, int p_start = 0, int p_end = -1) const;
 	int get_capture_count() const;
-	Error get_capture_limits(int p_capture, int& p_start, int& p_len) const;
-	String get_capture(int p_idx) const;
+	String get_capture(int capture) const;
+	Error compile(const String& p_pattern);
+	int find(const String& p_text, int p_start = 0, int p_end = -1) const;
 
 	RegEx();
 	RegEx(const String& p_pattern);

+ 4 - 1
drivers/png/SCsub

@@ -27,7 +27,10 @@ if ("neon_enabled" in env and env["neon_enabled"]):
 	if "S_compiler" in env:
 		env_neon['CC'] = env['S_compiler']
 	env_neon.Append(CPPFLAGS=["-DPNG_ARM_NEON"])
-	png_sources.append(env_neon.Object("#drivers/png/filter_neon.S"))
+	import os
+	# Currently .ASM filter_neon.S does not compile on NT.
+	if (os.name!="nt"):
+		png_sources.append(env_neon.Object("#drivers/png/filter_neon.S"))
 
 
 env.drivers_sources+=png_sources

+ 1 - 1
drivers/register_driver_types.cpp

@@ -48,7 +48,7 @@
 #endif
 
 
-#include "drivers/trex/regex.h"
+#include "drivers/nrex/regex.h"
 
 #ifdef MUSEPACK_ENABLED
 #include "mpc/audio_stream_mpc.h"

+ 1 - 1
drivers/speex/audio_stream_speex.cpp

@@ -21,7 +21,7 @@ void AudioStreamSpeex::update() {
 	//printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs);
 	//printf("playing %i, paused %i\n", (int)playing, (int)paused);
 
-	if (!playing || paused || !data.size())
+	if (!active || !playing || paused || !data.size())
 		return;
 
 	/*

+ 0 - 75
drivers/trex/TRexpp.h

@@ -1,75 +0,0 @@
-#ifndef _TREXPP_H_
-#define _TREXPP_H_
-/***************************************************************
-	T-Rex a tiny regular expression library
-
-	Copyright (C) 2003-2004 Alberto Demichelis
-
-	This software is provided 'as-is', without any express 
-	or implied warranty. In no event will the authors be held 
-	liable for any damages arising from the use of this software.
-
-	Permission is granted to anyone to use this software for 
-	any purpose, including commercial applications, and to alter
-	it and redistribute it freely, subject to the following restrictions:
-
-		1. The origin of this software must not be misrepresented;
-		you must not claim that you wrote the original software.
-		If you use this software in a product, an acknowledgment
-		in the product documentation would be appreciated but
-		is not required.
-
-		2. Altered source versions must be plainly marked as such,
-		and must not be misrepresented as being the original software.
-
-		3. This notice may not be removed or altered from any
-		source distribution.
-
-****************************************************************/
-
-extern "C" {
-#include "trex.h"
-}
-
-struct TRexParseException{TRexParseException(const TRexChar *c):desc(c){}const TRexChar *desc;};
-
-class TRexpp {
-public:
-	TRexpp() { _exp = (TRex *)0; }
-	~TRexpp() { CleanUp(); }
-	// compiles a regular expression
-	void Compile(const TRexChar *pattern) { 
-		const TRexChar *error;
-		CleanUp();
-		if(!(_exp = trex_compile(pattern,&error)))
-			throw TRexParseException(error);
-	}
-	// return true if the given text match the expression
-	bool Match(const TRexChar* text) { 
-		return _exp?(trex_match(_exp,text) != 0):false; 
-	}
-	// Searches for the first match of the expression in a zero terminated string
-	bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) { 
-		return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false; 
-	}
-	// Searches for the first match of the expression in a string sarting at text_begin and ending at text_end
-	bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) { 
-		return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false; 
-	}
-	bool GetSubExp(int n, const TRexChar** out_begin, int *out_len)
-	{
-		TRexMatch match;
-		TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False; 
-		if(res) {
-			*out_begin = match.begin;
-			*out_len = match.len;
-			return true;
-		}
-		return false;
-	}
-	int GetSubExpCount() { return _exp?trex_getsubexpcount(_exp):0; }
-private:
-	void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; }
-	TRex *_exp;
-};
-#endif //_TREXPP_H_

+ 0 - 15
drivers/trex/history.txt

@@ -1,15 +0,0 @@
-===version 1.3
--fixed a bug for GCC users(thx Brendan)
-
-===version 1.2
--added word boundary match \b and \B
--added vertical tab escape \v
--\w now also matches '_' (underscore)
--fixed greediness for * and +
-
-===version 1.1 , April 1, 2004
--fixed some minor bug
--added predefined character classes(\w,\W,\s,\S etc...)
-
-===version 1.0 , February 23, 2004
--first public realase

+ 0 - 171
drivers/trex/readme.txt

@@ -1,171 +0,0 @@
-T-REX 1.3 http://tiny-rex.sourceforge.net
-----------------------------------------------------------------------
-	T-Rex a tiny regular expression library
-
-	Copyright (C) 2003-2006 Alberto Demichelis
-
-	This software is provided 'as-is', without any express 
-	or implied warranty. In no event will the authors be held 
-	liable for any damages arising from the use of this software.
-
-	Permission is granted to anyone to use this software for 
-	any purpose, including commercial applications, and to alter
-	it and redistribute it freely, subject to the following restrictions:
-
-		1. The origin of this software must not be misrepresented;
-		you must not claim that you wrote the original software.
-		If you use this software in a product, an acknowledgment
-		in the product documentation would be appreciated but
-		is not required.
-
-		2. Altered source versions must be plainly marked as such,
-		and must not be misrepresented as being the original software.
-
-		3. This notice may not be removed or altered from any
-		source distribution.
-		
-----------------------------------------------------------------------
-TRex implements the following expressions
-
-\	Quote the next metacharacter
-^	Match the beginning of the string
-.	Match any character
-$	Match the end of the string
-|	Alternation
-()	Grouping (creates a capture)
-[]	Character class  
-
-==GREEDY CLOSURES==
-*	   Match 0 or more times
-+	   Match 1 or more times
-?	   Match 1 or 0 times
-{n}    Match exactly n times
-{n,}   Match at least n times
-{n,m}  Match at least n but not more than m times  
-
-==ESCAPE CHARACTERS==
-\t		tab                   (HT, TAB)
-\n		newline               (LF, NL)
-\r		return                (CR)
-\f		form feed             (FF)
-
-==PREDEFINED CLASSES==
-\l		lowercase next char
-\u		uppercase next char
-\a		letters
-\A		non letters
-\w		alphanimeric [0-9a-zA-Z]
-\W		non alphanimeric
-\s		space
-\S		non space
-\d		digits
-\D		non nondigits
-\x		exadecimal digits
-\X		non exadecimal digits
-\c		control charactrs
-\C		non control charactrs
-\p		punctation
-\P		non punctation
-\b		word boundary
-\B		non word boundary
-
-----------------------------------------------------------------------
-API DOC
-----------------------------------------------------------------------
-TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);
-
-compiles an expression and returns a pointer to the compiled version.
-in case of failure returns NULL.The returned object has to be deleted
-through the function trex_free().
-
-pattern
-	a pointer to a zero terminated string containing the pattern that 
-	has to be compiled.
-error
-	apointer to a string pointer that will be set with an error string
-	in case of failure.
-	
-----------------------------------------------------------------------
-void trex_free(TRex *exp)
-
-deletes a expression structure created with trex_compile()
-
-exp
-	the expression structure that has to be deleted
-
-----------------------------------------------------------------------
-TRexBool trex_match(TRex* exp,const TRexChar* text)
-
-returns TRex_True if the string specified in the parameter text is an
-exact match of the expression, otherwise returns TRex_False.
-
-exp
-	the compiled expression
-text
-	the string that has to be tested
-	
-----------------------------------------------------------------------
-TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
-
-searches the first match of the expressin in the string specified in the parameter text.
-if the match is found returns TRex_True and the sets out_begin to the beginning of the
-match and out_end at the end of the match; otherwise returns TRex_False.
-
-exp
-	the compiled expression
-text
-	the string that has to be tested
-out_begin
-	a pointer to a string pointer that will be set with the beginning of the match
-out_end
-	a pointer to a string pointer that will be set with the end of the match
-
-----------------------------------------------------------------------
-TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
-
-searches the first match of the expressin in the string delimited 
-by the parameter text_begin and text_end.
-if the match is found returns TRex_True and the sets out_begin to the beginning of the
-match and out_end at the end of the match; otherwise returns TRex_False.
-
-exp
-	the compiled expression
-text_begin
-	a pointer to the beginnning of the string that has to be tested
-text_end
-	a pointer to the end of the string that has to be tested
-out_begin
-	a pointer to a string pointer that will be set with the beginning of the match
-out_end
-	a pointer to a string pointer that will be set with the end of the match
-	
-----------------------------------------------------------------------
-int trex_getsubexpcount(TRex* exp)
-
-returns the number of sub expressions matched by the expression
-
-exp
-	the compiled expression
-
----------------------------------------------------------------------
-TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *submatch)
-
-retrieve the begin and and pointer to the length of the sub expression indexed
-by n. The result is passed trhough the struct TRexMatch:
-
-typedef struct {
-	const TRexChar *begin;
-	int len;
-} TRexMatch;
-
-the function returns TRex_True if n is valid index otherwise TRex_False.
-
-exp
-	the compiled expression
-n
-	the index of the submatch
-submatch
-	a pointer to structure that will store the result
-	
-this function works also after a match operation has been performend.
-	

+ 0 - 163
drivers/trex/regex.cpp

@@ -1,163 +0,0 @@
-/*************************************************/
-/*  regex.cpp                                    */
-/*************************************************/
-/*            This file is part of:              */
-/*                GODOT ENGINE                   */
-/*************************************************/
-/*       Source code within this file is:        */
-/*  (c) 2007-2010 Juan Linietsky, Ariel Manzur   */
-/*             All Rights Reserved.              */
-/*************************************************/
-
-#include "regex.h"
-
-extern "C" {
-
-#define _UNICODE
-#include "trex.h"
-
-};
-
-void RegEx::_bind_methods() {
-
-	ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile);
-	ObjectTypeDB::bind_method(_MD("find","text", "start","end"),&RegEx::_bind_find, DEFVAL(0), DEFVAL(-1));
-	ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures);
-};
-
-Error RegEx::compile(const String& p_pattern) {
-
-	clear();
-	const TRexChar* error;
-	exp = trex_compile(p_pattern.c_str(), &error);
-	ERR_FAIL_COND_V(!exp, FAILED);
-	return OK;
-};
-
-
-int RegEx::_bind_find(const String& p_text, int p_start, int p_end) const {
-
-	int start, end;
-	bool ret = find(p_text, start, end, NULL, p_start, p_end);
-
-	return ret?start:-1;
-};
-
-bool RegEx::find(const String& p_text, int& p_rstart, int &p_rend, List<String>* p_captures, int p_start, int p_end) const {
-
-	ERR_FAIL_COND_V( !exp, false );
-	text=p_text;
-
-	const CharType* str = p_text.c_str();
-	const CharType* start = str + p_start;
-	const CharType* end = str + (p_end == -1?p_text.size():p_end);
-
-	const CharType* out_begin;
-	const CharType* out_end;
-
-	bool ret = trex_searchrange(exp, start, end, &out_begin, &out_end);
-	if (ret) {
-
-		p_rstart = out_begin - str;
-		p_rend = out_end - str;
-
-		if (p_captures) {
-
-			int count = get_capture_count();
-			for (int i=0; i<count; i++) {
-
-				int start, len;
-				get_capture_limits(i, start, len);
-				p_captures->push_back(p_text.substr(start, len));
-			};
-		};
-	} else {
-
-		p_rstart = -1;
-	};
-
-	return ret;
-};
-
-
-bool RegEx::match(const String& p_text, List<String>* p_captures, int p_start, int p_end) const {
-
-	ERR_FAIL_COND_V( !exp, false );
-
-	int start, end;
-	return find(p_text, start, end, p_captures, p_start, p_end);
-};
-
-int RegEx::get_capture_count() const {
-
-	ERR_FAIL_COND_V( exp == NULL, -1 );
-
-	return trex_getsubexpcount(exp);
-};
-
-Error RegEx::get_capture_limits(int p_capture, int& p_start, int& p_len) const {
-
-	ERR_FAIL_COND_V( exp == NULL, ERR_UNCONFIGURED );
-
-	TRexMatch match;
-	TRexBool res = trex_getsubexp(exp, p_capture, &match);
-	ERR_FAIL_COND_V( !res, FAILED );
-	p_start = (int)(match.begin - text.c_str());
-	p_len = match.len;
-
-	return OK;
-};
-
-String RegEx::get_capture(int p_idx) const {
-
-	ERR_FAIL_COND_V( exp == NULL, "" );
-	int start, len;
-	Error ret = get_capture_limits(p_idx, start, len);
-	ERR_FAIL_COND_V(ret != OK, "");
-	if (len == 0)
-		return "";
-	return text.substr(start, len);
-};
-
-StringArray RegEx::_bind_get_captures() const {
-
-	StringArray ret;
-	int count = get_capture_count();
-	for (int i=0; i<count; i++) {
-
-		String c = get_capture(i);
-		ret.push_back(c);
-	};
-
-	return ret;
-};
-
-bool RegEx::is_valid() const {
-
-	return exp != NULL;
-};
-
-void RegEx::clear() {
-
-	if (exp) {
-
-		trex_free(exp);
-		exp = NULL;
-	};
-};
-
-RegEx::RegEx(const String& p_pattern) {
-
-	exp = NULL;
-	compile(p_pattern);
-};
-
-RegEx::RegEx() {
-
-	exp = NULL;
-};
-
-RegEx::~RegEx() {
-
-	clear();
-};

+ 0 - 41
drivers/trex/test.c

@@ -1,41 +0,0 @@
-#include "trex.h"
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _UNICODE
-#define trex_sprintf swprintf
-#else
-#define trex_sprintf sprintf
-#endif
-
-int main(int argc, char* argv[])
-{
-	const TRexChar *begin,*end;
-	TRexChar sTemp[200];
-	const TRexChar *error = NULL;
-	TRex *x = trex_compile(_TREXC("(x{1,5})xx"),&error);
-	if(x) {
-		trex_sprintf(sTemp,_TREXC("xxxxxxx"));
-		if(trex_search(x,sTemp,&begin,&end))
-		{
-			int i,n = trex_getsubexpcount(x);
-			TRexMatch match;
-			for(i = 0; i < n; i++)
-			{
-				TRexChar t[200];
-				trex_getsubexp(x,i,&match);
-				trex_sprintf(t,_TREXC("[%%d]%%.%ds\n"),match.len);
-				trex_printf(t,i,match.begin);
-			}
-			trex_printf(_TREXC("match! %d sub matches\n"),trex_getsubexpcount(x));
-		}
-		else {
-			trex_printf(_TREXC("no match!\n"));
-		}
-		trex_free(x);
-	}
-	else {
-		trex_printf(_TREXC("compilation error [%s]!\n"),error?error:_TREXC("undefined"));
-	}
-	return 0;
-}

+ 0 - 643
drivers/trex/trex.c

@@ -1,643 +0,0 @@
-	/* see copyright notice in trex.h */
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <setjmp.h>
-#include "trex.h"
-
-#ifdef _UINCODE
-#define scisprint iswprint
-#define scstrlen wcslen
-#define scprintf wprintf
-#define _SC(x) L##c
-#else
-#define scisprint isprint
-#define scstrlen strlen
-#define scprintf printf
-#define _SC(x) (x)
-#endif
-
-#ifdef _DEBUG
-#include <stdio.h>
-
-static const TRexChar *g_nnames[] =
-{
-	_SC("NONE"),_SC("OP_GREEDY"),	_SC("OP_OR"),
-	_SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"),	_SC("OP_CLASS"),
-	_SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
-	_SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
-};
-
-#endif
-#define OP_GREEDY		(MAX_CHAR+1) // * + ? {n}
-#define OP_OR			(MAX_CHAR+2)
-#define OP_EXPR			(MAX_CHAR+3) //parentesis ()
-#define OP_NOCAPEXPR	(MAX_CHAR+4) //parentesis (?:)
-#define OP_DOT			(MAX_CHAR+5)
-#define OP_CLASS		(MAX_CHAR+6)
-#define OP_CCLASS		(MAX_CHAR+7)
-#define OP_NCLASS		(MAX_CHAR+8) //negates class the [^
-#define OP_RANGE		(MAX_CHAR+9)
-#define OP_CHAR			(MAX_CHAR+10)
-#define OP_EOL			(MAX_CHAR+11)
-#define OP_BOL			(MAX_CHAR+12)
-#define OP_WB			(MAX_CHAR+13)
-
-#define TREX_SYMBOL_ANY_CHAR ('.')
-#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
-#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
-#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
-#define TREX_SYMBOL_BRANCH ('|')
-#define TREX_SYMBOL_END_OF_STRING ('$')
-#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
-#define TREX_SYMBOL_ESCAPE_CHAR ('\\')
-
-
-typedef int TRexNodeType;
-
-typedef struct tagTRexNode{
-	TRexNodeType type;
-	int left;
-	int right;
-	int next;
-}TRexNode;
-
-struct TRex{
-	const TRexChar *_eol;
-	const TRexChar *_bol;
-	const TRexChar *_p;
-	int _first;
-	int _op;
-	TRexNode *_nodes;
-	int _nallocated;
-	int _nsize;
-	int _nsubexpr;
-	TRexMatch *_matches;
-	int _currsubexp;
-	void *_jmpbuf;
-	const TRexChar **_error;
-};
-
-static int trex_list(TRex *exp);
-
-static int trex_newnode(TRex *exp, TRexNodeType type)
-{
-	TRexNode n;
-	int newid;
-	n.type = type;
-	n.next = n.right = n.left = -1;
-	if(type == OP_EXPR)
-		n.right = exp->_nsubexpr++;
-	if(exp->_nallocated < (exp->_nsize + 1)) {
-		//int oldsize = exp->_nallocated;
-		exp->_nallocated *= 2;
-		exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
-	}
-	exp->_nodes[exp->_nsize++] = n;
-	newid = exp->_nsize - 1;
-	return (int)newid;
-}
-
-static void trex_error(TRex *exp,const TRexChar *error)
-{
-	if(exp->_error) *exp->_error = error;
-	longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
-}
-
-static void trex_expect(TRex *exp, int n){
-	if((*exp->_p) != n) 
-		trex_error(exp, _SC("expected paren"));
-	exp->_p++;
-}
-
-static TRexChar trex_escapechar(TRex *exp)
-{
-	if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
-		exp->_p++;
-		switch(*exp->_p) {
-		case 'v': exp->_p++; return '\v';
-		case 'n': exp->_p++; return '\n';
-		case 't': exp->_p++; return '\t';
-		case 'r': exp->_p++; return '\r';
-		case 'f': exp->_p++; return '\f';
-		default: return (*exp->_p++);
-		}
-	} else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
-	return (*exp->_p++);
-}
-
-static int trex_charclass(TRex *exp,int classid)
-{
-	int n = trex_newnode(exp,OP_CCLASS);
-	exp->_nodes[n].left = classid;
-	return n;
-}
-
-static int trex_charnode(TRex *exp,TRexBool isclass)
-{
-	TRexChar t;
-	if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
-		exp->_p++;
-		switch(*exp->_p) {
-			case 'n': exp->_p++; return trex_newnode(exp,'\n');
-			case 't': exp->_p++; return trex_newnode(exp,'\t');
-			case 'r': exp->_p++; return trex_newnode(exp,'\r');
-			case 'f': exp->_p++; return trex_newnode(exp,'\f');
-			case 'v': exp->_p++; return trex_newnode(exp,'\v');
-			case 'a': case 'A': case 'w': case 'W': case 's': case 'S': 
-			case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': 
-			case 'p': case 'P': case 'l': case 'u': 
-				{
-				t = *exp->_p; exp->_p++; 
-				return trex_charclass(exp,t);
-				}
-			case 'b': 
-			case 'B':
-				if(!isclass) {
-					int node = trex_newnode(exp,OP_WB);
-					exp->_nodes[node].left = *exp->_p;
-					exp->_p++; 
-					return node;
-				} //else default
-			default: 
-				t = *exp->_p; exp->_p++; 
-				return trex_newnode(exp,t);
-		}
-	}
-	else if(!scisprint(*exp->_p)) {
-		
-		trex_error(exp,_SC("letter expected"));
-	}
-	t = *exp->_p; exp->_p++; 
-	return trex_newnode(exp,t);
-}
-static int trex_class(TRex *exp)
-{
-	int ret = -1;
-	int first = -1,chain;
-	if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
-		ret = trex_newnode(exp,OP_NCLASS);
-		exp->_p++;
-	}else ret = trex_newnode(exp,OP_CLASS);
-	
-	if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
-	chain = ret;
-	while(*exp->_p != ']' && exp->_p != exp->_eol) {
-		if(*exp->_p == '-' && first != -1){ 
-			int r,t;
-			if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
-			r = trex_newnode(exp,OP_RANGE);
-			if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
-			if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
-			exp->_nodes[r].left = exp->_nodes[first].type;
-			t = trex_escapechar(exp);
-			exp->_nodes[r].right = t;
-            exp->_nodes[chain].next = r;
-			chain = r;
-			first = -1;
-		}
-		else{
-			if(first!=-1){
-				int c = first;
-				exp->_nodes[chain].next = c;
-				chain = c;
-				first = trex_charnode(exp,TRex_True);
-			}
-			else{
-				first = trex_charnode(exp,TRex_True);
-			}
-		}
-	}
-	if(first!=-1){
-		int c = first;
-		exp->_nodes[chain].next = c;
-		chain = c;
-		first = -1;
-	}
-	/* hack? */
-	exp->_nodes[ret].left = exp->_nodes[ret].next;
-	exp->_nodes[ret].next = -1;
-	return ret;
-}
-
-static int trex_parsenumber(TRex *exp)
-{
-	int ret = *exp->_p-'0';
-	int positions = 10;
-	exp->_p++;
-	while(isdigit(*exp->_p)) {
-		ret = ret*10+(*exp->_p++-'0');
-		if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
-		positions *= 10;
-	};
-	return ret;
-}
-
-static int trex_element(TRex *exp)
-{
-	int ret = -1;
-	switch(*exp->_p)
-	{
-	case '(': {
-		int expr,newn;
-		exp->_p++;
-
-
-		if(*exp->_p =='?') {
-			exp->_p++;
-			trex_expect(exp,':');
-			expr = trex_newnode(exp,OP_NOCAPEXPR);
-		}
-		else
-			expr = trex_newnode(exp,OP_EXPR);
-		newn = trex_list(exp);
-		exp->_nodes[expr].left = newn;
-		ret = expr;
-		trex_expect(exp,')');
-			  }
-			  break;
-	case '[':
-		exp->_p++;
-		ret = trex_class(exp);
-		trex_expect(exp,']');
-		break;
-	case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
-	case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
-	default:
-		ret = trex_charnode(exp,TRex_False);
-		break;
-	}
-
-	{
-		int op;
-		TRexBool isgreedy = TRex_False;
-		unsigned short p0 = 0, p1 = 0;
-		switch(*exp->_p){
-			case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
-			case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
-			case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
-			case '{':
-				exp->_p++;
-				if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
-				p0 = (unsigned short)trex_parsenumber(exp);
-				/*******************************/
-				switch(*exp->_p) {
-			case '}':
-				p1 = p0; exp->_p++;
-				break;
-			case ',':
-				exp->_p++;
-				p1 = 0xFFFF;
-				if(isdigit(*exp->_p)){
-					p1 = (unsigned short)trex_parsenumber(exp);
-				}
-				trex_expect(exp,'}');
-				break;
-			default:
-				trex_error(exp,_SC(", or } expected"));
-		}
-		/*******************************/
-		isgreedy = TRex_True; 
-		break;
-
-		}
-		if(isgreedy) {
-			int nnode = trex_newnode(exp,OP_GREEDY);
-			op = OP_GREEDY;
-			exp->_nodes[nnode].left = ret;
-			exp->_nodes[nnode].right = ((p0)<<16)|p1;
-			ret = nnode;
-		}
-	}
-	if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
-		int nnode = trex_element(exp);
-		exp->_nodes[ret].next = nnode;
-	}
-
-	return ret;
-}
-
-static int trex_list(TRex *exp)
-{
-	int ret=-1,e;
-	if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
-		exp->_p++;
-		ret = trex_newnode(exp,OP_BOL);
-	}
-	e = trex_element(exp);
-	if(ret != -1) {
-		exp->_nodes[ret].next = e;
-	}
-	else ret = e;
-
-	if(*exp->_p == TREX_SYMBOL_BRANCH) {
-		int temp,tright;
-		exp->_p++;
-		temp = trex_newnode(exp,OP_OR);
-		exp->_nodes[temp].left = ret;
-		tright = trex_list(exp);
-		exp->_nodes[temp].right = tright;
-		ret = temp;
-	}
-	return ret;
-}
-
-static TRexBool trex_matchcclass(int cclass,TRexChar c)
-{
-	switch(cclass) {
-	case 'a': return isalpha(c)?TRex_True:TRex_False;
-	case 'A': return !isalpha(c)?TRex_True:TRex_False;
-	case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
-	case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
-	case 's': return isspace(c)?TRex_True:TRex_False;
-	case 'S': return !isspace(c)?TRex_True:TRex_False;
-	case 'd': return isdigit(c)?TRex_True:TRex_False;
-	case 'D': return !isdigit(c)?TRex_True:TRex_False;
-	case 'x': return isxdigit(c)?TRex_True:TRex_False;
-	case 'X': return !isxdigit(c)?TRex_True:TRex_False;
-	case 'c': return iscntrl(c)?TRex_True:TRex_False;
-	case 'C': return !iscntrl(c)?TRex_True:TRex_False;
-	case 'p': return ispunct(c)?TRex_True:TRex_False;
-	case 'P': return !ispunct(c)?TRex_True:TRex_False;
-	case 'l': return islower(c)?TRex_True:TRex_False;
-	case 'u': return isupper(c)?TRex_True:TRex_False;
-	}
-	return TRex_False; /*cannot happen*/
-}
-
-static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
-{
-	do {
-		switch(node->type) {
-			case OP_RANGE:
-				if(c >= node->left && c <= node->right) return TRex_True;
-				break;
-			case OP_CCLASS:
-				if(trex_matchcclass(node->left,c)) return TRex_True;
-				break;
-			default:
-				if(c == node->type)return TRex_True;
-		}
-	} while((node->next != -1) && (node = &exp->_nodes[node->next]));
-	return TRex_False;
-}
-
-static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
-{
-	
-	TRexNodeType type = node->type;
-	switch(type) {
-	case OP_GREEDY: {
-		//TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
-		TRexNode *greedystop = NULL;
-		int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
-		const TRexChar *s=str, *good = str;
-
-		if(node->next != -1) {
-			greedystop = &exp->_nodes[node->next];
-		}
-		else {
-			greedystop = next;
-		}
-
-		while((nmaches == 0xFFFF || nmaches < p1)) {
-
-			const TRexChar *stop;
-			if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
-				break;
-			nmaches++;
-			good=s;
-			if(greedystop) {
-				//checks that 0 matches satisfy the expression(if so skips)
-				//if not would always stop(for instance if is a '?')
-				if(greedystop->type != OP_GREEDY ||
-				(greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
-				{
-					TRexNode *gnext = NULL;
-					if(greedystop->next != -1) {
-						gnext = &exp->_nodes[greedystop->next];
-					}else if(next && next->next != -1){
-						gnext = &exp->_nodes[next->next];
-					}
-					stop = trex_matchnode(exp,greedystop,s,gnext);
-					if(stop) {
-						//if satisfied stop it
-						if(p0 == p1 && p0 == nmaches) break;
-						else if(nmaches >= p0 && p1 == 0xFFFF) break;
-						else if(nmaches >= p0 && nmaches <= p1) break;
-					}
-				}
-			}
-			
-			if(s >= exp->_eol)
-				break;
-		}
-		if(p0 == p1 && p0 == nmaches) return good;
-		else if(nmaches >= p0 && p1 == 0xFFFF) return good;
-		else if(nmaches >= p0 && nmaches <= p1) return good;
-		return NULL;
-	}
-	case OP_OR: {
-			const TRexChar *asd = str;
-			TRexNode *temp=&exp->_nodes[node->left];
-			while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
-				if(temp->next != -1)
-					temp = &exp->_nodes[temp->next];
-				else
-					return asd;
-			}
-			asd = str;
-			temp = &exp->_nodes[node->right];
-			while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
-				if(temp->next != -1)
-					temp = &exp->_nodes[temp->next];
-				else
-					return asd;
-			}
-			return NULL;
-			break;
-	}
-	case OP_EXPR:
-	case OP_NOCAPEXPR:{
-			TRexNode *n = &exp->_nodes[node->left];
-			const TRexChar *cur = str;
-			int capture = -1;
-			if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
-				capture = exp->_currsubexp;
-				exp->_matches[capture].begin = cur;
-				exp->_currsubexp++;
-			}
-			
-			do {
-				TRexNode *subnext = NULL;
-				if(n->next != -1) {
-					subnext = &exp->_nodes[n->next];
-				}else {
-					subnext = next;
-				}
-				if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
-					if(capture != -1){
-						exp->_matches[capture].begin = 0;
-						exp->_matches[capture].len = 0;
-					}
-					return NULL;
-				}
-			} while((n->next != -1) && (n = &exp->_nodes[n->next]));
-
-			if(capture != -1) 
-				exp->_matches[capture].len = cur - exp->_matches[capture].begin;
-			return cur;
-	}				 
-	case OP_WB:
-		if((str == exp->_bol && !isspace(*str))
-		 || (str == exp->_eol && !isspace(*(str-1)))
-		 || (!isspace(*str) && isspace(*(str+1)))
-		 || (isspace(*str) && !isspace(*(str+1))) ) {
-			return (node->left == 'b')?str:NULL;
-		}
-		return (node->left == 'b')?NULL:str;
-	case OP_BOL:
-		if(str == exp->_bol) return str;
-		return NULL;
-	case OP_EOL:
-		if(str == exp->_eol) return str;
-		return NULL;
-	case OP_DOT:{
-		*str++;
-				}
-		return str;
-	case OP_NCLASS:
-	case OP_CLASS:
-		if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
-			*str++;
-			return str;
-		}
-		return NULL;
-	case OP_CCLASS:
-		if(trex_matchcclass(node->left,*str)) {
-			*str++;
-			return str;
-		}
-		return NULL;
-	default: /* char */
-		if(*str != node->type) return NULL;
-		*str++;
-		return str;
-	}
-	return NULL;
-}
-
-/* public api */
-TRex *trex_compile(const TRexChar *pattern,const TRexChar **error)
-{
-	TRex *exp = (TRex *)malloc(sizeof(TRex));
-	exp->_eol = exp->_bol = NULL;
-	exp->_p = pattern;
-	exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
-	exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
-	exp->_nsize = 0;
-	exp->_matches = 0;
-	exp->_nsubexpr = 0;
-	exp->_first = trex_newnode(exp,OP_EXPR);
-	exp->_error = error;
-	exp->_jmpbuf = malloc(sizeof(jmp_buf));
-	if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
-		int res = trex_list(exp);
-		exp->_nodes[exp->_first].left = res;
-		if(*exp->_p!='\0')
-			trex_error(exp,_SC("unexpected character"));
-#ifdef _DEBUG
-		{
-			int nsize,i;
-			TRexNode *t;
-			nsize = exp->_nsize;
-			t = &exp->_nodes[0];
-			scprintf(_SC("\n"));
-			for(i = 0;i < nsize; i++) {
-				if(exp->_nodes[i].type>MAX_CHAR)
-					scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
-				else
-					scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
-				scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
-			}
-			scprintf(_SC("\n"));
-		}
-#endif
-		exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
-		memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
-	}
-	else{
-		trex_free(exp);
-		return NULL;
-	}
-	return exp;
-}
-
-void trex_free(TRex *exp)
-{
-	if(exp)	{
-		if(exp->_nodes) free(exp->_nodes);
-		if(exp->_jmpbuf) free(exp->_jmpbuf);
-		if(exp->_matches) free(exp->_matches);
-		free(exp);
-	}
-}
-
-TRexBool trex_match(TRex* exp,const TRexChar* text)
-{
-	const TRexChar* res = NULL;
-	exp->_bol = text;
-	exp->_eol = text + scstrlen(text);
-	exp->_currsubexp = 0;
-	res = trex_matchnode(exp,exp->_nodes,text,NULL);
-	if(res == NULL || res != exp->_eol)
-		return TRex_False;
-	return TRex_True;
-}
-
-TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
-{
-	const TRexChar *cur = NULL;
-	int node = exp->_first;
-	if(text_begin >= text_end) return TRex_False;
-	exp->_bol = text_begin;
-	exp->_eol = text_end;
-	do {
-		cur = text_begin;
-		while(node != -1) {
-			exp->_currsubexp = 0;
-			cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
-			if(!cur)
-				break;
-			node = exp->_nodes[node].next;
-		}
-		*text_begin++;
-	} while(cur == NULL && text_begin != text_end);
-
-	if(cur == NULL)
-		return TRex_False;
-
-	--text_begin;
-
-	if(out_begin) *out_begin = text_begin;
-	if(out_end) *out_end = cur;
-	return TRex_True;
-}
-
-TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
-{
-	return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
-}
-
-int trex_getsubexpcount(TRex* exp)
-{
-	return exp->_nsubexpr;
-}
-
-TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
-{
-	if( n<0 || n >= exp->_nsubexpr) return TRex_False;
-	*subexp = exp->_matches[n];
-	return TRex_True;
-}
-

+ 0 - 70
drivers/trex/trex.h

@@ -1,70 +0,0 @@
-#ifndef _TREX_H_
-#define _TREX_H_
-/***************************************************************
-	T-Rex a tiny regular expression library
-
-	Copyright (C) 2003-2006 Alberto Demichelis
-
-	This software is provided 'as-is', without any express 
-	or implied warranty. In no event will the authors be held 
-	liable for any damages arising from the use of this software.
-
-	Permission is granted to anyone to use this software for 
-	any purpose, including commercial applications, and to alter
-	it and redistribute it freely, subject to the following restrictions:
-
-		1. The origin of this software must not be misrepresented;
-		you must not claim that you wrote the original software.
-		If you use this software in a product, an acknowledgment
-		in the product documentation would be appreciated but
-		is not required.
-
-		2. Altered source versions must be plainly marked as such,
-		and must not be misrepresented as being the original software.
-
-		3. This notice may not be removed or altered from any
-		source distribution.
-
-****************************************************************/
-
-#define _UNICODE
-
-
-#ifdef _UNICODE
-#define TRexChar wchar_t
-#define MAX_CHAR 0xFFFF
-#define _TREXC(c) L##c 
-#define trex_strlen wcslen
-#define trex_printf wprintf
-#else
-#define TRexChar char
-#define MAX_CHAR 0xFF
-#define _TREXC(c) (c) 
-#define trex_strlen strlen
-#define trex_printf printf
-#endif
-
-#ifndef TREX_API
-#define TREX_API extern
-#endif
-
-#define TRex_True 1
-#define TRex_False 0
-
-typedef unsigned int TRexBool;
-typedef struct TRex TRex;
-
-typedef struct {
-	const TRexChar *begin;
-	int len;
-} TRexMatch;
-
-TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);
-TREX_API void trex_free(TRex *exp);
-TREX_API TRexBool trex_match(TRex* exp,const TRexChar* text);
-TREX_API TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
-TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end);
-TREX_API int trex_getsubexpcount(TRex* exp);
-TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
-
-#endif

+ 14 - 0
drivers/unix/os_unix.cpp

@@ -57,8 +57,14 @@
 #include <errno.h>
 #include <assert.h>
 #include "globals.h"
+
+extern bool _print_error_enabled;
+
 void OS_Unix::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
 
+	if (!_print_error_enabled)
+		return;
+
 	if (p_rationale && p_rationale[0]) {
 
 		print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
@@ -217,6 +223,14 @@ uint64_t OS_Unix::get_unix_time() const {
 	return time(NULL);
 };
 
+uint64_t OS_Unix::get_system_time_msec() const {
+	struct timeval tv_now;
+	gettimeofday(&tv_now, NULL);
+	localtime(&tv_now.tv_usec);
+	uint64_t msec = tv_now.tv_usec/1000;
+	return msec;
+}
+
 
 OS::Date OS_Unix::get_date(bool utc) const {
 

+ 1 - 0
drivers/unix/os_unix.h

@@ -93,6 +93,7 @@ public:
 	virtual TimeZoneInfo get_time_zone_info() const;
 
 	virtual uint64_t get_unix_time() const;
+	virtual uint64_t get_system_time_msec() const;
 
 	virtual void delay_usec(uint32_t p_usec) const; 
 	virtual uint64_t get_ticks_usec() const;

+ 1 - 1
drivers/vorbis/audio_stream_ogg_vorbis.cpp

@@ -232,7 +232,7 @@ void AudioStreamOGGVorbis::seek_pos(float p_time) {
 
 	if (!playing)
 		return;
-	bool ok = ov_time_seek(&vf,p_time*1000)==0;
+	bool ok = ov_time_seek(&vf,p_time)==0;
 	ERR_FAIL_COND(!ok);
 	frames_mixed=stream_srate*p_time;
 }

+ 9 - 6
main/main.cpp

@@ -518,14 +518,14 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
 	}
 
 
-
+	GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048);
 	if (debug_mode == "remote") {
 
 		ScriptDebuggerRemote *sdr = memnew( ScriptDebuggerRemote );
 		uint16_t debug_port = GLOBAL_DEF("debug/remote_port",6007);
 		if (debug_host.find(":")!=-1) {
-		    debug_port=debug_host.get_slice(":",1).to_int();
-		    debug_host=debug_host.get_slice(":",0);
+		    debug_port=debug_host.get_slicec(':',1).to_int();
+		    debug_host=debug_host.get_slicec(':',0);
 		}
 		Error derr = sdr->connect_to_host(debug_host,debug_port);
 
@@ -546,8 +546,8 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
 		file_access_network_client=memnew(FileAccessNetworkClient);
 		int port;
 		if (remotefs.find(":")!=-1) {
-			port=remotefs.get_slice(":",1).to_int();
-			remotefs=remotefs.get_slice(":",0);
+			port=remotefs.get_slicec(':',1).to_int();
+			remotefs=remotefs.get_slicec(':',0);
 		} else {
 			port=6010;
 		}
@@ -605,6 +605,9 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
 	if (bool(Globals::get_singleton()->get("application/disable_stdout"))) {
 		quiet_stdout=true;
 	}
+	if (bool(Globals::get_singleton()->get("application/disable_stderr"))) {
+		_print_error_enabled = false;
+	};
 
 	if (quiet_stdout)
 		_print_line_enabled=false;
@@ -1219,7 +1222,7 @@ bool Main::start() {
 						String s = E->get().name;
 						if (!s.begins_with("autoload/"))
 							continue;
-						String name = s.get_slice("/",1);
+						String name = s.get_slicec('/',1);
 						String path = Globals::get_singleton()->get(s);
 						RES res = ResourceLoader::load(path);
 						ERR_EXPLAIN("Can't autoload: "+path);

+ 464 - 82
modules/gdscript/gd_editor.cpp

@@ -29,6 +29,7 @@
 #include "gd_script.h"
 #include "gd_compiler.h"
 #include "globals.h"
+#include "os/file_access.h"
 
 void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
 
@@ -238,26 +239,26 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p
 	if (_debug_parse_err_line>=0)
 		return;
 
-    ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
-    int l = _debug_call_stack_pos - p_level -1;
+	ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+	int l = _debug_call_stack_pos - p_level -1;
 
 
-    GDInstance *instance = _call_stack[l].instance;
+	GDInstance *instance = _call_stack[l].instance;
 
-    if (!instance)
-	return;
+	if (!instance)
+		return;
 
-    Ref<GDScript> script = instance->get_script();
-    ERR_FAIL_COND( script.is_null() );
+	Ref<GDScript> script = instance->get_script();
+	ERR_FAIL_COND( script.is_null() );
 
 
-    const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
+	const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
 
-    for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
+	for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
 
-	p_members->push_back(E->key());
-	p_values->push_back( instance->debug_get_member_by_index(E->get().index));
-    }
+		p_members->push_back(E->key());
+		p_values->push_back( instance->debug_get_member_by_index(E->get().index));
+	}
 
 }
 void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
@@ -317,6 +318,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
 struct GDCompletionIdentifier {
 
 	StringName obj_type;
+	Ref<GDScript> script;
 	Variant::Type type;
 	Variant value; //im case there is a value, also return it
 };
@@ -446,7 +448,7 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
 						base_class=base_class->subclasses[subclass];
 					} else {
 
-						print_line("Could not find subclass: "+subclass);
+						//print_line("Could not find subclass: "+subclass);
 						return _get_type_from_class(context); //fail please
 					}
 				}
@@ -631,7 +633,9 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
 						//try calling the function if constant and all args are constant, should not crash..
 						Object *baseptr = base.value;
 
-						if (baseptr && mb->is_const() && pi.type==Variant::OBJECT) {
+
+						if (mb->is_const() && pi.type==Variant::OBJECT) {
+
 							bool all_valid=true;
 							Vector<Variant> args;
 							for(int i=2;i<op->arguments.size();i++) {
@@ -648,25 +652,88 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
 									all_valid=false;
 								}
 							}
-							if (all_valid) {
-								Vector<const Variant*> argptr;
-								for(int i=0;i<args.size();i++) {
-									argptr.push_back(&args[i]);
-								}
 
-								Variant::CallError ce;
-								Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);
+							if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) {
+
+								String arg1=args[0];
+								if (arg1.begins_with("/root/")) {
+									String which = arg1.get_slice("/",2);
+									if (which!="") {
+										List<PropertyInfo> props;
+										Globals::get_singleton()->get_property_list(&props);
+										//print_line("find singleton");
+
+										for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+
+											String s = E->get().name;
+											if (!s.begins_with("autoload/"))
+												continue;
+											//print_line("found "+s);
+											String name = s.get_slice("/",1);
+											//print_line("name: "+name+", which: "+which);
+											if (name==which) {
+												String script = Globals::get_singleton()->get(s);
 
+												if (!script.begins_with("res://")) {
+													script="res://"+script;
+												}
 
-								if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {
+												if (!script.ends_with(".gd")) {
+													//not a script, try find the script anyway,
+													//may have some success
+													script=script.basename()+".gd";
+												}
 
-									if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {
+												if (FileAccess::exists(script)) {
 
-										r_type=_get_type_from_variant(ret);
-										return true;
+													//print_line("is a script");
+
+
+													Ref<Script> scr;
+													if (ScriptCodeCompletionCache::get_sigleton())
+														scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script);
+													else
+														scr = ResourceLoader::load(script);
+
+
+													r_type.obj_type="Node";
+													r_type.type=Variant::OBJECT;
+													r_type.script=scr;
+													r_type.value=Variant();
+
+													return true;
+
+												}
+											}
+										}
 									}
 								}
+							}
+
+
+
+							if (baseptr) {
 
+								if (all_valid) {
+									Vector<const Variant*> argptr;
+									for(int i=0;i<args.size();i++) {
+										argptr.push_back(&args[i]);
+									}
+
+									Variant::CallError ce;
+									Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);
+
+
+									if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {
+
+										if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {
+
+											r_type=_get_type_from_variant(ret);
+											return true;
+										}
+									}
+
+								}
 							}
 						}
 
@@ -1281,6 +1348,7 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid
 static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set<String>& result, String& arghint) {
 
 
+	//print_line("find type arguments?");
 	if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) {
 
 		List<PropertyInfo> pinfo;
@@ -1301,33 +1369,233 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
 
 
 		MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
-		if (!m)
-			return;
+		if (!m) {
+			//not in static method, see script
+
+			//print_line("not in static: "+String(p_method));
+			Ref<GDScript> on_script;
+
+			if (id.value.get_type()) {
+				Object *obj=id.value;
+
+
+				if (obj) {
+
+
+					GDScript *scr = obj->cast_to<GDScript>();
+					if (scr) {
+						while (scr) {
+
+							for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+								if (E->get().is_static() && p_method==E->get().get_name()) {
+									arghint="static func "+String(p_method)+"(";
+									for(int i=0;i<E->get().get_argument_count();i++) {
+										if (i>0)
+											arghint+=", ";
+										else
+											arghint+=" ";
+										if (i==p_argidx) {
+											arghint+=String::chr(0xFFFF);
+										}
+										arghint+="var "+E->get().get_argument_name(i);
+										int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count();
+										if (i>=deffrom) {
+											int defidx = deffrom-i;
+											if (defidx>=0 && defidx<E->get().get_default_argument_count()) {
+												arghint+="="+E->get().get_default_argument(defidx).get_construct_string();
+											}
+										}
+										if (i==p_argidx) {
+											arghint+=String::chr(0xFFFF);
+										}
+									}
+									arghint+=")";
+									return; //found
+								}
+							}
+
+							if (scr->get_base().is_valid())
+								scr=scr->get_base().ptr();
+							else
+								scr=NULL;
+						}
+					} else {
+						on_script=obj->get_script();
+					}
+				}
+			}
+
+			//print_line("but it has a script?");
+			if (!on_script.is_valid() && id.script.is_valid()) {
+				//print_line("yes");
+				on_script=id.script;
+			}
 
-		if (p_method.operator String()=="connect") {
+			if (on_script.is_valid()) {
 
+				GDScript *scr = on_script.ptr();
+				if (scr) {
+					while (scr) {
 
-			if (p_argidx==0) {
-				List<MethodInfo> sigs;
-				ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
-				for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
-					result.insert("\""+E->get().name+"\"");
+						String code = scr->get_source_code();
+						//print_line("has source code!");
+
+						if (code!="") {
+							//if there is code, parse it. This way is slower but updates in real-time
+							GDParser p;
+							//Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+							Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
+
+							if (err==OK) {
+								//print_line("checking the functions...");
+								//only if ok, otherwise use what is cached on the script
+								//GDParser::ClassNode *base = p.
+								const GDParser::Node *root = p.get_parse_tree();
+								ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS);
+
+								const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+
+								const GDParser::FunctionNode* func=NULL;
+								bool st=false;
+
+								for(int i=0;i<cl->functions.size();i++) {
+									//print_line(String(cl->functions[i]->name)+" vs "+String(p_method));
+									if (cl->functions[i]->name==p_method) {
+										func=cl->functions[i];
+									}
+								}
+
+								for(int i=0;i<cl->static_functions.size();i++) {
+
+									//print_line(String(cl->static_functions[i]->name)+" vs "+String(p_method));
+									if (cl->static_functions[i]->name==p_method) {
+										func=cl->static_functions[i];
+										st=true;
+									}
+
+								}
+
+								if (func) {
+
+									arghint="func "+String(p_method)+"(";
+									if (st)
+										arghint="static "+arghint;
+									for(int i=0;i<func->arguments.size();i++) {
+										if (i>0)
+											arghint+=", ";
+										else
+											arghint+=" ";
+										if (i==p_argidx) {
+											arghint+=String::chr(0xFFFF);
+										}
+										arghint+="var "+String(func->arguments[i]);
+										int deffrom = func->arguments.size()-func->default_values.size();
+										if (i>=deffrom) {
+
+											int defidx = deffrom-i;
+
+											if (defidx>=0 && defidx<func->default_values.size() && func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) {
+												const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(func->default_values[defidx]);
+												if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+													const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(op->arguments[1]);
+													arghint+="="+cn->value.get_construct_string();
+												}
+											}
+										}
+										if (i==p_argidx) {
+											arghint+=String::chr(0xFFFF);
+										}
+									}
+
+									arghint+=" )";
+									return;
+								}
+							} else {
+								//print_line("failed parsing?");
+								code="";
+							}
+
+						}
+
+						if (code=="") {
+
+							for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+								if (p_method==E->get().get_name()) {
+									arghint="func "+String(p_method)+"(";
+									for(int i=0;i<E->get().get_argument_count();i++) {
+										if (i>0)
+											arghint+=", ";
+										else
+											arghint+=" ";
+										if (i==p_argidx) {
+											arghint+=String::chr(0xFFFF);
+										}
+										arghint+="var "+E->get().get_argument_name(i);
+										int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count();
+										if (i>=deffrom) {
+											int defidx = deffrom-i;
+											if (defidx>=0 && defidx<E->get().get_default_argument_count()) {
+												arghint+="="+E->get().get_default_argument(defidx).get_construct_string();
+											}
+										}
+										if (i==p_argidx) {
+											arghint+=String::chr(0xFFFF);
+										}
+									}
+									arghint+=")";
+									return; //found
+								}
+							}
+#if 0
+							//use class directly, no code was found
+							if (!isfunction) {
+								for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+									options.insert(E->key());
+								}
+							}
+							for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+								options.insert(String(E->key())+"(");
+							}
+
+							for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) {
+								options.insert(E->get());
+							}
+#endif
+						}
+
+						if (scr->get_base().is_valid())
+							scr=scr->get_base().ptr();
+						else
+							scr=NULL;
+					}
 				}
 			}
-			/*if (p_argidx==2) {
 
-				ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR);
-				const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
-				if (op->arguments.size()>)
 
-			}*/		
 		} else {
+			//regular method
+
+			if (p_method.operator String()=="connect") {
+
+
+				if (p_argidx==0) {
+					List<MethodInfo> sigs;
+					ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
+					for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
+						result.insert("\""+E->get().name+"\"");
+					}
+				}
+				/*if (p_argidx==2) {
+
+					ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR);
+					const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
+					if (op->arguments.size()>)
 
-			Object *obj=id.value;
-			if (obj) {
-				List<String> options;
-				obj->get_argument_options(p_method,p_argidx,&options);
-				if (obj->is_type("Node") && p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node")) {
+				}*/
+			} else {
+
+				if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) {
 
 					List<PropertyInfo> props;
 					Globals::get_singleton()->get_property_list(&props);
@@ -1339,55 +1607,62 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
 							continue;
 					//	print_line("found "+s);
 						String name = s.get_slice("/",1);
-						options.push_back("\"/root/"+name+"\"");
+						result.insert("\"/root/"+name+"\"");
 					}
 				}
-				for(List<String>::Element *E=options.front();E;E=E->next()) {
 
-					result.insert(E->get());
+				Object *obj=id.value;
+				if (obj) {
+					List<String> options;
+					obj->get_argument_options(p_method,p_argidx,&options);
+
+					for(List<String>::Element *E=options.front();E;E=E->next()) {
+
+						result.insert(E->get());
+					}
 				}
+
 			}
 
-		}
+			arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
 
-		arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
+			for(int i=0;i<m->get_argument_count();i++) {
+				if (i>0)
+					arghint+=", ";
+				else
+					arghint+=" ";
 
-		for(int i=0;i<m->get_argument_count();i++) {
-			if (i>0)
-				arghint+=", ";
-			else
-				arghint+=" ";
+				if (i==p_argidx) {
+					arghint+=String::chr(0xFFFF);
+				}
+				String n = m->get_argument_info(i).name;
+				int dp = n.find(":");
+				if (dp!=-1)
+					n=n.substr(0,dp);
+				arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n;
+				int deffrom = m->get_argument_count()-m->get_default_argument_count();
 
-			if (i==p_argidx) {
-				arghint+=String::chr(0xFFFF);
-			}
-			String n = m->get_argument_info(i).name;
-			int dp = n.find(":");
-			if (dp!=-1)
-				n=n.substr(0,dp);
-			arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n;
-			int deffrom = m->get_argument_count()-m->get_default_argument_count();
 
+				if (i>=deffrom) {
+					int defidx = i-deffrom;
 
-			if (i>=deffrom) {
-				int defidx = i-deffrom;
+					if (defidx>=0 && defidx<m->get_default_argument_count()) {
+						Variant v= m->get_default_argument(i);
+						arghint+="="+v.get_construct_string();
+					}
+				}
 
-				if (defidx>=0 && defidx<m->get_default_argument_count()) {
-					Variant v= m->get_default_argument(i);
-					arghint+="="+v.get_construct_string();
+				if (i==p_argidx) {
+					arghint+=String::chr(0xFFFF);
 				}
-			}
 
-			if (i==p_argidx) {
-				arghint+=String::chr(0xFFFF);
 			}
-
-		}
-		if (m->get_argument_count()>0)
-			arghint+=" ";
+			if (m->get_argument_count()>0)
+				arghint+=" ";
 
 
-		arghint+=")";
+			arghint+=")";
+		}
 
 	}
 }
@@ -1434,7 +1709,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
 		arghint+=")";
 
 	} else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
-		//complete built-in function
+		//complete constructor
 		const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]);
 
 		List<MethodInfo> mil;
@@ -1569,7 +1844,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
 
 			}
 		} else {
-
+			//indexed lookup
 
 			GDCompletionIdentifier ci;
 			if (_guess_expression_type(context,op->arguments[0],p_line,ci)) {
@@ -1735,20 +2010,123 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
 
 				if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
 
+					Ref<GDScript> on_script;
 
 					if (t.value.get_type()) {
 						Object *obj=t.value;
+
+
 						if (obj) {
+
+
 							GDScript *scr = obj->cast_to<GDScript>();
+							if (scr) {
+								while (scr) {
+
+									if (!isfunction) {
+										for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+											options.insert(E->key());
+										}
+									}
+									for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+										if (E->get().is_static())
+											options.insert(E->key());
+									}
+
+									if (scr->get_base().is_valid())
+										scr=scr->get_base().ptr();
+									else
+										scr=NULL;
+								}
+							} else {
+								on_script=obj->get_script();
+							}
+						}
+					}
+
+
+					if (!on_script.is_valid() && t.script.is_valid()) {
+						on_script=t.script;
+					}
+
+					if (on_script.is_valid()) {
+
+						GDScript *scr = on_script.ptr();
+						if (scr) {
 							while (scr) {
 
-								if (!isfunction) {
-									for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
-										options.insert(E->key());
+								String code = scr->get_source_code();
+
+								if (code!="") {
+									//if there is code, parse it. This way is slower but updates in real-time
+									GDParser p;
+									//Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+									Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
+
+									if (err==OK) {
+										//only if ok, otherwise use what is cached on the script
+										//GDParser::ClassNode *base = p.
+										const GDParser::Node *root = p.get_parse_tree();
+										ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_PARSE_ERROR);
+
+										const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+
+										for(int i=0;i<cl->functions.size();i++) {
+
+											if (cl->functions[i]->arguments.size())
+												options.insert(String(cl->functions[i]->name)+"(");
+											else
+												options.insert(String(cl->functions[i]->name)+"()");
+										}
+
+										for(int i=0;i<cl->static_functions.size();i++) {
+
+											if (cl->static_functions[i]->arguments.size())
+												options.insert(String(cl->static_functions[i]->name)+"(");
+											else
+												options.insert(String(cl->static_functions[i]->name)+"()");
+
+										}
+
+										if (!isfunction) {
+											for(int i=0;i<cl->variables.size();i++) {
+
+												options.insert(String(cl->variables[i].identifier));
+											}
+
+											for(int i=0;i<cl->constant_expressions.size();i++) {
+
+												options.insert(String(cl->constant_expressions[i].identifier));
+											}
+
+										}
+
+
+									} else {
+										code=""; //well, then no code
 									}
+
 								}
-								for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
-									options.insert(E->key());
+
+								if (code=="") {
+									//use class directly, no code was found
+									if (!isfunction) {
+										for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+											options.insert(E->key());
+										}
+									}
+									for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+										if (E->get().get_argument_count())
+											options.insert(String(E->key())+"()");
+										else
+											options.insert(String(E->key())+"(");
+
+									}
+
+									for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) {
+										options.insert(E->get());
+									}
 								}
 
 								if (scr->get_base().is_valid())
@@ -1760,6 +2138,10 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
 					}
 
 
+
+
+
+
 					if (!isfunction) {
 						ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
 					}

+ 27 - 9
modules/gdscript/gd_parser.cpp

@@ -2315,6 +2315,17 @@ void GDParser::_parse_class(ClassNode *p_class) {
 
 								case Variant::INT: {
 
+									if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FLAGS") {
+
+										current_export.hint=PROPERTY_HINT_ALL_FLAGS;
+										tokenizer->advance();
+										if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+											_set_error("Expected ')' in hint.");
+											return;
+										}
+										break;
+									}
+
 									if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) {
 										//enumeration
 										current_export.hint=PROPERTY_HINT_ENUM;
@@ -2542,16 +2553,23 @@ void GDParser::_parse_class(ClassNode *p_class) {
 					} else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
 
 						String identifier = tokenizer->get_token_identifier();
-						if (!ObjectTypeDB::is_type(identifier,"Resource")) {
-
-							current_export=PropertyInfo();
-							_set_error("Export hint not a type or resource.");
+						if (identifier == "flag") {
+							current_export.type=Variant::INT;
+							current_export.hint=PROPERTY_HINT_ALL_FLAGS;
+						}else if (identifier == "multiline"){
+							current_export.type=Variant::STRING;
+							current_export.hint=PROPERTY_HINT_MULTILINE_TEXT;
+						} else {
+							if (!ObjectTypeDB::is_type(identifier,"Resource")) {
+	
+								current_export=PropertyInfo();
+								_set_error("Export hint not a type or resource.");
+							}
+	
+							current_export.type=Variant::OBJECT;
+							current_export.hint=PROPERTY_HINT_RESOURCE_TYPE;
+							current_export.hint_string=identifier;
 						}
-
-						current_export.type=Variant::OBJECT;
-						current_export.hint=PROPERTY_HINT_RESOURCE_TYPE;
-						current_export.hint_string=identifier;
-
 						tokenizer->advance();
 					}
 

+ 10 - 2
modules/gdscript/gd_script.cpp

@@ -1977,9 +1977,17 @@ void GDScript::_bind_methods() {
 
 	ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new"));	
 
+	ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code);
+
 }
 
 
+Vector<uint8_t> GDScript::get_as_byte_code() const {
+
+	GDTokenizerBuffer tokenizer;
+	return tokenizer.parse_code_string(source);
+};
+
 
 Error GDScript::load_byte_code(const String& p_path) {
 
@@ -2556,9 +2564,9 @@ void GDScriptLanguage::init() {
 
 	//populate native classes
 
-	List<String> class_list;
+	List<StringName> class_list;
 	ObjectTypeDB::get_type_list(&class_list);
-	for(List<String>::Element *E=class_list.front();E;E=E->next()) {
+	for(List<StringName>::Element *E=class_list.front();E;E=E->next()) {
 
 		StringName n = E->get();
 		String s = String(n);

+ 15 - 0
modules/gdscript/gd_script.h

@@ -349,6 +349,8 @@ public:
 	Error load_source_code(const String& p_path);
 	Error load_byte_code(const String& p_path);
 
+	Vector<uint8_t> get_as_byte_code() const;
+
 	virtual ScriptLanguage *get_language() const;
 
 	GDScript();
@@ -473,6 +475,19 @@ public:
     }
 
 
+	virtual Vector<StackInfo> debug_get_current_stack_info() {
+	    if (Thread::get_main_ID()!=Thread::get_caller_ID())
+		return Vector<StackInfo>();
+
+		Vector<StackInfo> csi;
+		csi.resize(_debug_call_stack_pos);
+		for(int i=0;i<_debug_call_stack_pos;i++) {
+			csi[_debug_call_stack_pos-i-1].line=_call_stack[i].line?*_call_stack[i].line:0;
+			csi[_debug_call_stack_pos-i-1].script=Ref<GDScript>(_call_stack[i].function->get_script());
+		}
+		return csi;
+	}
+
 	struct {
 
 		StringName _init;

+ 7 - 1
modules/gdscript/gd_tokenizer.cpp

@@ -97,6 +97,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
 "preload",
 "assert",
 "yield",
+"signal",
 "'['",
 "']'",
 "'{'",
@@ -642,6 +643,11 @@ void GDTokenizerText::_advance() {
 						str+=res;
 
 					} else {
+						if (CharType(GETCHAR(i))=='\n') {
+							line++;
+							column=0;
+						}
+
 						str+=CharType(GETCHAR(i));
 					}
 					i++;
@@ -1040,7 +1046,7 @@ void GDTokenizerText::advance(int p_amount) {
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 
-#define BYTECODE_VERSION 4
+#define BYTECODE_VERSION 5
 
 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
 

+ 4 - 4
modules/gridmap/grid_map.cpp

@@ -130,8 +130,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
 
 
 	} else if (name.begins_with("areas/")) {
-		int which = name.get_slice("/",1).to_int();
-		String what=name.get_slice("/",2);
+		int which = name.get_slicec('/',1).to_int();
+		String what=name.get_slicec('/',2);
 		if (what=="bounds") {
 			ERR_FAIL_COND_V(area_map.has(which),false);
 			create_area(which,p_value);
@@ -215,8 +215,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const {
 
 		r_ret= d;
 	} else if (name.begins_with("areas/")) {
-		int which = name.get_slice("/",1).to_int();
-		String what=name.get_slice("/",2);
+		int which = name.get_slicec('/',1).to_int();
+		String what=name.get_slicec('/',2);
 		if (what=="bounds")
 			r_ret= area_get_bounds(which);
 		else if (what=="name")

+ 41 - 1
platform/android/detect.py

@@ -54,13 +54,53 @@ def create(env):
 
 def configure(env):
 
+	# Workaround for MinGW. See:
+	# http://www.scons.org/wiki/LongCmdLinesOnWin32
+	import os
+	if (os.name=="nt"):
+	
+		import subprocess
+			
+		def mySubProcess(cmdline,env):
+			#print "SPAWNED : " + cmdline
+			startupinfo = subprocess.STARTUPINFO()
+			startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+			proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+				stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
+			data, err = proc.communicate()
+			rv = proc.wait()
+			if rv:
+				print "====="
+				print err
+				print "====="
+			return rv
+				
+		def mySpawn(sh, escape, cmd, args, env):
+								
+			newargs = ' '.join(args[1:])
+			cmdline = cmd + " " + newargs
+				
+			rv=0
+			if len(cmdline) > 32000 and cmd.endswith("ar") :
+				cmdline = cmd + " " + args[1] + " " + args[2] + " "
+				for i in range(3,len(args)) :
+					rv = mySubProcess( cmdline + args[i], env )
+					if rv :
+						break	
+			else:				
+				rv = mySubProcess( cmdline, env )
+					
+			return rv
+				
+		env['SPAWN'] = mySpawn
+	
 	if env['x86']=='yes':
 		env['NDK_TARGET']='x86-4.8'
 
 	if env['PLATFORM'] == 'win32':
 		import methods
 		env.Tool('gcc')
-		env['SPAWN'] = methods.win32_spawn
+		#env['SPAWN'] = methods.win32_spawn
 		env['SHLIBSUFFIX'] = '.so'
 
 #	env.android_source_modules.append("../libs/apk_expansion")	

+ 20 - 15
platform/android/export/export.cpp

@@ -228,7 +228,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 	String get_package_name();
 
 	String get_project_name() const;
-	void _fix_manifest(Vector<uint8_t>& p_manifest);
+	void _fix_manifest(Vector<uint8_t>& p_manifest, bool p_give_internet);
 	void _fix_resources(Vector<uint8_t>& p_manifest);
 	static Error save_apk_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
 
@@ -249,11 +249,11 @@ public:
 	virtual int get_device_count() const;
 	virtual String get_device_name(int p_device) const;
 	virtual String get_device_info(int p_device) const;
-	virtual Error run(int p_device,bool p_dumb=false);
+	virtual Error run(int p_device,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool requieres_password(bool p_debug) const { return !p_debug; }
 	virtual String get_binary_extension() const { return "apk"; }
-	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+	virtual Error export_project(const String& p_path, bool p_debug, bool p_dumb=false, bool p_remote_debug=false);
 
 	virtual bool can_export(String *r_error=NULL) const;
 
@@ -317,7 +317,7 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
 		apk_expansion_pkey=p_value;
 	else if (n.begins_with("permissions/")) {
 
-		String what = n.get_slice("/",1).to_upper();
+		String what = n.get_slicec('/',1).to_upper();
 		bool state = p_value;
 		if (state)
 			perms.insert(what);
@@ -325,7 +325,7 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
 			perms.erase(what);
 	} else if (n.begins_with("user_permissions/")) {
 
-		int which = n.get_slice("/",1).to_int();
+		int which = n.get_slicec('/',1).to_int();
 		ERR_FAIL_INDEX_V(which,MAX_USER_PERMISSIONS,false);
 		user_perms[which]=p_value;
 
@@ -390,11 +390,11 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret)
 		r_ret=apk_expansion_pkey;
 	else if (n.begins_with("permissions/")) {
 
-		String what = n.get_slice("/",1).to_upper();
+		String what = n.get_slicec('/',1).to_upper();
 		r_ret = perms.has(what);
 	} else if (n.begins_with("user_permissions/")) {
 
-		int which = n.get_slice("/",1).to_int();
+		int which = n.get_slicec('/',1).to_int();
 		ERR_FAIL_INDEX_V(which,MAX_USER_PERMISSIONS,false);
 		r_ret=user_perms[which];
 	} else
@@ -608,7 +608,7 @@ String EditorExportPlatformAndroid::get_project_name() const {
 }
 
 
-void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
+void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool p_give_internet) {
 
 
 	const int CHUNK_AXML_FILE = 0x00080003;
@@ -838,7 +838,10 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
 
 						} else if (value.begins_with("godot.")) {
 							String perm = value.get_slice(".",1);
-							if (perms.has(perm)) {
+							print_line("PERM: "+perm+" HAS: "+itos(perms.has(perm)));
+
+							if (perms.has(perm) || (p_give_internet && perm=="INTERNET")) {
+
 								string_table[attr_value]="android.permission."+perm;
 							}
 
@@ -1011,7 +1014,7 @@ Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String&
 
 
 
-Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_debug, bool p_dumb,bool p_remote_debug) {
 
 	String src_apk;
 
@@ -1075,7 +1078,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
 
 		if (file=="AndroidManifest.xml") {
 
-			_fix_manifest(data);
+			_fix_manifest(data,p_dumb || p_remote_debug);
 		}
 
 		if (file=="resources.arsc") {
@@ -1153,9 +1156,11 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
 		}
 	}
 
+	gen_export_flags(cl,p_dumb,p_remote_debug);
+
 	if (p_dumb) {
 
-		String host = EditorSettings::get_singleton()->get("file_server/host");
+		/*String host = EditorSettings::get_singleton()->get("file_server/host");
 		int port = EditorSettings::get_singleton()->get("file_server/post");
 		String passwd = EditorSettings::get_singleton()->get("file_server/password");
 		cl.push_back("-rfs");
@@ -1163,7 +1168,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
 		if (passwd!="") {
 			cl.push_back("-rfs_pass");
 			cl.push_back(passwd);
-		}
+		}*/
 
 
 	} else {
@@ -1480,7 +1485,7 @@ void EditorExportPlatformAndroid::_device_poll_thread(void *ud) {
 
 }
 
-Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb, bool p_remote_debug) {
 
 	ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
 	device_lock->lock();
@@ -1499,7 +1504,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 	ep.step("Exporting APK",0);
 
 	String export_to=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport.apk";
-	Error err = export_project(export_to,true,p_dumb);
+	Error err = export_project(export_to,true,p_dumb,p_remote_debug);
 	if (err) {
 		device_lock->unlock();
 		return err;

+ 4 - 4
platform/bb10/export/export.cpp

@@ -67,11 +67,11 @@ public:
 	virtual int get_device_count() const;
 	virtual String get_device_name(int p_device) const;
 	virtual String get_device_info(int p_device) const;
-	virtual Error run(int p_device,bool p_dumb=false);
+	virtual Error run(int p_device,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool requieres_password(bool p_debug) const { return !p_debug; }
 	virtual String get_binary_extension() const { return "bar"; }
-	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool can_export(String *r_error=NULL) const;
 
@@ -270,7 +270,7 @@ void EditorExportPlatformBB10::_fix_descriptor(Vector<uint8_t>& p_descriptor) {
 
 
 
-Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debug, bool p_dumb, bool p_remote_debug) {
 
 
 	EditorProgress ep("export","Exporting for BlackBerry 10",104);
@@ -619,7 +619,7 @@ void EditorExportPlatformBB10::_device_poll_thread(void *ud) {
 
 }
 
-Error EditorExportPlatformBB10::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformBB10::run(int p_device, bool p_dumb, bool p_remote_debug) {
 
 	ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
 

+ 23 - 0
platform/iphone/app_delegate.mm

@@ -138,6 +138,29 @@ static int frame_count = 0;
 		Main::setup2();
 		++frame_count;
 
+		// this might be necessary before here
+		for (NSString* key in [[NSBundle mainBundle] infoDictionary]) {
+			NSObject* value = [[[NSBundle mainBundle] infoDictionary] objectForKey:key];
+			String ukey = String::utf8([key UTF8String]);
+
+			// we need a NSObject to Variant conversor
+
+			if ([value isKindOfClass:[NSString class]]) {
+				NSString* str = (NSString*)value;
+				String uval = String::utf8([str UTF8String]);
+
+				Globals::get_singleton()->set("Info.plist/"+ukey, uval);
+
+			} else if ([value isKindOfClass:[NSNumber class]]) {
+
+				NSNumber* n = (NSNumber*)value;
+				double dval = [n doubleValue];
+
+				Globals::get_singleton()->set("Info.plist/"+ukey, dval);
+			};
+			// do stuff
+		}
+
 	} break;
 /*
 	case 3: {

+ 4 - 4
platform/javascript/export/export.cpp

@@ -77,11 +77,11 @@ public:
 	virtual int get_device_count() const { return show_run?1:0; };
 	virtual String get_device_name(int p_device) const  { return "Run in Browser"; }
 	virtual String get_device_info(int p_device) const { return "Run exported HTML in the system's default browser."; }
-	virtual Error run(int p_device,bool p_dumb=false);
+	virtual Error run(int p_device,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool requieres_password(bool p_debug) const { return false; }
 	virtual String get_binary_extension() const { return "html"; }
-	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool can_export(String *r_error=NULL) const;
 
@@ -194,7 +194,7 @@ struct JSExportData {
 
 
 
-Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool p_debug, bool p_dumb, bool p_remote_debug) {
 
 
 	String src_template;
@@ -299,7 +299,7 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool
 }
 
 
-Error EditorExportPlatformJavaScript::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformJavaScript::run(int p_device, bool p_dumb, bool p_remote_debug) {
 
 	String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmp_export.html";
 	Error err = export_project(path,true,"");

+ 4 - 4
platform/osx/export/export.cpp

@@ -57,11 +57,11 @@ public:
 	virtual int get_device_count() const { return 0; };
 	virtual String get_device_name(int p_device) const  { return String(); }
 	virtual String get_device_info(int p_device) const { return String(); }
-	virtual Error run(int p_device,bool p_dumb=false);
+	virtual Error run(int p_device,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool requieres_password(bool p_debug) const { return false; }
 	virtual String get_binary_extension() const { return "zip"; }
-	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+	virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false,bool p_remote_debug=false);
 
 	virtual bool can_export(String *r_error=NULL) const;
 
@@ -245,7 +245,7 @@ void EditorExportPlatformOSX::_fix_plist(Vector<uint8_t>& plist,const String& p_
 	}
 }
 
-Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, bool p_dumb, bool p_remote_debug) {
 
 	String src_pkg;
 
@@ -437,7 +437,7 @@ Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug
 }
 
 
-Error EditorExportPlatformOSX::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformOSX::run(int p_device, bool p_dumb, bool p_remote_debug) {
 
 	return OK;
 }

+ 6 - 0
platform/windows/os_windows.cpp

@@ -1899,6 +1899,12 @@ uint64_t OS_Windows::get_unix_time() const {
 	return (*(uint64_t*)&ft - *(uint64_t*)&fep) / 10000000;
 };
 
+uint64_t OS_Windows::get_system_time_msec() const {
+	SYSTEMTIME st;
+	GetSystemTime(&st);
+	return st.wMilliseconds;
+}
+
 void OS_Windows::delay_usec(uint32_t p_usec) const {
 
         if (p_usec < 1000)

+ 2 - 1
platform/windows/os_windows.h

@@ -263,6 +263,7 @@ public:
 	virtual Time get_time(bool utc) const;
 	virtual TimeZoneInfo get_time_zone_info() const;
 	virtual uint64_t get_unix_time() const;
+	virtual uint64_t get_system_time_msec() const;
 
 	virtual bool can_draw() const;
 	virtual Error set_cwd(const String& p_cwd);
@@ -272,7 +273,7 @@ public:
 
 	virtual Error execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL);
 	virtual Error kill(const ProcessID& p_pid);
-
+	
 	virtual bool has_environment(const String& p_var) const;
 	virtual String get_environment(const String& p_var) const;
 

+ 1 - 0
platform/x11/os_x11.cpp

@@ -267,6 +267,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
 		for(int i=0;i<AudioDriverManagerSW::get_driver_count();i++) {
 			if (i==p_audio_driver)
 				continue;
+			AudioDriverManagerSW::get_driver(i)->set_singleton();
 			if (AudioDriverManagerSW::get_driver(i)->init()==OK) {
 				success=true;
 				print_line("Audio Driver Failed: "+String(AudioDriverManagerSW::get_driver(p_audio_driver)->get_name()));

+ 4 - 4
scene/2d/animated_sprite.cpp

@@ -330,11 +330,11 @@ void AnimatedSprite::_bind_methods() {
 
 	ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
 	ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
-	ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
 
 }
 

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

@@ -428,8 +428,9 @@ void Area2D::set_enable_monitoring(bool p_enable) {
 
 	if (monitoring) {
 
-		Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
-		Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout");
+		Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_body_inout);
+		Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_area_inout);
+
 	} else {
 		Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
 		Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName());
@@ -652,17 +653,17 @@ void Area2D::_bind_methods() {
 
 
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode"));
-	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale"));
+	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
+	ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale"));
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp"));
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority"));
-	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
-	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"));
+	ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
+	ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
+	ADD_PROPERTYNO( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+	ADD_PROPERTYNO( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
 
 }
 

+ 6 - 6
scene/2d/canvas_item.cpp

@@ -1071,8 +1071,8 @@ void CanvasItem::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("draw_rect","rect","color"),&CanvasItem::draw_rect);
 	ObjectTypeDB::bind_method(_MD("draw_circle","pos","radius","color"),&CanvasItem::draw_circle);
 	ObjectTypeDB::bind_method(_MD("draw_texture","texture:Texture","pos"),&CanvasItem::draw_texture);
-	ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate"),&CanvasItem::draw_texture_rect,DEFVAL(false),DEFVAL(Color(1,1,1)));
-	ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1)));
+	ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate","transpose"),&CanvasItem::draw_texture_rect,DEFVAL(Color(1,1,1)),DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate","transpose"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));
 	ObjectTypeDB::bind_method(_MD("draw_style_box","style_box:StyleBox","rect"),&CanvasItem::draw_style_box);
 	ObjectTypeDB::bind_method(_MD("draw_primitive","points","colors","uvs","texture:Texture","width"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()),DEFVAL(1.0));
 	ObjectTypeDB::bind_method(_MD("draw_polygon","points","colors","uvs","texture:Texture"),&CanvasItem::draw_polygon,DEFVAL(Array()),DEFVAL(Ref<Texture>()));
@@ -1103,14 +1103,14 @@ void CanvasItem::_bind_methods() {
 
 	BIND_VMETHOD(MethodInfo("_draw"));
 
-	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") );
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") );
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") );
+	ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") );
+	ADD_PROPERTYNO( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") );
+	ADD_PROPERTYNO( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility
 
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
-	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
+	ADD_PROPERTYNO( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"material/material",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), _SCS("set_material"),_SCS("get_material") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"material/use_parent"), _SCS("set_use_parent_material"),_SCS("get_use_parent_material") );
 	//exporting these two things doesn't really make much sense i think

+ 36 - 22
scene/2d/collision_object_2d.cpp

@@ -115,19 +115,16 @@ void CollisionObject2D::_update_shapes() {
 bool CollisionObject2D::_set(const StringName& p_name, const Variant& p_value) {
 	String name=p_name;
 
-	if (name=="shape_count") {
+	if (name.begins_with("shapes/")) {
 
-		shapes.resize(p_value);
-		_update_shapes();
-		_change_notify();
-
-	} else if (name.begins_with("shapes/")) {
-
-		int idx=name.get_slice("/",1).to_int();
-		String what=name.get_slice("/",2);
-		if (what=="shape")
-			set_shape(idx,RefPtr(p_value));
-		else if (what=="transform")
+		int idx=name.get_slicec('/',1).to_int();
+		String what=name.get_slicec('/',2);
+		if (what=="shape") {
+			if (idx>=shapes.size())
+				add_shape(RefPtr(p_value));
+			else
+				set_shape(idx,RefPtr(p_value));
+		} else if (what=="transform")
 			set_shape_transform(idx,p_value);
 		else if (what=="trigger")
 			set_shape_as_trigger(idx,p_value);
@@ -143,12 +140,10 @@ bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const {
 
 	String name=p_name;
 
-	if (name=="shape_count") {
-		r_ret= shapes.size();
-	} else if (name.begins_with("shapes/")) {
+	if (name.begins_with("shapes/")) {
 
-		int idx=name.get_slice("/",1).to_int();
-		String what=name.get_slice("/",2);
+		int idx=name.get_slicec('/',1).to_int();
+		String what=name.get_slicec('/',2);
 		if (what=="shape")
 			r_ret= get_shape(idx);
 		else if (what=="transform")
@@ -163,7 +158,7 @@ bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const {
 
 void CollisionObject2D::_get_property_list( List<PropertyInfo> *p_list) const {
 
-	p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+	//p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
 
 	for(int i=0;i<shapes.size();i++) {
 		String path="shapes/"+itos(i)+"/";
@@ -254,12 +249,19 @@ void CollisionObject2D::_bind_methods() {
 
 void CollisionObject2D::add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform) {
 
+	ERR_FAIL_COND(p_shape.is_null());
+
 	ShapeData sdata;
 	sdata.shape=p_shape;
 	sdata.xform=p_transform;
 	sdata.trigger=false;
-	shapes.push_back(sdata);
-	_update_shapes();
+
+	if (area)
+		Physics2DServer::get_singleton()->area_add_shape(get_rid(),p_shape->get_rid(),p_transform);
+	else
+		Physics2DServer::get_singleton()->body_add_shape(get_rid(),p_shape->get_rid(),p_transform);
+
+	shapes.push_back(sdata);	
 
 }
 int CollisionObject2D::get_shape_count() const {
@@ -270,8 +272,15 @@ int CollisionObject2D::get_shape_count() const {
 void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape) {
 
 	ERR_FAIL_INDEX(p_shape_idx,shapes.size());
+	ERR_FAIL_COND(p_shape.is_null());
+
 	shapes[p_shape_idx].shape=p_shape;
-	_update_shapes();
+	if (area)
+		Physics2DServer::get_singleton()->area_set_shape(get_rid(),p_shape_idx,p_shape->get_rid());
+	else
+		Physics2DServer::get_singleton()->body_set_shape(get_rid(),p_shape_idx,p_shape->get_rid());
+
+//	_update_shapes();
 }
 
 void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_transform) {
@@ -279,7 +288,12 @@ void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_t
 	ERR_FAIL_INDEX(p_shape_idx,shapes.size());
 	shapes[p_shape_idx].xform=p_transform;
 
-	_update_shapes();
+	if (area)
+		Physics2DServer::get_singleton()->area_set_shape_transform(get_rid(),p_shape_idx,p_transform);
+	else
+		Physics2DServer::get_singleton()->body_set_shape_transform(get_rid(),p_shape_idx,p_transform);
+
+//	_update_shapes();
 }
 
 Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const {

+ 5 - 5
scene/2d/node_2d.cpp

@@ -398,11 +398,11 @@ void Node2D::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("get_relative_transform"),&Node2D::get_relative_transform);
 
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
-	ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
-	ADD_PROPERTY(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z"));
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative"));
 
 
 }

+ 18 - 18
scene/2d/particles_2d.cpp

@@ -1072,19 +1072,19 @@ void Particles2D::_bind_methods() {
 
 	ADD_PROPERTY(PropertyInfo(Variant::INT,"config/amount",PROPERTY_HINT_EXP_RANGE,"1,1024"),_SCS("set_amount"),_SCS("get_amount") );
 	ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/lifetime",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_lifetime"),_SCS("get_lifetime") );
-	ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") );
-	ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") );
-	ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") );
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") );
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset"));
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents"));
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space"));
-	ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness"));
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/flip_h"),_SCS("set_flip_h"),_SCS("is_flipped_h"));
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/flip_v"),_SCS("set_flip_v"),_SCS("is_flipped_v"));
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
-	ADD_PROPERTY(PropertyInfo(Variant::INT,"config/h_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_h_frames"),_SCS("get_h_frames"));
-	ADD_PROPERTY(PropertyInfo(Variant::INT,"config/v_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_v_frames"),_SCS("get_v_frames"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") );
+	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") );
+	ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") );
+	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") );
+	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL,"config/flip_h"),_SCS("set_flip_h"),_SCS("is_flipped_h"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL,"config/flip_v"),_SCS("set_flip_v"),_SCS("is_flipped_v"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::INT,"config/h_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_h_frames"),_SCS("get_h_frames"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::INT,"config/v_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_v_frames"),_SCS("get_v_frames"));
 
 
 	for(int i=0;i<PARAM_MAX;i++) {
@@ -1092,10 +1092,10 @@ void Particles2D::_bind_methods() {
 	}
 
 	for(int i=0;i<PARAM_MAX;i++) {
-		ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i);
+		ADD_PROPERTYINZ(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i);
 	}
 
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1", 0), _SCS("set_color_phases"), _SCS("get_color_phases"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1", 0), _SCS("set_color_phases"), _SCS("get_color_phases"));
 
 	//Backward compatibility. They will be converted to color ramp
 	for(int i=0;i<MAX_COLOR_PHASES;i++) {
@@ -1104,10 +1104,10 @@ void Particles2D::_bind_methods() {
 		ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color", PROPERTY_HINT_NONE, "", 0),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i );
 	}
 
-	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color/color"),_SCS("set_color"),_SCS("get_color"));
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"color/color_ramp",PROPERTY_HINT_RESOURCE_TYPE,"ColorRamp"),_SCS("set_color_ramp"),_SCS("get_color_ramp"));
+	ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "color/color"),_SCS("set_color"),_SCS("get_color"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"color/color_ramp",PROPERTY_HINT_RESOURCE_TYPE,"ColorRamp"),_SCS("set_color_ramp"),_SCS("get_color_ramp"));
 
-	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points"));
+	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points"));
 
 	BIND_CONSTANT( PARAM_DIRECTION );
 	BIND_CONSTANT( PARAM_SPREAD );

+ 19 - 15
scene/2d/sprite.cpp

@@ -103,14 +103,18 @@ void Sprite::set_texture(const Ref<Texture>& p_texture) {
 
 	if (p_texture==texture)
 		return;
+#ifdef DEBUG_ENABLED
 	if (texture.is_valid()) {
 		texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
 	}
+#endif
 	texture=p_texture;
+#ifdef DEBUG_ENABLED
 	if (texture.is_valid()) {
 		texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
 		texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
 	}
+#endif
 	update();
 	item_rect_changed();
 }
@@ -313,17 +317,17 @@ void Sprite::_bind_methods() {
 
 	ADD_SIGNAL(MethodInfo("frame_changed"));
 
-	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
-	ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
-	ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
-	ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
 
 }
 
@@ -530,10 +534,10 @@ void ViewportSprite::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&ViewportSprite::set_modulate);
 	ObjectTypeDB::bind_method(_MD("get_modulate"),&ViewportSprite::get_modulate);
 
-	ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
-	ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
-	ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
+	ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
 
 }
 

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

@@ -579,6 +579,10 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) {
 	call_deferred("_update_dirty_quadrants");
 }
 
+void TileMap::set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) {
+
+	set_cell(p_pos.x,p_pos.y,p_tile,p_flip_x,p_flip_y,p_transpose);
+}
 
 void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) {
 
@@ -1106,6 +1110,7 @@ void TileMap::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce);
 
 	ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("set_cellv","pos","tile","flip_x","flip_y","transpose"),&TileMap::set_cellv,DEFVAL(false),DEFVAL(false),DEFVAL(false));
 	ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell);
 	ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped);
 	ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped);

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

@@ -207,6 +207,8 @@ public:
 	bool is_cell_y_flipped(int p_x,int p_y) const;
 	bool is_cell_transposed(int p_x,int p_y) const;
 
+	void set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false);
+
 	Rect2 get_item_rect() const;
 
 	void set_collision_layer(uint32_t p_layer);

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

@@ -299,8 +299,8 @@ void Area::set_enable_monitoring(bool p_enable) {
 
 	if (monitoring) {
 
-		PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
-		PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout");
+		PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_body_inout);
+		PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_area_inout);
 	} else {
 		PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
 		PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName());

+ 4 - 4
scene/3d/collision_object.cpp

@@ -122,8 +122,8 @@ bool CollisionObject::_set(const StringName& p_name, const Variant& p_value) {
 
 	} else if (name.begins_with("shapes/")) {
 
-		int idx=name.get_slice("/",1).to_int();
-		String what=name.get_slice("/",2);
+		int idx=name.get_slicec('/',1).to_int();
+		String what=name.get_slicec('/',2);
 		if (what=="shape")
 			set_shape(idx,RefPtr(p_value));
 		else if (what=="transform")
@@ -148,8 +148,8 @@ bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const {
 		r_ret= shapes.size();
 	} else if (name.begins_with("shapes/")) {
 
-		int idx=name.get_slice("/",1).to_int();
-		String what=name.get_slice("/",2);
+		int idx=name.get_slicec('/',1).to_int();
+		String what=name.get_slicec('/',2);
 		if (what=="shape")
 			r_ret= get_shape(idx);
 		else if (what=="transform")

+ 4 - 4
scene/3d/skeleton.cpp

@@ -41,8 +41,8 @@ bool Skeleton::_set(const StringName& p_path, const Variant& p_value) {
 	if (!path.begins_with("bones/"))
 		return false;
 		
-	int which=path.get_slice("/",1).to_int();
-	String what=path.get_slice("/",2);
+	int which=path.get_slicec('/',1).to_int();
+	String what=path.get_slicec('/',2);
 
 
 	if (which==bones.size() && what=="name") {
@@ -88,8 +88,8 @@ bool Skeleton::_get(const StringName& p_name,Variant &r_ret) const {
 	if (!path.begins_with("bones/"))
 		return false;
 		
-	int which=path.get_slice("/",1).to_int();
-	String what=path.get_slice("/",2);
+	int which=path.get_slicec('/',1).to_int();
+	String what=path.get_slicec('/',2);
 		
 	ERR_FAIL_INDEX_V( which, bones.size(), false );
 	

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

@@ -758,7 +758,7 @@ void Spatial::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") );
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") );
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") );
-	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") );
+	ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") );
 	//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") );
 
 	ADD_SIGNAL( MethodInfo("visibility_changed" ) );

+ 12 - 9
scene/animation/animation_player.cpp

@@ -35,10 +35,10 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) {
 
 	String name=p_name;
 
-	if (name=="playback/speed" || name=="speed") { //bw compatibility
+	if (p_name==SceneStringNames::get_singleton()->playback_speed || p_name==SceneStringNames::get_singleton()->speed) { //bw compatibility
 		set_speed(p_value);
 
-	} else if (name=="playback/active") {
+	} else if (p_name==SceneStringNames::get_singleton()->playback_active) {
 		set_active(p_value);
 	} else if (name.begins_with("playback/play")) {
 
@@ -52,16 +52,16 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) {
 	} else if (name.begins_with("anims/")) {
 	
 
-		String which=name.get_slice("/",1);
+		String which=name.get_slicec('/',1);
 		
 		add_animation(which,p_value);
 	} else if (name.begins_with("next/")) {
 
 
-		String which=name.get_slice("/",1);
+		String which=name.get_slicec('/',1);
 		animation_set_next(which,p_value);
 
-	} else if (name=="blend_times") {
+	} else if (p_name==SceneStringNames::get_singleton()->blend_times) {
 	
 		Array array=p_value;
 		int len = array.size();
@@ -77,7 +77,7 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) {
 			set_blend_time(from,to,time);
 		}
 
-	} else if (name=="autoplay") {
+	} else if (p_name==SceneStringNames::get_singleton()->autoplay) {
 		autoplay=p_value;
 	
 	} else
@@ -106,12 +106,12 @@ bool AnimationPlayer::_get(const StringName& p_name,Variant &r_ret) const {
 
 	} else if (name.begins_with("anims/")) {
 	
-		String which=name.get_slice("/",1);
+		String which=name.get_slicec('/',1);
 		
 		r_ret= get_animation(which).get_ref_ptr();
 	} else if (name.begins_with("next/")) {
 
-		String which=name.get_slice("/",1);
+		String which=name.get_slicec('/',1);
 
 		r_ret= animation_get_next(which);
 
@@ -661,8 +661,11 @@ void AnimationPlayer::_animation_process(float p_delta) {
 
 Error AnimationPlayer::add_animation(const StringName& p_name, const Ref<Animation>& p_animation) {
 
+#ifdef DEBUG_ENABLED
 	ERR_EXPLAIN("Invalid animation name: "+String(p_name));
 	ERR_FAIL_COND_V( String(p_name).find("/")!=-1 || String(p_name).find(":")!=-1 || String(p_name).find(",")!=-1 || String(p_name).find("[")!=-1, ERR_INVALID_PARAMETER );
+#endif
+
 	ERR_FAIL_COND_V( p_animation.is_null() , ERR_INVALID_PARAMETER );
 	
 	//print_line("Add anim: "+String(p_name)+" name: "+p_animation->get_name());
@@ -1271,7 +1274,7 @@ AnimationPlayer::AnimationPlayer() {
 	animation_process_mode=ANIMATION_PROCESS_IDLE;
 	processing=false;
         default_blend_time=0;
-	root=NodePath("..");
+	root=SceneStringNames::get_singleton()->path_pp;
 	playing = false;
 	active=true;
 }

+ 1 - 1
scene/audio/sample_player.cpp

@@ -102,7 +102,7 @@ bool SamplePlayer::_get(const StringName& p_name,Variant &r_ret) const {
 		r_ret= get_sample_library();
 	} else if (name.begins_with("default/")) {
 
-			String what=name.get_slice("/",1);
+			String what=name.get_slicec('/',1);
 
 			if (what=="volume_db")
 				r_ret= get_default_volume_db();

+ 3 - 3
scene/gui/base_button.cpp

@@ -390,10 +390,10 @@ void BaseButton::_bind_methods() {
 	ADD_SIGNAL( MethodInfo("pressed" ) );
 	ADD_SIGNAL( MethodInfo("released" ) );
 	ADD_SIGNAL( MethodInfo("toggled", PropertyInfo( Variant::BOOL,"pressed") ) );
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled"));
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode"));
-    ADD_PROPERTY( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed"));
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed"));
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press"));
 
 
 	BIND_CONSTANT( DRAW_NORMAL );

+ 4 - 4
scene/gui/button.cpp

@@ -225,11 +225,11 @@ void Button::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_text_align"),&Button::get_text_align);
 	ObjectTypeDB::bind_method(_MD("is_flat"),&Button::is_flat);
 
-	ADD_PROPERTY( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") );
-	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") );
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flat" ), _SCS("set_flat"),_SCS("is_flat") );
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "clip_text" ), _SCS("set_clip_text"),_SCS("get_clip_text") );
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "align",PROPERTY_HINT_ENUM,"Left,Center,Right" ), _SCS("set_text_align"),_SCS("get_text_align") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "clip_text" ), _SCS("set_clip_text"),_SCS("get_clip_text") );
+	ADD_PROPERTYNO( PropertyInfo( Variant::INT, "align",PROPERTY_HINT_ENUM,"Left,Center,Right" ), _SCS("set_text_align"),_SCS("get_text_align") );
 
 }
 

+ 4 - 4
scene/gui/button_array.cpp

@@ -34,7 +34,7 @@ bool ButtonArray::_set(const StringName& p_name, const Variant& p_value) {
 	String n=String(p_name);
 	if (n.begins_with("button/")) {
 
-		String what = n.get_slice("/",1);
+		String what = n.get_slicec('/',1);
 		if (what=="count") {
 			int new_size=p_value;
 			if (new_size>0 && buttons.size()==0) {
@@ -57,7 +57,7 @@ bool ButtonArray::_set(const StringName& p_name, const Variant& p_value) {
 		} else {
 			int idx=what.to_int();
 			ERR_FAIL_INDEX_V(idx,buttons.size(),false);
-			String f = n.get_slice("/",2);
+			String f = n.get_slicec('/',2);
 			if (f=="text")
 				buttons[idx].text=p_value;
 			else if (f=="icon")
@@ -80,7 +80,7 @@ bool ButtonArray::_get(const StringName& p_name,Variant &r_ret) const {
 	String n=String(p_name);
 	if (n.begins_with("button/")) {
 
-		String what = n.get_slice("/",1);
+		String what = n.get_slicec('/',1);
 		if (what=="count") {
 			r_ret=buttons.size();
 		} else if (what=="align") {
@@ -92,7 +92,7 @@ bool ButtonArray::_get(const StringName& p_name,Variant &r_ret) const {
 		} else {
 			int idx=what.to_int();
 			ERR_FAIL_INDEX_V(idx,buttons.size(),false);
-			String f = n.get_slice("/",2);
+			String f = n.get_slicec('/',2);
 			if (f=="text")
 				r_ret=buttons[idx].text;
 			else if (f=="icon")

+ 20 - 20
scene/gui/control.cpp

@@ -136,27 +136,27 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) {
 	if (p_value.get_type()==Variant::NIL) {
 
 		if (name.begins_with("custom_icons/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			data.icon_override.erase(dname);
 			notification(NOTIFICATION_THEME_CHANGED);
 			update();
 		} else if (name.begins_with("custom_styles/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			data.style_override.erase(dname);
 			notification(NOTIFICATION_THEME_CHANGED);
 			update();
 		} else if (name.begins_with("custom_fonts/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			data.font_override.erase(dname);
 			notification(NOTIFICATION_THEME_CHANGED);
 			update();
 		} else if (name.begins_with("custom_colors/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			data.color_override.erase(dname);
 			notification(NOTIFICATION_THEME_CHANGED);
 			update();
 		} else if (name.begins_with("custom_constants/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			data.constant_override.erase(dname);
 			notification(NOTIFICATION_THEME_CHANGED);
 			update();
@@ -165,23 +165,23 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) {
 
 	} else {
 		if (name.begins_with("custom_icons/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			notification(NOTIFICATION_THEME_CHANGED);
 			add_icon_override(dname,p_value);
 		} else if (name.begins_with("custom_styles/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			add_style_override(dname,p_value);
 			notification(NOTIFICATION_THEME_CHANGED);
 		} else if (name.begins_with("custom_fonts/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			add_font_override(dname,p_value);
 			notification(NOTIFICATION_THEME_CHANGED);
 		} else if (name.begins_with("custom_colors/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			add_color_override(dname,p_value);
 			notification(NOTIFICATION_THEME_CHANGED);
 		} else if (name.begins_with("custom_constants/")) {
-			String dname = name.get_slice("/",1);
+			String dname = name.get_slicec('/',1);
 			add_constant_override(dname,p_value);
 			notification(NOTIFICATION_THEME_CHANGED);
 		} else
@@ -217,22 +217,22 @@ bool Control::_get(const StringName& p_name,Variant &r_ret) const {
 		return false;
 
 	if (sname.begins_with("custom_icons/")) {
-		String name = sname.get_slice("/",1);
+		String name = sname.get_slicec('/',1);
 
 		r_ret= data.icon_override.has(name)?Variant(data.icon_override[name]):Variant();
 	} else if (sname.begins_with("custom_styles/")) {
-		String name = sname.get_slice("/",1);
+		String name = sname.get_slicec('/',1);
 
 		r_ret= data.style_override.has(name)?Variant(data.style_override[name]):Variant();
 	} else if (sname.begins_with("custom_fonts/")) {
-		String name = sname.get_slice("/",1);
+		String name = sname.get_slicec('/',1);
 
 		r_ret= data.font_override.has(name)?Variant(data.font_override[name]):Variant();
 	} else if (sname.begins_with("custom_colors/")) {
-		String name = sname.get_slice("/",1);
+		String name = sname.get_slicec('/',1);
 		r_ret= data.color_override.has(name)?Variant(data.color_override[name]):Variant();
 	} else if (sname.begins_with("custom_constants/")) {
-		String name = sname.get_slice("/",1);
+		String name = sname.get_slicec('/',1);
 
 		r_ret= data.constant_override.has(name)?Variant(data.constant_override[name]):Variant();
 	} else
@@ -2832,16 +2832,16 @@ void Control::_bind_methods() {
 	ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/size", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_size"),_SCS("get_size") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/min_size"), _SCS("set_custom_minimum_size"),_SCS("get_custom_minimum_size") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"hint/tooltip", PROPERTY_HINT_MULTILINE_TEXT), _SCS("set_tooltip"),_SCS("_get_tooltip") );
-	ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT );
-	ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/top" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_TOP );
-	ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/right" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_RIGHT );
-	ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/bottom" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_BOTTOM );
+	ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT );
+	ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/top" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_TOP );
+	ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/right" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_RIGHT );
+	ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/bottom" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_BOTTOM );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"focus/ignore_mouse"), _SCS("set_ignore_mouse"),_SCS("is_ignoring_mouse") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"focus/stop_mouse"), _SCS("set_stop_mouse"),_SCS("is_stopping_mouse") );
 
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"size_flags/horizontal", PROPERTY_HINT_FLAGS, "Expand,Fill"), _SCS("set_h_size_flags"),_SCS("get_h_size_flags") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"size_flags/vertical", PROPERTY_HINT_FLAGS, "Expand,Fill"), _SCS("set_v_size_flags"),_SCS("get_v_size_flags") );
-	ADD_PROPERTY( PropertyInfo(Variant::INT,"size_flags/stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), _SCS("set_stretch_ratio"),_SCS("get_stretch_ratio") );
+	ADD_PROPERTYNO( PropertyInfo(Variant::INT,"size_flags/stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), _SCS("set_stretch_ratio"),_SCS("get_stretch_ratio") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"theme/theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), _SCS("set_theme"),_SCS("get_theme") );
 
 	BIND_CONSTANT( ANCHOR_BEGIN );

+ 5 - 5
scene/gui/label.cpp

@@ -613,11 +613,11 @@ void Label::_bind_methods() {
 	BIND_CONSTANT( VALIGN_BOTTOM );
 	BIND_CONSTANT( VALIGN_FILL );
 
-	ADD_PROPERTY( PropertyInfo( Variant::STRING, "text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL), _SCS("set_text"),_SCS("get_text") );
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") );
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") );
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") );
-	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL), _SCS("set_text"),_SCS("get_text") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") );
+	ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") );
 	ADD_PROPERTY( PropertyInfo( Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_percent_visible"),_SCS("get_percent_visible") );
 
 }

+ 112 - 3
scene/gui/tabs.cpp

@@ -56,7 +56,14 @@ Size2 Tabs::get_minimum_size() const {
 		else
 			ms.width+=tab_bg->get_minimum_size().width;
 
+		if (tabs[i].right_button.is_valid()) {
+			Ref<Texture> rb=tabs[i].right_button;
+			Size2 bms = rb->get_size()+get_stylebox("button")->get_minimum_size();
+			bms.width+=get_constant("hseparation");
 
+			ms.width+=bms.width;
+			ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
+		}
 	}
 
 	return ms;
@@ -66,6 +73,39 @@ Size2 Tabs::get_minimum_size() const {
 
 void Tabs::_input_event(const InputEvent& p_event) {
 
+	if (p_event.type==InputEvent::MOUSE_MOTION) {
+
+		Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y );
+
+		int hover=-1;
+		for(int i=0;i<tabs.size();i++) {
+
+			if (tabs[i].rb_rect.has_point(pos)) {
+				hover=i;
+				break;
+			}
+		}
+
+		if (hover!=rb_hover) {
+			rb_hover=hover;
+			update();
+		}
+		return;
+	}
+
+	if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
+	    !p_event.mouse_button.pressed &&
+	    p_event.mouse_button.button_index==BUTTON_LEFT) {
+
+		if (rb_hover!=-1) {
+			//pressed
+			emit_signal("right_button_pressed",rb_hover);
+		}
+
+		rb_pressing=false;
+		update();
+	}
+
 	if (p_event.type==InputEvent::MOUSE_BUTTON &&
 	    p_event.mouse_button.pressed &&
 	    p_event.mouse_button.button_index==BUTTON_LEFT) {
@@ -76,6 +116,12 @@ void Tabs::_input_event(const InputEvent& p_event) {
 		int found=-1;
 		for(int i=0;i<tabs.size();i++) {
 
+			if (tabs[i].rb_rect.has_point(pos)) {
+				rb_pressing=true;
+				update();
+				return;
+			}
+
 			int ofs=tabs[i].ofs_cache;
 			int size = tabs[i].ofs_cache;
 			if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) {
@@ -100,7 +146,10 @@ void Tabs::_notification(int p_what) {
 
 	switch(p_what) {
 
-
+		case NOTIFICATION_MOUSE_EXIT: {
+			rb_hover=-1;
+			update();
+		} break;
 		case NOTIFICATION_DRAW: {
 
 			RID ci = get_canvas_item();
@@ -142,7 +191,7 @@ void Tabs::_notification(int p_what) {
 
 				Ref<Texture> icon;
 				if (tabs[i].icon.is_valid()) {
-					Ref<Texture> icon = tabs[i].icon;
+					icon = tabs[i].icon;
 					if (icon.is_valid()) {
 						lsize+=icon->get_width();
 						if (s!="")
@@ -151,6 +200,16 @@ void Tabs::_notification(int p_what) {
 					}
 				}
 
+				if (tabs[i].right_button.is_valid()) {
+					Ref<StyleBox> style = get_stylebox("button");
+					Ref<Texture> rb=tabs[i].right_button;
+
+					lsize+=get_constant("hseparation");
+					lsize+=style->get_margin(MARGIN_LEFT);
+					lsize+=rb->get_width();
+					lsize+=style->get_margin(MARGIN_RIGHT);
+
+				}
 
 				Ref<StyleBox> sb;
 				int va;
@@ -184,7 +243,37 @@ void Tabs::_notification(int p_what) {
 
 				font->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col );
 
-				w+=slen+sb->get_margin(MARGIN_RIGHT);
+				w+=slen;
+
+				if (tabs[i].right_button.is_valid()) {
+					Ref<StyleBox> style = get_stylebox("button");
+					Ref<Texture> rb=tabs[i].right_button;
+
+					w+=get_constant("hseparation");
+
+					Rect2 rb_rect;
+					rb_rect.size=style->get_minimum_size()+rb->get_size();
+					rb_rect.pos.x=w;
+					rb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(rb_rect.size.y))/2;
+
+					if (rb_hover==i) {
+						if (rb_pressing)
+							get_stylebox("button_pressed")->draw(ci,rb_rect);
+						else
+							style->draw(ci,rb_rect);
+					}
+
+					w+=style->get_margin(MARGIN_LEFT);
+
+					rb->draw(ci,Point2i( w,rb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
+					w+=rb->get_width();
+					w+=style->get_margin(MARGIN_RIGHT);
+					tabs[i].rb_rect=rb_rect;
+
+
+				}
+
+				w+=sb->get_margin(MARGIN_RIGHT);
 
 				tabs[i].size_cache=w-tabs[i].ofs_cache;
 
@@ -252,6 +341,23 @@ Ref<Texture> Tabs::get_tab_icon(int p_tab) const{
 
 }
 
+
+
+void Tabs::set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button){
+
+	ERR_FAIL_INDEX(p_tab,tabs.size());
+	tabs[p_tab].right_button=p_right_button;
+	update();
+	minimum_size_changed();
+
+}
+Ref<Texture> Tabs::get_tab_right_button(int p_tab) const{
+
+	ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>());
+	return tabs[p_tab].right_button;
+
+}
+
 void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) {
 
 	Tab t;
@@ -316,6 +422,7 @@ void Tabs::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_tab_align"),&Tabs::get_tab_align);
 
 	ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab")));
+	ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab")));
 
 	ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") );
 
@@ -328,5 +435,7 @@ Tabs::Tabs() {
 
 	current=0;
 	tab_align=ALIGN_CENTER;
+	rb_hover=-1;
+	rb_pressing=false;
 
 }

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov