Browse Source

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

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

Juan Linietsky 11 years ago
parent
commit
9b8696d3dd
61 changed files with 4224 additions and 1310 deletions
  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 = {}
 
+
 for p in platform_list:
 
 	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.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")
 
+
 Export('env')
 
 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_FAIL_COND_V( err != OK, "" );
 
-	int b64len = len / 3 * 4 + 4;
+	int b64len = len / 3 * 4 + 4 + 1;
 	DVector<uint8_t> b64buff;
 	b64buff.resize(b64len);
 	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();
 
 	DVector<uint8_t> buf;
-	buf.resize(strlen / 4 * 3);
+	buf.resize(strlen / 4 * 3 + 1);
 	DVector<uint8_t>::Write w = buf.write();
 
 	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)
 		_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);
-	if (format==FORMAT_ETC && _image_decompress_etc)
+	else if (format==FORMAT_ETC && _image_decompress_etc)
 		_image_decompress_etc(this);
+	else
+		return ERR_UNAVAILABLE;
+	return OK;
 }
 
 

+ 3 - 3
core/image.h

@@ -45,8 +45,8 @@
 class Image {
 
 	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:
 
@@ -317,7 +317,7 @@ public:
 
 	Error compress(CompressMode p_mode=COMPRESS_BC);
 	Image compressed(int p_mode); /* from the Image::CompressMode enum */
-	void decompress();
+	Error decompress();
 
 	void fix_alpha_edges();
 	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) {
 
-	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("&gt;","<");
 	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("&amp;","&");
-
+*/
 	//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) {
 
 			CharType c=get_char();
+			if (c<=32)
+				continue;
 
 			if (idx&1) {
 
 				byte|=HEX2CHR(c);
 				bytesptr[idx>>1]=byte;
+				//printf("%x\n",int(byte));
 			} else {
 
 				byte=HEX2CHR(c)<<4;

+ 1 - 1
core/io/resource_format_xml.h

@@ -68,7 +68,7 @@ friend class ResourceFormatLoaderXML;
 	List<RES> resource_cache;
 	Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true);
 	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 parse_property_data(String &r_data);
 	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);
 	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 {
 

+ 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
 	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;
+	_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;
 	bool intersects_plane(const Plane &p_plane) const;
 
@@ -89,7 +91,7 @@ public:
 	_FORCE_INLINE_ real_t get_shortest_axis_size() 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;
 	_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;
 }
 
+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;
 
 #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);
 		Vector3 e1=from-to;
 		for (int j=0;j<3;j++) {
-			Vector3 e2=edge_norms[i];
+			Vector3 e2=edge_norms[j];
 
 			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;
+	_FORCE_INLINE_ bool intersects_aabb2(const AABB& p_aabb) const;
 	operator String() const;
 
         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

+ 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;
 	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) {
 
-		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 {
 		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 {
 
 	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);
 }
 
+bool PackedDataContainerRef::_is_dictionary() const {
+
+	return from->_type_at_ofs(offset) == PackedDataContainer::TYPE_DICT;
+};
 
 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_get"),&PackedDataContainerRef::_iter_get);
 	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;
 	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;
+	uint32_t _type_at_ofs(uint32_t p_ofs) const;
 	int _size(uint32_t p_ofs) const;
 
 protected:
@@ -100,6 +101,7 @@ public:
 	Variant _iter_init(const Array& p_iter);
 	Variant _iter_next(const Array& p_iter);
 	Variant _iter_get(const Variant& p_iter);
+	bool _is_dictionary() const;
 
 	int size() 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) {
 
 	if (values.has(p_name)) {

+ 1 - 0
core/script_language.h

@@ -166,6 +166,7 @@ public:
 	virtual ~ScriptLanguage() {};	
 };
 
+extern uint8_t script_encryption_key[32];
 
 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_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>
 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;
 }
 
-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;
 }
 

