Przeglądaj źródła

Light Baker!
-=-=-=-=-=-=

-Support for lightmap baker, have fun figuring out how it works before tutorial is published.

Juan Linietsky 11 lat temu
rodzic
commit
9b8696d3dd
61 zmienionych plików z 4224 dodań i 1310 usunięć
  1. 1 0
      SConstruct
  2. 28 0
      core/SCsub
  3. 2 2
      core/bind/core_bind.cpp
  4. 6 3
      core/image.cpp
  5. 3 3
      core/image.h
  6. 7 2
      core/io/resource_format_xml.cpp
  7. 1 1
      core/io/resource_format_xml.h
  8. 0 9
      core/math/aabb.cpp
  9. 60 1
      core/math/aabb.h
  10. 1 1
      core/math/face3.cpp
  11. 169 0
      core/math/face3.h
  12. 18 2
      core/packed_data_container.cpp
  13. 2 0
      core/packed_data_container.h
  14. 0 2
      core/script_language.cpp
  15. 1 0
      core/script_language.h
  16. 99 14
      core/ustring.cpp
  17. 1 1
      core/variant_op.cpp
  18. 0 250
      demos/3d/platformer/stage2.xml
  19. BIN
      demos/3d/platformer/tiles.res
  20. 47 2
      drivers/gles2/rasterizer_gles2.cpp
  21. 88 1
      drivers/gles2/shaders/material.glsl
  22. 2 0
      drivers/unix/ip_unix.cpp
  23. 26 3
      modules/gdscript/gd_script.cpp
  24. 1 0
      modules/gdscript/gd_tokenizer.cpp
  25. 65 13
      modules/gdscript/register_types.cpp
  26. 139 1
      modules/gridmap/grid_map.cpp
  27. 13 0
      modules/gridmap/grid_map.h
  28. 1 1
      platform/javascript/detect.py
  29. 0 7
      scene/3d/baked_light.cpp
  30. 0 15
      scene/3d/baked_light.h
  31. 65 0
      scene/3d/baked_light_instance.cpp
  32. 33 0
      scene/3d/baked_light_instance.h
  33. 32 0
      scene/3d/light.cpp
  34. 17 0
      scene/3d/light.h
  35. 1 0
      scene/3d/sprite_3d.cpp
  36. 2 2
      scene/3d/sprite_3d.h
  37. 75 3
      scene/3d/visual_instance.cpp
  38. 8 1
      scene/3d/visual_instance.h
  39. 3 2
      scene/register_scene_types.cpp
  40. 308 0
      scene/resources/baked_light.cpp
  41. 106 0
      scene/resources/baked_light.h
  42. 4 0
      scene/scene_string_names.cpp
  43. 3 0
      scene/scene_string_names.h
  44. 21 0
      servers/visual/rasterizer.h
  45. 300 9
      servers/visual/visual_server_raster.cpp
  46. 55 2
      servers/visual/visual_server_raster.h
  47. 20 0
      servers/visual/visual_server_wrap_mt.h
  48. 2 0
      servers/visual_server.cpp
  49. 28 1
      servers/visual_server.h
  50. 60 3
      tools/editor/editor_import_export.cpp
  51. 14 0
      tools/editor/editor_import_export.h
  52. BIN
      tools/editor/icons/icon_bake.png
  53. BIN
      tools/editor/icons/icon_reload.png
  54. 1 0
      tools/editor/io_plugins/editor_import_collada.cpp
  55. 10 6
      tools/editor/io_plugins/editor_texture_import_plugin.cpp
  56. 1765 0
      tools/editor/plugins/baked_light_baker.cpp
  57. 316 0
      tools/editor/plugins/baked_light_baker.h
  58. 105 927
      tools/editor/plugins/baked_light_editor_plugin.cpp
  59. 16 14
      tools/editor/plugins/baked_light_editor_plugin.h
  60. 64 6
      tools/editor/project_export.cpp
  61. 9 0
      tools/editor/project_export.h

+ 1 - 0
SConstruct

@@ -169,6 +169,7 @@ if (env_base['target']=='debug'):
 
 
 env_base.platforms = {}
 env_base.platforms = {}
 
 
+
 for p in platform_list:
 for p in platform_list:
 
 
 	if env_base['platform'] != "" and env_base['platform'] != p:
 	if env_base['platform'] != "" and env_base['platform'] != p:

+ 28 - 0
core/SCsub

@@ -19,9 +19,37 @@ f = open("global_defaults.cpp","wb")
 f.write(gd_cpp)
 f.write(gd_cpp)
 f.close()
 f.close()
 
 
+import os
+txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0"
+if ("SCRIPT_AES256_ENCRYPTION_KEY" in os.environ):
+	e=os.environ["SCRIPT_AES256_ENCRYPTION_KEY"]
+	txt = ""
+	ec_valid=True
+	if (len(e)!=64):
+		ec_valid=False
+	else:
+
+		for i in range(len(e)>>1):
+			if (i>0):
+				txt+=","
+			txts="0x"+e[i*2:i*2+2]
+			try:
+				int(txts,16)
+			except:
+				ec_valid=False
+			txt+=txts
+	if (not ec_valid):
+		txt = "0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0"
+		print("Invalid AES256 encryption key, not 64 bits hex: "+e)
+
+f = open("script_encryption_key.cpp", "wb")
+f.write("#include \"globals.h\"\nuint8_t script_encryption_key[32]={" + txt + "};\n")
+f.close()
+
 
 
 env.add_source_files(env.core_sources,"*.cpp")
 env.add_source_files(env.core_sources,"*.cpp")
 
 
+
 Export('env')
 Export('env')
 
 
 import make_binders
 import make_binders

+ 2 - 2
core/bind/core_bind.cpp

@@ -1418,7 +1418,7 @@ String _Marshalls::variant_to_base64(const Variant& p_var) {
 	err = encode_variant(p_var,&w[0],len);
 	err = encode_variant(p_var,&w[0],len);
 	ERR_FAIL_COND_V( err != OK, "" );
 	ERR_FAIL_COND_V( err != OK, "" );
 
 
-	int b64len = len / 3 * 4 + 4;
+	int b64len = len / 3 * 4 + 4 + 1;
 	DVector<uint8_t> b64buff;
 	DVector<uint8_t> b64buff;
 	b64buff.resize(b64len);
 	b64buff.resize(b64len);
 	DVector<uint8_t>::Write w64 = b64buff.write();
 	DVector<uint8_t>::Write w64 = b64buff.write();
@@ -1437,7 +1437,7 @@ Variant _Marshalls::base64_to_variant(const String& p_str) {
 	CharString cstr = p_str.ascii();
 	CharString cstr = p_str.ascii();
 
 
 	DVector<uint8_t> buf;
 	DVector<uint8_t> buf;
-	buf.resize(strlen / 4 * 3);
+	buf.resize(strlen / 4 * 3 + 1);
 	DVector<uint8_t>::Write w = buf.write();
 	DVector<uint8_t>::Write w = buf.write();
 
 
 	int len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen);
 	int len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen);

+ 6 - 3
core/image.cpp

@@ -1399,14 +1399,17 @@ int Image::get_format_pallete_size(Format p_format) {
 }
 }
 
 
 
 
-void Image::decompress() {
+Error Image::decompress() {
 
 
 	if (format>=FORMAT_BC1 && format<=FORMAT_BC5 && _image_decompress_bc)
 	if (format>=FORMAT_BC1 && format<=FORMAT_BC5 && _image_decompress_bc)
 		_image_decompress_bc(this);
 		_image_decompress_bc(this);
-	if (format>=FORMAT_PVRTC2 && format<=FORMAT_PVRTC4_ALPHA && _image_decompress_pvrtc)
+	else if (format>=FORMAT_PVRTC2 && format<=FORMAT_PVRTC4_ALPHA && _image_decompress_pvrtc)
 		_image_decompress_pvrtc(this);
 		_image_decompress_pvrtc(this);
-	if (format==FORMAT_ETC && _image_decompress_etc)
+	else if (format==FORMAT_ETC && _image_decompress_etc)
 		_image_decompress_etc(this);
 		_image_decompress_etc(this);
+	else
+		return ERR_UNAVAILABLE;
+	return OK;
 }
 }
 
 
 
 

+ 3 - 3
core/image.h

@@ -45,8 +45,8 @@
 class Image {
 class Image {
 
 
 	enum { 
 	enum { 
-		MAX_WIDTH=4096, // force a limit somehow
-		MAX_HEIGHT=4096 // force a limit somehow
+		MAX_WIDTH=16384, // force a limit somehow
+		MAX_HEIGHT=16384// force a limit somehow
 	};
 	};
 public:
 public:
 
 
@@ -317,7 +317,7 @@ public:
 
 
 	Error compress(CompressMode p_mode=COMPRESS_BC);
 	Error compress(CompressMode p_mode=COMPRESS_BC);
 	Image compressed(int p_mode); /* from the Image::CompressMode enum */
 	Image compressed(int p_mode); /* from the Image::CompressMode enum */
-	void decompress();
+	Error decompress();
 
 
 	void fix_alpha_edges();
 	void fix_alpha_edges();
 	void premultiply_alpha();
 	void premultiply_alpha();

+ 7 - 2
core/io/resource_format_xml.cpp

@@ -193,7 +193,9 @@ Error ResourceInteractiveLoaderXML::close_tag(const String& p_name) {
 
 
 void ResourceInteractiveLoaderXML::unquote(String& p_str) {
 void ResourceInteractiveLoaderXML::unquote(String& p_str) {
 
 
-	p_str=p_str.strip_edges();
+	p_str=p_str.strip_edges().replace("\"","").xml_unescape();
+
+	/*p_str=p_str.strip_edges();
 	p_str=p_str.replace("\"","");
 	p_str=p_str.replace("\"","");
 	p_str=p_str.replace("&gt;","<");
 	p_str=p_str.replace("&gt;","<");
 	p_str=p_str.replace("&lt;",">");
 	p_str=p_str.replace("&lt;",">");
@@ -205,7 +207,7 @@ void ResourceInteractiveLoaderXML::unquote(String& p_str) {
 		p_str=p_str.replace("&#"+String::num(i)+";",chr);
 		p_str=p_str.replace("&#"+String::num(i)+";",chr);
 	}
 	}
 	p_str=p_str.replace("&amp;","&");
 	p_str=p_str.replace("&amp;","&");
-
+*/
 	//p_str.parse_utf8( p_str.ascii(true).get_data() );
 	//p_str.parse_utf8( p_str.ascii(true).get_data() );
 
 
 }
 }
@@ -652,11 +654,14 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
 		while( idx<len*2) {
 		while( idx<len*2) {
 
 
 			CharType c=get_char();
 			CharType c=get_char();
+			if (c<=32)
+				continue;
 
 
 			if (idx&1) {
 			if (idx&1) {
 
 
 				byte|=HEX2CHR(c);
 				byte|=HEX2CHR(c);
 				bytesptr[idx>>1]=byte;
 				bytesptr[idx>>1]=byte;
+				//printf("%x\n",int(byte));
 			} else {
 			} else {
 
 
 				byte=HEX2CHR(c)<<4;
 				byte=HEX2CHR(c)<<4;

+ 1 - 1
core/io/resource_format_xml.h

@@ -68,7 +68,7 @@ friend class ResourceFormatLoaderXML;
 	List<RES> resource_cache;
 	List<RES> resource_cache;
 	Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true);
 	Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true);
 	Error close_tag(const String& p_name);
 	Error close_tag(const String& p_name);
-	void unquote(String& p_str);
+	_FORCE_INLINE_ void unquote(String& p_str);
 	Error goto_end_of_tag();
 	Error goto_end_of_tag();
 	Error parse_property_data(String &r_data);
 	Error parse_property_data(String &r_data);
 	Error parse_property(Variant& r_v, String &r_name);
 	Error parse_property(Variant& r_v, String &r_name);

+ 0 - 9
core/math/aabb.cpp

@@ -335,15 +335,6 @@ AABB AABB::grow(real_t p_by) const {
 	aabb.grow_by(p_by);
 	aabb.grow_by(p_by);
 	return aabb;
 	return aabb;
 }
 }
-void AABB::grow_by(real_t p_amount) {
-
-	pos.x-=p_amount;
-	pos.y-=p_amount;
-	pos.z-=p_amount;
-	size.x+=2.0*p_amount;
-	size.y+=2.0*p_amount;
-	size.z+=2.0*p_amount;
-}
 
 
 void AABB::get_edge(int p_edge,Vector3& r_from,Vector3& r_to) const {
 void AABB::get_edge(int p_edge,Vector3& r_from,Vector3& r_to) const {
 
 

+ 60 - 1
core/math/aabb.h

@@ -73,6 +73,8 @@ public:
 	AABB intersection(const AABB& p_aabb) const; ///get box where two intersect, empty if no intersection occurs
 	AABB intersection(const AABB& p_aabb) const; ///get box where two intersect, empty if no intersection occurs
 	bool intersects_segment(const Vector3& p_from, const Vector3& p_to,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const;
 	bool intersects_segment(const Vector3& p_from, const Vector3& p_to,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const;
 	bool intersects_ray(const Vector3& p_from, const Vector3& p_dir,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const;
 	bool intersects_ray(const Vector3& p_from, const Vector3& p_dir,Vector3* r_clip=NULL,Vector3* r_normal=NULL) const;
+	_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &from,const Vector3& p_dir, float t0, float t1) const;
+
 	_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const;
 	_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_plane, int p_plane_count) const;
 	bool intersects_plane(const Plane &p_plane) const;
 	bool intersects_plane(const Plane &p_plane) const;
 
 
@@ -89,7 +91,7 @@ public:
 	_FORCE_INLINE_ real_t get_shortest_axis_size() const;
 	_FORCE_INLINE_ real_t get_shortest_axis_size() const;
 
 
 	AABB grow(real_t p_by) const;
 	AABB grow(real_t p_by) const;
-	void grow_by(real_t p_amount);
+	_FORCE_INLINE_ void grow_by(real_t p_amount);
 
 
 	void get_edge(int p_edge,Vector3& r_from,Vector3& r_to) const;
 	void get_edge(int p_edge,Vector3& r_from,Vector3& r_to) const;
 	_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
 	_FORCE_INLINE_ Vector3 get_endpoint(int p_point) const;
@@ -314,6 +316,63 @@ inline real_t AABB::get_shortest_axis_size() const {
 	return max_size;
 	return max_size;
 }
 }
 
 
+bool AABB::smits_intersect_ray(const Vector3 &from,const Vector3& dir, float t0, float t1) const {
+
+	float divx=1.0/dir.x;
+	float divy=1.0/dir.y;
+	float divz=1.0/dir.z;
+
+	Vector3 upbound=pos+size;
+	float tmin, tmax, tymin, tymax, tzmin, tzmax;
+	if (dir.x >= 0) {
+		tmin = (pos.x - from.x) * divx;
+		tmax = (upbound.x - from.x) * divx;
+	}
+	else {
+		tmin = (upbound.x - from.x) * divx;
+		tmax = (pos.x - from.x) * divx;
+	}
+	if (dir.y >= 0) {
+		tymin = (pos.y - from.y) * divy;
+		tymax = (upbound.y - from.y) * divy;
+	}
+	else {
+		tymin = (upbound.y - from.y) * divy;
+		tymax = (pos.y - from.y) * divy;
+	}
+	if ( (tmin > tymax) || (tymin > tmax) )
+		return false;
+	if (tymin > tmin)
+			tmin = tymin;
+	if (tymax < tmax)
+		tmax = tymax;
+	if (dir.z >= 0) {
+		tzmin = (pos.z - from.z) * divz;
+		tzmax = (upbound.z - from.z) * divz;
+	}
+	else {
+		tzmin = (upbound.z - from.z) * divz;
+		tzmax = (pos.z - from.z) * divz;
+	}
+	if ( (tmin > tzmax) || (tzmin > tmax) )
+		return false;
+	if (tzmin > tmin)
+		tmin = tzmin;
+	if (tzmax < tmax)
+		tmax = tzmax;
+	return ( (tmin < t1) && (tmax > t0) );
+}
+
+void AABB::grow_by(real_t p_amount) {
+
+	pos.x-=p_amount;
+	pos.y-=p_amount;
+	pos.z-=p_amount;
+	size.x+=2.0*p_amount;
+	size.y+=2.0*p_amount;
+	size.z+=2.0*p_amount;
+}
+
 typedef AABB Rect3;
 typedef AABB Rect3;
 
 
 #endif // AABB_H
 #endif // AABB_H

+ 1 - 1
core/math/face3.cpp

@@ -247,7 +247,7 @@ bool Face3::intersects_aabb(const AABB& p_aabb) const {
 		p_aabb.get_edge(i,from,to);
 		p_aabb.get_edge(i,from,to);
 		Vector3 e1=from-to;
 		Vector3 e1=from-to;
 		for (int j=0;j<3;j++) {
 		for (int j=0;j<3;j++) {
-			Vector3 e2=edge_norms[i];
+			Vector3 e2=edge_norms[j];
 
 
 			Vector3 axis=vec3_cross( e1, e2 );
 			Vector3 axis=vec3_cross( e1, e2 );
 
 

+ 169 - 0
core/math/face3.h

@@ -86,6 +86,7 @@ public:
         }
         }
 
 
         bool intersects_aabb(const AABB& p_aabb) const;
         bool intersects_aabb(const AABB& p_aabb) const;
+	_FORCE_INLINE_ bool intersects_aabb2(const AABB& p_aabb) const;
 	operator String() const;
 	operator String() const;
 
 
         inline Face3() {}
         inline Face3() {}
@@ -94,4 +95,172 @@ public:
 };
 };
 
 
 
 
+bool Face3::intersects_aabb2(const AABB& p_aabb) const {
+
+	Vector3 perp = (vertex[0]-vertex[2]).cross(vertex[0]-vertex[1]);
+
+	Vector3 half_extents = p_aabb.size * 0.5;
+	Vector3 ofs = p_aabb.pos + half_extents;
+
+	Vector3 sup =Vector3(
+			(perp.x>0) ? -half_extents.x : half_extents.x,
+			(perp.y>0) ? -half_extents.y : half_extents.y,
+			(perp.z>0) ? -half_extents.z : half_extents.z
+		);
+
+	float d = perp.dot(vertex[0]);
+	float dist_a = perp.dot(ofs+sup)-d;
+	float dist_b = perp.dot(ofs-sup)-d;
+
+	if (dist_a*dist_b > 0)
+		return false; //does not intersect the plane
+
+
+#define TEST_AXIS(m_ax)\
+	{\
+		float aabb_min=p_aabb.pos.m_ax;\
+		float aabb_max=p_aabb.pos.m_ax+p_aabb.size.m_ax;\
+		float tri_min,tri_max;\
+		for (int i=0;i<3;i++) {\
+			if (i==0 || vertex[i].m_ax > tri_max)\
+				tri_max=vertex[i].m_ax;\
+			if (i==0 || vertex[i].m_ax < tri_min)\
+				tri_min=vertex[i].m_ax;\
+		}\
+\
+		if (tri_max<aabb_min || aabb_max<tri_min)\
+			return false;\
+	}
+
+	TEST_AXIS(x);
+	TEST_AXIS(y);
+	TEST_AXIS(z);
+
+#undef TEST_AXIS
+
+
+	Vector3 edge_norms[3]={
+		vertex[0]-vertex[1],
+		vertex[1]-vertex[2],
+		vertex[2]-vertex[0],
+	};
+
+	for (int i=0;i<12;i++) {
+
+		Vector3 from,to;
+		switch(i) {
+
+			case 0:{
+
+				from=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y		, p_aabb.pos.z		);
+				to=Vector3( p_aabb.pos.x	, p_aabb.pos.y		, p_aabb.pos.z		);
+			} break;
+			case 1:{
+
+				from=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y		, p_aabb.pos.z+p_aabb.size.z	);
+				to=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y		, p_aabb.pos.z		);
+			} break;
+			case 2:{
+				from=Vector3( p_aabb.pos.x	, p_aabb.pos.y		, p_aabb.pos.z+p_aabb.size.z	);
+				to=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y		, p_aabb.pos.z+p_aabb.size.z	);
+
+			} break;
+			case 3:{
+
+				from=Vector3( p_aabb.pos.x	, p_aabb.pos.y		, p_aabb.pos.z		);
+				to=Vector3( p_aabb.pos.x	, p_aabb.pos.y		, p_aabb.pos.z+p_aabb.size.z	);
+
+			} break;
+			case 4:{
+
+				from=Vector3( p_aabb.pos.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z		);
+				to=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z		);
+			} break;
+			case 5:{
+
+				from=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z		);
+				to=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z+p_aabb.size.z	);
+			} break;
+			case 6:{
+				from=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z+p_aabb.size.z	);
+				to=Vector3( p_aabb.pos.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z+p_aabb.size.z	);
+
+			} break;
+			case 7:{
+
+				from=Vector3( p_aabb.pos.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z+p_aabb.size.z	);
+				to=Vector3( p_aabb.pos.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z		);
+
+			} break;
+			case 8:{
+
+				from=Vector3( p_aabb.pos.x	, p_aabb.pos.y		, p_aabb.pos.z+p_aabb.size.z	);
+				to=Vector3( p_aabb.pos.x	, p_aabb.pos.y+p_aabb.size.y		, p_aabb.pos.z+p_aabb.size.z	);
+
+			} break;
+			case 9:{
+
+				from=Vector3( p_aabb.pos.x	, p_aabb.pos.y		, p_aabb.pos.z		);
+				to=Vector3( p_aabb.pos.x	, p_aabb.pos.y+p_aabb.size.y	, p_aabb.pos.z		);
+
+			} break;
+			case 10:{
+
+				from=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y		, p_aabb.pos.z		);
+				to=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y+p_aabb.size.y	, p_aabb.pos.z		);
+
+			} break;
+			case 11:{
+
+				from=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y		, p_aabb.pos.z+p_aabb.size.z		);
+				to=Vector3( p_aabb.pos.x+p_aabb.size.x	, p_aabb.pos.y+p_aabb.size.y	, p_aabb.pos.z+p_aabb.size.z		);
+
+			} break;
+
+		}
+
+		Vector3 e1=from-to;
+		for (int j=0;j<3;j++) {
+			Vector3 e2=edge_norms[j];
+
+			Vector3 axis=vec3_cross( e1, e2 );
+
+			if (axis.length_squared()<0.0001)
+				continue; // coplanar
+			//axis.normalize();
+
+			Vector3 sup2 =Vector3(
+					(axis.x>0) ? -half_extents.x : half_extents.x,
+					(axis.y>0) ? -half_extents.y : half_extents.y,
+					(axis.z>0) ? -half_extents.z : half_extents.z
+				);
+
+			float maxB = axis.dot(ofs+sup2);
+			float minB = axis.dot(ofs-sup2);
+			if (minB>maxB) {
+				SWAP(maxB,minB);
+			}
+
+			float minT=1e20,maxT=-1e20;
+			for (int k=0;k<3;k++) {
+
+				float d=axis.dot(vertex[k]);
+
+				if (d > maxT)
+					maxT=d;
+
+				if (d < minT)
+					minT=d;
+			}
+
+			if (maxB<minT || maxT<minB)
+				return false;
+		}
+	}
+	return true;
+
+
+}
+
+
 #endif // FACE3_H
 #endif // FACE3_H

+ 18 - 2
core/packed_data_container.cpp

@@ -89,11 +89,13 @@ Variant PackedDataContainer::_iter_get_ofs(const Variant& p_iter,uint32_t p_offs
 	bool err=false;
 	bool err=false;
 	if (type==TYPE_ARRAY) {
 	if (type==TYPE_ARRAY) {
 
 
-		return _get_at_ofs(p_offset+8+pos*4,rd.ptr(),err);
+		uint32_t vpos = decode_uint32(rd.ptr() + p_offset+8+pos*4);
+		return _get_at_ofs(vpos,rd.ptr(),err);
 
 
 	} else if (type==TYPE_DICT) {
 	} else if (type==TYPE_DICT) {
 
 
-		return _get_at_ofs(p_offset+8+pos*12+8,rd.ptr(),err);
+		uint32_t vpos = decode_uint32(rd.ptr() + p_offset+8+pos*12+4);
+		return _get_at_ofs(vpos,rd.ptr(),err);
 	} else {
 	} else {
 		ERR_FAIL_V(Variant());
 		ERR_FAIL_V(Variant());
 	}
 	}
@@ -127,6 +129,15 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs,const uint8_t *p_buf,boo
 
 
 }
 }
 
 
+uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
+
+	DVector<uint8_t>::Read rd=data.read();
+	const uint8_t *r=&rd[p_ofs];
+	uint32_t type = decode_uint32(r);
+
+	return type;
+};
+
 int PackedDataContainer::_size(uint32_t p_ofs) const {
 int PackedDataContainer::_size(uint32_t p_ofs) const {
 
 
 	DVector<uint8_t>::Read rd=data.read();
 	DVector<uint8_t>::Read rd=data.read();
@@ -408,6 +419,10 @@ Variant PackedDataContainerRef::_iter_get(const Variant& p_iter){
 	return from->_iter_get_ofs(p_iter,offset);
 	return from->_iter_get_ofs(p_iter,offset);
 }
 }
 
 
+bool PackedDataContainerRef::_is_dictionary() const {
+
+	return from->_type_at_ofs(offset) == PackedDataContainer::TYPE_DICT;
+};
 
 
 void PackedDataContainerRef::_bind_methods() {
 void PackedDataContainerRef::_bind_methods() {
 
 
@@ -415,6 +430,7 @@ void PackedDataContainerRef::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("_iter_init"),&PackedDataContainerRef::_iter_init);
 	ObjectTypeDB::bind_method(_MD("_iter_init"),&PackedDataContainerRef::_iter_init);
 	ObjectTypeDB::bind_method(_MD("_iter_get"),&PackedDataContainerRef::_iter_get);
 	ObjectTypeDB::bind_method(_MD("_iter_get"),&PackedDataContainerRef::_iter_get);
 	ObjectTypeDB::bind_method(_MD("_iter_next"),&PackedDataContainerRef::_iter_next);
 	ObjectTypeDB::bind_method(_MD("_iter_next"),&PackedDataContainerRef::_iter_next);
+	ObjectTypeDB::bind_method(_MD("_is_dictionary"),&PackedDataContainerRef::_is_dictionary);
 }
 }
 
 
 
 

+ 2 - 0
core/packed_data_container.h

