소스 검색

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

Conflicts:
	drivers/SCsub
	platform/x11/detect.py
	platform/x11/os_x11.h
Anton Yabchinskiy 10 년 전
부모
커밋
4ab1bcde35
100개의 변경된 파일4019개의 추가작업 그리고 1161개의 파일을 삭제
  1. 0 5
      README.md
  2. 4 3
      core/bind/core_bind.cpp
  3. 1 1
      core/bind/core_bind.h
  4. 2 0
      core/io/http_client.cpp
  5. 1 1
      core/io/ip.cpp
  6. 3 1
      core/io/xml_parser.cpp
  7. 5 1
      core/math/math_funcs.h
  8. 3 1
      core/method_bind.cpp
  9. 5 0
      core/object.cpp
  10. 1 0
      core/object.h
  11. 15 2
      core/object_type_db.cpp
  12. 1 1
      core/object_type_db.h
  13. 1 0
      core/register_core_types.cpp
  14. 1 1
      core/script_language.h
  15. 126 0
      core/variant.cpp
  16. 7 1
      core/variant.h
  17. 6 0
      core/variant_call.cpp
  18. 1 1
      demos/3d/mousepick_test/mousepick.gd
  19. 2 2
      demos/misc/tween/main.gd
  20. 1 0
      drivers/SCsub
  21. 1 1
      drivers/chibi/cp_loader_s3m.cpp
  22. 10 0
      drivers/gles1/rasterizer_gles1.cpp
  23. 3 0
      drivers/gles1/rasterizer_gles1.h
  24. 48 1
      drivers/gles2/rasterizer_gles2.cpp
  25. 3 0
      drivers/gles2/rasterizer_gles2.h
  26. 1 1
      drivers/gles2/shaders/material.glsl
  27. 1 1
      drivers/mpc/audio_stream_mpc.cpp
  28. 5 1
      drivers/png/pngpriv.h
  29. 5 0
      drivers/pulseaudio/SCsub
  30. 194 0
      drivers/pulseaudio/audio_driver_pulseaudio.cpp
  31. 79 0
      drivers/pulseaudio/audio_driver_pulseaudio.h
  32. 3 0
      drivers/theoraplayer/SCsub
  33. 1 1
      drivers/unix/ip_unix.cpp
  34. 6 0
      drivers/unix/os_unix.cpp
  35. 1 1
      drivers/vorbis/os.h
  36. 5 2
      drivers/windows/dir_access_windows.cpp
  37. 0 1
      drivers/windows/file_access_windows.cpp
  38. 1 0
      main/main.cpp
  39. 0 30
      makefile
  40. 7 0
      modules/gdscript/gd_compiler.cpp
  41. 1158 365
      modules/gdscript/gd_editor.cpp
  42. 254 52
      modules/gdscript/gd_parser.cpp
  43. 52 3
      modules/gdscript/gd_parser.h
  44. 2 1
      modules/gdscript/gd_script.cpp
  45. 19 1
      modules/gdscript/gd_script.h
  46. 5 1
      modules/gdscript/gd_tokenizer.cpp
  47. 1 0
      modules/gdscript/gd_tokenizer.h
  48. 20 2
      platform/android/java/src/com/android/godot/GodotIO.java
  49. 2 1
      platform/windows/os_windows.cpp
  50. 1 1
      platform/winrt/SCsub
  51. 234 11
      platform/winrt/app.cpp
  52. 12 2
      platform/winrt/app.h
  53. 99 26
      platform/winrt/detect.py
  54. 27 1
      platform/winrt/gl_context_egl.cpp
  55. 1 0
      platform/winrt/gl_context_egl.h
  56. 14 7
      platform/winrt/include/EGL/eglext.h
  57. 2 2
      platform/winrt/include/EGL/eglplatform.h
  58. 57 159
      platform/winrt/include/GLSLANG/ShaderLang.h
  59. 75 18
      platform/winrt/include/GLSLANG/ShaderVars.h
  60. 28 3
      platform/winrt/os_winrt.cpp
  61. 7 0
      platform/winrt/os_winrt.h
  62. 7 0
      platform/x11/detect.py
  63. 16 0
      platform/x11/os_x11.cpp
  64. 9 1
      platform/x11/os_x11.h
  65. 21 1
      scene/2d/collision_polygon_2d.cpp
  66. 4 0
      scene/2d/collision_polygon_2d.h
  67. 4 1
      scene/2d/physics_body_2d.cpp
  68. 7 0
      scene/3d/physics_body.cpp
  69. 13 0
      scene/animation/animation_player.cpp
  70. 3 0
      scene/animation/animation_player.h
  71. 120 75
      scene/animation/tween.cpp
  72. 24 21
      scene/animation/tween.h
  73. 2 2
      scene/gui/box_container.cpp
  74. 57 39
      scene/gui/control.cpp
  75. 320 0
      scene/gui/graph_node.cpp
  76. 61 0
      scene/gui/graph_node.h
  77. 528 283
      scene/gui/text_edit.cpp
  78. 15 3
      scene/gui/text_edit.h
  79. 20 0
      scene/main/node.cpp
  80. 1 0
      scene/main/node.h
  81. 2 0
      scene/register_scene_types.cpp
  82. 21 9
      scene/resources/audio_stream_resampled.cpp
  83. 2 2
      scene/resources/audio_stream_resampled.h
  84. 11 2
      scene/resources/default_theme/default_theme.cpp
  85. BIN
      scene/resources/default_theme/graph_node.png
  86. BIN
      scene/resources/default_theme/graph_port.png
  87. 1 0
      scene/resources/default_theme/theme_data.h
  88. 16 0
      scene/resources/material.cpp
  89. 1 0
      scene/resources/material.h
  90. 3 1
      scene/resources/polygon_path_finder.cpp
  91. 43 0
      scene/resources/shader.cpp
  92. 6 1
      scene/resources/shader.h
  93. 4 0
      servers/visual/rasterizer.h
  94. 10 0
      servers/visual/rasterizer_dummy.cpp
  95. 4 0
      servers/visual/rasterizer_dummy.h
  96. 10 0
      servers/visual/visual_server_raster.cpp
  97. 4 0
      servers/visual/visual_server_raster.h
  98. 4 0
      servers/visual/visual_server_wrap_mt.h
  99. 4 0
      servers/visual_server.h
  100. 11 3
      tools/editor/code_editor.cpp

+ 0 - 5
README.md

@@ -10,11 +10,6 @@ The editor, language and APIs are feature rich, yet simple to learn, allowing yo
 Godot has been developed by Juan Linietsky and Ariel Manzur for several years, and was born as an in-house engine, used to publish several work-for-hire titles.
 Development is sponsored by OKAM Studio (http://www.okamstudio.com).
 
-### Godot is BETA. Collaborate!!
-
-Having been developed as in-house means that the user experience may still not be ideal for everyone. The features needed to make a great game are there, but we really need your help to fix all the rough edges and improve usability (via feedback and/or code contributions).
-We know we are close to having an awesome, open source, game engine with nothing to envy from the best commercial offerings, but we can't do this alone. This is why Godot is now open source, so everyone can help us reach this goal.
-
 ### Documentation
 
 Documentation has been moved to the [GitHub Wiki](https://github.com/okamstudio/godot/wiki).

+ 4 - 3
core/bind/core_bind.cpp

@@ -12,9 +12,9 @@ Ref<ResourceInteractiveLoader> _ResourceLoader::load_interactive(const String& p
 	return ResourceLoader::load_interactive(p_path,p_type_hint);
 }
 
-RES _ResourceLoader::load(const String &p_path,const String& p_type_hint) {
+RES _ResourceLoader::load(const String &p_path,const String& p_type_hint, bool p_no_cache) {
 
-	RES ret =  ResourceLoader::load(p_path,p_type_hint);
+	RES ret =  ResourceLoader::load(p_path,p_type_hint, p_no_cache);
 	return ret;
 }
 
@@ -59,7 +59,7 @@ void _ResourceLoader::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("load_interactive:ResourceInteractiveLoader","path","type_hint"),&_ResourceLoader::load_interactive,DEFVAL(""));
-	ObjectTypeDB::bind_method(_MD("load:Resource","path","type_hint"),&_ResourceLoader::load,DEFVAL(""));
+	ObjectTypeDB::bind_method(_MD("load:Resource","path","type_hint", "p_no_cache"),&_ResourceLoader::load,DEFVAL(""), DEFVAL(false));
 	ObjectTypeDB::bind_method(_MD("get_recognized_extensions_for_type","type"),&_ResourceLoader::get_recognized_extensions_for_type);
 	ObjectTypeDB::bind_method(_MD("set_abort_on_missing_resources","abort"),&_ResourceLoader::set_abort_on_missing_resources);
 	ObjectTypeDB::bind_method(_MD("get_dependencies"),&_ResourceLoader::get_dependencies);
@@ -1121,6 +1121,7 @@ String _File::get_as_text() const {
 		text+=l+"\n";
 		l = get_line();
 	}
+	text+=l;
 
 	return text;
 

+ 1 - 1
core/bind/core_bind.h

@@ -21,7 +21,7 @@ public:
 
 	static _ResourceLoader *get_singleton() { return singleton; }
 	Ref<ResourceInteractiveLoader> load_interactive(const String& p_path,const String& p_type_hint="");
-	RES load(const String &p_path,const String& p_type_hint="");
+	RES load(const String &p_path,const String& p_type_hint="", bool p_no_cache = false);
 	DVector<String> get_recognized_extensions_for_type(const String& p_type);
 	void set_abort_on_missing_resources(bool p_abort);
 	StringArray get_dependencies(const String& p_path);

+ 2 - 0
core/io/http_client.cpp

@@ -29,6 +29,8 @@
 #include "http_client.h"
 #include "io/stream_peer_ssl.h"
 
+VARIANT_ENUM_CAST(HTTPClient::Status);
+
 Error HTTPClient::connect_url(const String& p_url) {
 
 	return OK;

+ 1 - 1
core/io/ip.cpp

@@ -31,7 +31,7 @@
 #include "os/semaphore.h"
 #include "hash_map.h"
 
-
+VARIANT_ENUM_CAST(IP::ResolverStatus);
 
 /************* RESOLVER ******************/
 

+ 3 - 1
core/io/xml_parser.cpp

@@ -30,9 +30,11 @@
 #include "print_string.h"
 //#define DEBUG_XML
 
+VARIANT_ENUM_CAST(XMLParser::NodeType);
+
 static bool _equalsn(const CharType* str1, const CharType* str2, int len) {
 	int i;
-	for(i=0; str1[i] && str2[i] && i < len; ++i)
+	for(i=0; i < len && str1[i] && str2[i] ; ++i)
 	     if (str1[i] != str2[i])
 		     return false;
 

+ 5 - 1
core/math/math_funcs.h

@@ -136,7 +136,10 @@ public:
 
 		static int b;
 
-#if defined(_MSC_VER) && _MSC_VER < 1800
+#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone?
+		b = (int)((a>0.0f) ? (a + 0.5f):(a -0.5f));
+
+#elif defined(_MSC_VER) && _MSC_VER < 1800
 		__asm fld a
 		__asm fistp b
 /*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
@@ -147,6 +150,7 @@ public:
 		"fistpl %0      \n\t"
 		: "=m" (b)
 		: "m" (a));*/
+
 #else
 		b=lrintf(a); //assuming everything but msvc 2012 or earlier has lrint
 #endif

+ 3 - 1
core/method_bind.cpp

@@ -87,7 +87,9 @@ Vector<StringName> MethodBind::get_argument_names() const {
 
 
 void MethodBind::set_default_arguments(const Vector<Variant>& p_defargs) {
-	default_arguments=p_defargs; default_argument_count=default_arguments.size();
+	default_arguments=p_defargs;
+	default_argument_count=default_arguments.size();
+
 }
 
 #ifdef DEBUG_METHODS_ENABLED

+ 5 - 0
core/object.cpp

@@ -1694,6 +1694,11 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
 }
 
 
+void Object::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+
+}
+
 int ObjectDB::get_object_count() {
 
 	GLOBAL_LOCK_FUNCTION;

+ 1 - 0
core/object.h

@@ -583,6 +583,7 @@ public:
 
 	virtual void get_translatable_strings(List<String> *p_strings) const;
 
+	virtual void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
 
 	StringName XL_MESSAGE(const StringName& p_message) const; //translate message (internationalization)
 	StringName tr(const StringName& p_message) const; //translate message (alternative)

+ 15 - 2
core/object_type_db.cpp

@@ -805,12 +805,25 @@ void ObjectTypeDB::add_virtual_method(const StringName& p_type,const MethodInfo&
 
 }
 
-void ObjectTypeDB::get_virtual_methods(const StringName& p_type,List<MethodInfo> * p_methods ) {
+void ObjectTypeDB::get_virtual_methods(const StringName& p_type, List<MethodInfo> * p_methods , bool p_no_inheritance) {
 
 	ERR_FAIL_COND(!types.has(p_type));
 
 #ifdef DEBUG_METHODS_ENABLED
-	*p_methods=types[p_type].virtual_methods;
+
+	TypeInfo *type=types.getptr(p_type);
+	TypeInfo *check=type;
+	while(check) {
+
+		for(List<MethodInfo>::Element *E=check->virtual_methods.front();E;E=E->next()) {
+			p_methods->push_back(E->get());
+		}
+
+		if (p_no_inheritance)
+			return;
+		check=check->inherits_ptr;
+	}
+
 #endif
 
 }

+ 1 - 1
core/object_type_db.h

@@ -468,7 +468,7 @@ public:
 	static MethodBind *get_method(StringName p_type, StringName p_name);
 
 	static void add_virtual_method(const StringName& p_type,const MethodInfo& p_method );
-	static void get_virtual_methods(const StringName& p_type,List<MethodInfo> * p_methods );
+	static void get_virtual_methods(const StringName& p_type,List<MethodInfo> * p_methods,bool p_no_inheritance=false );
 	
 	static void bind_integer_constant(const StringName& p_type, const StringName &p_name, int p_constant);
 	static void get_integer_constant_list(const StringName& p_type, List<String> *p_constants, bool p_no_inheritance=false);

+ 1 - 0
core/register_core_types.cpp

@@ -110,6 +110,7 @@ void register_core_types() {
 
 
 	ObjectTypeDB::register_type<Reference>();
+	ObjectTypeDB::register_type<WeakRef>();
 	ObjectTypeDB::register_type<ResourceImportMetadata>();
 	ObjectTypeDB::register_type<Resource>();
 	ObjectTypeDB::register_type<FuncRef>();

+ 1 - 1
core/script_language.h

@@ -144,7 +144,7 @@ public:
 	virtual bool has_named_classes() const=0;
 	virtual int find_function(const String& p_function,const String& p_code) const=0;
 	virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const=0;
-	virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_keyword, List<String>* r_options) { return ERR_UNAVAILABLE; }
+	virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint) { return ERR_UNAVAILABLE; }
 	virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const=0;
 
 	/* DEBUGGER FUNCTIONS */

+ 126 - 0
core/variant.cpp

@@ -2631,3 +2631,129 @@ Variant Variant::call(const StringName& p_method,VARIANT_ARG_DECLARE) {
 	return ret;
 }
 
+
+String Variant::get_construct_string() const {
+
+	switch( type ) {
+
+		case NIL: return "null";
+		case BOOL: return _data._bool ? "true" : "false";
+		case INT: return String::num(_data._int);
+		case REAL: return String::num(_data._real);
+		case STRING: return "\""+*reinterpret_cast<const String*>(_data._mem)+"\"";
+		case VECTOR2: return "Vector2("+operator Vector2()+")";
+		case RECT2: return "Rect2("+operator Rect2()+")";
+		case MATRIX32: return "Matrix32("+operator Matrix32()+")";
+		case VECTOR3: return "Vector3("+operator Vector3()+")";
+		case PLANE: return "Plane("+operator Plane()+")";
+		//case QUAT:
+		case _AABB: return "AABB("+operator AABB()+")";
+		case QUAT: return "Quat("+operator Quat()+")";
+		case MATRIX3: return "Matrix3("+operator Matrix3()+")";
+		case TRANSFORM: return "Transform("+operator Transform()+")";
+		case NODE_PATH: return "@\""+operator NodePath()+"\"";
+		case INPUT_EVENT: return "InputEvent()";
+		case COLOR: return "Color("+String::num( operator Color().r)+","+String::num( operator Color().g)+","+String::num( operator Color().b)+","+String::num( operator Color().a)+")" ;
+		case DICTIONARY: {
+
+			const Dictionary &d =*reinterpret_cast<const Dictionary*>(_data._mem);
+			//const String *K=NULL;
+			String str="{";
+			List<Variant> keys;
+			d.get_key_list(&keys);
+
+			Vector<_VariantStrPair> pairs;
+
+			for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+				_VariantStrPair sp;
+				sp.key=E->get().get_construct_string();
+				sp.value=d[E->get()].get_construct_string();
+				pairs.push_back(sp);
+			}
+
+			pairs.sort();
+
+			for(int i=0;i<pairs.size();i++) {
+				if (i>0)
+					str+=", ";
+				str+="("+pairs[i].key+":"+pairs[i].value+")";
+			}
+			str+="}";
+
+			return str;
+		} break;
+		case VECTOR3_ARRAY: {
+
+			DVector<Vector3> vec = operator DVector<Vector3>();
+			String str="[";
+			for(int i=0;i<vec.size();i++) {
+
+				if (i>0)
+					str+=", ";
+				str+=Variant( vec[i] ).get_construct_string();
+			}
+			return str+"]";
+		} break;
+		case STRING_ARRAY: {
+
+			DVector<String> vec = operator DVector<String>();
+			String str="[";
+			for(int i=0;i<vec.size();i++) {
+
+				if (i>0)
+					str+=", ";
+				str=str+=Variant( vec[i] ).get_construct_string();
+			}
+			return str+"]";
+		} break;
+		case INT_ARRAY: {
+
+			DVector<int> vec = operator DVector<int>();
+			String str="[";
+			for(int i=0;i<vec.size();i++) {
+
+				if (i>0)
+					str+=", ";
+				str=str+itos(vec[i]);
+			}
+			return str+"]";
+		} break;
+		case REAL_ARRAY: {
+
+			DVector<real_t> vec = operator DVector<real_t>();
+			String str="[";
+			for(int i=0;i<vec.size();i++) {
+
+				if (i>0)
+					str+=", ";
+				str=str+rtos(vec[i]);
+			}
+			return str+"]";
+		} break;
+		case ARRAY: {
+
+			Array arr = operator Array();
+			String str="[";
+			for (int i=0; i<arr.size(); i++) {
+				if (i)
+					str+=", ";
+				str += arr[i].get_construct_string();
+			};
+			return str+"]";
+
+		} break;
+		case OBJECT: {
+
+			if (_get_obj().obj)
+				return _get_obj().obj->get_type()+".new()";
+			else
+				return "null";
+
+		} break;
+		default: {
+			return "["+get_type_name(type)+"]";
+		}
+	}
+
+}

+ 7 - 1
core/variant.h

@@ -167,14 +167,18 @@ public:
 	static String get_type_name(Variant::Type p_type);
 	static bool can_convert(Type p_type_from,Type p_type_to);
 
+
+
 	template<class T>
 	static Type get_type_for() {
 		
 		GetSimpleType<T> t;
 		Variant v(t.type);
-		return v.get_type();
+		Type r = v.get_type();
+		return r;
 	}
 
+
 	bool is_ref() const;
 	_FORCE_INLINE_ bool is_num() const { return type==INT || type==REAL; };
 	_FORCE_INLINE_ bool is_array() const { return type>=ARRAY; };
@@ -415,6 +419,8 @@ public:
 	static bool has_numeric_constant(Variant::Type p_type, const StringName& p_value);
 	static int get_numeric_constant_value(Variant::Type p_type, const StringName& p_value);
 
+	String get_construct_string() const;
+
 	void operator=(const Variant& p_variant); // only this is enough for all the other types
 	Variant(const Variant& p_variant);
 	_FORCE_INLINE_ Variant() { type=NIL; }

+ 6 - 0
core/variant_call.cpp

@@ -757,6 +757,11 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 		r_ret=Quat(*p_args[0],*p_args[1],*p_args[2],*p_args[3]);
 	}
 
+    static void Quat_init2(Variant& r_ret,const Variant** p_args) {
+
+        r_ret=Quat(((Vector3)(*p_args[0])),((float)(*p_args[1])));
+    }
+
 	static void Color_init1(Variant& r_ret,const Variant** p_args) {
 
 		r_ret=Color(*p_args[0],*p_args[1],*p_args[2],*p_args[3]);
@@ -1509,6 +1514,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
 	_VariantCall::add_constructor(_VariantCall::Plane_init3,Variant::PLANE,"normal",Variant::VECTOR3,"d",Variant::REAL);
 
 	_VariantCall::add_constructor(_VariantCall::Quat_init1,Variant::QUAT,"x",Variant::REAL,"y",Variant::REAL,"z",Variant::REAL,"w",Variant::REAL);
+    _VariantCall::add_constructor(_VariantCall::Quat_init2,Variant::QUAT,"axis",Variant::VECTOR3,"angle",Variant::REAL);
 
 	_VariantCall::add_constructor(_VariantCall::Color_init1,Variant::COLOR,"r",Variant::REAL,"g",Variant::REAL,"b",Variant::REAL,"a",Variant::REAL);
 	_VariantCall::add_constructor(_VariantCall::Color_init2,Variant::COLOR,"r",Variant::REAL,"g",Variant::REAL,"b",Variant::REAL);

+ 1 - 1
demos/3d/mousepick_test/mousepick.gd

@@ -9,7 +9,7 @@ var gray_mat = FixedMaterial.new()
 
 var selected=false
 
-func _input_event(event,pos,normal,shape):
+func _input_event(camera,event,pos,normal,shape):
 	if (event.type==InputEvent.MOUSE_BUTTON and event.pressed):
 		if (not selected):
 			get_node("mesh").set_material_override(gray_mat)

+ 2 - 2
demos/misc/tween/main.gd

@@ -112,8 +112,8 @@ func reset_tween():
 		tween.interpolate_property(sprite, "transform/rot", 360, 0, 2, state.trans, state.eases, 2)
 	
 	if get_node("modes/callback").is_pressed():
-		tween.interpolate_callback(self, "on_callback", 0.5, "0.5 second's after")
-		tween.interpolate_callback(self, "on_callback", 1.2, "1.2 second's after")
+		tween.interpolate_callback(self, 0.5, "on_callback", "0.5 second's after")
+		tween.interpolate_callback(self, 0.2, "on_callback", "1.2 second's after")
 	
 	if get_node("modes/follow").is_pressed():
 		follow.show()

+ 1 - 0
drivers/SCsub

@@ -8,6 +8,7 @@ Export('env')
 SConscript('unix/SCsub');
 SConscript('alsa/SCsub');
 SConscript('ao/SCsub');
+SConscript('pulseaudio/SCsub');
 SConscript('windows/SCsub');
 SConscript('gles2/SCsub');
 SConscript('gles1/SCsub');

+ 1 - 1
drivers/chibi/cp_loader_s3m.cpp

@@ -162,7 +162,7 @@ CPLoader::Error  CPLoader_S3M::load_sample(CPSample *p_sample) {
 		p_sample->set_default_volume(def_volume);
 		p_sample->set_name(name);
 		
-		char scrs[4];
+		char scrs[5];
 		file->get_byte_array((uint8_t*)scrs,4);
 		scrs[4]=0;
 

+ 10 - 0
drivers/gles1/rasterizer_gles1.cpp

@@ -1021,6 +1021,16 @@ void RasterizerGLES1::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_
 
 }
 
+
+void RasterizerGLES1::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+}
+
+RID RasterizerGLES1::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const {
+
+	return RID();
+}
+
 /* COMMON MATERIAL API */
 
 

+ 3 - 0
drivers/gles1/rasterizer_gles1.h

@@ -875,6 +875,9 @@ public:
 
 	virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
 
+	virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+	virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
+
 	/* COMMON MATERIAL API */
 
 	virtual RID material_create();

+ 48 - 1
drivers/gles2/rasterizer_gles2.cpp

@@ -1539,6 +1539,29 @@ void RasterizerGLES2::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_
 
 }
 
+void RasterizerGLES2::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+	Shader *shader=shader_owner.get(p_shader);
+	ERR_FAIL_COND(!shader);
+	ERR_FAIL_COND(!texture_owner.owns(p_texture));
+
+	if (p_texture.is_valid())
+		shader->default_textures[p_name]=p_texture;
+	else
+		shader->default_textures.erase(p_name);
+
+}
+
+RID RasterizerGLES2::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{
+	const Shader *shader=shader_owner.get(p_shader);
+
+	const Map<StringName,RID>::Element *E=shader->default_textures.find(p_name);
+	if (!E)
+		return RID();
+	return E->get();
+}
+
+
 
 /* COMMON MATERIAL API */
 
@@ -4991,9 +5014,26 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
 				Texture *t=NULL;
 				if (rid.is_valid()) {
 
+
 					t=texture_owner.get(rid);
-					if (!t)
+					if (!t) {
 						E->get().value=RID(); //nullify, invalid texture
+						rid=RID();
+					}
+				} else {
+
+
+				}
+
+				if (!rid.is_valid()) {
+					//use from default textures
+					Map<StringName,RID>::Element *F=p_material->shader_cache->default_textures.find(E->key());
+					if (F) {
+						t=texture_owner.get(F->get());
+						if (!t) {
+							p_material->shader_cache->default_textures.erase(E->key());
+						}
+					}
 				}
 
 
@@ -5020,6 +5060,13 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
 
 		}
 
+		for (Map<StringName,RID>::Element *E=p_material->shader_cache->default_textures.front();E;E=E->next()) {
+			if (p_material->shader_params.has(E->key()))
+				continue;
+
+
+		}
+
 		if (p_material->shader_cache->has_texscreen && framebuffer.active) {
 			material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_SCREEN_MULT,Vector2(float(viewport.width)/framebuffer.width,float(viewport.height)/framebuffer.height));
 			material_shader.set_uniform(MaterialShaderGLES2::TEXSCREEN_TEX,texcoord);

+ 3 - 0
drivers/gles2/rasterizer_gles2.h