+ 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);
 			Variant vref=ref;
 			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) {
 				valid=false;

File diff suppressed because it is too large
+ 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->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
 	texture->width=p_width;
 	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 Skeleton *prev_skeleton =NULL;
 	uint8_t prev_sort_flags=0xFF;
+	const BakedLightData *prev_baked_light=NULL;
 
 	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_PSSM4,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;
 		const Skeleton *skeleton = e->skeleton;
 		const Geometry *geometry_cmp = e->geometry_cmp;
+		const BakedLightData *baked_light = e->instance->baked_light;
 
 		bool rebind=false;
+		bool bind_baked_light_octree=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;
 			}
 
+			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) {
@@ -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);
 
 
@@ -5726,6 +5770,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		prev_light=e->light;
 		prev_light_type=e->light_type;
 		prev_sort_flags=sort_flags;
+		prev_baked_light=baked_light;
 //		prev_geometry_type=geometry->type;
 	}
 

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

@@ -93,6 +93,13 @@ varying vec3 tangent_interp;
 varying vec3 binormal_interp;
 #endif
 
+#ifdef ENABLE_AMBIENT_OCTREE
+
+uniform highp mat4 ambient_octree_inverse_transform;
+varying highp vec3 ambient_octree_coords;
+
+#endif
+
 #ifdef USE_FOG
 
 varying vec4 fog_interp;