@@ -68,6 +68,7 @@ class PackedDataContainer : public Resource {
 friend class PackedDataContainerRef;
 friend class PackedDataContainerRef;
 	Variant _key_at_ofs(uint32_t p_ofs,const Variant& p_key,bool &err) const;
 	Variant _key_at_ofs(uint32_t p_ofs,const Variant& p_key,bool &err) const;
 	Variant _get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const;
 	Variant _get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const;
+	uint32_t _type_at_ofs(uint32_t p_ofs) const;
 	int _size(uint32_t p_ofs) const;
 	int _size(uint32_t p_ofs) const;
 
 
 protected:
 protected:
@@ -100,6 +101,7 @@ public:
 	Variant _iter_init(const Array& p_iter);
 	Variant _iter_init(const Array& p_iter);
 	Variant _iter_next(const Array& p_iter);
 	Variant _iter_next(const Array& p_iter);
 	Variant _iter_get(const Variant& p_iter);
 	Variant _iter_get(const Variant& p_iter);
+	bool _is_dictionary() const;
 
 
 	int size() const;
 	int size() const;
 	virtual Variant getvar(const Variant& p_key, bool *r_valid=NULL) const;
 	virtual Variant getvar(const Variant& p_key, bool *r_valid=NULL) const;

+ 0 - 2
core/script_language.cpp

@@ -229,8 +229,6 @@ ScriptDebugger::ScriptDebugger() {
 }
 }
 
 
 
 
-
-
 bool PlaceHolderScriptInstance::set(const StringName& p_name, const Variant& p_value) {
 bool PlaceHolderScriptInstance::set(const StringName& p_name, const Variant& p_value) {
 
 
 	if (values.has(p_name)) {
 	if (values.has(p_name)) {

+ 1 - 0
core/script_language.h

@@ -166,6 +166,7 @@ public:
 	virtual ~ScriptLanguage() {};	
 	virtual ~ScriptLanguage() {};	
 };
 };
 
 
+extern uint8_t script_encryption_key[32];
 
 
 class PlaceHolderScriptInstance : public ScriptInstance {
 class PlaceHolderScriptInstance : public ScriptInstance {
 
 

+ 99 - 14
core/ustring.cpp

@@ -1596,6 +1596,7 @@ bool String::is_numeric() const {
 };
 };
 
 
 #define IS_DIGIT(m_d) ( (m_d)>='0' && (m_d)<='9' )
 #define IS_DIGIT(m_d) ( (m_d)>='0' && (m_d)<='9' )
+#define IS_HEX_DIGIT(m_d) ( ( (m_d)>='0' && (m_d)<='9' ) || ( (m_d)>='a' && (m_d)<='f' ) || ( (m_d)>='A' && (m_d)<='F' ) )
 
 
 template<class C>
 template<class C>
 static double built_in_strtod(const C *string,         /* A decimal ASCII floating-point number,
 static double built_in_strtod(const C *string,         /* A decimal ASCII floating-point number,
@@ -2891,23 +2892,107 @@ String String::xml_escape(bool p_escape_quotes) const {
 	return str;
 	return str;
 }
 }
 
 
-String String::xml_unescape() const {
+static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src,int p_src_len,CharType *p_dst) {
 
 
-	String str=*this;
-	str=str.strip_edges();
-	//str=str.replace("\"","");
-	str=str.replace("&gt;","<");
-	str=str.replace("&lt;",">");
-	str=str.replace("&apos;","'");
-	str=str.replace("&quot;","\"");
-	/*
-	for (int i=1;i<32;i++) {
+	int len=0;
+	while(p_src_len) {
 
 
-		char chr[2]={i,0};
-		str=str.replace("&#"+String::num(i)+";",chr);
-	}*/
-	str=str.replace("&amp;","&");
+		if (*p_src=='&') {
+
+			int eat=0;
+
+			if (p_src_len>=4 && p_src[1]=='#') {
+
+				CharType c=0;
+
+				for(int i=2;i<p_src_len;i++) {
+
+					eat=i+1;
+					CharType ct=p_src[i];
+					if (ct==';') {
+						break;
+					} else if (ct>='0' && ct<='9') {
+						ct=ct-'0';
+					} else if (ct>='a' && ct<='f') {
+						ct=(ct-'a')+10;
+					} else if (ct>='A' && ct<='F') {
+						ct=(ct-'A')+10;
+					} else {
+						continue;
+					}
+					c<<=4;
+					c|=ct;
+				}
+
+				if (p_dst)
+					*p_dst=c;
+
+			} else if (p_src_len>=4 && p_src[1]=='g' && p_src[2]=='t' && p_src[3]==';') {
+
+				if (p_dst)
+					*p_dst='<';
+				eat=4;
+			} else if (p_src_len>=4 && p_src[1]=='l' && p_src[2]=='t' && p_src[3]==';') {
+
+				if (p_dst)
+					*p_dst='>';
+				eat=4;
+			} else if (p_src_len>=5 && p_src[1]=='a' && p_src[2]=='m' && p_src[3]=='p' && p_src[4]==';') {
+
+				if (p_dst)
+					*p_dst='&';
+				eat=5;
+			} else if (p_src_len>=6 && p_src[1]=='q' && p_src[2]=='u' && p_src[3]=='o' && p_src[4]=='t' && p_src[5]==';') {
+
+				if (p_dst)
+					*p_dst='"';
+				eat=6;
+			} else if (p_src_len>=6 && p_src[1]=='a' && p_src[2]=='p' && p_src[3]=='o' && p_src[4]=='s' && p_src[5]==';') {
+
+				if (p_dst)
+					*p_dst='\'';
+				eat=6;
+			} else {
+
+				if (p_dst)
+					*p_dst=*p_src;
+				eat=1;
+
+			}
+
+			if (p_dst)
+				p_dst++;
+
+			len++;
+			p_src+=eat;
+			p_src_len-=eat;
+		} else {
+
+			if (p_dst) {
+				*p_dst=*p_src;
+				p_dst++;
+			}
+			len++;
+			p_src++;
+			p_src_len--;
+		}
+	}
+
+	return len;
+
+}
 
 
+String String::xml_unescape() const {
+
+
+	String str;
+	int l = length();
+	int len = _xml_unescape(c_str(),l,NULL);
+	if (len==0)
+		return String();
+	str.resize(len+1);
+	_xml_unescape(c_str(),l,&str[0]);
+	str[len]=0;
 	return str;
 	return str;
 }
 }
 
 

+ 1 - 1
core/variant_op.cpp

@@ -2907,7 +2907,7 @@ bool Variant::iter_init(Variant& r_iter,bool &valid) const {
 			ref.push_back(r_iter);
 			ref.push_back(r_iter);
 			Variant vref=ref;
 			Variant vref=ref;
 			const Variant *refp[]={&vref};
 			const Variant *refp[]={&vref};
-			Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_next,refp,1,ce);
+			Variant ret = _get_obj().obj->call(CoreStringNames::get_singleton()->_iter_init,refp,1,ce);
 
 
 			if (ref.size()!=1 || ce.error!=Variant::CallError::CALL_OK) {
 			if (ref.size()!=1 || ce.error!=Variant::CallError::CALL_OK) {
 				valid=false;
 				valid=false;

Plik diff jest za duży
+ 0 - 250
demos/3d/platformer/stage2.xml


BIN
demos/3d/platformer/tiles.res


+ 47 - 2
drivers/gles2/rasterizer_gles2.cpp

@@ -1042,8 +1042,8 @@ void RasterizerGLES2::texture_set_size_override(RID p_texture,int p_width, int p
 	ERR_FAIL_COND(!texture);
 	ERR_FAIL_COND(!texture);
 	ERR_FAIL_COND(texture->render_target);
 	ERR_FAIL_COND(texture->render_target);
 
 
-	ERR_FAIL_COND(p_width<=0 || p_width>4096);
-	ERR_FAIL_COND(p_height<=0 || p_height>4096);
+	ERR_FAIL_COND(p_width<=0 || p_width>16384);
+	ERR_FAIL_COND(p_height<=0 || p_height>16384);
 	//real texture size is in alloc width and height
 	//real texture size is in alloc width and height
 	texture->width=p_width;
 	texture->width=p_width;
 	texture->height=p_height;
 	texture->height=p_height;
@@ -5471,6 +5471,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 	const ParamOverrideMap* prev_overrides=NULL; // make it diferent than NULL
 	const ParamOverrideMap* prev_overrides=NULL; // make it diferent than NULL
 	const Skeleton *prev_skeleton =NULL;
 	const Skeleton *prev_skeleton =NULL;
 	uint8_t prev_sort_flags=0xFF;
 	uint8_t prev_sort_flags=0xFF;
+	const BakedLightData *prev_baked_light=NULL;
 
 
 	Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID;
 	Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID;
 
 
@@ -5486,6 +5487,9 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,false);
 		material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM,false);
 		material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false);
 		material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false);
 		material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false);
 		material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false);
+		material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false);
+//		material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,false);
+
 	}
 	}
 
 
 
 
@@ -5503,8 +5507,10 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		uint8_t sort_flags= e->sort_flags;
 		uint8_t sort_flags= e->sort_flags;
 		const Skeleton *skeleton = e->skeleton;
 		const Skeleton *skeleton = e->skeleton;
 		const Geometry *geometry_cmp = e->geometry_cmp;
 		const Geometry *geometry_cmp = e->geometry_cmp;
+		const BakedLightData *baked_light = e->instance->baked_light;
 
 
 		bool rebind=false;
 		bool rebind=false;
+		bool bind_baked_light_octree=false;
 		bool additive=false;
 		bool additive=false;
 
 
 
 
@@ -5622,6 +5628,32 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 				current_blend_mode=desired_blend_mode;
 				current_blend_mode=desired_blend_mode;
 			}
 			}
 
 
+			material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false);
+//			material_shader.set_conditional(MaterialShaderGLES2::USE_AMBIENT_TEXTURE,false);
+
+			if (!additive && baked_light) {
+
+				if (baked_light->mode==VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) {
+					material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,true);
+					bind_baked_light_octree=true;
+					if (prev_baked_light!=baked_light) {
+						Texture *tex=texture_owner.get(baked_light->octree_texture);
+						if (tex) {
+
+							glActiveTexture(GL_TEXTURE5);
+							glBindTexture(tex->target,tex->tex_id); //bind the texture
+						}
+
+					}
+				} else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) {
+
+					//material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,true);
+				}
+			}
+
+			if (int(prev_baked_light!=NULL) ^ int(baked_light!=NULL)) {
+				rebind=true;
+			}
 		}
 		}
 
 
 		if (sort_flags!=prev_sort_flags) {
 		if (sort_flags!=prev_sort_flags) {
@@ -5672,6 +5704,18 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 			}
 			}
 		}
 		}
 
 
+		if (bind_baked_light_octree && (baked_light!=prev_baked_light || rebind)) {
+
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_INVERSE_TRANSFORM, *e->instance->baked_light_octree_xform);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_SIZE, baked_light->octree_lattice_size);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_DIVIDE, baked_light->octree_lattice_divide);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_STEPS, baked_light->octree_steps);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,5);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_PIX_SIZE,baked_light->octree_tex_pixel_size);
+
+
+		}
+
 		_set_cull(e->mirror,p_reverse_cull);
 		_set_cull(e->mirror,p_reverse_cull);
 
 
 
 
@@ -5726,6 +5770,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		prev_light=e->light;
 		prev_light=e->light;
 		prev_light_type=e->light_type;
 		prev_light_type=e->light_type;
 		prev_sort_flags=sort_flags;
 		prev_sort_flags=sort_flags;
+		prev_baked_light=baked_light;
 //		prev_geometry_type=geometry->type;
 //		prev_geometry_type=geometry->type;
 	}
 	}
 
 

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

@@ -93,6 +93,13 @@ varying vec3 tangent_interp;
 varying vec3 binormal_interp;
 varying vec3 binormal_interp;
 #endif
 #endif
 
 
+#ifdef ENABLE_AMBIENT_OCTREE
+
+uniform highp mat4 ambient_octree_inverse_transform;
+varying highp vec3 ambient_octree_coords;
+
+#endif
+
 #ifdef USE_FOG
 #ifdef USE_FOG
 
 
 varying vec4 fog_interp;
 varying vec4 fog_interp;
@@ -173,12 +180,19 @@ void main() {
 #ifdef USE_UNIFORM_INSTANCING
 #ifdef USE_UNIFORM_INSTANCING
 
 
 	highp mat4 modelview = (camera_inverse_transform * (world_transform * instance_transform));
 	highp mat4 modelview = (camera_inverse_transform * (world_transform * instance_transform));
+#ifdef ENABLE_AMBIENT_OCTREE
+	highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * (world_transform * instance_transform));
+#endif
+
 #else
 #else
 
 
 #ifdef USE_ATTRIBUTE_INSTANCING
 #ifdef USE_ATTRIBUTE_INSTANCING
 
 
 	highp mat4 minst=mat4(instance_row0,instance_row1,instance_row2,instance_row3);
 	highp mat4 minst=mat4(instance_row0,instance_row1,instance_row2,instance_row3);
 	highp mat4 modelview = (camera_inverse_transform * (world_transform * minst));
 	highp mat4 modelview = (camera_inverse_transform * (world_transform * minst));
+#ifdef ENABLE_AMBIENT_OCTREE
+	highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * (world_transform * minst));
+#endif
 
 
 #else
 #else
 
 
@@ -201,9 +215,16 @@ void main() {
 	);*/
 	);*/
 
 
 	highp mat4 modelview = (camera_inverse_transform * (world_transform * minst));
 	highp mat4 modelview = (camera_inverse_transform * (world_transform * minst));
+#ifdef ENABLE_AMBIENT_OCTREE
+	highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * (world_transform * minst));
+#endif
 
 
 #else
 #else
 	highp mat4 modelview = (camera_inverse_transform * world_transform);
 	highp mat4 modelview = (camera_inverse_transform * world_transform);
+#ifdef ENABLE_AMBIENT_OCTREE
+	highp mat4 ambient_octree_transform = (ambient_octree_inverse_transform * world_transform);
+#endif
+
 #endif
 #endif
 
 
 #endif
 #endif
@@ -233,6 +254,11 @@ void main() {
 
 
 #endif
 #endif
 
 
+#ifdef ENABLE_AMBIENT_OCTREE
+
+	ambient_octree_coords = (ambient_octree_transform * vertex_in).xyz;
+#endif
+
 	vertex_interp = (modelview * vertex_in).xyz;
 	vertex_interp = (modelview * vertex_in).xyz;
 	normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz);
 	normal_interp = normalize((modelview * vec4(normal_in,0.0)).xyz);
 
 
@@ -515,6 +541,16 @@ vec3 process_shade(in vec3 normal, in vec3 light_dir, in vec3 eye_vec, in vec3 d
 uniform float const_light_mult;
 uniform float const_light_mult;
 uniform float time;
 uniform float time;
 
 
+#ifdef ENABLE_AMBIENT_OCTREE
+
+varying highp vec3 ambient_octree_coords;
+uniform highp float ambient_octree_lattice_size;
+uniform highp vec2 ambient_octree_pix_size;
+uniform highp float ambient_octree_lattice_divide;
+uniform highp sampler2D ambient_octree_tex;
+uniform int ambient_octree_steps;
+
+#endif
 
 
 
 
 FRAGMENT_SHADER_GLOBALS
 FRAGMENT_SHADER_GLOBALS
@@ -745,10 +781,57 @@ FRAGMENT_SHADER_CODE
 	}
 	}
 #endif
 #endif
 
 
+#ifdef ENABLE_AMBIENT_OCTREE
+
+	vec3 ambientmap_color = vec3(0.0,0.0,0.0);
+
+
+	{
+
+		//read position from initial lattice grid
+		highp vec3 lattice_pos = floor(ambient_octree_coords*ambient_octree_lattice_size);
+		highp vec2 octant_uv = highp vec2(lattice_pos.x+ambient_octree_lattice_size*lattice_pos.z,lattice_pos.y);
+		octant_uv=(octant_uv*highp vec2(2.0,4.0)+highp vec2(0.0,4.0));
+		highp float ld = 1.0/ambient_octree_lattice_size;
+
+
+		//go down the octree
+
+		for(int i=0;i<ambient_octree_steps;i++) {
+
+
+			highp vec3 sub=mod(ambient_octree_coords,ld);
+			ld*=0.5;
+			highp vec3 s = step(ld,sub);
+			octant_uv+=s.xy;
+			octant_uv.y+=s.z*2.0;
+			octant_uv=(octant_uv+0.5)*ambient_octree_pix_size;
+			highp vec4 new_uv = texture2D(ambient_octree_tex,octant_uv);
+			octant_uv=floor(highp vec2( dot(new_uv.xy,highp vec2(65280.0,255.0)),  dot(new_uv.zw,highp vec2(65280.0,255.0)) )+0.5);//+ambient_octree_pix_size*0.5;
+
+		}
+
+		//sample color
+		octant_uv=(octant_uv+0.5)*ambient_octree_pix_size;
+		highp vec3 sub=(mod(ambient_octree_coords,ld)/ld);
+		octant_uv.xy+=sub.xy*ambient_octree_pix_size.xy;
+		vec3 col_up=texture2D(ambient_octree_tex,octant_uv).rgb;
+		octant_uv.y+=ambient_octree_pix_size.y*2.0;
+		vec3 col_down=texture2D(ambient_octree_tex,octant_uv).rgb;
+		ambientmap_color=mix(col_down,col_up,1.0-sub.z);
+
+		ambientmap_color*=diffuse.rgb;
+
+	}
+
+#endif
 
 
         float shadow_attenuation = 1.0;
         float shadow_attenuation = 1.0;
 
 
 
 
+
+
+
 #ifdef LIGHT_USE_SHADOW
 #ifdef LIGHT_USE_SHADOW
 #ifdef LIGHT_TYPE_DIRECTIONAL
 #ifdef LIGHT_TYPE_DIRECTIONAL
 
 
@@ -921,6 +1004,8 @@ FRAGMENT_SHADER_CODE
 #endif
 #endif
 
 
 
 
+
+
 #ifdef USE_VERTEX_LIGHTING
 #ifdef USE_VERTEX_LIGHTING
 
 
 	vec3 ambient = light_ambient*diffuse.rgb;
 	vec3 ambient = light_ambient*diffuse.rgb;
@@ -933,11 +1018,13 @@ FRAGMENT_SHADER_CODE
 	diffuse.rgb=(diffuse.rgb * diffuse_interp.rgb + specular * specular_interp)*shadow_attenuation + ambient;
 	diffuse.rgb=(diffuse.rgb * diffuse_interp.rgb + specular * specular_interp)*shadow_attenuation + ambient;
 	diffuse.rgb+=emission * const_light_mult;
 	diffuse.rgb+=emission * const_light_mult;
 
 
-
 #endif
 #endif
 
 
 
 
+#ifdef ENABLE_AMBIENT_OCTREE
 
 
+	diffuse.rgb+=ambientmap_color;
+#endif
 
 
 
 
 #ifdef USE_SHADOW_PASS
 #ifdef USE_SHADOW_PASS

+ 2 - 0
drivers/unix/ip_unix.cpp

@@ -130,6 +130,8 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
 	getifaddrs(&ifAddrStruct);
 	getifaddrs(&ifAddrStruct);
 
 
 	for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
 	for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