@@ -195,6 +195,7 @@ class RasterizerGLES2 : public Rasterizer {
 		Map<StringName,ShaderLanguage::Uniform> uniforms;
 		StringName first_texture;
 
+		Map<StringName,RID> default_textures;
 
 		SelfList<Shader> dirty_list;
 
@@ -1255,6 +1256,8 @@ public:
 
 	virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
 
+	virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+	virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
 
 	/* COMMON MATERIAL API */
 

+ 1 - 1
drivers/gles2/shaders/material.glsl

@@ -1230,7 +1230,7 @@ LIGHT_SHADER_CODE
 
 	vec3 ambient = const_light_mult*ambient_light*diffuse.rgb;
 # if defined(LIGHT_TYPE_OMNI) || defined (LIGHT_TYPE_SPOT)
-	ambient*=diffuse_interp.a; //attenuation affects ambient too
+//	ambient*=diffuse_interp.a; //attenuation affects ambient too
 
 # endif
 

+ 1 - 1
drivers/mpc/audio_stream_mpc.cpp

@@ -275,7 +275,7 @@ void AudioStreamMPC::stop()  {
 }
 bool AudioStreamMPC::is_playing() const  {
 
-	return active;
+	return active || (get_total() - get_todo() -1 > 0);
 }
 
 void AudioStreamMPC::set_paused(bool p_paused)  {

+ 5 - 1
drivers/png/pngpriv.h

@@ -341,7 +341,11 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
 #  ifdef _WINDOWS_  /* Favor Windows over C runtime fns */
 #    define CVT_PTR(ptr)         (ptr)
 #    define CVT_PTR_NOCHECK(ptr) (ptr)
-#    define png_strlen  lstrlenA
+#    ifdef WINRT_ENABLED
+#      define png_strlen  strlen
+#    else
+#      define png_strlen  lstrlenA
+#    endif
 #    define png_memcmp  memcmp
 #    define png_memcpy  CopyMemory
 #    define png_memset  memset

+ 5 - 0
drivers/pulseaudio/SCsub

@@ -0,0 +1,5 @@
+Import('env')
+
+env.add_source_files(env.drivers_sources,"*.cpp")
+
+Export('env')

+ 194 - 0
drivers/pulseaudio/audio_driver_pulseaudio.cpp

@@ -0,0 +1,194 @@
+/*************************************************************************/
+/*  audio_driver_alsa.cpp                                                */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+#include "audio_driver_pulseaudio.h"
+
+#ifdef PULSEAUDIO_ENABLED
+
+#include <pulse/error.h>
+
+#include "globals.h"
+
+Error AudioDriverPulseAudio::init() {
+
+    active = false;
+    thread_exited = false;
+    exit_thread = false;
+	pcm_open = false;
+	samples_in = NULL;
+	samples_out = NULL;
+
+	mix_rate = 44100;
+	output_format = OUTPUT_STEREO;
+	channels = 2;
+
+    pa_sample_spec spec;
+    spec.format = PA_SAMPLE_S16LE;
+    spec.channels = channels;
+    spec.rate = mix_rate;
+
+    int error_code;
+    pulse = pa_simple_new(NULL,         // default server
+                          "Godot",      // application name
+                          PA_STREAM_PLAYBACK,
+                          NULL,         // default device
+                          "Sound",      // stream description
+                          &spec,
+                          NULL,         // use default channel map
+                          NULL,         // use default buffering attributes
+                          &error_code
+                          );
+
+    if (pulse == NULL) {
+
+        fprintf(stderr, "PulseAudio ERR: %s\n", pa_strerror(error_code));\
+        ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN);
+    }
+
+    int latency = GLOBAL_DEF("audio/output_latency", 25);
+    buffer_size = nearest_power_of_2(latency * mix_rate / 1000);
+
+    samples_in = memnew_arr(int32_t, buffer_size * channels);
+    samples_out = memnew_arr(int16_t, buffer_size * channels);
+
+    mutex = Mutex::create();
+    thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
+
+	return OK;
+}
+
+void AudioDriverPulseAudio::thread_func(void* p_udata) {
+
+    AudioDriverPulseAudio* ad = (AudioDriverPulseAudio*)p_udata;
+
+	while (!ad->exit_thread) {
+
+		if (!ad->active) {
+
+            for (unsigned int i=0; i < ad->buffer_size * ad->channels; i++) {
+
+				ad->samples_out[i] = 0;
+            }
+
+		} else {
+
+			ad->lock();
+
+			ad->audio_server_process(ad->buffer_size, ad->samples_in);
+
+			ad->unlock();
+
+            for (unsigned int i=0; i < ad->buffer_size * ad->channels;i ++) {
+
+                ad->samples_out[i] = ad->samples_in[i] >> 16;
+			}
+        }
+
+        // pa_simple_write always consumes the entire buffer
+
+        int error_code;
+        int byte_size = ad->buffer_size * sizeof(int16_t) * ad->channels;
+        if (pa_simple_write(ad->pulse, ad->samples_out, byte_size, &error_code) < 0) {
+
+            // can't recover here
+            fprintf(stderr, "PulseAudio failed and can't recover: %s\n", pa_strerror(error_code));
+            ad->active = false;
+            ad->exit_thread = true;
+            break;
+        }
+    }
+
+    ad->thread_exited = true;
+}
+
+void AudioDriverPulseAudio::start() {
+
+	active = true;
+}
+
+int AudioDriverPulseAudio::get_mix_rate() const {
+
+	return mix_rate;
+}
+
+AudioDriverSW::OutputFormat AudioDriverPulseAudio::get_output_format() const {
+
+	return output_format;
+}
+
+void AudioDriverPulseAudio::lock() {
+
+	if (!thread || !mutex)
+		return;
+	mutex->lock();
+}
+
+void AudioDriverPulseAudio::unlock() {
+
+	if (!thread || !mutex)
+		return;
+	mutex->unlock();
+}
+
+void AudioDriverPulseAudio::finish() {
+
+	if (!thread)
+		return;
+
+	exit_thread = true;
+	Thread::wait_to_finish(thread);
+
+    if (pulse)
+        pa_simple_free(pulse);
+
+	if (samples_in) {
+		memdelete_arr(samples_in);
+		memdelete_arr(samples_out);
+	};
+
+	memdelete(thread);
+    if (mutex) {
+		memdelete(mutex);
+        mutex = NULL;
+    }
+
+	thread = NULL;
+}
+
+AudioDriverPulseAudio::AudioDriverPulseAudio() {
+
+	mutex = NULL;
+    thread = NULL;
+    pulse = NULL;
+}
+
+AudioDriverPulseAudio::~AudioDriverPulseAudio() {
+
+}
+
+#endif

+ 79 - 0
drivers/pulseaudio/audio_driver_pulseaudio.h

@@ -0,0 +1,79 @@
+/*************************************************************************/
+/*  audio_driver_pulseaudio.h                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                    http://www.godotengine.org                         */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+#include "servers/audio/audio_server_sw.h"
+
+#ifdef PULSEAUDIO_ENABLED
+
+#include "core/os/thread.h"
+#include "core/os/mutex.h"
+
+#include <pulse/simple.h>
+
+class AudioDriverPulseAudio : public AudioDriverSW {
+
+	Thread* thread;
+	Mutex* mutex;
+
+    pa_simple* pulse;
+
+	int32_t* samples_in;
+	int16_t* samples_out;
+
+	static void thread_func(void* p_udata);
+
+	unsigned int mix_rate;
+	OutputFormat output_format;
+
+    unsigned int buffer_size;
+	int channels;
+
+	bool active;
+	bool thread_exited;
+	mutable bool exit_thread;
+	bool pcm_open;
+
+public:
+
+	const char* get_name() const {
+        return "PulseAudio";
+	};
+
+	virtual Error init();
+	virtual void start();
+	virtual int get_mix_rate() const;
+	virtual OutputFormat get_output_format() const;
+	virtual void lock();
+	virtual void unlock();
+	virtual void finish();
+
+    AudioDriverPulseAudio();
+    ~AudioDriverPulseAudio();
+};
+
+#endif

+ 3 - 0
drivers/theoraplayer/SCsub

@@ -78,6 +78,9 @@ else:
 if env["platform"] == "android":
 	env_theora.Append(CPPFLAGS=["-D_ANDROID"])
 
+if env["platform"] == "winrt":
+		env_theora.Append(CPPFLAGS=["-D_WINRT"])
+
 env_theora.Append(CPPPATH=["#drivers/theoraplayer/include/theoraplayer", "#drivers/theoraplayer/src/YUV", "#drivers/theoraplayer/src/YUV/libyuv/include", "#drivers/theoraplayer/src/Theora", "#drivers/theoraplayer/src/AVFoundation"])
 
 objs = []

+ 1 - 1
drivers/unix/ip_unix.cpp

@@ -28,7 +28,7 @@
 /*************************************************************************/
 #include "ip_unix.h"
 
-#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
+#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) && !defined(WINRT_ENABLED)
 
 
 #ifdef WINDOWS_ENABLED

+ 6 - 0
drivers/unix/os_unix.cpp

@@ -332,6 +332,12 @@ Error OS_Unix::execute(const String& p_path, const List<String>& p_arguments,boo
 Error OS_Unix::kill(const ProcessID& p_pid) {
 
 	int ret = ::kill(p_pid,SIGKILL);
+	if (!ret) {
+		//avoid zombie process
+		int st;
+		::waitpid(p_pid,&st,0);
+
+	}
 	return ret?ERR_INVALID_PARAMETER:OK;
 }
 

+ 1 - 1
drivers/vorbis/os.h

@@ -120,7 +120,7 @@ static inline int vorbis_ftoi(double f){  /* yes, double!  Otherwise,
 
 /* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the
  * 64 bit compiler */
-#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_WIN32_WCE)
+#if defined(_MSC_VER) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(WINDOWSPHONE_ENABLED)
 #  define VORBIS_FPU_CONTROL
 
 typedef ogg_int16_t vorbis_fpu_control;

+ 5 - 2
drivers/windows/dir_access_windows.cpp

@@ -106,6 +106,7 @@ String DirAccessWindows::get_next() {
 		return name;
 	} else {
 
+#ifndef WINRT_ENABLED
 		_cisdir=(p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
 
 		String name=p->f.cFileName;
@@ -117,7 +118,8 @@ String DirAccessWindows::get_next() {
 		}
 
 		return name;
-
+#endif
+		return "";
 	}
 }
 
@@ -358,6 +360,7 @@ bool DirAccessWindows::dir_exists(String p_dir) {
 		return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
 
 	} else {
+#ifndef WINRT_ENABLED
 		DWORD fileAttr;
 
 		fileAttr = GetFileAttributesExA(p_dir.ascii().get_data(), GetFileExInfoStandard, &fileInfo);
@@ -366,8 +369,8 @@ bool DirAccessWindows::dir_exists(String p_dir) {
 
 		return (fileAttr&FILE_ATTRIBUTE_DIRECTORY);
 
+#endif
 	}
-
 	return false;
 }
 

+ 0 - 1
drivers/windows/file_access_windows.cpp

@@ -54,7 +54,6 @@ void FileAccessWindows::check_errors() const {
 Error FileAccessWindows::_open(const String& p_filename, int p_mode_flags) {
 
 	String filename=fix_path(p_filename);
-
 	if (f)
 		close();
 

+ 1 - 0
main/main.cpp

@@ -147,6 +147,7 @@ void Main::print_help(const char* p_binary) {
 			OS::get_singleton()->print(", ");
 		OS::get_singleton()->print("%s",OS::get_singleton()->get_audio_driver_name(i));
 	}
+    OS::get_singleton()->print(")\n");
 	OS::get_singleton()->print("\t-rthread <mode>\t : Render Thread Mode ('unsafe', 'safe', 'separate).");
 	OS::get_singleton()->print(")\n");
 	OS::get_singleton()->print("\t-s,-script [script] : Run a script.\n");	

+ 0 - 30
makefile

@@ -1,30 +0,0 @@
-#*************************************************************************/
-#*                       This file is part of:                           */
-#*                           GODOT ENGINE                                */
-#*                    http://www.godotengine.org                         */
-#*************************************************************************/
-# Simple makefile to give support for external C/C++ IDEs                */
-#*************************************************************************/
-
-# Default build
-all: debug
-
-# Release Build
-release:
-	scons target="release" bin/godot
-
-# Profile Build
-profile:
-	scons target="profile" bin/godot
-
-# Debug Build
-debug:
-	# Debug information (code size gets severely affected):
-	# g: Default (same as g2)
-	# g0: no debug info
-	# g1: minimal info
-	# g3: maximal info
-	scons target="debug" CCFLAGS="-g" bin/godot
-
-clean:
-	scons -c bin/godot

+ 7 - 0
modules/gdscript/gd_compiler.cpp

@@ -1168,6 +1168,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
 	codegen.current_line=0;
 	codegen.call_max=0;
 	codegen.debug_stack=ScriptDebugger::get_singleton()!=NULL;
+	Vector<StringName> argnames;
 
 	int stack_level=0;
 
@@ -1175,6 +1176,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
 		for(int i=0;i<p_func->arguments.size();i++) {
 			int idx = i;
 			codegen.add_stack_identifier(p_func->arguments[i],i);
+#ifdef TOOLS_ENABLED
+			argnames.push_back(p_func->arguments[i]);
+#endif
 		}
 		stack_level=p_func->arguments.size();
 	}
@@ -1249,6 +1253,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
 	if (p_func)
 		gdfunc->_static=p_func->_static;
 
+#ifdef TOOLS_ENABLED
+	gdfunc->arg_names=argnames;
+#endif
 	//constants
 	if (codegen.constant_map.size()) {
 		gdfunc->_constant_count=codegen.constant_map.size();

+ 1158 - 365
modules/gdscript/gd_editor.cpp

@@ -312,171 +312,278 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
 
 }
 
-static void _parse_native_symbols(const StringName& p_native,bool p_static,List<String>* r_options) {
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
 
-	if (!p_static) {
-		List<MethodInfo> methods;
-		ObjectTypeDB::get_method_list(p_native,&methods);
-		for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
-			if (!E->get().name.begins_with("_")) {
-				r_options->push_back(E->get().name);
-			}
+struct GDCompletionIdentifier {
+
+	StringName obj_type;
+	Variant::Type type;
+	Variant value; //im case there is a value, also return it
+};
+
+
+
+static GDCompletionIdentifier _get_type_from_variant(const Variant& p_variant) {
+
+	GDCompletionIdentifier t;
+	t.type=p_variant.get_type();
+	t.value=p_variant;
+	if (p_variant.get_type()==Variant::OBJECT) {
+		Object *obj = p_variant;
+		if (obj) {
+			//if (obj->cast_to<GDNativeClass>()) {
+			//	t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
+			//	t.value=Variant();
+			//} else {
+				t.obj_type=obj->get_type();
+			//}
 		}
 	}
+	return t;
+}
 
-	List<String> constants;
-	ObjectTypeDB::get_integer_constant_list(p_native,&constants);
+static GDCompletionIdentifier _get_type_from_pinfo(const PropertyInfo& p_info) {
 
-	for(List<String>::Element *E=constants.front();E;E=E->next()) {
-		r_options->push_back(E->get());
+	GDCompletionIdentifier t;
+	t.type=p_info.type;
+	if (p_info.hint==PROPERTY_HINT_RESOURCE_TYPE) {
+		t.obj_type=p_info.hint_string;
 	}
-
+	return t;
 }
 
+struct GDCompletionContext {
 
-static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,List<String>* r_options,List<String>::Element *p_indices);
+	const GDParser::ClassNode *_class;
+	const GDParser::FunctionNode *function;
+	const GDParser::BlockNode *block;
+	Object* base;
+	String base_path;
 
+};
 
-static bool _parse_completion_variant(const Variant& p_var,List<String>* r_options,List<String>::Element *p_indices) {
 
-	if (p_indices) {
+static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
 
-		bool ok;
-		Variant si = p_var.get(p_indices->get(),&ok);
-		if (!ok)
-			return false;
-		return _parse_completion_variant(si,r_options,p_indices->next());
-	} else {
 
-		switch(p_var.get_type()) {
 
+	if (context._class->extends_used) {
+		//do inheritance
+		String path = context._class->extends_file;
+
+		Ref<GDScript> script;
+		Ref<GDNativeClass> native;
 
-			case Variant::DICTIONARY: {
+		if (path!="") {
+			//path (and optionally subclasses)
 
-				Dictionary d=p_var;
-				List<Variant> vl;
-				d.get_key_list(&vl);
-				for (List<Variant>::Element *E=vl.front();E;E=E->next()) {
+			if (path.is_rel_path()) {
 
-					if (E->get().get_type()==Variant::STRING)
-						r_options->push_back(E->get());
-				}
+				path=context.base_path.plus_file(path);
+			}
+			script = ResourceLoader::load(path);
+			if (script.is_null()) {
+				return REF();
+			}
+			if (script->is_valid()) {
+
+				return REF();
+			}
+			//print_line("EXTENDS PATH: "+path+" script is "+itos(script.is_valid())+" indices is "+itos(script->member_indices.size())+" valid? "+itos(script->valid));
+
+			if (context._class->extends_class.size()) {
+
+				for(int i=0;i<context._class->extends_class.size();i++) {
+
+					String sub = context._class->extends_class[i];
+					if (script->get_subclasses().has(sub)) {
 
+						script=script->get_subclasses()[sub];
+					} else {
 
-				List<MethodInfo> ml;
-				p_var.get_method_list(&ml);
-				for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
-					r_options->push_back(E->get().name);
+						return REF();
+					}
 				}
+			}
+
+			if (script.is_valid())
+				return script;
+
+		} else {
 
-			} break;
-			case Variant::OBJECT: {
+			if (context._class->extends_class.size()==0) {
+				ERR_PRINT("BUG");
+				return REF();
+			}
+
+			String base=context._class->extends_class[0];
+			const GDParser::ClassNode *p = context._class->owner;
+			Ref<GDScript> base_class;
+#if 0
+			while(p) {
+
+				if (p->subclasses.has(base)) {
 
+					base_class=p->subclasses[base];
+					break;
+				}
+				p=p->_owner;
+			}
+#endif
+			if (base_class.is_valid()) {
+#if 0
+				for(int i=1;i<context._class->extends_class.size();i++) {
 
-				Object *o=p_var;
-				if (o) {
-					print_line("OBJECT: "+o->get_type());
-					if (p_var.is_ref() && o->cast_to<GDScript>()) {
+					String subclass=context._class->extends_class[i];
 
-						Ref<GDScript> gds = p_var;
-						_parse_script_symbols(gds,true,r_options,NULL);
-					} else if (o->is_type("GDNativeClass")){
+					if (base_class->subclasses.has(subclass)) {
 
-						GDNativeClass *gnc = o->cast_to<GDNativeClass>();
-						_parse_native_symbols(gnc->get_name(),false,r_options);
+						base_class=base_class->subclasses[subclass];
 					} else {
 
-						print_line("REGULAR BLEND");
-						_parse_native_symbols(o->get_type(),false,r_options);
+						print_line("Could not find subclass: "+subclass);
+						return _get_type_from_class(context); //fail please
 					}
 				}
 
-			} break;
-			default: {
+				script=base_class;
+#endif
+
+			} else {
+
+				if (context._class->extends_class.size()>1) {
+
+					return REF();
+
 
-				List<PropertyInfo> pi;
-				p_var.get_property_list(&pi);
-				for(List<PropertyInfo>::Element *E=pi.front();E;E=E->next()) {
-					r_options->push_back(E->get().name);
 				}
-				List<StringName> cl;
+				//if not found, try engine classes
+				if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
 
-				p_var.get_numeric_constants_for_type(p_var.get_type(),&cl);
-				for(List<StringName>::Element *E=cl.front();E;E=E->next()) {
-					r_options->push_back(E->get());
+					return REF();
 				}
 
-				List<MethodInfo> ml;
-				p_var.get_method_list(&ml);
-				for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
-					r_options->push_back(E->get().name);
+				int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
+				native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
+				if (!native.is_valid()) {
+
+					print_line("Global not a class: '"+base+"'");
+
 				}
+				return native;
+			}
+
 
-			} break;
 		}
 
-		return true;
 	}
 
-
+	return Ref<Reference>();
 }
 
-struct GDCompletionIdentifier {
 
-	StringName obj_type;
-	Variant::Type type;
-};
+static GDCompletionIdentifier _get_native_class(GDCompletionContext& context) {
+
+	//eeh...
+	GDCompletionIdentifier id;
+	id.type=Variant::NIL;
+
+	REF pc  = _get_parent_class(context);
+	if (!pc.is_valid()) {
+		return id;
+	}
+	Ref<GDNativeClass> nc = pc;
+	Ref<GDScript> s = pc;
+
+	if (s.is_null() && nc.is_null()) {
+		return id;
+	}
+	while(!s.is_null()) {
+		nc=s->get_native();
+		s=s->get_base();
+	}
+	if (nc.is_null()) {
+		return id;
+	}
+
 
 
-static GDCompletionIdentifier _guess_identifier_type(const GDParser::ClassNode *p_class,int p_line,const StringName& p_identifier);
+	id.type=Variant::OBJECT;
+	if (context.base)
+		id.value=context.base;
+	id.obj_type=nc->get_name();
+	return id;
+}
+
+static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type);
 
 
-static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_class,const GDParser::Node *p_node,int p_line,GDCompletionIdentifier &r_type) {
+static bool _guess_expression_type(GDCompletionContext& context,const GDParser::Node* p_node,int p_line,GDCompletionIdentifier &r_type) {
 
 
 	if (p_node->type==GDParser::Node::TYPE_CONSTANT) {
 
 		const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node);
 
-		r_type.type=cn->value.get_type();
-		if (r_type.type==Variant::OBJECT) {
-			Object *obj = cn->value;
-			if (obj) {
-				r_type.obj_type=obj->get_type();
-			}
-		}
+		r_type=_get_type_from_variant(cn->value);
 
 		return true;
 	} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
 
 		r_type.type=Variant::DICTIONARY;
+
+
+		//what the heck, fill it anyway
+		const GDParser::DictionaryNode *an = static_cast<const GDParser::DictionaryNode *>(p_node);
+		Dictionary d;
+		for(int i=0;i<an->elements.size();i++) {
+			GDCompletionIdentifier k;
+			if (_guess_expression_type(context,an->elements[i].key,p_line,k) && k.value.get_type()!=Variant::NIL) {
+				GDCompletionIdentifier v;
+				if (_guess_expression_type(context,an->elements[i].value,p_line,v)) {
+					d[k.value]=v.value;
+				}
+
+			}
+		}
+		r_type.value=d;
 		return true;
 	} else if (p_node->type==GDParser::Node::TYPE_ARRAY) {
 
 		r_type.type=Variant::ARRAY;
+		//what the heck, fill it anyway
+		const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode *>(p_node);
+		Array arr;
+		arr.resize(an->elements.size());
+		for(int i=0;i<an->elements.size();i++) {
+			GDCompletionIdentifier ci;
+			if (_guess_expression_type(context,an->elements[i],p_line,ci)) {
+				arr[i]=ci.value;
+			}
+		}
+		r_type.value=arr;
 		return true;
 
 	} else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
 
 		MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function);
-		r_type.type=mi.return_val.type;
-		if (mi.return_val.hint==PROPERTY_HINT_RESOURCE_TYPE) {
-			r_type.obj_type=mi.return_val.hint_string;
-		}
+		r_type=_get_type_from_pinfo(mi.return_val);
+
 		return true;
 	} else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) {
 
-
-		r_type=_guess_identifier_type(p_class,p_line,static_cast<const GDParser::IdentifierNode *>(p_node)->name);
-		return true;
+		return _guess_identifier_type(context,p_line-1,static_cast<const GDParser::IdentifierNode *>(p_node)->name,r_type);
 	} else if (p_node->type==GDParser::Node::TYPE_SELF) {
 		//eeh...
-		return false;
+
+		r_type=_get_native_class(context);
+		return r_type.type!=Variant::NIL;
 
 	} else if (p_node->type==GDParser::Node::TYPE_OPERATOR) {
+
+
 		const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node);
 		if (op->op==GDParser::OperatorNode::OP_CALL) {
-
 			if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
 
 				const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode *>(op->arguments[0]);
@@ -486,25 +593,86 @@ static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_cl
 
 
 				const GDParser::BuiltInFunctionNode *bin = static_cast<const GDParser::BuiltInFunctionNode *>(op->arguments[0]);
-				return _guess_identifier_type_in_expression(p_class,bin,p_line,r_type);
+				return _guess_expression_type(context,bin,p_line,r_type);
 
 			} else if (op->arguments.size()>1 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
 
+
 				GDCompletionIdentifier base;
-				if (!_guess_identifier_type_in_expression(p_class,op->arguments[0],p_line,base))
+				if (!_guess_expression_type(context,op->arguments[0],p_line,base))
 					return false;
-				StringName id = static_cast<const GDParser::IdentifierNode *>(p_node)->name;
+
+				StringName id = static_cast<const GDParser::IdentifierNode *>(op->arguments[1])->name;
+
 				if (base.type==Variant::OBJECT) {
 
+					if (id.operator String()=="new" && base.value.get_type()==Variant::OBJECT) {
+						Object *obj = base.value;
+						if (obj && obj->cast_to<GDNativeClass>()) {
+							GDNativeClass *gdnc = obj->cast_to<GDNativeClass>();
+							r_type.type=Variant::OBJECT;
+							r_type.value=Variant();
+							r_type.obj_type=gdnc->get_name();
+							return true;
+						}
+					}
+
 					if (ObjectTypeDB::has_method(base.obj_type,id)) {
+
 #ifdef TOOLS_ENABLED
 						MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id);
 						PropertyInfo pi = mb->get_argument_info(-1);
 
+						//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) {
+							bool all_valid=true;
+							Vector<Variant> args;
+							for(int i=2;i<op->arguments.size();i++) {
+								GDCompletionIdentifier arg;
+
+								if (_guess_expression_type(context,op->arguments[i],p_line,arg)) {
+									if (arg.value.get_type()!=Variant::NIL && arg.value.get_type()!=Variant::OBJECT) { // calling with object seems dangerous, i don' t know
+										args.push_back(arg.value);
+									} else {
+										all_valid=false;
+										break;
+									}
+								} else {
+									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 (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;
+									}
+								}
+
+							}
+						}
+
 						r_type.type=pi.type;
 						if (pi.hint==PROPERTY_HINT_RESOURCE_TYPE) {
 							r_type.obj_type=pi.hint_string;
 						}
+
+
+
+						return true;
 #else
 						return false;
 #endif
@@ -519,7 +687,8 @@ static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_cl
 					v.get_method_list(&mi);
 					for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
 
-						if (E->get().name==id.operator String()) {
+						if (!E->get().name.begins_with("_") && E->get().name==id.operator String()) {
+
 
 							MethodInfo mi = E->get();
 							r_type.type=mi.return_val.type;
@@ -534,49 +703,157 @@ static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_cl
 
 
 			}
+		} else if (op->op==GDParser::OperatorNode::OP_INDEX || op->op==GDParser::OperatorNode::OP_INDEX_NAMED) {
+
+			GDCompletionIdentifier p1;
+			GDCompletionIdentifier p2;
+
+
+
+			if (op->op==GDParser::OperatorNode::OP_INDEX_NAMED) {
+
+				if (op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
+					String id = static_cast<const GDParser::IdentifierNode*>(op->arguments[1])->name;
+					p2.type=Variant::STRING;
+					p2.value=id;
+				}
+
+			} else {
+				if (op->arguments[1]) {
+					if (!_guess_expression_type(context,op->arguments[1],p_line,p2)) {
+
+						return false;
+					}
+				}
+			}
+
+			if (op->arguments[0]->type==GDParser::Node::TYPE_ARRAY) {
+
+				const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode *>(op->arguments[0]);
+				if (p2.value.is_num()) {
+					int index = p2.value;
+					if (index<0 || index>=an->elements.size())
+						return false;
+					return _guess_expression_type(context,an->elements[index],p_line,r_type);
+				}
+
+			} else if (op->arguments[0]->type==GDParser::Node::TYPE_DICTIONARY) {
+
+				const GDParser::DictionaryNode *dn = static_cast<const GDParser::DictionaryNode *>(op->arguments[0]);
+
+				if (p2.value.get_type()==Variant::NIL)
+					return false;
+
+				for(int i=0;i<dn->elements.size();i++) {
+
+					GDCompletionIdentifier k;
+
+					if (!_guess_expression_type(context,dn->elements[i].key,p_line,k)) {
+
+						return false;
+					}
+
+					if (k.value.get_type()==Variant::NIL)
+						return false;
+
+					if (k.value==p2.value) {
+
+						return _guess_expression_type(context,dn->elements[i].value,p_line,r_type);
+					}
+				}
+
+			} else {
+
+				if (op->arguments[0]) {
+					if (!_guess_expression_type(context,op->arguments[0],p_line,p1)) {
+
+						return false;
+					}
+
+				}
+
+				if (p1.value.get_type()==Variant::OBJECT) {
+					//??
+				} else if (p1.value.get_type()!=Variant::NIL) {
+
+					bool valid;
+					Variant ret = p1.value.get(p2.value,&valid);
+					if (valid) {
+						r_type=_get_type_from_variant(ret);
+						return true;
+					}
+
+				} else {
+					if (p1.type!=Variant::NIL) {
+						Variant::CallError ce;
+						Variant base = Variant::construct(p1.type,NULL,0,ce);
+						bool valid;
+						Variant ret = base.get(p2.value,&valid);
+						if (valid) {
+							r_type=_get_type_from_variant(ret);
+							return true;
+						}
+					}
+				}
+			}
+
 		} else {
 
+
 			Variant::Operator vop = Variant::OP_MAX;
 			switch(op->op) {
-				case GDParser::OperatorNode::OP_ASSIGN_ADD: vop=Variant::OP_ADD; break;
-				case GDParser::OperatorNode::OP_ASSIGN_SUB: vop=Variant::OP_SUBSTRACT; break;
-				case GDParser::OperatorNode::OP_ASSIGN_MUL: vop=Variant::OP_MULTIPLY; break;
-				case GDParser::OperatorNode::OP_ASSIGN_DIV: vop=Variant::OP_DIVIDE; break;
-				case GDParser::OperatorNode::OP_ASSIGN_MOD: vop=Variant::OP_MODULE; break;
-				case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: vop=Variant::OP_SHIFT_LEFT; break;
-				case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: vop=Variant::OP_SHIFT_RIGHT; break;
-				case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: vop=Variant::OP_BIT_AND; break;
-				case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: vop=Variant::OP_BIT_OR; break;
-				case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: vop=Variant::OP_BIT_XOR; break;
+				case GDParser::OperatorNode::OP_ADD: vop=Variant::OP_ADD; break;
+				case GDParser::OperatorNode::OP_SUB: vop=Variant::OP_SUBSTRACT; break;
+				case GDParser::OperatorNode::OP_MUL: vop=Variant::OP_MULTIPLY; break;
+				case GDParser::OperatorNode::OP_DIV: vop=Variant::OP_DIVIDE; break;
+				case GDParser::OperatorNode::OP_MOD: vop=Variant::OP_MODULE; break;
+				case GDParser::OperatorNode::OP_SHIFT_LEFT: vop=Variant::OP_SHIFT_LEFT; break;
+				case GDParser::OperatorNode::OP_SHIFT_RIGHT: vop=Variant::OP_SHIFT_RIGHT; break;
+				case GDParser::OperatorNode::OP_BIT_AND: vop=Variant::OP_BIT_AND; break;
+				case GDParser::OperatorNode::OP_BIT_OR: vop=Variant::OP_BIT_OR; break;
+				case GDParser::OperatorNode::OP_BIT_XOR: vop=Variant::OP_BIT_XOR; break;
 				default:{}
 
 			}
 
+
+
 			if (vop==Variant::OP_MAX)
 				return false;
 
+
+
 			GDCompletionIdentifier p1;
 			GDCompletionIdentifier p2;
 
 			if (op->arguments[0]) {
-				if (!_guess_identifier_type_in_expression(p_class,op->arguments[0],p_line,p1))
+				if (!_guess_expression_type(context,op->arguments[0],p_line,p1)) {
+
 					return false;
+				}
+
 			}
 
 			if (op->arguments.size()>1) {
-				if (!_guess_identifier_type_in_expression(p_class,op->arguments[1],p_line,p2))
+				if (!_guess_expression_type(context,op->arguments[1],p_line,p2)) {
+
 					return false;
+				}
 			}
 
 			Variant::CallError ce;
-			Variant v1 = Variant::construct(p1.type,NULL,0,ce);
-			Variant v2 = Variant::construct(p2.type,NULL,0,ce);
+			bool v1_use_value = p1.value.get_type()!=Variant::NIL && p1.value.get_type()!=Variant::OBJECT;
+			Variant v1 = (v1_use_value)?p1.value:Variant::construct(p1.type,NULL,0,ce);
+			bool v2_use_value = p2.value.get_type()!=Variant::NIL && p2.value.get_type()!=Variant::OBJECT;
+			Variant v2 = (v2_use_value)?p2.value:Variant::construct(p2.type,NULL,0,ce);
 			// avoid potential invalid ops
 			if ((vop==Variant::OP_DIVIDE || vop==Variant::OP_MODULE) && v2.get_type()==Variant::INT) {
 				v2=1;
+				v2_use_value=false;
 			}
 			if (vop==Variant::OP_DIVIDE && v2.get_type()==Variant::REAL) {
 				v2=1.0;
+				v2_use_value=false;
 			}
 
 			Variant r;
@@ -585,6 +862,9 @@ static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_cl
 			if (!valid)
 				return false;
 			r_type.type=r.get_type();
+			if (v1_use_value && v2_use_value)
+				r_type.value=r;
+
 			return true;
 
 		}
@@ -594,46 +874,42 @@ static bool _guess_identifier_type_in_expression(const GDParser::ClassNode *p_cl
 	return false;
 }
 
-static bool _guess_identifier_type_in_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
-
-
-	for(int i=0;i<p_block->sub_blocks.size();i++) {
-		//parse inner first
-		if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) {
-			if (_guess_identifier_type_in_block(p_class,p_block->sub_blocks[i],p_line,p_identifier,r_type))
-				return true;
-		}
-	}
+static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
 
 
 
 	const GDParser::Node *last_assign=NULL;
 	int last_assign_line=-1;
 
-	for (int i=0;i<p_block->statements.size();i++) {
+	for (int i=0;i<context.block->statements.size();i++) {
+
+		if (context.block->statements[i]->line>p_line)
+			continue;
 
-		if (p_block->statements[i]->line>p_line)
-			break;
 
+		if (context.block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
 
-		if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+			const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(context.block->statements[i]);
 
-			const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);
 			if (lv->assign && lv->name==p_identifier) {
+
 				last_assign=lv->assign;
-				last_assign_line=p_block->statements[i]->line;
+				last_assign_line=context.block->statements[i]->line;
 			}
 		}
 
-		if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
-			const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_block->statements[i]);
+		if (context.block->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
+			const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(context.block->statements[i]);
 			if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
 
 				if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
+
 					const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]);
+
 					if (id->name==p_identifier) {
+
 						last_assign=op->arguments[1];
-						last_assign_line=p_block->statements[i]->line;
+						last_assign_line=context.block->statements[i]->line;
 					}
 				}
 			}
@@ -642,418 +918,935 @@ static bool _guess_identifier_type_in_block(const GDParser::ClassNode *p_class,c
 
 	//use the last assignment, (then backwards?)
 	if (last_assign) {
-		return _guess_identifier_type_in_expression(p_class,last_assign,last_assign_line-1,r_type);
+
+		return _guess_expression_type(context,last_assign,last_assign_line,r_type);
 	}
 
+
 	return false;
 }
 
-static GDCompletionIdentifier _guess_identifier_type(const GDParser::ClassNode *p_class,int p_line,const StringName& p_identifier) {
+static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
 
+	//go to block first
 
-	return GDCompletionIdentifier();
-}
-
-static void _parse_expression_node(const GDParser::ClassNode *p_class,const GDParser::Node *p_node,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
 
+	const GDParser::BlockNode *block=context.block;
 
+	while(block) {
 
-	if (p_node->type==GDParser::Node::TYPE_CONSTANT) {
-
-		const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node);
-		_parse_completion_variant(cn->value,r_options,p_indices?p_indices->next():NULL);
-	} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
+		GDCompletionContext c = context;
+		c.block=block;
 
-		const GDParser::DictionaryNode *dn=static_cast<const GDParser::DictionaryNode*>(p_node);
-		for (int i=0;i<dn->elements.size();i++) {
+		if (_guess_identifier_type_in_block(c,p_line,p_identifier,r_type)) {
+			return true;
+		}
 
-			if (dn->elements[i].key->type==GDParser::Node::TYPE_CONSTANT) {
+		block=block->parent_block;
+	}
 
-				const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(dn->elements[i].key);
-				if (cn->value.get_type()==Variant::STRING) {
+	//guess from argument if virtual
+	if (context.function && context.function->name!=StringName()) {
 
-					String str=cn->value;
-					if (p_indices) {
+		int argindex = -1;
 
-						if (str==p_indices->get()) {
-							_parse_expression_node(p_class,dn->elements[i].value,p_line,r_options,p_indices->next());
-							return;
-						}
+		for(int i=0;i<context.function->arguments.size();i++) {
 
-					} else {
-						r_options->push_back(str);
-					}
-				}
+			if (context.function->arguments[i]==p_identifier) {
+				argindex=i;
+				break;
 			}
+
 		}
-	} else if (p_node->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
 
-		MethodInfo mi = GDFunctions::get_info(static_cast<const GDParser::BuiltInFunctionNode*>(p_node)->function);
+		if (argindex!=-1) {
+			GDCompletionIdentifier id =_get_native_class(context);
+			if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
+				//this kinda sucks but meh
 
-		Variant::CallError ce;
-		_parse_completion_variant(Variant::construct(mi.return_val.type,NULL,0,ce),r_options,p_indices?p_indices->next():NULL);
-	} else if (p_node->type==GDParser::Node::TYPE_IDENTIFIER) {
+				List<MethodInfo> vmethods;
+				ObjectTypeDB::get_virtual_methods(id.obj_type,&vmethods);
+				for (List<MethodInfo>::Element *E=vmethods.front();E;E=E->next()) {
 
-		//GDCompletionIdentifier idt = _guess_identifier_type(p_class,p_line-1,static_cast<const GDParser::IdentifierNode *>(p_node)->name);
-		//Variant::CallError ce;
-		//_parse_completion_variant(Variant::construct(mi.return_val.type,NULL,0,ce),r_options,p_indices?p_indices->next():NULL);
-	}
-}
 
-static bool _parse_completion_block(const GDParser::ClassNode *p_class,const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
+					if (E->get().name==context.function->name && argindex<E->get().arguments.size()) {
 
-	print_line("COMPLETION BLOCK "+itos(p_block->line)+" -> "+itos(p_block->end_line));
+						PropertyInfo arg=E->get().arguments[argindex];
 
-	for(int i=0;i<p_block->sub_blocks.size();i++) {
-		//parse inner first
-		if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) {
-			if (_parse_completion_block(p_class,p_block->sub_blocks[i],p_line,r_options,p_indices))
-				return true;
+						int scp = arg.name.find(":");
+						if (scp!=-1) {
+
+
+							r_type.type=Variant::OBJECT;
+							r_type.obj_type=arg.name.substr(scp+1,arg.name.length());
+							return true;
+
+						} else {
+
+							r_type.type=arg.type;
+							if (arg.hint==PROPERTY_HINT_RESOURCE_TYPE)
+								r_type.obj_type=arg.hint_string;
+							return true;
+						}
+					}
+				}
+			}
 		}
 	}
 
-	if (p_indices) {
+	//guess type in constant
 
-		//parse indices in expressions :|
+	for(int i=0;i<context._class->constant_expressions.size();i++) {
 
-		const GDParser::Node *last_assign=NULL;
-		int last_assign_line=-1;
+		if (context._class->constant_expressions[i].identifier==p_identifier) {
 
-		for (int i=0;i<p_block->statements.size();i++) {
+			ERR_FAIL_COND_V( context._class->constant_expressions[i].expression->type!=GDParser::Node::TYPE_CONSTANT, false );
+			r_type=_get_type_from_variant(static_cast<const GDParser::ConstantNode*>(context._class->constant_expressions[i].expression)->value );
+			return true;
+		}
+	}
 
-			if (p_block->statements[i]->line>p_line)
-				break;
+	if (!(context.function && context.function->_static)) {
 
+		for(int i=0;i<context._class->variables.size();i++) {
 
-			if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+			if (context._class->variables[i].identifier==p_identifier) {
 
-				const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);				
-				if (lv->assign && String(lv->name)==p_indices->get()) {
-					last_assign=lv->assign;
-					last_assign_line=p_block->statements[i]->line;
+				if (context._class->variables[i]._export.type!=Variant::NIL) {
+
+					r_type=_get_type_from_pinfo(context._class->variables[i]._export);
+					return true;
+				} else if (context._class->variables[i].expression) {
+					return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
 				}
 			}
 		}
+	}
 
-		//use the last assignment, (then backwards?)
-		if (last_assign) {
-			_parse_expression_node(p_class,last_assign,last_assign_line,r_options,p_indices->next());
-			return true;
-		}
 
-	} else {
-		//no indices, just add all variables and continue
-		for(int i=0;i<p_block->variables.size();i++) {
-			//parse variables second
-			if (p_line>=p_block->variable_lines[i]) {
-				r_options->push_back(p_block->variables[i]);
-			} else break;
 
+	for(Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
+		if (E->key()==p_identifier) {
+
+			r_type=_get_type_from_variant(GDScriptLanguage::get_singleton()->get_global_array()[E->get()]);
+			return true;
 		}
-	}
 
+	}
 	return false;
 }
 
 
-static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,List<String>* r_options,List<String>::Element *p_indices) {
+static void _find_identifiers_in_block(GDCompletionContext& context,int p_line,bool p_only_functions,Set<String>& result) {
 
-	//for (Map<StringName,Ref<GDScript> >::Element ?
+	if (p_only_functions)
+		return;
 
-	if (!p_static && !p_indices) {
-		for(const Set<StringName>::Element *E=p_script->get_members().front();E;E=E->next()) {
+	for (int i=0;i<context.block->statements.size();i++) {
 
-			r_options->push_back(E->get());
-		}
-	}
+		if (context.block->statements[i]->line>p_line)
+			continue;
 
-	for (const Map<StringName,Variant >::Element *E=p_script->get_constants().front();E;E=E->next()) {
 
-		if( p_indices) {
-			if (p_indices->get()==String(E->get())) {
-				_parse_completion_variant(E->get(),r_options,p_indices->next());
-				return true;
-			}
-		} else {
-			r_options->push_back(E->key());
+		if (context.block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+
+			const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(context.block->statements[i]);
+			result.insert(lv->name.operator String());
 		}
 	}
+}
 
-	if (!p_indices){
-		for (const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().front();E;E=E->next()) {
+static void _find_identifiers_in_class(GDCompletionContext& context,bool p_static,bool p_only_functions,Set<String>& result) {
 
-			if (E->get().is_static() || !p_static)
-				r_options->push_back(E->key());
+	if (!p_static && !p_only_functions) {
+
+		for(int i=0;i<context._class->variables.size();i++) {
+			result.insert(context._class->variables[i].identifier);
 		}
 	}
+	if (!p_only_functions) {
+
+		for(int i=0;i<context._class->constant_expressions.size();i++) {
+			result.insert(context._class->constant_expressions[i].identifier);
+		}
+
+		for(int i=0;i<context._class->subclasses.size();i++) {
+			result.insert(context._class->subclasses[i]->name);
+		}
 
-	if (p_script->get_base().is_valid()){
-		if (_parse_script_symbols(p_script->get_base(),p_static,r_options,p_indices))
-			return true;
-	} else if (p_script->get_native().is_valid() && !p_indices) {
-		_parse_native_symbols(p_script->get_native()->get_name(),p_static,r_options);
 	}
 
-	return false;
-}
+	for(int i=0;i<context._class->static_functions.size();i++) {
+		if (context._class->static_functions[i]->arguments.size())
+			result.insert(context._class->static_functions[i]->name.operator String()+"(");
+		else
+			result.insert(context._class->static_functions[i]->name.operator String()+"()");
+	}
+
+	if (!p_static) {
+
+		for(int i=0;i<context._class->functions.size();i++) {
+			if (context._class->functions[i]->arguments.size())
+				result.insert(context._class->functions[i]->name.operator String()+"(");
+			else
+				result.insert(context._class->functions[i]->name.operator String()+"()");
+		}
+	}
 
+	//globals
 
-static bool _parse_completion_class(const String& p_base_path,const GDParser::ClassNode *p_class,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
+	Ref<Reference> base = _get_parent_class(context);
 
-	//checks known classes or built-in types for completion
+	while(true) {
 
-	if (p_indices && !p_indices->next()) {
-		//built-in types do not have sub-classes, try these first if no sub-indices exist.
-		static const char*_type_names[Variant::VARIANT_MAX]={
-			"null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
-			"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
-			"Vector2Array","Vector3Array","ColorArray"};
+		Ref<GDScript> script = base;
+		Ref<GDNativeClass> nc = base;
+		if (script.is_valid()) {
 
-		for(int i=0;i<Variant::VARIANT_MAX;i++) {
+			if (!p_static && !p_only_functions) {
+				for (const Set<StringName>::Element *E=script->get_members().front();E;E=E->next()) {
+					result.insert(E->get().operator String());
+				}
+			}
 
-			if (p_indices->get()==_type_names[i]) {
+			if (!p_only_functions) {
+				for (const Map<StringName,Variant>::Element *E=script->get_constants().front();E;E=E->next()) {
+					result.insert(E->key().operator String());
+				}
+			}
 
-				List<StringName> ic;
+			for (const Map<StringName,GDFunction>::Element *E=script->get_member_functions().front();E;E=E->next()) {
+				if (!p_static || E->get().is_static()) {
+					if (E->get().get_argument_count())
+						result.insert(E->key().operator String()+"(");
+					else
+						result.insert(E->key().operator String()+"()");
+				}
+			}
 
-				Variant::get_numeric_constants_for_type(Variant::Type(i),&ic);
-				for(List<StringName>::Element *E=ic.front();E;E=E->next()) {
-					r_options->push_back(E->get());
+			if (!p_only_functions)	{
+				for (const Map<StringName,Ref<GDScript> >::Element *E=script->get_subclasses().front();E;E=E->next()) {
+					result.insert(E->key().operator String());
 				}
-				return true;
 			}
-		}
+
+			base=script->get_base();
+			if (base.is_null())
+				base=script->get_native();
+		} else if (nc.is_valid()) {
+
+			if (!p_only_functions) {
+
+				StringName type = nc->get_name();
+				List<String> constants;
+				ObjectTypeDB::get_integer_constant_list(type,&constants);
+				for(List<String>::Element *E=constants.front();E;E=E->next()) {
+					result.insert(E->get());
+				}
+
+				List<MethodInfo> methods;
+				ObjectTypeDB::get_method_list(type,&methods);
+				for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+					if (E->get().name.begins_with("_"))
+						continue;
+					if (E->get().arguments.size())
+						result.insert(E->get().name+"(");
+					else
+						result.insert(E->get().name+"()");
+				}
+			}
+			break;
+		} else
+			break;
+
 	}
 
-	// check the sub-classes of current class
+}
 
-	for(int i=0;i<p_class->subclasses.size();i++) {
+static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_only_functions,Set<String>& result) {
 
-		if (p_line>=p_class->subclasses[i]->line && (p_line<=p_class->subclasses[i]->end_line || p_class->subclasses[i]->end_line==-1)) {
-			// if OK in sub-classes, try completing the sub-class
-			if (_parse_completion_class(p_base_path,p_class->subclasses[i],p_line,r_options,p_indices))
-				return true;
-		}
+	const GDParser::BlockNode *block=context.block;
+
+	while(block) {
+
+		GDCompletionContext c = context;
+		c.block=block;
+
+		_find_identifiers_in_block(c,p_line,p_only_functions,result);
+		block=block->parent_block;
+	}
+
+	const GDParser::ClassNode *clss=context._class;
+
+	bool _static=context.function && context.function->_static;
+
+	while(clss) {
+		GDCompletionContext c = context;
+		c._class=clss;
+		c.block=NULL;
+		c.function=NULL;
+		_find_identifiers_in_class(c,_static,p_only_functions,result);
+		clss=clss->owner;
 	}
 
-	bool in_static_func=false;
+	for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
 
-	for(int i=0;i<p_class->functions.size();i++) {
+		result.insert(GDFunctions::get_func_name(GDFunctions::Function(i)));
+	}
 
-		const GDParser::FunctionNode *fu = p_class->functions[i];
+	static const char*_type_names[Variant::VARIANT_MAX]={
+		"null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
+		"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
+		"Vector2Array","Vector3Array","ColorArray"};
 
-		if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
-			//if in function, first block stuff from outer to inner
-			if (_parse_completion_block(p_class,fu->body,p_line,r_options,p_indices))
-				return true;
-			//then function arguments
-			if (!p_indices) {
-				for(int j=0;j<fu->arguments.size();j++) {
+	for(int i=0;i<Variant::VARIANT_MAX;i++) {
+		result.insert(_type_names[i]);
+	}
+
+	for(const Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
+		result.insert(E->key().operator String());
+	}
+}
+
+
+static String _get_visual_datatype(const PropertyInfo& p_info,bool p_isarg=true) {
+
+	String n = p_info.name;
+	int idx = n.find(":");
+	if (idx!=-1) {
+		return n.substr(idx+1,n.length());
+	}
+
+	if (p_info.type==Variant::OBJECT && p_info.hint==PROPERTY_HINT_RESOURCE_TYPE)
+		return p_info.hint_string;
+	if (p_info.type==Variant::NIL) {
+		if (p_isarg)
+			return "var";
+		else
+			return "void";
+	}
+
+	return Variant::get_type_name(p_info.type);
+}
+
+static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argidx,String& arghint) {
+
+	arghint="func "+p_func->name+"(";
+	for (int i=0;i<p_func->arguments.size();i++) {
+		if (i>0)
+			arghint+=", ";
+		else
+			arghint+=" ";
+
+		if (i==p_argidx) {
+			arghint+=String::chr(0xFFFF);
+		}
+		arghint+=p_func->arguments[i].operator String();
+		int deffrom = p_func->arguments.size()-p_func->default_values.size();
+
+		if (i>=deffrom) {
+			int defidx = deffrom-i;
+
+			if (defidx>=0 && defidx<p_func->default_values.size()) {
+
+				if (p_func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) {
+
+					const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_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();
+
+					}
+				} else {
 
-					r_options->push_back(fu->arguments[j]);
 				}
 			}
 		}
 
+		if (i==p_argidx) {
+			arghint+=String::chr(0xFFFF);
+		}
 	}
+	if (p_func->arguments.size()>0)
+		arghint+=" ";
+	arghint+=")";
+}
 
-	for(int i=0;i<p_class->static_functions.size();i++) {
 
-		const GDParser::FunctionNode *fu = p_class->static_functions[i];
+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) {
 
-		if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
 
-			//if in function, first block stuff from outer to inne
-			if (_parse_completion_block(p_class,fu->body,p_line,r_options,p_indices))
-				return true;
-			//then function arguments
-			if (!p_indices) {
-				for(int j=0;j<fu->arguments.size();j++) {
+	if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
+
+
+		MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
+		if (!m)
+			return;
 
-					r_options->push_back(fu->arguments[j]);
+		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) {
 
-			in_static_func=true;
-		}
+				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 {
 
+			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()) {
 
-	//add all local names
-	if (!p_indices) {
+					result.insert(E->get());
+				}
+			}
 
-		if (!in_static_func) {
+		}
 
-			for(int i=0;i<p_class->variables.size();i++) {
+		arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
 
-				r_options->push_back(p_class->variables[i].identifier);
+		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();
 
-		for(int i=0;i<p_class->constant_expressions.size();i++) {
 
-			r_options->push_back(p_class->constant_expressions[i].identifier);
-		}
+			if (i>=deffrom) {
+				int defidx = i-deffrom;
 
-		if (!in_static_func) {
-			for(int i=0;i<p_class->functions.size();i++) {
+				if (defidx>=0 && defidx<m->get_default_argument_count()) {
+					Variant v= m->get_default_argument(i);
+					arghint+="="+v.get_construct_string();
+				}
+			}
 
-				r_options->push_back(p_class->functions[i]->name);
+			if (i==p_argidx) {
+				arghint+=String::chr(0xFFFF);
 			}
+
 		}
+		if (m->get_argument_count()>0)
+			arghint+=" ";
 
-		for(int i=0;i<p_class->static_functions.size();i++) {
 
-			r_options->push_back(p_class->static_functions[i]->name);
-		}
+		arghint+=")";
+
 	}
+}
 
 
-	if (p_class->extends_used) {
-		//do inheritance
-		String path = p_class->extends_file;
+static void _find_call_arguments(GDCompletionContext& context,const GDParser::Node* p_node, int p_line,int p_argidx, Set<String>& result, String& arghint) {
 
-		Ref<GDScript> script;
-		Ref<GDNativeClass> native;
 
-		if (path!="") {
-			//path (and optionally subclasses)
 
-			script = ResourceLoader::load(path);
-			if (script.is_null()) {
-				return false;
+	if (!p_node || p_node->type!=GDParser::Node::TYPE_OPERATOR) {
+
+		return;
+	}
+
+	const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(p_node);
+
+	if (op->op!=GDParser::OperatorNode::OP_CALL) {
+
+		return;
+	}
+
+	if (op->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) {
+		//complete built-in function
+		const GDParser::BuiltInFunctionNode *fn = static_cast<const GDParser::BuiltInFunctionNode*>(op->arguments[0]);
+		MethodInfo mi = GDFunctions::get_info(fn->function);
+
+		arghint = _get_visual_datatype(mi.return_val,false)+" "+GDFunctions::get_func_name(fn->function)+String("(");
+		for(int i=0;i<mi.arguments.size();i++) {
+			if (i>0)
+				arghint+=", ";
+			else
+				arghint+=" ";
+			if (i==p_argidx) {
+				arghint+=String::chr(0xFFFF);
+			}
+			arghint+=_get_visual_datatype(mi.arguments[i])+" "+mi.arguments[i].name;
+			if (i==p_argidx) {
+				arghint+=String::chr(0xFFFF);
 			}
 
-			if (p_class->extends_class.size()) {
+		}
+		if (mi.arguments.size()>0)
+			arghint+=" ";
+		arghint+=")";
+
+	} else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
+		//complete built-in function
+		const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]);
+
+		List<MethodInfo> mil;
+		Variant::get_constructor_list(tn->vtype,&mil);
+
+		for(List<MethodInfo>::Element *E=mil.front();E;E=E->next()) {
+
+			MethodInfo mi = E->get();
+			if (mi.arguments.size()==0)
+				continue;
+			if (E->prev())
+				arghint+="\n";
+			arghint += Variant::get_type_name(tn->vtype)+" "+Variant::get_type_name(tn->vtype)+String("(");
+			for(int i=0;i<mi.arguments.size();i++) {
+				if (i>0)
+					arghint+=", ";
+				else
+					arghint+=" ";
+				if (i==p_argidx) {
+					arghint+=String::chr(0xFFFF);
+				}
+				arghint+=_get_visual_datatype(mi.arguments[i])+" "+mi.arguments[i].name;
+				if (i==p_argidx) {
+					arghint+=String::chr(0xFFFF);
+				}
 
-				for(int i=0;i<p_class->extends_class.size();i++) {
+			}
+			if (mi.arguments.size()>0)
+				arghint+=" ";
+			arghint+=")";
+		}
 
-					String sub = p_class->extends_class[i];
-					if (script->get_subclasses().has(sub)) {
+	} else if (op->arguments.size()>=2 && op->arguments[1]->type==GDParser::Node::TYPE_IDENTIFIER) {
+		//make sure identifier exists...
 
-						script=script->get_subclasses()[sub];
-					} else {
+		const GDParser::IdentifierNode *id=static_cast<const GDParser::IdentifierNode *>(op->arguments[1]);
 
-						return false;
+		if (op->arguments[0]->type==GDParser::Node::TYPE_SELF) {
+			//self, look up
+
+			for(int i=0;i<context._class->static_functions.size();i++) {
+				if (context._class->static_functions[i]->name==id->name) {
+					_make_function_hint(context._class->static_functions[i],p_argidx,arghint);
+					return;
+				}
+			}
+
+			if (context.function && !context.function->_static) {
+
+				for(int i=0;i<context._class->functions.size();i++) {
+					if (context._class->functions[i]->name==id->name) {
+						_make_function_hint(context._class->functions[i],p_argidx,arghint);
+						return;
 					}
 				}
 			}
 
-		} else {
+			Ref<Reference> base = _get_parent_class(context);
 
-			ERR_FAIL_COND_V(p_class->extends_class.size()==0,false);
-			//look around for the subclasses
+			while(true) {
 
-			String base=p_class->extends_class[0];
-			Ref<GDScript> base_class;
-#if 0
-			while(p) {
+				Ref<GDScript> script = base;
+				Ref<GDNativeClass> nc = base;
+				if (script.is_valid()) {
 
-				if (p->subclasses.has(base)) {
 
-					base_class=p->subclasses[base];
+					for (const Map<StringName,GDFunction>::Element *E=script->get_member_functions().front();E;E=E->next()) {
+
+						if (E->key()==id->name) {
+
+							if (context.function && context.function->_static && !E->get().is_static())
+								continue;
+
+
+							arghint = "func "+id->name.operator String()+String("(");
+							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+=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);
+								}
+
+							}
+							if (E->get().get_argument_count()>0)
+								arghint+=" ";
+							arghint+=")";
+							return;
+						}
+					}
+
+					base=script->get_base();
+					if (base.is_null())
+						base=script->get_native();
+				} else if (nc.is_valid()) {
+
+					if (context.function && !context.function->_static) {
+
+						GDCompletionIdentifier ci;
+						ci.type=Variant::OBJECT;
+						ci.obj_type=nc->get_name();
+						if (!context._class->owner)
+							ci.value=context.base;
+
+						_find_type_arguments(p_node,p_line,id->name,ci,p_argidx,result,arghint);
+						//guess type..
+						/*
+						List<MethodInfo> methods;
+						ObjectTypeDB::get_method_list(type,&methods);
+						for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+							//if (E->get().arguments.size())
+							//	result.insert(E->get().name+"(");
+							//else
+							//	result.insert(E->get().name+"()");
+						}*/
+					}
 					break;
-				}
-				p=p->_owner;
+				} else
+					break;
+
 			}
+		} else {
 
-			if (base_class.is_valid()) {
 
-				for(int i=1;i<p_class->extends_class.size();i++) {
+			GDCompletionIdentifier ci;
+			if (_guess_expression_type(context,op->arguments[0],p_line,ci)) {
 
-					String subclass=p_class->extends_class[i];
+				_find_type_arguments(p_node,p_line,id->name,ci,p_argidx,result,arghint);
+				return;
+			}
 
-					if (base_class->subclasses.has(subclass)) {
+		}
 
-						base_class=base_class->subclasses[subclass];
-					} else {
+	}
+#if 0
+	bool _static=context.function->_static;
 
-						_set_error("Could not find subclass: "+subclass,p_class);
-						return ERR_FILE_NOT_FOUND;
-					}
-				}
 
 
-			} else {
-#endif
-				if (p_class->extends_class.size()>1) {
 
-					return false;
+	for(int i=0;i<context._class->static_functions.size();i++) {
+		if (context._class->static_functions[i]->arguments.size())
+			result.insert(context._class->static_functions[i]->name.operator String()+"(");
+		else
+			result.insert(context._class->static_functions[i]->name.operator String()+"()");
+	}
+
+	if (!p_static) {
+
+		for(int i=0;i<context._class->functions.size();i++) {
+			if (context._class->functions[i]->arguments.size())
+				result.insert(context._class->functions[i]->name.operator String()+"(");
+			else
+				result.insert(context._class->functions[i]->name.operator String()+"()");
+		}
+	}
+
+	Ref<Reference> base = _get_parent_class(context);
+
+	while(true) {
 
+		Ref<GDScript> script = base;
+		Ref<GDNativeClass> nc = base;
+		if (script.is_valid()) {
+
+			if (!p_static && !p_only_functions) {
+				for (const Set<StringName>::Element *E=script->get_members().front();E;E=E->next()) {
+					result.insert(E->get().operator String());
 				}
-				//if not found, try engine classes
-				if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
-					return false;
+			}
+
+			if (!p_only_functions) {
+				for (const Map<StringName,Variant>::Element *E=script->get_constants().front();E;E=E->next()) {
+					result.insert(E->key().operator String());
 				}
+			}
 
-				int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
-				native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
-				if (!native.is_valid()) {
-					return false;
+			for (const Map<StringName,GDFunction>::Element *E=script->get_member_functions().front();E;E=E->next()) {
+				if (!p_static || E->get().is_static()) {
+					if (E->get().get_argument_count())
+						result.insert(E->key().operator String()+"(");
+					else
+						result.insert(E->key().operator String()+"()");
 				}
-#if 0
 			}
-#endif
 
-		}
+			if (!p_only_functions)	{
+				for (const Map<StringName,Ref<GDScript> >::Element *E=script->get_subclasses().front();E;E=E->next()) {
+					result.insert(E->key().operator String());
+				}
+			}
 
-		if (script.is_valid()) {
-			if (_parse_script_symbols(script,in_static_func,r_options,p_indices))
-				return true;
+			base=script->get_base();
+			if (base.is_null())
+				base=script->get_native();
+		} else if (nc.is_valid()) {
 
-		} else if (native.is_valid() && !p_indices) {
+			if (!p_only_functions) {
 
-			_parse_native_symbols(native->get_name(),in_static_func,r_options);
-		}
-	}
+				StringName type = nc->get_name();
+				List<String> constants;
+				ObjectTypeDB::get_integer_constant_list(type,&constants);
+				for(List<String>::Element *E=constants.front();E;E=E->next()) {
+					result.insert(E->get());
+				}
 
-	return false;
+				List<MethodInfo> methods;
+				ObjectTypeDB::get_method_list(type,&methods);
+				for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+					if (E->get().arguments.size())
+						result.insert(E->get().name+"(");
+					else
+						result.insert(E->get().name+"()");
+				}
+			}
+			break;
+		} else
+			break;
 
-}
+	}
+
+	for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
 
+		result.insert(GDFunctions::get_func_name(GDFunctions::Function(i)));
+	}
 
-Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_base, List<String>* r_options) {
+#endif
 
+}
 
+Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) {
+	//print_line( p_code.replace(String::chr(0xFFFF),"<cursor>"));
 
 	GDParser p;
 	Error err = p.parse(p_code,p_base_path);
-	// don't care much about error I guess
-	const GDParser::Node* root = p.get_parse_tree();
-	ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_INVALID_DATA);
+	bool isfunction=false;
+	Set<String> options;
+
+	GDCompletionContext context;
+	context._class=p.get_completion_class();
+	context.block=p.get_completion_block();
+	context.function=p.get_completion_function();
+	context.base=p_owner;
+	context.base_path=p_base_path;
+
+	switch(p.get_completion_type()) {
+
+		case GDParser::COMPLETION_NONE: {
+			print_line("No completion");
+		} break;
+		case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
+			print_line("Built in type constant");
+			List<StringName> constants;
+			Variant::get_numeric_constants_for_type(p.get_completion_built_in_constant(),&constants);
+			for(List<StringName>::Element *E=constants.front();E;E=E->next()) {
+				options.insert(E->get().operator String());
+			}
 
-	print_line("BASE: "+p_base);
-	const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
 
-	List<String> indices;
-	Vector<String> spl = p_base.split(".");
+		} break;
+		case GDParser::COMPLETION_FUNCTION:
+			isfunction=true;
+		case GDParser::COMPLETION_IDENTIFIER: {
 
-	for(int i=0;i<spl.size()-1;i++) {
-		print_line("INDEX "+itos(i)+":  "+spl[i]);
-		indices.push_back(spl[i]);
-	}
+			_find_identifiers(context,p.get_completion_line(),isfunction,options);
+		} break;
+		case GDParser::COMPLETION_PARENT_FUNCTION: {
+			print_line("parent function");
+
+		} break;
+		case GDParser::COMPLETION_METHOD:
+			isfunction=true;
+		case GDParser::COMPLETION_INDEX: {
+
+			const GDParser::Node *node = p.get_completion_node();
+			if (node->type!=GDParser::Node::TYPE_OPERATOR)
+				break;
+
+
+
+
+			GDCompletionIdentifier t;
+			if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) {
+
+				if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
+
+
+					if (t.value.get_type()) {
+						Object *obj=t.value;
+						if (obj) {
+							GDScript *scr = obj->cast_to<GDScript>();
+							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()) {
+									options.insert(E->key());
+								}
+
+								if (scr->get_base().is_valid())
+									scr=scr->get_base().ptr();
+								else
+									scr=NULL;
+							}
+						}
+					}
+
+
+					if (!isfunction) {
+						ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
+					}
+					List<MethodInfo> mi;
+					ObjectTypeDB::get_method_list(t.obj_type,&mi);
+					for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+
+						if (E->get().name.begins_with("_"))
+							continue;
+
+						if (E->get().arguments.size())
+							options.insert(E->get().name+"(");
+						else
+							options.insert(E->get().name+"()");
+
+					}
+				} else {
+
+
+					if (t.type==Variant::INPUT_EVENT) {
+
+						//this is hardcoded otherwise it's not obvious
+						Set<String> exclude;
+
+						for(int i=0;i<InputEvent::TYPE_MAX;i++) {
+
+							InputEvent ie;
+							ie.type=InputEvent::Type(i);
+							static const char*evnames[]={
+								"# Common",
+								"# Key",
+								"# MouseMotion",
+								"# MouseButton",
+								"# JoyMotion",
+								"# JoyButton",
+								"# ScreenTouch",
+								"# ScreenDrag",
+								"# Action"
+							};
+
+							r_options->push_back(evnames[i]);
+
+							Variant v = ie;
+
+							if (i==0) {
+								List<MethodInfo> mi;
+								v.get_method_list(&mi);
+								for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+									r_options->push_back(E->get().name+"(");
+
+								}
 
-	//parse completion inside of the class first
-	if (_parse_completion_class(p_base,cl,p_line,r_options,indices.front()))
-		return OK;
+							}
+
+							List<PropertyInfo> pi;
+							v.get_property_list(&pi);
+
+							for (List<PropertyInfo>::Element *E=pi.front();E;E=E->next()) {
+
+								if (i==0)
+									exclude.insert(E->get().name);
+								else if (exclude.has(E->get().name))
+									continue;
+
+								r_options->push_back(E->get().name);
+							}
+						}
+						return OK;
+					} else {
+						if (t.value.get_type()==Variant::NIL) {
+							Variant::CallError ce;
+							t.value=Variant::construct(t.type,NULL,0,ce);
+						}
 
-	//if parsing completion inside of the class fails (none found), try using globals for completion
-	for(Map<StringName,int>::Element *E=globals.front();E;E=E->next()) {
-		if (!indices.empty()) {
-			if (String(E->key())==indices.front()->get()) {
 
-				_parse_completion_variant(global_array[E->get()],r_options,indices.front()->next());
+						if (!isfunction) {
+							List<PropertyInfo> pl;
+							t.value.get_property_list(&pl);
+							for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
 
-				return OK;
+								if (E->get().name.find("/")==-1)
+									options.insert(E->get().name);
+							}
+						}
+
+						List<MethodInfo> mi;
+						t.value.get_method_list(&mi);
+						for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
+							if (E->get().arguments.size())
+								options.insert(E->get().name+"(");
+							else
+								options.insert(E->get().name+"()");
+
+						}
+					}
+				}
 			}
-		} else {
-			r_options->push_back(E->key());
-		}
+
+
+		} break;
+		case GDParser::COMPLETION_CALL_ARGUMENTS: {
+
+			_find_call_arguments(context,p.get_completion_node(),p.get_completion_line(),p.get_completion_argument_index(),options,r_call_hint);
+		} break;
+
+
+	}
+
+
+	for(Set<String>::Element *E=options.front();E;E=E->next()) {
+		r_options->push_back(E->get());
 	}
 
 	return OK;
 }
 
+#else
+
+Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) {
+	return OK;
+}
+
+#endif
+
+
 void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const {
 
 

+ 254 - 52
modules/gdscript/gd_parser.cpp

@@ -30,19 +30,6 @@
 #include "print_string.h"
 #include "io/resource_loader.h"
 #include "os/file_access.h"
-/* TODO:
-
-   *Property reduce constant expressions
-   *Implement missing operators in variant?
-   *constructor
- */
-
-/*
- todo:
- fix post ++,--
- make sure ++,-- don't work on constant expressions
- seems passing parent node as param is not needed
- */
 
 template<class T>
 T* GDParser::alloc_node() {
@@ -116,14 +103,20 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) {
 	}
 }
 
-bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static) {
+bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static,bool p_can_codecomplete) {
 
 	if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
 		tokenizer->advance();
 	} else {
 
+		int argidx=0;
+
 		while(true) {
 
+			if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+				_make_completable_call(argidx);
+				completion_node=p_parent;
+			}
 
 			Node*arg  = _parse_expression(p_parent,p_static);
 			if (!arg)
@@ -144,6 +137,7 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
 				}
 
 				tokenizer->advance();
+				argidx++;
 			} else {
 				// something is broken
 				_set_error("Expected ',' or ')'");
@@ -158,6 +152,48 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
 }
 
 
+void GDParser::_make_completable_call(int p_arg) {
+
+	completion_cursor=StringName();
+	completion_type=COMPLETION_CALL_ARGUMENTS;
+	completion_class=current_class;
+	completion_function=current_function;
+	completion_line=tokenizer->get_token_line();
+	completion_argument=p_arg;
+	completion_block=current_block;
+	tokenizer->advance();
+
+}
+
+
+bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& identifier) {
+
+	identifier=StringName();
+	if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
+		identifier=tokenizer->get_token_identifier();
+		tokenizer->advance();
+	}
+	if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+
+		completion_cursor=identifier;
+		completion_type=p_type;
+		completion_class=current_class;
+		completion_function=current_function;
+		completion_line=tokenizer->get_token_line();
+		completion_block=current_block;
+		tokenizer->advance();
+
+		if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
+			identifier=identifier.operator String() + tokenizer->get_token_identifier().operator String();
+			tokenizer->advance();
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
 
 GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign) {
 
@@ -199,6 +235,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 
 			tokenizer->advance();
 			expr=subexpr;
+		} else if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+			tokenizer->advance();
+			continue; //no point in cursor in the middle of expression
 
 		} else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) {
 
@@ -327,12 +366,19 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 
 			Variant::Type bi_type = tokenizer->get_token_type();
 			tokenizer->advance(2);
-			if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+
+			StringName identifier;
+
+			if (_get_completable_identifier(COMPLETION_BUILT_IN_TYPE_CONSTANT,identifier)) {
+
+				completion_built_in_constant=bi_type;
+			}
+
+			if (identifier==StringName()) {
 
 				_set_error("Built-in type constant expected after '.'");
 				return NULL;
 			}
-			StringName identifier = tokenizer->get_token_identifier();
 			if (!Variant::has_numeric_constant(bi_type,identifier)) {
 
 				_set_error("Static constant  '"+identifier.operator String()+"' not present in built-in type "+Variant::get_type_name(bi_type)+".");
@@ -342,7 +388,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 			ConstantNode *cn = alloc_node<ConstantNode>();
 			cn->value=Variant::get_numeric_constant_value(bi_type,identifier);
 			expr=cn;
-			tokenizer->advance();
+
 
 		} else if (tokenizer->get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) {
 			//function or constructor
@@ -355,23 +401,35 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 				TypeNode *tn = alloc_node<TypeNode>();
 				tn->vtype=tokenizer->get_token_type();
 				op->arguments.push_back(tn);
+				tokenizer->advance(2);
 			} else if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC) {
 
 				BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>();
 				bn->function=tokenizer->get_token_built_in_func();
 				op->arguments.push_back(bn);
+				tokenizer->advance(2);
 			} else {
 
 				SelfNode *self = alloc_node<SelfNode>();
 				op->arguments.push_back(self);
 
+				StringName identifier;
+				if (_get_completable_identifier(COMPLETION_FUNCTION,identifier)) {
+
+				}
+
 				IdentifierNode* id = alloc_node<IdentifierNode>();
-				id->name=tokenizer->get_token_identifier();
+				id->name=identifier;
 				op->arguments.push_back(id);
+				tokenizer->advance(1);
 			}
 
