浏览代码

Making Godot Easier to Use..
-=-=-=-=-=-=-=-=-=-=-=-=-=-=

-Auto indenter in code editor, this makes it much easier to paste external code.
-Zoom in 2D viewport now uses the mouse pointer as reference.
-Obscure hack to see where code/line of GDScript in C++ backtrace.
-Fixed a bug where keys would get stuck on X11 if pressed simultaneously
-Added Api on IP singleton to request local IPs.
-Premultiplied alpha support when importing texture, editing PNGs and as a blend mode.

Juan Linietsky 11 年之前
父节点
当前提交
1cad087969
共有 53 个文件被更改,包括 923 次插入101 次删除
  1. 7 0
      core/bind/core_bind.cpp
  2. 10 0
      core/bind/core_bind.h
  3. 25 0
      core/image.cpp
  4. 1 0
      core/image.h
  5. 5 0
      core/io/file_access_encrypted.cpp
  6. 13 0
      core/io/ip.cpp
  7. 3 0
      core/io/ip.h
  8. 1 1
      core/os/file_access.cpp
  9. 2 0
      core/os/input.cpp
  10. 1 1
      core/os/main_loop.cpp
  11. 1 0
      core/script_language.h
  12. 8 4
      demos/2d/platformer/stage.xml
  13. 4 1
      doc/make_doc.sh
  14. 3 0
      drivers/gles2/shaders/canvas.glsl
  15. 99 0
      drivers/unix/ip_unix.cpp
  16. 2 0
      drivers/unix/ip_unix.h
  17. 10 0
      modules/gdscript/gd_compiler.cpp
  18. 64 0
      modules/gdscript/gd_editor.cpp
  19. 19 4
      modules/gdscript/gd_parser.cpp
  20. 2 0
      modules/gdscript/gd_parser.h
  21. 3 0
      modules/gdscript/gd_script.cpp
  22. 6 2
      modules/gdscript/gd_script.h
  23. 1 0
      platform/android/SCsub
  24. 221 0
      platform/android/ifaddrs_android.cpp
  25. 46 0
      platform/android/ifaddrs_android.h
  26. 33 0
      platform/android/java/src/com/android/godot/Godot.java
  27. 30 7
      platform/android/java/src/com/android/godot/GodotPaymentV3.java
  28. 1 2
      platform/android/java/src/com/android/godot/payments/ConsumeTask.java
  29. 6 4
      platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java
  30. 3 0
      platform/android/java/src/com/android/godot/payments/PaymentsCache.java
  31. 7 5
      platform/android/java/src/com/android/godot/payments/PaymentsManager.java
  32. 3 3
      platform/android/java/src/com/android/godot/payments/PurchaseTask.java
  33. 1 1
      platform/android/sign.sh
  34. 4 2
      platform/iphone/detect.py
  35. 10 3
      platform/iphone/gl_view.mm
  36. 2 2
      platform/windows/detect.py
  37. 16 20
      platform/x11/os_x11.cpp
  38. 1 1
      platform/x11/os_x11.h
  39. 3 2
      scene/2d/canvas_item.cpp
  40. 2 1
      scene/2d/canvas_item.h
  41. 3 1
      scene/resources/material.cpp
  42. 1 0
      scene/resources/material.h
  43. 12 0
      scene/resources/texture.cpp
  44. 1 0
      scene/resources/texture.h
  45. 2 1
      servers/visual_server.h
  46. 12 0
      tools/editor/io_plugins/editor_texture_import_plugin.cpp
  47. 2 1
      tools/editor/io_plugins/editor_texture_import_plugin.h
  48. 161 32
      tools/editor/plugins/baked_light_editor_plugin.cpp
  49. 12 0
      tools/editor/plugins/baked_light_editor_plugin.h
  50. 15 0
      tools/editor/plugins/canvas_item_editor_plugin.cpp
  51. 21 0
      tools/editor/plugins/script_editor_plugin.cpp
  52. 1 0
      tools/editor/plugins/script_editor_plugin.h
  53. 1 0
      tools/editor/property_editor.cpp

+ 7 - 0
core/bind/core_bind.cpp

@@ -98,6 +98,13 @@ void _ResourceSaver::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("save","path","resource:Resource"),&_ResourceSaver::save, DEFVAL(0));
 	ObjectTypeDB::bind_method(_MD("get_recognized_extensions","type"),&_ResourceSaver::get_recognized_extensions);
+
+	BIND_CONSTANT(FLAG_RELATIVE_PATHS);
+	BIND_CONSTANT(FLAG_BUNDLE_RESOURCES);
+	BIND_CONSTANT(FLAG_CHANGE_PATH);
+	BIND_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES);
+	BIND_CONSTANT(FLAG_SAVE_BIG_ENDIAN);
+	BIND_CONSTANT(FLAG_COMPRESS);
 }
 
 _ResourceSaver::_ResourceSaver() {

+ 10 - 0
core/bind/core_bind.h

@@ -39,6 +39,16 @@ protected:
 	static _ResourceSaver *singleton;
 public:
 
+	enum SaverFlags {
+
+		FLAG_RELATIVE_PATHS=1,
+		FLAG_BUNDLE_RESOURCES=2,
+		FLAG_CHANGE_PATH=4,
+		FLAG_OMIT_EDITOR_PROPERTIES=8,
+		FLAG_SAVE_BIG_ENDIAN=16,
+		FLAG_COMPRESS=32,
+	};
+
 	static _ResourceSaver *get_singleton() { return singleton; }
 
 	Error save(const String &p_path,const RES& p_resource, uint32_t p_flags);

+ 25 - 0
core/image.cpp

@@ -1660,6 +1660,31 @@ void Image::set_compress_bc_func(void (*p_compress_func)(Image *)) {
 }
 
 
+
+void Image::premultiply_alpha() {
+
+	if (data.size()==0)
+		return;
+
+	if (format!=FORMAT_RGBA)
+		return; //not needed
+
+	DVector<uint8_t>::Write wp = data.write();
+	unsigned char *data_ptr=wp.ptr();
+
+
+	for(int i=0;i<height;i++) {
+		for(int j=0;j<width;j++) {
+
+			BColor bc = _get_pixel(j,i,data_ptr,0);
+			bc.r=(int(bc.r)*int(bc.a))>>8;
+			bc.g=(int(bc.g)*int(bc.a))>>8;
+			bc.b=(int(bc.b)*int(bc.a))>>8;
+			_put_pixel(j,i,bc,data_ptr);
+		}
+	}
+}
+
 void Image::fix_alpha_edges() {
 
 	if (data.size()==0)

+ 1 - 0
core/image.h

@@ -320,6 +320,7 @@ public:
 	void decompress();
 
 	void fix_alpha_edges();
+	void premultiply_alpha();
 
 	void blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2& p_dest);
 	void brush_transfer(const Image& p_src, const Image& p_brush, const Point2& p_dest);

+ 5 - 0
core/io/file_access_encrypted.cpp

@@ -25,6 +25,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base,const Vector<uint8_
 
 	} else if (p_mode==MODE_READ) {
 
+		writing=false;
 		key=p_key;
 		uint32_t magic = p_base->get_32();
 		print_line("MAGIC: "+itos(magic));
@@ -278,6 +279,10 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String& p_file){
 FileAccessEncrypted::FileAccessEncrypted() {
 
 	file=NULL;
+	pos=0;
+	eofed=false;
+	mode=MODE_MAX;
+	writing=false;
 }
 
 

+ 13 - 0
core/io/ip.cpp

@@ -188,6 +188,18 @@ void IP::erase_resolve_item(ResolverID p_id) {
 }
 
 
+Array IP::_get_local_addresses() const {
+
+	Array addresses;
+	List<IP_Address> ip_addresses;
+	get_local_addresses(&ip_addresses);
+	for(List<IP_Address>::Element *E=ip_addresses.front();E;E=E->next()) {
+		addresses.push_back(E->get());
+	}
+
+	return addresses;
+}
+
 void IP::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("resolve_hostname","host"),&IP::resolve_hostname);
@@ -195,6 +207,7 @@ void IP::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_resolve_item_status","id"),&IP::get_resolve_item_status);
 	ObjectTypeDB::bind_method(_MD("get_resolve_item_address","id"),&IP::get_resolve_item_address);
 	ObjectTypeDB::bind_method(_MD("erase_resolve_item","id"),&IP::erase_resolve_item);