+		if (!ifa->ifa_addr)
+			continue;
 		if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
 		if (ifa ->ifa_addr->sa_family==AF_INET) { // check it is IP4
 			// is a valid IP4 Address
 			// is a valid IP4 Address
 
 

+ 26 - 3
modules/gdscript/gd_script.cpp

@@ -31,6 +31,7 @@
 #include "global_constants.h"
 #include "global_constants.h"
 #include "gd_compiler.h"
 #include "gd_compiler.h"
 #include "os/file_access.h"
 #include "os/file_access.h"
+#include "io/file_access_encrypted.h"
 
 
 /* TODO:
 /* TODO:
 
 
@@ -1591,7 +1592,28 @@ void GDScript::_bind_methods() {
 
 
 Error GDScript::load_byte_code(const String& p_path) {
 Error GDScript::load_byte_code(const String& p_path) {
 
 
-	Vector<uint8_t> bytecode = FileAccess::get_file_as_array(p_path);
+	Vector<uint8_t> bytecode;
+
+	if (p_path.ends_with("gde")) {
+
+		FileAccess *fa = FileAccess::open(p_path,FileAccess::READ);
+		ERR_FAIL_COND_V(!fa,ERR_CANT_OPEN);
+		FileAccessEncrypted *fae = memnew( FileAccessEncrypted );
+		ERR_FAIL_COND_V(!fae,ERR_CANT_OPEN);
+		Vector<uint8_t> key;
+		key.resize(32);
+		for(int i=0;i<key.size();i++) {
+			key[i]=script_encryption_key[i];
+		}
+		Error err = fae->open_and_parse(fa,key,FileAccessEncrypted::MODE_READ);
+		ERR_FAIL_COND_V(err,err);
+		bytecode.resize(fae->get_len());
+		fae->get_buffer(bytecode.ptr(),bytecode.size());
+		memdelete(fae);
+	} else {
+
+		bytecode = FileAccess::get_file_as_array(p_path);
+	}
 	ERR_FAIL_COND_V(bytecode.size()==0,ERR_PARSE_ERROR);
 	ERR_FAIL_COND_V(bytecode.size()==0,ERR_PARSE_ERROR);
 	path=p_path;
 	path=p_path;
 
 
@@ -2225,7 +2247,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig
 
 
 	Ref<GDScript> scriptres(script);
 	Ref<GDScript> scriptres(script);
 
 
-	if (p_path.ends_with(".gdc")) {
+	if (p_path.ends_with(".gde") || p_path.ends_with(".gdc")) {
 
 
 		script->set_script_path(p_original_path); // script needs this.
 		script->set_script_path(p_original_path); // script needs this.
 		script->set_path(p_original_path);
 		script->set_path(p_original_path);
@@ -2258,6 +2280,7 @@ void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_ext
 
 
 	p_extensions->push_back("gd");
 	p_extensions->push_back("gd");
 	p_extensions->push_back("gdc");
 	p_extensions->push_back("gdc");
+	p_extensions->push_back("gde");
 }
 }
 
 
 bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {
 bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {
@@ -2268,7 +2291,7 @@ bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {
 String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
 String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
 
 
 	String el = p_path.extension().to_lower();
 	String el = p_path.extension().to_lower();
-	if (el=="gd" || el=="gdc")
+	if (el=="gd" || el=="gdc" || el=="gde")
 		return "GDScript";
 		return "GDScript";
 	return "";
 	return "";
 }
 }

+ 1 - 0
modules/gdscript/gd_tokenizer.cpp

@@ -757,6 +757,7 @@ void GDTokenizerText::_advance() {
 							{Variant::_RID,"RID"},
 							{Variant::_RID,"RID"},
 							{Variant::OBJECT,"Object"},
 							{Variant::OBJECT,"Object"},
 							{Variant::INPUT_EVENT,"InputEvent"},
 							{Variant::INPUT_EVENT,"InputEvent"},
+							{Variant::NODE_PATH,"NodePath"},
 							{Variant::DICTIONARY,"dict"},
 							{Variant::DICTIONARY,"dict"},
 							{Variant::DICTIONARY,"Dictionary"},
 							{Variant::DICTIONARY,"Dictionary"},
 							{Variant::ARRAY,"Array"},
 							{Variant::ARRAY,"Array"},

+ 65 - 13
modules/gdscript/register_types.cpp

@@ -14,6 +14,8 @@
 #include "gd_script.h"
 #include "gd_script.h"
 #include "io/resource_loader.h"
 #include "io/resource_loader.h"
 #include "os/file_access.h"
 #include "os/file_access.h"
+#include "io/file_access_encrypted.h"
+
 
 
 
 
 GDScriptLanguage *script_language_gd=NULL;
 GDScriptLanguage *script_language_gd=NULL;
@@ -25,6 +27,7 @@ ResourceFormatSaverGDScript *resource_saver_gd=NULL;
 #include "tools/editor/editor_import_export.h"
 #include "tools/editor/editor_import_export.h"
 #include "gd_tokenizer.h"
 #include "gd_tokenizer.h"
 #include "tools/editor/editor_node.h"
 #include "tools/editor/editor_node.h"
+#include "tools/editor/editor_settings.h"
 
 
 class EditorExportGDScript : public EditorExportPlugin {
 class EditorExportGDScript : public EditorExportPlugin {
 
 
@@ -34,20 +37,69 @@ public:
 
 
 	virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) {
 	virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) {
 		//compile gdscript to bytecode
 		//compile gdscript to bytecode
-		if (p_path.ends_with(".gd")) {
-			Vector<uint8_t> file = FileAccess::get_file_as_array(p_path);
-			if (file.empty())
-				return file;
-			String txt;
-			txt.parse_utf8((const char*)file.ptr(),file.size());
-			file = GDTokenizerBuffer::parse_code_string(txt);
-			if (!file.empty()) {
-				print_line("PREV: "+p_path);
-				p_path=p_path.basename()+".gdc";
-				print_line("NOW: "+p_path);
-				return file;
-			}
 
 
+		if (EditorImportExport::get_singleton()->script_get_action()!=EditorImportExport::SCRIPT_ACTION_NONE) {
+
+			if (p_path.ends_with(".gd")) {
+				Vector<uint8_t> file = FileAccess::get_file_as_array(p_path);
+				if (file.empty())
+					return file;
+				String txt;
+				txt.parse_utf8((const char*)file.ptr(),file.size());
+				file = GDTokenizerBuffer::parse_code_string(txt);
+
+				if (!file.empty()) {
+
+					if (EditorImportExport::get_singleton()->script_get_action()==EditorImportExport::SCRIPT_ACTION_ENCRYPT) {
+
+						String tmp_path=EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/script.gde");
+						FileAccess *fa = FileAccess::open(tmp_path,FileAccess::WRITE);
+						String skey=EditorImportExport::get_singleton()->script_get_encryption_key().to_lower();
+						Vector<uint8_t> key;
+						key.resize(32);
+						for(int i=0;i<32;i++) {
+							int v=0;
+							if (i*2<skey.length()) {
+								CharType ct = skey[i*2];
+								if (ct>='0' && ct<='9')
+									ct=ct-'0';
+								else if (ct>='a' && ct<='f')
+									ct=10+ct-'a';
+								v|=ct<<4;
+							}
+
+							if (i*2+1<skey.length()) {
+								CharType ct = skey[i*2+1];
+								if (ct>='0' && ct<='9')
+									ct=ct-'0';
+								else if (ct>='a' && ct<='f')
+									ct=10+ct-'a';
+								v|=ct;
+							}
+							key[i]=v;
+						}
+						FileAccessEncrypted *fae=memnew(FileAccessEncrypted);
+						Error err = fae->open_and_parse(fa,key,FileAccessEncrypted::MODE_WRITE_AES256);
+						if (err==OK) {
+
+							fae->store_buffer(file.ptr(),file.size());
+							p_path=p_path.basename()+".gde";
+						}
+
+						memdelete(fae);
+
+						file=FileAccess::get_file_as_array(tmp_path);
+						return file;
+
+
+					} else {
+
+						p_path=p_path.basename()+".gdc";
+						return file;
+					}
+				}
+
+			}
 		}
 		}
 
 
 		return Vector<uint8_t>();
 		return Vector<uint8_t>();

+ 139 - 1
modules/gridmap/grid_map.cpp

@@ -31,7 +31,9 @@
 #include "scene/resources/surface_tool.h"
 #include "scene/resources/surface_tool.h"
 #include "message_queue.h"
 #include "message_queue.h"
 #include "scene/3d/light.h"
 #include "scene/3d/light.h"
+#include "scene/3d/baked_light_instance.h"
 #include "io/marshalls.h"
 #include "io/marshalls.h"
+#include "scene/scene_string_names.h"
 
 
 
 
 bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
 bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
@@ -53,6 +55,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
 		set_center_z(p_value);
 		set_center_z(p_value);
 	} else if (name=="cell/scale") {
 	} else if (name=="cell/scale") {
 		set_cell_scale(p_value);
 		set_cell_scale(p_value);
+	} else if (name=="lighting/bake") {
+		set_use_baked_light(p_value);
 	} else if (name=="theme/bake") {
 	} else if (name=="theme/bake") {
 		set_bake(p_value);
 		set_bake(p_value);
 /*	} else if (name=="cells") {
 /*	} else if (name=="cells") {
@@ -120,6 +124,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
 				g.baked=b;
 				g.baked=b;
 				g.bake_instance=VS::get_singleton()->instance_create();;
 				g.bake_instance=VS::get_singleton()->instance_create();;
 				VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid());
 				VS::get_singleton()->instance_set_base(g.bake_instance,g.baked->get_rid());
+				VS::get_singleton()->instance_geometry_set_baked_light(g.bake_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID());
 			}
 			}
 		}
 		}
 
 
@@ -169,6 +174,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const {
 		r_ret= get_center_z();
 		r_ret= get_center_z();
 	} else if (name=="cell/scale") {
 	} else if (name=="cell/scale") {
 		r_ret= cell_scale;
 		r_ret= cell_scale;
+	} else if (name=="lighting/bake") {
+		r_ret=is_using_baked_light();
 	} else if (name=="theme/bake") {
 	} else if (name=="theme/bake") {
 		r_ret= bake;
 		r_ret= bake;
 	} else if (name=="data") {
 	} else if (name=="data") {
@@ -231,6 +238,7 @@ void GridMap::_get_property_list( List<PropertyInfo> *p_list) const {
 
 
 	p_list->push_back( PropertyInfo( Variant::OBJECT, "theme/theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"));
 	p_list->push_back( PropertyInfo( Variant::OBJECT, "theme/theme", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"));
 	p_list->push_back( PropertyInfo( Variant::BOOL, "theme/bake"));
 	p_list->push_back( PropertyInfo( Variant::BOOL, "theme/bake"));
+	p_list->push_back( PropertyInfo( Variant::BOOL, "lighting/bake"));
 	p_list->push_back( PropertyInfo( Variant::REAL, "cell/size",PROPERTY_HINT_RANGE,"0.01,16384,0.01") );
 	p_list->push_back( PropertyInfo( Variant::REAL, "cell/size",PROPERTY_HINT_RANGE,"0.01,16384,0.01") );
 	p_list->push_back( PropertyInfo( Variant::INT, "cell/octant_size",PROPERTY_HINT_RANGE,"1,1024,1") );
 	p_list->push_back( PropertyInfo( Variant::INT, "cell/octant_size",PROPERTY_HINT_RANGE,"1,1024,1") );
 	p_list->push_back( PropertyInfo( Variant::BOOL, "cell/center_x") );
 	p_list->push_back( PropertyInfo( Variant::BOOL, "cell/center_x") );
@@ -428,6 +436,8 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){
 		ii.multimesh->set_mesh(ii.mesh);
 		ii.multimesh->set_mesh(ii.mesh);
 		ii.multimesh_instance = VS::get_singleton()->instance_create();
 		ii.multimesh_instance = VS::get_singleton()->instance_create();
 		VS::get_singleton()->instance_set_base(ii.multimesh_instance,ii.multimesh->get_rid());
 		VS::get_singleton()->instance_set_base(ii.multimesh_instance,ii.multimesh->get_rid());
+		VS::get_singleton()->instance_geometry_set_baked_light(ii.multimesh_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID());
+
 		if (!baked_lock) {
 		if (!baked_lock) {
 
 
 			//unbake just in case
 			//unbake just in case
@@ -863,6 +873,12 @@ void GridMap::_notification(int p_what) {
 			awaiting_update=false;
 			awaiting_update=false;
 
 
 			last_transform=get_global_transform();
 			last_transform=get_global_transform();
+
+			if (use_baked_light) {
+
+				_find_baked_light();
+			}
+
 		} break;
 		} break;
 		case NOTIFICATION_TRANSFORM_CHANGED: {
 		case NOTIFICATION_TRANSFORM_CHANGED: {
 
 
@@ -883,6 +899,17 @@ void GridMap::_notification(int p_what) {
 				_octant_exit_world(E->key());
 				_octant_exit_world(E->key());
 			}
 			}
 
 
+			if (use_baked_light) {
+
+				if (baked_light_instance) {
+					baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
+					baked_light_instance=NULL;
+				}
+				_baked_light_changed();
+
+			}
+
+
 			//_queue_dirty_map(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
 			//_queue_dirty_map(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
 			//_update_dirty_map_callback();
 			//_update_dirty_map_callback();
 			//_update_area_instances();
 			//_update_area_instances();
@@ -1028,6 +1055,14 @@ void GridMap::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_unused_area_id","area"),&GridMap::get_unused_area_id);
 	ObjectTypeDB::bind_method(_MD("get_unused_area_id","area"),&GridMap::get_unused_area_id);
 	ObjectTypeDB::bind_method(_MD("bake_geometry"),&GridMap::bake_geometry);
 	ObjectTypeDB::bind_method(_MD("bake_geometry"),&GridMap::bake_geometry);
 
 
+	ObjectTypeDB::bind_method(_MD("_baked_light_changed"),&GridMap::_baked_light_changed);
+	ObjectTypeDB::bind_method(_MD("set_use_baked_light","use"),&GridMap::set_use_baked_light);
+	ObjectTypeDB::bind_method(_MD("is_using_baked_light","use"),&GridMap::is_using_baked_light);
+
+	ObjectTypeDB::bind_method(_MD("_get_baked_light_meshes"),&GridMap::_get_baked_light_meshes);
+
+
+
 	ObjectTypeDB::set_method_flags("GridMap","bake_geometry",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
 	ObjectTypeDB::set_method_flags("GridMap","bake_geometry",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
 
 
 	ObjectTypeDB::bind_method(_MD("clear"),&GridMap::clear);
 	ObjectTypeDB::bind_method(_MD("clear"),&GridMap::clear);
@@ -1496,6 +1531,108 @@ void GridMap::bake_geometry() {
 
 
 }
 }
 
 
+void GridMap::_baked_light_changed() {
+
+//	if (!baked_light_instance)
+//		VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),RID());
+//	else
+//		VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),baked_light_instance->get_baked_light_instance());
+	for(Map<OctantKey,Octant*>::Element *E=octant_map.front();E;E=E->next()) {
+
+		for(Map<int,Octant::ItemInstances>::Element *F=E->get()->items.front();F;F=F->next()) {
+
+			VS::get_singleton()->instance_geometry_set_baked_light(F->get().multimesh_instance,baked_light_instance?baked_light_instance->get_baked_light_instance():RID());
+		}
+
+	}
+
+}
+
+void GridMap::_find_baked_light() {
+
+	Node *n=get_parent();
+	while(n) {
+
+		BakedLightInstance *bl=n->cast_to<BakedLightInstance>();
+		if (bl) {
+
+			baked_light_instance=bl;
+			baked_light_instance->connect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
+			_baked_light_changed();
+
+			return;
+		}
+
+		n=n->get_parent();
+	}
+
+	_baked_light_changed();
+}
+
+
+Array GridMap::_get_baked_light_meshes() {
+
+	if (theme.is_null())
+		return Array();
+
+	Vector3 ofs(cell_size*0.5*int(center_x),cell_size*0.5*int(center_y),cell_size*0.5*int(center_z));
+	Array meshes;
+
+	for (Map<IndexKey,Cell>::Element *E=cell_map.front();E;E=E->next()) {
+
+
+		int id = E->get().item;
+		if (!theme->has_item(id))
+			continue;
+		Ref<Mesh> mesh=theme->get_item_mesh(id);
+		if (mesh.is_null())
+			continue;
+
+		IndexKey ik=E->key();
+
+		Vector3 cellpos = Vector3(ik.x,ik.y,ik.z );
+
+		Transform xform;
+
+		xform.basis.set_orthogonal_index(E->get().rot);
+
+
+		xform.set_origin( cellpos*cell_size+ofs);
+		xform.basis.scale(Vector3(cell_scale,cell_scale,cell_scale));
+
+		meshes.push_back(xform);
+		meshes.push_back(mesh);
+
+	}
+
+	return meshes;
+}
+
+void GridMap::set_use_baked_light(bool p_use) {
+
+	if (use_baked_light==p_use)
+		return;
+
+	use_baked_light=p_use;
+
+	if (is_inside_world()) {
+		if (!p_use) {
+			if (baked_light_instance) {
+				baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
+				baked_light_instance=NULL;
+			}
+			_baked_light_changed();
+		} else {
+			_find_baked_light();
+		}
+	}
+
+}
+
+bool GridMap::is_using_baked_light() const{
+
+	return use_baked_light;
+}
 
 
 
 
 GridMap::GridMap() {
 GridMap::GridMap() {
@@ -1516,7 +1653,8 @@ GridMap::GridMap() {
 	bake=false;
 	bake=false;
 	cell_scale=1.0;
 	cell_scale=1.0;
 
 
-
+	baked_light_instance=NULL;
+	use_baked_light=false;
 
 
 
 
 }
 }

+ 13 - 0
modules/gridmap/grid_map.h

@@ -38,6 +38,8 @@
 //should scale better with hardware that supports instancing
 //should scale better with hardware that supports instancing
 
 
 
 
+class BakedLightInstance;
+
 class GridMap : public Spatial {
 class GridMap : public Spatial {
 
 
 
 
@@ -202,6 +204,14 @@ class GridMap : public Spatial {
 
 
 	void _clear_internal(bool p_keep_areas=false);
 	void _clear_internal(bool p_keep_areas=false);
 
 
+	BakedLightInstance *baked_light_instance;
+	bool use_baked_light;
+	void _find_baked_light();
+	void _baked_light_changed();
+
+
+	Array _get_baked_light_meshes();
+
 protected:
 protected:
 
 
 	bool _set(const StringName& p_name, const Variant& p_value);
 	bool _set(const StringName& p_name, const Variant& p_value);
@@ -211,6 +221,7 @@ protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
 	static void _bind_methods();
 	static void _bind_methods();
 
 
+
 public:
 public:
 
 
 	enum {
 	enum {
@@ -262,6 +273,8 @@ public:
 
 
 	void bake_geometry();
 	void bake_geometry();
 
 
+	void set_use_baked_light(bool p_use);
+	bool is_using_baked_light() const;
 	void clear();
 	void clear();
 
 
 	GridMap();
 	GridMap();

+ 1 - 1
platform/javascript/detect.py

@@ -30,7 +30,7 @@ def get_flags():
 		('theora', 'no'),
 		('theora', 'no'),
 		('tools', 'no'),
 		('tools', 'no'),
 		('nedmalloc', 'no'),
 		('nedmalloc', 'no'),
-		('vorbis', 'yes'),
+		('vorbis', 'no'),
 		('musepack', 'no'),
 		('musepack', 'no'),
 		('squirrel', 'no'),
 		('squirrel', 'no'),
 		('squish', 'no'),
 		('squish', 'no'),

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

@@ -1,7 +0,0 @@
-#include "baked_light.h"
-#include "mesh_instance.h"
-
-BakedLight::BakedLight() {
-
-
-}

+ 0 - 15
scene/3d/baked_light.h

@@ -1,15 +0,0 @@
-#ifndef BAKED_LIGHT_H
-#define BAKED_LIGHT_H
-
-#include "scene/3d/spatial.h"
-class BakedLightBaker;
-
-
-class BakedLight : public Spatial {
-	OBJ_TYPE(BakedLight,Spatial);
-
-public:
-	BakedLight();
-};
-
-#endif // BAKED_LIGHT_H

+ 65 - 0
scene/3d/baked_light_instance.cpp

@@ -0,0 +1,65 @@
+#include "baked_light_instance.h"
+#include "scene/scene_string_names.h"
+
+
+RID BakedLightInstance::get_baked_light_instance() const {
+
+	if (baked_light.is_null())
+		return RID();
+	else
+		return get_instance();
+
+}
+
+void BakedLightInstance::set_baked_light(const Ref<BakedLight>& p_baked_light) {
+
+	baked_light=p_baked_light;	
+
+	RID base_rid;
+
+	if (baked_light.is_valid())
+		base_rid=baked_light->get_rid();
+	else
+		base_rid=RID();
+
+	set_base(base_rid);
+
+	if (is_inside_world()) {
+
+		emit_signal(SceneStringNames::get_singleton()->baked_light_changed);
+
+//		for (List<Node*>::Element *E=baked_geometry.front();E;E=E->next()) {
+//			VS::get_singleton()->instance_geometry_set_baked_light(E->get()->get_instance(),baked_light.is_valid()?get_instance():RID());
+//		}
+	}
+}
+
+Ref<BakedLight> BakedLightInstance::get_baked_light() const{
+
+	return baked_light;
+}
+
+AABB BakedLightInstance::get_aabb() const {
+
+	return AABB(Vector3(0,0,0),Vector3(1,1,1));
+}
+DVector<Face3> BakedLightInstance::get_faces(uint32_t p_usage_flags) const {
+
+	return DVector<Face3>();
+}
+
+
+void BakedLightInstance::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_baked_light","baked_light"),&BakedLightInstance::set_baked_light);
+	ObjectTypeDB::bind_method(_MD("get_baked_light"),&BakedLightInstance::get_baked_light);
+	ObjectTypeDB::bind_method(_MD("get_baked_light_instance"),&BakedLightInstance::get_baked_light_instance);
+
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"baked_light",PROPERTY_HINT_RESOURCE_TYPE,"BakedLight"),_SCS("set_baked_light"),_SCS("get_baked_light"));
+	ADD_SIGNAL( MethodInfo("baked_light_changed"));
+}
+
+BakedLightInstance::BakedLightInstance() {
+
+
+}

+ 33 - 0
scene/3d/baked_light_instance.h

@@ -0,0 +1,33 @@
+#ifndef BAKED_LIGHT_INSTANCE_H
+#define BAKED_LIGHT_INSTANCE_H
+
+#include "scene/3d/visual_instance.h"
+#include "scene/resources/baked_light.h"
+
+class BakedLightBaker;
+
+
+class BakedLightInstance : public VisualInstance {
+	OBJ_TYPE(BakedLightInstance,VisualInstance);
+
+	Ref<BakedLight> baked_light;
+
+
+protected:
+
+	static void _bind_methods();
+public:
+
+
+	RID get_baked_light_instance() const;
+
+	void set_baked_light(const Ref<BakedLight>& baked_light);
+	Ref<BakedLight> get_baked_light() const;
+
+	virtual AABB get_aabb() const;
+	virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+	BakedLightInstance();
+};
+
+#endif // BAKED_LIGHT_H

+ 32 - 0
scene/3d/light.cpp

@@ -351,6 +351,17 @@ void Light::set_operator(Operator p_op) {
 
 
 }
 }
 
 
+void Light::set_bake_mode(BakeMode p_bake_mode) {
+
+	bake_mode=p_bake_mode;
+}
+
+Light::BakeMode Light::get_bake_mode() const {
+
+	return bake_mode;
+}
+
+
 Light::Operator Light::get_operator() const {
 Light::Operator Light::get_operator() const {
 
 
 	return op;
 	return op;
@@ -416,6 +427,18 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo
 
 
 }
 }
 
 
+void Light::set_enabled(bool p_enabled) {
+
+	enabled=p_enabled;
+	VS::get_singleton()->instance_light_set_enabled(get_instance(),enabled);
+}
+
+bool Light::is_enabled() const{
+
+	return enabled;
+}
+
+
 void Light::_bind_methods() {
 void Light::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("set_parameter","variable","value"), &Light::set_parameter );
 	ObjectTypeDB::bind_method(_MD("set_parameter","variable","value"), &Light::set_parameter );
@@ -428,8 +451,14 @@ void Light::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_projector:Texture"), &Light::get_projector );
 	ObjectTypeDB::bind_method(_MD("get_projector:Texture"), &Light::get_projector );
 	ObjectTypeDB::bind_method(_MD("set_operator","operator"), &Light::set_operator );
 	ObjectTypeDB::bind_method(_MD("set_operator","operator"), &Light::set_operator );
 	ObjectTypeDB::bind_method(_MD("get_operator"), &Light::get_operator );
 	ObjectTypeDB::bind_method(_MD("get_operator"), &Light::get_operator );
+	ObjectTypeDB::bind_method(_MD("set_bake_mode","bake_mode"), &Light::set_bake_mode );
+	ObjectTypeDB::bind_method(_MD("get_bake_mode"), &Light::get_bake_mode );
+	ObjectTypeDB::bind_method(_MD("set_enabled","enabled"), &Light::set_enabled );
+	ObjectTypeDB::bind_method(_MD("is_enabled"), &Light::is_enabled );
 
 
 
 
+	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled"));
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY );
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY );
 	/*
 	/*
 	if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
 	if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
@@ -490,6 +519,8 @@ Light::Light(VisualServer::LightType p_type) {
 	op=OPERATOR_ADD;
 	op=OPERATOR_ADD;
 	set_project_shadows( false );
 	set_project_shadows( false );
 	set_base(light);
 	set_base(light);
+	enabled=true;
+	bake_mode=BAKE_MODE_DISABLED;
 
 
 }
 }
 
 
@@ -563,6 +594,7 @@ DirectionalLight::DirectionalLight() : Light( VisualServer::LIGHT_DIRECTIONAL )
 	shadow_param[SHADOW_PARAM_PSSM_SPLIT_WEIGHT]=0.5;
 	shadow_param[SHADOW_PARAM_PSSM_SPLIT_WEIGHT]=0.5;
 	shadow_param[SHADOW_PARAM_PSSM_ZOFFSET_SCALE]=2.0;
 	shadow_param[SHADOW_PARAM_PSSM_ZOFFSET_SCALE]=2.0;
 
 
+
 }
 }
 
 
 
 

+ 17 - 0
scene/3d/light.h

@@ -64,6 +64,14 @@ public:
 		COLOR_SPECULAR=VisualServer::LIGHT_COLOR_SPECULAR
 		COLOR_SPECULAR=VisualServer::LIGHT_COLOR_SPECULAR
 	};
 	};
 
 
+	enum BakeMode {
+
+		BAKE_MODE_DISABLED,
+		BAKE_MODE_INDIRECT,
+		BAKE_MODE_FULL
+
+	};
+
 
 
 	enum Operator {
 	enum Operator {
 
 
@@ -78,8 +86,10 @@ private:
 	Color colors[3];
 	Color colors[3];
 	
 	
 	
 	
+	BakeMode bake_mode;
 	VisualServer::LightType type;
 	VisualServer::LightType type;
 	bool shadows;
 	bool shadows;
+	bool enabled;
 	Operator op;
 	Operator op;
 	
 	
 // bind helpers
 // bind helpers
@@ -114,6 +124,12 @@ public:
 	void set_operator(Operator p_op);
 	void set_operator(Operator p_op);
 	Operator get_operator() const;
 	Operator get_operator() const;
 
 
+	void set_bake_mode(BakeMode p_bake_mode);
+	BakeMode get_bake_mode() const;
+
+	void set_enabled(bool p_enabled);
+	bool is_enabled() const;
+
 	virtual AABB get_aabb() const;
 	virtual AABB get_aabb() const;
 	virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
 	virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
 
 
@@ -127,6 +143,7 @@ public:
 VARIANT_ENUM_CAST( Light::Parameter );
 VARIANT_ENUM_CAST( Light::Parameter );
 VARIANT_ENUM_CAST( Light::LightColor );
 VARIANT_ENUM_CAST( Light::LightColor );
 VARIANT_ENUM_CAST( Light::Operator );
 VARIANT_ENUM_CAST( Light::Operator );
+VARIANT_ENUM_CAST( Light::BakeMode);
 
 
 
 
 class DirectionalLight : public Light {
 class DirectionalLight : public Light {

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

@@ -479,6 +479,7 @@ void Sprite3D::set_frame(int p_frame) {
 	if (frame != p_frame)
 	if (frame != p_frame)
 
 
 	frame=p_frame;
 	frame=p_frame;
+	_queue_update();
 }
 }
 
 
 int Sprite3D::get_frame() const {
 int Sprite3D::get_frame() const {

+ 2 - 2
scene/3d/sprite_3d.h

@@ -5,9 +5,9 @@
 #include "scene/2d/animated_sprite.h"
 #include "scene/2d/animated_sprite.h"
 
 
 
 
-class SpriteBase3D : public VisualInstance {
+class SpriteBase3D : public GeometryInstance {
 
 
-	OBJ_TYPE(SpriteBase3D,VisualInstance);
+	OBJ_TYPE(SpriteBase3D,GeometryInstance);
 public:
 public:
 
 
 	enum DrawFlags {
 	enum DrawFlags {

+ 75 - 3
scene/3d/visual_instance.cpp

@@ -31,7 +31,7 @@
 #include "servers/visual_server.h"
 #include "servers/visual_server.h"
 #include "room_instance.h"
 #include "room_instance.h"
 #include "scene/scene_string_names.h"
 #include "scene/scene_string_names.h"
-
+#include "baked_light_instance.h"
 #include "skeleton.h"
 #include "skeleton.h"
 
 
 AABB VisualInstance::get_transformed_aabb() const {
 AABB VisualInstance::get_transformed_aabb() const {
@@ -186,6 +186,61 @@ float GeometryInstance::get_draw_range_end() const {
 	return draw_end;
 	return draw_end;
 }
 }
 
 
+void GeometryInstance::_notification(int p_what) {
+
+	if (p_what==NOTIFICATION_ENTER_WORLD) {
+
+		if (flags[FLAG_USE_BAKED_LIGHT]) {
+
+			_find_baked_light();
+		}
+
+
+	} else if (p_what==NOTIFICATION_EXIT_WORLD) {
+
+		if (flags[FLAG_USE_BAKED_LIGHT]) {
+
+			if (baked_light_instance) {
+				baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
+				baked_light_instance=NULL;
+			}
+			_baked_light_changed();
+
+		}
+	}
+
+}
+
+void GeometryInstance::_baked_light_changed() {
+
+	if (!baked_light_instance)
+		VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),RID());
+	else
+		VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),baked_light_instance->get_baked_light_instance());
+
+}
+
+void GeometryInstance::_find_baked_light() {
+
+	Node *n=get_parent();
+	while(n) {
+
+		BakedLightInstance *bl=n->cast_to<BakedLightInstance>();
+		if (bl) {
+
+			baked_light_instance=bl;
+			baked_light_instance->connect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
+			_baked_light_changed();
+
+			return;
+		}
+
+		n=n->get_parent();
+	}
+
+	_baked_light_changed();
+}
+
 void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
 void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
 
 
 	ERR_FAIL_INDEX(p_flag,FLAG_MAX);
 	ERR_FAIL_INDEX(p_flag,FLAG_MAX);
@@ -198,8 +253,20 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
 		_change_notify("geometry/visible");
 		_change_notify("geometry/visible");
 		emit_signal(SceneStringNames::get_singleton()->visibility_changed);
 		emit_signal(SceneStringNames::get_singleton()->visibility_changed);
 	}
 	}
-
-
+	if (p_flag==FLAG_USE_BAKED_LIGHT) {
+
+		if (is_inside_world()) {
+			if (!p_value) {
+				if (baked_light_instance) {
+					baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
+					baked_light_instance=NULL;
+				}
+				_baked_light_changed();
+			} else {
+				_find_baked_light();
+			}
+		}
+	}
 }
 }
 
 
 bool GeometryInstance::get_flag(Flags p_flag) const{
 bool GeometryInstance::get_flag(Flags p_flag) const{
@@ -224,6 +291,8 @@ void GeometryInstance::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end);
 	ObjectTypeDB::bind_method(_MD("set_draw_range_end","mode"), &GeometryInstance::set_draw_range_end);
 	ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end);
 	ObjectTypeDB::bind_method(_MD("get_draw_range_end"), &GeometryInstance::get_draw_range_end);
 
 
+	ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
+
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
 	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override"));
 	ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override"));
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/cast_shadow"), _SCS("set_flag"), _SCS("get_flag"),FLAG_CAST_SHADOW);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/cast_shadow"), _SCS("set_flag"), _SCS("get_flag"),FLAG_CAST_SHADOW);
@@ -234,6 +303,7 @@ void GeometryInstance::_bind_methods() {
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/billboard_y"), _SCS("set_flag"), _SCS("get_flag"),FLAG_BILLBOARD_FIX_Y);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS);
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS);
+	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
 
 
 	ADD_SIGNAL( MethodInfo("visibility_changed"));
 	ADD_SIGNAL( MethodInfo("visibility_changed"));
 
 
@@ -258,5 +328,7 @@ GeometryInstance::GeometryInstance() {
 	flags[FLAG_BILLBOARD_FIX_Y]=false;
 	flags[FLAG_BILLBOARD_FIX_Y]=false;
 	flags[FLAG_DEPH_SCALE]=false;
 	flags[FLAG_DEPH_SCALE]=false;
 	flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
 	flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
+	baked_light_instance=NULL;
+
 
 
 }
 }

+ 8 - 1
scene/3d/visual_instance.h

@@ -78,6 +78,8 @@ public:
 
 
 };
 };
 
 
+class BakedLightInstance;
+
 class GeometryInstance : public VisualInstance {
 class GeometryInstance : public VisualInstance {
 
 
 	OBJ_TYPE( GeometryInstance, VisualInstance );
 	OBJ_TYPE( GeometryInstance, VisualInstance );
@@ -91,7 +93,7 @@ public:
 		FLAG_BILLBOARD_FIX_Y=VS::INSTANCE_FLAG_BILLBOARD_FIX_Y,
 		FLAG_BILLBOARD_FIX_Y=VS::INSTANCE_FLAG_BILLBOARD_FIX_Y,
 		FLAG_DEPH_SCALE=VS::INSTANCE_FLAG_DEPH_SCALE,
 		FLAG_DEPH_SCALE=VS::INSTANCE_FLAG_DEPH_SCALE,
 		FLAG_VISIBLE_IN_ALL_ROOMS=VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
 		FLAG_VISIBLE_IN_ALL_ROOMS=VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
-		FLAG_USE_BAKED_LIGHT_VOLUME=VS::INSTANCE_FLAG_USE_BAKED_LIGHT_VOLUME,
+		FLAG_USE_BAKED_LIGHT=VS::INSTANCE_FLAG_USE_BAKED_LIGHT,
 		FLAG_MAX=VS::INSTANCE_FLAG_MAX,
 		FLAG_MAX=VS::INSTANCE_FLAG_MAX,
 	};
 	};
 
 
@@ -102,8 +104,13 @@ private:
 	Ref<Material> material_override;
 	Ref<Material> material_override;
 	float draw_begin;
 	float draw_begin;
 	float draw_end;
 	float draw_end;
+	void _find_baked_light();
+	BakedLightInstance *baked_light_instance;
+
+	void _baked_light_changed();
 protected:
 protected:
 
 
+	void _notification(int p_what);
 	static void _bind_methods();
 	static void _bind_methods();
 public:
 public:
 
 

+ 3 - 2
scene/register_scene_types.cpp

@@ -187,7 +187,7 @@
 #include "scene/3d/area.h"
 #include "scene/3d/area.h"
 #include "scene/3d/physics_joint.h"
 #include "scene/3d/physics_joint.h"
 #include "scene/3d/multimesh_instance.h"
 #include "scene/3d/multimesh_instance.h"
-#include "scene/3d/baked_light.h"
+#include "scene/3d/baked_light_instance.h"
 #include "scene/3d/ray_cast.h"
 #include "scene/3d/ray_cast.h"
 #include "scene/3d/immediate_geometry.h"
 #include "scene/3d/immediate_geometry.h"
 #include "scene/3d/sprite_3d.h"
 #include "scene/3d/sprite_3d.h"
@@ -407,7 +407,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<PathFollow>();
 	ObjectTypeDB::register_type<PathFollow>();
 	ObjectTypeDB::register_type<VisibilityNotifier>();
 	ObjectTypeDB::register_type<VisibilityNotifier>();
 	ObjectTypeDB::register_type<VisibilityEnabler>();
 	ObjectTypeDB::register_type<VisibilityEnabler>();
-	ObjectTypeDB::register_type<BakedLight>();
+	ObjectTypeDB::register_type<BakedLightInstance>();
 	ObjectTypeDB::register_type<WorldEnvironment>();
 	ObjectTypeDB::register_type<WorldEnvironment>();
 
 
 	//scenariofx	
 	//scenariofx	
@@ -515,6 +515,7 @@ void register_scene_types() {
 
 
 	ObjectTypeDB::register_type<SurfaceTool>();
 	ObjectTypeDB::register_type<SurfaceTool>();
 	ObjectTypeDB::register_type<MeshDataTool>();
 	ObjectTypeDB::register_type<MeshDataTool>();
+	ObjectTypeDB::register_type<BakedLight>();
 
 
 	OS::get_singleton()->yield(); //may take time to init
 	OS::get_singleton()->yield(); //may take time to init
 
 

+ 308 - 0
scene/resources/baked_light.cpp

@@ -0,0 +1,308 @@
+#include "baked_light.h"
+#include "servers/visual_server.h"
+
+void BakedLight::set_mode(Mode p_mode) {
+
+	mode=p_mode;
+	VS::get_singleton()->baked_light_set_mode(baked_light,(VS::BakedLightMode(p_mode)));
+}
+
+BakedLight::Mode BakedLight::get_mode() const{
+
+	return mode;
+}
+
+void BakedLight::set_octree(const DVector<uint8_t>& p_octree) {
+
+	VS::get_singleton()->baked_light_set_octree(baked_light,p_octree);
+}
+
+DVector<uint8_t> BakedLight::get_octree() const {
+
+	return VS::get_singleton()->baked_light_get_octree(baked_light);
+}
+
+
+void BakedLight::_update_lightmaps() {
+
+	VS::get_singleton()->baked_light_clear_lightmaps(baked_light);
+	for(Map<int,Ref<Texture> >::Element *E=lightmaps.front();E;E=E->next()) {
+
+		VS::get_singleton()->baked_light_add_lightmap(baked_light,E->get()->get_rid(),E->key());
+	}
+
+}
+
+void BakedLight::add_lightmap(const Ref<Texture> p_texture,int p_id) {
+
+	ERR_FAIL_COND(!p_texture.is_valid());
+	ERR_FAIL_COND(p_id<0);
+	lightmaps[p_id]=p_texture;
+	VS::get_singleton()->baked_light_add_lightmap(baked_light,p_texture->get_rid(),p_id);
+}
+
+void BakedLight::erase_lightmap(int p_id) {
+
+	ERR_FAIL_COND(!lightmaps.has(p_id));
+	lightmaps.erase(p_id);
+	_update_lightmaps();
+}
+
+void BakedLight::get_lightmaps(List<int> *r_lightmaps) {
+
+	for(Map<int,Ref<Texture> >::Element *E=lightmaps.front();E;E=E->next()) {
+
+		r_lightmaps->push_back(E->key());
+	}
+
+}
+
+Ref<Texture> BakedLight::get_lightmap_texture(int p_id) {
+
+	if (!lightmaps.has(p_id))
+		return Ref<Texture>();
+
+	return lightmaps[p_id];
+
+
+}
+
+void BakedLight::clear_lightmaps() {
+
+	lightmaps.clear();
+	_update_lightmaps();
+}
+
+RID BakedLight::get_rid() const {
+
+	return baked_light;
+}
+
+Array BakedLight::_get_lightmap_data() const {
+
+	Array ret;
+	ret.resize(lightmaps.size()*2);
+
+	int idx=0;
+	for(Map<int,Ref<Texture> >::Element *E=lightmaps.front();E;E=E->next()) {
+
+		ret[idx++]=E->key();
+		ret[idx++]=E->get();
+	}
+
+	return ret;
+
+}
+
+void BakedLight::_set_lightmap_data(Array p_array){
+
+	lightmaps.clear();
+	for(int i=0;i<p_array.size();i+=2) {
+
+		int id = p_array[i];
+		Ref<Texture> tex = p_array[i+1];
+		ERR_CONTINUE(id<0);
+		ERR_CONTINUE(tex.is_null());
+		lightmaps[id]=tex;
+	}
+	_update_lightmaps();
+}
+
+
+void BakedLight::set_cell_subdivision(int p_subdiv) {
+
+	cell_subdiv=p_subdiv;
+}
+
+int BakedLight::get_cell_subdivision() const{
+
+	return cell_subdiv;
+}
+
+void BakedLight::set_initial_lattice_subdiv(int p_size){
+
+	lattice_subdiv=p_size;
+}
+int BakedLight::get_initial_lattice_subdiv() const{
+
+	return lattice_subdiv;
+}
+
+void BakedLight::set_plot_size(float p_size){
+
+	plot_size=p_size;
+}
+float BakedLight::get_plot_size() const{
+
+	return plot_size;
+}
+
+void BakedLight::set_bounces(int p_size){
+
+	bounces=p_size;
+}
+int BakedLight::get_bounces() const{
+
+	return bounces;
+}
+
+void BakedLight::set_cell_extra_margin(float p_margin) {
+	cell_extra_margin=p_margin;
+}
+
+float BakedLight::get_cell_extra_margin() const {
+
+	return cell_extra_margin;
+}
+
+void BakedLight::set_edge_damp(float p_margin) {
+	edge_damp=p_margin;
+}
+
+float BakedLight::get_edge_damp() const {
+
+	return edge_damp;
+}
+
+
+void BakedLight::set_normal_damp(float p_margin) {
+	normal_damp=p_margin;
+}
+
+float BakedLight::get_normal_damp() const {
+
+	return normal_damp;
+}
+
+void BakedLight::set_energy_multiplier(float p_multiplier){
+
+	energy_multiply=p_multiplier;
+}
+float BakedLight::get_energy_multiplier() const{
+
+	return energy_multiply;
+}
+
+void BakedLight::set_gamma_adjust(float p_adjust){
+
+	gamma_adjust=p_adjust;
+}
+float BakedLight::get_gamma_adjust() const{
+
+	return gamma_adjust;
+}
+
+void BakedLight::set_bake_flag(BakeFlags p_flags,bool p_enable){
+
+	flags[p_flags]=p_enable;
+}
+bool BakedLight::get_bake_flag(BakeFlags p_flags) const{
+
+	return flags[p_flags];
+}
+
+
+
+void BakedLight::_bind_methods(){
+
+
+	ObjectTypeDB::bind_method(_MD("set_mode","mode"),&BakedLight::set_mode);
+	ObjectTypeDB::bind_method(_MD("get_mode"),&BakedLight::get_mode);
+
+	ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree);
+	ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree);
+
+	ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","id"),&BakedLight::add_lightmap);
+	ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap);
+	ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps);
+
+	ObjectTypeDB::bind_method(_MD("_set_lightmap_data","lightmap_data"),&BakedLight::_set_lightmap_data);
+	ObjectTypeDB::bind_method(_MD("_get_lightmap_data"),&BakedLight::_get_lightmap_data);
+
+	ObjectTypeDB::bind_method(_MD("set_cell_subdivision","cell_subdivision"),&BakedLight::set_cell_subdivision);
+	ObjectTypeDB::bind_method(_MD("get_cell_subdivision"),&BakedLight::get_cell_subdivision);
+
+	ObjectTypeDB::bind_method(_MD("set_initial_lattice_subdiv","cell_subdivision"),&BakedLight::set_initial_lattice_subdiv);
+	ObjectTypeDB::bind_method(_MD("get_initial_lattice_subdiv","cell_subdivision"),&BakedLight::get_initial_lattice_subdiv);
+
+	ObjectTypeDB::bind_method(_MD("set_plot_size","plot_size"),&BakedLight::set_plot_size);
+	ObjectTypeDB::bind_method(_MD("get_plot_size"),&BakedLight::get_plot_size);
+
+	ObjectTypeDB::bind_method(_MD("set_bounces","bounces"),&BakedLight::set_bounces);
+	ObjectTypeDB::bind_method(_MD("get_bounces"),&BakedLight::get_bounces);
+
+	ObjectTypeDB::bind_method(_MD("set_cell_extra_margin","cell_extra_margin"),&BakedLight::set_cell_extra_margin);
+	ObjectTypeDB::bind_method(_MD("get_cell_extra_margin"),&BakedLight::get_cell_extra_margin);
+
+	ObjectTypeDB::bind_method(_MD("set_edge_damp","edge_damp"),&BakedLight::set_edge_damp);
+	ObjectTypeDB::bind_method(_MD("get_edge_damp"),&BakedLight::get_edge_damp);
+
+	ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp);
+	ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp);
+
+	ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier);
+	ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier);
+
+	ObjectTypeDB::bind_method(_MD("set_gamma_adjust","gamma_adjust"),&BakedLight::set_gamma_adjust);
+	ObjectTypeDB::bind_method(_MD("get_gamma_adjust"),&BakedLight::get_gamma_adjust);
+
+	ObjectTypeDB::bind_method(_MD("set_bake_flag","flag","enabled"),&BakedLight::set_bake_flag);
+	ObjectTypeDB::bind_method(_MD("get_bake_flag","flag"),&BakedLight::get_bake_flag);
+
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Octree,Lightmaps"),_SCS("set_mode"),_SCS("get_mode"));
+
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/cell_subdiv",PROPERTY_HINT_RANGE,"4,14,1"),_SCS("set_cell_subdivision"),_SCS("get_cell_subdivision"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/lattice_subdiv",PROPERTY_HINT_RANGE,"1,5,1"),_SCS("set_initial_lattice_subdiv"),_SCS("get_initial_lattice_subdiv"));
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/light_bounces",PROPERTY_HINT_RANGE,"0,3,1"),_SCS("set_bounces"),_SCS("get_bounces"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust"));
+	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE);
+	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR);
+	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT);
+	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY);
+
+	ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree"));
+	ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp"));
+
+	BIND_CONSTANT(  MODE_OCTREE );
+	BIND_CONSTANT(  MODE_LIGHTMAPS );
+
+	BIND_CONSTANT(  BAKE_DIFFUSE );
+	BIND_CONSTANT(  BAKE_SPECULAR );
+	BIND_CONSTANT(  BAKE_TRANSLUCENT );
+	BIND_CONSTANT(  BAKE_CONSERVE_ENERGY );
+	BIND_CONSTANT(  BAKE_MAX );
+
+
+}
+
+
+BakedLight::BakedLight() {
+
+	cell_subdiv=8;
+	lattice_subdiv=4;
+	plot_size=2.5;
+	bounces=1;
+	energy_multiply=1.0;
+	gamma_adjust=1.0;
+	cell_extra_margin=0.05;
+	edge_damp=0.0;
+	normal_damp=0.0;
+
+	flags[BAKE_DIFFUSE]=true;
+	flags[BAKE_SPECULAR]=false;
+	flags[BAKE_TRANSLUCENT]=true;
+	flags[BAKE_CONSERVE_ENERGY]=false;
+
+	mode=MODE_OCTREE;
+	baked_light=VS::get_singleton()->baked_light_create();
+}
+
+BakedLight::~BakedLight() {
+
+	VS::get_singleton()->free(baked_light);
+}

+ 106 - 0
scene/resources/baked_light.h

@@ -0,0 +1,106 @@
+#ifndef BAKED_LIGHT_H
+#define BAKED_LIGHT_H
+
+#include "resource.h"
+#include "scene/resources/texture.h"
+
+class BakedLight : public Resource {
+
+	OBJ_TYPE( BakedLight, Resource);
+public:
+	enum Mode {
+
+		MODE_OCTREE,
+		MODE_LIGHTMAPS
+	};
+
+	enum BakeFlags {
+		BAKE_DIFFUSE,
+		BAKE_SPECULAR,
+		BAKE_TRANSLUCENT,
+		BAKE_CONSERVE_ENERGY,
+		BAKE_MAX
+	};
+
+private:
+
+	RID baked_light;
+	Mode mode;
+	Map<int,Ref<Texture> > lightmaps;
+
+	//bake vars
+	int cell_subdiv;
+	int lattice_subdiv;
+	float plot_size;
+	float energy_multiply;
+	float gamma_adjust;
+	float cell_extra_margin;
+	float edge_damp;
+	float normal_damp;
+	int bounces;
+	bool flags[BAKE_MAX];
+
+
+
+	void _update_lightmaps();
+
+	Array _get_lightmap_data() const;
+	void _set_lightmap_data(Array p_array);
+	static void _bind_methods();
+
+public:
+
+	void set_cell_subdivision(int p_subdiv);
+	int get_cell_subdivision() const;
+
+	void set_initial_lattice_subdiv(int p_size);
+	int get_initial_lattice_subdiv() const;
+
+	void set_plot_size(float p_size);
+	float get_plot_size() const;
+
+	void set_bounces(int p_size);
+	int get_bounces() const;
+
+	void set_energy_multiplier(float p_multiplier);
+	float get_energy_multiplier() const;
+
+	void set_gamma_adjust(float p_adjust);
+	float get_gamma_adjust() const;
+
+	void set_cell_extra_margin(float p_margin);
+	float get_cell_extra_margin() const;
+
+	void set_edge_damp(float p_margin);
+	float get_edge_damp() const;
+
+	void set_normal_damp(float p_margin);
+	float get_normal_damp() const;
+
+	void set_bake_flag(BakeFlags p_flags,bool p_enable);
+	bool get_bake_flag(BakeFlags p_flags) const;
+
+
+	void set_mode(Mode p_mode);
+	Mode get_mode() const;
+
+	void set_octree(const DVector<uint8_t>& p_octree);
+	DVector<uint8_t> get_octree() const;
+
+	void add_lightmap(const Ref<Texture> p_texture,int p_id);
+	void erase_lightmap(int p_id);
+	void get_lightmaps(List<int> *r_lightmaps);
+	Ref<Texture> get_lightmap_texture(int p_id);
+	void clear_lightmaps();
+
+	virtual RID get_rid() const;
+
+	BakedLight();
+	~BakedLight();
+};
+
+
+VARIANT_ENUM_CAST(BakedLight::Mode);
+VARIANT_ENUM_CAST(BakedLight::BakeFlags);
+
+#endif // BAKED_LIGHT_H

+ 4 - 0
scene/scene_string_names.cpp

@@ -140,4 +140,8 @@ SceneStringNames::SceneStringNames() {
 	_im_update = StaticCString::create("_im_update");
 	_im_update = StaticCString::create("_im_update");
 	_queue_update = StaticCString::create("_queue_update");
 	_queue_update = StaticCString::create("_queue_update");
 
 
+	baked_light_changed = StaticCString::create("baked_light_changed");
+	_baked_light_changed = StaticCString::create("_baked_light_changed");
+
+
 }
 }

+ 3 - 0
scene/scene_string_names.h

@@ -148,6 +148,9 @@ public:
 	StringName _im_update;
 	StringName _im_update;
 	StringName _queue_update;
 	StringName _queue_update;
 
 
+	StringName baked_light_changed;
+	StringName _baked_light_changed;
+
 
 
 };
 };
 
 

+ 21 - 0
servers/visual/rasterizer.h

@@ -302,6 +302,11 @@ public:
 	virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible)=0;
 	virtual void multimesh_set_visible_instances(RID p_multimesh,int p_visible)=0;
 	virtual int multimesh_get_visible_instances(RID p_multimesh) const=0;
 	virtual int multimesh_get_visible_instances(RID p_multimesh) const=0;
 
 
+	/* BAKED LIGHT */
+
+
+
+
 	/* IMMEDIATE API */
 	/* IMMEDIATE API */
 
 
 	virtual RID immediate_create()=0;
 	virtual RID immediate_create()=0;
@@ -490,6 +495,20 @@ public:
 	
 	
 	typedef Map<StringName,Variant> ParamOverrideMap;
 	typedef Map<StringName,Variant> ParamOverrideMap;
 
 
+	struct BakedLightData {
+
+		VS::BakedLightMode mode;
+		RID octree_texture;
+		float color_multiplier; //used for both lightmaps and octree
+		Transform octree_transform;
+		Map<int,RID> lightmaps;
+		//cache
+
+		float octree_lattice_size;
+		float octree_lattice_divide;
+		int octree_steps;
+		Vector2 octree_tex_pixel_size;
+	};
 
 
 	struct InstanceData {
 	struct InstanceData {
 
 
@@ -498,6 +517,8 @@ public:
 		RID material_override;
 		RID material_override;
 		Vector<RID> light_instances;
 		Vector<RID> light_instances;
 		Vector<float> morph_values;
 		Vector<float> morph_values;
+		BakedLightData *baked_light;
+		Transform *baked_light_octree_xform;
 		bool mirror :8;
 		bool mirror :8;
 		bool depth_scale :8;
 		bool depth_scale :8;
 		bool billboard :8;
 		bool billboard :8;

+ 300 - 9
servers/visual/visual_server_raster.cpp

@@ -31,6 +31,7 @@
 #include "globals.h"
 #include "globals.h"
 #include "default_mouse_cursor.xpm"
 #include "default_mouse_cursor.xpm"
 #include "sort.h"
 #include "sort.h"
+#include "io/marshalls.h"
 // careful, these may run in different threads than the visual server
 // careful, these may run in different threads than the visual server
 
 
 BalloonAllocator<> *VisualServerRaster::OctreeAllocator::allocator=NULL;
 BalloonAllocator<> *VisualServerRaster::OctreeAllocator::allocator=NULL;
@@ -921,6 +922,7 @@ void VisualServerRaster::room_set_bounds(RID p_room, const BSP_Tree& p_bounds) {
 	Room *room = room_owner.get(p_room);
 	Room *room = room_owner.get(p_room);
 	ERR_FAIL_COND(!room);
 	ERR_FAIL_COND(!room);
 	room->bounds=p_bounds;
 	room->bounds=p_bounds;
+	_dependency_queue_update(p_room,true);
 
 
 }
 }
 
 
@@ -1032,6 +1034,138 @@ float VisualServerRaster::portal_get_connect_range(RID p_portal) const {
 }
 }
 
 
 
 
+RID VisualServerRaster::baked_light_create() {
+
+	BakedLight *baked_light = memnew( BakedLight );
+	ERR_FAIL_COND_V(!baked_light,RID());
+	baked_light->data.mode=BAKED_LIGHT_OCTREE;
+
+	baked_light->data.octree_lattice_size=0;
+	baked_light->data.octree_lattice_divide=0;
+	baked_light->data.octree_steps=1;
+
+	return baked_light_owner.make_rid( baked_light );
+
+}
+
+void VisualServerRaster::baked_light_set_mode(RID p_baked_light,BakedLightMode p_mode){
+
+	VS_CHANGED;
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+	baked_light->data.mode=p_mode;
+	baked_light->data.color_multiplier=1.0;
+	_dependency_queue_update(p_baked_light,true);
+
+
+}
+
+VisualServer::BakedLightMode VisualServerRaster::baked_light_get_mode(RID p_baked_light) const{
+
+	const BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND_V(!baked_light,BAKED_LIGHT_OCTREE);
+	return baked_light->data.mode;
+
+}
+
+void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree){
+
+	VS_CHANGED;
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+
+	if (p_octree.size()==0) {
+		if (baked_light->data.octree_texture.is_valid())
+			rasterizer->free(baked_light->data.octree_texture);
+		baked_light->data.octree_texture=RID();
+		baked_light->octree_aabb=AABB();
+		baked_light->octree_tex_size=Size2();
+	} else {
+
+		int tex_w;
+		int tex_h;
+		bool is16;
+		{
+			DVector<uint8_t>::Read r=p_octree.read();
+			tex_w = decode_uint32(&r[0]);
+			tex_h = decode_uint32(&r[4]);
+			print_line("TEX W: "+itos(tex_w)+" TEX H:"+itos(tex_h)+" LEN: "+itos(p_octree.size()));
+			is16=decode_uint32(&r[8]);
+			baked_light->data.octree_lattice_size=decode_float(&r[12]);
+			baked_light->data.octree_lattice_divide=tex_w/4.0;
+			print_line("LATTICE SIZE: "+rtos(baked_light->data.octree_lattice_size));
+			print_line("LATTICE DIVIDE: "+rtos(baked_light->data.octree_lattice_divide));
+			baked_light->data.octree_steps=decode_uint32(&r[16]);
+			baked_light->data.octree_tex_pixel_size.x=1.0/tex_w;
+			baked_light->data.octree_tex_pixel_size.y=1.0/tex_h;
+
+
+			baked_light->octree_aabb.pos.x=decode_float(&r[32]);
+			baked_light->octree_aabb.pos.y=decode_float(&r[36]);
+			baked_light->octree_aabb.pos.z=decode_float(&r[40]);
+			baked_light->octree_aabb.size.x=decode_float(&r[44]);
+			baked_light->octree_aabb.size.y=decode_float(&r[48]);
+			baked_light->octree_aabb.size.z=decode_float(&r[52]);
+
+
+		}
+
+		if (baked_light->data.octree_texture.is_valid()) {
+			if (tex_w!=baked_light->octree_tex_size.x || tex_h!=baked_light->octree_tex_size.y) {
+
+				rasterizer->free(baked_light->data.octree_texture);
+				baked_light->data.octree_texture=RID();
+			}
+		}
+
+		if (!baked_light->data.octree_texture.is_valid()) {
+			baked_light->data.octree_texture=rasterizer->texture_create();
+			rasterizer->texture_allocate(baked_light->data.octree_texture,tex_w,tex_h,Image::FORMAT_RGBA,TEXTURE_FLAG_FILTER);
+		}
+
+		Image img(tex_w,tex_h,0,Image::FORMAT_RGBA,p_octree);
+		rasterizer->texture_set_data(baked_light->data.octree_texture,img);
+
+	}
+
+
+	_dependency_queue_update(p_baked_light,true);
+
+}
+
+DVector<uint8_t> VisualServerRaster::baked_light_get_octree(RID p_baked_light) const{
+
+
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND_V(!baked_light,DVector<uint8_t>());
+
+	if (rasterizer->is_texture(baked_light->data.octree_texture)) {
+
+		Image img = rasterizer->texture_get_data(baked_light->data.octree_texture);
+		return img.get_data();
+	} else {
+		return DVector<uint8_t>();
+	}
+}
+
+void VisualServerRaster::baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id){
+
+	VS_CHANGED;
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+	baked_light->data.lightmaps.insert(p_id,p_texture);
+
+}
+void VisualServerRaster::baked_light_clear_lightmaps(RID p_baked_light){
+
+	VS_CHANGED;
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+	baked_light->data.lightmaps.clear();
+
+}
+
+
 /* CAMERA API */
 /* CAMERA API */
 
 
 RID VisualServerRaster::camera_create() {
 RID VisualServerRaster::camera_create() {
@@ -1710,6 +1844,23 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) {
 
 
 		}
 		}
 
 