-			tokenizer->advance(2);
-			if (!_parse_arguments(op,op->arguments,p_static))
+			if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+				_make_completable_call(0);
+				completion_node=op;
+
+			}
+			if (!_parse_arguments(op,op->arguments,p_static,true))
 				return NULL;
 
 			expr=op;
@@ -380,25 +438,27 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 			//identifier (reference)
 
 			const ClassNode* cln = static_cast<const ClassNode*>(get_parse_tree());
-		  bool             bfn = false;
-		  StringName       idn( tokenizer->get_token_identifier() );
-		  
-		  for( int i=0; i<cln->constant_expressions.size(); ++i ) {
-		  
-		    if( cln->constant_expressions[i].identifier == idn ) {
-		      tokenizer->advance();
-		      expr = cln->constant_expressions[i].expression;
-		      bfn  = true;
-		      break;
-		    }
-		  }
-		  
-		  if( !bfn ) {
-  			IdentifierNode *id = alloc_node<IdentifierNode>();
-  			id->name = idn;
-  			tokenizer->advance();
-  			expr = id;
-		  }
+			bool             bfn = false;
+			StringName       identifier;
+			if (_get_completable_identifier(COMPLETION_IDENTIFIER,identifier)) {
+
+			}
+
+			for( int i=0; i<cln->constant_expressions.size(); ++i ) {
+
+				if( cln->constant_expressions[i].identifier == identifier ) {
+
+					expr = cln->constant_expressions[i].expression;
+					bfn  = true;
+					break;
+				}
+			}
+
+			if ( !bfn ) {
+				IdentifierNode *id = alloc_node<IdentifierNode>();
+				id->name = identifier;
+				expr = id;
+			}
 
 		} else if (/*tokenizer->get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) {
 
@@ -600,7 +660,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 
 			expr=dict;
 
-		} else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
+		} else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && (tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
 			// parent call
 
 			tokenizer->advance(); //goto identifier
@@ -611,12 +671,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 			/*SelfNode *self = alloc_node<SelfNode>();
 			op->arguments.push_back(self);
 			forbidden for now */
+			StringName identifier;
+			if (_get_completable_identifier(COMPLETION_PARENT_FUNCTION,identifier)) {
+				//indexing stuff
+			}
 
-			IdentifierNode* id = alloc_node<IdentifierNode>();
-			id->name=tokenizer->get_token_identifier();
+			IdentifierNode *id = alloc_node<IdentifierNode>();
+			id->name=identifier;
 			op->arguments.push_back(id);
 
-			tokenizer->advance(2);
+			tokenizer->advance(1);
 			if (!_parse_arguments(op,op->arguments,p_static))
 				return NULL;
 
@@ -651,7 +715,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 
 				//indexing using "."
 
-				if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
+				if (tokenizer->get_token(1)!=GDTokenizer::TK_CURSOR && tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
 					_set_error("Expected identifier as member");
 					return NULL;
 				} else if (tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
@@ -659,37 +723,67 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
 					OperatorNode * op = alloc_node<OperatorNode>();
 					op->op=OperatorNode::OP_CALL;
 
+					tokenizer->advance();
+
 					IdentifierNode * id = alloc_node<IdentifierNode>();
-					if (tokenizer->get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) {
+					if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC ) {
 						//small hack so built in funcs don't obfuscate methods
 
-						id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func(1));
+						id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func());
+						tokenizer->advance();
+
 					} else {
-						id->name=tokenizer->get_token_identifier(1);
+						StringName identifier;
+						if (_get_completable_identifier(COMPLETION_METHOD,identifier)) {
+							completion_node=op;
+							//indexing stuff
+						}
+
+						id->name=identifier;
 					}
 
 					op->arguments.push_back(expr); // call what
 					op->arguments.push_back(id); // call func
 					//get arguments