+	ObjectTypeDB::bind_method(_MD("get_local_addresses"),&IP::_get_local_addresses);
 
 	BIND_CONSTANT( RESOLVER_STATUS_NONE );
 	BIND_CONSTANT( RESOLVER_STATUS_WAITING );

+ 3 - 0
core/io/ip.h

@@ -66,16 +66,19 @@ protected:
 	static void _bind_methods();
 
 	virtual IP_Address _resolve_hostname(const String& p_hostname)=0;
+	Array _get_local_addresses() const;
 
 	static IP* (*_create)();
 public:
 
 
+
 	IP_Address resolve_hostname(const String& p_hostname);
 	// async resolver hostname
 	ResolverID resolve_hostname_queue_item(const String& p_hostname);
 	ResolverStatus get_resolve_item_status(ResolverID p_id) const;
 	IP_Address get_resolve_item_address(ResolverID p_id) const;
+	virtual void get_local_addresses(List<IP_Address> *r_addresses) const=0;
 	void erase_resolve_item(ResolverID p_id);
 
 	static IP* get_singleton();

+ 1 - 1
core/os/file_access.cpp

@@ -100,7 +100,7 @@ FileAccess *FileAccess::open(const String& p_path, int p_mode_flags, Error *r_er
 	FileAccess *ret=NULL;
 	if (!(p_mode_flags&WRITE) && PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled()) {
 		ret = PackedData::get_singleton()->try_open_path(p_path);
-        if (ret) {
+		if (ret) {
 			if (r_error)
 				*r_error=OK;
 			return ret;

+ 2 - 0
core/os/input.cpp

@@ -211,6 +211,8 @@ void InputDefault::parse_input_event(const InputEvent& p_event) {
 			if (p_event.key.scancode==0)
 				break;
 
+		//	print_line(p_event);
+
 			if (p_event.key.pressed)
 				keys_pressed.insert(p_event.key.scancode);
 			else

+ 1 - 1
core/os/main_loop.cpp

@@ -37,7 +37,7 @@ void MainLoop::_bind_methods() {
 	BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
 	BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
 	BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST);
-
+	BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
 
 };
 

+ 1 - 0
core/script_language.h

@@ -141,6 +141,7 @@ public:
 	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 void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const=0;
 
 	/* DEBUGGER FUNCTIONS */
 

+ 8 - 4
demos/2d/platformer/stage.xml

@@ -3,10 +3,10 @@
 	<ext_resource path="res://music.ogg" type="AudioStream"></ext_resource>
 	<ext_resource path="res://tileset.xml" type="TileSet"></ext_resource>
 	<ext_resource path="res://coin.xml" type="PackedScene"></ext_resource>
+	<ext_resource path="res://player.xml" type="PackedScene"></ext_resource>
+	<ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource>
 	<ext_resource path="res://seesaw.xml" type="PackedScene"></ext_resource>
 	<ext_resource path="res://enemy.xml" type="PackedScene"></ext_resource>
-	<ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource>
-	<ext_resource path="res://player.xml" type="PackedScene"></ext_resource>
 	<ext_resource path="res://parallax_bg.xml" type="PackedScene"></ext_resource>
 	<main_resource>
 		<dictionary name="_bundled" shared="false">
@@ -160,9 +160,13 @@
 							<string> "pixel_snap" </string>
 							<bool> False </bool>
 							<string> "zoom" </string>
-							<real> 0.735092 </real>
+							<real> 0.54036 </real>
+							<string> "use_snap" </string>
+							<bool> False </bool>
 							<string> "ofs" </string>
-							<vector2> 55.9232, 767.661 </vector2>
+							<vector2> 418.81, 615.088 </vector2>
+							<string> "snap" </string>
+							<int> 10 </int>
 						</dictionary>
 						<string> "3D" </string>
 						<dictionary  shared="false">

+ 4 - 1
doc/make_doc.sh

@@ -6436,7 +6436,10 @@ void RasterizerGLES2::canvas_set_blend_mode(VS::MaterialBlendMode p_mode) {
 		case VS::MATERIAL_BLEND_MODE_MUL: {
 			glBlendEquation(GL_FUNC_ADD);
 			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
-
+		} break;
+		case VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA: {
+			glBlendEquation(GL_FUNC_ADD);
+			glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
 		} break;
 
 	}

+ 3 - 0
drivers/gles2/shaders/canvas.glsl

@@ -64,6 +64,9 @@ void main() {
 	highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1)  );
 	color = vec4(vec3(enc32),1.0);
 #endif
+
+//	color.rgb*=color.a;
 	gl_FragColor = color;
+
 }
 

+ 99 - 0
drivers/unix/ip_unix.cpp

@@ -30,12 +30,24 @@
 
 #if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
 
+
 #ifdef WINDOWS_ENABLED
+#define WINVER 0x0600
 #include <ws2tcpip.h>
 #include <winsock2.h>
 #include <windows.h>
+#include <stdio.h>
+#include <iphlpapi.h>
 #else
 #include <netdb.h>
+#ifdef ANDROID_ENABLED
+#include "platform/android/ifaddrs_android.h"
+#else
+#include <ifaddrs.h>
+#endif
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
 #endif
 IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
 
@@ -52,6 +64,93 @@ IP_Address IP_Unix::_resolve_hostname(const String& p_hostname) {
 
 }
 
+#if defined(WINDOWS_ENABLED)
+
+void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
+
+	ULONG buf_size = 1024;
+	IP_ADAPTER_ADDRESSES* addrs;
+
+	while (true) {
+
+		addrs = (IP_ADAPTER_ADDRESSES*)memalloc(buf_size);
+		int err = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST |
+									   GAA_FLAG_SKIP_MULTICAST |
+									   GAA_FLAG_SKIP_DNS_SERVER |
+									   GAA_FLAG_SKIP_FRIENDLY_NAME,
+									 NULL, addrs, &buf_size);
+		if (err == NO_ERROR) {
+			break;
+		};
+		memfree(addrs);
+		if (err == ERROR_BUFFER_OVERFLOW) {
+			continue; // will go back and alloc the right size
+		};
+
+		ERR_EXPLAIN("Call to GetAdaptersAddresses failed with error " + itos(err));
+		ERR_FAIL();
+		return;
+	};
+
+
+	IP_ADAPTER_ADDRESSES* adapter = addrs;
+
+	while (adapter != NULL) {
+
+		IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress;
+		while (address != NULL) {
+
+			char addr_chr[INET_ADDRSTRLEN];
+			SOCKADDR_IN* ipv4 = reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr);
+
+			IP_Address ip;
+			ip.host= *((unsigned long*)&ipv4->sin_addr);
+
+
+			//inet_ntop(AF_INET, &ipv4->sin_addr, addr_chr, INET_ADDRSTRLEN);
+
+			r_addresses->push_back(ip);
+
+			address = address->Next;
+		};
+		adapter = adapter->Next;
+	};
+
+	memfree(addrs);
+};
+
+
+#else
+
+void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
+
+	struct ifaddrs * ifAddrStruct=NULL;
+	struct ifaddrs * ifa=NULL;
+
+	getifaddrs(&ifAddrStruct);
+
+	for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
+		if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
+			// is a valid IP4 Address
+
+			IP_Address ip;
+			ip.host= *((unsigned long*)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr);
+
+			r_addresses->push_back(ip);
+		}/* else if (ifa->ifa_addr->sa_family==AF_INET6) { // check it is IP6
+			// is a valid IP6 Address
+			tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+			char addressBuffer[INET6_ADDRSTRLEN];
+			inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
+			printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
+		} */
+	}
+
+	if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
+
+}
+#endif
+
 void IP_Unix::make_default() {
 
 	_create=_create_unix;

+ 2 - 0
drivers/unix/ip_unix.h

@@ -41,6 +41,8 @@ class IP_Unix : public IP {
 	static IP* _create_unix();
 public:
 
+	virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
+
 	static void make_default();
 	IP_Unix();
 };

+ 10 - 0
modules/gdscript/gd_compiler.cpp

@@ -1263,6 +1263,16 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
 	gdfunc->name=func_name;
 	gdfunc->_script=p_script;
 	gdfunc->source=source;
+
+#ifdef DEBUG_ENABLED
+
+	{
+		gdfunc->func_cname=(String(source)+" - "+String(func_name)).utf8();
+		gdfunc->_func_cname=gdfunc->func_cname.get_data();
+
+	}
+
+#endif
 	if (p_func) {
 		gdfunc->_initial_line=p_func->line;
 	} else {

+ 64 - 0
modules/gdscript/gd_editor.cpp

@@ -787,3 +787,67 @@ Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const
 	return OK;
 }
 
+void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_line) const {
+
+
+	Vector<String> lines = p_code.split("\n");
+	List<int> indent_stack;
+
+	for(int i=0;i<lines.size();i++) {
+
+		String l = lines[i];
+		int tc=0;
+		for(int j=0;j<l.length();j++) {
+			if (l[j]==' ' || l[j]=='\t') {
+
+				tc++;
+			} else {
+				break;
+			}
+		}
+
+
+		String st = l.substr(tc,l.length()).strip_edges();
+		if (st=="" || st.begins_with("#"))
+			continue; //ignore!
+
+		int ilevel=0;
+		if (indent_stack.size()) {
+			ilevel=indent_stack.back()->get();
+		}
+
+		if (tc>ilevel) {
+			indent_stack.push_back(tc);
+		} else if (tc<ilevel) {
+			while(indent_stack.size() && indent_stack.back()->get()>tc) {
+				indent_stack.pop_back();
+			}
+
+			if (indent_stack.size() && indent_stack.back()->get()!=tc)
+				indent_stack.push_back(tc); //this is not right but gets the job done
+		}
+
+		if (i>=p_from_line) {
+
+			l="";
+			for(int j=0;j<indent_stack.size();j++)
+				l+="\t";
+			l+=st;
+
+
+		} else if (i>p_to_line) {
+			break;
+		}
+
+		//print_line(itos(indent_stack.size())+","+itos(tc)+": "+l);
+		lines[i]=l;
+	}
+
+	p_code="";
+	for(int i=0;i<lines.size();i++) {
+		if (i>0)
+			p_code+="\n";
+		p_code+=lines[i];
+	}
+
+}