+		if (instance->baked_light_info) {
+
+			while(instance->baked_light_info->owned_instances.size()) {
+
+				Instance *owned=instance->baked_light_info->owned_instances.front()->get();
+				owned->baked_light=NULL;
+				owned->data.baked_light=NULL;
+				owned->data.baked_light_octree_xform=NULL;
+				owned->BLE=NULL;
+				instance->baked_light_info->owned_instances.pop_front();
+			}
+
+			memdelete(instance->baked_light_info);
+			instance->baked_light_info=NULL;
+
+		}
+
 		if (instance->scenario && instance->octree_id) {
 		if (instance->scenario && instance->octree_id) {
 			instance->scenario->octree.erase( instance->octree_id );
 			instance->scenario->octree.erase( instance->octree_id );
 			instance->octree_id=0;
 			instance->octree_id=0;
@@ -1796,6 +1947,14 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) {
 			instance->base_type=INSTANCE_PORTAL;
 			instance->base_type=INSTANCE_PORTAL;
 			instance->portal_info = memnew(Instance::PortalInfo);
 			instance->portal_info = memnew(Instance::PortalInfo);
 			instance->portal_info->portal=portal_owner.get(p_base);
 			instance->portal_info->portal=portal_owner.get(p_base);
+		} else if (baked_light_owner.owns(p_base)) {
+
+			instance->base_type=INSTANCE_BAKED_LIGHT;
+			instance->baked_light_info=memnew(Instance::BakedLightInfo);
+			instance->baked_light_info->baked_light=baked_light_owner.get(p_base);
+
+			//instance->portal_info = memnew(Instance::PortalInfo);
+			//instance->portal_info->portal=portal_owner.get(p_base);
 		} else {
 		} else {
 			ERR_EXPLAIN("Invalid base RID for instance!")
 			ERR_EXPLAIN("Invalid base RID for instance!")
 			ERR_FAIL();
 			ERR_FAIL();
@@ -2365,6 +2524,68 @@ float VisualServerRaster::instance_geometry_get_draw_range_max(RID p_instance) c
 
 
 }
 }
 
 