@@ -173,12 +180,19 @@ void main() {
 #ifdef USE_UNIFORM_INSTANCING
 
 	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
 
 #ifdef USE_ATTRIBUTE_INSTANCING
 
 	highp mat4 minst=mat4(instance_row0,instance_row1,instance_row2,instance_row3);
 	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
 
@@ -201,9 +215,16 @@ void main() {
 	);*/
 
 	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
 	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
@@ -233,6 +254,11 @@ void main() {
 
 #endif
 
+#ifdef ENABLE_AMBIENT_OCTREE
+
+	ambient_octree_coords = (ambient_octree_transform * vertex_in).xyz;
+#endif
+
 	vertex_interp = (modelview * vertex_in).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 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
@@ -745,10 +781,57 @@ FRAGMENT_SHADER_CODE
 	}
 #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;
 
 
+
+
+
 #ifdef LIGHT_USE_SHADOW
 #ifdef LIGHT_TYPE_DIRECTIONAL
 
@@ -921,6 +1004,8 @@ FRAGMENT_SHADER_CODE
 #endif
 
 
+
+
 #ifdef USE_VERTEX_LIGHTING
 
 	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+=emission * const_light_mult;
 
-
 #endif
 
 
+#ifdef ENABLE_AMBIENT_OCTREE
 
+	diffuse.rgb+=ambientmap_color;
+#endif
 
 
 #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);
 
 	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
 			// is a valid IP4 Address
 

+ 26 - 3
modules/gdscript/gd_script.cpp

@@ -31,6 +31,7 @@
 #include "global_constants.h"
 #include "gd_compiler.h"
 #include "os/file_access.h"
+#include "io/file_access_encrypted.h"
 
 /* TODO:
 
@@ -1591,7 +1592,28 @@ void GDScript::_bind_methods() {
 
 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);
 	path=p_path;
 
@@ -2225,7 +2247,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig
 
 	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_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("gdc");
+	p_extensions->push_back("gde");
 }
 
 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 el = p_path.extension().to_lower();
-	if (el=="gd" || el=="gdc")
+	if (el=="gd" || el=="gdc" || el=="gde")
 		return "GDScript";
 	return "";
 }

+ 1 - 0
modules/gdscript/gd_tokenizer.cpp

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

+ 65 - 13
modules/gdscript/register_types.cpp

@@ -14,6 +14,8 @@
 #include "gd_script.h"
 #include "io/resource_loader.h"
 #include "os/file_access.h"
+#include "io/file_access_encrypted.h"
+
 
 
 GDScriptLanguage *script_language_gd=NULL;
@@ -25,6 +27,7 @@ ResourceFormatSaverGDScript *resource_saver_gd=NULL;
 #include "tools/editor/editor_import_export.h"
 #include "gd_tokenizer.h"
 #include "tools/editor/editor_node.h"
+#include "tools/editor/editor_settings.h"
 
 class EditorExportGDScript : public EditorExportPlugin {
 
@@ -34,20 +37,69 @@ public:
 
 	virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) {
 		//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>();

+ 139 - 1
modules/gridmap/grid_map.cpp

@@ -31,7 +31,9 @@
 #include "scene/resources/surface_tool.h"
 #include "message_queue.h"
 #include "scene/3d/light.h"
+#include "scene/3d/baked_light_instance.h"
 #include "io/marshalls.h"
+#include "scene/scene_string_names.h"
 
 
 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);
 	} else if (name=="cell/scale") {
 		set_cell_scale(p_value);
+	} else if (name=="lighting/bake") {
+		set_use_baked_light(p_value);
 	} else if (name=="theme/bake") {
 		set_bake(p_value);
 /*	} else if (name=="cells") {
@@ -120,6 +124,7 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
 				g.baked=b;
 				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_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();
 	} else if (name=="cell/scale") {
 		r_ret= cell_scale;
+	} else if (name=="lighting/bake") {
+		r_ret=is_using_baked_light();
 	} else if (name=="theme/bake") {
 		r_ret= bake;
 	} 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::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::INT, "cell/octant_size",PROPERTY_HINT_RANGE,"1,1024,1") );
 	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_instance = VS::get_singleton()->instance_create();
 		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) {
 
 			//unbake just in case
@@ -863,6 +873,12 @@ void GridMap::_notification(int p_what) {
 			awaiting_update=false;
 
 			last_transform=get_global_transform();
+
+			if (use_baked_light) {
+
+				_find_baked_light();
+			}
+
 		} break;
 		case NOTIFICATION_TRANSFORM_CHANGED: {
 
@@ -883,6 +899,17 @@ void GridMap::_notification(int p_what) {
 				_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);
 			//_update_dirty_map_callback();
 			//_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("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::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() {
@@ -1516,7 +1653,8 @@ GridMap::GridMap() {
 	bake=false;
 	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
 
 
+class BakedLightInstance;
+
 class GridMap : public Spatial {
 
 
@@ -202,6 +204,14 @@ class GridMap : public Spatial {
 
 	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:
 
 	bool _set(const StringName& p_name, const Variant& p_value);
@@ -211,6 +221,7 @@ protected:
 	void _notification(int p_what);
 	static void _bind_methods();
 
+
 public:
 
 	enum {
@@ -262,6 +273,8 @@ public:
 
 	void bake_geometry();
 
+	void set_use_baked_light(bool p_use);
+	bool is_using_baked_light() const;
 	void clear();
 
 	GridMap();

+ 1 - 1
platform/javascript/detect.py

@@ -30,7 +30,7 @@ def get_flags():
 		('theora', 'no'),
 		('tools', 'no'),
 		('nedmalloc', 'no'),
-		('vorbis', 'yes'),
+		('vorbis', 'no'),
 		('musepack', 'no'),
 		('squirrel', '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 {
 
 	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() {
 
 	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("set_operator","operator"), &Light::set_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 );
 	/*
 	if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
@@ -490,6 +519,8 @@ Light::Light(VisualServer::LightType p_type) {
 	op=OPERATOR_ADD;
 	set_project_shadows( false );
 	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_ZOFFSET_SCALE]=2.0;
 
+
 }
 
 

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

@@ -64,6 +64,14 @@ public:
 		COLOR_SPECULAR=VisualServer::LIGHT_COLOR_SPECULAR
 	};
 
+	enum BakeMode {
+
+		BAKE_MODE_DISABLED,
+		BAKE_MODE_INDIRECT,
+		BAKE_MODE_FULL
+
+	};
+
 
 	enum Operator {
 
@@ -78,8 +86,10 @@ private:
 	Color colors[3];
 	
 	
+	BakeMode bake_mode;
 	VisualServer::LightType type;
 	bool shadows;
+	bool enabled;
 	Operator op;
 	
 // bind helpers
@@ -114,6 +124,12 @@ public:
 	void set_operator(Operator p_op);
 	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 DVector<Face3> get_faces(uint32_t p_usage_flags) const;
 
@@ -127,6 +143,7 @@ public:
 VARIANT_ENUM_CAST( Light::Parameter );
 VARIANT_ENUM_CAST( Light::LightColor );
 VARIANT_ENUM_CAST( Light::Operator );
+VARIANT_ENUM_CAST( Light::BakeMode);
 
 
 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)
 
 	frame=p_frame;
+	_queue_update();
 }
 
 int Sprite3D::get_frame() const {

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

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

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

@@ -31,7 +31,7 @@
 #include "servers/visual_server.h"
 #include "room_instance.h"
 #include "scene/scene_string_names.h"
-
+#include "baked_light_instance.h"
 #include "skeleton.h"
 
 AABB VisualInstance::get_transformed_aabb() const {
@@ -186,6 +186,61 @@ float GeometryInstance::get_draw_range_end() const {
 	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) {
 
 	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");
 		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{
@@ -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("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_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);
@@ -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/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/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
 
 	ADD_SIGNAL( MethodInfo("visibility_changed"));
 
@@ -258,5 +328,7 @@ GeometryInstance::GeometryInstance() {
 	flags[FLAG_BILLBOARD_FIX_Y]=false;
 	flags[FLAG_DEPH_SCALE]=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 {
 
 	OBJ_TYPE( GeometryInstance, VisualInstance );
@@ -91,7 +93,7 @@ public:
 		FLAG_BILLBOARD_FIX_Y=VS::INSTANCE_FLAG_BILLBOARD_FIX_Y,
 		FLAG_DEPH_SCALE=VS::INSTANCE_FLAG_DEPH_SCALE,
 		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,
 	};
 
@@ -102,8 +104,13 @@ private:
 	Ref<Material> material_override;
 	float draw_begin;
 	float draw_end;
+	void _find_baked_light();
+	BakedLightInstance *baked_light_instance;
+
+	void _baked_light_changed();
 protected:
 
+	void _notification(int p_what);
 	static void _bind_methods();
 public:
 

+ 3 - 2
scene/register_scene_types.cpp

@@ -187,7 +187,7 @@
 #include "scene/3d/area.h"
 #include "scene/3d/physics_joint.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/immediate_geometry.h"
 #include "scene/3d/sprite_3d.h"
@@ -407,7 +407,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<PathFollow>();
 	ObjectTypeDB::register_type<VisibilityNotifier>();
 	ObjectTypeDB::register_type<VisibilityEnabler>();
-	ObjectTypeDB::register_type<BakedLight>();
+	ObjectTypeDB::register_type<BakedLightInstance>();
 	ObjectTypeDB::register_type<WorldEnvironment>();
 
 	//scenariofx	
@@ -515,6 +515,7 @@ void register_scene_types() {
 
 	ObjectTypeDB::register_type<SurfaceTool>();
 	ObjectTypeDB::register_type<MeshDataTool>();
+	ObjectTypeDB::register_type<BakedLight>();
 
 	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");
 	_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 _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 int multimesh_get_visible_instances(RID p_multimesh) const=0;
 
+	/* BAKED LIGHT */
+
+
+
+
 	/* IMMEDIATE API */
 
 	virtual RID immediate_create()=0;
@@ -490,6 +495,20 @@ public:
 	
 	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 {
 
@@ -498,6 +517,8 @@ public:
 		RID material_override;
 		Vector<RID> light_instances;
 		Vector<float> morph_values;
+		BakedLightData *baked_light;
+		Transform *baked_light_octree_xform;
 		bool mirror :8;
 		bool depth_scale :8;
 		bool billboard :8;

+ 300 - 9
servers/visual/visual_server_raster.cpp

@@ -31,6 +31,7 @@
 #include "globals.h"
 #include "default_mouse_cursor.xpm"
 #include "sort.h"
+#include "io/marshalls.h"
 // careful, these may run in different threads than the visual server
 
 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);
 	ERR_FAIL_COND(!room);
 	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 */
 
 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) {
 			instance->scenario->octree.erase( instance->octree_id );
 			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->portal_info = memnew(Instance::PortalInfo);
 			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 {
 			ERR_EXPLAIN("Invalid base RID for instance!")
 			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) {
 
 	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
 		InstanceSet::Element *E=p_instance->lights.front();
@@ -2395,13 +2616,20 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
 			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();
+	} 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;
 
 	AABB new_aabb;
@@ -2463,7 +2691,7 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
 
 		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;
 		}
 