-					tokenizer->advance(3);
-					if (!_parse_arguments(op,op->arguments,p_static))
+					tokenizer->advance(1);
+					if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+						_make_completable_call(0);
+						completion_node=op;
+
+					}
+					if (!_parse_arguments(op,op->arguments,p_static,true))
 						return NULL;
 					expr=op;
 
 				} else {
 					//simple indexing!
+
+
 					OperatorNode * op = alloc_node<OperatorNode>();
 					op->op=OperatorNode::OP_INDEX_NAMED;
+					tokenizer->advance();
+
+
+					StringName identifier;
+					if (_get_completable_identifier(COMPLETION_INDEX,identifier)) {
+
+						if (identifier==StringName()) {
+							identifier="@temp"; //so it parses allright
+						}
+						completion_node=op;
+
+						//indexing stuff
+					}
 
 					IdentifierNode * id = alloc_node<IdentifierNode>();
-					id->name=tokenizer->get_token_identifier(1);
+					id->name=identifier;
 
 					op->arguments.push_back(expr);
 					op->arguments.push_back(id);
 
 					expr=op;
 
-					tokenizer->advance(2);
+
 				}
 
 			} else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_OPEN) {
@@ -1442,6 +1536,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 				cf_if->arguments.push_back(condition);
 
 				cf_if->body = alloc_node<BlockNode>();
+				cf_if->body->parent_block=p_block;
 				p_block->sub_blocks.push_back(cf_if->body);
 
 				if (!_enter_indent_block(cf_if->body)) {
@@ -1449,7 +1544,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 					return;
 				}
 
+				current_block=cf_if->body;
 				_parse_block(cf_if->body,p_static);
+				current_block=p_block;
+
 				if (error_set)
 					return;
 				p_block->statements.push_back(cf_if);
@@ -1476,6 +1574,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 						tokenizer->advance();
 
 						cf_if->body_else=alloc_node<BlockNode>();
+						cf_if->body_else->parent_block=p_block;
 						p_block->sub_blocks.push_back(cf_if->body_else);
 
 						ControlFlowNode *cf_else = alloc_node<ControlFlowNode>();
@@ -1491,6 +1590,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 						cf_if->body_else->statements.push_back(cf_else);
 						cf_if=cf_else;
 						cf_if->body=alloc_node<BlockNode>();
+						cf_if->body->parent_block=p_block;
 						p_block->sub_blocks.push_back(cf_if->body);
 
 
@@ -1499,7 +1599,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 							return;
 						}
 
+						current_block=cf_else->body;
 						_parse_block(cf_else->body,p_static);
+						current_block=p_block;
 						if (error_set)
 							return;
 
@@ -1515,13 +1617,16 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 
 						tokenizer->advance();
 						cf_if->body_else=alloc_node<BlockNode>();
+						cf_if->body_else->parent_block=p_block;
 						p_block->sub_blocks.push_back(cf_if->body_else);
 
 						if (!_enter_indent_block(cf_if->body_else)) {
 							p_block->end_line=tokenizer->get_token_line();
 							return;
 						}
+						current_block=cf_if->body_else;
 						_parse_block(cf_if->body_else,p_static);
+						current_block=p_block;
 						if (error_set)
 							return;
 
@@ -1548,6 +1653,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 				cf_while->arguments.push_back(condition);
 
 				cf_while->body = alloc_node<BlockNode>();
+				cf_while->body->parent_block=p_block;
 				p_block->sub_blocks.push_back(cf_while->body);
 
 				if (!_enter_indent_block(cf_while->body)) {
@@ -1555,7 +1661,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 					return;
 				}
 
+				current_block=cf_while->body;
 				_parse_block(cf_while->body,p_static);
+				current_block=p_block;
 				if (error_set)
 					return;
 				p_block->statements.push_back(cf_while);
@@ -1592,6 +1700,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 				cf_for->arguments.push_back(container);
 
 				cf_for->body = alloc_node<BlockNode>();
+				cf_for->body->parent_block=p_block;
 				p_block->sub_blocks.push_back(cf_for->body);
 
 				if (!_enter_indent_block(cf_for->body)) {
@@ -1599,7 +1708,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 					return;
 				}
 
+				current_block=cf_for->body;
 				_parse_block(cf_for->body,p_static);
+				current_block=p_block;
+
 				if (error_set)
 					return;
 				p_block->statements.push_back(cf_for);
@@ -1865,7 +1977,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
 
 				ClassNode *newclass = alloc_node<ClassNode>();
 				newclass->initializer = alloc_node<BlockNode>();
+				newclass->initializer->parent_class=newclass;
 				newclass->name=name;
+				newclass->owner=p_class;
 
 				p_class->subclasses.push_back(newclass);
 
@@ -1882,7 +1996,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
 					_set_error("Indented block expected.");
 					return;
 				}
+				current_class=newclass;
 				_parse_class(newclass);
+				current_class=p_class;
 
 			} break;
 			/* this is for functions....
@@ -2020,6 +2136,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
 				tokenizer->advance();
 
 				BlockNode *block = alloc_node<BlockNode>();
+				block->parent_class=p_class;
 
 				if (name=="_init") {
 
@@ -2095,8 +2212,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
 					p_class->functions.push_back(function);
 
 
-				_parse_block(block,_static);
+				current_function=function;
 				function->body=block;
+				current_block=block;
+				_parse_block(block,_static);
+				current_block=NULL;
+
 				//arguments
 			} break;
 			case GDTokenizer::TK_PR_EXPORT: {
@@ -2401,7 +2522,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
 				}
 
 				member.identifier=tokenizer->get_token_identifier();
+				member.expression=NULL;
 				member._export.name=member.identifier;
+				member.line=tokenizer->get_token_line();
 				tokenizer->advance();
 
 				if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) {
@@ -2417,6 +2540,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
 					if (!subexpr)
 						return;
 
+					member.expression=subexpr;
+
 					if (autoexport) {
 						if (subexpr->type==Node::TYPE_ARRAY) {
 
@@ -2608,6 +2733,8 @@ Error GDParser::_parse(const String& p_base_path) {
 	//assume class
 	ClassNode *main_class = alloc_node<ClassNode>();
 	main_class->initializer = alloc_node<BlockNode>();
+	main_class->initializer->parent_class=main_class;
+	current_class=main_class;
 
 	_parse_class(main_class);
 
@@ -2625,6 +2752,15 @@ Error GDParser::_parse(const String& p_base_path) {
 
 Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) {
 
+	completion_type=COMPLETION_NONE;
+	completion_node=NULL;
+	completion_class=NULL;
+	completion_function=NULL;
+	completion_block=NULL;
+	current_block=NULL;
+	current_class=NULL;
+	current_function=NULL;
+
 	self_path=p_self_path;
 	GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer );
 	tb->set_code_buffer(p_bytecode);
@@ -2638,6 +2774,16 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
 
 Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) {
 
+	completion_type=COMPLETION_NONE;
+	completion_node=NULL;
+	completion_class=NULL;
+	completion_function=NULL;
+	completion_block=NULL;
+	current_block=NULL;
+	current_class=NULL;
+
+	current_function=NULL;
+
 	self_path=p_self_path;
 	GDTokenizerText *tt = memnew( GDTokenizerText );
 	tt->set_code(p_code);
@@ -2667,6 +2813,16 @@ void GDParser::clear() {
 	head=NULL;
 	list=NULL;
 
+	completion_type=COMPLETION_NONE;
+	completion_node=NULL;
+	completion_class=NULL;
+	completion_function=NULL;
+	completion_block=NULL;
+	current_block=NULL;
+	current_class=NULL;
+
+	current_function=NULL;
+
 	validating=false;
 	error_set=false;
 	tab_level.clear();
@@ -2680,6 +2836,52 @@ void GDParser::clear() {
 
 }
 
+
+GDParser::CompletionType GDParser::get_completion_type() {
+
+	return completion_type;
+}
+
+StringName GDParser::get_completion_cursor() {
+
+	return completion_cursor;
+}
+
+int GDParser::get_completion_line() {
+
+	return completion_line;
+}
+
+Variant::Type GDParser::get_completion_built_in_constant(){
+
+	return completion_built_in_constant;
+}
+
+GDParser::Node *GDParser::get_completion_node(){
+
+	return completion_node;
+}
+
+GDParser::BlockNode *GDParser::get_completion_block() {
+
+	return completion_block;
+}
+
+GDParser::ClassNode *GDParser::get_completion_class(){
+
+	return completion_class;
+}
+
+GDParser::FunctionNode *GDParser::get_completion_function(){
+
+	return completion_function;
+}
+
+int GDParser::get_completion_argument_index() {
+
+	return completion_argument;
+}
+
 GDParser::GDParser() {
 
 	head=NULL;

+ 52 - 3
modules/gdscript/gd_parser.h

@@ -84,6 +84,8 @@ public:
 			StringName identifier;
 			StringName setter;
 			StringName getter;
+			int line;
+			Node *expression;
 		};
 		struct Constant {
 			StringName identifier;
@@ -96,10 +98,11 @@ public:
 		Vector<FunctionNode*> functions;
 		Vector<FunctionNode*> static_functions;
 		BlockNode *initializer;
+		ClassNode *owner;
 		//Vector<Node*> initializers;
 		int end_line;
 
-		ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1;}
+		ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1; owner=NULL;}
 	};
 
 
@@ -118,6 +121,8 @@ public:
 
 	struct BlockNode : public Node {
 
+		ClassNode *parent_class;
+		BlockNode *parent_block;
 		Map<StringName,int> locals;
 		List<Node*> statements;
 		Vector<StringName> variables;
@@ -126,7 +131,7 @@ public:
 		//the following is useful for code completion
 		List<BlockNode*> sub_blocks;
 		int end_line;
-		BlockNode() { type=TYPE_BLOCK; end_line=-1;}
+		BlockNode() { type=TYPE_BLOCK; end_line=-1; parent_block=NULL; parent_class=NULL; }
 	};
 
 	struct TypeNode : public Node {
@@ -349,6 +354,18 @@ public:
 	};
 */
 
+	enum CompletionType {
+		COMPLETION_NONE,
+		COMPLETION_BUILT_IN_TYPE_CONSTANT,
+		COMPLETION_FUNCTION,
+		COMPLETION_IDENTIFIER,
+		COMPLETION_PARENT_FUNCTION,
+		COMPLETION_METHOD,
+		COMPLETION_CALL_ARGUMENTS,
+		COMPLETION_INDEX,
+	};
+
+
 
 private:
 
@@ -375,12 +392,31 @@ private:
 	String base_path;
 	String self_path;
 