+
+void VisualServerRaster::instance_geometry_set_baked_light(RID p_instance,RID p_baked_light) {
+
+	VS_CHANGED;
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+
+	if (instance->baked_light) {
+
+
+		instance->baked_light->baked_light_info->owned_instances.erase(instance->BLE);
+		instance->BLE=NULL;
+		instance->baked_light=NULL;
+		instance->data.baked_light=NULL;
+		instance->data.baked_light_octree_xform=NULL;
+
+	}
+
+	if (!p_baked_light.is_valid())
+		return;
+	Instance *bl_instance = instance_owner.get( p_baked_light );
+	ERR_FAIL_COND( !bl_instance );
+	ERR_FAIL_COND( bl_instance->base_type!=INSTANCE_BAKED_LIGHT );
+
+	instance->baked_light=bl_instance;
+	instance->BLE=bl_instance->baked_light_info->owned_instances.push_back(instance);
+	instance->data.baked_light=&bl_instance->baked_light_info->baked_light->data;
+	instance->data.baked_light_octree_xform=&bl_instance->baked_light_info->affine_inverse;
+
+}
+
+RID VisualServerRaster::instance_geometry_get_baked_light(RID p_instance) const{
+
+	const Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND_V( !instance,RID() );
+	if (instance->baked_light)
+		instance->baked_light->self;
+	return RID();
+
+}
+
+void VisualServerRaster::instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id){
+
+	VS_CHANGED;
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	instance->lightmap_texture_index=p_tex_id;
+
+
+}
+int VisualServerRaster::instance_geometry_get_baked_light_texture_index(RID p_instance) const{
+
+	const Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND_V( !instance,0 );
+
+	return instance->lightmap_texture_index;
+
+}
+
+
 void VisualServerRaster::_update_instance(Instance *p_instance) {
 void VisualServerRaster::_update_instance(Instance *p_instance) {
 
 
 	p_instance->version++;
 	p_instance->version++;
@@ -2385,7 +2606,7 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
 	}
 	}
 		
 		
 
 
-	if (p_instance->base_type&INSTANCE_GEOMETRY_MASK) {
+	if ((1<<p_instance->base_type)&INSTANCE_GEOMETRY_MASK) {
 
 
 		//make sure lights are updated
 		//make sure lights are updated
 		InstanceSet::Element *E=p_instance->lights.front();
 		InstanceSet::Element *E=p_instance->lights.front();
@@ -2395,13 +2616,20 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
 			E=E->next();
 			E=E->next();
 		}
 		}
 
 
-	}
-
-	if (p_instance->base_type == INSTANCE_ROOM) {
+	} else if (p_instance->base_type == INSTANCE_ROOM) {
 
 
 		p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse();
 		p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse();
+	} else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) {
+
+		Transform scale;
+		scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size);
+		scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos;
+		//print_line("scale: "+scale);
+		p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse();
 	}
 	}
 
 
+
+
 	p_instance->data.mirror = p_instance->data.transform.basis.determinant() < 0.0;
 	p_instance->data.mirror = p_instance->data.transform.basis.determinant() < 0.0;
 
 
 	AABB new_aabb;
 	AABB new_aabb;
@@ -2463,7 +2691,7 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
 
 
 		if (p_instance->base_type == INSTANCE_LIGHT) {
 		if (p_instance->base_type == INSTANCE_LIGHT) {
 
 
-			pairable_mask=INSTANCE_GEOMETRY_MASK;
+			pairable_mask=p_instance->light_info->enabled?INSTANCE_GEOMETRY_MASK:0;
 			pairable=true;
 			pairable=true;
 		}
 		}
 
 
@@ -2578,6 +2806,13 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) {
 			}
 			}
 
 
 		} break;			
 		} break;			
+		case VisualServer::INSTANCE_BAKED_LIGHT: {
+
+			BakedLight *baked_light = baked_light_owner.get( p_instance->base_rid );
+			ERR_FAIL_COND(!baked_light);
+			new_aabb=baked_light->octree_aabb;
+
+		} break;
 		default: {}
 		default: {}
 	}
 	}
 
 
@@ -2607,6 +2842,33 @@ void VisualServerRaster::_update_instances() {
 	}
 	}
 }
 }
 
 
+void VisualServerRaster::instance_light_set_enabled(RID p_instance,bool p_enabled) {
+
+	VS_CHANGED;
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+	ERR_FAIL_COND( instance->base_type!=INSTANCE_LIGHT );
+
+	if (p_enabled==instance->light_info->enabled)
+		return;
+
+	instance->light_info->enabled=p_enabled;
+	if (light_get_type(instance->base_rid)!=VS::LIGHT_DIRECTIONAL && instance->octree_id && instance->scenario)
+		instance->scenario->octree.set_pairable(instance->octree_id,p_enabled,1<<INSTANCE_LIGHT,p_enabled?INSTANCE_GEOMETRY_MASK:0);
+
+	//_instance_queue_update( instance , true );
+
+}
+
+bool VisualServerRaster::instance_light_is_enabled(RID p_instance) const {
+
+	const Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND_V( !instance,false );
+	ERR_FAIL_COND_V( instance->base_type!=INSTANCE_LIGHT,false );
+
+	return instance->light_info->enabled;
+}
+
 /****** CANVAS *********/
 /****** CANVAS *********/
 RID VisualServerRaster::canvas_create() {
 RID VisualServerRaster::canvas_create() {
 
 
@@ -3330,6 +3592,13 @@ void VisualServerRaster::black_bars_set_margins(int p_left, int p_top, int p_rig
 	black_margin[MARGIN_BOTTOM]=p_bottom;
 	black_margin[MARGIN_BOTTOM]=p_bottom;
 }
 }
 
 
+void VisualServerRaster::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) {
+
+	black_image[MARGIN_LEFT]=p_left;
+	black_image[MARGIN_TOP]=p_top;
+	black_image[MARGIN_RIGHT]=p_right;
+	black_image[MARGIN_BOTTOM]=p_bottom;
+}
 
 
 void VisualServerRaster::_free_attached_instances(RID p_rid,bool p_free_scenario) {
 void VisualServerRaster::_free_attached_instances(RID p_rid,bool p_free_scenario) {
 
 
@@ -3414,6 +3683,17 @@ void VisualServerRaster::free( RID p_rid ) {
 		portal_owner.free(p_rid);
 		portal_owner.free(p_rid);
 		memdelete(portal);
 		memdelete(portal);
 
 
+	} else if (baked_light_owner.owns(p_rid)) {
+
+		_free_attached_instances(p_rid);
+
+		BakedLight *baked_light = baked_light_owner.get(p_rid);
+		ERR_FAIL_COND(!baked_light);
+		if (baked_light->data.octree_texture.is_valid())
+			rasterizer->free(baked_light->data.octree_texture);
+		baked_light_owner.free(p_rid);
+		memdelete(baked_light);
+
 	} else if (camera_owner.owns(p_rid)) {
 	} else if (camera_owner.owns(p_rid)) {
 		// delete te camera
 		// delete te camera
 		
 		
@@ -3464,8 +3744,9 @@ void VisualServerRaster::free( RID p_rid ) {
 
 
 		instance_set_room(p_rid,RID());
 		instance_set_room(p_rid,RID());
 		instance_set_scenario(p_rid,RID());
 		instance_set_scenario(p_rid,RID());
+		instance_geometry_set_baked_light(p_rid,RID());
 		instance_set_base(p_rid,RID());
 		instance_set_base(p_rid,RID());
-			
+
 		instance_owner.free(p_rid);
 		instance_owner.free(p_rid);
 		memdelete(instance);
 		memdelete(instance);
 		
 		
@@ -5101,7 +5382,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 
 
 			Instance  *light = E->get().is_valid()?instance_owner.get(E->get()):NULL;
 			Instance  *light = E->get().is_valid()?instance_owner.get(E->get()):NULL;
 
 
-			if (rasterizer->light_has_shadow(light->base_rid)) {
+			if (light && light->light_info->enabled && rasterizer->light_has_shadow(light->base_rid)) {
 				//rasterizer->light_instance_set_active_hint(light->light_info->instance);
 				//rasterizer->light_instance_set_active_hint(light->light_info->instance);
 				_light_instance_update_shadow(light,p_scenario,p_camera,cull_range);
 				_light_instance_update_shadow(light,p_scenario,p_camera,cull_range);
 			}
 			}
@@ -5190,6 +5471,9 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 			Instance  *light = E->get().is_valid()?instance_owner.get(E->get()):NULL;
 			Instance  *light = E->get().is_valid()?instance_owner.get(E->get()):NULL;
 
 
 			ERR_CONTINUE(!light);
 			ERR_CONTINUE(!light);
+			if (!light->light_info->enabled)
+				continue;
+
 			rasterizer->add_light(light->light_info->instance);
 			rasterizer->add_light(light->light_info->instance);
 			light->light_info->last_add_pass=render_pass;
 			light->light_info->last_add_pass=render_pass;
 		}
 		}
@@ -5694,9 +5978,16 @@ void VisualServerRaster::_draw_cursors_and_margins() {
 		rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1));
 		rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1));
 	};
 	};
 
 
-	if (black_margin[MARGIN_LEFT])
+	if (black_image[MARGIN_LEFT].is_valid()) {
+		Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_LEFT]),rasterizer->texture_get_height(black_image[MARGIN_LEFT]));
+		rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_LEFT],Color(1,1,1));
+	} else if (black_margin[MARGIN_LEFT])
 		rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
 		rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
-	if (black_margin[MARGIN_RIGHT])
+
+	if (black_image[MARGIN_RIGHT].is_valid()) {
+		Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_RIGHT]),rasterizer->texture_get_height(black_image[MARGIN_RIGHT]));
+		rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_RIGHT],Color(1,1,1));
+	} else if (black_margin[MARGIN_RIGHT])
 		rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
 		rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
 	if (black_margin[MARGIN_TOP])
 	if (black_margin[MARGIN_TOP])
 		rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
 		rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,1,1),RID(),Color(0,0,0));

+ 55 - 2
servers/visual/visual_server_raster.h

@@ -87,6 +87,14 @@ class VisualServerRaster : public VisualServer {
 		Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; }
 		Portal() { enabled=true; disable_distance=50; disable_color=Color(); connect_range=0.8; }
 	};
 	};
 
 
+	struct BakedLight {
+
+		Rasterizer::BakedLightData data;
+		AABB octree_aabb;
+		Size2i octree_tex_size;
+
+	};
+
 
 
 	struct Camera  {
 	struct Camera  {
  
  
@@ -149,6 +157,7 @@ class VisualServerRaster : public VisualServer {
 		float draw_range_begin;
 		float draw_range_begin;
 		float draw_range_end;
 		float draw_range_end;
 		float extra_margin;
 		float extra_margin;
+		int lightmap_texture_index;
 
 
 
 
 		Rasterizer::InstanceData data;
 		Rasterizer::InstanceData data;
@@ -158,6 +167,8 @@ class VisualServerRaster : public VisualServer {
 		Set<Instance*> valid_auto_rooms;
 		Set<Instance*> valid_auto_rooms;
 		Instance *room;
 		Instance *room;
 		List<Instance*>::Element *RE;
 		List<Instance*>::Element *RE;
+		Instance *baked_light;
+		List<Instance*>::Element *BLE;
 		bool exterior;
 		bool exterior;
 
 
 		uint64_t last_render_pass;
 		uint64_t last_render_pass;
@@ -205,6 +216,7 @@ class VisualServerRaster : public VisualServer {
 			uint64_t last_add_pass;
 			uint64_t last_add_pass;
 			List<RID>::Element *D; // directional light in scenario
 			List<RID>::Element *D; // directional light in scenario
 			InstanceSet affected;
 			InstanceSet affected;
+			bool enabled;
 			float dtc; //distance to camera, used for sorting
 			float dtc; //distance to camera, used for sorting
 
 
 			
 			
@@ -213,8 +225,16 @@ class VisualServerRaster : public VisualServer {
 				D=NULL;	
 				D=NULL;	
 				light_set_index=-1;
 				light_set_index=-1;
 				last_add_pass=0;
 				last_add_pass=0;
+				enabled=true;
 			}
 			}
 		};
 		};
+
+		struct BakedLightInfo {
+
+			BakedLight *baked_light;
+			Transform affine_inverse;
+			List<Instance*> owned_instances;
+		};
 		
 		
 		struct ParticlesInfo {
 		struct ParticlesInfo {
 			
 			
@@ -226,6 +246,7 @@ class VisualServerRaster : public VisualServer {
 		LightInfo *light_info;
 		LightInfo *light_info;
 		ParticlesInfo *particles_info;
 		ParticlesInfo *particles_info;
 		PortalInfo * portal_info;
 		PortalInfo * portal_info;
+		BakedLightInfo * baked_light_info;
 
 
 
 
 		Instance() { 
 		Instance() { 
@@ -244,6 +265,8 @@ class VisualServerRaster : public VisualServer {
 			data.depth_scale=false;
 			data.depth_scale=false;
 			data.billboard=false;
 			data.billboard=false;
 			data.billboard_y=false;
 			data.billboard_y=false;
+			data.baked_light=NULL;
+			data.baked_light_octree_xform=NULL;
 			version=1;
 			version=1;
 			room_info=NULL;
 			room_info=NULL;
 			room=NULL;
 			room=NULL;
@@ -255,6 +278,10 @@ class VisualServerRaster : public VisualServer {
 			draw_range_end=0;
 			draw_range_end=0;
 			extra_margin=0;
 			extra_margin=0;
 			visible_in_all_rooms=false;
 			visible_in_all_rooms=false;
+			lightmap_texture_index=-1;
+			baked_light=NULL;
+			baked_light_info=NULL;
+			BLE=NULL;
 
 
 			light_cache_dirty=true;
 			light_cache_dirty=true;
 
 
@@ -270,6 +297,8 @@ class VisualServerRaster : public VisualServer {
 				memdelete(room_info);
 				memdelete(room_info);
 			if (portal_info)
 			if (portal_info)
 				memdelete(portal_info);
 				memdelete(portal_info);
+			if (baked_light_info)
+				memdelete(baked_light_info);
 		};
 		};
 	};
 	};
 	
 	
@@ -570,6 +599,7 @@ class VisualServerRaster : public VisualServer {
 	bool light_discard_enabled;
 	bool light_discard_enabled;
 	bool shadows_enabled;
 	bool shadows_enabled;
 	int black_margin[4];
 	int black_margin[4];
+	RID black_image[4];
 
 
 	Vector<Vector3> aabb_random_points;
 	Vector<Vector3> aabb_random_points;
 	Vector<Vector3> transformed_aabb_random_points;
 	Vector<Vector3> transformed_aabb_random_points;
@@ -596,7 +626,9 @@ class VisualServerRaster : public VisualServer {
 	
 	
 	mutable RID_Owner<Room> room_owner;
 	mutable RID_Owner<Room> room_owner;
 	mutable RID_Owner<Portal> portal_owner;
 	mutable RID_Owner<Portal> portal_owner;
-	
+
+	mutable RID_Owner<BakedLight> baked_light_owner;
+
 	mutable RID_Owner<Camera> camera_owner;
 	mutable RID_Owner<Camera> camera_owner;
 	mutable RID_Owner<Viewport> viewport_owner;
 	mutable RID_Owner<Viewport> viewport_owner;
 	
 	
@@ -902,8 +934,19 @@ public:
 	virtual void portal_set_connect_range(RID p_portal, float p_range);
 	virtual void portal_set_connect_range(RID p_portal, float p_range);
 	virtual float portal_get_connect_range(RID p_portal) const;
 	virtual float portal_get_connect_range(RID p_portal) const;
 
 
+	/* BAKED LIGHT */
+
+	virtual RID baked_light_create();
+
+	virtual void baked_light_set_mode(RID p_baked_light,BakedLightMode p_mode);
+	virtual BakedLightMode baked_light_get_mode(RID p_baked_light) const;
+
+	virtual void baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree);
+	virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const;
+
+	virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id);
+	virtual void baked_light_clear_lightmaps(RID p_baked_light);
 
 
-			
 	/* CAMERA API */
 	/* CAMERA API */
 	
 	
 	virtual RID camera_create();
 	virtual RID camera_create();
@@ -1036,6 +1079,15 @@ public:
 	virtual float instance_geometry_get_draw_range_max(RID p_instance) const;
 	virtual float instance_geometry_get_draw_range_max(RID p_instance) const;
 	virtual float instance_geometry_get_draw_range_min(RID p_instance) const;
 	virtual float instance_geometry_get_draw_range_min(RID p_instance) const;
 
 
+	virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light);
+	virtual RID instance_geometry_get_baked_light(RID p_instance) const;
+
+	virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id);
+	virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const;
+
+	virtual void instance_light_set_enabled(RID p_instance,bool p_enabled);
+	virtual bool instance_light_is_enabled(RID p_instance) const;
+
 	/* CANVAS (2D) */
 	/* CANVAS (2D) */
 	
 	
 	virtual RID canvas_create();
 	virtual RID canvas_create();
@@ -1093,6 +1145,7 @@ public:
 	/* BLACK BARS */
 	/* BLACK BARS */
 
 
 	virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom);
 	virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom);
+	virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom);
 
 
 	/* FREE */
 	/* FREE */
 	
 	

+ 20 - 0
servers/visual/visual_server_wrap_mt.h

@@ -879,6 +879,17 @@ public:
 	FUNC1RC(float,portal_get_connect_range,RID);
 	FUNC1RC(float,portal_get_connect_range,RID);
 
 
 
 
+	FUNC0R(RID,baked_light_create);
+	FUNC2(baked_light_set_mode,RID,BakedLightMode);
+	FUNC1RC(BakedLightMode,baked_light_get_mode,RID);
+
+	FUNC2(baked_light_set_octree,RID,DVector<uint8_t>);
+	FUNC1RC(DVector<uint8_t>,baked_light_get_octree,RID);
+
+
+	FUNC3(baked_light_add_lightmap,RID,RID,int);
+	FUNC1(baked_light_clear_lightmaps,RID);
+
 
 
 	/* CAMERA API */
 	/* CAMERA API */
 
 
@@ -1014,6 +1025,14 @@ public:
 	FUNC1RC(float,instance_geometry_get_draw_range_max,RID);
 	FUNC1RC(float,instance_geometry_get_draw_range_max,RID);
 	FUNC1RC(float,instance_geometry_get_draw_range_min,RID);
 	FUNC1RC(float,instance_geometry_get_draw_range_min,RID);
 
 
+	FUNC2(instance_geometry_set_baked_light,RID, RID );
+	FUNC1RC(RID,instance_geometry_get_baked_light,RID);
+
+	FUNC2(instance_geometry_set_baked_light_texture_index,RID, int);
+	FUNC1RC(int,instance_geometry_get_baked_light_texture_index,RID);
+
+	FUNC2(instance_light_set_enabled,RID,bool);
+	FUNC1RC(bool,instance_light_is_enabled,RID);
 
 
 	/* CANVAS (2D) */
 	/* CANVAS (2D) */
 
 
@@ -1076,6 +1095,7 @@ public:
 	/* BLACK BARS */
 	/* BLACK BARS */
 
 
 	FUNC4(black_bars_set_margins,int , int , int , int );
 	FUNC4(black_bars_set_margins,int , int , int , int );
+	FUNC4(black_bars_set_images,RID , RID , RID , RID );
 
 
 	/* FREE */
 	/* FREE */
 
 

+ 2 - 0
servers/visual_server.cpp

@@ -145,6 +145,7 @@ RID VisualServer::_make_test_cube() {
 	tangents.push_back( normal_points[m_idx][0] );\
 	tangents.push_back( normal_points[m_idx][0] );\
 	tangents.push_back( 1.0 );\
 	tangents.push_back( 1.0 );\
 	uvs.push_back( Vector3(uv_points[m_idx*2+0],uv_points[m_idx*2+1],0) );\
 	uvs.push_back( Vector3(uv_points[m_idx*2+0],uv_points[m_idx*2+1],0) );\
+	print_line(itos( (face_points[m_idx][0]>0?1:0)|(face_points[m_idx][1]>0?2:0)|(face_points[m_idx][2]>0?4:0)));\
 	vtx_idx++;\
 	vtx_idx++;\
 
 
 	for (int i=0;i<6;i++) {
 	for (int i=0;i<6;i++) {
@@ -527,6 +528,7 @@ void VisualServer::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("cursor_set_pos"),&VisualServer::cursor_set_pos);
 	ObjectTypeDB::bind_method(_MD("cursor_set_pos"),&VisualServer::cursor_set_pos);
 
 
 	ObjectTypeDB::bind_method(_MD("black_bars_set_margins","left","top","right","bottom"),&VisualServer::black_bars_set_margins);
 	ObjectTypeDB::bind_method(_MD("black_bars_set_margins","left","top","right","bottom"),&VisualServer::black_bars_set_margins);
+	ObjectTypeDB::bind_method(_MD("black_bars_set_images","left","top","right","bottom"),&VisualServer::black_bars_set_images);
 
 
 	ObjectTypeDB::bind_method(_MD("make_sphere_mesh"),&VisualServer::make_sphere_mesh);
 	ObjectTypeDB::bind_method(_MD("make_sphere_mesh"),&VisualServer::make_sphere_mesh);
 	ObjectTypeDB::bind_method(_MD("mesh_add_surface_from_planes"),&VisualServer::mesh_add_surface_from_planes);
 	ObjectTypeDB::bind_method(_MD("mesh_add_surface_from_planes"),&VisualServer::mesh_add_surface_from_planes);

+ 28 - 1
servers/visual_server.h

@@ -576,6 +576,23 @@ public:
 	virtual float portal_get_connect_range(RID p_portal) const =0;
 	virtual float portal_get_connect_range(RID p_portal) const =0;
 
 
 
 
+	/* BAKED LIGHT API */
+
+	virtual RID baked_light_create()=0;
+	enum BakedLightMode {
+		BAKED_LIGHT_OCTREE,
+		BAKED_LIGHT_LIGHTMAPS
+	};
+
+	virtual void baked_light_set_mode(RID p_baked_light,BakedLightMode p_mode)=0;
+	virtual BakedLightMode baked_light_get_mode(RID p_baked_light) const=0;
+
+	virtual void baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree)=0;
+	virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const=0;
+
+	virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id)=0;
+	virtual void baked_light_clear_lightmaps(RID p_baked_light)=0;
+
 
 
 	/* CAMERA API */
 	/* CAMERA API */
 	
 	
@@ -792,6 +809,7 @@ public:
 		INSTANCE_LIGHT,
 		INSTANCE_LIGHT,
 		INSTANCE_ROOM,
 		INSTANCE_ROOM,
 		INSTANCE_PORTAL,
 		INSTANCE_PORTAL,
+		INSTANCE_BAKED_LIGHT,
 		
 		
 		INSTANCE_GEOMETRY_MASK=(1<<INSTANCE_MESH)|(1<<INSTANCE_MULTIMESH)|(1<<INSTANCE_IMMEDIATE)|(1<<INSTANCE_PARTICLES)
 		INSTANCE_GEOMETRY_MASK=(1<<INSTANCE_MESH)|(1<<INSTANCE_MULTIMESH)|(1<<INSTANCE_IMMEDIATE)|(1<<INSTANCE_PARTICLES)
 	};
 	};
@@ -849,7 +867,7 @@ public:
 		INSTANCE_FLAG_RECEIVE_SHADOWS,
 		INSTANCE_FLAG_RECEIVE_SHADOWS,
 		INSTANCE_FLAG_DEPH_SCALE,
 		INSTANCE_FLAG_DEPH_SCALE,
 		INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
 		INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
-		INSTANCE_FLAG_USE_BAKED_LIGHT_VOLUME,
+		INSTANCE_FLAG_USE_BAKED_LIGHT,
 		INSTANCE_FLAG_MAX
 		INSTANCE_FLAG_MAX
 	};
 	};
 
 
@@ -863,6 +881,14 @@ public:
 	virtual float instance_geometry_get_draw_range_max(RID p_instance) const=0;
 	virtual float instance_geometry_get_draw_range_max(RID p_instance) const=0;
 	virtual float instance_geometry_get_draw_range_min(RID p_instance) const=0;
 	virtual float instance_geometry_get_draw_range_min(RID p_instance) const=0;
 
 
+	virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light)=0;
+	virtual RID instance_geometry_get_baked_light(RID p_instance) const=0;
+
+	virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id)=0;
+	virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const=0;
+
+	virtual void instance_light_set_enabled(RID p_instance,bool p_enabled)=0;
+	virtual bool instance_light_is_enabled(RID p_instance) const=0;
 
 
 	/* CANVAS (2D) */
 	/* CANVAS (2D) */
 
 
@@ -923,6 +949,7 @@ public:
 
 
 
 
 	virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom)=0;
 	virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom)=0;
+	virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom)=0;
 
 
 
 
 	/* FREE */
 	/* FREE */

+ 60 - 3
tools/editor/editor_import_export.cpp

@@ -704,11 +704,11 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
 
 
 			int flags=0;
 			int flags=0;
 
 
-			if (Globals::get_singleton()->get("texture_import/filter"))
+			if (Globals::get_singleton()->get("image_loader/filter"))
 				flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER;
 				flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER;
-			if (!Globals::get_singleton()->get("texture_import/gen_mipmaps"))
+			if (!Globals::get_singleton()->get("image_loader/gen_mipmaps"))
 				flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS;
 				flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS;
-			if (!Globals::get_singleton()->get("texture_import/repeat"))
+			if (!Globals::get_singleton()->get("image_loader/repeat"))
 				flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT;
 				flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT;
 
 
 			flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA;
 			flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA;
@@ -1533,6 +1533,26 @@ void EditorImportExport::load_config() {
 	}
 	}
 
 
 
 
+	if (cf->has_section("script")) {
+
+		if (cf->has_section_key("script","action")) {
+
+			String action = cf->get_value("script","action");
+			if (action=="compile")
+				script_action=SCRIPT_ACTION_COMPILE;
+			else if (action=="encrypt")
+				script_action=SCRIPT_ACTION_ENCRYPT;
+			else
+				script_action=SCRIPT_ACTION_NONE;
+
+		}
+
+		if (cf->has_section_key("script","encrypt_key")) {
+
+			script_key = cf->get_value("script","encrypt_key");
+		}
+	}
+
 }
 }
 
 
 
 
@@ -1634,10 +1654,39 @@ void EditorImportExport::save_config() {
 		cf->set_value("image_group_files","files",igfsave);
 		cf->set_value("image_group_files","files",igfsave);
 	}
 	}
 
 
+	switch(script_action) {
+		case SCRIPT_ACTION_NONE: cf->set_value("script","action","none"); break;
+		case SCRIPT_ACTION_COMPILE: cf->set_value("script","action","compile"); break;
+		case SCRIPT_ACTION_ENCRYPT: cf->set_value("script","action","encrypt"); break;
+	}
+
+	cf->set_value("script","encrypt_key",script_key);
+
 	cf->save("res://export.cfg");
 	cf->save("res://export.cfg");
 
 
 }
 }
 
 