@@ -2578,6 +2806,13 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) {
 			}
 
 		} 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: {}
 	}
 
@@ -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 *********/
 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;
 }
 
+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) {
 
@@ -3414,6 +3683,17 @@ void VisualServerRaster::free( RID p_rid ) {
 		portal_owner.free(p_rid);
 		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)) {
 		// delete te camera
 		
@@ -3464,8 +3744,9 @@ void VisualServerRaster::free( RID p_rid ) {
 
 		instance_set_room(p_rid,RID());
 		instance_set_scenario(p_rid,RID());
+		instance_geometry_set_baked_light(p_rid,RID());
 		instance_set_base(p_rid,RID());
-			
+
 		instance_owner.free(p_rid);
 		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;
 
-			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);
 				_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;
 
 			ERR_CONTINUE(!light);
+			if (!light->light_info->enabled)
+				continue;
+
 			rasterizer->add_light(light->light_info->instance);
 			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));
 	};
 
-	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));
-	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));
 	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));

+ 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; }
 	};
 
+	struct BakedLight {
+
+		Rasterizer::BakedLightData data;
+		AABB octree_aabb;
+		Size2i octree_tex_size;
+
+	};
+
 
 	struct Camera  {
  
@@ -149,6 +157,7 @@ class VisualServerRaster : public VisualServer {
 		float draw_range_begin;
 		float draw_range_end;
 		float extra_margin;
+		int lightmap_texture_index;
 
 
 		Rasterizer::InstanceData data;
@@ -158,6 +167,8 @@ class VisualServerRaster : public VisualServer {
 		Set<Instance*> valid_auto_rooms;
 		Instance *room;
 		List<Instance*>::Element *RE;
+		Instance *baked_light;
+		List<Instance*>::Element *BLE;
 		bool exterior;
 
 		uint64_t last_render_pass;
@@ -205,6 +216,7 @@ class VisualServerRaster : public VisualServer {
 			uint64_t last_add_pass;
 			List<RID>::Element *D; // directional light in scenario
 			InstanceSet affected;
+			bool enabled;
 			float dtc; //distance to camera, used for sorting
 
 			
@@ -213,8 +225,16 @@ class VisualServerRaster : public VisualServer {
 				D=NULL;	
 				light_set_index=-1;
 				last_add_pass=0;
+				enabled=true;
 			}
 		};
+
+		struct BakedLightInfo {
+
+			BakedLight *baked_light;
+			Transform affine_inverse;
+			List<Instance*> owned_instances;
+		};
 		
 		struct ParticlesInfo {
 			
@@ -226,6 +246,7 @@ class VisualServerRaster : public VisualServer {
 		LightInfo *light_info;
 		ParticlesInfo *particles_info;
 		PortalInfo * portal_info;
+		BakedLightInfo * baked_light_info;
 
 
 		Instance() { 
@@ -244,6 +265,8 @@ class VisualServerRaster : public VisualServer {
 			data.depth_scale=false;
 			data.billboard=false;
 			data.billboard_y=false;
+			data.baked_light=NULL;
+			data.baked_light_octree_xform=NULL;
 			version=1;
 			room_info=NULL;
 			room=NULL;
@@ -255,6 +278,10 @@ class VisualServerRaster : public VisualServer {
 			draw_range_end=0;
 			extra_margin=0;
 			visible_in_all_rooms=false;
+			lightmap_texture_index=-1;
+			baked_light=NULL;
+			baked_light_info=NULL;
+			BLE=NULL;
 
 			light_cache_dirty=true;
 
@@ -270,6 +297,8 @@ class VisualServerRaster : public VisualServer {
 				memdelete(room_info);
 			if (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 shadows_enabled;
 	int black_margin[4];
+	RID black_image[4];
 
 	Vector<Vector3> 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<Portal> portal_owner;
-	
+
+	mutable RID_Owner<BakedLight> baked_light_owner;
+
 	mutable RID_Owner<Camera> camera_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 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 */
 	
 	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_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) */
 	
 	virtual RID canvas_create();
@@ -1093,6 +1145,7 @@ public:
 	/* 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_images(RID p_left, RID p_top, RID p_right, RID p_bottom);
 
 	/* FREE */
 	

+ 20 - 0
servers/visual/visual_server_wrap_mt.h

@@ -879,6 +879,17 @@ public:
 	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 */
 
@@ -1014,6 +1025,14 @@ public:
 	FUNC1RC(float,instance_geometry_get_draw_range_max,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) */
 
@@ -1076,6 +1095,7 @@ public:
 	/* BLACK BARS */
 
 	FUNC4(black_bars_set_margins,int , int , int , int );
+	FUNC4(black_bars_set_images,RID , RID , RID , RID );
 
 	/* 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( 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++;\
 
 	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("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("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;
 
 
+	/* 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 */
 	
@@ -792,6 +809,7 @@ public:
 		INSTANCE_LIGHT,
 		INSTANCE_ROOM,
 		INSTANCE_PORTAL,
+		INSTANCE_BAKED_LIGHT,
 		
 		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_DEPH_SCALE,
 		INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,
-		INSTANCE_FLAG_USE_BAKED_LIGHT_VOLUME,
+		INSTANCE_FLAG_USE_BAKED_LIGHT,
 		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_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) */
 
@@ -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_images(RID p_left, RID p_top, RID p_right, RID p_bottom)=0;
 
 
 	/* FREE */

+ 60 - 3
tools/editor/editor_import_export.cpp

@@ -704,11 +704,11 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
 
 			int flags=0;
 
-			if (Globals::get_singleton()->get("texture_import/filter"))
+			if (Globals::get_singleton()->get("image_loader/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;
-			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_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);
 	}
 
+	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");
 
 }
 
+
+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() {
 
 	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_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("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() {
@@ -1659,6 +1713,9 @@ EditorImportExport::EditorImportExport() {
 	image_action_compress_quality=0.7;
 	image_formats.insert("png");
 	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,
 	};
 
+	enum ScriptAction {
+		SCRIPT_ACTION_NONE,
+		SCRIPT_ACTION_COMPILE,
+		SCRIPT_ACTION_ENCRYPT
+	};
 
 protected:
 
@@ -254,6 +259,9 @@ protected:
 	Map<StringName,StringName> image_group_files;
 	Vector<String> diff_packs;
 
+	ScriptAction script_action;
+	String script_key;
+
 	static EditorImportExport* singleton;
 
 	static void _bind_methods();
@@ -316,6 +324,11 @@ public:
 
 	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 save_config();
@@ -324,5 +337,6 @@ public:
 };
 
 VARIANT_ENUM_CAST(EditorImportExport::ImageAction);
+VARIANT_ENUM_CAST(EditorImportExport::ScriptAction);
 
 #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 {
 				//mesh since nothing else
 				node = memnew( MeshInstance );
+				node->cast_to<MeshInstance>()->set_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT,true);
 			}
 		} break;
 		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))
 		tex_flags|=Texture::FLAG_MIPMAPS;
 
+	print_line("path: "+p_path+" flags: "+itos(tex_flags));
 	int shrink=1;
 	if (from->has_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;
 
-			if (Globals::get_singleton()->get("texture_import/filter"))
+			if (Globals::get_singleton()->get("image_loader/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;
-			if (!Globals::get_singleton()->get("texture_import/repeat"))
+			if (!Globals::get_singleton()->get("image_loader/repeat"))
 				flags|=IMAGE_FLAG_REPEAT;
 
 			flags|=IMAGE_FLAG_FIX_BORDER_ALPHA;
@@ -1102,11 +1103,11 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
 
 			int flags=0;
 
-			if (Globals::get_singleton()->get("texture_import/filter"))
+			if (Globals::get_singleton()->get("image_loader/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;
-			if (!Globals::get_singleton()->get("texture_import/repeat"))
+			if (!Globals::get_singleton()->get("image_loader/repeat"))
 				flags|=IMAGE_FLAG_REPEAT;
 
 			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);
 	MD5Final(&ctx);
 
+
+
 	uint64_t sd=0;
 	String smd5;
 
 	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/");
 

+ 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

File diff suppressed because it is too large
+ 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_node.h"
-#include "scene/3d/baked_light.h"
+#include "tools/editor/plugins/baked_light_baker.h"
 #include "scene/gui/spin_box.h"
 
+
+
 /**
 	@author Juan Linietsky <[email protected]>
 */
 
 
-class BakedLightBaker;
+
 class MeshInstance;
 
 class BakedLightEditor : public Control {
@@ -20,20 +22,18 @@ class BakedLightEditor : public Control {
 
 
 	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;
 	AcceptDialog *err_dialog;
 
-	MenuButton * options;
-	BakedLight *node;
+	HBoxContainer *bake_hbox;
+	Button *button_bake;
+	Button *button_reset;
+	Label *bake_info;
+
+
+	BakedLightInstance *node;
 
 	enum Menu {
 
@@ -41,7 +41,9 @@ class BakedLightEditor : public Control {
 		MENU_OPTION_CLEAR
 	};
 
-	static void _bake_thread_func(void *arg);
+	void _bake_pressed();
+	void _clear_pressed();
+
 	void _end_baking();
 	void _menu_option(int);
 
@@ -52,7 +54,7 @@ protected:
 	void _notification(int p_what);
 public:
 
-	void edit(BakedLight *p_baked_light);
+	void edit(BakedLightInstance *p_baked_light);
 	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) {
 
 	switch(p_what) {
@@ -277,10 +297,16 @@ void ProjectExportDialog::_notification(int p_what) {
 			image_action->select(EditorImportExport::get_singleton()->get_export_image_action());
 			image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality());
 			image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_shrink());
+			_update_script();
+
+
 			image_quality->connect("value_changed",this,"_quality_edited");
 			image_shrink->connect("value_changed",this,"_shrink_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++) {
 				if (EditorImportExport::get_singleton()->get_image_formats().has(formats[i]->get_text(0)))
 					formats[i]->set_checked(0,true);
@@ -651,10 +677,15 @@ bool ProjectExportDialog::_update_group_treef(TreeItem *p_parent,EditorFileSyste
 }
 void ProjectExportDialog::_update_group_tree() {
 
+	if (updating)
+		return;
+
 	group_images->clear();
 
 	if (_get_selected_group()=="")
 		return;
+
+	updating=true;
 	print_line("****UGT");
 	List<String> img_extensions;
 	ImageLoader::get_recognized_extensions(&img_extensions);
@@ -677,7 +708,7 @@ void ProjectExportDialog::_update_group_tree() {
 		groupenum+=","+String(E->get());
 	}
 
-
+	updating=false;
 
 
 	_update_group_treef(NULL,EditorFileSystem::get_singleton()->get_filesystem(),extensions,groupenum,group_index);
@@ -690,7 +721,7 @@ void ProjectExportDialog::_group_changed(Variant v) {
 		return;
 	if (_get_selected_group()=="")
 		return;
-
+	updating=true;
 	StringName name = _get_selected_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());
@@ -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_undo_method(this,"_save_export_cfg");
 	EditorNode::get_undo_redo()->commit_action();
+	updating=false;
 }
 
 void ProjectExportDialog::_group_item_edited() {
@@ -926,11 +958,11 @@ void ProjectExportDialog::_group_atlas_preview() {
 
 	int flags=0;
 
-	if (Globals::get_singleton()->get("texture_import/filter"))
+	if (Globals::get_singleton()->get("image_loader/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;
-	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_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) {
 
 	_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_select_all"),&ProjectExportDialog::_group_select_all);
 	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);
@@ -1171,7 +1216,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	group_lossy_quality->set_step(0.1);
 	group_lossy_quality->set_val(0.7);
 	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->set_pressed("Generate Atlas");
@@ -1261,6 +1306,18 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	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;
 
@@ -1302,6 +1359,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
 	add_child(pck_export);
 
 	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;
 
 
+	VBoxContainer *script_vbox;
+	OptionButton *script_mode;
+	LineEdit *script_key;
+
+
+
 	void _export_mode_changed(int p_idx);
 	void _prop_edited(String what);
 
@@ -166,6 +172,9 @@ private:
 	void _group_select_none();
 	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_pck(const String& p_file);
 	void ok_pressed();

Some files were not shown because too many files changed in this diff