+
+	ClassNode *current_class;
+	FunctionNode *current_function;
+	BlockNode *current_block;
+
+	bool _get_completable_identifier(CompletionType p_type,StringName& identifier);
+	void _make_completable_call(int p_arg);
+
+	CompletionType completion_type;
+	StringName completion_cursor;
+	bool completion_static;
+	Variant::Type completion_built_in_constant;
+	Node *completion_node;
+	ClassNode *completion_class;
+	FunctionNode *completion_function;
+	BlockNode *completion_block;
+	int completion_line;
+	int completion_argument;
+
 	PropertyInfo current_export;
 
 	void _set_error(const String& p_error, int p_line=-1, int p_column=-1);
 
 
-	bool _parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static);
+	bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false);
 	bool _enter_indent_block(BlockNode *p_block=NULL);
 	bool _parse_newline();
 	Node* _parse_expression(Node *p_parent,bool p_static,bool p_allow_assign=false);
@@ -404,6 +440,19 @@ public:
 
 	const Node *get_parse_tree() const;
 
+	//completion info
+
+	CompletionType get_completion_type();
+	StringName get_completion_cursor();
+	int get_completion_line();
+	Variant::Type get_completion_built_in_constant();
+	Node *get_completion_node();
+	ClassNode *get_completion_class();
+	BlockNode *get_completion_block();
+	FunctionNode *get_completion_function();
+	int get_completion_argument_index();
+
+
 	void clear();
 	GDParser();
 	~GDParser();

+ 2 - 1
modules/gdscript/gd_script.cpp

@@ -1440,8 +1440,8 @@ GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Obj
 
 	if (err.error!=Variant::CallError::CALL_OK) {
 		instance->script=Ref<GDScript>();
+		instance->owner->set_script_instance(NULL);
 		instances.erase(p_owner);
-		memdelete(instance);
 		ERR_FAIL_COND_V(err.error!=Variant::CallError::CALL_OK, NULL); //error consrtucting
 	}
 
@@ -1756,6 +1756,7 @@ bool GDScript::_update_exports() {
 	return changed;
 
 #endif
+	return false;
 }
 
 void GDScript::update_exports() {

+ 19 - 1
modules/gdscript/gd_script.h

@@ -129,6 +129,10 @@ friend class GDCompiler;
 	const char*_func_cname;
 #endif
 
+#ifdef TOOLS_ENABLED
+	Vector<StringName> arg_names;
+#endif
+
 	List<StackDebug> stack_debug;
 
 	_FORCE_INLINE_ Variant *_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self,Variant *p_stack,String& r_error) const;
@@ -169,6 +173,19 @@ public:
 	_FORCE_INLINE_ bool is_empty() const { return _code_size==0; }
 
 	int get_argument_count() const { return _argument_count; }
+	StringName get_argument_name(int p_idx) const {
+#ifdef TOOLS_ENABLED
+		ERR_FAIL_INDEX_V(p_idx,arg_names.size(),StringName());
+		return arg_names[p_idx];
+#endif
+		return StringName();
+
+	}
+	Variant get_default_argument(int p_idx) const {
+		ERR_FAIL_INDEX_V(p_idx,default_arguments.size(),Variant());
+		return default_arguments[p_idx];
+	}
+
 	Variant call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err,CallState *p_state=NULL);
 
 	GDFunction();
@@ -293,6 +310,7 @@ protected:
 	static void _bind_methods();
 public:
 
+	bool is_valid() const { return valid; }
 
 	const Map<StringName,Ref<GDScript> >& get_subclasses() const { return subclasses; }
 	const Map<StringName,Variant >& get_constants() const { return constants; }
@@ -488,7 +506,7 @@ public:
 	virtual bool has_named_classes() const;
 	virtual int find_function(const String& p_function,const String& p_code) const;
 	virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
-	virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path,const String& p_keyword, List<String>* r_options);
+	virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint);
 	virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
 
 	/* DEBUGGER FUNCTIONS */

+ 5 - 1
modules/gdscript/gd_tokenizer.cpp

@@ -110,7 +110,8 @@ const char* GDTokenizer::token_names[TK_MAX]={
 "':'",
 "'\\n'",
 "Error",
-"EOF"};
+"EOF",
+"Cursor"};
 
 const char *GDTokenizer::get_token_name(Token p_token) {
 
@@ -648,6 +649,9 @@ void GDTokenizerText::_advance() {
 				}
 
 			} break;
+			case 0xFFFF: {
+				_make_token(TK_CURSOR);
+			} break;
 			default: {
 
 				if (_is_number(GETCHAR(0)) || (GETCHAR(0)=='.' && _is_number(GETCHAR(1)))) {

+ 1 - 0
modules/gdscript/gd_tokenizer.h

@@ -118,6 +118,7 @@ public:
 		TK_NEWLINE,
 		TK_ERROR,
 		TK_EOF,
+		TK_CURSOR, //used for code completion
 		TK_MAX
 	};
 

+ 20 - 2
platform/android/java/src/com/android/godot/GodotIO.java

@@ -438,8 +438,26 @@ public class GodotIO {
 
 		try {
 			Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
-			Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(p_uri));
-			activity.startActivity(myIntent);
+			String path = p_uri;
+			String type="";
+			if (path.startsWith("/")) {
+				//absolute path to filesystem, prepend file://
+				path="file://"+path;
+				if (p_uri.endsWith(".png") || p_uri.endsWith(".jpg") || p_uri.endsWith(".gif") || p_uri.endsWith(".webp")) {
+
+					type="image/*";
+				}
+			}
+
+			Intent intent = new Intent();
+			intent.setAction(Intent.ACTION_VIEW);
+			if (!type.equals("")) {
+				intent.setDataAndType(Uri.parse(path), type);
+			} else {
+				intent.setData(Uri.parse(path));
+			}
+
+			activity.startActivity(intent);
 			return 0;
 		} catch (ActivityNotFoundException e) {
 

+ 2 - 1
platform/windows/os_windows.cpp

@@ -1396,8 +1396,9 @@ void OS_Windows::set_window_title(const String& p_title) {
 
 void OS_Windows::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
 
-	
+
 }
+
 OS::VideoMode OS_Windows::get_video_mode(int p_screen) const {
 
 	return video_mode;

+ 1 - 1
platform/winrt/SCsub

@@ -8,4 +8,4 @@ files = [
 	'os_winrt.cpp',
 ]
 
-env.Program('#bin/godot_rt', files)
+env.Program('#bin/godot', files)

+ 234 - 11
platform/winrt/app.cpp

@@ -5,6 +5,8 @@
 #include "app.h"
 
 #include "main/main.h"
+#include "core/os/dir_access.h"
+#include "core/os/file_access.h"
 
 using namespace Windows::ApplicationModel::Core;
 using namespace Windows::ApplicationModel::Activation;
@@ -70,8 +72,9 @@ void App::Initialize(CoreApplicationView^ applicationView)
 }
 
 // Called when the CoreWindow object is created (or re-created).
-void App::SetWindow(CoreWindow^ window)
+void App::SetWindow(CoreWindow^ p_window)
 {
+	window = p_window;
     window->VisibilityChanged +=
         ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &App::OnVisibilityChanged);
 
@@ -89,23 +92,230 @@ void App::SetWindow(CoreWindow^ window)
     pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;
 #endif
 
-    // The CoreWindow has been created, so EGL can be initialized.
+
+	window->PointerPressed +=
+		ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerPressed);
+
+	window->PointerMoved +=
+		ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerMoved);
+
+	window->PointerReleased +=
+		ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerReleased);
+
+	//window->PointerWheelChanged +=
+	//	ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerWheelChanged);
+
+
+
+	char* args[] = {"-path", "game", NULL};
+	Main::setup("winrt", 2, args, false);
+
+	// The CoreWindow has been created, so EGL can be initialized.
 	ContextEGL* context = memnew(ContextEGL(window));
 	os->set_gl_context(context);
-    UpdateWindowSize(Size(window->Bounds.Width, window->Bounds.Height));
+	UpdateWindowSize(Size(window->Bounds.Width, window->Bounds.Height));
+
+	Main::setup2();
+}
+
+static int _get_button(Windows::UI::Input::PointerPoint ^pt) {
+
+	using namespace Windows::UI::Input;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+	return BUTTON_LEFT;
+#else
+	switch (pt->Properties->PointerUpdateKind)
+	{
+		case PointerUpdateKind::LeftButtonPressed:
+		case PointerUpdateKind::LeftButtonReleased:
+			return BUTTON_LEFT;
+
+		case PointerUpdateKind::RightButtonPressed:
+		case PointerUpdateKind::RightButtonReleased:
+			return BUTTON_RIGHT;
+
+		case PointerUpdateKind::MiddleButtonPressed:
+		case PointerUpdateKind::MiddleButtonReleased:
+			return BUTTON_MIDDLE;
+
+		case PointerUpdateKind::XButton1Pressed:
+		case PointerUpdateKind::XButton1Released:
+			return BUTTON_WHEEL_UP;
+
+		case PointerUpdateKind::XButton2Pressed:
+		case PointerUpdateKind::XButton2Released:
+			return BUTTON_WHEEL_DOWN;
+
+		default:
+			break;
+	}
+#endif
+
+	return 0;
+};
+
+static bool _is_touch(Windows::UI::Input::PointerPoint ^pointerPoint) {
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+	return true;
+#else
+	using namespace Windows::Devices::Input;
+	switch (pointerPoint->PointerDevice->PointerDeviceType) {
+		case PointerDeviceType::Touch:
+		case PointerDeviceType::Pen:
+			return true;
+		default:
+			return false;
+	}
+#endif
 }
 
+
+static Windows::Foundation::Point _get_pixel_position(CoreWindow^ window, Windows::Foundation::Point rawPosition, OS* os) {
+
+	Windows::Foundation::Point outputPosition;
+
+	// Compute coordinates normalized from 0..1.
+	// If the coordinates need to be sized to the SDL window,
+	// we'll do that after.
+	#if 1 || WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+	outputPosition.X = rawPosition.X / window->Bounds.Width;
+	outputPosition.Y = rawPosition.Y / window->Bounds.Height;
+	#else
+	switch (DisplayProperties::CurrentOrientation)
+	{
+		case DisplayOrientations::Portrait:
+			outputPosition.X = rawPosition.X / window->Bounds.Width;
+			outputPosition.Y = rawPosition.Y / window->Bounds.Height;
+			break;
+		case DisplayOrientations::PortraitFlipped:
+			outputPosition.X = 1.0f - (rawPosition.X / window->Bounds.Width);
+			outputPosition.Y = 1.0f - (rawPosition.Y / window->Bounds.Height);
+			break;
+		case DisplayOrientations::Landscape:
+			outputPosition.X = rawPosition.Y / window->Bounds.Height;
+			outputPosition.Y = 1.0f - (rawPosition.X / window->Bounds.Width);
+			break;
+		case DisplayOrientations::LandscapeFlipped:
+			outputPosition.X = 1.0f - (rawPosition.Y / window->Bounds.Height);
+			outputPosition.Y = rawPosition.X / window->Bounds.Width;
+			break;
+		default:
+			break;
+	}
+	#endif
+
+	OS::VideoMode vm = os->get_video_mode();
+	outputPosition.X *= vm.width;
+	outputPosition.Y *= vm.height;
+
+	return outputPosition;
+};
+
+static int _get_finger(uint32_t p_touch_id) {
+
+	return p_touch_id % 31; // for now
+};
+
+void App::pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed) {
+
+	Windows::UI::Input::PointerPoint ^point = args->CurrentPoint;
+	Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
+	int but = _get_button(point);
+	if (_is_touch(point)) {
+
+		InputEvent event;
+		event.type = InputEvent::SCREEN_TOUCH;
+		event.device = 0;
+		event.screen_touch.pressed = p_pressed;
+		event.screen_touch.x = pos.X;
+		event.screen_touch.y = pos.Y;
+		event.screen_touch.index = _get_finger(point->PointerId);
+
+		last_touch_x[event.screen_touch.index] = pos.X;
+		last_touch_y[event.screen_touch.index] = pos.Y;
+
+		os->input_event(event);
+		if (event.screen_touch.index != 0)
+			return;
+
+	}; // fallthrought of sorts
+
+	InputEvent event;
+	event.type = InputEvent::MOUSE_BUTTON;
+	event.device = 0;
+	event.mouse_button.pressed = p_pressed;
+	event.mouse_button.button_index = but;
+	event.mouse_button.x = pos.X;
+	event.mouse_button.y = pos.Y;
+	event.mouse_button.global_x = pos.X;
+	event.mouse_button.global_y = pos.Y;
+
+	last_touch_x[31] = pos.X;
+	last_touch_y[31] = pos.Y;
+
+	os->input_event(event);
+};
+
+
+void App::OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
+
+	pointer_event(sender, args, true);
+};
+
+
+void App::OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
+
+	pointer_event(sender, args, false);
+};
+
+void App::OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
+
+	Windows::UI::Input::PointerPoint ^point = args->CurrentPoint;
+	Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
+
+	if (_is_touch(point)) {
+
+		InputEvent event;
+		event.type = InputEvent::SCREEN_DRAG;
+		event.device = 0;
+		event.screen_drag.x = pos.X;
+		event.screen_drag.y = pos.Y;
+		event.screen_drag.index = _get_finger(point->PointerId);
+		event.screen_drag.relative_x = event.screen_drag.x - last_touch_x[event.screen_drag.index];
+		event.screen_drag.relative_y = event.screen_drag.y - last_touch_y[event.screen_drag.index];
+
+		os->input_event(event);
+		if (event.screen_drag.index != 0)
+			return;
+
+	}; // fallthrought of sorts
+
+	InputEvent event;
+	event.type = InputEvent::MOUSE_MOTION;
+	event.device = 0;
+	event.mouse_motion.x = pos.X;
+	event.mouse_motion.y = pos.Y;
+	event.mouse_motion.global_x = pos.X;
+	event.mouse_motion.global_y = pos.Y;
+	event.mouse_motion.relative_x = pos.X - last_touch_x[31];
+	event.mouse_motion.relative_y = pos.Y - last_touch_y[31];
+
+	os->input_event(event);
+
+};
+
+
 // Initializes scene resources
 void App::Load(Platform::String^ entryPoint)
 {
-	char** args = {NULL};
-	Main::setup("winrt", 0, args);
+	//char* args[] = {"-test", "render", NULL};
+	//Main::setup("winrt", 2, args);
 }
 
 // This method is called after the window becomes active.
 void App::Run()
 {
-
 	if (Main::start())
 		os->run();
 }
@@ -147,16 +357,29 @@ void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ ar
     // On Windows Phone 8.1, the window size changes when the device is rotated.
     // The default framebuffer will not be automatically resized when this occurs.
     // It is therefore up to the app to handle rotation-specific logic in its rendering code.
+	//os->screen_size_changed();
+	UpdateWindowSize(args->Size);
 #endif
 }
 
 void App::UpdateWindowSize(Size size)
 {
-	/*
-    DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
-    Size pixelSize(ConvertDipsToPixels(size.Width, currentDisplayInformation->LogicalDpi), ConvertDipsToPixels(size.Height, currentDisplayInformation->LogicalDpi));
-    
+	float dpi;
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
+	DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
+	dpi = currentDisplayInformation->LogicalDpi;
+#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+	dpi = DisplayProperties::LogicalDpi;
+#endif
+	Size pixelSize(ConvertDipsToPixels(size.Width, dpi), ConvertDipsToPixels(size.Height, dpi));
+
     mWindowWidth = static_cast<GLsizei>(pixelSize.Width);
     mWindowHeight = static_cast<GLsizei>(pixelSize.Height);
-	*/
+
+	OS::VideoMode vm;
+	vm.width = mWindowWidth;
+	vm.height = mWindowHeight;
+	vm.fullscreen = true;
+	vm.resizable = false;
+	os->set_video_mode(vm);
 }

+ 12 - 2
platform/winrt/app.h

@@ -32,6 +32,12 @@ namespace $ext_safeprojectname$
         void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
         void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
 
+		void pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed);
+		void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+		void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+		void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+
+
         void UpdateWindowSize(Windows::Foundation::Size size);
         void InitializeEGL(Windows::UI::Core::CoreWindow^ window);
         void CleanupEGL();
@@ -44,8 +50,12 @@ namespace $ext_safeprojectname$
         EGLDisplay mEglDisplay;
         EGLContext mEglContext;
         EGLSurface mEglSurface;
-        
+
+		CoreWindow^ window;
 		OSWinrt* os;
-    };
+
+		int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
+		int last_touch_y[32];
+	};
 
 }

+ 99 - 26
platform/winrt/detect.py

@@ -3,6 +3,7 @@
 import os
 
 import sys	
+import string
 
 
 def is_active():
@@ -29,55 +30,127 @@ def get_flags():
 def configure(env):
 
 	env.Append(CPPPATH=['#platform/winrt', '#platform/winrt/include'])
+	arch = ""
 
-	env['OBJSUFFIX'] = ".rt" + env['OBJSUFFIX']
-	env['LIBSUFFIX'] = ".rt" + env['LIBSUFFIX']
+	if os.getenv('PLATFORM') == "ARM":
 
-	env.Append(LIBPATH=['#platform/winrt/x64/lib'])
+		# compiler commandline
+		# debug:   /Yu"pch.h" /MP /GS     /analyze- /W3 /wd"4453" /wd"28204"     /Zc:wchar_t /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.WindowsPhone\" /I"Generated Files\" /I"ARM\Debug\"   /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.Shared\" /ZW:nostdlib /Zi /Gm- /Od /sdl /Fd"ARM\Debug\vc120.pdb"   /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /D "_DEBUG" /errorReport:prompt /WX- /Zc:forScope /RTC1 /ZW /Gd /Oy- /MDd    /Fa"ARM\Debug\"   /EHsc /nologo /Fo"ARM\Debug\"   /Fp"ARM\Debug\App2.WindowsPhone.pch"
+		# release: /Yu"pch.h" /MP /GS /GL /analyze- /W3 /wd"4453" /wd"28204" /Gy /Zc:wchar_t /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.WindowsPhone\" /I"Generated Files\" /I"ARM\Release\" /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.Shared\" /ZW:nostdlib /Zi /Gm- /O2 /sdl /Fd"ARM\Release\vc120.pdb" /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE"             /errorReport:prompt /WX- /Zc:forScope       /ZW /Gd /Oy- /Oi /MD /Fa"ARM\Release\" /EHsc /nologo /Fo"ARM\Release\" /Fp"ARM\Release\App2.WindowsPhone.pch"
 
-	if (env["target"]=="release"):
+		# linker commandline
+		# debug:   /OUT:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.exe"   /MANIFEST:NO       /NXCOMPAT /PDB:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.pdb"   /DYNAMICBASE "WindowsPhoneCore.lib" "RuntimeObject.lib" "PhoneAppModelHost.lib" /DEBUG /MACHINE:ARM /NODEFAULTLIB:"kernel32.lib" /NODEFAULTLIB:"ole32.lib" /WINMD /APPCONTAINER /INCREMENTAL /PGD:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.pgd"   /WINMDFILE:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.winmd"   /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"ARM\Debug\App2.WindowsPhone.exe.intermediate.manifest"            /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
+		# release: /OUT:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.exe" /MANIFEST:NO /LTCG /NXCOMPAT /PDB:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.pdb" /DYNAMICBASE "WindowsPhoneCore.lib" "RuntimeObject.lib" "PhoneAppModelHost.lib" /DEBUG /MACHINE:ARM /NODEFAULTLIB:"kernel32.lib" /NODEFAULTLIB:"ole32.lib" /WINMD /APPCONTAINER /OPT:REF     /PGD:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.pgd" /WINMDFILE:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.winmd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"ARM\Release\App2.WindowsPhone.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
 
-		env.Append(CCFLAGS=['/O2'])
-		env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
-		env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
+		arch = "arm"
 
-	elif (env["target"]=="test"):
+		env.Append(LINKFLAGS=['/INCREMENTAL:NO', '/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', "WindowsPhoneCore.lib", "RuntimeObject.lib", "PhoneAppModelHost.lib", "/DEBUG", "/MACHINE:ARM", '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"', '/WINMD', '/APPCONTAINER', '/MANIFESTUAC:NO', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1'])
+		env.Append(LIBPATH=['#platform/winrt/ARM/lib'])
 
-		env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
-		env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+		env.Append(CCFLAGS=string.split('/MP /GS /wd"4453" /wd"28204" /analyze- /Zc:wchar_t /Zi /Gm- /Od /fp:precise /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /DWINDOWSPHONE_ENABLED /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /RTC1 /Gd /EHsc /nologo'))
+		env.Append(CXXFLAGS=string.split('/ZW'))
 
-	elif (env["target"]=="debug"):
+		if (env["target"]=="release"):
 
-		env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO','/O1'])
-		env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
-		env.Append(LINKFLAGS=['/DEBUG'])
+			env.Append(CCFLAGS=['/O2'])
+			env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
 
-	elif (env["target"]=="profile"):
+		elif (env["target"]=="test"):
 
-		env.Append(CCFLAGS=['-g','-pg'])
-		env.Append(LINKFLAGS=['-pg'])
+			env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+			env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
 
-	env.Append(CCFLAGS=['/Gd','/GR','/nologo', '/EHsc'])
-	env.Append(CXXFLAGS=['/TP', '/ZW'])
-	env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
-	#env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
+		elif (env["target"]=="debug"):
+
+			env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+			env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+			env.Append(LINKFLAGS=['/DEBUG', '/D_DEBUG'])
+
+		elif (env["target"]=="profile"):
+
+			env.Append(CCFLAGS=['-g','-pg'])
+			env.Append(LINKFLAGS=['-pg'])
+
+
+		env['ENV'] = os.environ;
+		# fix environment for windows phone 8.1
+		env['ENV']['WINDOWSPHONEKITDIR'] = env['ENV']['WINDOWSPHONEKITDIR'].replace("8.0", "8.1") # wtf
+		env['ENV']['INCLUDE'] = env['ENV']['INCLUDE'].replace("8.0", "8.1")
+		env['ENV']['LIB'] = env['ENV']['LIB'].replace("8.0", "8.1")
+		env['ENV']['PATH'] = env['ENV']['PATH'].replace("8.0", "8.1")
+		env['ENV']['LIBPATH'] = env['ENV']['LIBPATH'].replace("8.0\\Windows Metadata", "8.1\\References\\CommonConfiguration\\Neutral")
+
+	else:
+
+		arch = "x64"
+		env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', "kernel32.lib", '/MACHINE:X64', '/WINMD', '/APPCONTAINER', '/MANIFESTUAC:NO', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1'])
+
+		env.Append(LIBPATH=['#platform/winrt/x64/lib'])
+
+
+		if (env["target"]=="release"):
+
+			env.Append(CCFLAGS=['/O2'])
+			env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
+			env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
+
+		elif (env["target"]=="test"):
+
+			env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+			env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+
+		elif (env["target"]=="debug"):
+
+			env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+			env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+			env.Append(LINKFLAGS=['/DEBUG', '/D_DEBUG'])
+
+		elif (env["target"]=="profile"):
+
+			env.Append(CCFLAGS=['-g','-pg'])
+			env.Append(LINKFLAGS=['-pg'])
+
+
+		env.Append(CCFLAGS=string.split('/MP /GS /wd"4453" /wd"28204" /Zc:wchar_t /Gm- /Od /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /EHsc /nologo'))
+		env.Append(CXXFLAGS=string.split('/ZW'))
+		env.Append(CCFLAGS=['/AI', os.environ['VCINSTALLDIR']+'\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR']+'\\References\\CommonConfiguration\\Neutral'])
+		env.Append(CCFLAGS=['/DWINAPI_FAMILY=WINAPI_FAMILY_APP', '/D_WIN32_WINNT=0x0603', '/DNTDDI_VERSION=0x06030000'])
+
+		env['ENV'] = os.environ;
+
+
+	env["PROGSUFFIX"]="."+arch+env["PROGSUFFIX"]
+	env["OBJSUFFIX"]="."+arch+env["OBJSUFFIX"]
+	env["LIBSUFFIX"]="."+arch+env["LIBSUFFIX"]
+
+
+	#env.Append(CCFLAGS=['/Gd','/GR','/nologo', '/EHsc'])
+	#env.Append(CXXFLAGS=['/TP', '/ZW'])
+	#env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
+	##env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
 	env.Append(CCFLAGS=['/DWINRT_ENABLED'])
 	env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
-	env.Append(CCFLAGS=['/DWINAPI_FAMILY=WINAPI_FAMILY_APP', '/D_WIN32_WINNT=0x0603', '/DNTDDI_VERSION=0x06030000'])
 	env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
 	#env.Append(CCFLAGS=['/DWIN32'])
 	env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
 
 	env.Append(CCFLAGS=['/DGLES2_ENABLED'])
 	#env.Append(CCFLAGS=['/DGLES1_ENABLED'])
-	env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32'])
-		
+
+	LIBS=[
+		#'winmm',
+		'libEGL',
+		'libGLESv2',
+		'libANGLE',
+		#'kernel32','ole32','user32', 'advapi32'
+		]
+	env.Append(LINKFLAGS=[p+".lib" for p in LIBS])
+
 	import methods
 	env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
 	env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
 	env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
 	env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
 
-	env['ENV'] = os.environ;
-
 
+#/c/Program Files (x86)/Windows Phone Kits/8.1/lib/ARM/WindowsPhoneCore.lib

+ 27 - 1
platform/winrt/gl_context_egl.cpp

@@ -1,5 +1,7 @@
 #include "gl_context_egl.h"
 