+
+void EditorImportExport::script_set_action(ScriptAction p_action) {
+
+	script_action=p_action;
+}
+
+EditorImportExport::ScriptAction EditorImportExport::script_get_action() const{
+
+	return script_action;
+}
+
+void EditorImportExport::script_set_encryption_key(const String& p_key){
+
+	script_key=p_key;
+}
+String EditorImportExport::script_get_encryption_key() const{
+
+	return script_key;
+}
+
+
 void EditorImportExport::_bind_methods() {
 void EditorImportExport::_bind_methods() {
 
 
 	ObjectTypeDB::bind_method(_MD("image_export_group_create"),&EditorImportExport::image_export_group_create);
 	ObjectTypeDB::bind_method(_MD("image_export_group_create"),&EditorImportExport::image_export_group_create);
@@ -1649,6 +1698,11 @@ void EditorImportExport::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("image_export_group_get_make_atlas"),&EditorImportExport::image_export_group_get_make_atlas);
 	ObjectTypeDB::bind_method(_MD("image_export_group_get_make_atlas"),&EditorImportExport::image_export_group_get_make_atlas);
 	ObjectTypeDB::bind_method(_MD("image_export_group_get_shrink"),&EditorImportExport::image_export_group_get_shrink);
 	ObjectTypeDB::bind_method(_MD("image_export_group_get_shrink"),&EditorImportExport::image_export_group_get_shrink);
 	ObjectTypeDB::bind_method(_MD("image_add_to_export_group"),&EditorImportExport::image_add_to_export_group);
 	ObjectTypeDB::bind_method(_MD("image_add_to_export_group"),&EditorImportExport::image_add_to_export_group);
+	ObjectTypeDB::bind_method(_MD("script_set_action"),&EditorImportExport::script_set_action);
+	ObjectTypeDB::bind_method(_MD("script_set_encryption_key"),&EditorImportExport::script_set_encryption_key);
+	ObjectTypeDB::bind_method(_MD("script_get_action"),&EditorImportExport::script_get_action);
+	ObjectTypeDB::bind_method(_MD("script_get_encryption_key"),&EditorImportExport::script_get_encryption_key);
+
 }
 }
 
 
 EditorImportExport::EditorImportExport() {
 EditorImportExport::EditorImportExport() {
@@ -1659,6 +1713,9 @@ EditorImportExport::EditorImportExport() {
 	image_action_compress_quality=0.7;
 	image_action_compress_quality=0.7;
 	image_formats.insert("png");
 	image_formats.insert("png");
 	image_shrink=1;
 	image_shrink=1;
+
+	script_action=SCRIPT_ACTION_COMPILE;
+
 }
 }
 
 
 
 

+ 14 - 0
tools/editor/editor_import_export.h

@@ -227,6 +227,11 @@ public:
 		IMAGE_ACTION_COMPRESS_RAM,
 		IMAGE_ACTION_COMPRESS_RAM,
 	};
 	};
 
 
+	enum ScriptAction {
+		SCRIPT_ACTION_NONE,
+		SCRIPT_ACTION_COMPILE,
+		SCRIPT_ACTION_ENCRYPT
+	};
 
 
 protected:
 protected:
 
 
@@ -254,6 +259,9 @@ protected:
 	Map<StringName,StringName> image_group_files;
 	Map<StringName,StringName> image_group_files;
 	Vector<String> diff_packs;
 	Vector<String> diff_packs;
 
 
+	ScriptAction script_action;
+	String script_key;
+
 	static EditorImportExport* singleton;
 	static EditorImportExport* singleton;
 
 
 	static void _bind_methods();
 	static void _bind_methods();
@@ -316,6 +324,11 @@ public:
 
 
 	Set<String>& get_image_formats() { return image_formats; }
 	Set<String>& get_image_formats() { return image_formats; }
 
 
+	void script_set_action(ScriptAction p_action);
+	ScriptAction script_get_action() const;
+
+	void script_set_encryption_key(const String& p_key);
+	String script_get_encryption_key() const;
 
 
 	void load_config();
 	void load_config();
 	void save_config();
 	void save_config();
@@ -324,5 +337,6 @@ public:
 };
 };
 
 
 VARIANT_ENUM_CAST(EditorImportExport::ImageAction);
 VARIANT_ENUM_CAST(EditorImportExport::ImageAction);
+VARIANT_ENUM_CAST(EditorImportExport::ScriptAction);
 
 
 #endif // EDITOR_IMPORT_EXPORT_H
 #endif // EDITOR_IMPORT_EXPORT_H

BIN
tools/editor/icons/icon_bake.png


BIN
tools/editor/icons/icon_reload.png


+ 1 - 0
tools/editor/io_plugins/editor_import_collada.cpp

@@ -290,6 +290,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
 			} else {
 			} else {
 				//mesh since nothing else
 				//mesh since nothing else
 				node = memnew( MeshInstance );
 				node = memnew( MeshInstance );
+				node->cast_to<MeshInstance>()->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT,true);
 			}
 			}
 		} break;
 		} break;
 		case Collada::Node::TYPE_SKELETON: {
 		case Collada::Node::TYPE_SKELETON: {

+ 10 - 6
tools/editor/io_plugins/editor_texture_import_plugin.cpp

@@ -732,6 +732,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 	if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS))
 	if (!(flags&EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS))
 		tex_flags|=Texture::FLAG_MIPMAPS;
 		tex_flags|=Texture::FLAG_MIPMAPS;
 
 
+	print_line("path: "+p_path+" flags: "+itos(tex_flags));
 	int shrink=1;
 	int shrink=1;
 	if (from->has_option("shrink"))
 	if (from->has_option("shrink"))
 		shrink=from->get_option("shrink");
 		shrink=from->get_option("shrink");
@@ -1073,11 +1074,11 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
 
 
 			int flags=0;
 			int flags=0;
 
 
-			if (Globals::get_singleton()->get("texture_import/filter"))
+			if (Globals::get_singleton()->get("image_loader/filter"))
 				flags|=IMAGE_FLAG_FILTER;
 				flags|=IMAGE_FLAG_FILTER;
-			if (!Globals::get_singleton()->get("texture_import/gen_mipmaps"))
+			if (!Globals::get_singleton()->get("image_loader/gen_mipmaps"))
 				flags|=IMAGE_FLAG_NO_MIPMAPS;
 				flags|=IMAGE_FLAG_NO_MIPMAPS;
-			if (!Globals::get_singleton()->get("texture_import/repeat"))
+			if (!Globals::get_singleton()->get("image_loader/repeat"))
 				flags|=IMAGE_FLAG_REPEAT;
 				flags|=IMAGE_FLAG_REPEAT;
 
 
 			flags|=IMAGE_FLAG_FIX_BORDER_ALPHA;
 			flags|=IMAGE_FLAG_FIX_BORDER_ALPHA;
@@ -1102,11 +1103,11 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
 
 
 			int flags=0;
 			int flags=0;
 
 
-			if (Globals::get_singleton()->get("texture_import/filter"))
+			if (Globals::get_singleton()->get("image_loader/filter"))
 				flags|=IMAGE_FLAG_FILTER;
 				flags|=IMAGE_FLAG_FILTER;
-			if (!Globals::get_singleton()->get("texture_import/gen_mipmaps"))
+			if (!Globals::get_singleton()->get("image_loader/gen_mipmaps"))
 				flags|=IMAGE_FLAG_NO_MIPMAPS;
 				flags|=IMAGE_FLAG_NO_MIPMAPS;
-			if (!Globals::get_singleton()->get("texture_import/repeat"))
+			if (!Globals::get_singleton()->get("image_loader/repeat"))
 				flags|=IMAGE_FLAG_REPEAT;
 				flags|=IMAGE_FLAG_REPEAT;
 
 
 			flags|=IMAGE_FLAG_FIX_BORDER_ALPHA;
 			flags|=IMAGE_FLAG_FIX_BORDER_ALPHA;
@@ -1147,10 +1148,13 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
 	MD5Update(&ctx,&shrink,1);
 	MD5Update(&ctx,&shrink,1);
 	MD5Final(&ctx);
 	MD5Final(&ctx);
 
 
+
+
 	uint64_t sd=0;
 	uint64_t sd=0;
 	String smd5;
 	String smd5;
 
 
 	String md5 = String::md5(ctx.digest);
 	String md5 = String::md5(ctx.digest);
+	print_line(p_path+" MD5: "+md5+" FLAGS: "+itos(flags));
 
 
 	String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/");
 	String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/");
 
 

+ 1765 - 0
tools/editor/plugins/baked_light_baker.cpp