+ 19 - 4
modules/gdscript/gd_parser.cpp

@@ -1221,6 +1221,15 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 			return; //go back a level
 		}
 
+		if (pending_newline!=-1) {
+
+			NewLineNode *nl = alloc_node<NewLineNode>();
+			nl->line=pending_newline;
+			p_block->statements.push_back(nl);
+			pending_newline=-1;
+
+		}
+
 		switch(token) {
 
 
@@ -1234,16 +1243,19 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
 			} break;
 			case GDTokenizer::TK_NEWLINE: {
 
-				NewLineNode *nl = alloc_node<NewLineNode>();
-				nl->line=tokenizer->get_token_line();
-				p_block->statements.push_back(nl);
-
 				if (!_parse_newline()) {
 					if (!error_set) {
 						p_block->end_line=tokenizer->get_token_line();
+						pending_newline=p_block->end_line;
+
 					}
 					return;
 				}
+
+				NewLineNode *nl = alloc_node<NewLineNode>();
+				nl->line=tokenizer->get_token_line();
+				p_block->statements.push_back(nl);
+
 			} break;
 			case GDTokenizer::TK_CF_PASS: {
 				if (tokenizer->get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE ) {
@@ -1782,6 +1794,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
 			case GDTokenizer::TK_PR_FUNCTION: {
 
 				bool _static=false;
+				pending_newline=-1;
 
 				if (tokenizer->get_token(-1)==GDTokenizer::TK_PR_STATIC) {
 
@@ -2490,6 +2503,7 @@ void GDParser::clear() {
 	tab_level.push_back(0);
 	error_line=0;
 	error_column=0;
+	pending_newline=-1;
 	parenthesis=0;
 	current_export.type=Variant::NIL;
 	error="";
@@ -2501,6 +2515,7 @@ GDParser::GDParser() {
 	head=NULL;
 	list=NULL;
 	tokenizer=NULL;
+	pending_newline=-1;
 	clear();
 
 }

+ 2 - 0
modules/gdscript/gd_parser.h

@@ -362,6 +362,8 @@ private:
 	int error_line;
 	int error_column;
 
+	int pending_newline;
+
 	List<int> tab_level;
 
 	String base_path;

+ 3 - 0
modules/gdscript/gd_script.cpp

@@ -1159,6 +1159,9 @@ GDFunction::GDFunction() {
 	_stack_size=0;
 	_call_size=0;
 	name="<anonymous>";
+#ifdef DEBUG_ENABLED
+	_func_cname=NULL;
+#endif
 
 }
 

+ 6 - 2
modules/gdscript/gd_script.h

@@ -118,10 +118,13 @@ friend class GDCompiler;
 	Vector<Variant> constants;
 	Vector<StringName> global_names;
 	Vector<int> default_arguments;
-
 	Vector<int> code;
+#ifdef DEBUG_ENABLED
+	CharString func_cname;
+	const char*_func_cname;
+#endif
 
-    List<StackDebug> stack_debug;
+	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;
 	_FORCE_INLINE_ String _get_call_error(const Variant::CallError& p_err, const String& p_where,const Variant**argptrs) const;
@@ -427,6 +430,7 @@ public:
 	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 void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
 
 	/* DEBUGGER FUNCTIONS */
 

+ 1 - 0
platform/android/SCsub

@@ -13,6 +13,7 @@ android_files = [
 	'dir_access_jandroid.cpp',
 	'thread_jandroid.cpp',
 	'audio_driver_jandroid.cpp',
+	'ifaddrs_android.cpp',
 	'android_native_app_glue.c',
 	'java_glue.cpp'
 ]

+ 221 - 0
platform/android/ifaddrs_android.cpp

@@ -0,0 +1,221 @@
+/*
+ * libjingle
+ * Copyright 2012, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ifaddrs_android.h"
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+struct netlinkrequest {
+	nlmsghdr header;
+	ifaddrmsg msg;
+};
+namespace {
+const int kMaxReadSize = 4096;
+};
+static int set_ifname(struct ifaddrs* ifaddr, int interface) {
+	char buf[IFNAMSIZ] = {0};
+	char* name = if_indextoname(interface, buf);
+	if (name == NULL) {
+		return -1;
+	}
+	ifaddr->ifa_name = new char[strlen(name) + 1];
+	strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
+	return 0;
+}
+static int set_flags(struct ifaddrs* ifaddr) {
+	int fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd == -1) {
+		return -1;
+	}
+	ifreq ifr;
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
+	int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
+	close(fd);
+	if (rc == -1) {
+		return -1;
+	}
+	ifaddr->ifa_flags = ifr.ifr_flags;
+	return 0;
+}
+static int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
+		  size_t len) {
+	if (msg->ifa_family == AF_INET) {
+		sockaddr_in* sa = new sockaddr_in;
+		sa->sin_family = AF_INET;
+		memcpy(&sa->sin_addr, data, len);
+		ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+	} else if (msg->ifa_family == AF_INET6) {
+		sockaddr_in6* sa = new sockaddr_in6;
+		sa->sin6_family = AF_INET6;
+		sa->sin6_scope_id = msg->ifa_index;
+		memcpy(&sa->sin6_addr, data, len);
+		ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+	} else {
+		return -1;
+	}
+	return 0;
+}
+static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
+	char* prefix = NULL;
+	if (family == AF_INET) {
+		sockaddr_in* mask = new sockaddr_in;
+		mask->sin_family = AF_INET;
+		memset(&mask->sin_addr, 0, sizeof(in_addr));
+		ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+		if (prefixlen > 32) {
+			prefixlen = 32;
+		}
+		prefix = reinterpret_cast<char*>(&mask->sin_addr);
+	} else if (family == AF_INET6) {
+		sockaddr_in6* mask = new sockaddr_in6;
+		mask->sin6_family = AF_INET6;
+		memset(&mask->sin6_addr, 0, sizeof(in6_addr));
+		ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+		if (prefixlen > 128) {
+			prefixlen = 128;
+		}
+		prefix = reinterpret_cast<char*>(&mask->sin6_addr);
+	} else {
+		return -1;
+	}
+	for (int i = 0; i < (prefixlen / 8); i++) {
+		*prefix++ = 0xFF;
+	}
+	char remainder = 0xff;
+	remainder <<= (8 - prefixlen % 8);
+	*prefix = remainder;
+	return 0;
+}
+static int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
+		     size_t len) {
+	if (set_ifname(ifaddr, msg->ifa_index) != 0) {
+		return -1;
+	}
+	if (set_flags(ifaddr) != 0) {
+		return -1;
+	}
+	if (set_addresses(ifaddr, msg, bytes, len) != 0) {
+		return -1;
+	}
+	if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
+		return -1;
+	}
+	return 0;
+}
+int getifaddrs(struct ifaddrs** result) {
+	int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (fd < 0) {
+		return -1;
+	}
+	netlinkrequest ifaddr_request;
+	memset(&ifaddr_request, 0, sizeof(ifaddr_request));
+	ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
+	ifaddr_request.header.nlmsg_type = RTM_GETADDR;
+	ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
+	ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
+	if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
+		close(fd);
+		return -1;
+	}
+	struct ifaddrs* start = NULL;
+	struct ifaddrs* current = NULL;
+	char buf[kMaxReadSize];
+	ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
+	while (amount_read > 0) {
+		nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
+		size_t header_size = static_cast<size_t>(amount_read);
+		for ( ; NLMSG_OK(header, header_size);
+		      header = NLMSG_NEXT(header, header_size)) {
+			switch (header->nlmsg_type) {
+			case NLMSG_DONE:
+				// Success. Return.
+				*result = start;
+				close(fd);
+				return 0;
+			case NLMSG_ERROR:
+				close(fd);
+				freeifaddrs(start);
+				return -1;
+			case RTM_NEWADDR: {
+				ifaddrmsg* address_msg =
+						reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
+				rtattr* rta = IFA_RTA(address_msg);
+				ssize_t payload_len = IFA_PAYLOAD(header);
+				while (RTA_OK(rta, payload_len)) {
+					if (rta->rta_type == IFA_ADDRESS) {
+						int family = address_msg->ifa_family;
+						if (family == AF_INET || family == AF_INET6) {
+							ifaddrs* newest = new ifaddrs;
+							memset(newest, 0, sizeof(ifaddrs));
+							if (current) {
+								current->ifa_next = newest;
+							} else {
+								start = newest;
+							}
+							if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
+									     RTA_PAYLOAD(rta)) != 0) {
+								freeifaddrs(start);
+								*result = NULL;
+								return -1;
+							}
+							current = newest;
+						}
+					}
+					rta = RTA_NEXT(rta, payload_len);
+				}
+				break;
+			}
+			}
+		}
+		amount_read = recv(fd, &buf, kMaxReadSize, 0);
+	}
+	close(fd);
+	freeifaddrs(start);
+	return -1;
+}
+void freeifaddrs(struct ifaddrs* addrs) {
+	struct ifaddrs* last = NULL;
+	struct ifaddrs* cursor = addrs;
+	while (cursor) {
+		delete[] cursor->ifa_name;
+		delete cursor->ifa_addr;
+		delete cursor->ifa_netmask;
+		last = cursor;
+		cursor = cursor->ifa_next;
+		delete last;
+	}
+}

+ 46 - 0
platform/android/ifaddrs_android.h

@@ -0,0 +1,46 @@
+/*
+ * libjingle
+ * Copyright 2013, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TALK_BASE_IFADDRS_ANDROID_H_
+#define TALK_BASE_IFADDRS_ANDROID_H_
+#include <stdio.h>
+#include <sys/socket.h>
+// Implementation of getifaddrs for Android.
+// Fills out a list of ifaddr structs (see below) which contain information
+// about every network interface available on the host.
+// See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function).
+struct ifaddrs {
+	struct ifaddrs* ifa_next;
+	char* ifa_name;
+	unsigned int ifa_flags;
+	struct sockaddr* ifa_addr;
+	struct sockaddr* ifa_netmask;
+	// Real ifaddrs has broadcast, point to point and data members.
+	// We don't need them (yet?).
+};
+int getifaddrs(struct ifaddrs** result);
+void freeifaddrs(struct ifaddrs* addrs);
+#endif  // TALK_BASE_IFADDRS_ANDROID_H_

+ 33 - 0
platform/android/java/src/com/android/godot/Godot.java

@@ -65,6 +65,9 @@ import java.io.InputStream;
 
 public class Godot extends Activity implements SensorEventListener
 {	
+
+	static final int MAX_SINGLETONS = 64;
+
 	static public class SingletonBase {
 
 		protected void registerClass(String p_name, String[] p_methods) {
@@ -104,8 +107,21 @@ public class Godot extends Activity implements SensorEventListener
 
 
 			}
+
+			Godot.singletons[Godot.singleton_count++]=this;
+		}
+
+		protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
+
+
+		}
+
+		protected void onMainResume() {
+
+
 		}
 
+
 		public void registerMethods() {}
 	}
 
@@ -133,6 +149,12 @@ public class Godot extends Activity implements SensorEventListener
 		//setTitle(title);
 	}
 
+
+	static SingletonBase singletons[] = new SingletonBase[MAX_SINGLETONS];
+	static int singleton_count=0;
+
+
+
 	public interface ResultCallback {
 		public void callback(int requestCode, int resultCode, Intent data);
 	};
@@ -147,6 +169,11 @@ public class Godot extends Activity implements SensorEventListener
 			result_callback.callback(requestCode, resultCode, data);
 			result_callback = null;
 		};
+
+		for(int i=0;i<singleton_count;i++) {
+
+			singletons[i].onMainActivityResult(requestCode,resultCode,data);
+		}
 	};
 
 	public void onVideoInit(boolean use_gl2) {
@@ -271,6 +298,12 @@ public class Godot extends Activity implements SensorEventListener
 		mView.onResume();
 		mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
 		GodotLib.focusin();
+
+		for(int i=0;i<singleton_count;i++) {
+
+			singletons[i].onMainResume();
+		}
+
 	}
 
 	@Override public void onSensorChanged(SensorEvent event) {

+ 30 - 7
platform/android/java/src/com/android/godot/GodotPaymentV3.java

@@ -1,7 +1,10 @@
 package com.android.godot;
 
 
+import org.json.JSONObject;
+
 import android.app.Activity;
+import android.util.Log;
 
 
 public class GodotPaymentV3 extends Godot.SingletonBase {
@@ -13,14 +16,17 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
 	private String accessToken;
 	
 	private String purchaseValidationUrlPrefix;
+	
+	private String transactionId;
 
-	public void purchase( String _sku) {
+	public void purchase( String _sku, String _transactionId) {
 		final String sku = _sku;
+		final String transactionId = _transactionId;
 		activity.getPaymentsManager().setBaseSingleton(this);
 		activity.runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
-				activity.getPaymentsManager().requestPurchase(sku);				
+				activity.getPaymentsManager().requestPurchase(sku, transactionId);				
 			}
 		});
 	};
@@ -38,22 +44,31 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
 	
 	public GodotPaymentV3(Activity p_activity) {
 
-		registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix"});
+		registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature"});
 		activity=(Godot) p_activity;
 	}
 
 
+	private String signature;
+	public String getSignature(){
+	        return this.signature;
+	}
+	
 	
-	public void callbackSuccess(String ticket){
-        GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket});
+	public void callbackSuccess(String ticket, String signature){
+	        Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
+            GodotLib.calldeferred(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature});
+        	Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
 	}
 	
 	public void callbackFail(){
-        GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
+                GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
+//                GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
 	}
 	
 	public void callbackCancel(){
-		GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
+		GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{});
+//		GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
 	}
 	
 	public int getPurchaseCallbackId() {
@@ -84,4 +99,12 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
 		this.accessToken = accessToken;
 	}
 	
+	public void setTransactionId(String transactionId){
+		this.transactionId = transactionId;
+	}
+	
+	public String getTransactionId(){
+		return this.transactionId;
+	}
+	
 }

+ 1 - 2
platform/android/java/src/com/android/godot/payments/ConsumeTask.java

@@ -56,8 +56,7 @@ abstract public class ConsumeTask {
 			
 			protected void onPostExecute(String param){
 				if(param == null){
-					
-					success(new PaymentsCache(context).getConsumableValue("ticket", sku));
+					success( new PaymentsCache(context).getConsumableValue("ticket", sku) );
 				}else{
 					error(param);
 				}

+ 6 - 4
platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java

@@ -34,7 +34,8 @@ abstract public class HandlePurchaseTask {
 		
 		String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
 		Log.d("XXX", "Purchase data:" + purchaseData);
-//		String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
+		String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
+		Log.d("XXX", "Purchase signature:" + dataSignature);
 		
 		if (resultCode == Activity.RESULT_OK) {
 			
@@ -57,12 +58,13 @@ abstract public class HandlePurchaseTask {
 					error("Untrusted callback");
 					return;
 				}
-				
+				Log.d("XXX", "Este es el product ID:" + productId);
+				pc.setConsumableValue("ticket_signautre", productId, dataSignature);
 				pc.setConsumableValue("ticket", productId, purchaseData);
 				pc.setConsumableFlag("block", productId, true);
 				pc.setConsumableValue("token", productId, purchaseToken);
 				
-				success(productId);
+				success(productId, dataSignature);
 				return;
 			}	catch (JSONException e) {
 				error(e.getMessage());
@@ -72,7 +74,7 @@ abstract public class HandlePurchaseTask {
 		}
 	}
 
-	abstract protected void success(String ticket);
+	abstract protected void success(String ticket, String signature);
 	abstract protected void error(String message);
 	abstract protected void canceled();
 

+ 3 - 0
platform/android/java/src/com/android/godot/payments/PaymentsCache.java

@@ -2,6 +2,7 @@ package com.android.godot.payments;
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.util.Log;
 
 public class PaymentsCache {
 	
@@ -30,12 +31,14 @@ public class PaymentsCache {
 		SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); 
 	    SharedPreferences.Editor editor = sharedPref.edit();
 	    editor.putString(sku, value);
+	    Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
 	    editor.commit();
 	}
 
 	public String getConsumableValue(String set, String sku){
 	    SharedPreferences sharedPref = context.getSharedPreferences(
 	    		"consumables_" + set, Context.MODE_PRIVATE);
+	    Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
 	    return sharedPref.getString(sku, null);
 	}
 

+ 7 - 5
platform/android/java/src/com/android/godot/payments/PaymentsManager.java

@@ -6,6 +6,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.IBinder;
+import android.util.Log;
 
 import com.android.godot.Godot;
 import com.android.godot.GodotPaymentV3;
@@ -63,7 +64,7 @@ public class PaymentsManager {
 	    }
 	};
 	
-	public void requestPurchase(String sku){
+	public void requestPurchase(String sku, String transactionId){
 		new PurchaseTask(mService, Godot.getInstance()) {
 			
 			@Override
@@ -76,7 +77,7 @@ public class PaymentsManager {
 			protected void canceled() {
 				godotPaymentV3.callbackCancel();
 			}
-		}.purchase(sku);
+		}.purchase(sku, transactionId);
 
 	}
 
@@ -84,13 +85,14 @@ public class PaymentsManager {
 		new HandlePurchaseTask(activity){
 
 			@Override
-			protected void success(final String sku) {
+			protected void success(final String sku, final String signature) {
 				new ConsumeTask(mService, activity) {
 					
 					@Override
 					protected void success(String ticket) {
 //						godotPaymentV3.callbackSuccess("");
-						godotPaymentV3.callbackSuccess(ticket);
+						Log.d("XXX", "calling success:" + signature);
+						godotPaymentV3.callbackSuccess(ticket, signature);
 					}
 					
 					@Override
@@ -131,7 +133,7 @@ public class PaymentsManager {
 					
 					@Override
 					protected void success(String ticket) {
-						godotPaymentV3.callbackSuccess(ticket);
+						godotPaymentV3.callbackSuccess(ticket, null);
 						
 					}
 					

+ 3 - 3
platform/android/java/src/com/android/godot/payments/PurchaseTask.java

@@ -31,7 +31,7 @@ abstract public class PurchaseTask {
 
 	private boolean isLooping = false;
 	
-	public void purchase(final String sku){
+	public void purchase(final String sku, final String transactionId){
 		Log.d("XXX", "Starting purchase for: " + sku);
 		PaymentsCache pc = new PaymentsCache(context);
 		Boolean isBlocked = pc.getConsumableFlag("block", sku);
@@ -40,7 +40,7 @@ abstract public class PurchaseTask {
 //			error("Awaiting payment confirmation");
 //			return;
 //		}
-		final String hash = Crypt.createRandomHash() + Crypt.createRandomHash();
+		final String hash = transactionId;
 
 		Bundle buyIntentBundle;
 		try {
@@ -76,7 +76,7 @@ abstract public class PurchaseTask {
 						return;
 					}
 					isLooping=true;
-					PurchaseTask.this.purchase(sku);
+					PurchaseTask.this.purchase(sku, transactionId);
 					
 				}
 				

+ 1 - 1
platform/android/sign.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 
-jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore /home/luis/Downloads/carnavalguachin.keystore -storepass 12345678 "$1" momoselacome
+jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore my-release-key.keystore "$1" reduz
 
 echo ""
 echo ""

+ 4 - 2
platform/iphone/detect.py

@@ -21,7 +21,8 @@ def get_opts():
 	return [
 		('IPHONEPLATFORM', 'name of the iphone platform', 'iPhoneOS'),
 		('IPHONEPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
-		('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/'),
+		('IOS_SDK_VERSION', 'The SDK version', 'iPhoneOS7.0'),
+		('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/${IOS_SDK_VERSION}.sdk/'),
 		('game_center', 'Support for game center', 'yes'),
 		('store_kit', 'Support for in-app store', 'yes'),
 		('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
@@ -37,6 +38,7 @@ def get_flags():
 		('tools', 'yes'),
 		('nedmalloc', 'no'),
 		('webp', 'yes'),
+		('openssl','builtin'), #use builtin openssl
 	]
 
 
@@ -81,7 +83,7 @@ def configure(env):
 							'-framework', 'AudioToolbox',
 							'-framework', 'SystemConfiguration',
 							'-framework', 'Security',
-							'-framework', 'AdSupport',
+							#'-framework', 'AdSupport',
 							'-framework', 'MediaPlayer',
 							])
 

+ 10 - 3
platform/iphone/gl_view.mm

@@ -50,6 +50,7 @@ static String keyboard_text;
 static GLView* _instance = NULL;
 
 static bool video_found_error = false;
+static bool video_playing = false;
 static float video_previous_volume = 0.0f;
 
 void _show_keyboard(String p_existing) {
@@ -91,24 +92,29 @@ bool _play_video(String p_path, float p_volume) {
 	[_instance addSubview:_instance.moviePlayerController.view];
 	[_instance.moviePlayerController play];
 
+	video_playing = true;
+
 	return true;
 }
 
 bool _is_video_playing() {
 	//NSInteger playback_state = _instance.moviePlayerController.playbackState;
-	if (video_found_error)
-		return false;
-	return (_instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying);
+	return video_playing || _instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying;
+	//if (video_found_error)
+	//	return false;
+	//return (_instance.moviePlayerController.playbackState == MPMoviePlaybackStatePlaying);
 }
 
 void _pause_video() {
 	[_instance.moviePlayerController pause];
+	video_playing = false;
 }
 
 void _stop_video() {
 	[_instance.moviePlayerController stop];
 	[_instance.moviePlayerController.view removeFromSuperview];
 	[[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
+	video_playing = false;
 }
 
 @implementation GLView
@@ -549,6 +555,7 @@ static void clear_touches() {
     [_instance.moviePlayerController.view removeFromSuperview];
 
     [[MPMusicPlayerController applicationMusicPlayer] setVolume: video_previous_volume];
+	video_playing = false;
 }
 
 @end

+ 2 - 2
platform/windows/detect.py

@@ -117,7 +117,7 @@ def configure(env):
 		env.Append(CCFLAGS=['/DGLES2_ENABLED'])
 		env.Append(CCFLAGS=['/DGLES1_ENABLED'])
 		env.Append(CCFLAGS=['/DGLEW_ENABLED'])
-		env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32','wsock32', 'shell32','advapi32'])
+		env.Append(LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI', 'wsock32', 'shell32','advapi32'])
 		
 		env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
                 if (os.getenv("DXSDK_DIR")):
@@ -196,7 +196,7 @@ def configure(env):
 		env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
 		env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
 		env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLES1_ENABLED','-DGLEW_ENABLED'])
-		env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','wsock32','kernel32'])
+		env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','wsock32','kernel32'])
 		#'d3dx9d'
 		env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
 		env.Append(LINKFLAGS=['-g'])

+ 16 - 20
platform/x11/os_x11.cpp

@@ -480,7 +480,7 @@ unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
 	return state;
 }
 	
-void OS_X11::handle_key_event(XKeyEvent *p_event) {
+void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
 
 			
 	// X11 functions don't know what const is
@@ -591,17 +591,9 @@ void OS_X11::handle_key_event(XKeyEvent *p_event) {
 	// To detect them, i use XPeekEvent and check that their
 	// difference in time is below a treshold.
 	
-	bool echo=false;
-	
-	if (xkeyevent->type == KeyPress) {
-			
-		// saved the time of the last keyrelease to see
-		// if it's the same as this keypress.
-		if (xkeyevent->time==last_keyrelease_time)
-			echo=true;
 
-	} else {
-	
+	if (xkeyevent->type != KeyPress) {
+				
 		// make sure there are events pending,
 		// so this call won't block.
 		if (XPending(x11_display)>0) {
@@ -615,17 +607,21 @@ void OS_X11::handle_key_event(XKeyEvent *p_event) {
 			// not very helpful today.
 			
 			::Time tresh=ABS(peek_event.xkey.time-xkeyevent->time);
-			if (peek_event.type == KeyPress && tresh<5 )
-				echo=true;
+			if (peek_event.type == KeyPress && tresh<5 ) {
+				KeySym rk;
+				nbytes=XLookupString((XKeyEvent*)&peek_event, str, 256, &rk, NULL);
+				if (rk==keysym_keycode) {
+					XEvent event;
+					XNextEvent(x11_display, &event); //erase next event
+					handle_key_event( (XKeyEvent*)&event,true );
+					return; //ignore current, echo next
+				}
+			}
 				
 			// use the time from peek_event so it always works
-			last_keyrelease_time=peek_event.xkey.time;
-		} else {
-			last_keyrelease_time=xkeyevent->time;
 		}
 	
-		// save the time to check for echo when keypress happens
-		
+		// save the time to check for echo when keypress happens		
 	}
 	
 	
@@ -643,7 +639,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event) {
 
 	event.key.scancode=keycode;
 	event.key.unicode=unicode;
-	event.key.echo=echo;
+	event.key.echo=p_echo;
 
 	if (event.key.scancode==KEY_BACKTAB) {
 		//make it consistent accross platforms.
@@ -1017,7 +1013,7 @@ String OS_X11::get_name() {
 
 Error OS_X11::shell_open(String p_uri) {
 
-
+	return ERR_UNAVAILABLE;
 }
 
 

+ 1 - 1
platform/x11/os_x11.h

@@ -90,7 +90,7 @@ class OS_X11 : public OS_Unix {
 	MouseMode mouse_mode;
 	Point2i center;
 	
-	void handle_key_event(XKeyEvent *p_event);
+	void handle_key_event(XKeyEvent *p_event,bool p_echo=false);
 	void process_xevents();
 	virtual void delete_main_loop();
 	IP_Unix *ip_unix;

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

@@ -447,7 +447,7 @@ float CanvasItem::get_self_opacity() const {
 
 void CanvasItem::set_blend_mode(BlendMode p_blend_mode) {
 
-	ERR_FAIL_INDEX(p_blend_mode,4);
+	ERR_FAIL_INDEX(p_blend_mode,5);
 	blend_mode=p_blend_mode;
 	VisualServer::get_singleton()->canvas_item_set_blend_mode(canvas_item,VS::MaterialBlendMode(blend_mode));
 
@@ -794,7 +794,7 @@ void CanvasItem::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility
 
-	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
+	ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
 	//exporting these two things doesn't really make much sense i think
 	//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") );
 	//ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled"));
@@ -810,6 +810,7 @@ void CanvasItem::_bind_methods() {
 	BIND_CONSTANT( BLEND_MODE_ADD );
 	BIND_CONSTANT( BLEND_MODE_SUB );
 	BIND_CONSTANT( BLEND_MODE_MUL );
+	BIND_CONSTANT( BLEND_MODE_PREMULT_ALPHA );
 
 
 	BIND_CONSTANT( NOTIFICATION_DRAW);

+ 2 - 1
scene/2d/canvas_item.h

@@ -49,7 +49,8 @@ public:
 		BLEND_MODE_MIX, //default
 		BLEND_MODE_ADD,
 		BLEND_MODE_SUB,
-		BLEND_MODE_MUL
+		BLEND_MODE_MUL,
+		BLEND_MODE_PREMULT_ALPHA
 	};
 
 private:

+ 3 - 1
scene/resources/material.cpp

@@ -158,7 +158,7 @@ void Material::_bind_methods() {
 	for(int i=0;i<HINT_MAX;i++)
 		ADD_PROPERTYI( PropertyInfo( Variant::BOOL, String()+"hints/"+_hint_names[i] ),_SCS("set_hint"),_SCS("get_hint"),_hint_indices[i]);
 
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "params/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub" ), _SCS("set_blend_mode"),_SCS("get_blend_mode"));
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "params/blend_mode",PROPERTY_HINT_ENUM,"Mix,Add,Sub,PMAlpha" ), _SCS("set_blend_mode"),_SCS("get_blend_mode"));
 	ADD_PROPERTY( PropertyInfo( Variant::REAL, "params/line_width",PROPERTY_HINT_RANGE,"0.1,32.0,0.1" ), _SCS("set_line_width"),_SCS("get_line_width"));
 
 
@@ -189,6 +189,8 @@ void Material::_bind_methods() {
 	BIND_CONSTANT( BLEND_MODE_MIX );
 	BIND_CONSTANT( BLEND_MODE_ADD );
 	BIND_CONSTANT( BLEND_MODE_SUB );
+	BIND_CONSTANT( BLEND_MODE_MUL );
+	BIND_CONSTANT( BLEND_MODE_PREMULT_ALPHA );
 
 }
 

+ 1 - 0
scene/resources/material.h

@@ -75,6 +75,7 @@ public:
 		BLEND_MODE_MUL = VS::MATERIAL_BLEND_MODE_MUL,
 		BLEND_MODE_ADD = VS::MATERIAL_BLEND_MODE_ADD,
 		BLEND_MODE_SUB = VS::MATERIAL_BLEND_MODE_SUB,
+		BLEND_MODE_PREMULT_ALPHA = VS::MATERIAL_BLEND_MODE_PREMULT_ALPHA,
 
 	};
 

+ 12 - 0
scene/resources/texture.cpp

@@ -302,6 +302,16 @@ void ImageTexture::fix_alpha_edges() {
 	}
 }
 
+void ImageTexture::premultiply_alpha() {
+
+	if (format==Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) {
+
+		Image img = get_data();
+		img.premultiply_alpha();
+		set_data(img);
+	}
+}
+
 bool ImageTexture::has_alpha() const {
 
 	return ( format==Image::FORMAT_GRAYSCALE_ALPHA || format==Image::FORMAT_INDEXED_ALPHA || format==Image::FORMAT_RGBA );
@@ -386,8 +396,10 @@ void ImageTexture::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality","quality"),&ImageTexture::set_lossy_storage_quality);
 	ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"),&ImageTexture::get_lossy_storage_quality);
 	ObjectTypeDB::bind_method(_MD("fix_alpha_edges"),&ImageTexture::fix_alpha_edges);
+	ObjectTypeDB::bind_method(_MD("premultiply_alpha"),&ImageTexture::premultiply_alpha);
 	ObjectTypeDB::bind_method(_MD("set_size_override","size"),&ImageTexture::set_size_override);
 	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("fix_alpha_edges"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("premultiply_alpha"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
 	ObjectTypeDB::bind_method(_MD("_reload_hook","rid"),&ImageTexture::_reload_hook);
 
 

+ 1 - 0
scene/resources/texture.h

@@ -143,6 +143,7 @@ public:
 	float get_lossy_storage_quality() const;
 
 	void fix_alpha_edges();
+	void premultiply_alpha();
 
 	void set_size_override(const Size2& p_size);
 

+ 2 - 1
servers/visual_server.h

@@ -199,7 +199,8 @@ public:
 		MATERIAL_BLEND_MODE_MIX, //default
 		MATERIAL_BLEND_MODE_ADD,
 		MATERIAL_BLEND_MODE_SUB,
-		MATERIAL_BLEND_MODE_MUL
+		MATERIAL_BLEND_MODE_MUL,
+		MATERIAL_BLEND_MODE_PREMULT_ALPHA
 	};
 
 

+ 12 - 0
tools/editor/io_plugins/editor_texture_import_plugin.cpp

@@ -44,6 +44,7 @@ static const char *flag_names[]={
 	"No MipMaps",
 	"Repeat",
 	"Filter (Magnifying)",
+	"Premultiply Alpha",
 	NULL
 };
 
@@ -55,6 +56,7 @@ static const char *flag_short_names[]={
 	"NoMipMap",
 	"Repeat",
 	"Filter",
+	"PMAlpha",
 	NULL
 };
 
@@ -919,6 +921,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 			image.fix_alpha_edges();
 		}
 
+		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+			image.premultiply_alpha();
+		}
+
 
 		if (shrink>1) {
 
@@ -972,6 +979,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 			image.fix_alpha_edges();
 		}
 
+		if (image.get_format()==Image::FORMAT_RGBA && flags&IMAGE_FLAG_PREMULT_ALPHA) {
+
+			image.premultiply_alpha();
+		}
+
 		int orig_w=image.get_width();
 		int orig_h=image.get_height();
 

+ 2 - 1
tools/editor/io_plugins/editor_texture_import_plugin.h

@@ -91,7 +91,8 @@ public:
 		IMAGE_FLAG_COMPRESS_EXTRA=8, // used for pvrtc2
 		IMAGE_FLAG_NO_MIPMAPS=16, //normal for 2D games
 		IMAGE_FLAG_REPEAT=32, //usually disabled in 2D
-		IMAGE_FLAG_FILTER=64 //almost always enabled
+		IMAGE_FLAG_FILTER=64, //almost always enabled
+		IMAGE_FLAG_PREMULT_ALPHA=128//almost always enabled
 	};
 
 	virtual String get_name() const;

+ 161 - 32
tools/editor/plugins/baked_light_editor_plugin.cpp

@@ -134,6 +134,8 @@ public:
 
 
 	void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
+	void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
+
 	void _throw_ray(const Vector3& p_from, const Vector3& p_to,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces);
 
 
@@ -165,7 +167,7 @@ public:
 	}
 
 	BakedLightBaker() {
-		octree_depth=8;
+		octree_depth=6;
 		octree=NULL;
 		bvh=NULL;
 		leaf_list=NULL;
@@ -408,7 +410,7 @@ void BakedLightBaker::_make_bvh() {
 void BakedLightBaker::_octree_insert(const AABB& p_aabb,Octant *p_octant,Triangle* p_triangle, int p_depth) {
 
 	if (p_octant->leaf) {
-
+#if 0
 		if (p_aabb.has_point(p_triangle->vertices[0]) && p_aabb.has_point(p_triangle->vertices[1]) &&p_aabb.has_point(p_triangle->vertices[2])) {
 			//face is completely enclosed, add area
 			p_octant->surface_area+=Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area();
@@ -433,12 +435,18 @@ void BakedLightBaker::_octree_insert(const AABB& p_aabb,Octant *p_octant,Triangl
 				p.d=-p_aabb.pos[i];
 				poly=Geometry::clip_polygon(poly,p);
 			}
+
+
 			//calculate area
+			float clipped_area=0;
 			for(int i=2;i<poly.size();i++) {
-				p_octant->surface_area+=Face3(poly[0],poly[i-1],poly[i]).get_area();
+				clipped_area+=Face3(poly[0],poly[i-1],poly[i]).get_area();
 			}
-		}
 
+			print_line(itos(poly.size())+" Base: "+rtos(Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).get_area())+" clipped: "+rtos(clipped_area));
+			p_octant->surface_area+=clipped_area;
+		}
+#endif
 	} else {
 
 
@@ -500,7 +508,7 @@ void BakedLightBaker::_make_octree() {
 	octree_aabb=base;
 
 	cell_size=base.size.x;
-	for(int i=0;i<=octree_depth;i++)
+	for(int i=0;i<octree_depth;i++)
 		cell_size/=2.0;
 
 	octree = memnew( Octant );
@@ -526,7 +534,7 @@ void BakedLightBaker::_plot_light(const Vector3& p_plot_pos,const AABB& p_plot_a
 		float d = p_plot_pos.distance_to(center);
 		if (d>r)
 			return; //oh crap! outside radius
-		float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
+		float intensity = 1.0;// - (d/r)*(d/r); //not gauss but..
 		p_octant->light_accum[0]+=p_light.r*intensity;
 		p_octant->light_accum[1]+=p_light.g*intensity;
 		p_octant->light_accum[2]+=p_light.b*intensity;
@@ -558,6 +566,42 @@ void BakedLightBaker::_plot_light(const Vector3& p_plot_pos,const AABB& p_plot_a
 	}
 }
 
+void BakedLightBaker::_plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light) {
+
+
+	if (p_octant->leaf) {
+
+		p_octant->light_accum[0]+=p_light.r;
+		p_octant->light_accum[1]+=p_light.g;
+		p_octant->light_accum[2]+=p_light.b;
+
+	} else {
+
+		for(int i=0;i<8;i++) {
+
+			if (!p_octant->children[i])
+				continue;
+
+			AABB aabb=p_aabb;
+			aabb.size*=0.5;
+			if (i&1)
+				aabb.pos.x+=aabb.size.x;
+			if (i&2)
+				aabb.pos.y+=aabb.size.y;
+			if (i&4)
+				aabb.pos.z+=aabb.size.z;
+
+
+			if (!aabb.has_point(p_plot_pos))
+				continue;
+
+			_plot_light_point(p_plot_pos,p_octant->children[i],aabb,p_light);
+
+		}
+
+	}
+}
+
 
 void BakedLightBaker::_throw_ray(const Vector3& p_begin, const Vector3& p_end,const Color& p_light,float *p_att_curve,float p_att_curve_len,int p_bounces) {
 
@@ -692,6 +736,7 @@ void BakedLightBaker::_throw_ray(const Vector3& p_begin, const Vector3& p_end,co
 		aabb.size=Vector3(2,2,2)*cell_size*plot_size;
 
 		_plot_light(r_point,aabb,octree,octree_aabb,p_light);
+//		_plot_light_point(r_point,octree,octree_aabb,p_light);
 
 	}
 
@@ -772,9 +817,21 @@ void BakedLightBaker::bake(Node* p_node) {
 
 
 
+void BakedLightEditor::_end_baking() {
+
+	if (!bake_thread)
+		return;
+
+	bake_thread_exit=true;
+	Thread::wait_to_finish(bake_thread);
+	bake_thread=NULL;
+	bake_thread_exit=false;
+}
+
 void BakedLightEditor::_node_removed(Node *p_node) {
 
 	if(p_node==node) {
+		_end_baking();
 		node=NULL;
 		p_node->remove_child(preview);
 		preview->set_mesh(Ref<Mesh>());
@@ -784,6 +841,79 @@ void BakedLightEditor::_node_removed(Node *p_node) {
 }
 
 
+void BakedLightEditor::_bake_thread_func(void *arg) {
+
+	BakedLightEditor *ble = (BakedLightEditor*)arg;
+
+	while(!ble->bake_thread_exit) {
+
+		ble->baker->throw_rays(1000);
+	}
+
+}
+
+
+
+void BakedLightEditor::_notification(int p_option) {
+
+
+	if (p_option==NOTIFICATION_PROCESS) {
+
+		if (bake_thread) {
+
+			update_timeout-=get_process_delta_time();
+			if (update_timeout<0) {
+
+
+
+				float norm =  baker->get_normalization();
+				float max_lum=0;
+				{
+					DVector<Color>::Write cw=colors.write();
+					BakedLightBaker::Octant *oct = baker->leaf_list;
+					int vert_idx=0;
+
+					while(oct) {
+
+						Color color;
+
+
+						color.r=oct->light_accum[0]/norm;
+						color.g=oct->light_accum[1]/norm;
+						color.b=oct->light_accum[2]/norm;
+						float lum = color.get_v();
+						//if (lum<0.05)
+						//	color.a=0;
+						if (lum>max_lum)
+							max_lum=lum;
+
+						for (int i=0;i<36;i++) {
+
+
+							cw[vert_idx++]=color;
+						}
+
+						oct=oct->next_leaf;
+
+					}
+				}
+
+
+				Array a;
+				a.resize(Mesh::ARRAY_MAX);
+				a[Mesh::ARRAY_VERTEX]=vertices;
+				a[Mesh::ARRAY_COLOR]=colors;
+				while(mesh->get_surface_count())
+					mesh->surface_remove(0);
+				mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
+				mesh->surface_set_material(0,material);
+
+				update_timeout=1;
+			}
+		}
+	}
+}
+
 
 void BakedLightEditor::_menu_option(int p_option) {
 
@@ -797,13 +927,9 @@ void BakedLightEditor::_menu_option(int p_option) {
 			preview->set_mesh(Ref<Mesh>());
 			baker->base_inv=node->get_global_transform().affine_inverse();
 			baker->bake(node);
-			baker->throw_rays(100000);
-			float norm =  baker->get_normalization();
-			float max_lum=0;
 
 			print_line("CELLS: "+itos(baker->cell_count));
-			DVector<Color> colors;
-			DVector<Vector3> vertices;
+			print_line("cell size: "+rtos(baker->cell_size));
 			colors.resize(baker->cell_count*36);
 			vertices.resize(baker->cell_count*36);
 
@@ -817,12 +943,6 @@ void BakedLightEditor::_menu_option(int p_option) {
 				while(oct) {
 
 					Color color;
-					color.r=oct->light_accum[0]/norm;
-					color.g=oct->light_accum[1]/norm;
-					color.b=oct->light_accum[2]/norm;
-					float lum = color.get_v();
-					if (lum>max_lum)
-						max_lum=lum;
 
 					for (int i=0;i<6;i++) {
 
@@ -845,7 +965,7 @@ void BakedLightEditor::_menu_option(int p_option) {
 						}
 
 						for(int j=0;j<4;j++) {
-							face_points[j]*=baker->cell_size;
+							face_points[j]*=baker->cell_size*0.5;
 							face_points[j]+=Vector3(oct->offset[0],oct->offset[1],oct->offset[2]);
 						}
 
@@ -873,25 +993,20 @@ void BakedLightEditor::_menu_option(int p_option) {
 
 			}
 
-			print_line("max lum: "+rtos(max_lum));
 			Array a;
 			a.resize(Mesh::ARRAY_MAX);
 			a[Mesh::ARRAY_VERTEX]=vertices;
 			a[Mesh::ARRAY_COLOR]=colors;
+			while(mesh->get_surface_count())
+				mesh->surface_remove(0);
+			mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
+			mesh->surface_set_material(0,material);
 
-			Ref<FixedMaterial> matcol = memnew( FixedMaterial );
-			matcol->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
-			matcol->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
-			matcol->set_flag(FixedMaterial::FLAG_UNSHADED,true);
-			matcol->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true);
-			matcol->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
-			Ref<Mesh> m = memnew( Mesh );
-			m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
-			m->surface_set_material(0,matcol);
-			preview->set_mesh(m);
-
-
-
+			bake_thread_exit=false;
+			update_timeout=0;
+			set_process(true);
+			bake_thread=Thread::create(_bake_thread_func,this);
+			preview->set_mesh(mesh);
 
 
 		} break;
@@ -914,6 +1029,7 @@ void BakedLightEditor::edit(BakedLight *p_baked_light) {
 	}
 
 	node=p_baked_light;
+	_end_baking();
 
 	if (node)
 		node->add_child(preview);
@@ -943,6 +1059,19 @@ BakedLightEditor::BakedLightEditor() {
 	node=NULL;
 	baker = memnew( BakedLightBaker );
 	preview = memnew( MeshInstance );
+	bake_thread=NULL;
+	update_timeout=0;
+
+	material = Ref<FixedMaterial> ( memnew( FixedMaterial ) );
+	material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
+	material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
+	material->set_flag(FixedMaterial::FLAG_UNSHADED,true);
+	material->set_flag(FixedMaterial::FLAG_DOUBLE_SIDED,true);
+	material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
+
+	mesh = Ref<Mesh>( memnew( Mesh ));
+
+
 }
 
 BakedLightEditor::~BakedLightEditor() {

+ 12 - 0
tools/editor/plugins/baked_light_editor_plugin.h

@@ -19,6 +19,15 @@ class BakedLightEditor : public Control {
 	OBJ_TYPE(BakedLightEditor, Control );
 
 
+	float update_timeout;
+	DVector<Color> colors;
+	DVector<Vector3> vertices;
+	Ref<Mesh> mesh;
+	Ref<FixedMaterial> material;
+
+	Thread *bake_thread;
+	bool bake_thread_exit;
+
 	MeshInstance *preview;
 	BakedLightBaker *baker;
 	AcceptDialog *err_dialog;
@@ -32,12 +41,15 @@ class BakedLightEditor : public Control {
 		MENU_OPTION_CLEAR
 	};
 
+	static void _bake_thread_func(void *arg);
+	void _end_baking();
 	void _menu_option(int);
 
 friend class BakedLightEditorPlugin;
 protected:
 	void _node_removed(Node *p_node);
 	static void _bind_methods();
+	void _notification(int p_what);
 public:
 
 	void edit(BakedLight *p_baked_light);

+ 15 - 0
tools/editor/plugins/canvas_item_editor_plugin.cpp

@@ -608,7 +608,14 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
 
 		if (b.button_index==BUTTON_WHEEL_DOWN) {
 
+			float prev_zoom=zoom;
 			zoom=zoom*0.95;
+			{
+				Point2 ofs(b.x,b.y);
+				ofs = ofs/prev_zoom - ofs/zoom;
+				h_scroll->set_val( h_scroll->get_val() + ofs.x );
+				v_scroll->set_val( v_scroll->get_val() + ofs.y );
+			}
 			_update_scroll(0);
 			viewport->update();
 			return;
@@ -616,7 +623,15 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
 
 		if (b.button_index==BUTTON_WHEEL_UP) {
 
+			float prev_zoom=zoom;
 			zoom=zoom*(1.0/0.95);
+			{
+				Point2 ofs(b.x,b.y);
+				ofs = ofs/prev_zoom - ofs/zoom;
+				h_scroll->set_val( h_scroll->get_val() + ofs.x );
+				v_scroll->set_val( v_scroll->get_val() + ofs.y );
+			}
+
 			_update_scroll(0);
 			viewport->update();
 			return;

+ 21 - 0
tools/editor/plugins/script_editor_plugin.cpp

@@ -687,6 +687,26 @@ void ScriptEditor::_menu_option(int p_option) {
 
 			current->get_text_edit()->query_code_comple();
 
+		} break;
+		case EDIT_AUTO_INDENT: {
+
+			TextEdit *te = current->get_text_edit();
+			String text = te->get_text();
+			Ref<Script> scr = current->get_edited_script();
+			if (scr.is_null())
+				return;
+			int begin,end;
+			if (te->is_selection_active()) {
+				begin=te->get_selection_from_line();
+				end=te->get_selection_to_line();
+			} else {
+				begin=0;
+				end=te->get_line_count()-1;
+			}
+			scr->get_language()->auto_indent_code(text,begin,end);
+			te->set_text(text);
+
+
 		} break;
 		case SEARCH_FIND: {
 
@@ -1321,6 +1341,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 	edit_menu->get_popup()->add_item("Select All",EDIT_SELECT_ALL,KEY_MASK_CMD|KEY_A);
 	edit_menu->get_popup()->add_separator();
 	edit_menu->get_popup()->add_item("Complete Symbol",EDIT_COMPLETE,KEY_MASK_CMD|KEY_SPACE);
+	edit_menu->get_popup()->add_item("Auto Indent",EDIT_AUTO_INDENT,KEY_MASK_CMD|KEY_I);
 	edit_menu->get_popup()->connect("item_pressed", this,"_menu_option");
 
 

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

@@ -122,6 +122,7 @@ class ScriptEditor : public VBoxContainer {
 		EDIT_PASTE,
 		EDIT_SELECT_ALL,
 		EDIT_COMPLETE,
+		EDIT_AUTO_INDENT,
 		SEARCH_FIND,
 		SEARCH_FIND_NEXT,
 		SEARCH_REPLACE,

+ 1 - 0
tools/editor/property_editor.cpp

@@ -1566,6 +1566,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
 		add_child(checks20[i]);
 		checks20[i]->hide();
 		checks20[i]->connect("pressed",this,"_action_pressed",make_binds(i));
+		checks20[i]->set_tooltip("Bit "+itos(i)+", val "+itos(1<<i)+".");
 	}
 
 	text_edit = memnew( TextEdit );