+#include "EGL/eglext.h"
+
 using namespace Platform;
 
 void ContextEGL::release_current() {
@@ -22,6 +24,14 @@ int ContextEGL::get_window_height() {
 	return height;
 };
 
+void ContextEGL::reset() {
+
+	cleanup();
+
+	window = CoreWindow::GetForCurrentThread();
+	initialize();
+};
+
 void ContextEGL::swap_buffers() {
 
 	if (eglSwapBuffers(mEglDisplay, mEglSurface) != EGL_TRUE)
@@ -63,7 +73,23 @@ Error ContextEGL::initialize() {
 
 	try {
 
-		display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+		const EGLint displayAttributes[] =
+		{
+			EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+			EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9,
+			EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3,
+			EGL_NONE,
+		};
+
+		PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+
+		if (!eglGetPlatformDisplayEXT)
+		{
+			throw Exception::CreateException(E_FAIL, L"Failed to get function eglGetPlatformDisplayEXT");
+		}
+
+		display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes);
+
 		if (display == EGL_NO_DISPLAY)
 		{
 			throw Exception::CreateException(E_FAIL, L"Failed to get default EGL display");

+ 1 - 0
platform/winrt/gl_context_egl.h

@@ -32,6 +32,7 @@ public:
 	virtual void swap_buffers();
 
 	virtual Error initialize();
+	void reset();
 
 	void cleanup();
 

+ 14 - 7
platform/winrt/include/EGL/eglext.h

@@ -432,31 +432,38 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSu
 #define EGL_ANGLE_direct3d_display 1
 #define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
 #define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
-#define EGL_D3D11_FL9_3_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-4)
 #endif /* EGL_ANGLE_direct3d_display */
 
 #ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
 #define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
 #endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
 
+#ifndef EGL_ANGLE_surface_d3d_render_to_back_buffer
+#define EGL_ANGLE_surface_d3d_render_to_back_buffer 1
+#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER 0x320B
+#define EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER 0x320C
+#endif /* EGL_ANGLE_surface_d3d_render_to_back_buffer */
+
 #ifndef EGL_ANGLE_platform_angle
 #define EGL_ANGLE_platform_angle 1
 #define EGL_PLATFORM_ANGLE_ANGLE          0x3201
 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE     0x3202
-#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3204
+#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3205
 #endif /* EGL_ANGLE_platform_angle */
 
 #ifndef EGL_ANGLE_platform_angle_d3d
 #define EGL_ANGLE_platform_angle_d3d 1
-#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3204
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3205
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
+#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3206
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
+#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
 #endif /* EGL_ANGLE_platform_angle_d3d */
 
 #ifndef EGL_ANGLE_platform_angle_opengl
 #define EGL_ANGLE_platform_angle_opengl 1
-#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3207
-#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x3208
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3209
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320A
 #endif /* EGL_ANGLE_platform_angle_opengl */
 
 #ifndef EGL_ARM_pixmap_multisample_discard

+ 2 - 2
platform/winrt/include/EGL/eglplatform.h

@@ -76,12 +76,12 @@
 typedef HDC     EGLNativeDisplayType;
 typedef HBITMAP EGLNativePixmapType;
 
-#if defined(WINAPI_FAMILY) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */
 #include <inspectable.h>
 typedef IInspectable* EGLNativeWindowType;
 #else
 typedef HWND    EGLNativeWindowType;
-#endif // defined(WINAPI_FAMILY) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#endif
 
 #elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */
 

+ 57 - 159
platform/winrt/include/GLSLANG/ShaderLang.h

@@ -27,6 +27,10 @@
 
 #include "KHR/khrplatform.h"
 
+#include <map>
+#include <string>
+#include <vector>
+
 //
 // This is the platform independent interface between an OGL driver
 // and the shading language compiler.
@@ -39,20 +43,20 @@ typedef unsigned int GLenum;
 }
 
 // Must be included after GLenum proxy typedef
+// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
 #include "ShaderVars.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // Version number for shader translation API.
 // It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 129
+#define ANGLE_SH_VERSION 132
 
 typedef enum {
   SH_GLES2_SPEC = 0x8B40,
   SH_WEBGL_SPEC = 0x8B41,
 
+  SH_GLES3_SPEC = 0x8B86,
+  SH_WEBGL2_SPEC = 0x8B87,
+
   // The CSS Shaders spec is a subset of the WebGL spec.
   //
   // In both CSS vertex and fragment shaders, ANGLE:
@@ -84,31 +88,6 @@ typedef enum {
   SH_HLSL11_OUTPUT = 0x8B48
 } ShShaderOutput;
 
-typedef enum {
-  SH_PRECISION_HIGHP     = 0x5001,
-  SH_PRECISION_MEDIUMP   = 0x5002,
-  SH_PRECISION_LOWP      = 0x5003,
-  SH_PRECISION_UNDEFINED = 0
-} ShPrecisionType;
-
-typedef enum {
-  SH_INFO_LOG_LENGTH                = 0x8B84,
-  SH_OBJECT_CODE_LENGTH             = 0x8B88,  // GL_SHADER_SOURCE_LENGTH
-  SH_ACTIVE_UNIFORMS                = 0x8B86,
-  SH_ACTIVE_UNIFORM_MAX_LENGTH      = 0x8B87,
-  SH_ACTIVE_ATTRIBUTES              = 0x8B89,
-  SH_ACTIVE_ATTRIBUTE_MAX_LENGTH    = 0x8B8A,
-  SH_VARYINGS                       = 0x8BBB,
-  SH_VARYING_MAX_LENGTH             = 0x8BBC,
-  SH_MAPPED_NAME_MAX_LENGTH         = 0x6000,
-  SH_NAME_MAX_LENGTH                = 0x6001,
-  SH_HASHED_NAME_MAX_LENGTH         = 0x6002,
-  SH_HASHED_NAMES_COUNT             = 0x6003,
-  SH_SHADER_VERSION                 = 0x6004,
-  SH_RESOURCES_STRING_LENGTH        = 0x6005,
-  SH_OUTPUT_TYPE                    = 0x6006
-} ShShaderInfo;
-
 // Compile options.
 typedef enum {
   SH_VALIDATE                = 0,
@@ -188,6 +167,11 @@ typedef enum {
   // This flag scalarizes vec/ivec/bvec/mat constructor args.
   // It is intended as a workaround for Linux/Mac driver bugs.
   SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
+
+  // This flag overwrites a struct name with a unique prefix.
+  // It is intended as a workaround for drivers that do not handle
+  // struct scopes correctly, including all Mac drivers and Linux AMD.
+  SH_REGENERATE_STRUCT_NAMES = 0x80000,
 } ShCompileOptions;
 
 // Defines alternate strategies for implementing array index clamping.
@@ -202,14 +186,14 @@ typedef enum {
 //
 // Driver must call this first, once, before doing any other
 // compiler operations.
-// If the function succeeds, the return value is nonzero, else zero.
+// If the function succeeds, the return value is true, else false.
 //
-COMPILER_EXPORT int ShInitialize();
+COMPILER_EXPORT bool ShInitialize();
 //
 // Driver should call this at shutdown.
-// If the function succeeds, the return value is nonzero, else zero.
+// If the function succeeds, the return value is true, else false.
 //
-COMPILER_EXPORT int ShFinalize();
+COMPILER_EXPORT bool ShFinalize();
 
 // The 64 bits hash function. The first parameter is the input string; the
 // second parameter is the string length.
@@ -240,6 +224,12 @@ typedef struct
     int EXT_frag_depth;
     int EXT_shader_texture_lod;
 
+    // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
+    // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
+    // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers
+    // function. This applies to Tegra K1 devices.
+    int NV_draw_buffers;
+
     // Set to 1 if highp precision is supported in the fragment language.
     // Default is 0.
     int FragmentPrecisionHigh;
@@ -268,8 +258,10 @@ typedef struct
 
 //
 // Initialize built-in resources with minimum expected values.
+// Parameters:
+// resources: The object to initialize. Will be comparable with memcmp.
 //
-COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources);
+COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources *resources);
 
 //
 // ShHandle held by but opaque to the driver.  It is allocated,
@@ -278,18 +270,15 @@ COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources);
 //
 // If handle creation fails, 0 will be returned.
 //
-typedef void* ShHandle;
+typedef void *ShHandle;
 
 //
-// Returns the a concatenated list of the items in ShBuiltInResources as a string.
+// Returns the a concatenated list of the items in ShBuiltInResources as a
+// null-terminated string.
 // This function must be updated whenever ShBuiltInResources is changed.
 // Parameters:
 // handle: Specifies the handle of the compiler to be used.
-// outStringLen: Specifies the size of the buffer, in number of characters. The size
-//               of the buffer required to store the resources string can be obtained
-//               by calling ShGetInfo with SH_RESOURCES_STRING_LENGTH.
-// outStr: Returns a null-terminated string representing all the built-in resources.
-COMPILER_EXPORT void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outStr);
+COMPILER_EXPORT const std::string &ShGetBuiltInResourcesString(const ShHandle handle);
 
 //
 // Driver calls these to create and destroy compiler objects.
@@ -307,12 +296,12 @@ COMPILER_EXPORT ShHandle ShConstructCompiler(
     sh::GLenum type,
     ShShaderSpec spec,
     ShShaderOutput output,
-    const ShBuiltInResources* resources);
+    const ShBuiltInResources *resources);
 COMPILER_EXPORT void ShDestruct(ShHandle handle);
 
 //
 // Compiles the given shader source.
-// If the function succeeds, the return value is nonzero, else zero.
+// If the function succeeds, the return value is true, else false.
 // Parameters:
 // handle: Specifies the handle of compiler to be used.
 // shaderStrings: Specifies an array of pointers to null-terminated strings
@@ -334,123 +323,36 @@ COMPILER_EXPORT void ShDestruct(ShHandle handle);
 // SH_VARIABLES: Extracts attributes, uniforms, and varyings.
 //               Can be queried by calling ShGetVariableInfo().
 //
-COMPILER_EXPORT int ShCompile(
+COMPILER_EXPORT bool ShCompile(
     const ShHandle handle,
-    const char* const shaderStrings[],
+    const char * const shaderStrings[],
     size_t numStrings,
-    int compileOptions
-    );
+    int compileOptions);
 
-// Returns a parameter from a compiled shader.
-// Parameters:
-// handle: Specifies the compiler
-// pname: Specifies the parameter to query.
-// The following parameters are defined:
-// SH_INFO_LOG_LENGTH: the number of characters in the information log
-//                     including the null termination character.
-// SH_OBJECT_CODE_LENGTH: the number of characters in the object code
-//                        including the null termination character.
-// SH_ACTIVE_ATTRIBUTES: the number of active attribute variables.
-// SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: the length of the longest active attribute
-//                                 variable name including the null
-//                                 termination character.
-// SH_ACTIVE_UNIFORMS: the number of active uniform variables.
-// SH_ACTIVE_UNIFORM_MAX_LENGTH: the length of the longest active uniform
-//                               variable name including the null
-//                               termination character.
-// SH_VARYINGS: the number of varying variables.
-// SH_VARYING_MAX_LENGTH: the length of the longest varying variable name
-//                        including the null termination character.
-// SH_MAPPED_NAME_MAX_LENGTH: the length of the mapped variable name including
-//                            the null termination character.
-// SH_NAME_MAX_LENGTH: the max length of a user-defined name including the
-//                     null termination character.
-// SH_HASHED_NAME_MAX_LENGTH: the max length of a hashed name including the
-//                            null termination character.
-// SH_HASHED_NAMES_COUNT: the number of hashed names from the latest compile.
-// SH_SHADER_VERSION: the version of the shader language
-// SH_OUTPUT_TYPE: the currently set language output type
-//
-// params: Requested parameter
-COMPILER_EXPORT void ShGetInfo(const ShHandle handle,
-                               ShShaderInfo pname,
-                               size_t* params);
+// Return the version of the shader language.
+COMPILER_EXPORT int ShGetShaderVersion(const ShHandle handle);
 
-// Returns nul-terminated information log for a compiled shader.
+// Return the currently set language output type.
+COMPILER_EXPORT ShShaderOutput ShGetShaderOutputType(
+    const ShHandle handle);
+
+// Returns null-terminated information log for a compiled shader.
 // Parameters:
 // handle: Specifies the compiler
-// infoLog: Specifies an array of characters that is used to return
-//          the information log. It is assumed that infoLog has enough memory
-//          to accomodate the information log. The size of the buffer required
-//          to store the returned information log can be obtained by calling
-//          ShGetInfo with SH_INFO_LOG_LENGTH.
-COMPILER_EXPORT void ShGetInfoLog(const ShHandle handle, char* infoLog);
+COMPILER_EXPORT const std::string &ShGetInfoLog(const ShHandle handle);
 
 // Returns null-terminated object code for a compiled shader.
 // Parameters:
 // handle: Specifies the compiler
-// infoLog: Specifies an array of characters that is used to return
-//          the object code. It is assumed that infoLog has enough memory to
-//          accomodate the object code. The size of the buffer required to
-//          store the returned object code can be obtained by calling
-//          ShGetInfo with SH_OBJECT_CODE_LENGTH.
-COMPILER_EXPORT void ShGetObjectCode(const ShHandle handle, char* objCode);
-
-// Returns information about a shader variable.
-// Parameters:
-// handle: Specifies the compiler
-// variableType: Specifies the variable type; options include
-//               SH_ACTIVE_ATTRIBUTES, SH_ACTIVE_UNIFORMS, SH_VARYINGS.
-// index: Specifies the index of the variable to be queried.
-// length: Returns the number of characters actually written in the string
-//         indicated by name (excluding the null terminator) if a value other
-//         than NULL is passed.
-// size: Returns the size of the variable.
-// type: Returns the data type of the variable.
-// precision: Returns the precision of the variable.
-// staticUse: Returns 1 if the variable is accessed in a statement after
-//            pre-processing, whether or not run-time flow of control will
-//            cause that statement to be executed.
-//            Returns 0 otherwise.
-// name: Returns a null terminated string containing the name of the
-//       variable. It is assumed that name has enough memory to accormodate
-//       the variable name. The size of the buffer required to store the
-//       variable name can be obtained by calling ShGetInfo with
-//       SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_ACTIVE_UNIFORM_MAX_LENGTH,
-//       SH_VARYING_MAX_LENGTH.
-// mappedName: Returns a null terminated string containing the mapped name of
-//             the variable, It is assumed that mappedName has enough memory
-//             (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care about the
-//             mapped name. If the name is not mapped, then name and mappedName
-//             are the same.
-COMPILER_EXPORT void ShGetVariableInfo(const ShHandle handle,
-                                       ShShaderInfo variableType,
-                                       int index,
-                                       size_t* length,
-                                       int* size,
-                                       sh::GLenum* type,
-                                       ShPrecisionType* precision,
-                                       int* staticUse,
-                                       char* name,
-                                       char* mappedName);
-
-// Returns information about a name hashing entry from the latest compile.
+COMPILER_EXPORT const std::string &ShGetObjectCode(const ShHandle handle);
+
+// Returns a (original_name, hash) map containing all the user defined
+// names in the shader, including variable names, function names, struct
+// names, and struct field names.
 // Parameters:
 // handle: Specifies the compiler
-// index: Specifies the index of the name hashing entry to be queried.
-// name: Returns a null terminated string containing the user defined name.
-//       It is assumed that name has enough memory to accomodate the name.
-//       The size of the buffer required to store the user defined name can
-//       be obtained by calling ShGetInfo with SH_NAME_MAX_LENGTH.
-// hashedName: Returns a null terminated string containing the hashed name of
-//             the uniform variable, It is assumed that hashedName has enough
-//             memory to accomodate the name. The size of the buffer required
-//             to store the name can be obtained by calling ShGetInfo with
-//             SH_HASHED_NAME_MAX_LENGTH.
-COMPILER_EXPORT void ShGetNameHashingEntry(const ShHandle handle,
-                                           int index,
-                                           char* name,
-                                           char* hashedName);
+COMPILER_EXPORT const std::map<std::string, std::string> *ShGetNameHashingMap(
+    const ShHandle handle);
 
 // Shader variable inspection.
 // Returns a pointer to a list of variables of the designated type.
@@ -470,17 +372,17 @@ typedef struct
     int size;
 } ShVariableInfo;
 
-// Returns 1 if the passed in variables pack in maxVectors following
+// Returns true if the passed in variables pack in maxVectors following
 // the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
-// Returns 0 otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS
+// Returns false otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS
 // flag above.
 // Parameters:
 // maxVectors: the available rows of registers.
 // varInfoArray: an array of variable info (types and sizes).
 // varInfoArraySize: the size of the variable array.
-COMPILER_EXPORT int ShCheckVariablesWithinPackingLimits(
+COMPILER_EXPORT bool ShCheckVariablesWithinPackingLimits(
     int maxVectors,
-    ShVariableInfo* varInfoArray,
+    ShVariableInfo *varInfoArray,
     size_t varInfoArraySize);
 
 // Gives the compiler-assigned register for an interface block.
@@ -491,7 +393,7 @@ COMPILER_EXPORT int ShCheckVariablesWithinPackingLimits(
 // interfaceBlockName: Specifies the interface block
 // indexOut: output variable that stores the assigned register
 COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle,
-                                                 const char *interfaceBlockName,
+                                                 const std::string &interfaceBlockName,
                                                  unsigned int *indexOut);
 
 // Gives the compiler-assigned register for uniforms in the default
@@ -503,11 +405,7 @@ COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle,
 // interfaceBlockName: Specifies the uniform
 // indexOut: output variable that stores the assigned register
 COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle,
-                                          const char *uniformName,
+                                          const std::string &uniformName,
                                           unsigned int *indexOut);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif // _COMPILER_INTERFACE_INCLUDED_

+ 75 - 18
platform/winrt/include/GLSLANG/ShaderVars.h

@@ -15,6 +15,7 @@
 #include <algorithm>
 
 // Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum
+// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
 
 namespace sh
 {
@@ -39,7 +40,7 @@ enum BlockLayoutType
 // Note: we must override the copy constructor and assignment operator so we can
 // work around excessive GCC binary bloating:
 // See https://code.google.com/p/angleproject/issues/detail?id=697
-struct ShaderVariable
+struct COMPILER_EXPORT ShaderVariable
 {
     ShaderVariable();
     ShaderVariable(GLenum typeIn, unsigned int arraySizeIn);
@@ -49,6 +50,22 @@ struct ShaderVariable
 
     bool isArray() const { return arraySize > 0; }
     unsigned int elementCount() const { return std::max(1u, arraySize); }
+    bool isStruct() const { return !fields.empty(); }
+
+    // All of the shader's variables are described using nested data
+    // structures. This is needed in order to disambiguate similar looking
+    // types, such as two structs containing the same fields, but in
+    // different orders. "findInfoByMappedName" provides an easy query for
+    // users to dive into the data structure and fetch the unique variable
+    // instance corresponding to a dereferencing chain of the top-level
+    // variable.
+    // Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable
+    // that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]'
+    // in |originalName|, based on the assumption that |this| defines 'a'.
+    // If no match is found, return false.
+    bool findInfoByMappedName(const std::string &mappedFullName,
+                              const ShaderVariable **leafVar,
+                              std::string* originalFullName) const;
 
     GLenum type;
     GLenum precision;
@@ -56,58 +73,97 @@ struct ShaderVariable
     std::string mappedName;
     unsigned int arraySize;
     bool staticUse;
+    std::vector<ShaderVariable> fields;
+    std::string structName;
+
+  protected:
+    bool isSameVariableAtLinkTime(const ShaderVariable &other,
+                                  bool matchPrecision) const;
+
+    bool operator==(const ShaderVariable &other) const;
+    bool operator!=(const ShaderVariable &other) const
+    {
+        return !operator==(other);
+    }
 };
 
-struct Uniform : public ShaderVariable
+struct COMPILER_EXPORT Uniform : public ShaderVariable
 {
     Uniform();
     ~Uniform();
     Uniform(const Uniform &other);
     Uniform &operator=(const Uniform &other);
-
-    bool isStruct() const { return !fields.empty(); }
-
-    std::vector<Uniform> fields;
+    bool operator==(const Uniform &other) const;
+    bool operator!=(const Uniform &other) const
+    {
+        return !operator==(other);
+    }
+
+    // Decide whether two uniforms are the same at shader link time,
+    // assuming one from vertex shader and the other from fragment shader.
+    // See GLSL ES Spec 3.00.3, sec 4.3.5.
+    bool isSameUniformAtLinkTime(const Uniform &other) const;
 };
 
-struct Attribute : public ShaderVariable
+struct COMPILER_EXPORT Attribute : public ShaderVariable
 {
     Attribute();
     ~Attribute();
     Attribute(const Attribute &other);
     Attribute &operator=(const Attribute &other);
+    bool operator==(const Attribute &other) const;
+    bool operator!=(const Attribute &other) const
+    {
+        return !operator==(other);
+    }
 
     int location;
 };
 
-struct InterfaceBlockField : public ShaderVariable
+struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable
 {
     InterfaceBlockField();
     ~InterfaceBlockField();
     InterfaceBlockField(const InterfaceBlockField &other);
     InterfaceBlockField &operator=(const InterfaceBlockField &other);
+    bool operator==(const InterfaceBlockField &other) const;
+    bool operator!=(const InterfaceBlockField &other) const
+    {
+        return !operator==(other);
+    }
+
+    // Decide whether two InterfaceBlock fields are the same at shader
+    // link time, assuming one from vertex shader and the other from
+    // fragment shader.
+    // See GLSL ES Spec 3.00.3, sec 4.3.7.
+    bool isSameInterfaceBlockFieldAtLinkTime(
+        const InterfaceBlockField &other) const;
 
-    bool isStruct() const { return !fields.empty(); }
-
-    bool isRowMajorMatrix;
-    std::vector<InterfaceBlockField> fields;
+    bool isRowMajorLayout;
 };
 
-struct Varying : public ShaderVariable
+struct COMPILER_EXPORT Varying : public ShaderVariable
 {
     Varying();
     ~Varying();
-    Varying(const Varying &other);
+    Varying(const Varying &otherg);
     Varying &operator=(const Varying &other);
+    bool operator==(const Varying &other) const;
+    bool operator!=(const Varying &other) const
+    {
+        return !operator==(other);
+    }
 
-    bool isStruct() const { return !fields.empty(); }
+    // Decide whether two varyings are the same at shader link time,
+    // assuming one from vertex shader and the other from fragment shader.
+    // See GLSL ES Spec 3.00.3, sec 4.3.9.
+    bool isSameVaryingAtLinkTime(const Varying &other) const;
 
     InterpolationType interpolation;
-    std::vector<Varying> fields;
-    std::string structName;
+    bool isInvariant;
 };
 
-struct InterfaceBlock
+struct COMPILER_EXPORT InterfaceBlock
 {
     InterfaceBlock();
     ~InterfaceBlock();
@@ -116,6 +172,7 @@ struct InterfaceBlock
 
     std::string name;
     std::string mappedName;
+    std::string instanceName;
     unsigned int arraySize;
     BlockLayoutType layout;
     bool isRowMajorLayout;

+ 28 - 3
platform/winrt/os_winrt.cpp

@@ -71,7 +71,7 @@ const char * OSWinrt::get_video_driver_name(int p_driver) const {
 
 OS::VideoMode OSWinrt::get_default_video_mode() const {
 
-	return VideoMode(800,600,false);	
+	return video_mode;
 }
 
 int OSWinrt::get_audio_driver_count() const {
@@ -142,12 +142,27 @@ void OSWinrt::set_gl_context(ContextEGL* p_context) {
 	gl_context = p_context;
 };
 
+void OSWinrt::screen_size_changed() {
+
+	gl_context->reset();
+};
+
 void OSWinrt::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
 
     main_loop=NULL;
     outside=true;
 
 	gl_context->initialize();
+	VideoMode vm;
+	vm.width = gl_context->get_window_width();
+	vm.height = gl_context->get_window_height();
+	vm.fullscreen = true;
+	vm.resizable = false;
+
+	set_video_mode(vm);
+
+	gl_context->make_current();
+	rasterizer = memnew( RasterizerGLES2 );
 
 	visual_server = memnew( VisualServerRaster(rasterizer) );
 	if (get_render_thread_mode()!=RENDER_THREAD_UNSAFE) {
@@ -270,6 +285,11 @@ String OSWinrt::get_clipboard() const {
 };
 
 
+void OSWinrt::input_event(InputEvent &p_event) {
+	p_event.ID = ++last_id;
+	input->parse_input_event(p_event);
+};
+
 void OSWinrt::delete_main_loop() {
 
 	if (main_loop)
@@ -392,7 +412,7 @@ void OSWinrt::set_window_title(const String& p_title) {
 
 void OSWinrt::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
 
-	
+	video_mode = p_video_mode;
 }
 OS::VideoMode OSWinrt::get_video_mode(int p_screen) const {
 
@@ -512,7 +532,7 @@ Error OSWinrt::kill(const ProcessID& p_pid) {
 
 Error OSWinrt::set_cwd(const String& p_cwd) {
 
-	return OK;
+	return FAILED;
 }
 
 String OSWinrt::get_executable_path() const {
@@ -553,8 +573,12 @@ Error OSWinrt::shell_open(String p_uri) {
 
 String OSWinrt::get_locale() const {
 
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // this should work on phone 8.1, but it doesn't
+	return "en";
+#else
 	Platform::String ^language = Windows::Globalization::Language::CurrentInputMethodLanguageTag;
 	return language->Data();
+#endif
 }
 
 void OSWinrt::release_rendering_thread() {
@@ -634,6 +658,7 @@ OSWinrt::OSWinrt() {
 
 	gl_context = NULL;
 
+	AudioDriverManagerSW::add_driver(&audio_driver);
 }
 
 

+ 7 - 0
platform/winrt/os_winrt.h

@@ -40,6 +40,7 @@
 #include "servers/spatial_sound/spatial_sound_server_sw.h"
 #include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
 #include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/audio/audio_driver_dummy.h"
 
 #include "gl_context_egl.h"
 
@@ -124,6 +125,7 @@ class OSWinrt : public OS {
 
 	MainLoop *main_loop;
 
+	AudioDriverDummy audio_driver;
 	AudioServerSW *audio_server;
 	SampleManagerMallocSW *sample_manager;
 	SpatialSoundServerSW *spatial_sound_server;
@@ -226,17 +228,22 @@ public:
 	virtual String get_data_dir() const;
 
 	void set_gl_context(ContextEGL* p_context);
+	void screen_size_changed();
 
 	virtual void release_rendering_thread();
 	virtual void make_rendering_thread();
 	virtual void swap_buffers();
 
+	virtual bool has_touchscreen_ui_hint() const { return true; };
+
 	virtual Error shell_open(String p_uri);
 
 	void run();
 
 	virtual bool get_swap_ok_cancel() { return true; }
 
+	void input_event(InputEvent &p_event);
+
 	OSWinrt();
 	~OSWinrt();
 

+ 7 - 0
platform/x11/detect.py

@@ -122,6 +122,13 @@ def configure(env):
 	if platform.platform() == 'Linux':
 		env.Append(CPPFLAGS=["-DALSA_ENABLED"])
 		env.Append(LIBS=['asound'])
+        if not os.system("pkg-config --exists libpulse-simple"):
+            print("Enabling PulseAudio")
+            env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"])
+            env.ParseConfig('pkg-config --cflags --libs libpulse-simple')
+        else:
+            print("PulseAudio development libraries not found, disabling driver")
+
 	env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLES_OVER_GL'])
 	env.Append(LIBS=['GL', 'GLU', 'pthread', 'z'])
 	#env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])

+ 16 - 0
platform/x11/os_x11.cpp

@@ -75,6 +75,18 @@ OS::VideoMode OS_X11::get_default_video_mode() const {
 	return OS::VideoMode(800,600,false);
 }
 
+int OS_X11::get_audio_driver_count() const {
+
+    return AudioDriverManagerSW::get_driver_count();
+}
+
+const char *OS_X11::get_audio_driver_name(int p_driver) const {
+
+    AudioDriverSW* driver = AudioDriverManagerSW::get_driver(p_driver);
+    ERR_FAIL_COND_V( !driver, "" );
+    return AudioDriverManagerSW::get_driver(p_driver)->get_name();
+}
+
 void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
 
 	last_button_state=0;
@@ -1447,6 +1459,10 @@ OS_X11::OS_X11() {
 	AudioDriverManagerSW::add_driver(&driver_rtaudio);
 #endif
 
+#ifdef PULSEAUDIO_ENABLED
+	AudioDriverManagerSW::add_driver(&driver_pulseaudio);
+#endif
+
 #ifdef ALSA_ENABLED
 	AudioDriverManagerSW::add_driver(&driver_alsa);
 #endif

+ 9 - 1
platform/x11/os_x11.h

@@ -44,6 +44,7 @@
 #include "drivers/rtaudio/audio_driver_rtaudio.h"
 #include "drivers/alsa/audio_driver_alsa.h"
 #include "drivers/ao/audio_driver_ao.h"
+#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
 #include "servers/physics_2d/physics_2d_server_sw.h"
 
 #include <X11/keysym.h>
@@ -134,6 +135,10 @@ class OS_X11 : public OS_Unix {
 	AudioDriverAO driver_ao;
 #endif
 
+#ifdef PULSEAUDIO_ENABLED
+	AudioDriverPulseAudio driver_pulseaudio;
+#endif
+
 	enum {
 		JOYSTICKS_MAX = 8,
 		MAX_JOY_AXIS = 32768, // I've no idea
@@ -165,7 +170,10 @@ protected:
 	virtual int get_video_driver_count() const;
 	virtual const char * get_video_driver_name(int p_driver) const;	
 	virtual VideoMode get_default_video_mode() const;
-	
+
+    virtual int get_audio_driver_count() const;
+    virtual const char * get_audio_driver_name(int p_driver) const;
+
 	virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);	
 	virtual void finalize();
 

+ 21 - 1
scene/2d/collision_polygon_2d.cpp

@@ -41,7 +41,6 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
 
 	bool solids=build_mode==BUILD_SOLIDS;
 
-
 	if (solids) {
 
 		//here comes the sun, lalalala
@@ -51,6 +50,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
 			Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D );
 			convex->set_points(decomp[i]);
 			co->add_shape(convex,get_transform());
+			if (trigger)
+				co->set_shape_as_trigger(co->get_shape_count()-1,true);
 
 		}
 
@@ -71,6 +72,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
 		concave->set_segments(segments);
 
 		co->add_shape(concave,get_transform());
+		if (trigger)
+			co->set_shape_as_trigger(co->get_shape_count()-1,true);
 
 	}
 
@@ -166,6 +169,18 @@ Rect2 CollisionPolygon2D::get_item_rect() const {
 	return aabb;
 }
 
+void CollisionPolygon2D::set_trigger(bool p_trigger) {
+
+	trigger=p_trigger;
+	_update_parent();
+}
+
+bool CollisionPolygon2D::is_trigger() const{
+
+	return trigger;
+}
+
+
 void CollisionPolygon2D::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object);
@@ -175,14 +190,19 @@ void CollisionPolygon2D::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode);
 	ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode);
 
+	ObjectTypeDB::bind_method(_MD("set_trigger"),&CollisionPolygon2D::set_trigger);
+	ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionPolygon2D::is_trigger);
+
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Segments"),_SCS("set_build_mode"),_SCS("get_build_mode"));
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger"));
 }
 
 CollisionPolygon2D::CollisionPolygon2D() {
 
 	aabb=Rect2(-10,-10,20,20);
 	build_mode=BUILD_SOLIDS;
+	trigger=false;
 
 
 }

+ 4 - 0
scene/2d/collision_polygon_2d.h

@@ -50,6 +50,7 @@ protected:
 	Rect2 aabb;
 	BuildMode build_mode;
 	Vector<Point2> polygon;
+	bool trigger;
 
 	void _add_to_collision_object(Object *p_obj);
 	void _update_parent();
@@ -60,6 +61,9 @@ protected:
 	static void _bind_methods();
 public:
 
+	void set_trigger(bool p_trigger);
+	bool is_trigger() const;
+
 	void set_build_mode(BuildMode p_mode);
 	BuildMode get_build_mode() const;
 

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

@@ -858,7 +858,8 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 		//motion recover
 		for(int i=0;i<get_shape_count();i++) {
 
-
+			if (is_shape_set_as_trigger(i))
+				continue;
 			if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask))
 				collided=true;
 
@@ -902,6 +903,8 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
 
 	for(int i=0;i<get_shape_count();i++) {
 
+		if (is_shape_set_as_trigger(i))
+			continue;
 
 		float lsafe,lunsafe;
 		bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask);

+ 7 - 0
scene/3d/physics_body.cpp

@@ -870,6 +870,9 @@ Vector3 KinematicBody::move(const Vector3& p_motion) {
 		for(int j=0;j<8;j++) {
 			for(int i=0;i<res_shapes;i++) {
 
+				if (is_shape_set_as_trigger(i))
+					continue;
+
 				Vector3 a = sr[i*2+0];
 				Vector3 b = sr[i*2+1];
 				//print_line(String()+a+" -> "+b);
@@ -930,6 +933,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) {
 	for(int i=0;i<get_shape_count();i++) {
 
 
+		if (is_shape_set_as_trigger(i))
+			continue;
 
 		float lsafe,lunsafe;
 		PhysicsDirectSpaceState::ShapeRestInfo lrest;
@@ -1041,6 +1046,8 @@ bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) {
 	//fill exclude list..
 	for(int i=0;i<get_shape_count();i++) {
 
+		if (is_shape_set_as_trigger(i))
+			continue;
 
 		bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,0,exclude,get_layer_mask(),mask);
 		if (col)

+ 13 - 0
scene/animation/animation_player.cpp

@@ -1178,6 +1178,19 @@ NodePath AnimationPlayer::get_root() const {
 	return root;
 }
 
+void AnimationPlayer::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+	String pf = p_function;
+	if (p_function=="play" || p_function=="remove_animation" || p_function=="has_animation" || p_function=="queue") {
+		List<StringName> al;
+		get_animation_list(&al);
+		for (List<StringName>::Element *E=al.front();E;E=E->next()) {
+
+			r_options->push_back("\""+String(E->get())+"\"");
+		}
+	}
+	Node::get_argument_options(p_function,p_idx,r_options);
+}
 
 void AnimationPlayer::_bind_methods() {
 

+ 3 - 0
scene/animation/animation_player.h

@@ -289,6 +289,9 @@ public:
 	NodePath get_root() const;
 
 	void clear_caches(); ///< must be called by hand if an animation was modified after added
+
+	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
+
 	
 	AnimationPlayer();	
 	~AnimationPlayer();

+ 120 - 75
scene/animation/tween.cpp

@@ -124,32 +124,34 @@ void Tween::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_tween_process_mode"),&Tween::get_tween_process_mode);
 
 	ObjectTypeDB::bind_method(_MD("start"),&Tween::start );
-	ObjectTypeDB::bind_method(_MD("reset","node","key"),&Tween::reset );
+	ObjectTypeDB::bind_method(_MD("reset","object","key"),&Tween::reset );
 	ObjectTypeDB::bind_method(_MD("reset_all"),&Tween::reset_all );
-	ObjectTypeDB::bind_method(_MD("stop","node","key"),&Tween::stop );
+	ObjectTypeDB::bind_method(_MD("stop","object","key"),&Tween::stop );
 	ObjectTypeDB::bind_method(_MD("stop_all"),&Tween::stop_all );
-	ObjectTypeDB::bind_method(_MD("resume","node","key"),&Tween::resume );
+	ObjectTypeDB::bind_method(_MD("resume","object","key"),&Tween::resume );
 	ObjectTypeDB::bind_method(_MD("resume_all"),&Tween::resume_all );
-	ObjectTypeDB::bind_method(_MD("remove","node","key"),&Tween::remove );
+	ObjectTypeDB::bind_method(_MD("remove","object","key"),&Tween::remove );
 	ObjectTypeDB::bind_method(_MD("remove_all"),&Tween::remove_all );
 	ObjectTypeDB::bind_method(_MD("seek","time"),&Tween::seek );
 	ObjectTypeDB::bind_method(_MD("tell"),&Tween::tell );
 	ObjectTypeDB::bind_method(_MD("get_runtime"),&Tween::get_runtime );
 
-	ObjectTypeDB::bind_method(_MD("interpolate_property","node","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("interpolate_method","node","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("interpolate_callback","node","callback","times_in_sec","args"),&Tween::interpolate_callback, DEFVAL(Variant()) );
-	ObjectTypeDB::bind_method(_MD("follow_property","node","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("follow_method","node","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("targeting_property","node","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("targeting_method","node","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("interpolate_property","object","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("interpolate_method","object","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("interpolate_callback","object","times_in_sec","callback","args"),&Tween::interpolate_callback, DEFVAL(Variant()) );
+	ObjectTypeDB::bind_method(_MD("follow_property","object","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("follow_method","object","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("targeting_property","object","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("targeting_method","object","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
 
-	ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
-	ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
-	ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
+	ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
+	ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
+	ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
 
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_tween_process_mode"), _SCS("get_tween_process_mode"));
-	//ADD_PROPERTY( PropertyInfo( Variant::BOOL, "activate"), _SCS("set_active"), _SCS("is_active"));
+
+	BIND_CONSTANT(TWEEN_PROCESS_FIXED);
+	BIND_CONSTANT(TWEEN_PROCESS_IDLE);
 
 	BIND_CONSTANT(TRANS_LINEAR);
 	BIND_CONSTANT(TRANS_SINE);
@@ -181,19 +183,19 @@ Variant& Tween::_get_initial_val(InterpolateData& p_data) {
 		case TARGETING_PROPERTY:
 		case TARGETING_METHOD: {
 
-				Node *node = get_node(p_data.target);
-				ERR_FAIL_COND_V(node == NULL,p_data.initial_val);
+				Object *object = ObjectDB::get_instance(p_data.target_id);
+				ERR_FAIL_COND_V(object == NULL,p_data.initial_val);
 
 				static Variant initial_val;
 				if(p_data.type == TARGETING_PROPERTY) {
 
 					bool valid = false;
-					initial_val = node->get(p_data.target_key, &valid);
+					initial_val = object->get(p_data.target_key, &valid);
 					ERR_FAIL_COND_V(!valid,p_data.initial_val);
 				} else {
 
 					Variant::CallError error;
-					initial_val = node->call(p_data.target_key, NULL, 0, error);
+					initial_val = object->call(p_data.target_key, NULL, 0, error);
 					ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val);
 				}
 				return initial_val;
@@ -213,7 +215,7 @@ Variant& Tween::_get_delta_val(InterpolateData& p_data) {
 		case FOLLOW_PROPERTY:
 		case FOLLOW_METHOD: {
 
-				Node *target = get_node(p_data.target);
+				Object *target = ObjectDB::get_instance(p_data.target_id);
 				ERR_FAIL_COND_V(target == NULL,p_data.initial_val);
 
 				Variant final_val;
@@ -264,6 +266,11 @@ Variant Tween::_run_equation(InterpolateData& p_data) {
 
 	switch(initial_val.get_type())
 	{
+
+	case Variant::BOOL:
+		result = ((int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec)) >= 0.5;
+		break;
+
 	case Variant::INT:
 		result = (int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec);
 		break;
@@ -409,7 +416,7 @@ Variant Tween::_run_equation(InterpolateData& p_data) {
 
 bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
 
-	Object *object = get_node(p_data.path);
+	Object *object = ObjectDB::get_instance(p_data.id);
 	ERR_FAIL_COND_V(object == NULL, false);
 
 	switch(p_data.type) {
@@ -452,6 +459,7 @@ void Tween::_tween_process(float p_delta) {
 		return;
 	p_delta *= speed_scale;
 
+	pending_update ++;
 	// if repeat and all interpolates was finished then reset all interpolates
 	if(repeat) {
 		bool all_finished = true;
@@ -476,7 +484,7 @@ void Tween::_tween_process(float p_delta) {
 		if(!data.active || data.finish)
 			continue;
 
-		Object *object = get_node(data.path);
+		Object *object = ObjectDB::get_instance(data.id);
 		if(object == NULL)
 			continue;
 
@@ -523,6 +531,7 @@ void Tween::_tween_process(float p_delta) {
 		if(data.finish)
 			emit_signal("tween_complete",object,data.key);
 	}
+	pending_update --;
 }
 
 void Tween::set_tween_process_mode(TweenProcessMode p_mode) {
@@ -598,16 +607,17 @@ bool Tween::start() {
 	return true;
 }
 
-bool Tween::reset(Node *p_node, String p_key) {
+bool Tween::reset(Object *p_object, String p_key) {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
 
-		if(node == p_node && data.key == p_key) {
+		if(object == p_object && data.key == p_key) {
 
 			data.elapsed = 0;
 			data.finish = false;
@@ -615,11 +625,13 @@ bool Tween::reset(Node *p_node, String p_key) {
 				_apply_tween_value(data, data.initial_val);
 		}
 	}
+	pending_update --;
 	return true;
 }
 
 bool Tween::reset_all() {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
@@ -628,20 +640,23 @@ bool Tween::reset_all() {
 		if(data.delay == 0)
 			_apply_tween_value(data, data.initial_val);
 	}
+	pending_update --;
 	return true;
 }
 
-bool Tween::stop(Node *p_node, String p_key) {
+bool Tween::stop(Object *p_object, String p_key) {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
-		if(node == p_node && data.key == p_key)
+		if(object == p_object && data.key == p_key)
 			data.active = false;
 	}
+	pending_update --;
 	return true;
 }
 
@@ -650,28 +665,32 @@ bool Tween::stop_all() {
 	set_active(false);
 	_set_process(false);
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
 		data.active = false;
 	}
+	pending_update --;
 	return true;
 }
 
-bool Tween::resume(Node *p_node, String p_key) {
+bool Tween::resume(Object *p_object, String p_key) {
 
 	set_active(true);
 	_set_process(true);
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
-		if(node == p_node && data.key == p_key)
+		if(object == p_object && data.key == p_key)
 			data.active = true;
 	}
+	pending_update --;
 	return true;
 }
 
@@ -680,23 +699,26 @@ bool Tween::resume_all() {
 	set_active(true);
 	_set_process(true);
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
 		data.active = true;
 	}
+	pending_update --;
 	return true;
 }
 
-bool Tween::remove(Node *p_node, String p_key) {
+bool Tween::remove(Object *p_object, String p_key) {
 
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
-		if(node == p_node && data.key == p_key) {
+		if(object == p_object && data.key == p_key) {
 			interpolates.erase(E);
 			return true;
 		}
@@ -706,6 +728,7 @@ bool Tween::remove(Node *p_node, String p_key) {
 
 bool Tween::remove_all() {
 
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	set_active(false);
 	_set_process(false);
 	interpolates.clear();
@@ -714,6 +737,7 @@ bool Tween::remove_all() {
 
 bool Tween::seek(real_t p_time) {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
@@ -744,11 +768,13 @@ bool Tween::seek(real_t p_time) {
 
 		_apply_tween_value(data, result);
 	}
+	pending_update --;
 	return true;
 }
 
 real_t Tween::tell() const {
 
+	pending_update ++;
 	real_t pos = 0;
 	for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
@@ -756,11 +782,13 @@ real_t Tween::tell() const {
 		if(data.elapsed > pos)
 			pos = data.elapsed;
 	}
+	pending_update --;
 	return pos;
 }
 
 real_t Tween::get_runtime() const {
 
+	pending_update ++;
 	real_t runtime = 0;
 	for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
@@ -769,6 +797,7 @@ real_t Tween::get_runtime() const {
 		if(t > runtime)
 			runtime = t;
 	}
+	pending_update --;
 	return runtime;
 }
 
@@ -779,6 +808,12 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final
 	Variant& delta_val = p_delta_val;
 
 	switch(initial_val.get_type()) {
+
+		case Variant::BOOL:
+			//delta_val = p_final_val;
+			delta_val = (int) p_final_val - (int) p_initial_val;
+			break;
+
 		case Variant::INT:
 			delta_val = (int) final_val - (int) initial_val;
 			break;
@@ -873,7 +908,7 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final
 	return true;
 }
 
-bool Tween::interpolate_property(Node *p_node
+bool Tween::interpolate_property(Object *p_object
 	, String p_property
 	, Variant p_initial_val
 	, Variant p_final_val
@@ -882,11 +917,12 @@ bool Tween::interpolate_property(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@@ -894,7 +930,7 @@ bool Tween::interpolate_property(Node *p_node
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
 	bool prop_valid = false;
-	p_node->get(p_property,&prop_valid);
+	p_object->get(p_property,&prop_valid);
 	ERR_FAIL_COND_V(!prop_valid, false);
 
 	InterpolateData data;
@@ -903,7 +939,7 @@ bool Tween::interpolate_property(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_property;
 	data.initial_val = p_initial_val;
 	data.final_val = p_final_val;
@@ -919,7 +955,7 @@ bool Tween::interpolate_property(Node *p_node
 	return true;
 }
 
-bool Tween::interpolate_method(Node *p_node
+bool Tween::interpolate_method(Object *p_object
 	, String p_method
 	, Variant p_initial_val
 	, Variant p_final_val
@@ -928,18 +964,19 @@ bool Tween::interpolate_method(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 
 	InterpolateData data;
 	data.active = true;
@@ -947,7 +984,7 @@ bool Tween::interpolate_method(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_method;
 	data.initial_val = p_initial_val;
 	data.final_val = p_final_val;
@@ -963,16 +1000,17 @@ bool Tween::interpolate_method(Node *p_node
 	return true;
 }
 
-bool Tween::interpolate_callback(Node *p_node
-	, String p_callback
+bool Tween::interpolate_callback(Object *p_object
 	, real_t p_times_in_sec
+	, String p_callback
 	, Variant p_arg
 ) {
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(pending_update != 0, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_callback), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
 
 	InterpolateData data;
 	data.active = true;
@@ -980,30 +1018,33 @@ bool Tween::interpolate_callback(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_callback;
 	data.times_in_sec = p_times_in_sec;
 	data.delay = 0;
 	data.arg = p_arg;
 
+	pending_update ++;
 	interpolates.push_back(data);
+	pending_update --;
 	return true;
 }
 
-bool Tween::follow_property(Node *p_node
+bool Tween::follow_property(Object *p_object
 	, String p_property
 	, Variant p_initial_val
-	, Node *p_target
+	, Object *p_target
 	, String p_target_property
 	, real_t p_times_in_sec
 	, TransitionType p_trans_type
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_target == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@@ -1011,7 +1052,7 @@ bool Tween::follow_property(Node *p_node
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
 	bool prop_valid = false;
-	p_node->get(p_property,&prop_valid);
+	p_object->get(p_property,&prop_valid);
 	ERR_FAIL_COND_V(!prop_valid, false);
 
 	bool target_prop_valid = false;
@@ -1028,10 +1069,10 @@ bool Tween::follow_property(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_property;
 	data.initial_val = p_initial_val;
-	data.target = p_target->get_path();
+	data.target_id = p_target->get_instance_ID();
 	data.target_key = p_target_property;
 	data.times_in_sec = p_times_in_sec;
 	data.trans_type = p_trans_type;
@@ -1042,27 +1083,28 @@ bool Tween::follow_property(Node *p_node
 	return true;
 }
 
-bool Tween::follow_method(Node *p_node
+bool Tween::follow_method(Object *p_object
 	, String p_method
 	, Variant p_initial_val
-	, Node *p_target
+	, Object *p_target
 	, String p_target_method
 	, real_t p_times_in_sec
 	, TransitionType p_trans_type
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_target == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 	ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false);
 
 	Variant::CallError error;
@@ -1079,10 +1121,10 @@ bool Tween::follow_method(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_method;
 	data.initial_val = p_initial_val;
-	data.target = p_target->get_path();
+	data.target_id = p_target->get_instance_ID();
 	data.target_key = p_target_method;
 	data.times_in_sec = p_times_in_sec;
 	data.trans_type = p_trans_type;
@@ -1093,9 +1135,9 @@ bool Tween::follow_method(Node *p_node
 	return true;
 }
 
-bool Tween::targeting_property(Node *p_node
+bool Tween::targeting_property(Object *p_object
 	, String p_property
-	, Node *p_initial
+	, Object *p_initial
 	, String p_initial_property
 	, Variant p_final_val
 	, real_t p_times_in_sec
@@ -1103,10 +1145,11 @@ bool Tween::targeting_property(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@@ -1114,7 +1157,7 @@ bool Tween::targeting_property(Node *p_node
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
 	bool prop_valid = false;
-	p_node->get(p_property,&prop_valid);
+	p_object->get(p_property,&prop_valid);
 	ERR_FAIL_COND_V(!prop_valid, false);
 
 	bool initial_prop_valid = false;
@@ -1131,9 +1174,9 @@ bool Tween::targeting_property(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_property;
-	data.target = p_initial->get_path();
+	data.target_id = p_initial->get_instance_ID();
 	data.target_key = p_initial_property;
 	data.initial_val = initial_val;
 	data.final_val = p_final_val;
@@ -1150,9 +1193,9 @@ bool Tween::targeting_property(Node *p_node
 }
 
 
-bool Tween::targeting_method(Node *p_node
+bool Tween::targeting_method(Object *p_object
 	, String p_method
-	, Node *p_initial
+	, Object *p_initial
 	, String p_initial_method
 	, Variant p_final_val
 	, real_t p_times_in_sec
@@ -1160,17 +1203,18 @@ bool Tween::targeting_method(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 	ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false);
 
 	Variant::CallError error;
@@ -1187,9 +1231,9 @@ bool Tween::targeting_method(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_method;
-	data.target = p_initial->get_path();
+	data.target_id = p_initial->get_instance_ID();
 	data.target_key = p_initial_method;
 	data.initial_val = initial_val;
 	data.final_val = p_final_val;
@@ -1213,6 +1257,7 @@ Tween::Tween() {
 	active=false;
 	repeat=false;
 	speed_scale=1;
+	pending_update=0;
 }
 
 Tween::~Tween() {

+ 24 - 21
scene/animation/tween.h

@@ -54,15 +54,17 @@ public:
         TRANS_CIRC,
         TRANS_BOUNCE,
         TRANS_BACK,
-	TRANS_COUNT,
+
+		TRANS_COUNT,
     };
         
     enum EaseType {
         EASE_IN,
         EASE_OUT,
         EASE_IN_OUT,
-	EASE_OUT_IN,
-	EASE_COUNT,
+		EASE_OUT_IN,
+
+		EASE_COUNT,
     };
 
 private:
@@ -82,12 +84,12 @@ private:
 		InterpolateType type;
 		bool finish;
 		real_t elapsed;
-		NodePath path;
+		ObjectID id;
 		StringName key;
 		Variant initial_val;
 		Variant delta_val;
 		Variant final_val;
-		NodePath target;
+		ObjectID target_id;
 		StringName target_key;
 		real_t times_in_sec;
 		TransitionType trans_type;
@@ -102,6 +104,7 @@ private:
 	bool active;
 	bool repeat;
 	float speed_scale;
+	mutable int pending_update;
 
 	List<InterpolateData> interpolates;
 
@@ -142,20 +145,20 @@ public:
 	float get_speed() const;
 
 	bool start();
-	bool reset(Node *p_node, String p_key);
+	bool reset(Object *p_node, String p_key);
 	bool reset_all();
-	bool stop(Node *p_node, String p_key);
+	bool stop(Object *p_node, String p_key);
 	bool stop_all();
-	bool resume(Node *p_node, String p_key);
+	bool resume(Object *p_node, String p_key);
 	bool resume_all();
-	bool remove(Node *p_node, String p_key);
+	bool remove(Object *p_node, String p_key);
 	bool remove_all();
 
 	bool seek(real_t p_time);
 	real_t tell() const;
 	real_t get_runtime() const;
 
-	bool interpolate_property(Node *p_node
+	bool interpolate_property(Object *p_node
 		, String p_property
 		, Variant p_initial_val
 		, Variant p_final_val
@@ -165,7 +168,7 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool interpolate_method(Node *p_node
+	bool interpolate_method(Object *p_node
 		, String p_method
 		, Variant p_initial_val
 		, Variant p_final_val
@@ -175,16 +178,16 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool interpolate_callback(Node *p_node
-		, String p_callback
+	bool interpolate_callback(Object *p_node
 		, real_t p_times_in_sec
+		, String p_callback
 		, Variant p_arg = Variant()
 	);
 
-	bool follow_property(Node *p_node
+	bool follow_property(Object *p_node
 		, String p_property
 		, Variant p_initial_val
-		, Node *p_target
+		, Object *p_target
 		, String p_target_property
 		, real_t p_times_in_sec
 		, TransitionType p_trans_type
@@ -192,10 +195,10 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool follow_method(Node *p_node
+	bool follow_method(Object *p_node
 		, String p_method
 		, Variant p_initial_val
-		, Node *p_target
+		, Object *p_target
 		, String p_target_method
 		, real_t p_times_in_sec
 		, TransitionType p_trans_type
@@ -203,9 +206,9 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool targeting_property(Node *p_node
+	bool targeting_property(Object *p_node
 		, String p_property
-		, Node *p_initial
+		, Object *p_initial
 		, String p_initial_property
 		, Variant p_final_val
 		, real_t p_times_in_sec
@@ -214,9 +217,9 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool targeting_method(Node *p_node
+	bool targeting_method(Object *p_node
 		, String p_method
-		, Node *p_initial
+		, Object *p_initial
 		, String p_initial_method
 		, Variant p_final_val
 		, real_t p_times_in_sec

+ 2 - 2
scene/gui/box_container.cpp

@@ -44,7 +44,7 @@ void BoxContainer::_resort() {
 
 	Size2i new_size=get_size();;
 
-	int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer");
+	int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer");
 
 	bool first=true;
 	int children_count=0;
@@ -202,7 +202,7 @@ Size2 BoxContainer::get_minimum_size() const {
 	/* Calculate MINIMUM SIZE */
 
 	Size2i minimum;
-	int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer");
+	int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer");
 
 	bool first=true;
 

+ 57 - 39
scene/gui/control.cpp

@@ -1325,9 +1325,12 @@ Size2 Control::get_minimum_size() const {
 
 Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type) const {
 	
-	const Ref<Texture>* tex = data.icon_override.getptr(p_name);
-	if (tex)
-		return *tex;	
+	if (p_type==StringName()) {
+
+		const Ref<Texture>* tex = data.icon_override.getptr(p_name);
+		if (tex)
+			return *tex;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 
@@ -1353,12 +1356,11 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type
 
 Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const {
 		
-	
-	const Ref<StyleBox>* style = data.style_override.getptr(p_name);
-	
-	
-	if (style)
-		return *style;	
+	if (p_type==StringName()) {
+		const Ref<StyleBox>* style = data.style_override.getptr(p_name);
+		if (style)
+			return *style;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 
@@ -1381,10 +1383,12 @@ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p
 
 }
 Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) const {
-	
-	const Ref<Font>* font = data.font_override.getptr(p_name);
-	if (font)
-		return *font;	
+
+	if (p_type==StringName()) {
+		const Ref<Font>* font = data.font_override.getptr(p_name);
+		if (font)
+			return *font;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 
@@ -1410,10 +1414,12 @@ Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) c
 
 }
 Color Control::get_color(const StringName& p_name,const StringName& p_type) const {
-	
-	const Color* color = data.color_override.getptr(p_name);
-	if (color)
-		return *color;	
+
+	if (p_type==StringName()) {
+		const Color* color = data.color_override.getptr(p_name);
+		if (color)
+			return *color;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 	// try with custom themes
@@ -1437,10 +1443,12 @@ Color Control::get_color(const StringName& p_name,const StringName& p_type) cons
 }
 
 int Control::get_constant(const StringName& p_name,const StringName& p_type) const {
-	
-	const int* constant = data.constant_override.getptr(p_name);
-	if (constant)
-		return *constant;	
+
+	if (p_type==StringName()) {
+		const int* constant = data.constant_override.getptr(p_name);
+		if (constant)
+			return *constant;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 		// try with custom themes
@@ -1467,9 +1475,11 @@ int Control::get_constant(const StringName& p_name,const StringName& p_type) con
 
 bool Control::has_icon(const StringName& p_name,const StringName& p_type) const {
 	
-	const Ref<Texture>* tex = data.icon_override.getptr(p_name);
-	if (tex)
-		return true;	
+	if (p_type==StringName()) {
+		const Ref<Texture>* tex = data.icon_override.getptr(p_name);
+		if (tex)
+			return true;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 
@@ -1494,11 +1504,12 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const
 }
 bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const {
 		
-	
-	const Ref<StyleBox>* style = data.style_override.getptr(p_name);
-		
-	if (style)
-		return true;	
+	if (p_type==StringName()) {
+		const Ref<StyleBox>* style = data.style_override.getptr(p_name);
+
+		if (style)
+			return true;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 
@@ -1523,9 +1534,11 @@ bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) co
 }
 bool Control::has_font(const StringName& p_name,const StringName& p_type) const {
 	
-	const Ref<Font>* font = data.font_override.getptr(p_name);
-	if (font)
-		return true;	
+	if (p_type==StringName()) {
+		const Ref<Font>* font = data.font_override.getptr(p_name);
+		if (font)
+			return true;
+	}
 
 
 	StringName type = p_type?p_type:get_type_name();
@@ -1551,9 +1564,11 @@ bool Control::has_font(const StringName& p_name,const StringName& p_type) const
 }
 bool Control::has_color(const StringName& p_name,const StringName& p_type) const {
 	
-	const Color* color = data.color_override.getptr(p_name);
-	if (color)
-		return true;	
+	if (p_type==StringName()) {
+		const Color* color = data.color_override.getptr(p_name);
+		if (color)
+			return true;
+	}
 
 	StringName type = p_type?p_type:get_type_name();
 
@@ -1578,10 +1593,13 @@ bool Control::has_color(const StringName& p_name,const StringName& p_type) const
 }
 
 bool Control::has_constant(const StringName& p_name,const StringName& p_type) const {
-	
-	const int* constant = data.constant_override.getptr(p_name);
-	if (constant)
-		return true;	
+
+	if (p_type==StringName()) {
+
+		const int* constant = data.constant_override.getptr(p_name);
+		if (constant)
+			return true;
+	}
 
 
 	StringName type = p_type?p_type:get_type_name();

+ 320 - 0
scene/gui/graph_node.cpp

@@ -0,0 +1,320 @@
+#include "graph_node.h"
+
+
+bool GraphNode::_set(const StringName& p_name, const Variant& p_value) {
+
+	if (!p_name.operator String().begins_with("slot/"))
+		return false;
+
+	int idx=p_name.operator String().get_slice("/",1).to_int();
+	String what = p_name.operator String().get_slice("/",2);
+
+
+	Slot si;
+	if (slot_info.has(idx))
+		si=slot_info[idx];
+
+
+	if (what=="left_enabled")
+		si.enable_left=p_value;
+	else if (what=="left_type")
+		si.type_left=p_value;
+	else if (what=="left_color")
+		si.color_left=p_value;
+	else if (what=="right_enabled")
+		si.enable_right=p_value;
+	else if (what=="right_type")
+		si.type_right=p_value;
+	else if (what=="right_color")
+		si.color_right=p_value;
+	else
+		return false;
+
+	set_slot(idx,si.enable_left,si.type_left,si.color_left,si.enable_right,si.type_right,si.color_right);
+	update();
+	return true;
+}
+
+bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
+
+
+	print_line("get "+p_name.operator String());
+	if (!p_name.operator String().begins_with("slot/")) {
+		print_line("no begins");
+		return false;
+	}
+
+	int idx=p_name.operator String().get_slice("/",1).to_int();
+	String what = p_name.operator String().get_slice("/",2);
+
+
+
+	Slot si;
+	if (slot_info.has(idx))
+		si=slot_info[idx];
+
+	if (what=="left_enabled")
+		r_ret=si.enable_left;
+	else if (what=="left_type")
+		r_ret=si.type_left;
+	else if (what=="left_color")
+		r_ret=si.color_left;
+	else if (what=="right_enabled")
+		r_ret=si.enable_right;
+	else if (what=="right_type")
+		r_ret=si.type_right;
+	else if (what=="right_color")
+		r_ret=si.color_right;
+	else
+		return false;
+
+	print_line("ask for: "+p_name.operator String()+" get: "+String(r_ret));
+	return true;
+}
+void GraphNode::_get_property_list( List<PropertyInfo> *p_list) const{
+
+	int idx=0;
+	for(int i=0;i<get_child_count();i++) {
+		Control *c=get_child(i)->cast_to<Control>();
+		if (!c || c->is_set_as_toplevel() || !c->get_owner())
+			continue;
+
+		String base="slot/"+itos(idx)+"/";
+
+		p_list->push_back(PropertyInfo(Variant::BOOL,base+"left_enabled"));
+		p_list->push_back(PropertyInfo(Variant::INT,base+"left_type"));
+		p_list->push_back(PropertyInfo(Variant::COLOR,base+"left_color"));
+		p_list->push_back(PropertyInfo(Variant::BOOL,base+"right_enabled"));
+		p_list->push_back(PropertyInfo(Variant::INT,base+"right_type"));
+		p_list->push_back(PropertyInfo(Variant::COLOR,base+"right_color"));
+
+		idx++;
+	}
+}
+
+
+void GraphNode::_resort() {
+
+
+
+	int sep=get_constant("separation");
+	Ref<StyleBox> sb=get_stylebox("frame");
+	bool first=true;
+
+	Size2 minsize;
+
+	for(int i=0;i<get_child_count();i++) {
+		Control *c=get_child(i)->cast_to<Control>();
+		if (!c)
+			continue;
+		if (c->is_set_as_toplevel())
+			continue;
+
+		Size2i size=c->get_combined_minimum_size();
+
+		minsize.y+=size.y;
+		minsize.x=MAX(minsize.x,size.x);
+
+		if (first)
+			first=false;
+		else
+			minsize.y+=sep;
+
+	}
+
+	int vofs=0;
+	int w = get_size().x - sb->get_minimum_size().x;
+
+
+	cache_y.clear();
+	for(int i=0;i<get_child_count();i++) {
+		Control *c=get_child(i)->cast_to<Control>();
+		if (!c)
+			continue;
+		if (c->is_set_as_toplevel() || !c->get_owner())
+			continue;
+
+		Size2i size=c->get_combined_minimum_size();
+
+		Rect2 r(sb->get_margin(MARGIN_LEFT),sb->get_margin(MARGIN_TOP)+vofs,w,size.y);
+
+		fit_child_in_rect(c,r);
+		cache_y.push_back(vofs+size.y*0.5);
+
+		if (vofs>0)
+			vofs+=sep;
+		vofs+=size.y;
+
+
+	}
+
+	_change_notify();
+	update();
+
+}
+
+
+void GraphNode::_notification(int p_what) {
+
+	if (p_what==NOTIFICATION_DRAW) {
+
+		Ref<StyleBox> sb=get_stylebox("frame");
+		Ref<Texture> port =get_icon("port");
+		Point2i icofs = -port->get_size()*0.5;
+		int edgeofs=3;
+		icofs.y+=sb->get_margin(MARGIN_TOP);
+		draw_style_box(sb,Rect2(Point2(),get_size()));
+
+		for (Map<int,Slot>::Element *E=slot_info.front();E;E=E->next()) {
+
+			if (E->key()>cache_y.size())
+				continue;
+			if (!slot_info.has(E->key()))
+				continue;
+			const Slot &s=slot_info[E->key()];
+			//left
+			if (s.enable_left)
+				port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left);
+			if (s.enable_right)
+				port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right);
+
+		}
+	}
+	if (p_what==NOTIFICATION_SORT_CHILDREN) {
+
+		_resort();
+	}
+
+}
+
+void GraphNode::set_title(const String& p_title) {
+
+	title=p_title;
+	update();
+}
+
+String GraphNode::get_title() const {
+
+	return title;
+}
+
+void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) {
+
+	ERR_FAIL_COND(p_idx<0);
+
+	if (!p_enable_left && p_type_left==0 && p_color_left==Color(1,1,1,1) && !p_enable_right && p_type_right==0 && p_color_right==Color(1,1,1,1)) {
+		slot_info.erase(p_idx);
+		return;
+	}
+
+	Slot s;
+	s.enable_left=p_enable_left;
+	s.type_left=p_type_left;
+	s.color_left=p_color_left;
+	s.enable_right=p_enable_right;
+	s.type_right=p_type_right;
+	s.color_right=p_color_right;
+	slot_info[p_idx]=s;
+	update();
+}
+
+void GraphNode::clear_slot(int p_idx){
+
+	slot_info.erase(p_idx);
+	update();
+}
+void GraphNode::clear_all_slots(){
+
+	slot_info.clear();
+	update();
+}
+bool GraphNode::is_slot_enabled_left(int p_idx) const{
+
+	if (!slot_info.has(p_idx))
+		return false;
+	return slot_info[p_idx].enable_left;
+
+}
+
+int GraphNode::get_slot_type_left(int p_idx) const{
+
+	if (!slot_info.has(p_idx))
+		return 0;
+	return slot_info[p_idx].type_left;
+
+}
+
+Color GraphNode::get_slot_color_left(int p_idx) const{
+
+	if (!slot_info.has(p_idx))
+		return Color(1,1,1,1);
+	return slot_info[p_idx].color_left;
+
+}
+
+bool GraphNode::is_slot_enabled_right(int p_idx) const{
+
+	if (!slot_info.has(p_idx))
+		return false;
+	return slot_info[p_idx].enable_right;
+
+}
+
+
+
+int GraphNode::get_slot_type_right(int p_idx) const{
+
+	if (!slot_info.has(p_idx))
+		return 0;
+	return slot_info[p_idx].type_right;
+
+}
+
+Color GraphNode::get_slot_color_right(int p_idx) const{
+
+	if (!slot_info.has(p_idx))
+		return Color(1,1,1,1);
+	return slot_info[p_idx].color_right;
+
+}
+
+Size2 GraphNode::get_minimum_size() const {
+
+	int sep=get_constant("separation");
+	Ref<StyleBox> sb=get_stylebox("frame");
+	bool first=true;
+
+	Size2 minsize;
+
+	for(int i=0;i<get_child_count();i++) {
+
+		Control *c=get_child(i)->cast_to<Control>();
+		if (!c)
+			continue;
+		if (c->is_set_as_toplevel() || !c->get_owner())
+			continue;
+
+		Size2i size=c->get_combined_minimum_size();
+
+		minsize.y+=size.y;
+		minsize.x=MAX(minsize.x,size.x);
+
+		if (first)
+			first=false;
+		else
+			minsize.y+=sep;
+	}
+
+	return minsize+sb->get_minimum_size();
+}
+
+
+void GraphNode::_bind_methods() {
+
+
+}
+
+GraphNode::GraphNode() {
+
+
+}

+ 61 - 0
scene/gui/graph_node.h

@@ -0,0 +1,61 @@
+#ifndef GRAPH_NODE_H
+#define GRAPH_NODE_H
+
+#include "scene/gui/container.h"
+
+class GraphNode : public Container {
+
+	OBJ_TYPE(GraphNode,Container);
+
+
+	String title;
+	struct Slot {
+		bool enable_left;
+		int type_left;
+		Color color_left;
+		bool enable_right;
+		int type_right;
+		Color color_right;
+
+
+		Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); };
+	};
+
+	Vector<int> cache_y;
+
+	Map<int,Slot> slot_info;
+
+	void _resort();
+protected:
+
+	void _notification(int p_what);
+	static void _bind_methods();
+
+	bool _set(const StringName& p_name, const Variant& p_value);
+	bool _get(const StringName& p_name,Variant &r_ret) const;
+	void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+
+
+	void set_title(const String& p_title);
+	String get_title() const;
+
+	void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right);
+	void clear_slot(int p_idx);
+	void clear_all_slots();
+	bool is_slot_enabled_left(int p_idx) const;
+	int get_slot_type_left(int p_idx) const;
+	Color get_slot_color_left(int p_idx) const;
+	bool is_slot_enabled_right(int p_idx) const;
+	int get_slot_type_right(int p_idx) const;
+	Color get_slot_color_right(int p_idx) const;
+
+	virtual Size2 get_minimum_size() const;
+
+	GraphNode();
+};
+
+
+#endif // GRAPH_NODE_H

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 528 - 283
scene/gui/text_edit.cpp


+ 15 - 3
scene/gui/text_edit.h

@@ -79,6 +79,7 @@ class TextEdit : public Control  {
 		Color mark_color;
 		Color breakpoint_color;
 		Color current_line_color;
+		Color brace_mismatch_color;
 
 		int row_height;
 		int line_spacing;
@@ -185,6 +186,8 @@ class TextEdit : public Control  {
 	int completion_index;
 	Rect2i completion_rect;
 	int completion_line_ofs;
+	String completion_hint;
+	int completion_hint_offset;
 
 	bool setting_text;
 
@@ -208,6 +211,7 @@ class TextEdit : public Control  {
 	bool line_numbers;
 	
 	bool auto_brace_completion_enabled;
+	bool brace_matching_enabled;
 	bool cut_copy_line;
 
 	uint64_t last_dblclk;
@@ -261,6 +265,7 @@ class TextEdit : public Control  {
 
 	void _clear();
 	void _cancel_completion();
+	void _cancel_code_hint();
 	void _confirm_completion();
 	void _update_completion_candidates();
 
@@ -313,7 +318,11 @@ public:
 	inline void set_auto_brace_completion(bool p_enabled) {
 		auto_brace_completion_enabled = p_enabled;
 	}
-	
+	inline void set_brace_matching(bool p_enabled) {
+		brace_matching_enabled=p_enabled;
+		update();
+	}
+
 	void cursor_set_column(int p_col);
 	void cursor_set_line(int p_row);
 
@@ -350,7 +359,7 @@ public:
 
 	void undo();
 	void redo();
-    void clear_undo_history();
+	void clear_undo_history();
 
 
 	void set_draw_tabs(bool p_draw);
@@ -376,10 +385,13 @@ public:
 
 	void set_tooltip_request_func(Object *p_obj, const StringName& p_function, const Variant& p_udata);
 
-	void set_completion(bool p_enabled,const Vector<String>& p_prefixes);
+	void set_completion(bool p_enabled,const Vector<String>& p_prefixes);	
 	void code_complete(const Vector<String> &p_strings);
+	void set_code_hint(const String& p_hint);
 	void query_code_comple();
 
+	String get_text_for_completion();
+
 	TextEdit();
 	~TextEdit();
 };

+ 20 - 0
scene/main/node.cpp

@@ -1731,6 +1731,26 @@ NodePath Node::get_import_path() const {
 
 #endif
 
+static void _add_nodes_to_options(const Node *p_base,const Node *p_node,List<String>*r_options) {
+
+	if (p_node!=p_base && !p_node->get_owner())
+		return;
+	String n = p_base->get_path_to(p_node);
+	r_options->push_back("\""+n+"\"");
+	for(int i=0;i<p_node->get_child_count();i++) {
+		_add_nodes_to_options(p_base,p_node->get_child(i),r_options);
+	}
+}
+
+void Node::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+	String pf=p_function;
+	if ((pf=="has_node" || pf=="get_node") && p_idx==0) {
+
+		_add_nodes_to_options(this,this,r_options);
+	}
+	Object::get_argument_options(p_function,p_idx,r_options);
+}
 
 void Node::_bind_methods() {
 

+ 1 - 0
scene/main/node.h

@@ -284,6 +284,7 @@ public:
 	NodePath get_import_path() const;
 #endif
 
+	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
 
 	_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
 

+ 2 - 0
scene/register_scene_types.cpp

@@ -75,6 +75,7 @@
 #include "scene/gui/split_container.h"
 #include "scene/gui/video_player.h"
 #include "scene/gui/reference_frame.h"
+#include "scene/gui/graph_node.h"
 #include "scene/resources/video_stream.h"
 #include "scene/2d/particles_2d.h"
 #include "scene/2d/path_2d.h"
@@ -303,6 +304,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_virtual_type<SplitContainer>();
 	ObjectTypeDB::register_type<HSplitContainer>();
 	ObjectTypeDB::register_type<VSplitContainer>();
+	ObjectTypeDB::register_type<GraphNode>();
 
 	OS::get_singleton()->yield(); //may take time to init
 

+ 21 - 9
scene/resources/audio_stream_resampled.cpp

@@ -38,15 +38,18 @@ int AudioStreamResampled::get_channel_count() const {
 
 
 template<int C>
-void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
+uint32_t AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
+
+	uint32_t read=offset&MIX_FRAC_MASK;
 
 	for (int i=0;i<p_todo;i++) {
 
 		offset = (offset + p_increment)&(((1<<(rb_bits+MIX_FRAC_BITS))-1));
+		read+=p_increment;
 		uint32_t pos = offset >> MIX_FRAC_BITS;
 		uint32_t frac = offset & MIX_FRAC_MASK;
 #ifndef FAST_AUDIO
-		ERR_FAIL_COND(pos>=rb_len);
+		ERR_FAIL_COND_V(pos>=rb_len,0);
 #endif
 		uint32_t pos_next = (pos+1)&rb_mask;
 		//printf("rb pos %i\n",pos);
@@ -151,7 +154,7 @@ void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increm
 	}
 
 
-	rb_read_pos=offset>>MIX_FRAC_BITS;
+	return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS;
 
 }
 
@@ -173,10 +176,10 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
 
 	} else if (rb_read_pos<write_pos_cache) {
 
-		rb_todo=write_pos_cache-rb_read_pos-1;
+		rb_todo=write_pos_cache-rb_read_pos; //-1?
 	} else {
 
-		rb_todo=(rb_len-rb_read_pos)+write_pos_cache-1;
+		rb_todo=(rb_len-rb_read_pos)+write_pos_cache; //-1?
 	}
 
 	int todo = MIN( ((int64_t(rb_todo)<<MIX_FRAC_BITS)/increment)+1, p_frames );
@@ -220,13 +223,22 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) {
 #endif
 	{
 
+		uint32_t read=0;
 		switch(channels) {
-			case 1: _resample<1>(p_dest,todo,increment); break;
-			case 2: _resample<2>(p_dest,todo,increment); break;
-			case 4: _resample<4>(p_dest,todo,increment); break;
-			case 6: _resample<6>(p_dest,todo,increment); break;
+			case 1: read=_resample<1>(p_dest,todo,increment); break;
+			case 2: read=_resample<2>(p_dest,todo,increment); break;
+			case 4: read=_resample<4>(p_dest,todo,increment); break;
+			case 6: read=_resample<6>(p_dest,todo,increment); break;
 		}
 
+		if (read>rb_todo)
+			read=rb_todo;
+
+		rb_read_pos = (rb_read_pos+read)&rb_mask;
+
+
+
+
 	}
 
 	return true;

+ 2 - 2
scene/resources/audio_stream_resampled.h

@@ -57,7 +57,7 @@ class AudioStreamResampled : public AudioStream {
 
 
 	template<int C>
-	void _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
+	uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
 
 
 protected:
@@ -97,7 +97,7 @@ protected:
 	_FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; }
 	_FORCE_INLINE_ void write(uint32_t p_frames) {
 
-		ERR_FAIL_COND(p_frames > rb_len);
+		ERR_FAIL_COND(p_frames >= rb_len);
 
 		switch(channels) {
 			case 1: {

+ 11 - 2
scene/resources/default_theme/default_theme.cpp

@@ -65,7 +65,7 @@ static Ref<Texture> make_icon(T p_src) {
 	
 	
 	Ref<ImageTexture> texture( memnew( ImageTexture ) );
-	texture->create_from_image( Image(p_src) );
+	texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER );
 		
 	return texture;
 }
@@ -331,6 +331,7 @@ void make_default_theme() {
 	t->set_color("current_line_color","TextEdit", Color(0.3,0.5,0.8,0.15) );
 	t->set_color("cursor_color","TextEdit", control_font_color );
 	t->set_color("symbol_color","TextEdit", control_font_color_hover );
+	t->set_color("brace_mismatch_color","TextEdit", Color(1,0.2,0.2) );
 	t->set_constant("line_spacing","TextEdit",1 );
 
 	t->set_stylebox("scroll","HScrollBar", make_stylebox( hscroll_bg_png,3,3,3,3,0,0,0,0) );
@@ -415,7 +416,15 @@ void make_default_theme() {
 	t->set_color("font_color_hover","PopupMenu", control_font_color );
 	t->set_constant("hseparation","PopupMenu",2);
 	t->set_constant("vseparation","PopupMenu",1);
-		
+
+	Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,21,6,5,16,21,16,5);
+	//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
+	//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
+	t->set_stylebox("frame","GraphNode", graphsb );
+	t->set_constant("separation","GraphNode", 1 );
+	t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
+
+
 	t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) );
 	t->set_stylebox("bg_focus","Tree", focus );
 	Ref<StyleBoxTexture> tree_selected = make_stylebox( selection_png,4,4,4,4);

BIN
scene/resources/default_theme/graph_node.png


BIN
scene/resources/default_theme/graph_port.png


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 0
scene/resources/default_theme/theme_data.h


+ 16 - 0
scene/resources/material.cpp

@@ -458,6 +458,8 @@ FixedMaterial::~FixedMaterial() {
 }
 
 
+
+
 bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) {
 
 	if (p_name==SceneStringNames::get_singleton()->shader_shader) {
@@ -558,7 +560,21 @@ void ShaderMaterial::_bind_methods() {
 }
 
 
+void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
+
+	String f = p_function.operator String();
+	if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) {
 
+		if (shader.is_valid()) {
+			List<PropertyInfo> pl;
+			shader->get_param_list(&pl);
+			for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
+				r_options->push_back(E->get().name);
+			}
+		}
+	}
+	Material::get_argument_options(p_function,p_idx,r_options);
+}
 
 ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){
 

+ 1 - 0
scene/resources/material.h

@@ -243,6 +243,7 @@ public:
 	void set_shader_param(const StringName& p_param,const Variant& p_value);
 	Variant get_shader_param(const StringName& p_param) const;
 
+	void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
 
 	ShaderMaterial();
 };

+ 3 - 1
scene/resources/polygon_path_finder.cpp

@@ -142,6 +142,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector
 			if (d<closest_dist) {
 				ignore_from_edge=E->get();
 				closest_dist=d;
+				closest_point=closest;
 			}
 		}
 
@@ -168,6 +169,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector
 			if (d<closest_dist) {
 				ignore_to_edge=E->get();
 				closest_dist=d;
+				closest_point=closest;
 			}
 		}
 
@@ -529,7 +531,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const {
 
 		float d = p_point.distance_squared_to(points[i].pos);
 		if (d<closest_dist) {
-			d=closest_dist;
+			closest_dist=d;
 			closest_idx=i;
 		}
 

+ 43 - 0
scene/resources/shader.cpp

@@ -120,6 +120,13 @@ Dictionary Shader::_get_code() {
 	c["vertex_ofs"]=0;
 	c["light"]=ls;
 	c["light_ofs"]=0;
+	Array arr;
+	for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) {
+		arr.push_back(E->key());
+		arr.push_back(E->get());
+	}
+	if (arr.size())
+		c["default_tex"]=arr;
 	return c;
 }
 
@@ -132,8 +139,41 @@ void Shader::_set_code(const Dictionary& p_string) {
 		light=p_string["light"];
 
 	set_code(p_string["vertex"],p_string["fragment"],light);
+	if (p_string.has("default_tex")) {
+		Array arr=p_string["default_tex"];
+		if ((arr.size()&1)==0) {
+			for(int i=0;i<arr.size();i+=2)
+				set_default_texture_param(arr[i],arr[i+1]);
+		}
+	}
+}
+
+void Shader::set_default_texture_param(const StringName& p_param,const Ref<Texture>& p_texture) {
+
+	if (p_texture.is_valid())
+		default_textures[p_param]=p_texture;
+	else
+		default_textures.erase(p_param);
+}
+
+Ref<Texture> Shader::get_default_texture_param(const StringName& p_param) const{
+
+	if (default_textures.has(p_param))
+		return default_textures[p_param];
+	else
+		return Ref<Texture>();
 }
 
+void Shader::get_default_texture_param_list(List<StringName>* r_textures) const{
+
+	for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) {
+
+		r_textures->push_back(E->key());
+	}
+
+}
+
+
 void Shader::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode);
@@ -144,6 +184,9 @@ void Shader::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_fragment_code"),&Shader::get_fragment_code);
 	ObjectTypeDB::bind_method(_MD("get_light_code"),&Shader::get_light_code);
 
+	ObjectTypeDB::bind_method(_MD("set_default_texture_param","param","texture:Texture"),&Shader::set_default_texture_param);
+	ObjectTypeDB::bind_method(_MD("get_default_texture_param:Texture","param"),&Shader::get_default_texture_param);
+
 	ObjectTypeDB::bind_method(_MD("has_param","name"),&Shader::has_param);
 
 	ObjectTypeDB::bind_method(_MD("_set_code","code"),&Shader::_set_code);

+ 6 - 1
scene/resources/shader.h

@@ -31,7 +31,7 @@
 
 #include "resource.h"
 #include "io/resource_loader.h"
-
+#include "scene/resources/texture.h"
 class Shader : public Resource {
 
 	OBJ_TYPE(Shader,Resource);
@@ -48,6 +48,7 @@ class Shader : public Resource {
 	// convertion fast and save memory.
 	mutable bool params_cache_dirty;
 	mutable Map<StringName,StringName> params_cache; //map a shader param to a material param..
+	Map<StringName,Ref<Texture> > default_textures;
 
 protected:
 
@@ -72,6 +73,10 @@ public:
 	void get_param_list(List<PropertyInfo> *p_params) const;
 	bool has_param(const StringName& p_param) const;
 
+	void set_default_texture_param(const StringName& p_param, const Ref<Texture> &p_texture);
+	Ref<Texture> get_default_texture_param(const StringName& p_param) const;
+	void get_default_texture_param_list(List<StringName>* r_textures) const;
+
 	virtual RID get_rid() const;
 
 	Shader();

+ 4 - 0
servers/visual/rasterizer.h

@@ -187,6 +187,7 @@ public:
 	virtual bool texture_has_alpha(RID p_texture) const=0;
 	virtual void texture_set_size_override(RID p_texture,int p_width, int p_height)=0;
 
+
 	virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const=0;
 
 	/* SHADER API */
@@ -203,6 +204,9 @@ public:
 
 	virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const=0;
 
+	virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture)=0;
+	virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const=0;
+
 	/* COMMON MATERIAL API */
 
 	virtual RID material_create()=0;

+ 10 - 0
servers/visual/rasterizer_dummy.cpp

@@ -221,6 +221,16 @@ void RasterizerDummy::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_
 
 }
 
+
+void RasterizerDummy::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+}
+
+RID RasterizerDummy::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const {
+
+	return RID();
+}
+
 /* COMMON MATERIAL API */
 
 

+ 4 - 0
servers/visual/rasterizer_dummy.h

@@ -429,6 +429,10 @@ public:
 
 	virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
 
+
+	virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+	virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
+
 	/* COMMON MATERIAL API */
 
 	virtual RID material_create();

+ 10 - 0
servers/visual/visual_server_raster.cpp

@@ -157,6 +157,16 @@ void VisualServerRaster::shader_get_param_list(RID p_shader, List<PropertyInfo>
 }
 
 
+void VisualServerRaster::shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture) {
+
+	rasterizer->shader_set_default_texture_param(p_shader,p_name,p_texture);
+}
+
+RID VisualServerRaster::shader_get_default_texture_param(RID p_shader, const StringName& p_name) const{
+
+	return rasterizer->shader_get_default_texture_param(p_shader,p_name);
+}
+
 
 /* Material */
 

+ 4 - 0
servers/visual/visual_server_raster.h

@@ -756,6 +756,10 @@ public:
 
 	virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const;
 
+	virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture);
+	virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const;
+
+
 	/* COMMON MATERIAL API */
 
 	virtual RID material_create();

+ 4 - 0
servers/visual/visual_server_wrap_mt.h

@@ -653,6 +653,10 @@ public:
 	FUNC1RC(String,shader_get_light_code,RID);
 	FUNC2SC(shader_get_param_list,RID,List<PropertyInfo>*);
 
+	FUNC3(shader_set_default_texture_param,RID,const StringName&,RID);
+	FUNC2RC(RID,shader_get_default_texture_param,RID,const StringName&);
+
+
 	/*virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) {
 		if (Thread::get_caller_ID()!=server_thread) {
 			command_queue.push_and_sync( visual_server, &VisualServer::shader_get_param_list,p_shader,p_param_list);

+ 4 - 0
servers/visual_server.h

@@ -140,6 +140,7 @@ public:
 		SHADER_POST_PROCESS,
 	};
 
+
 	virtual RID shader_create(ShaderMode p_mode=SHADER_MATERIAL)=0;
 
 	virtual void shader_set_mode(RID p_shader,ShaderMode p_mode)=0;
@@ -151,6 +152,9 @@ public:
 	virtual String shader_get_light_code(RID p_shader) const=0;
 	virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const=0;
 
+	virtual void shader_set_default_texture_param(RID p_shader, const StringName& p_name, RID p_texture)=0;
+	virtual RID shader_get_default_texture_param(RID p_shader, const StringName& p_name) const=0;
+
 
 	/* COMMON MATERIAL API */
 

+ 11 - 3
tools/editor/code_editor.cpp

@@ -487,6 +487,7 @@ FindReplaceDialog::FindReplaceDialog() {
 
 	vb->add_child(error_label);
 
+
 	set_hide_on_ok(false);
 
 }
@@ -507,15 +508,19 @@ void CodeTextEditor::_text_changed() {
 }
 
 void CodeTextEditor::_code_complete_timer_timeout() {
+	if (!is_visible())
+		return;
 	if (enable_complete_timer)
 		text_editor->query_code_comple();
 }
 
-void CodeTextEditor::_complete_request(const String& p_request, int p_line) {
+void CodeTextEditor::_complete_request() {
 
 	List<String> entries;
-	_code_complete_script(text_editor->get_text(),p_request,p_line,&entries);
+	_code_complete_script(text_editor->get_text_for_completion(),&entries);
 	// print_line("COMPLETE: "+p_request);
+	if (entries.size()==0)
+		return;
 	Vector<String> strs;
 	strs.resize(entries.size());
 	int i=0;
@@ -555,7 +560,7 @@ void CodeTextEditor::_on_settings_change() {
 	
 	// AUTO BRACE COMPLETION 
 	text_editor->set_auto_brace_completion(
-		EDITOR_DEF("text_editor/auto_brace_complete", false)
+		EDITOR_DEF("text_editor/auto_brace_complete", true)
 	);
 
 	code_complete_timer->set_wait_time(
@@ -596,6 +601,7 @@ CodeTextEditor::CodeTextEditor() {
 	text_editor->set_margin(MARGIN_BOTTOM,20);
 	text_editor->add_font_override("font",get_font("source","Fonts"));
 	text_editor->set_show_line_numbers(true);
+	text_editor->set_brace_matching(true);
 
 	line_col = memnew( Label );
 	add_child(line_col);
@@ -632,6 +638,8 @@ CodeTextEditor::CodeTextEditor() {
 	text_editor->connect("request_completion", this,"_complete_request");
 	Vector<String> cs;
 	cs.push_back(".");
+	cs.push_back(",");
+	cs.push_back("(");
 	text_editor->set_completion(true,cs);
 	idle->connect("timeout", this,"_text_changed_idle_timeout");
 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.