@@ -0,0 +1,1765 @@
+
+#include "baked_light_baker.h"
+#include <stdlib.h>
+#include <cmath>
+#include "io/marshalls.h"
+#include "tools/editor/editor_node.h"
+
+
+BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>& p_tex) {
+
+	if (!tex_map.has(p_tex)) {
+
+		Ref<ImageTexture> imgtex=p_tex;
+		if (imgtex.is_null())
+			return NULL;
+		Image image=imgtex->get_data();
+		if (image.empty())
+			return NULL;
+
+		if (image.get_format()!=Image::FORMAT_RGBA) {
+			if (image.get_format()>Image::FORMAT_INDEXED_ALPHA) {
+				Error err = image.decompress();
+				if (err)
+					return NULL;
+			}
+
+			if (image.get_format()!=Image::FORMAT_RGBA)
+				image.convert(Image::FORMAT_RGBA);
+		}
+
+		DVector<uint8_t> dvt=image.get_data();
+		DVector<uint8_t>::Read r=dvt.read();
+		MeshTexture mt;
+		mt.tex_w=image.get_width();
+		mt.tex_h=image.get_height();
+		int len = image.get_width()*image.get_height()*4;
+		mt.tex.resize(len);
+		copymem(mt.tex.ptr(),r.ptr(),len);
+
+		textures.push_back(mt);
+		tex_map[p_tex]=&textures.back()->get();
+	}
+
+	return tex_map[p_tex];
+}
+
+
+void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform) {
+
+
+	for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+		if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+			continue;
+		Ref<Material> mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i);
+
+		MeshMaterial *matptr=NULL;
+
+		if (mat.is_valid()) {
+
+			if (!mat_map.has(mat)) {
+
+				MeshMaterial mm;
+
+				Ref<FixedMaterial> fm = mat;
+				if (fm.is_valid()) {
+					//fixed route
+					mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE);
+					mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE));
+					mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR);
+					mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR));
+				} else {
+
+					mm.diffuse.color=Color(1,1,1,1);
+					mm.diffuse.tex=NULL;
+					mm.specular.color=Color(0,0,0,1);
+					mm.specular.tex=NULL;
+				}
+
+				materials.push_back(mm);
+				mat_map[mat]=&materials.back()->get();
+
+			}
+
+			matptr=mat_map[mat];
+
+		}
+
+
+		int facecount=0;
+
+
+		if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) {
+
+			facecount=p_mesh->surface_get_array_index_len(i);
+		} else {
+
+			facecount=p_mesh->surface_get_array_len(i);
+		}
+
+		ERR_CONTINUE((facecount==0 || (facecount%3)!=0));
+
+		facecount/=3;
+
+		int tbase=triangles.size();
+		triangles.resize(facecount+tbase);
+
+
+		Array a = p_mesh->surface_get_arrays(i);
+
+		DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+		DVector<Vector3>::Read vr=vertices.read();
+		DVector<Vector2> uv;
+		DVector<Vector2>::Read uvr;
+		DVector<Vector3> normal;
+		DVector<Vector3>::Read normalr;
+		bool read_uv=false;
+		bool read_normal=false;
+
+		if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV) {
+
+			uv=a[Mesh::ARRAY_TEX_UV];
+			uvr=uv.read();
+			read_uv=true;
+		}
+
+		if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) {
+
+			normal=a[Mesh::ARRAY_NORMAL];
+			normalr=normal.read();
+			read_normal=true;
+		}
+
+		Matrix3 normal_xform = p_xform.basis.inverse().transposed();
+
+
+		if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_INDEX) {
+
+			DVector<int> indices = a[Mesh::ARRAY_INDEX];
+			DVector<int>::Read ir = indices.read();
+
+			for(int i=0;i<facecount;i++) {
+				Triangle &t=triangles[tbase+i];
+				t.vertices[0]=p_xform.xform(vr[ ir[i*3+0] ]);
+				t.vertices[1]=p_xform.xform(vr[ ir[i*3+1] ]);
+				t.vertices[2]=p_xform.xform(vr[ ir[i*3+2] ]);
+				t.material=matptr;
+				if (read_uv) {
+
+					t.uvs[0]=uvr[ ir[i*3+0] ];
+					t.uvs[1]=uvr[ ir[i*3+1] ];
+					t.uvs[2]=uvr[ ir[i*3+2] ];
+				}
+				if (read_normal) {
+
+					t.normals[0]=normal_xform.xform(normalr[ ir[i*3+0] ]).normalized();
+					t.normals[1]=normal_xform.xform(normalr[ ir[i*3+1] ]).normalized();
+					t.normals[2]=normal_xform.xform(normalr[ ir[i*3+2] ]).normalized();
+				}
+			}
+
+		} else {
+
+			for(int i=0;i<facecount;i++) {
+				Triangle &t=triangles[tbase+i];
+				t.vertices[0]=p_xform.xform(vr[ i*3+0 ]);
+				t.vertices[1]=p_xform.xform(vr[ i*3+1 ]);
+				t.vertices[2]=p_xform.xform(vr[ i*3+2 ]);
+				t.material=matptr;
+				if (read_uv) {
+
+					t.uvs[0]=uvr[ i*3+0 ];
+					t.uvs[1]=uvr[ i*3+1 ];
+					t.uvs[2]=uvr[ i*3+2 ];
+				}
+				if (read_normal) {
+
+					t.normals[0]=normal_xform.xform(normalr[ i*3+0 ]).normalized();
+					t.normals[1]=normal_xform.xform(normalr[ i*3+1 ]).normalized();
+					t.normals[2]=normal_xform.xform(normalr[ i*3+2 ]).normalized();
+				}
+			}
+		}
+	}
+
+}
+
+
+void BakedLightBaker::_parse_geometry(Node* p_node) {
+
+	if (p_node->cast_to<MeshInstance>()) {
+
+		MeshInstance *meshi=p_node->cast_to<MeshInstance>();
+		Ref<Mesh> mesh=meshi->get_mesh();
+		if (mesh.is_valid()) {
+			_add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform());
+		}
+	} else if (p_node->cast_to<Light>()) {
+
+		Light *dl=p_node->cast_to<Light>();
+
+		if (dl->get_bake_mode()!=Light::BAKE_MODE_DISABLED) {
+
+
+			LightData dirl;
+			dirl.type=VS::LightType(dl->get_light_type());
+			dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE);
+			dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR);
+			dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY);
+			dirl.pos=dl->get_global_transform().origin;
+			dirl.up=dl->get_global_transform().basis.get_axis(1).normalized();
+			dirl.left=dl->get_global_transform().basis.get_axis(0).normalized();
+			dirl.dir=-dl->get_global_transform().basis.get_axis(2).normalized();
+			dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE);
+			dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION);
+			dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION);
+			dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS);
+			dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL;
+			dirl.rays_thrown=0;
+			lights.push_back(dirl);
+		}
+
+	} else if (p_node->cast_to<Spatial>()){
+
+		Spatial *sp = p_node->cast_to<Spatial>();
+
+		Array arr = p_node->call("_get_baked_light_meshes");
+		for(int i=0;i<arr.size();i+=2) {
+
+			Transform xform=arr[i];
+			Ref<Mesh> mesh=arr[i+1];
+			_add_mesh(mesh,Ref<Material>(),base_inv * (sp->get_global_transform() * xform));
+		}
+	}
+
+	for(int i=0;i<p_node->get_child_count();i++) {
+
+		_parse_geometry(p_node->get_child(i));
+	}
+}
+
+
+void BakedLightBaker::_fix_lights() {
+
+
+	total_light_area=0;
+	for(int i=0;i<lights.size();i++) {
+
+		LightData &dl=lights[i];
+
+		switch(dl.type) {
+			case VS::LIGHT_DIRECTIONAL: {
+
+				float up_max=-1e10;
+				float dir_max=-1e10;
+				float left_max=-1e10;
+				float up_min=1e10;
+				float dir_min=1e10;
+				float left_min=1e10;
+
+				for(int j=0;j<triangles.size();j++) {
+
+					for(int k=0;k<3;k++) {
+
+						Vector3 v = triangles[j].vertices[k];
+
+						float up_d = dl.up.dot(v);
+						float dir_d = dl.dir.dot(v);
+						float left_d = dl.left.dot(v);
+
+						if (up_d>up_max)
+							up_max=up_d;
+						if (up_d<up_min)
+							up_min=up_d;
+
+						if (left_d>left_max)
+							left_max=left_d;
+						if (left_d<left_min)
+							left_min=left_d;
+
+						if (dir_d>dir_max)
+							dir_max=dir_d;
+						if (dir_d<dir_min)
+							dir_min=dir_d;
+
+					}
+				}
+
+				//make a center point, then the upvector and leftvector
+				dl.pos = dl.left*( left_max+left_min )*0.5 + dl.up*( up_max+up_min )*0.5 + dl.dir*(dir_min-(dir_max-dir_min));
+				dl.left*=(left_max-left_min)*0.5;
+				dl.up*=(up_max-up_min)*0.5;
+				dl.length = (dir_max - dir_min)*10; //arbitrary number to keep it in scale
+				dl.area=dl.left.length()*2*dl.up.length()*2;
+				dl.constant=1.0/dl.area;
+			} break;
+			case VS::LIGHT_OMNI:
+			case VS::LIGHT_SPOT: {
+
+				dl.attenuation_table.resize(ATTENUATION_CURVE_LEN);
+				for(int j=0;j<ATTENUATION_CURVE_LEN;j++) {
+					dl.attenuation_table[j]=1.0-Math::pow(j/float(ATTENUATION_CURVE_LEN),dl.attenuation);
+					float falloff=j*dl.radius/float(ATTENUATION_CURVE_LEN);
+					if (falloff==0)
+						falloff=0.000001;
+					float intensity=4*Math_PI*(falloff*falloff);
+					//dl.attenuation_table[j]*=falloff*falloff;
+					dl.attenuation_table[j]*=1.0/(3.0/intensity);
+
+				}
+				if (dl.type==VS::LIGHT_OMNI) {
+
+					dl.area=4.0*Math_PI*pow(dl.radius,2.0);
+					dl.constant=1.0/3.5;
+				} else {
+
+
+					float r = Math::tan(Math::deg2rad(dl.spot_angle))*dl.radius;
+					float c = 1.0-(Math::deg2rad(dl.spot_angle)*0.5+0.5);
+					dl.constant=1.0/3.5;
+					dl.constant*=1.0/c;
+
+					dl.area=Math_PI*r*r*c;
+				}
+
+			} break;
+
+
+		}
+
+		total_light_area+=dl.area;
+	}
+}
+
+BakedLightBaker::BVH* BakedLightBaker::_parse_bvh(BVH** p_children, int p_size, int p_depth, int &max_depth) {
+
+	if (p_depth>max_depth) {
+		max_depth=p_depth;
+	}
+
+	if (p_size==1) {
+
+		return p_children[0];
+	} else if (p_size==0) {
+
+		return NULL;
+	}
+
+
+	AABB aabb;
+	aabb=p_children[0]->aabb;
+	for(int i=1;i<p_size;i++) {
+
+		aabb.merge_with(p_children[i]->aabb);
+	}
+
+	int li=aabb.get_longest_axis_index();
+
+	switch(li) {
+
+		case Vector3::AXIS_X: {
+			SortArray<BVH*,BVHCmpX> sort_x;
+			sort_x.nth_element(0,p_size,p_size/2,p_children);
+			//sort_x.sort(&p_bb[p_from],p_size);
+		} break;
+		case Vector3::AXIS_Y: {
+			SortArray<BVH*,BVHCmpY> sort_y;
+			sort_y.nth_element(0,p_size,p_size/2,p_children);
+			//sort_y.sort(&p_bb[p_from],p_size);
+		} break;
+		case Vector3::AXIS_Z: {
+			SortArray<BVH*,BVHCmpZ> sort_z;
+			sort_z.nth_element(0,p_size,p_size/2,p_children);
+			//sort_z.sort(&p_bb[p_from],p_size);
+
+		} break;
+	}
+
+
+	BVH* left = _parse_bvh(p_children,p_size/2,p_depth+1,max_depth);
+	BVH* right = _parse_bvh(&p_children[p_size/2],p_size-p_size/2,p_depth+1,max_depth);
+
+	BVH *_new = memnew(BVH);
+	_new->aabb=aabb;
+	_new->center=aabb.pos+aabb.size*0.5;
+	_new->children[0]=left;
+	_new->children[1]=right;
+	_new->leaf=NULL;
+
+	return _new;
+}
+
+void BakedLightBaker::_make_bvh() {
+
+	Vector<BVH*> bases;
+	bases.resize(triangles.size());
+	int max_depth=0;
+	for(int i=0;i<triangles.size();i++) {
+		bases[i]=memnew( BVH );
+		bases[i]->leaf=&triangles[i];
+		bases[i]->aabb.pos=triangles[i].vertices[0];
+		bases[i]->aabb.expand_to(triangles[i].vertices[1]);
+		bases[i]->aabb.expand_to(triangles[i].vertices[2]);
+		triangles[i].aabb=bases[i]->aabb;
+		bases[i]->center=bases[i]->aabb.pos+bases[i]->aabb.size*0.5;
+	}
+
+	bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth);
+	ray_stack = memnew_arr(uint32_t,max_depth);
+	bvh_stack = memnew_arr(BVH*,max_depth);
+}
+
+void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_depth) {
+
+
+
+
+	uint32_t *stack=octant_stack;
+	uint32_t *ptr_stack=octantptr_stack;
+	Octant *octants=octant_pool.ptr();
+
+	stack[0]=0;
+	ptr_stack[0]=0;
+
+	int stack_pos=0;
+
+
+	while(true) {
+
+		Octant *octant=&octants[ptr_stack[stack_pos]];
+		if (stack[stack_pos]<8) {
+
+			int i = stack[stack_pos];
+			stack[stack_pos]++;
+
+
+
+			//fit_aabb=fit_aabb.grow(bvh->aabb.size.x*0.0001);
+
+			int child_idx =octant->children[i];
+			bool encloses;
+			if (!child_idx) {
+
+				AABB aabb=octant->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;
+
+				aabb.grow_by(cell_size*octree_extra_margin);
+				if (!aabb.intersects(p_triangle->aabb))
+					continue;
+				encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb);
+				if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb))
+					continue;
+			} else {
+
+				Octant *child=&octants[child_idx];
+				AABB aabb=child->aabb;
+				aabb.grow_by(cell_size*octree_extra_margin);
+				if (!aabb.intersects(p_triangle->aabb))
+					continue;
+				encloses=aabb.grow(cell_size*-octree_extra_margin*2.0).encloses(p_triangle->aabb);
+				if (!encloses && !Face3(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).intersects_aabb2(aabb))
+					continue;
+
+			}
+
+			if (encloses)
+				stack[stack_pos]=8; // quick and dirty opt
+
+			if (!child_idx) {
+
+
+				if (octant_pool_size==octant_pool.size()) {
+					octant_pool.resize(octant_pool_size+OCTANT_POOL_CHUNK);
+					octants=octant_pool.ptr();
+					octant=&octants[ptr_stack[stack_pos]];
+				}
+				child_idx=octant_pool_size++;
+				octant->children[i]=child_idx;
+				Octant *child=&octants[child_idx];
+
+				child->aabb=octant->aabb;
+				child->texture_x=0;
+				child->texture_y=0;
+
+				child->aabb.size*=0.5;
+				if (i&1)
+					child->aabb.pos.x+=child->aabb.size.x;
+				if (i&2)
+					child->aabb.pos.y+=child->aabb.size.y;
+				if (i&4)
+					child->aabb.pos.z+=child->aabb.size.z;
+
+
+
+				if (stack_pos==octree_depth-1) {
+					child->leaf=true;
+					child->offset[0]=child->aabb.pos.x+child->aabb.size.x*0.5;
+					child->offset[1]=child->aabb.pos.y+child->aabb.size.y*0.5;
+					child->offset[2]=child->aabb.pos.z+child->aabb.size.z*0.5;
+					child->next_leaf=leaf_list;
+
+					for(int ci=0;ci<8;ci++) {
+						child->normal_accum[ci][0]=0;
+						child->normal_accum[ci][1]=0;
+						child->normal_accum[ci][2]=0;
+					}
+
+					child->bake_neighbour=0;
+					child->first_neighbour=true;
+					leaf_list=child_idx;
+					cell_count++;
+
+					int lz = lights.size();
+					child->light = memnew_arr(OctantLight,lz);
+
+					for(int li=0;li<lz;li++) {
+						for(int ci=0;ci<8;ci++) {
+							child->light[li].accum[ci][0]=0;
+							child->light[li].accum[ci][1]=0;
+							child->light[li].accum[ci][2]=0;
+						}
+					}
+
+					child->parent=ptr_stack[stack_pos];
+
+				} else {
+
+					child->leaf=false;
+					for(int j=0;j<8;j++) {
+						child->children[j]=0;
+					}
+				}
+			}
+
+			if (!octants[child_idx].leaf) {
+				stack_pos++;
+				stack[stack_pos]=0;
+				ptr_stack[stack_pos]=child_idx;
+			} else {
+
+				Octant *child=&octants[child_idx];
+
+				Vector3 n = Plane(p_triangle->vertices[0],p_triangle->vertices[1],p_triangle->vertices[2]).normal;
+
+
+				for(int ci=0;ci<8;ci++) {
+
+					Vector3 pos = child->aabb.pos;
+
+					if (ci&1)
+						pos.x+=child->aabb.size.x;
+					if (ci&2)
+						pos.y+=child->aabb.size.y;
+					if (ci&4)
+						pos.z+=child->aabb.size.z;
+
+
+					pos.x=floor((pos.x+cell_size*0.5)/cell_size);
+					pos.y=floor((pos.y+cell_size*0.5)/cell_size);
+					pos.z=floor((pos.z+cell_size*0.5)/cell_size);
+
+					Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos);
+					if (!E) {
+						endpoint_normal[pos]=n;
+					} else {
+						E->get()+=n;
+					}
+
+				}
+
+			}
+
+
+		} else {
+			stack_pos--;
+			if (stack_pos<0)
+				break;
+		}
+	}
+
+
+}
+
+
+void BakedLightBaker::_make_octree() {
+
+
+	AABB base = bvh->aabb;
+	float lal=base.get_longest_axis_size();
+	//must be square because we want square blocks
+	base.size.x=lal;
+	base.size.y=lal;
+	base.size.z=lal;
+	base.grow_by(lal*0.001); //for precision
+	octree_aabb=base;
+
+	cell_size=base.size.x;
+	for(int i=0;i<octree_depth;i++)
+		cell_size/=2.0;
+	octant_stack = memnew_arr(uint32_t,octree_depth*2 );
+	octantptr_stack = memnew_arr(uint32_t,octree_depth*2 );
+
+	octant_pool.resize(OCTANT_POOL_CHUNK);
+	octant_pool_size=1;
+	Octant *root=octant_pool.ptr();
+	root->leaf=false;
+	root->aabb=octree_aabb;
+	root->parent=-1;
+	for(int i=0;i<8;i++)
+		root->children[i]=0;
+
+	EditorProgress ep("bake_octree","Parsing "+itos(triangles.size())+" Triangles:",triangles.size());
+
+	for(int i=0;i<triangles.size();i++) {
+
+		_octree_insert(0,&triangles[i],octree_depth-1);
+		if ((i%1000)==0) {
+
+			ep.step("Triangle# "+itos(i),i);
+		}
+	}
+
+	{
+		uint32_t oct_idx=leaf_list;
+		Octant *octants=octant_pool.ptr();
+		while(oct_idx) {
+
+			BakedLightBaker::Octant *oct = &octants[oct_idx];
+			for(int ci=0;ci<8;ci++) {
+
+
+				Vector3 pos = oct->aabb.pos;
+
+				if (ci&1)
+					pos.x+=oct->aabb.size.x;
+				if (ci&2)
+					pos.y+=oct->aabb.size.y;
+				if (ci&4)
+					pos.z+=oct->aabb.size.z;
+
+
+				pos.x=floor((pos.x+cell_size*0.5)/cell_size);
+				pos.y=floor((pos.y+cell_size*0.5)/cell_size);
+				pos.z=floor((pos.z+cell_size*0.5)/cell_size);
+
+				Map<Vector3,Vector3>::Element *E=endpoint_normal.find(pos);
+				if (!E) {
+					//?
+					print_line("lolwut?");
+				} else {
+					Vector3 n = E->get().normalized();
+					oct->normal_accum[ci][0]=n.x;
+					oct->normal_accum[ci][1]=n.y;
+					oct->normal_accum[ci][2]=n.z;
+
+				}
+
+			}
+
+			oct_idx=oct->next_leaf;
+		}
+	}
+
+
+}
+
+
+
+
+
+void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light, const Plane& p_plane) {
+
+	//stackless version
+
+	uint32_t *stack=octant_stack;
+	uint32_t *ptr_stack=octantptr_stack;
+	Octant *octants=octant_pool.ptr();
+
+	stack[0]=0;
+	ptr_stack[0]=0;
+
+	int stack_pos=0;
+
+
+	while(true) {
+
+		Octant &octant=octants[ptr_stack[stack_pos]];
+
+		if (octant.leaf) {
+
+
+
+			//if (p_plane.normal.dot(octant.aabb.get_support(p_plane.normal)) < p_plane.d-CMP_EPSILON) { //octants behind are no go
+
+
+
+			float r=cell_size*plot_size;
+			for(int i=0;i<8;i++) {
+				Vector3 pos=octant.aabb.pos;
+				if (i&1)
+					pos.x+=octant.aabb.size.x;
+				if (i&2)
+					pos.y+=octant.aabb.size.y;
+				if (i&4)
+					pos.z+=octant.aabb.size.z;
+
+
+
+				float d = p_plot_pos.distance_to(pos);
+
+				if (d<=r) {
+
+
+					float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
+					float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2])));
+					intensity*=pow(damp,edge_damp);
+					//intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
+					octant.light[p_light_index].accum[i][0]+=p_light.r*intensity;
+					octant.light[p_light_index].accum[i][1]+=p_light.g*intensity;
+					octant.light[p_light_index].accum[i][2]+=p_light.b*intensity;
+				}
+			}
+
+			stack_pos--;
+		} else if (stack[stack_pos]<8) {
+
+			int i = stack[stack_pos];
+			stack[stack_pos]++;
+
+			if (!octant.children[i]) {
+				continue;
+			}
+
+			Octant &child=octants[octant.children[i]];
+
+			if (!child.aabb.intersects(p_plot_aabb))
+				continue;
+
+			if (child.aabb.encloses(p_plot_aabb)) {
+				stack[stack_pos]=8; //don't test the rest
+			}
+
+			stack_pos++;
+			stack[stack_pos]=0;
+			ptr_stack[stack_pos]=octant.children[i];
+		} else {
+			stack_pos--;
+			if (stack_pos<0)
+				break;
+		}
+	}
+
+
+}
+
+
+float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce) {
+
+
+	uint32_t* stack = ray_stack;
+	BVH **bstack = bvh_stack;
+
+	enum {
+		TEST_AABB_BIT=0,
+		VISIT_LEFT_BIT=1,
+		VISIT_RIGHT_BIT=2,
+		VISIT_DONE_BIT=3,
+
+
+	};
+
+	Vector3 n = (p_end-p_begin);
+	float len=n.length();
+	if (len==0)
+		return 0;
+	n/=len;
+
+
+	real_t d=1e10;
+	bool inters=false;
+	Vector3 r_normal;
+	Vector3 r_point;
+	Vector3 end=p_end;
+
+	Triangle *triangle=NULL;
+
+	//for(int i=0;i<max_depth;i++)
+	//	stack[i]=0;
+
+	int level=0;
+	//AABB ray_aabb;
+	//ray_aabb.pos=p_begin;
+	//ray_aabb.expand_to(p_end);
+
+
+	const BVH *bvhptr = bvh;
+
+	bstack[0]=bvh;
+	stack[0]=TEST_AABB_BIT;
+
+
+	while(true) {
+
+		uint32_t mode = stack[level];
+		const BVH &b = *bstack[level];
+		bool done=false;
+
+		switch(mode) {
+			case TEST_AABB_BIT: {
+
+				if (b.leaf) {
+
+
+					Face3 f3(b.leaf->vertices[0],b.leaf->vertices[1],b.leaf->vertices[2]);
+
+
+					Vector3 res;
+
+					if (f3.intersects_segment(p_begin,end,&res)) {
+
+
+						float nd = n.dot(res);
+						if (nd<d) {
+
+							d=nd;
+							r_point=res;
+							end=res;
+							len=(p_begin-end).length();
+							r_normal=f3.get_plane().get_normal();
+							triangle=b.leaf;
+							inters=true;
+						}
+
+					}
+
+					stack[level]=VISIT_DONE_BIT;
+				} else {
+
+
+					bool valid = b.aabb.smits_intersect_ray(p_begin,n,0,len);
+					//bool valid = b.aabb.intersects_segment(p_begin,p_end);
+	//				bool valid = b.aabb.intersects(ray_aabb);
+
+					if (!valid) {
+
+						stack[level]=VISIT_DONE_BIT;
+
+					} else {
+
+						stack[level]=VISIT_LEFT_BIT;
+					}
+				}
+
+			} continue;
+			case VISIT_LEFT_BIT: {
+
+				stack[level]=VISIT_RIGHT_BIT;
+				bstack[level+1]=b.children[0];
+				stack[level+1]=TEST_AABB_BIT;
+				level++;
+
+			} continue;
+			case VISIT_RIGHT_BIT: {
+
+				stack[level]=VISIT_DONE_BIT;
+				bstack[level+1]=b.children[1];
+				stack[level+1]=TEST_AABB_BIT;
+				level++;
+			} continue;
+			case VISIT_DONE_BIT: {
+
+				if (level==0) {
+					done=true;
+					break;
+				} else
+					level--;
+
+			} continue;
+		}
+
+
+		if (done)
+			break;
+	}
+
+
+	if (inters) {
+
+
+
+		//should check if there is normals first
+		Vector2 uv;
+		if (true) {
+
+			triangle->get_uv_and_normal(r_point,uv,r_normal);
+
+		} else {
+
+		}
+
+		if (n.dot(r_normal)>0)
+			r_normal=-r_normal;
+
+
+		//ok...
+		Color diffuse_at_point(0.8,0.8,0.8);
+		Color specular_at_point(0.0,0.0,0.0);
+
+		if (triangle->material) {
+
+			//triangle->get_uv(r_point);
+			diffuse_at_point=triangle->material->diffuse.get_color(uv);
+			specular_at_point=triangle->material->specular.get_color(uv);
+		}
+
+		float dist = p_begin.distance_to(r_point);
+
+		AABB aabb;
+		aabb.pos=r_point;
+		aabb.pos-=Vector3(1,1,1)*cell_size*plot_size;
+		aabb.size=Vector3(2,2,2)*cell_size*plot_size;
+
+		Color res_light=p_light;
+		float att=1.0;
+		float dp=(1.0-normal_damp)*n.dot(-r_normal)+normal_damp;
+
+		if (p_att_curve) {
+
+			p_att_pos+=dist;
+			int cpos = Math::fast_ftoi((p_att_pos/p_att_curve_len)*ATTENUATION_CURVE_LEN);
+			cpos=CLAMP(cpos,0,ATTENUATION_CURVE_LEN-1);
+			att=p_att_curve[cpos];
+		}
+
+
+		res_light.r*=dp;
+		res_light.g*=dp;
+		res_light.b*=dp;
+
+		//light is plotted before multiplication with diffuse, this way
+		//the multiplication can happen with more detail in the shader
+
+
+		float ret=1e6;
+
+		if (p_bounces>0) {
+
+
+			p_rest-=dist;
+			if (p_rest<CMP_EPSILON)
+				return 0;
+
+			if (r_normal==-n)
+				return 0; //todo change a little
+
+			r_point+=r_normal*0.01;
+
+
+
+
+			diffuse_at_point.r=res_light.r*diffuse_at_point.r;
+			diffuse_at_point.g=res_light.g*diffuse_at_point.g;
+			diffuse_at_point.b=res_light.b*diffuse_at_point.b;
+
+			specular_at_point.r=res_light.r*specular_at_point.r;
+			specular_at_point.g=res_light.g*specular_at_point.g;
+			specular_at_point.b=res_light.b*specular_at_point.b;
+
+
+
+			if (use_diffuse && (diffuse_at_point.r>CMP_EPSILON || diffuse_at_point.g>CMP_EPSILON || diffuse_at_point.b>CMP_EPSILON)) {
+				//diffuse bounce
+
+				Vector3 c1=r_normal.cross(n).normalized();
+				Vector3 c2=r_normal.cross(c1).normalized();
+				double r1 = double(rand())/RAND_MAX;
+				double r2 = double(rand())/RAND_MAX;
+				double r3 = double(rand())/RAND_MAX;
+#if 0
+				Vector3 next = - ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*(r3-0.5))).normalized()*0.5 + r_normal*0.5;
+
+				if (next==Vector3())
+					next=r_normal;
+				Vector3 rn=next.normalized();
+
+#else
+				Vector3 rn = ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*r3*0.5)).normalized();
+#endif
+
+
+				ret=_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
+			}
+
+			if (use_specular && (specular_at_point.r>CMP_EPSILON || specular_at_point.g>CMP_EPSILON || specular_at_point.b>CMP_EPSILON)) {
+				//specular bounce
+
+				//Vector3 c1=r_normal.cross(n).normalized();
+				//Vector3 c2=r_normal.cross(c1).normalized();
+
+				Vector3 rn = n - r_normal *r_normal.dot(n) * 2.0;
+
+				_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
+			}
+		}
+
+		//specular later
+//		_plot_light_point(r_point,octree,octree_aabb,p_light);
+
+
+		Color plot_light=res_light;
+		plot_light.r*=att;
+		plot_light.g*=att;
+		plot_light.b*=att;
+
+		if (!p_first_bounce) {
+
+
+			float r = plot_size * cell_size;
+			if (ret<r) {
+				//avoid accumulaiton of light on corners
+				//plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size);
+				plot_light=Color(0,0,0,0);
+			}
+		}
+
+
+		if (!p_first_bounce || lights[p_light_index].bake_direct) {
+			Plane plane(r_point,r_normal);
+			//print_line(String(plot_light)+String(" ")+rtos(att));
+			_plot_light(p_light_index,r_point,aabb,plot_light,plane);
+		}
+
+
+		return dist;
+	}
+
+	return 0;
+
+}
+
+
+
+
+void BakedLightBaker::_make_octree_texture() {
+
+
+	BakedLightBaker::Octant *octants=octant_pool.ptr();
+
+	//find neighbours first, to have a better idea of what amount of space is needed
+	{
+
+		Vector<OctantHash> octant_hashing;
+		octant_hashing.resize(octant_pool_size);
+		Vector<uint32_t> hash_table;
+		int hash_table_size=Math::larger_prime(16384);
+		hash_table.resize(hash_table_size);
+		uint32_t*hashptr = hash_table.ptr();
+		OctantHash*octhashptr = octant_hashing.ptr();
+
+		for(int i=0;i<hash_table_size;i++)
+			hashptr[i]=0;
+
+
+		//step 1 add to hash table
+
+		uint32_t oct_idx=leaf_list;
+
+
+		while(oct_idx) {
+
+			BakedLightBaker::Octant *oct = &octants[oct_idx];
+			uint64_t base=0;
+			Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive
+			base=int((pos.x+cell_size*0.5)/cell_size);
+			base<<=16;
+			base|=int((pos.y+cell_size*0.5)/cell_size);
+			base<<=16;
+			base|=int((pos.z+cell_size*0.5)/cell_size);
+
+			uint32_t hash = HashMapHahserDefault::hash(base);
+			uint32_t idx = hash % hash_table_size;
+			octhashptr[oct_idx].next=hashptr[idx];
+			octhashptr[oct_idx].hash=hash;
+			octhashptr[oct_idx].value=base;
+			hashptr[idx]=oct_idx;
+
+			oct_idx=oct->next_leaf;
+
+		}
+
+		//step 2 find neighbours
+		oct_idx=leaf_list;
+		int neighbours=0;
+
+
+		while(oct_idx) {
+
+			BakedLightBaker::Octant *oct = &octants[oct_idx];
+			Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive
+			pos.x+=cell_size;
+			uint64_t base=0;
+			base=int((pos.x+cell_size*0.5)/cell_size);
+			base<<=16;
+			base|=int((pos.y+cell_size*0.5)/cell_size);
+			base<<=16;
+			base|=int((pos.z+cell_size*0.5)/cell_size);
+
+			uint32_t hash = HashMapHahserDefault::hash(base);
+			uint32_t idx = hash % hash_table_size;
+
+			uint32_t bucket = hashptr[idx];
+
+			while(bucket) {
+
+				if (octhashptr[bucket].value==base) {
+
+					oct->bake_neighbour=bucket;
+					octants[bucket].first_neighbour=false;
+					neighbours++;
+					break;
+				}
+
+				bucket = octhashptr[bucket].next;
+			}
+
+			oct_idx=oct->next_leaf;
+
+		}
+
+		print_line("octant with neighbour: "+itos(neighbours));
+
+	}
+
+
+	//ok let's try to just create a texture
+
+	{
+
+		int otex_w=(1<<lattice_size)*(1<<lattice_size)*2; //make sure lattice fits horizontally
+		Vector3 lattice_cell_size=octree_aabb.size;
+		for(int i=0;i<lattice_size;i++) {
+
+			lattice_cell_size*=0.5;
+		}
+
+
+
+		while(true) {
+
+			//let's plot the leafs first, given the octree is not so obvious which size it will have
+			int row=4+4*(1<<lattice_size);
+
+
+			uint32_t oct_idx=leaf_list;
+
+			//untag
+			while(oct_idx) {
+
+				BakedLightBaker::Octant *oct = &octants[oct_idx];
+				//0,0 also means unprocessed
+				oct->texture_x=0;
+				oct->texture_y=0;
+				oct_idx=oct->next_leaf;
+
+			}
+
+			oct_idx=leaf_list;
+
+
+			print_line("begin at row "+itos(row));
+			int longest_line_reused=0;
+			int col=0;
+			int processed=0;
+
+			while(oct_idx) {
+
+				BakedLightBaker::Octant *oct = &octants[oct_idx];
+				if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) {
+					//was not processed
+					uint32_t current_idx=oct_idx;
+					int reused=0;
+
+					while(current_idx) {
+						BakedLightBaker::Octant *o = &octants[current_idx];
+						if (col+1 >= otex_w) {
+							col=0;
+							row+=4;
+						}
+						o->texture_x=col;
+						o->texture_y=row;
+						processed++;
+
+						if (o->bake_neighbour) {
+							reused++;
+						}
+						col+=o->bake_neighbour ? 1 : 2; //reuse neighbour
+						current_idx=o->bake_neighbour;
+					}
+
+					if (reused>longest_line_reused) {
+						longest_line_reused=reused;
+					}
+				}
+				oct_idx=oct->next_leaf;
+			}
+
+			print_line("processed "+itos(processed));
+
+			print_line("longest reused: "+itos(longest_line_reused));
+
+			col=0;
+			row+=4;
+			print_line("end at row "+itos(row));
+
+			//put octree, no need for recursion, just loop backwards.
+			int regular_octants=0;
+			for(int i=octant_pool_size-1;i>=0;i--) {
+
+				BakedLightBaker::Octant *oct = &octants[i];
+				if (oct->leaf) //ignore leaf
+					continue;
+				if (oct->aabb.size.x>lattice_cell_size.x*1.1) { //bigger than latice, skip
+					oct->texture_x=0;
+					oct->texture_y=0;
+				} else if (oct->aabb.size.x>lattice_cell_size.x*0.8) {
+					//this is the initial lattice
+					Vector3 pos = oct->aabb.pos - octree_aabb.pos; //make sure is always positive
+					int x = int((pos.x+lattice_cell_size.x*0.5)/lattice_cell_size.x);
+					int y = int((pos.y+lattice_cell_size.y*0.5)/lattice_cell_size.y);
+					int z = int((pos.z+lattice_cell_size.z*0.5)/lattice_cell_size.z);
+					//bug net
+					ERR_FAIL_INDEX(x,(1<<lattice_size));
+					ERR_FAIL_INDEX(y,(1<<lattice_size));
+					ERR_FAIL_INDEX(z,(1<<lattice_size));
+
+					/*int ofs = z*(1<<lattice_size)*(1<<lattice_size)+y*(1<<lattice_size)+x;
+					ofs*=4;
+					oct->texture_x=ofs%otex_w;
+					oct->texture_y=(ofs/otex_w)*4+4;
+					*/
+
+					oct->texture_x=(x+(1<<lattice_size)*z)*2;
+					oct->texture_y=4+y*4;
+					//print_line("pos: "+itos(x)+","+itos(y)+","+itos(z)+" -  ofs"+itos(oct->texture_x)+","+itos(oct->texture_y));
+
+
+				} else {
+					//an everyday regular octant
+
+					if (col+2 > otex_w) {
+						col=0;
+						row+=4;
+					}
+
+					oct->texture_x=col;
+					oct->texture_y=row;
+					col+=2;
+					regular_octants++;
+
+
+				}
+			}
+			print_line("octants end at row "+itos(row)+" totalling"+itos(regular_octants));
+
+			//ok evaluation.
+
+			if (otex_w<=2048 && row>2048) { //too big upwards, try bigger texture
+				otex_w*=2;
+				continue;
+			} else {
+				baked_octree_texture_w=otex_w;
+				baked_octree_texture_h=row+4;
+				break;
+			}
+
+		}
+
+
+	}
+
+
+	baked_octree_texture_h=nearest_power_of_2(baked_octree_texture_h);
+	print_line("RESULT! "+itos(baked_octree_texture_w)+","+itos(baked_octree_texture_h));
+
+}
+
+
+
+
+
+
+
+
+double BakedLightBaker::get_normalization(int p_light_idx) const {
+
+	double nrg=0;
+
+	const LightData &dl=lights[p_light_idx];
+	double cell_area = cell_size*cell_size;;
+	//nrg+= /*dl.energy */ (dl.rays_thrown * cell_area / dl.area);
+	nrg=dl.rays_thrown * cell_area;
+	nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel
+	nrg*=dl.constant;
+	//nrg*=5;
+	print_line("CS: "+rtos(cell_size));
+
+	return nrg;
+}
+
+void BakedLightBaker::throw_rays(int p_amount) {
+
+
+
+	for(int i=0;i<lights.size();i++) {
+
+		LightData &dl=lights[i];
+
+
+		int amount = p_amount * total_light_area / dl.area;
+
+		switch(dl.type) {
+
+			case VS::LIGHT_DIRECTIONAL: {
+
+
+				for(int j=0;j<amount;j++) {
+					Vector3 from = dl.pos;
+					double r1 = double(rand())/RAND_MAX;
+					double r2 = double(rand())/RAND_MAX;
+					from+=dl.up*(r1*2.0-1.0);
+					from+=dl.left*(r2*2.0-1.0);
+					Vector3 to = from+dl.dir*dl.length;
+					Color col=dl.diffuse;
+					col.r*=dl.energy;
+					col.g*=dl.energy;
+					col.b*=dl.energy;
+					dl.rays_thrown++;
+					total_rays++;
+					_throw_ray(i,from,to,dl.length,col,NULL,0,0,max_bounces,true);
+				}
+			} break;
+			case VS::LIGHT_OMNI: {
+
+
+				for(int j=0;j<amount;j++) {
+					Vector3 from = dl.pos;
+
+					double r1 = double(rand())/RAND_MAX;
+					double r2 = double(rand())/RAND_MAX;
+					double r3 = double(rand())/RAND_MAX;
+
+#if 0
+					//crap is not uniform..
+					Vector3 dir = Vector3(r1*2.0-1.0,r2*2.0-1.0,r3*2.0-1.0).normalized();
+
+#else
+
+					double phi = r1*Math_PI*2.0;
+					double costheta = r2*2.0-1.0;
+					double u = r3;
+
+					double theta = acos( costheta );
+					double r = 1.0 * pow( u,1/3.0 );
+
+					Vector3 dir(
+						r * sin( theta) * cos( phi ),
+						r * sin( theta) * sin( phi ),
+						r * cos( theta )
+					);
+					dir.normalize();
+
+#endif
+					Vector3 to = dl.pos+dir*dl.radius;
+					Color col=dl.diffuse;
+					col.r*=dl.energy;
+					col.g*=dl.energy;
+					col.b*=dl.energy;
+
+					dl.rays_thrown++;
+					total_rays++;
+					_throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
+//					_throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true);
+				}
+
+			} break;
+			case VS::LIGHT_SPOT: {
+
+				for(int j=0;j<amount;j++) {
+					Vector3 from = dl.pos;
+
+					double r1 = double(rand())/RAND_MAX;
+					double r2 = double(rand())/RAND_MAX;
+					double r3 = double(rand())/RAND_MAX;
+
+					float d=Math::tan(Math::deg2rad(dl.spot_angle));
+
+					float x = sin(r1*Math_PI*2.0)*d;
+					float y = cos(r1*Math_PI*2.0)*d;
+
+					Vector3 dir = r3*(dl.dir + dl.up*y + dl.left*x) + (1.0-r3)*dl.dir;
+					dir.normalize();
+
+
+					Vector3 to = dl.pos+dir*dl.radius;
+					Color col=dl.diffuse;
+					col.r*=dl.energy;
+					col.g*=dl.energy;
+					col.b*=dl.energy;
+
+					dl.rays_thrown++;
+					total_rays++;
+					_throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
+	//					_throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true);
+				}
+
+			} break;
+
+		}
+	}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) {
+
+	if (baking)
+		return;
+	cell_count=0;
+
+	base_inv=p_node->cast_to<Spatial>()->get_global_transform().affine_inverse();
+	EditorProgress ep("bake","Light Baker Setup:",5);
+	baked_light=p_light;
+	lattice_size=baked_light->get_initial_lattice_subdiv();
+	octree_depth=baked_light->get_cell_subdivision();
+	plot_size=baked_light->get_plot_size();
+	max_bounces=baked_light->get_bounces();
+	use_diffuse=baked_light->get_bake_flag(BakedLight::BAKE_DIFFUSE);
+	use_specular=baked_light->get_bake_flag(BakedLight::BAKE_SPECULAR);
+	use_translucency=baked_light->get_bake_flag(BakedLight::BAKE_TRANSLUCENT);
+
+	edge_damp=baked_light->get_edge_damp();
+	normal_damp=baked_light->get_normal_damp();
+	octree_extra_margin=baked_light->get_cell_extra_margin();
+
+
+
+	ep.step("Parsing Geometry",0);
+	_parse_geometry(p_node);
+	mat_map.clear();
+	tex_map.clear();
+	print_line("\ttotal triangles: "+itos(triangles.size()));
+	ep.step("Fixing Lights",1);
+	_fix_lights();
+	ep.step("Making BVH",2);
+	_make_bvh();
+	ep.step("Creating Light Octree",3);
+	_make_octree();
+	ep.step("Creating Octree Texture",4);
+	_make_octree_texture();
+	baking=true;
+	_start_thread();
+
+}
+
+
+void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
+
+
+	int len = baked_octree_texture_w*baked_octree_texture_h*4;
+	p_image.resize(len);
+	DVector<uint8_t>::Write w = p_image.write();
+	zeromem(w.ptr(),len);
+	float gamma = baked_light->get_gamma_adjust();
+	float mult = baked_light->get_energy_multiplier();
+
+	for(int i=0;i<len;i+=4) {
+		w[i+0]=0xFF;
+		w[i+1]=0;
+		w[i+2]=0xFF;
+		w[i+3]=0xFF;
+	}
+
+	encode_uint32(baked_octree_texture_w,&w[0]);
+	encode_uint32(baked_octree_texture_h,&w[4]);
+	encode_uint32(0,&w[8]);
+	encode_float(1<<lattice_size,&w[12]);
+	encode_uint32(octree_depth-lattice_size,&w[16]);
+
+	encode_float(octree_aabb.pos.x,&w[32]);
+	encode_float(octree_aabb.pos.y,&w[36]);
+	encode_float(octree_aabb.pos.z,&w[40]);
+	encode_float(octree_aabb.size.x,&w[44]);
+	encode_float(octree_aabb.size.y,&w[48]);
+	encode_float(octree_aabb.size.z,&w[52]);
+
+
+	BakedLightBaker::Octant *octants=octant_pool.ptr();
+	int octant_count=octant_pool_size;
+	uint8_t *ptr = w.ptr();
+
+
+	int child_offsets[8]={
+		0,
+		4,
+		baked_octree_texture_w*4,
+		baked_octree_texture_w*4+4,
+		baked_octree_texture_w*8+0,
+		baked_octree_texture_w*8+4,
+		baked_octree_texture_w*8+baked_octree_texture_w*4,
+		baked_octree_texture_w*8+baked_octree_texture_w*4+4,
+	};
+
+	Vector<double> norm_arr;
+	norm_arr.resize(lights.size());
+
+	for(int i=0;i<lights.size();i++) {
+		norm_arr[i] =  1.0/get_normalization(i);
+	}
+
+	const double *normptr=norm_arr.ptr();
+
+	int lz=lights.size();
+
+	for(int i=0;i<octant_count;i++) {
+
+		Octant &oct=octants[i];
+		if (oct.texture_x==0 && oct.texture_y==0)
+			continue;
+		int ofs = (oct.texture_y * baked_octree_texture_w + oct.texture_x)<<2;
+
+		if (oct.leaf) {
+
+			//write colors
+			for(int j=0;j<8;j++) {
+
+				//if (!oct.children[j])
+				//	continue;
+				uint8_t *iptr=&ptr[ofs+child_offsets[j]];
+				float r=0;
+				float g=0;
+				float b=0;
+
+				for(int k=0;k<lz;k++) {
+					r+=oct.light[k].accum[j][0]*normptr[k];
+					g+=oct.light[k].accum[j][1]*normptr[k];
+					b+=oct.light[k].accum[j][2]*normptr[k];
+				}
+
+				r=pow(r*mult,gamma);
+				g=pow(g*mult,gamma);
+				b=pow(b*mult,gamma);
+
+				float ic[3]={
+					r,
+					g,
+					b,
+				};
+				iptr[0]=CLAMP(ic[0]*255.0,0,255);
+				iptr[1]=CLAMP(ic[1]*255.0,0,255);
+				iptr[2]=CLAMP(ic[2]*255.0,0,255);
+				iptr[3]=255;
+			}
+
+		} else {
+
+
+			//write indices
+			for(int j=0;j<8;j++) {
+
+				if (!oct.children[j])
+					continue;
+				Octant&choct=octants[oct.children[j]];
+				uint8_t *iptr=&ptr[ofs+child_offsets[j]];
+
+				iptr[0]=choct.texture_x>>8;
+				iptr[1]=choct.texture_x&0xFF;
+				iptr[2]=choct.texture_y>>8;
+				iptr[3]=choct.texture_y&0xFF;
+
+			}
+		}
+
+	}
+
+
+}
+
+
+void BakedLightBaker::_free_bvh(BVH* p_bvh) {
+
+	if (!p_bvh->leaf) {
+		if (p_bvh->children[0])
+			_free_bvh(p_bvh->children[0]);
+		if (p_bvh->children[1])
+			_free_bvh(p_bvh->children[1]);
+	}
+
+	memdelete(p_bvh);
+
+}
+
+
+bool BakedLightBaker::is_baking() {
+
+	return baking;
+}
+
+void BakedLightBaker::set_pause(bool p_pause){
+
+	if (paused==p_pause)
+		return;
+
+	paused=p_pause;
+
+	if (paused) {
+		_stop_thread();
+	} else {
+		_start_thread();
+	}
+}
+bool BakedLightBaker::is_paused() {
+
+	return paused;
+
+}
+
+void BakedLightBaker::_bake_thread_func(void *arg) {
+
+	BakedLightBaker *ble = (BakedLightBaker*)arg;
+
+	ble->rays_at_snap_time=ble->total_rays;
+	ble->snap_time=OS::get_singleton()->get_ticks_usec();
+
+	while(!ble->bake_thread_exit) {
+
+		ble->throw_rays(1000);
+		uint64_t t=OS::get_singleton()->get_ticks_usec();
+		if (t-ble->snap_time>1000000) {
+
+			double time = (t-ble->snap_time)/1000000.0;
+
+			int rays=ble->total_rays-ble->rays_at_snap_time;
+			ble->rays_sec=int(rays/time);
+			ble->snap_time=OS::get_singleton()->get_ticks_usec();
+			ble->rays_at_snap_time=ble->total_rays;
+		}
+	}
+
+}
+
+void BakedLightBaker::_start_thread() {
+
+	if (thread!=NULL)
+		return;
+	bake_thread_exit=false;
+	thread=Thread::create(_bake_thread_func,this);
+
+}
+
+void BakedLightBaker::_stop_thread() {
+
+	if (thread==NULL)
+		return;
+	bake_thread_exit=true;
+	Thread::wait_to_finish(thread);
+	thread=NULL;
+}
+
+void BakedLightBaker::clear() {
+
+
+
+	_stop_thread();
+
+	if (bvh)
+		_free_bvh(bvh);
+
+	if (ray_stack)
+		memdelete_arr(ray_stack);
+	if (octant_stack)
+		memdelete_arr(octant_stack);
+	if (octantptr_stack)
+		memdelete_arr(octantptr_stack);
+	if (bvh_stack)
+		memdelete_arr(bvh_stack);
+
+	for(int i=0;i<octant_pool.size();i++) {
+		if (octant_pool[i].leaf) {
+			memdelete_arr( octant_pool[i].light );
+		}
+	}
+	octant_pool.clear();
+	octant_pool_size=0;
+	bvh=NULL;
+	leaf_list=0;
+	cell_count=0;
+	ray_stack=NULL;
+	octant_stack=NULL;
+	octantptr_stack=NULL;
+	bvh_stack=NULL;
+	materials.clear();
+	materials.clear();
+	textures.clear();
+	lights.clear();
+	triangles.clear();;
+	endpoint_normal.clear();
+	baked_octree_texture_w=0;
+	baked_octree_texture_h=0;
+	paused=false;
+	baking=false;
+	thread=NULL;
+	bake_thread_exit=false;
+	baked_light=Ref<BakedLight>();
+	total_rays=0;
+
+}
+
+BakedLightBaker::BakedLightBaker() {
+	octree_depth=9;
+	lattice_size=4;
+	octant_pool.clear();
+	octant_pool_size=0;
+	bvh=NULL;
+	leaf_list=0;
+	cell_count=0;
+	ray_stack=NULL;
+	bvh_stack=NULL;
+	octant_stack=NULL;
+	octantptr_stack=NULL;
+	plot_size=2.5;
+	max_bounces=2;
+	materials.clear();
+	baked_octree_texture_w=0;
+	baked_octree_texture_h=0;
+	paused=false;
+	baking=false;
+	thread=NULL;
+	bake_thread_exit=false;
+	rays_at_snap_time=0;
+	snap_time=0;
+	rays_sec=0;
+	total_rays=0;
+
+}
+
+BakedLightBaker::~BakedLightBaker() {
+
+	clear();
+}

+ 316 - 0
tools/editor/plugins/baked_light_baker.h

@@ -0,0 +1,316 @@
+#ifndef BAKED_LIGHT_BAKER_H
+#define BAKED_LIGHT_BAKER_H
+
+#include "scene/3d/baked_light_instance.h"
+#include "scene/3d/light.h"
+#include "scene/3d/mesh_instance.h"
+#include "os/thread.h"
+
+class BakedLightBaker {
+public:
+
+	enum {
+
+		ATTENUATION_CURVE_LEN=256,
+		OCTANT_POOL_CHUNK=1000000
+	};
+
+	struct OctantLight {
+
+		double accum[8][3];
+	};
+
+	struct Octant {
+		bool leaf;
+		AABB aabb;
+		uint16_t texture_x;
+		uint16_t texture_y;
+		float normal_accum[8][3];
+		int parent;
+		union {
+			struct {
+				int next_leaf;
+				float offset[3];
+				int bake_neighbour;
+				bool first_neighbour;
+				OctantLight *light;
+			};
+			int children[8];
+		};
+	};
+
+	struct OctantHash {
+
+		int next;
+		uint32_t hash;
+		uint64_t value;
+
+	};
+
+	struct MeshTexture {
+
+		Vector<uint8_t> tex;
+		int tex_w,tex_h;
+
+		_FORCE_INLINE_ void get_color(const Vector2& p_uv,Color& ret) {
+
+			if (tex_w && tex_h) {
+
+				int x = Math::fast_ftoi(Math::fposmod(p_uv.x,1.0)*tex_w);
+				int y = Math::fast_ftoi(Math::fposmod(p_uv.y,1.0)*tex_w);
+				x=CLAMP(x,0,tex_w-1);
+				y=CLAMP(y,0,tex_h-1);
+				const uint8_t*ptr = &tex[(y*tex_w+x)*4];
+				ret.r*=ptr[0]/255.0;
+				ret.g*=ptr[1]/255.0;
+				ret.b*=ptr[2]/255.0;
+				ret.a*=ptr[3]/255.0;
+			}
+		}
+
+	};
+
+	struct Param {
+
+		Color color;
+		MeshTexture*tex;
+		_FORCE_INLINE_ Color get_color(const Vector2& p_uv) {
+
+			Color ret=color;
+			if (tex)
+				tex->get_color(p_uv,ret);
+			return ret;
+
+		}
+
+	};
+
+	struct MeshMaterial {
+
+		Param diffuse;
+		Param specular;
+		Param emission;
+	};
+
+	struct Triangle {
+
+		AABB aabb;
+		Vector3 vertices[3];
+		Vector2 uvs[3];
+		Vector3 normals[3];
+		MeshMaterial *material;
+
+		_FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) {
+
+			Vector3 v0 = vertices[1] - vertices[0];
+			Vector3 v1 = vertices[2] - vertices[0];
+			Vector3 v2 = p_pos - vertices[0];
+
+			float d00 = v0.dot( v0);
+			float d01 = v0.dot( v1);
+			float d11 = v1.dot( v1);
+			float d20 = v2.dot( v0);
+			float d21 = v2.dot( v1);
+			float denom = (d00 * d11 - d01 * d01);
+			if (denom==0)
+				return uvs[0];
+			float v = (d11 * d20 - d01 * d21) / denom;
+			float w = (d00 * d21 - d01 * d20) / denom;
+			float u = 1.0f - v - w;
+
+			return uvs[0]*u + uvs[1]*v  + uvs[2]*w;
+		}
+
+		_FORCE_INLINE_ void get_uv_and_normal(const Vector3& p_pos,Vector2& r_uv,Vector3& r_normal) {
+
+			Vector3 v0 = vertices[1] - vertices[0];
+			Vector3 v1 = vertices[2] - vertices[0];
+			Vector3 v2 = p_pos - vertices[0];
+
+			float d00 = v0.dot( v0);
+			float d01 = v0.dot( v1);
+			float d11 = v1.dot( v1);
+			float d20 = v2.dot( v0);
+			float d21 = v2.dot( v1);
+			float denom = (d00 * d11 - d01 * d01);
+			if (denom==0) {
+				r_normal=normals[0];
+				r_uv=uvs[0];
+				return;
+			}
+			float v = (d11 * d20 - d01 * d21) / denom;
+			float w = (d00 * d21 - d01 * d20) / denom;
+			float u = 1.0f - v - w;
+
+			r_uv=uvs[0]*u + uvs[1]*v  + uvs[2]*w;
+			r_normal=(normals[0]*u+normals[1]*v+normals[2]*w).normalized();
+		}
+	};
+
+
+	struct BVH {
+
+		AABB aabb;
+		Vector3 center;
+		Triangle *leaf;
+		BVH*children[2];
+	};
+
+
+	struct BVHCmpX {
+
+		bool operator()(const BVH* p_left, const BVH* p_right) const {
+
+			return p_left->center.x < p_right->center.x;
+		}
+	};
+
+	struct BVHCmpY {
+
+		bool operator()(const BVH* p_left, const BVH* p_right) const {
+
+			return p_left->center.y < p_right->center.y;
+		}
+	};
+	struct BVHCmpZ {
+
+		bool operator()(const BVH* p_left, const BVH* p_right) const {
+
+			return p_left->center.z < p_right->center.z;
+		}
+	};
+
+
+	struct LightData {
+
+		VS::LightType type;
+
+		Vector3 pos;
+		Vector3 up;
+		Vector3 left;
+		Vector3 dir;
+		Color diffuse;
+		Color specular;
+		float energy;
+		float length;
+		int rays_thrown;
+
+		float radius;
+		float attenuation;
+		float spot_angle;
+		float spot_attenuation;
+		float area;
+
+		float constant;
+
+		bool bake_direct;
+
+		Vector<float> attenuation_table;
+
+	};
+
+
+	Vector<LightData> lights;
+
+	List<MeshMaterial> materials;
+	List<MeshTexture> textures;
+
+	AABB octree_aabb;
+	Vector<Octant> octant_pool;
+	int octant_pool_size;
+	BVH*bvh;
+	Vector<Triangle> triangles;
+	Transform base_inv;
+	int leaf_list;
+	int octree_depth;
+	int cell_count;
+	uint32_t *ray_stack;
+	uint32_t *octant_stack;
+	uint32_t *octantptr_stack;
+	Map<Vector3,Vector3> endpoint_normal;
+	BVH **bvh_stack;
+	float cell_size;
+	float plot_size; //multiplied by cell size
+	float octree_extra_margin;
+
+	int max_bounces;
+	uint64_t total_rays;
+	bool use_diffuse;
+	bool use_specular;
+	bool use_translucency;
+
+
+	int baked_octree_texture_w;
+	int baked_octree_texture_h;
+	int lattice_size;
+	float edge_damp;
+	float normal_damp;
+
+	bool paused;
+	bool baking;
+
+	Map<Ref<Material>,MeshMaterial*> mat_map;
+	Map<Ref<Texture>,MeshTexture*> tex_map;
+
+
+
+	MeshTexture* _get_mat_tex(const Ref<Texture>& p_tex);
+	void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform);
+	void _parse_geometry(Node* p_node);
+	BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth);
+	void _make_bvh();
+	void _make_octree();
+	void _make_octree_texture();
+	void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth);
+
+
+	void _free_bvh(BVH* p_bvh);
+
+	void _fix_lights();
+
+	Ref<BakedLight> baked_light;
+
+
+	//void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,int p_octant=0);
+	void _plot_light(int p_light_index,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Plane& p_plane);
+	//void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
+
+	float _throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false);
+
+
+	float total_light_area;
+	uint64_t rays_at_snap_time;
+	uint64_t snap_time;
+	int rays_sec;
+
+
+	Thread *thread;
+	bool bake_thread_exit;
+	static void _bake_thread_func(void *arg);
+
+	void _start_thread();
+	void _stop_thread();
+public:
+
+
+	void throw_rays(int p_amount);
+	double get_normalization(int p_light_idx) const;
+
+	void bake(const Ref<BakedLight>& p_light,Node *p_base);
+	bool is_baking();
+	void set_pause(bool p_pause);
+	bool is_paused();
+	int get_rays_sec() { return rays_sec; }
+
+	void update_octree_image(DVector<uint8_t> &p_image);
+
+	Ref<BakedLight> get_baked_light() { return baked_light; }
+
+	void clear();
+
+	BakedLightBaker();
+	~BakedLightBaker();
+
+};
+
+#endif // BAKED_LIGHT_BAKER_H

Plik diff jest za duży
+ 105 - 927
tools/editor/plugins/baked_light_editor_plugin.cpp


+ 16 - 14
tools/editor/plugins/baked_light_editor_plugin.h

@@ -3,15 +3,17 @@
 
 
 #include "tools/editor/editor_plugin.h"
 #include "tools/editor/editor_plugin.h"
 #include "tools/editor/editor_node.h"
 #include "tools/editor/editor_node.h"
-#include "scene/3d/baked_light.h"
+#include "tools/editor/plugins/baked_light_baker.h"
 #include "scene/gui/spin_box.h"
 #include "scene/gui/spin_box.h"
 
 
+
+
 /**
 /**
 	@author Juan Linietsky <[email protected]>
 	@author Juan Linietsky <[email protected]>
 */
 */
 
 
 
 
-class BakedLightBaker;
+
 class MeshInstance;
 class MeshInstance;
 
 
 class BakedLightEditor : public Control {
 class BakedLightEditor : public Control {
@@ -20,20 +22,18 @@ class BakedLightEditor : public Control {
 
 
 
 
 	float update_timeout;
 	float update_timeout;
-	DVector<Color> colors;
-	DVector<Vector3> vertices;
-	Ref<Mesh> mesh;
-	Ref<FixedMaterial> material;
-
-	Thread *bake_thread;
-	bool bake_thread_exit;
+	DVector<uint8_t> octree_texture;
 
 
-	MeshInstance *preview;
 	BakedLightBaker *baker;
 	BakedLightBaker *baker;
 	AcceptDialog *err_dialog;
 	AcceptDialog *err_dialog;
 
 
-	MenuButton * options;
-	BakedLight *node;
+	HBoxContainer *bake_hbox;
+	Button *button_bake;
+	Button *button_reset;
+	Label *bake_info;
+
+
+	BakedLightInstance *node;
 
 
 	enum Menu {
 	enum Menu {
 
 
@@ -41,7 +41,9 @@ class BakedLightEditor : public Control {
 		MENU_OPTION_CLEAR
 		MENU_OPTION_CLEAR
 	};
 	};
 
 
-	static void _bake_thread_func(void *arg);
+	void _bake_pressed();
+	void _clear_pressed();
+
 	void _end_baking();
 	void _end_baking();
 	void _menu_option(int);
 	void _menu_option(int);
 
 
@@ -52,7 +54,7 @@ protected:
 	void _notification(int p_what);
 	void _notification(int p_what);
 public:
 public:
 
 
-	void edit(BakedLight *p_baked_light);
+	void edit(BakedLightInstance *p_baked_light);
 	BakedLightEditor();
 	BakedLightEditor();
 	~BakedLightEditor();
 	~BakedLightEditor();
 };
 };

+ 64 - 6
tools/editor/project_export.cpp

@@ -232,6 +232,26 @@ void ProjectExportDialog::_format_toggled() {
 }
 }
 
 
 
 
+void ProjectExportDialog::_script_edited(Variant v) {
+
+	if (updating_script)
+		return;
+	updating_script=true;
+	EditorNode::get_undo_redo()->create_action("Edit Script Options");
+	EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"script_set_action",script_mode->get_selected());
+	EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(),"script_set_action",EditorImportExport::get_singleton()->script_get_action());
+	EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"script_set_encryption_key",script_key->get_text());
+	EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(),"script_set_encryption_key",EditorImportExport::get_singleton()->script_get_encryption_key());
+	EditorNode::get_undo_redo()->add_do_method(this,"_update_script");
+	EditorNode::get_undo_redo()->add_undo_method(this,"_update_script");
+	EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg");
+	EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg");
+	EditorNode::get_undo_redo()->commit_action();
+	updating_script=false;
+
+
+}
+
 void ProjectExportDialog::_notification(int p_what) {
 void ProjectExportDialog::_notification(int p_what) {
 
 
 	switch(p_what) {
 	switch(p_what) {
@@ -277,10 +297,16 @@ void ProjectExportDialog::_notification(int p_what) {
 			image_action->select(EditorImportExport::get_singleton()->get_export_image_action());
 			image_action->select(EditorImportExport::get_singleton()->get_export_image_action());
 			image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality());
 			image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality());
 			image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_shrink());
 			image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_shrink());
+			_update_script();
+
+
 			image_quality->connect("value_changed",this,"_quality_edited");
 			image_quality->connect("value_changed",this,"_quality_edited");
 			image_shrink->connect("value_changed",this,"_shrink_edited");
 			image_shrink->connect("value_changed",this,"_shrink_edited");
 			image_action->connect("item_selected",this,"_image_export_edited");
 			image_action->connect("item_selected",this,"_image_export_edited");
 
 
+			script_mode->connect("item_selected",this,"_script_edited");
+			script_key->connect("text_changed",this,"_script_edited");
+
 			for(int i=0;i<formats.size();i++) {
 			for(int i=0;i<formats.size();i++) {
 				if (EditorImportExport::get_singleton()->get_image_formats().has(formats[i]->get_text(0)))
 				if (EditorImportExport::get_singleton()->get_image_formats().has(formats[i]->get_text(0)))
 					formats[i]->set_checked(0,true);
 					formats[i]->set_checked(0,true);
@@ -651,10 +677,15 @@ bool ProjectExportDialog::_update_group_treef(TreeItem *p_parent,EditorFileSyste
 }
 }
 void ProjectExportDialog::_update_group_tree() {
 void ProjectExportDialog::_update_group_tree() {
 
 
+	if (updating)
+		return;
+
 	group_images->clear();
 	group_images->clear();
 
 
 	if (_get_selected_group()=="")
 	if (_get_selected_group()=="")
 		return;
 		return;
+
+	updating=true;
 	print_line("****UGT");
 	print_line("****UGT");
 	List<String> img_extensions;
 	List<String> img_extensions;
 	ImageLoader::get_recognized_extensions(&img_extensions);
 	ImageLoader::get_recognized_extensions(&img_extensions);
@@ -677,7 +708,7 @@ void ProjectExportDialog::_update_group_tree() {
 		groupenum+=","+String(E->get());
 		groupenum+=","+String(E->get());
 	}
 	}
 
 
-
+	updating=false;
 
 
 
 
 	_update_group_treef(NULL,EditorFileSystem::get_singleton()->get_filesystem(),extensions,groupenum,group_index);
 	_update_group_treef(NULL,EditorFileSystem::get_singleton()->get_filesystem(),extensions,groupenum,group_index);
@@ -690,7 +721,7 @@ void ProjectExportDialog::_group_changed(Variant v) {
 		return;
 		return;
 	if (_get_selected_group()=="")
 	if (_get_selected_group()=="")
 		return;
 		return;
-
+	updating=true;
 	StringName name = _get_selected_group();
 	StringName name = _get_selected_group();
 	EditorNode::get_undo_redo()->create_action("Change Image Group");
 	EditorNode::get_undo_redo()->create_action("Change Image Group");
 	EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"image_export_group_set_image_action",name,group_image_action->get_selected());
 	EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(),"image_export_group_set_image_action",name,group_image_action->get_selected());
@@ -706,6 +737,7 @@ void ProjectExportDialog::_group_changed(Variant v) {
 	EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg");
 	EditorNode::get_undo_redo()->add_do_method(this,"_save_export_cfg");
 	EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg");
 	EditorNode::get_undo_redo()->add_undo_method(this,"_save_export_cfg");
 	EditorNode::get_undo_redo()->commit_action();
 	EditorNode::get_undo_redo()->commit_action();
+	updating=false;
 }
 }
 
 
 void ProjectExportDialog::_group_item_edited() {
 void ProjectExportDialog::_group_item_edited() {
@@ -926,11 +958,11 @@ void ProjectExportDialog::_group_atlas_preview() {
 
 
 	int flags=0;
 	int flags=0;
 
 
-	if (Globals::get_singleton()->get("texture_import/filter"))
+	if (Globals::get_singleton()->get("image_loader/filter"))
 		flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER;
 		flags|=EditorTextureImportPlugin::IMAGE_FLAG_FILTER;
-	if (!Globals::get_singleton()->get("texture_import/gen_mipmaps"))
+	if (!Globals::get_singleton()->get("image_loader/gen_mipmaps"))
 		flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS;
 		flags|=EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS;
-	if (!Globals::get_singleton()->get("texture_import/repeat"))
+	if (!Globals::get_singleton()->get("image_loader/repeat"))
 		flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT;
 		flags|=EditorTextureImportPlugin::IMAGE_FLAG_REPEAT;
 
 
 	flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA;
 	flags|=EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA;
@@ -956,6 +988,17 @@ void ProjectExportDialog::_group_atlas_preview() {
 
 
 }
 }
 
 
+void ProjectExportDialog::_update_script() {
+
+	if (updating_script)
+		return;
+	updating_script=true;
+	script_mode->select(EditorImportExport::get_singleton()->script_get_action());
+	script_key->set_text(EditorImportExport::get_singleton()->script_get_encryption_key());
+	updating_script=false;
+
+}
+
 void ProjectExportDialog::_image_filter_changed(String) {
 void ProjectExportDialog::_image_filter_changed(String) {
 
 
 	_update_group_tree();
 	_update_group_tree();
@@ -991,6 +1034,8 @@ void ProjectExportDialog::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("_group_atlas_preview"),&ProjectExportDialog::_group_atlas_preview);
 	ObjectTypeDB::bind_method(_MD("_group_atlas_preview"),&ProjectExportDialog::_group_atlas_preview);
 	ObjectTypeDB::bind_method(_MD("_group_select_all"),&ProjectExportDialog::_group_select_all);
 	ObjectTypeDB::bind_method(_MD("_group_select_all"),&ProjectExportDialog::_group_select_all);
 	ObjectTypeDB::bind_method(_MD("_group_select_none"),&ProjectExportDialog::_group_select_none);
 	ObjectTypeDB::bind_method(_MD("_group_select_none"),&ProjectExportDialog::_group_select_none);
+	ObjectTypeDB::bind_method(_MD("_script_edited"),&ProjectExportDialog::_script_edited);
+	ObjectTypeDB::bind_method(_MD("_update_script"),&ProjectExportDialog::_update_script);
 
 
 
 
 	ObjectTypeDB::bind_method(_MD("export_platform"),&ProjectExportDialog::export_platform);
 	ObjectTypeDB::bind_method(_MD("export_platform"),&ProjectExportDialog::export_platform);
@@ -1171,7 +1216,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	group_lossy_quality->set_step(0.1);
 	group_lossy_quality->set_step(0.1);
 	group_lossy_quality->set_val(0.7);
 	group_lossy_quality->set_val(0.7);
 	group_options->add_margin_child("Lossy Quality:",group_lossy_quality);
 	group_options->add_margin_child("Lossy Quality:",group_lossy_quality);
-	group_lossy_quality->connect("value_changed",this,"_group_changed");
+	group_lossy_quality->connect("value_changed",this,"_quality_edited");
 
 
 	group_atlas = memnew(CheckButton);
 	group_atlas = memnew(CheckButton);
 	group_atlas->set_pressed("Generate Atlas");
 	group_atlas->set_pressed("Generate Atlas");
@@ -1261,6 +1306,18 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	hbc->add_child(button_reload);
 	hbc->add_child(button_reload);
 */
 */
 
 
+	script_vbox = memnew( VBoxContainer );
+	script_vbox->set_name("Script");
+	sections->add_child(script_vbox);
+	script_mode = memnew( OptionButton );
+	script_vbox->add_margin_child("Script Export Mode:",script_mode);
+	script_mode->add_item("Text");
+	script_mode->add_item("Compiled");
+	script_mode->add_item("Encrypted (Provide Key Below)");
+	script_key = memnew( LineEdit );
+	script_vbox->add_margin_child("Script Encryption Key (256-bits as hex):",script_key);
+
+
 
 
 	updating=false;
 	updating=false;
 
 
@@ -1302,6 +1359,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	add_child(pck_export);
 	add_child(pck_export);
 
 
 	button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck");
 	button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck");
+	updating_script=false;
 
 
 
 
 }
 }

+ 9 - 0
tools/editor/project_export.h

@@ -132,6 +132,12 @@ private:
 	TextureFrame *atlas_preview_frame;
 	TextureFrame *atlas_preview_frame;
 
 
 
 
+	VBoxContainer *script_vbox;
+	OptionButton *script_mode;
+	LineEdit *script_key;
+
+
+
 	void _export_mode_changed(int p_idx);
 	void _export_mode_changed(int p_idx);
 	void _prop_edited(String what);
 	void _prop_edited(String what);
 
 
@@ -166,6 +172,9 @@ private:
 	void _group_select_none();
 	void _group_select_none();
 	void _group_del(Object *item,int p_column, int p_button);
 	void _group_del(Object *item,int p_column, int p_button);
 
 
+	bool updating_script;
+	void _update_script();
+	void _script_edited(Variant v);
 	void _export_action(const String& p_file);
 	void _export_action(const String& p_file);
 	void _export_action_pck(const String& p_file);
 	void _export_action_pck(const String& p_file);
 	void ok_pressed();
 	void ok_pressed();

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików