Преглед изворни кода

work in progress global illumination

Juan Linietsky пре 8 година
родитељ
комит
075fde7f26

+ 11 - 11
core/image.cpp

@@ -390,16 +390,16 @@ void Image::convert( Format p_new_format ){
 		case FORMAT_R8|(FORMAT_RG8<<8): _convert<1,false,2,false,false,false>( width, height,rptr, wptr ); break;
 		case FORMAT_R8|(FORMAT_RGB8<<8): _convert<1,false,3,false,false,false>( width, height,rptr, wptr ); break;
 		case FORMAT_R8|(FORMAT_RGBA8<<8): _convert<1,false,3,true,false,false>( width, height,rptr, wptr ); break;
-		case FORMAT_RG8|(FORMAT_L8<<8): _convert<1,false,1,false,false,true>( width, height,rptr, wptr ); break;
-		case FORMAT_RG8|(FORMAT_LA8<<8): _convert<1,false,1,true,false,true>( width, height,rptr, wptr ); break;
-		case FORMAT_RG8|(FORMAT_R8<<8): _convert<1,false,1,false,false,false>( width, height,rptr, wptr ); break;
-		case FORMAT_RG8|(FORMAT_RGB8<<8): _convert<1,false,3,false,false,false>( width, height,rptr, wptr ); break;
-		case FORMAT_RG8|(FORMAT_RGBA8<<8): _convert<1,false,3,true,false,false>( width, height,rptr, wptr ); break;
-		case FORMAT_RGB8|(FORMAT_L8<<8): _convert<2,false,1,false,false,true>( width, height,rptr, wptr ); break;
-		case FORMAT_RGB8|(FORMAT_LA8<<8): _convert<2,false,1,true,false,true>( width, height,rptr, wptr ); break;
-		case FORMAT_RGB8|(FORMAT_R8<<8): _convert<2,false,1,false,false,false>( width, height,rptr, wptr ); break;
-		case FORMAT_RGB8|(FORMAT_RG8<<8): _convert<2,false,2,false,false,false>( width, height,rptr, wptr ); break;
-		case FORMAT_RGB8|(FORMAT_RGBA8<<8): _convert<2,false,3,true,false,false>( width, height,rptr, wptr ); break;
+		case FORMAT_RG8|(FORMAT_L8<<8): _convert<2,false,1,false,false,true>( width, height,rptr, wptr ); break;
+		case FORMAT_RG8|(FORMAT_LA8<<8): _convert<2,false,1,true,false,true>( width, height,rptr, wptr ); break;
+		case FORMAT_RG8|(FORMAT_R8<<8): _convert<2,false,1,false,false,false>( width, height,rptr, wptr ); break;
+		case FORMAT_RG8|(FORMAT_RGB8<<8): _convert<2,false,3,false,false,false>( width, height,rptr, wptr ); break;
+		case FORMAT_RG8|(FORMAT_RGBA8<<8): _convert<2,false,3,true,false,false>( width, height,rptr, wptr ); break;
+		case FORMAT_RGB8|(FORMAT_L8<<8): _convert<3,false,1,false,false,true>( width, height,rptr, wptr ); break;
+		case FORMAT_RGB8|(FORMAT_LA8<<8): _convert<3,false,1,true,false,true>( width, height,rptr, wptr ); break;
+		case FORMAT_RGB8|(FORMAT_R8<<8): _convert<3,false,1,false,false,false>( width, height,rptr, wptr ); break;
+		case FORMAT_RGB8|(FORMAT_RG8<<8): _convert<3,false,2,false,false,false>( width, height,rptr, wptr ); break;
+		case FORMAT_RGB8|(FORMAT_RGBA8<<8): _convert<3,false,3,true,false,false>( width, height,rptr, wptr ); break;
 		case FORMAT_RGBA8|(FORMAT_L8<<8): _convert<3,true,1,false,false,true>( width, height,rptr, wptr ); break;
 		case FORMAT_RGBA8|(FORMAT_LA8<<8): _convert<3,true,1,true,false,true>( width, height,rptr, wptr ); break;
 		case FORMAT_RGBA8|(FORMAT_R8<<8): _convert<3,true,1,false,false,false>( width, height,rptr, wptr ); break;
@@ -414,7 +414,7 @@ void Image::convert( Format p_new_format ){
 
 	bool gen_mipmaps=mipmaps;
 
-	mipmaps=false;
+//	mipmaps=false;
 
 	*this=new_img;
 

+ 83 - 2
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -1010,6 +1010,48 @@ void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
 	light_instance->last_scene_pass=scene_pass;
 }
 
+
+//////////////////////
+
+RID RasterizerSceneGLES3::gi_probe_instance_create() {
+
+	GIProbeInstance *gipi = memnew(GIProbeInstance);
+
+	return gi_probe_instance_owner.make_rid(gipi);
+}
+
+void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe,RID p_data) {
+
+	GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gipi);
+	gipi->data=p_data;
+	if (p_data.is_valid()) {
+		RasterizerStorageGLES3::GIProbeData *gipd = storage->gi_probe_data_owner.getornull(p_data);
+		ERR_FAIL_COND(!gipd);
+		if (gipd) {
+			gipi->tex_cache=gipd->tex_id;
+			gipi->cell_size_cache.x=1.0/gipd->width;
+			gipi->cell_size_cache.y=1.0/gipd->height;
+			gipi->cell_size_cache.z=1.0/gipd->depth;
+		}
+	}
+}
+void RasterizerSceneGLES3::gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform) {
+
+	GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gipi);
+	gipi->transform_to_data=p_xform;
+
+}
+
+void RasterizerSceneGLES3::gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds) {
+
+	GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gipi);
+	gipi->bounds=p_bounds;
+
+}
+
 ////////////////////////////
 ////////////////////////////
 ////////////////////////////
@@ -1438,7 +1480,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
 
 }
 
-void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) {
+void RasterizerSceneGLES3::_setup_light(RenderList::Element *e,const Transform& p_view_transform) {
 
 	int omni_indices[16];
 	int omni_count=0;
@@ -1509,7 +1551,33 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) {
 		glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::REFLECTION_INDICES),reflection_count,reflection_indices);
 	}
 
+	int gi_probe_count = e->instance->gi_probe_instances.size();
+	if (gi_probe_count) {
+		const RID * ridp = e->instance->gi_probe_instances.ptr();
 
+		GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[0]);
+
+		glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-6);
+		glBindTexture(GL_TEXTURE_3D,gipi->tex_cache);
+		state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform);
+		state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds);
+		state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE1, gipi->cell_size_cache);
+		if (gi_probe_count>1) {
+
+			GIProbeInstance *gipi2 = gi_probe_instance_owner.getptr(ridp[1]);
+
+			glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-7);
+			glBindTexture(GL_TEXTURE_3D,gipi2->tex_cache);
+			state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform);
+			state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds);
+			state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE2, gipi2->cell_size_cache);
+
+			state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, true );
+		} else {
+
+			state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false );
+		}
+	}
 }
 
 
@@ -1672,11 +1740,15 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
 					state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false);
 					state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false);
 					state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false);
+					state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,false);
 
 
 
 					//state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true);
 				} else {
+
+					state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,e->instance->gi_probe_instances.size()>0);
+
 					state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
 					state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,!p_directional_add);
 					state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false);
@@ -1711,9 +1783,12 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
 
 				}
 
+
+
 				rebind=true;
 			}
 
+
 			if (p_alpha_pass || p_directional_add) {
 				int desired_blend_mode;
 				if (p_directional_add) {
@@ -1794,7 +1869,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
 		}
 
 		if (!(e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) {
-			_setup_light(e);
+			_setup_light(e,p_view_transform);
+
 		}
 
 
@@ -1837,6 +1913,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
 	state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
 	state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false);
 	state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false);
+	state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,false);
 
 }
 
@@ -1950,6 +2027,10 @@ void RasterizerSceneGLES3::_add_geometry(  RasterizerStorageGLES3::Geometry* p_g
 
 			copymem(oe,e,sizeof(RenderList::Element));
 		}
+
+		if (e->instance->gi_probe_instances.size()) {
+			e->sort_key|=RenderList::SORT_KEY_GI_PROBES_FLAG;
+		}
 	}
 
 	//if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE)

+ 23 - 3
drivers/gles3/rasterizer_scene_gles3.h

@@ -526,6 +526,25 @@ public:
 	virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass);
 	virtual void light_instance_mark_visible(RID p_light_instance);
 
+	/* REFLECTION INSTANCE */
+
+	struct GIProbeInstance : public RID_Data {
+		RID data;
+		GLuint tex_cache;
+		Vector3 cell_size_cache;
+		Vector3 bounds;
+		Transform transform_to_data;
+	};
+
+
+
+	mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+
+	virtual RID gi_probe_instance_create();
+	virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data);
+	virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform);
+	virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds);
+
 	/* RENDER LIST */
 
 	struct RenderList {
@@ -541,8 +560,9 @@ public:
 			SORT_KEY_DEPTH_LAYER_SHIFT=60,
 			SORT_KEY_UNSHADED_FLAG=uint64_t(1)<<59,
 			SORT_KEY_NO_DIRECTIONAL_FLAG=uint64_t(1)<<58,
-			SORT_KEY_SHADING_SHIFT=58,
-			SORT_KEY_SHADING_MASK=3,
+			SORT_KEY_GI_PROBES_FLAG=uint64_t(1)<<57,
+			SORT_KEY_SHADING_SHIFT=57,
+			SORT_KEY_SHADING_MASK=7,
 			SORT_KEY_MATERIAL_INDEX_SHIFT=40,
 			SORT_KEY_GEOMETRY_INDEX_SHIFT=20,
 			SORT_KEY_GEOMETRY_TYPE_SHIFT=15,
@@ -669,7 +689,7 @@ public:
 	_FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection);
 	_FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
 	_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
-	_FORCE_INLINE_ void _setup_light(RenderList::Element *e);
+	_FORCE_INLINE_ void _setup_light(RenderList::Element *e,const Transform& p_view_transform);
 
 	void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows);
 

+ 309 - 8
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -1514,6 +1514,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
 	p_shader->valid=true;
 	p_shader->version++;
 
+
 }
 
 void RasterizerStorageGLES3::update_dirty_shaders() {
@@ -3600,16 +3601,15 @@ void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_
 	ERR_FAIL_COND(multimesh->color_format==VS::MULTIMESH_COLOR_NONE);
 
 	int stride = multimesh->color_floats+multimesh->xform_floats;
-	float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats];
+	float *dataptr=&multimesh->data[stride*p_index+multimesh->xform_floats];
 
 	if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
-		union {
-			uint32_t colu;
-			float colf;
-		} cu;
 
-		cu.colu=p_color.to_32();
-		dataptr[ 0]=cu.colf;
+		uint8_t *data8=(uint8_t*)dataptr;
+		data8[0]=CLAMP(p_color.r*255.0,0,255);
+		data8[1]=CLAMP(p_color.g*255.0,0,255);
+		data8[2]=CLAMP(p_color.b*255.0,0,255);
+		data8[3]=CLAMP(p_color.a*255.0,0,255);
 
 	} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
 		dataptr[ 0]=p_color.r;
@@ -3701,7 +3701,7 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p
 			float colf;
 		} cu;
 
-		return Color::hex(cu.colu);
+		return Color::hex(BSWAP32(cu.colu));
 
 	} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
 		Color c;
@@ -4385,6 +4385,15 @@ float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param
 	return light->param[p_param];
 }
 
+Color RasterizerStorageGLES3::light_get_color(RID p_light) {
+
+	const Light * light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light,Color());
+
+	return light->color;
+
+}
+
 bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const {
 
 	const Light * light = light_owner.getornull(p_light);
@@ -4668,6 +4677,261 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color
 
 }
 
+RID RasterizerStorageGLES3::gi_probe_create() {
+
+	GIProbe *gip = memnew( GIProbe );
+
+	gip->data_width=0;
+	gip->data_height=0;
+	gip->data_depth=0;
+	gip->bounds=AABB(Vector3(),Vector3(1,1,1));
+	gip->dynamic_range=1.0;
+	gip->version=1;
+	gip->cell_size=1.0;
+
+	return gi_probe_owner.make_rid(gip);
+}
+
+void RasterizerStorageGLES3::gi_probe_set_bounds(RID p_probe,const AABB& p_bounds){
+
+	GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gip);
+
+	gip->bounds=p_bounds;
+	gip->version++;
+	gip->instance_change_notify();
+}
+AABB RasterizerStorageGLES3::gi_probe_get_bounds(RID p_probe) const{
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,AABB());
+
+	return gip->bounds;
+}
+
+void RasterizerStorageGLES3::gi_probe_set_cell_size(RID p_probe,float p_size) {
+
+	GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gip);
+
+	gip->cell_size=p_size;
+	gip->version++;
+	gip->instance_change_notify();
+}
+
+float RasterizerStorageGLES3::gi_probe_get_cell_size(RID p_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,0);
+
+	return gip->cell_size;
+
+}
+
+void RasterizerStorageGLES3::gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform) {
+
+	GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gip);
+
+	gip->to_cell=p_xform;
+}
+
+Transform RasterizerStorageGLES3::gi_probe_get_to_cell_xform(RID p_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,Transform());
+
+	return gip->to_cell;
+
+}
+
+
+
+void RasterizerStorageGLES3::gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data){
+	GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gip);
+
+	gip->dynamic_data=p_data;
+	gip->version++;
+	gip->instance_change_notify();
+
+}
+DVector<int> RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) const{
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,DVector<int>());
+
+	return gip->dynamic_data;
+}
+
+void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe,float p_range){
+
+	GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND(!gip);
+
+	gip->dynamic_range=p_range;
+
+}
+float RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const{
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,0);
+
+	return gip->dynamic_range;
+}
+
+
+void RasterizerStorageGLES3::gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth) {
+
+	GIProbe *gip = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND(!gip);
+
+	if (gip->data.is_valid()) {
+		free(gip->data);
+	}
+
+	gip->data=RID();
+	//this is platform dependent
+
+	gip->version++;
+	gip->instance_change_notify();
+
+}
+DVector<uint8_t> RasterizerStorageGLES3::gi_probe_get_static_data(RID p_gi_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gip,DVector<uint8_t>());
+
+	//platform dependent
+	return DVector<uint8_t>();
+}
+VS::GIProbeDataFormat RasterizerStorageGLES3::gi_probe_get_static_data_format(RID p_gi_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe);
+	ERR_FAIL_COND_V(!gip,VS::GI_PROBE_DATA_RGBA8);
+
+	return gip->data_format;
+}
+int RasterizerStorageGLES3::gi_probe_get_static_data_width(RID p_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,0);
+
+	return gip->data_width;
+}
+int RasterizerStorageGLES3::gi_probe_get_static_data_height(RID p_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,0);
+	return gip->data_height;
+}
+int RasterizerStorageGLES3::gi_probe_get_static_data_depth(RID p_probe) const {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,0);
+	return gip->data_depth;
+}
+
+RID RasterizerStorageGLES3::gi_probe_get_data(RID p_probe) {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,RID());
+
+	return gip->data;
+}
+
+uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) {
+
+	const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+	ERR_FAIL_COND_V(!gip,0);
+
+	return gip->version;
+}
+
+RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth) {
+
+	GIProbeData *gipd = memnew( GIProbeData );
+
+	gipd->width=p_width;
+	gipd->height=p_height;
+	gipd->depth=p_depth;
+
+	glActiveTexture(GL_TEXTURE0);
+	glGenTextures(1,&gipd->tex_id);
+	glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
+
+	int level=0;
+
+	print_line("dyndata create");
+	while(true) {
+
+		Vector<uint8_t> data;
+		data.resize(p_width*p_height*p_depth*4);
+
+
+		for(int i=0;i<data.size();i+=4) {
+
+			data[i+0]=0xFF;
+			data[i+1]=0x00;
+			data[i+2]=0xFF;
+			data[i+3]=0xFF;
+		}
+
+		glTexImage3D(GL_TEXTURE_3D,level,GL_RGBA8,p_width,p_height,p_depth,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
+		if (p_width<=1 || p_height<=1 || p_depth<=1)
+			break;
+		p_width>>=1;
+		p_height>>=1;
+		p_depth>>=1;
+		level++;
+	}
+
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
+	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, level);
+
+	gipd->levels=level+1;
+
+	return gi_probe_data_owner.make_rid(gipd);
+}
+
+void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {
+
+	GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data);
+	ERR_FAIL_COND(!gipd);
+/*
+	Vector<uint8_t> data;
+	data.resize((gipd->width>>p_mipmap)*(gipd->height>>p_mipmap)*(gipd->depth>>p_mipmap)*4);
+
+	for(int i=0;i<(gipd->width>>p_mipmap);i++) {
+		for(int j=0;j<(gipd->height>>p_mipmap);j++) {
+			for(int k=0;k<(gipd->depth>>p_mipmap);k++) {
+
+				int ofs = (k*(gipd->height>>p_mipmap)*(gipd->width>>p_mipmap)) + j *(gipd->width>>p_mipmap) + i;
+				ofs*=4;
+				data[ofs+0]=i*0xFF/(gipd->width>>p_mipmap);
+				data[ofs+1]=j*0xFF/(gipd->height>>p_mipmap);
+				data[ofs+2]=k*0xFF/(gipd->depth>>p_mipmap);
+				data[ofs+3]=0xFF;
+			}
+		}
+	}
+*/
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
+	glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
+	//glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
+	//glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
+	print_line("update rgba8 "+itos(p_mipmap));
+}
+
+
+
+
 void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) {
 
 	Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
@@ -4709,6 +4973,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene:
 			inst = light_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
 		} break;
+		case VS::INSTANCE_GI_PROBE: {
+			inst = gi_probe_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
 		default: {
 			if (!inst) {
 				ERR_FAIL();
@@ -4744,6 +5012,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce
 			inst = light_owner.getornull(p_base);
 			ERR_FAIL_COND(!inst);
 		} break;
+		case VS::INSTANCE_GI_PROBE: {
+			inst = gi_probe_owner.getornull(p_base);
+			ERR_FAIL_COND(!inst);
+		} break;
 		default: {
 
 			if (!inst) {
@@ -5395,19 +5667,27 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
 	if (mesh_owner.owns(p_rid)) {
 		return VS::INSTANCE_MESH;
 	}
+
 	if (multimesh_owner.owns(p_rid)) {
 		return VS::INSTANCE_MULTIMESH;
 	}
+
 	if (immediate_owner.owns(p_rid)) {
 		return VS::INSTANCE_IMMEDIATE;
 	}
+
 	if (light_owner.owns(p_rid)) {
 		return VS::INSTANCE_LIGHT;
 	}
+
 	if (reflection_probe_owner.owns(p_rid)) {
 		return VS::INSTANCE_REFLECTION_PROBE;
 	}
 
+	if (gi_probe_owner.owns(p_rid)) {
+		return VS::INSTANCE_GI_PROBE;
+	}
+
 	return VS::INSTANCE_NONE;
 }
 
@@ -5561,6 +5841,27 @@ bool RasterizerStorageGLES3::free(RID p_rid){
 		reflection_probe_owner.free(p_rid);
 		memdelete(reflection_probe);
 
+	} else if (gi_probe_owner.owns(p_rid)) {
+
+		// delete the texture
+		GIProbe *gi_probe = gi_probe_owner.get(p_rid);
+
+		if (gi_probe->data.is_valid()) {
+			free(gi_probe->data);
+		}
+
+		gi_probe_owner.free(p_rid);
+		memdelete(gi_probe);
+	} else if (gi_probe_data_owner.owns(p_rid)) {
+
+		// delete the texture
+		GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid);
+
+		print_line("dyndata delete");
+		glDeleteTextures(1,&gi_probe_data->tex_id);
+		gi_probe_owner.free(p_rid);
+		memdelete(gi_probe_data);
+
 	} else if (canvas_occluder_owner.owns(p_rid)) {
 
 

+ 79 - 0
drivers/gles3/rasterizer_storage_gles3.h

@@ -799,6 +799,7 @@ public:
 
 	virtual VS::LightType light_get_type(RID p_light) const;
 	virtual float light_get_param(RID p_light,VS::LightParam p_param);
+	virtual Color light_get_color(RID p_light);
 
 	virtual AABB light_get_aabb(RID p_light) const;
 	virtual uint64_t light_get_version(RID p_light) const;
@@ -868,6 +869,84 @@ public:
 	virtual void portal_set_disable_distance(RID p_portal, float p_distance);
 	virtual void portal_set_disabled_color(RID p_portal, const Color& p_color);
 
+
+
+
+
+
+
+	/* GI PROBE API */
+
+	struct GIProbe : public Instantiable {
+
+
+		AABB bounds;
+		Transform to_cell;
+		float cell_size;
+
+		float dynamic_range;
+
+		uint32_t version;
+
+		DVector<int> dynamic_data;
+
+		RID data;
+		int data_width;
+		int data_height;
+		int data_depth;
+		VS::GIProbeDataFormat data_format;
+
+
+	};
+
+	mutable RID_Owner<GIProbe> gi_probe_owner;
+
+	virtual RID gi_probe_create();
+
+	virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds);
+	virtual AABB gi_probe_get_bounds(RID p_probe) const;
+
+	virtual void gi_probe_set_cell_size(RID p_probe, float p_size);
+	virtual float gi_probe_get_cell_size(RID p_probe) const;
+
+	virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform);
+	virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const;
+
+	virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data);
+	virtual DVector<int> gi_probe_get_dynamic_data(RID p_probe) const;
+
+	virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range);
+	virtual float gi_probe_get_dynamic_range(RID p_probe) const;
+
+
+	virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth);
+	virtual DVector<uint8_t> gi_probe_get_static_data(RID p_gi_probe) const;
+	virtual  VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const;
+	virtual int gi_probe_get_static_data_width(RID p_probe) const;
+	virtual int gi_probe_get_static_data_height(RID p_probe) const;
+	virtual int gi_probe_get_static_data_depth(RID p_probe) const;
+
+	virtual RID gi_probe_get_data(RID p_probe); //get data in case this is static
+	virtual uint32_t gi_probe_get_version(RID p_probe);
+
+	struct GIProbeData : public RID_Data {
+
+		int width;
+		int height;
+		int depth;
+		int levels;
+		GLuint tex_id;
+
+		GIProbeData() {
+		}
+	};
+
+	mutable RID_Owner<GIProbeData> gi_probe_data_owner;
+
+	virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth);
+	virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data);
+
+
 	virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
 	virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
 

+ 133 - 2
drivers/gles3/shaders/scene.glsl

@@ -838,6 +838,131 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta
 	}
 }
 
+#ifdef USE_GI_PROBES
+
+uniform mediump sampler3D gi_probe1; //texunit:-6
+uniform highp mat4 gi_probe_xform1;
+uniform highp vec3 gi_probe_bounds1;
+uniform highp vec3 gi_probe_cell_size1;
+
+uniform mediump sampler3D gi_probe2; //texunit:-7
+uniform highp mat4 gi_probe_xform2;
+uniform highp vec3 gi_probe_bounds2;
+uniform highp vec3 gi_probe_cell_size2;
+uniform bool gi_probe2_enabled;
+
+vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance) {
+
+
+	float dist = dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0;
+	float alpha=0.0;
+	vec4 color = vec4(0.0);
+
+	while(dist < max_distance && alpha < 0.95) {
+		float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+		vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
+		float a = (1.0 - alpha);
+		color.rgb += a * scolor.rgb;
+		alpha += a * scolor.a;
+		dist += diameter * 0.5;
+	}
+
+	return color.rgb;
+}
+
+void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) {
+
+
+
+	vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz;
+	vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz;
+
+	ref_vec = normalize(ref_pos - probe_pos);
+
+/*	out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0);
+	out_diff.a = 1.0;
+	return;*/
+	//out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0);
+	//return;
+
+	if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds)))))
+		return;
+
+	vec3 blendv = probe_pos/bounds * 2.0 - 1.0;
+	float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z));
+	blend=1.0;
+
+	//radiance
+
+#define MAX_CONE_DIRS 6
+	vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
+		vec3(0, 0, 1),
+		vec3(0.866025, 0, 0.5),
+		vec3(0.267617, 0.823639, 0.5),
+		vec3(-0.700629, 0.509037, 0.5),
+		vec3(-0.700629, -0.509037, 0.5),
+		vec3(0.267617, -0.823639, 0.5)
+	);
+
+	float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+
+	float max_distance = length(bounds);
+	vec3 light=vec3(0.0);
+	for(int i=0;i<MAX_CONE_DIRS;i++) {
+
+		vec3 dir = normalize( (probe_xform * vec4(pos + normal_mtx * cone_dirs[i],1.0)).xyz - probe_pos);
+		light+=cone_weights[i] * voxel_cone_trace(probe,cell_size,probe_pos,dir,0.577,max_distance);
+
+	}
+
+	out_diff = vec4(light*blend,blend);
+
+	//irradiance
+
+	vec3 irr_light =  voxel_cone_trace(probe,cell_size,probe_pos,ref_vec,tan(roughness * 0.5 * M_PI) ,max_distance);
+	//irr_light=vec3(0.0);
+
+	out_spec = vec4(irr_light*blend,blend);
+}
+
+
+void gi_probes_compute(vec3 pos, vec3 normal, float roughness, vec3 specular, inout vec3 out_specular, inout vec3 out_ambient) {
+
+
+	vec3 ref_vec = normalize(reflect(normalize(pos),normal));
+
+	//find arbitrary tangent and bitangent, then build a matrix
+	vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0);
+	vec3 tangent = normalize(cross(v0, normal));
+	vec3 bitangent = normalize(cross(tangent, normal));
+	mat3 normal_mat = mat3(tangent,bitangent,normal);
+
+	vec4 diff_accum = vec4(0.0);
+	vec4 spec_accum = vec4(0.0);
+
+	gi_probe_compute(gi_probe1,gi_probe_xform1,gi_probe_bounds1,gi_probe_cell_size1,pos,normal_mat,ref_vec,roughness,spec_accum,diff_accum);
+
+	if (gi_probe2_enabled) {
+
+		gi_probe_compute(gi_probe2,gi_probe_xform2,gi_probe_bounds2,gi_probe_cell_size2,pos,normal_mat,ref_vec,roughness,spec_accum,diff_accum);
+	}
+
+	if (diff_accum.a>0.0) {
+		diff_accum.rgb/=diff_accum.a;
+	}
+
+	if (spec_accum.a>0.0) {
+		spec_accum.rgb/=spec_accum.a;
+	}
+
+	out_specular+=spec_accum.rgb;
+	out_ambient+=diff_accum.rgb;
+
+}
+
+#endif
+
+
 void main() {
 
 #ifdef RENDER_SHADOW_DUAL_PARABOLOID
@@ -1161,21 +1286,27 @@ FRAGMENT_SHADER_CODE
 
 #endif //#USE_LIGHT_DIRECTIONAL
 
+#ifdef USE_GI_PROBES
+	gi_probes_compute(vertex,normal,roughness,specular,specular_light,ambient_light);
+#endif
+
 
 #ifdef USE_FORWARD_LIGHTING
 
 	highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0);
 	highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0);
 
+
+
 	for(int i=0;i<reflection_count;i++) {
 		reflection_process(reflection_indices[i],vertex,normal,binormal,tangent,roughness,anisotropy,ambient_light,specular_light,brdf,reflection_accum,ambient_accum);
 	}
 
 	if (reflection_accum.a>0.0) {
-		specular_light=reflection_accum.rgb/reflection_accum.a;
+		specular_light+=reflection_accum.rgb/reflection_accum.a;
 	}
 	if (ambient_accum.a>0.0) {
-		ambient_light=ambient_accum.rgb/ambient_accum.a;
+		ambient_light+=ambient_accum.rgb/ambient_accum.a;
 	}
 
 	for(int i=0;i<omni_light_count;i++) {

+ 1688 - 34
scene/3d/baked_light_instance.cpp

@@ -28,83 +28,1737 @@
 /*************************************************************************/
 #include "baked_light_instance.h"
 #include "scene/scene_string_names.h"
+#include "mesh_instance.h"
+#include "light.h"
+#include "math.h"
 
+#define FINDMINMAX(x0,x1,x2,min,max) \
+  min = max = x0;   \
+  if(x1<min) min=x1;\
+  if(x1>max) max=x1;\
+  if(x2<min) min=x2;\
+  if(x2>max) max=x2;
+
+static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox)
+{
+  int q;
+  Vector3 vmin,vmax;
+  for(q=0;q<=2;q++)
+  {
+    if(normal[q]>0.0f)
+    {
+      vmin[q]=-maxbox[q];
+      vmax[q]=maxbox[q];
+    }
+    else
+    {
+      vmin[q]=maxbox[q];
+      vmax[q]=-maxbox[q];
+    }
+  }
+  if(normal.dot(vmin)+d>0.0f) return false;
+  if(normal.dot(vmax)+d>=0.0f) return true;
+
+  return false;
+}
+
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb)             \
+    p0 = a*v0.y - b*v0.z;                    \
+    p2 = a*v2.y - b*v2.z;                    \
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+    rad = fa * boxhalfsize.y + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb)              \
+    p0 = a*v0.y - b*v0.z;                    \
+    p1 = a*v1.y - b*v1.z;                    \
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+    rad = fa * boxhalfsize.y + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb)             \
+    p0 = -a*v0.x + b*v0.z;                   \
+    p2 = -a*v2.x + b*v2.z;                       \
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb)              \
+    p0 = -a*v0.x + b*v0.z;                   \
+    p1 = -a*v1.x + b*v1.z;                       \
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb)             \
+    p1 = a*v1.x - b*v1.y;                    \
+    p2 = a*v2.x - b*v2.y;                    \
+	if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;   \
+    if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb)              \
+    p0 = a*v0.x - b*v0.y;                \
+    p1 = a*v1.x - b*v1.y;                    \
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;   \
+    if(min>rad || max<-rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) {
+
+  /*    use separating axis theorem to test overlap between triangle and box */
+  /*    need to test for overlap in these directions: */
+  /*    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+  /*       we do not even need to test these) */
+  /*    2) normal of the triangle */
+  /*    3) crossproduct(edge from tri, {x,y,z}-directin) */
+  /*       this gives 3x3=9 more tests */
+   Vector3 v0,v1,v2;
+   float min,max,d,p0,p1,p2,rad,fex,fey,fez;
+   Vector3 normal,e0,e1,e2;
+
+   /* This is the fastest branch on Sun */
+   /* move everything so that the boxcenter is in (0,0,0) */
+
+   v0=triverts[0]-boxcenter;
+   v1=triverts[1]-boxcenter;
+   v2=triverts[2]-boxcenter;
+
+   /* compute triangle edges */
+   e0=v1-v0;      /* tri edge 0 */
+   e1=v2-v1;      /* tri edge 1 */
+   e2=v0-v2;      /* tri edge 2 */
+
+   /* Bullet 3:  */
+   /*  test the 9 tests first (this was faster) */
+   fex = Math::abs(e0.x);
+   fey = Math::abs(e0.y);
+   fez = Math::abs(e0.z);
+   AXISTEST_X01(e0.z, e0.y, fez, fey);
+   AXISTEST_Y02(e0.z, e0.x, fez, fex);
+   AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+   fex = Math::abs(e1.x);
+   fey = Math::abs(e1.y);
+   fez = Math::abs(e1.z);
+   AXISTEST_X01(e1.z, e1.y, fez, fey);
+   AXISTEST_Y02(e1.z, e1.x, fez, fex);
+   AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+   fex = Math::abs(e2.x);
+   fey = Math::abs(e2.y);
+   fez = Math::abs(e2.z);
+   AXISTEST_X2(e2.z, e2.y, fez, fey);
+   AXISTEST_Y1(e2.z, e2.x, fez, fex);
+   AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+   /* Bullet 1: */
+   /*  first test overlap in the {x,y,z}-directions */
+   /*  find min, max of the triangle each direction, and test for overlap in */
+   /*  that direction -- this is equivalent to testing a minimal AABB around */
+   /*  the triangle against the AABB */
+
+   /* test in X-direction */
+   FINDMINMAX(v0.x,v1.x,v2.x,min,max);
+   if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+   /* test in Y-direction */
+   FINDMINMAX(v0.y,v1.y,v2.y,min,max);
+   if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+   /* test in Z-direction */
+   FINDMINMAX(v0.z,v1.z,v2.z,min,max);
+   if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+   /* Bullet 2: */
+   /*  test if the box intersects the plane of the triangle */
+   /*  compute plane equation of triangle: normal*x+d=0 */
+   normal=e0.cross(e1);
+   d=-normal.dot(v0);  /* plane eq: normal.x+d=0 */
+   if(!planeBoxOverlap(normal,d,boxhalfsize)) return false;
+
+   return true;   /* box and triangle overlaps */
+}
+
+
+Vector<Color> BakedLight::_get_bake_texture(Image &p_image,const Color& p_color) {
+
+	Vector<Color> ret;
+
+	if (p_image.empty()) {
+
+		ret.resize(bake_texture_size*bake_texture_size);
+		for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+			ret[i]=p_color;
+		}
+
+		return ret;
+	}
+
+	p_image.convert(Image::FORMAT_RGBA8);
+	p_image.resize(bake_texture_size,bake_texture_size,Image::INTERPOLATE_CUBIC);
+
+
+	DVector<uint8_t>::Read r = p_image.get_data().read();
+	ret.resize(bake_texture_size*bake_texture_size);
+
+	for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+		Color c;
+		c.r = r[i*4+0]/255.0;
+		c.g = r[i*4+1]/255.0;
+		c.b = r[i*4+2]/255.0;
+		c.a = r[i*4+3]/255.0;
+		ret[i]=c;
+
+	}
+
+	return ret;
+}
+
+
+BakedLight::MaterialCache BakedLight::_get_material_cache(Ref<Material> p_material) {
+
+	//this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+	Ref<FixedSpatialMaterial> mat = p_material;
+
+	Ref<Material> material = mat; //hack for now
+
+	if (material_cache.has(material)) {
+		return material_cache[material];
+	}
+
+	MaterialCache mc;
+
+	if (mat.is_valid()) {
+
+
+		Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+
+		Image img_albedo;
+		if (albedo_tex.is_valid()) {
+
+			img_albedo = albedo_tex->get_data();
+		}
+
+		mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo());
+
+		Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+
+		Color emission_col = mat->get_emission();
+		emission_col.r*=mat->get_emission_energy();
+		emission_col.g*=mat->get_emission_energy();
+		emission_col.b*=mat->get_emission_energy();
+
+		Image img_emission;
+
+		if (emission_tex.is_valid()) {
+
+			img_emission = emission_tex->get_data();
+		}
+
+		mc.emission=_get_bake_texture(img_emission,emission_col);
+
+	} else {
+		Image empty;
+
+		mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7));
+		mc.emission=_get_bake_texture(empty,Color(0,0,0));
+
+
+	}
+
+	material_cache[p_material]=mc;
+	return mc;
+
+
+}
+
+
+
+static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) {
+
+	if (p_pos.distance_squared_to(p_vtx[0])<CMP_EPSILON2)
+		return p_uv[0];
+	if (p_pos.distance_squared_to(p_vtx[1])<CMP_EPSILON2)
+		return p_uv[1];
+	if (p_pos.distance_squared_to(p_vtx[2])<CMP_EPSILON2)
+		return p_uv[2];
+
+	Vector3 v0 = p_vtx[1] - p_vtx[0];
+	Vector3 v1 = p_vtx[2] - p_vtx[0];
+	Vector3 v2 = p_pos - p_vtx[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 p_uv[0];
+	float v = (d11 * d20 - d01 * d21) / denom;
+	float w = (d00 * d21 - d01 * d20) / denom;
+	float u = 1.0f - v - w;
+
+	return p_uv[0]*u + p_uv[1]*v  + p_uv[2]*w;
+}
+
+void BakedLight::_plot_face(int p_idx, int p_level, const Vector3 *p_vtx, const Vector2* p_uv, const MaterialCache& p_material, const AABB &p_aabb) {
+
+
+
+	if (p_level==cell_subdiv-1) {
+		//plot the face by guessing it's albedo and emission value
+
+		//find best axis to map to, for scanning values
+		int closest_axis;
+		float closest_dot;
+
+		Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal;
+
+		for(int i=0;i<3;i++) {
+
+			Vector3 axis;
+			axis[i]=1.0;
+			float dot=ABS(normal.dot(axis));
+			if (i==0 || dot>closest_dot) {
+				closest_axis=i;
+				closest_dot=dot;
+			}
+		}
+
+		Vector3 axis;
+		axis[closest_axis]=1.0;
+		Vector3 t1;
+		t1[(closest_axis+1)%3]=1.0;
+		Vector3 t2;
+		t2[(closest_axis+2)%3]=1.0;
+
+		t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width);
+		t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width);
+
+		Color albedo_accum;
+		Color emission_accum;
+		float alpha=0.0;
+
+		//map to a grid average in the best axis for this face
+		for(int i=0;i<color_scan_cell_width;i++) {
+
+			Vector3 ofs_i=float(i)*t1;
+
+			for(int j=0;j<color_scan_cell_width;j++) {
+
+				Vector3 ofs_j=float(j)*t2;
+
+				Vector3 from = p_aabb.pos+ofs_i+ofs_j;
+				Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+				Vector3 half = (to-from)*0.5;
+
+				//is in this cell?
+				if (!fast_tri_box_overlap(from+half,half,p_vtx)) {
+					continue; //face does not span this cell
+				}
+
+				//go from -size to +size*2 to avoid skipping collisions
+				Vector3 ray_from = from + (t1+t2)*0.5 - axis * p_aabb.size[closest_axis];
+				Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis]*2;
+
+				Vector3 intersection;
+
+				if (!Geometry::ray_intersects_triangle(ray_from,ray_to,p_vtx[0],p_vtx[1],p_vtx[2],&intersection)) {
+					//no intersect? look in edges
+
+					float closest_dist=1e20;
+					for(int j=0;j<3;j++) {
+						Vector3 c;
+						Vector3 inters;
+						Geometry::get_closest_points_between_segments(p_vtx[j],p_vtx[(j+1)%3],ray_from,ray_to,inters,c);
+						float d=c.distance_to(intersection);
+						if (j==0 || d<closest_dist) {
+							closest_dist=d;
+							intersection=inters;
+						}
+					}
+				}
+
+				Vector2 uv = get_uv(intersection,p_vtx,p_uv);
+
+
+				int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+				int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+				int ofs = uv_y*bake_texture_size+uv_x;
+				albedo_accum.r+=p_material.albedo[ofs].r;
+				albedo_accum.g+=p_material.albedo[ofs].g;
+				albedo_accum.b+=p_material.albedo[ofs].b;
+				albedo_accum.a+=p_material.albedo[ofs].a;
+
+				emission_accum.r+=p_material.emission[ofs].r;
+				emission_accum.g+=p_material.emission[ofs].g;
+				emission_accum.b+=p_material.emission[ofs].b;
+				alpha+=1.0;
+
+			}
+		}
+
+
+		if (alpha==0) {
+			//could not in any way get texture information.. so use closest point to center
+
+			Face3 f( p_vtx[0],p_vtx[1],p_vtx[2]);
+			Vector3 inters = f.get_closest_point_to(p_aabb.pos+p_aabb.size*0.5);
+
+			Vector2 uv = get_uv(inters,p_vtx,p_uv);
+
+			int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+			int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+			int ofs = uv_y*bake_texture_size+uv_x;
+
+			alpha = 1.0/(color_scan_cell_width*color_scan_cell_width);
+
+			albedo_accum.r=p_material.albedo[ofs].r*alpha;
+			albedo_accum.g=p_material.albedo[ofs].g*alpha;
+			albedo_accum.b=p_material.albedo[ofs].b*alpha;
+			albedo_accum.a=p_material.albedo[ofs].a*alpha;
+
+			emission_accum.r=p_material.emission[ofs].r*alpha;
+			emission_accum.g=p_material.emission[ofs].g*alpha;
+			emission_accum.b=p_material.emission[ofs].b*alpha;
+
+
+			zero_alphas++;
+		} else {
+
+			float accdiv = 1.0/(color_scan_cell_width*color_scan_cell_width);
+			alpha*=accdiv;
+
+			albedo_accum.r*=accdiv;
+			albedo_accum.g*=accdiv;
+			albedo_accum.b*=accdiv;
+			albedo_accum.a*=accdiv;
+
+			emission_accum.r*=accdiv;
+			emission_accum.g*=accdiv;
+			emission_accum.b*=accdiv;
+		}
+
+		//put this temporarily here, corrected in a later step
+		bake_cells_write[p_idx].albedo[0]+=albedo_accum.r;
+		bake_cells_write[p_idx].albedo[1]+=albedo_accum.g;
+		bake_cells_write[p_idx].albedo[2]+=albedo_accum.b;
+		bake_cells_write[p_idx].light[0]+=emission_accum.r;
+		bake_cells_write[p_idx].light[1]+=emission_accum.g;
+		bake_cells_write[p_idx].light[2]+=emission_accum.b;
+		bake_cells_write[p_idx].alpha+=alpha;
+
+		static const Vector3 side_normals[6]={
+			Vector3(-1, 0, 0),
+			Vector3( 1, 0, 0),
+			Vector3( 0,-1, 0),
+			Vector3( 0, 1, 0),
+			Vector3( 0, 0,-1),
+			Vector3( 0, 0, 1),
+		};
+
+		for(int i=0;i<6;i++) {
+			if (normal.dot(side_normals[i])>CMP_EPSILON) {
+				bake_cells_write[p_idx].used_sides|=(1<<i);
+			}
+		}
+
+
+	} else {
+		//go down
+		for(int i=0;i<8;i++) {
+
+			AABB aabb=p_aabb;
+			aabb.size*=0.5;
+
+			if (i&1)
+				aabb.pos.x+=aabb.size.x;
+			if (i&2)
+				aabb.pos.y+=aabb.size.y;
+			if (i&4)
+				aabb.pos.z+=aabb.size.z;
+
+			{
+				AABB test_aabb=aabb;
+				//test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+				Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test
+
+				if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) {
+				//if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+					//does not fit in child, go on
+					continue;
+				}
+
+			}
+
+			if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY) {
+				//sub cell must be created
+
+				if (bake_cells_used==(1<<bake_cells_alloc)) {
+					//exhausted cells, creating more space
+					bake_cells_alloc++;
+					bake_cells_write=DVector<BakeCell>::Write();
+					bake_cells.resize(1<<bake_cells_alloc);
+					bake_cells_write=bake_cells.write();
+				}
+
+				bake_cells_write[p_idx].childs[i]=bake_cells_used;
+				bake_cells_level_used[p_level+1]++;
+				bake_cells_used++;
+
+
+			}
+
+
+			_plot_face(bake_cells_write[p_idx].childs[i],p_level+1,p_vtx,p_uv,p_material,aabb);
+		}
+	}
+}
+
+
+
+void BakedLight::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z) {
+
+
+
+	if (p_level==cell_subdiv-1) {
+
+
+		float alpha = bake_cells_write[p_idx].alpha;
+
+		bake_cells_write[p_idx].albedo[0]/=alpha;
+		bake_cells_write[p_idx].albedo[1]/=alpha;
+		bake_cells_write[p_idx].albedo[2]/=alpha;
+
+		//transfer emission to light
+		bake_cells_write[p_idx].light[0]/=alpha;
+		bake_cells_write[p_idx].light[1]/=alpha;
+		bake_cells_write[p_idx].light[2]/=alpha;
+
+		bake_cells_write[p_idx].alpha=1.0;
+
+		//remove neighbours from used sides
+
+		for(int n=0;n<6;n++) {
+
+			int ofs[3]={0,0,0};
+
+			ofs[n/2]=(n&1)?1:-1;
+
+			//convert to x,y,z on this level
+			int x=p_x;
+			int y=p_y;
+			int z=p_z;
+
+			x+=ofs[0];
+			y+=ofs[1];
+			z+=ofs[2];
+
+			int ofs_x=0;
+			int ofs_y=0;
+			int ofs_z=0;
+			int size = 1<<p_level;
+			int half=size/2;
+
+
+			if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) {
+				//neighbour is out, can't use it
+				bake_cells_write[p_idx].used_sides&=~(1<<uint32_t(n));
+				continue;
+			}
+
+			uint32_t neighbour=0;
+
+			for(int i=0;i<cell_subdiv-1;i++) {
+
+				BakeCell *bc = &bake_cells_write[neighbour];
+
+				int child = 0;
+				if (x >= ofs_x + half) {
+					child|=1;
+					ofs_x+=half;
+				}
+				if (y >= ofs_y + half) {
+					child|=2;
+					ofs_y+=half;
+				}
+				if (z >= ofs_z + half) {
+					child|=4;
+					ofs_z+=half;
+				}
+
+				neighbour = bc->childs[child];
+				if (neighbour==CHILD_EMPTY) {
+					break;
+				}
+
+				half>>=1;
+			}
+
+			if (neighbour!=CHILD_EMPTY) {
+				bake_cells_write[p_idx].used_sides&=~(1<<uint32_t(n));
+			}
+		}
+	} else {
+
+
+		//go down
+
+		float alpha_average=0;
+		int half = cells_per_axis >> (p_level+1);
+		for(int i=0;i<8;i++) {
+
+			uint32_t child = bake_cells_write[p_idx].childs[i];
+
+			if (child==CHILD_EMPTY)
+				continue;
+
+
+			int nx=p_x;
+			int ny=p_y;
+			int nz=p_z;
+
+			if (i&1)
+				nx+=half;
+			if (i&2)
+				ny+=half;
+			if (i&4)
+				nz+=half;
+
+			_fixup_plot(child,p_level+1,nx,ny,nz);
+			alpha_average+=bake_cells_write[child].alpha;
+		}
+
+		bake_cells_write[p_idx].alpha=alpha_average/8.0;
+		bake_cells_write[p_idx].light[0]=0;
+		bake_cells_write[p_idx].light[1]=0;
+		bake_cells_write[p_idx].light[2]=0;
+		bake_cells_write[p_idx].albedo[0]=0;
+		bake_cells_write[p_idx].albedo[1]=0;
+		bake_cells_write[p_idx].albedo[2]=0;
+
+	}
+
+	//clean up light
+	bake_cells_write[p_idx].light_pass=0;
+	//find neighbours
+
+
+
+}
+
+
+void BakedLight::_bake_add_mesh(const Transform& p_xform,Ref<Mesh>& p_mesh) {
+
+
+	for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+		if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+			continue; //only triangles
+
+		MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i));
+
+		Array a = p_mesh->surface_get_arrays(i);
+
+
+		DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+		DVector<Vector3>::Read vr=vertices.read();
+		DVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+		DVector<Vector2>::Read uvr;
+		DVector<int> index = a[Mesh::ARRAY_INDEX];
+
+		bool read_uv=false;
+
+		if (uv.size()) {
+
+			uvr=uv.read();
+			read_uv=true;
+		}
+
+		if (index.size()) {
+
+			int facecount = index.size()/3;
+			DVector<int>::Read ir=index.read();
+
+			for(int j=0;j<facecount;j++) {
+
+				Vector3 vtxs[3];
+				Vector2 uvs[3];
+
+				for(int k=0;k<3;k++) {
+					vtxs[k]=p_xform.xform(vr[ir[j*3+k]]);
+				}
+
+				if (read_uv) {
+					for(int k=0;k<3;k++) {
+						uvs[k]=uvr[ir[j*3+k]];
+					}
+				}
+
+				//plot face
+				_plot_face(0,0,vtxs,uvs,material,bounds);
+			}
+
+
+
+		} else {
+
+			int facecount = vertices.size()/3;
+
+			for(int j=0;j<facecount;j++) {
+
+				Vector3 vtxs[3];
+				Vector2 uvs[3];
+
+				for(int k=0;k<3;k++) {
+					vtxs[k]=p_xform.xform(vr[j*3+k]);
+				}
+
+				if (read_uv) {
+					for(int k=0;k<3;k++) {
+						uvs[k]=uvr[j*3+k];
+					}
+				}
+
+				//plot face
+				_plot_face(0,0,vtxs,uvs,material,bounds);
+			}
+
+		}
+	}
+}
+
+
+
+void BakedLight::_bake_add_to_aabb(const Transform& p_xform,Ref<Mesh>& p_mesh,bool &first) {
+
+	for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+		if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+			continue; //only triangles
+
+		Array a = p_mesh->surface_get_arrays(i);
+		DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+		int vc = vertices.size();
+		DVector<Vector3>::Read vr=vertices.read();
+
+		if (first) {
+			bounds.pos=p_xform.xform(vr[0]);
+			first=false;
+		}
+
+
+		for(int j=0;j<vc;j++) {
+			bounds.expand_to(p_xform.xform(vr[j]));
+		}
+	}
+}
+
+void BakedLight::bake() {
+
+
+	bake_cells_alloc=16;
+	bake_cells.resize(1<<bake_cells_alloc);
+	bake_cells_used=1;
+	cells_per_axis=(1<<(cell_subdiv-1));
+	zero_alphas=0;
+
+	bool aabb_first=true;
+	print_line("Generating AABB");
+
+	bake_cells_level_used.resize(cell_subdiv);
+	for(int i=0;i<cell_subdiv;i++) {
+		bake_cells_level_used[i]=0;
+	}
+
+	int count=0;
+	for (Set<GeometryInstance*>::Element *E=geometries.front();E;E=E->next()) {
+
+		print_line("aabb geom "+itos(count)+"/"+itos(geometries.size()));
+
+		GeometryInstance *geom = E->get();
+
+		if (geom->cast_to<MeshInstance>()) {
+
+			MeshInstance *mesh_instance = geom->cast_to<MeshInstance>();
+			Ref<Mesh> mesh = mesh_instance->get_mesh();
+			if (mesh.is_valid()) {
+
+				_bake_add_to_aabb(geom->get_relative_transform(this),mesh,aabb_first);
+			}
+		}
+		count++;
+	}
+
+	print_line("AABB: "+bounds);
+	ERR_FAIL_COND(aabb_first);
+
+	bake_cells_write = bake_cells.write();
+	count=0;
+
+	for (Set<GeometryInstance*>::Element *E=geometries.front();E;E=E->next()) {
+
+		GeometryInstance *geom = E->get();
+		print_line("plot geom "+itos(count)+"/"+itos(geometries.size()));
+
+		if (geom->cast_to<MeshInstance>()) {
+
+			MeshInstance *mesh_instance = geom->cast_to<MeshInstance>();
+			Ref<Mesh> mesh = mesh_instance->get_mesh();
+			if (mesh.is_valid()) {
+
+				_bake_add_mesh(geom->get_relative_transform(this),mesh);
+			}
+		}
+
+		count++;
+	}
+
+
+	_fixup_plot(0, 0,0,0,0);
+
+
+	bake_cells_write=DVector<BakeCell>::Write();
+
+	bake_cells.resize(bake_cells_used);
+
+
+
+	print_line("total bake cells used: "+itos(bake_cells_used));
+	for(int i=0;i<cell_subdiv;i++) {
+		print_line("level "+itos(i)+": "+itos(bake_cells_level_used[i]));
+	}
+	print_line("zero alphas: "+itos(zero_alphas));
+
+
+
+}
+
+
+
+void BakedLight::_bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign) {
+
+
+
+
+	if (p_level==cell_subdiv-1) {
+
+		Vector3 end;
+		end.x = float(p_x+0.5) / cells_per_axis;
+		end.y = float(p_y+0.5) / cells_per_axis;
+		end.z = float(p_z+0.5) / cells_per_axis;
+
+		end = bounds.pos + bounds.size*end;
+
+		float max_ray_len = (bounds.size).length()*1.2;
+
+		Vector3 begin = end + max_ray_len*-p_dir;
+
+		//clip begin
+
+		for(int i=0;i<3;i++) {
+
+			if (ABS(p_dir[i])<CMP_EPSILON) {
+				continue; // parallel to axis, don't clip
+			}
+
+			Plane p;
+			p.normal[i]=1.0;
+			p.d=bounds.pos[i];
+			if (p_dir[i]<0) {
+				p.d+=bounds.size[i];
+			}
+
+			Vector3 inters;
+			if (p.intersects_segment(end,begin,&inters)) {
+				begin=inters;
+			}
+
+		}
+
+
+		int idx = _plot_ray(begin,end);
+
+		if (idx>=0 && light_pass!=bake_cells_write[idx].light_pass) {
+			//hit something, add or remove light to it
+
+			Color albedo = Color(bake_cells_write[idx].albedo[0],bake_cells_write[idx].albedo[1],bake_cells_write[idx].albedo[2]);
+			bake_cells_write[idx].light[0]+=albedo.r*p_color.r*p_sign;
+			bake_cells_write[idx].light[1]+=albedo.g*p_color.g*p_sign;
+			bake_cells_write[idx].light[2]+=albedo.b*p_color.b*p_sign;
+			bake_cells_write[idx].light_pass=light_pass;
+
+		}
+
+
+	} else {
+
+		int half = cells_per_axis >> (p_level+1);
+
+		//go down
+		for(int i=0;i<8;i++) {
+
+			uint32_t child = bake_cells_write[p_idx].childs[i];
+
+			if (child==CHILD_EMPTY)
+				continue;
+
+			int nx=p_x;
+			int ny=p_y;
+			int nz=p_z;
+
+			if (i&1)
+				nx+=half;
+			if (i&2)
+				ny+=half;
+			if (i&4)
+				nz+=half;
+
+
+			_bake_directional(child,p_level+1,nx,ny,nz,p_dir,p_color,p_sign);
+		}
+	}
+}
+
+
+
+
+void BakedLight::_bake_light(Light* p_light) {
+
+	if (p_light->cast_to<DirectionalLight>()) {
+
+		DirectionalLight * dl = p_light->cast_to<DirectionalLight>();
+
+		Transform rel_xf = dl->get_relative_transform(this);
+
+		Vector3 light_dir = -rel_xf.basis.get_axis(2);
+
+		Color color = dl->get_color();
+		float nrg = dl->get_param(Light::PARAM_ENERGY);;
+		color.r*=nrg;
+		color.g*=nrg;
+		color.b*=nrg;
+
+		light_pass++;
+		_bake_directional(0,0,0,0,0,light_dir,color,1);
+
+	}
+}
+
+
+void BakedLight::_upscale_light(int p_idx,int p_level) {
+
+
+	//go down
+
+	float light_accum[3]={0,0,0};
+	float alpha_accum=0;
+
+	bool check_children = p_level < (cell_subdiv -2);
+
+	for(int i=0;i<8;i++) {
+
+		uint32_t child = bake_cells_write[p_idx].childs[i];
+
+		if (child==CHILD_EMPTY)
+			continue;
+
+		if (check_children) {
+			_upscale_light(child,p_level+1);
+		}
+
+		light_accum[0]+=bake_cells_write[child].light[0];
+		light_accum[1]+=bake_cells_write[child].light[1];
+		light_accum[2]+=bake_cells_write[child].light[2];
+		alpha_accum+=bake_cells_write[child].alpha;
+
+	}
+
+	bake_cells_write[p_idx].light[0]=light_accum[0]/8.0;
+	bake_cells_write[p_idx].light[1]=light_accum[1]/8.0;
+	bake_cells_write[p_idx].light[2]=light_accum[2]/8.0;
+	bake_cells_write[p_idx].alpha=alpha_accum/8.0;
+
+}
+
+
+void BakedLight::bake_lights() {
+
+	ERR_FAIL_COND(bake_cells.size()==0);
+
+	bake_cells_write = bake_cells.write();
+
+	for(Set<Light*>::Element *E=lights.front();E;E=E->next()) {
+
+		_bake_light(E->get());
+	}
+
+
+	_upscale_light(0,0);
+
+	bake_cells_write=DVector<BakeCell>::Write();
+
+}
+
+
+
+Color BakedLight::_cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle) {
+
+
+	Color color(0,0,0,0);
+	float tha = Math::tan(p_half_angle);//tan half angle
+	Vector3 from =(p_from-bounds.pos)/bounds.size; //convert to 0..1
+	from/=cells_per_axis; //convert to voxels of size 1
+	Vector3 dir = (p_dir/bounds.size).normalized();
+
+	float max_dist = Vector3(cells_per_axis,cells_per_axis,cells_per_axis).length();
+
+	float dist = 1.0;
+	// self occlusion in flat surfaces
+
+	float alpha=0;
+
+
+	while(dist < max_dist && alpha < 0.95) {
+
+#if 0
+		// smallest sample diameter possible is the voxel size
+		float diameter = MAX(1.0, 2.0 * tha * dist);
+		float lod = log2(diameter);
+
+		Vector3 sample_pos = from + dist * dir;
+
+
+		Color samples_base[2][8]={{Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)},
+		{Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)}};
+
+		float levelf = Math::fposmod(lod,1.0);
+		float fx = Math::fposmod(sample_pos.x,1.0);
+		float fy = Math::fposmod(sample_pos.y,1.0);
+		float fz = Math::fposmod(sample_pos.z,1.0);
+
+		for(int l=0;l<2;l++){
+
+			int bx = Math::floor(sample_pos.x);
+			int by = Math::floor(sample_pos.y);
+			int bz = Math::floor(sample_pos.z);
+
+			int lodn=int(Math::floor(lod))-l;
+
+			bx>>=lodn;
+			by>>=lodn;
+			bz>>=lodn;
+
+			int limit = MAX(0,cell_subdiv-lodn-1);
+
+			for(int c=0;c<8;c++) {
+
+				int x = bx;
+				int y = by;
+				int z = bz;
+
+				if (c&1) {
+					x+=1;
+				}
+				if (c&2) {
+					y+=1;
+				}
+				if (c&4) {
+					z+=1;
+				}
+
+				int ofs_x=0;
+				int ofs_y=0;
+				int ofs_z=0;
+				int size = cells_per_axis>>lodn;
+				int half=size/2;
+
+				bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size;
+
+				if (outside)
+					continue;
+
+
+				uint32_t cell=0;
+
+				for(int i=0;i<limit;i++) {
+
+					BakeCell *bc = &bake_cells_write[cell];
+
+					int child = 0;
+					if (x >= ofs_x + half) {
+						child|=1;
+						ofs_x+=half;
+					}
+					if (y >= ofs_y + half) {
+						child|=2;
+						ofs_y+=half;
+					}
+					if (z >= ofs_z + half) {
+						child|=4;
+						ofs_z+=half;
+					}
+
+					cell = bc->childs[child];
+					if (cell==CHILD_EMPTY)
+						break;
+
+					half>>=1;
+				}
+
+				if (cell!=CHILD_EMPTY) {
+
+					samples_base[l][c].r=bake_cells_write[cell].light[0];
+					samples_base[l][c].g=bake_cells_write[cell].light[1];
+					samples_base[l][c].b=bake_cells_write[cell].light[2];
+					samples_base[l][c].a=bake_cells_write[cell].alpha;
+				}
+
+			}
+
+
+		}
+
+		Color m0x0 = samples_base[0][0].linear_interpolate(samples_base[0][1],fx);
+		Color m0x1 = samples_base[0][2].linear_interpolate(samples_base[0][3],fx);
+		Color m0y0 = m0x0.linear_interpolate(m0x1,fy);
+		m0x0 = samples_base[0][4].linear_interpolate(samples_base[0][5],fx);
+		m0x1 = samples_base[0][6].linear_interpolate(samples_base[0][7],fx);
+		Color m0y1 = m0x0.linear_interpolate(m0x1,fy);
+		Color m0z = m0y0.linear_interpolate(m0y1,fz);
+
+		Color m1x0 = samples_base[1][0].linear_interpolate(samples_base[1][1],fx);
+		Color m1x1 = samples_base[1][2].linear_interpolate(samples_base[1][3],fx);
+		Color m1y0 = m1x0.linear_interpolate(m1x1,fy);
+		m1x0 = samples_base[1][4].linear_interpolate(samples_base[1][5],fx);
+		m1x1 = samples_base[1][6].linear_interpolate(samples_base[1][7],fx);
+		Color m1y1 = m1x0.linear_interpolate(m1x1,fy);
+		Color m1z = m1y0.linear_interpolate(m1y1,fz);
+
+		Color m = m0z.linear_interpolate(m1z,levelf);
+#else
+		float diameter = 1.0;
+		Vector3 sample_pos = from + dist * dir;
+
+		Color m(0,0,0,0);
+		{
+			int x = Math::floor(sample_pos.x);
+			int y = Math::floor(sample_pos.y);
+			int z = Math::floor(sample_pos.z);
+
+			int ofs_x=0;
+			int ofs_y=0;
+			int ofs_z=0;
+			int size = cells_per_axis;
+			int half=size/2;
+
+			bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size;
+
+			if (!outside) {
+
+
+				uint32_t cell=0;
+
+				for(int i=0;i<cell_subdiv-1;i++) {
+
+					BakeCell *bc = &bake_cells_write[cell];
+
+					int child = 0;
+					if (x >= ofs_x + half) {
+						child|=1;
+						ofs_x+=half;
+					}
+					if (y >= ofs_y + half) {
+						child|=2;
+						ofs_y+=half;
+					}
+					if (z >= ofs_z + half) {
+						child|=4;
+						ofs_z+=half;
+					}
+
+					cell = bc->childs[child];
+					if (cell==CHILD_EMPTY)
+						break;
+
+					half>>=1;
+				}
+
+				if (cell!=CHILD_EMPTY) {
+
+					m.r=bake_cells_write[cell].light[0];
+					m.g=bake_cells_write[cell].light[1];
+					m.b=bake_cells_write[cell].light[2];
+					m.a=bake_cells_write[cell].alpha;
+				}
+			}
+		}
+
+#endif
+		// front-to-back compositing
+		float a = (1.0 - alpha);
+		color.r += a * m.r;
+		color.g += a * m.g;
+		color.b += a * m.b;
+		alpha += a * m.a;
+		//occlusion += a * voxelColor.a;
+		//occlusion += (a * voxelColor.a) / (1.0 + 0.03 * diameter);
+		dist += diameter * 0.5; // smoother
+		//dist += diameter; // faster but misses more voxels
+	}
+
+	return color;
+}
+
+
+
+void BakedLight::_bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z) {
+
+
+
+
+	if (p_level==cell_subdiv-1) {
+
+		const int NUM_CONES = 6;
+		Vector3 cone_directions[6] = {
+					    Vector3(1, 0, 0),
+					    Vector3(0.5, 0.866025, 0),
+					    Vector3( 0.5, 0.267617, 0.823639),
+					    Vector3( 0.5, -0.700629, 0.509037),
+					    Vector3( 0.5, -0.700629, -0.509037),
+					    Vector3( 0.5, 0.267617, -0.823639)
+					    };
+		float coneWeights[6] = {0.25, 0.15, 0.15, 0.15, 0.15, 0.15};
+
+		Vector3 pos = (Vector3(p_x,p_y,p_z)/float(cells_per_axis))*bounds.size+bounds.pos;
+		Vector3 voxel_size = bounds.size/float(cells_per_axis);
+		pos+=voxel_size*0.5;
+
+		Color accum;
+
+		bake_cells_write[p_idx].light[0]=0;
+		bake_cells_write[p_idx].light[1]=0;
+		bake_cells_write[p_idx].light[2]=0;
+
+		int freepix=0;
+		for(int i=0;i<6;i++) {
+
+			if (!(bake_cells_write[p_idx].used_sides&(1<<i)))
+				continue;
+
+			if ((i&1)==0)
+				bake_cells_write[p_idx].light[i/2]=1.0;
+			freepix++;
+			continue;
+
+			int ofs = i/2;
+
+			Vector3 dir;
+			if ((i&1)==0)
+				dir[ofs]=1.0;
+			else
+				dir[ofs]=-1.0;
+
+			for(int j=0;j<1;j++) {
+
+
+				Vector3 cone_dir;
+				cone_dir.x = cone_directions[j][(ofs+0)%3];
+				cone_dir.y = cone_directions[j][(ofs+1)%3];
+				cone_dir.z = cone_directions[j][(ofs+2)%3];
+
+				cone_dir[ofs]*=dir[ofs];
+
+				Color res = _cone_trace(pos+dir*voxel_size,cone_dir,Math::deg2rad(29.9849));
+				accum.r+=res.r;//*coneWeights[j];
+				accum.g+=res.g;//*coneWeights[j];
+				accum.b+=res.b;//*coneWeights[j];
+			}
+
+
+		}
 #if 0
+		if (freepix==0) {
+			bake_cells_write[p_idx].light[0]=0;
+			bake_cells_write[p_idx].light[1]=0;
+			bake_cells_write[p_idx].light[2]=0;
+		}
+
+		if (freepix==1) {
+			bake_cells_write[p_idx].light[0]=1;
+			bake_cells_write[p_idx].light[1]=0;
+			bake_cells_write[p_idx].light[2]=0;
+		}
+
+		if (freepix==2) {
+			bake_cells_write[p_idx].light[0]=0;
+			bake_cells_write[p_idx].light[1]=1;
+			bake_cells_write[p_idx].light[2]=0;
+		}
+
+		if (freepix==3) {
+			bake_cells_write[p_idx].light[0]=1;
+			bake_cells_write[p_idx].light[1]=1;
+			bake_cells_write[p_idx].light[2]=0;
+		}
+
+		if (freepix==4) {
+			bake_cells_write[p_idx].light[0]=0;
+			bake_cells_write[p_idx].light[1]=0;
+			bake_cells_write[p_idx].light[2]=1;
+		}
+
+		if (freepix==5) {
+			bake_cells_write[p_idx].light[0]=1;
+			bake_cells_write[p_idx].light[1]=0;
+			bake_cells_write[p_idx].light[2]=1;
+		}
+
+		if (freepix==6) {
+			bake_cells_write[p_idx].light[0]=0;
+			bake_cells_write[p_idx].light[0]=1;
+			bake_cells_write[p_idx].light[0]=1;
+		}
+#endif
+		//bake_cells_write[p_idx].radiance[0]=accum.r;
+		//bake_cells_write[p_idx].radiance[1]=accum.g;
+		//bake_cells_write[p_idx].radiance[2]=accum.b;
+
+
+	} else {
+
+		int half = cells_per_axis >> (p_level+1);
+
+		//go down
+		for(int i=0;i<8;i++) {
+
+			uint32_t child = bake_cells_write[p_idx].childs[i];
+
+			if (child==CHILD_EMPTY)
+				continue;
+
+			int nx=p_x;
+			int ny=p_y;
+			int nz=p_z;
+
+			if (i&1)
+				nx+=half;
+			if (i&2)
+				ny+=half;
+			if (i&4)
+				nz+=half;
+
+
+			_bake_radiance(child,p_level+1,nx,ny,nz);
+		}
+	}
+}
+
+void BakedLight::bake_radiance() {
+
+	ERR_FAIL_COND(bake_cells.size()==0);
+
+	bake_cells_write = bake_cells.write();
+
+	_bake_radiance(0,0,0,0,0);
+
+	bake_cells_write=DVector<BakeCell>::Write();
 
-RID BakedLightInstance::get_baked_light_instance() const {
+}
+int BakedLight::_find_cell(int x,int y, int z) {
+
+
+	uint32_t cell=0;
+
+	int ofs_x=0;
+	int ofs_y=0;
+	int ofs_z=0;
+	int size = cells_per_axis;
+	int half=size/2;
+
+	if (x<0 || x>=size)
+		return -1;
+	if (y<0 || y>=size)
+		return -1;
+	if (z<0 || z>=size)
+		return -1;
+
+	for(int i=0;i<cell_subdiv-1;i++) {
+
+		BakeCell *bc = &bake_cells_write[cell];
+
+		int child = 0;
+		if (x >= ofs_x + half) {
+			child|=1;
+			ofs_x+=half;
+		}
+		if (y >= ofs_y + half) {
+			child|=2;
+			ofs_y+=half;
+		}
+		if (z >= ofs_z + half) {
+			child|=4;
+			ofs_z+=half;
+		}
 
-	if (baked_light.is_null())
-		return RID();
-	else
-		return get_instance();
+		cell = bc->childs[child];
+		if (cell==CHILD_EMPTY)
+			return -1;
+
+		half>>=1;
+	}
+
+	return cell;
 
 }
 
-void BakedLightInstance::set_baked_light(const Ref<BakedLight>& p_baked_light) {
 
-	baked_light=p_baked_light;
+int BakedLight::_plot_ray(const Vector3& p_from, const Vector3& p_to) {
+
+	Vector3 from = (p_from - bounds.pos) / bounds.size;
+	Vector3 to = (p_to - bounds.pos) / bounds.size;
 
-	RID base_rid;
+	int x1 = Math::floor(from.x*cells_per_axis);
+	int y1 = Math::floor(from.y*cells_per_axis);
+	int z1 = Math::floor(from.z*cells_per_axis);
 
-	if (baked_light.is_valid())
-		base_rid=baked_light->get_rid();
-	else
-		base_rid=RID();
+	int x2 = Math::floor(to.x*cells_per_axis);
+	int y2 = Math::floor(to.y*cells_per_axis);
+	int z2 = Math::floor(to.z*cells_per_axis);
 
-	set_base(base_rid);
 
-	if (is_inside_world()) {
+	int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+	int point[3];
 
-		emit_signal(SceneStringNames::get_singleton()->baked_light_changed);
+	point[0] = x1;
+	point[1] = y1;
+	point[2] = z1;
+	dx = x2 - x1;
+	dy = y2 - y1;
+	dz = z2 - z1;
+	x_inc = (dx < 0) ? -1 : 1;
+	l = ABS(dx);
+	y_inc = (dy < 0) ? -1 : 1;
+	m = ABS(dy);
+	z_inc = (dz < 0) ? -1 : 1;
+	n = ABS(dz);
+	dx2 = l << 1;
+	dy2 = m << 1;
+	dz2 = n << 1;
 
-//		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());
-//		}
+	if ((l >= m) && (l >= n)) {
+		err_1 = dy2 - l;
+		err_2 = dz2 - l;
+		for (i = 0; i < l; i++) {
+			int cell = _find_cell(point[0],point[1],point[2]);
+			if (cell>=0)
+				return cell;
+
+			if (err_1 > 0) {
+				point[1] += y_inc;
+				err_1 -= dx2;
+			}
+			if (err_2 > 0) {
+				point[2] += z_inc;
+				err_2 -= dx2;
+			}
+			err_1 += dy2;
+			err_2 += dz2;
+			point[0] += x_inc;
+		}
+	} else if ((m >= l) && (m >= n)) {
+		err_1 = dx2 - m;
+		err_2 = dz2 - m;
+		for (i = 0; i < m; i++) {
+			int cell = _find_cell(point[0],point[1],point[2]);
+			if (cell>=0)
+				return cell;
+			if (err_1 > 0) {
+				point[0] += x_inc;
+				err_1 -= dy2;
+			}
+			if (err_2 > 0) {
+				point[2] += z_inc;
+				err_2 -= dy2;
+			}
+			err_1 += dx2;
+			err_2 += dz2;
+			point[1] += y_inc;
+		}
+	} else {
+		err_1 = dy2 - n;
+		err_2 = dx2 - n;
+		for (i = 0; i < n; i++) {
+			int cell = _find_cell(point[0],point[1],point[2]);
+			if (cell>=0)
+				return cell;
+
+			if (err_1 > 0) {
+				point[1] += y_inc;
+				err_1 -= dz2;
+			}
+			if (err_2 > 0) {
+				point[0] += x_inc;
+				err_2 -= dz2;
+			}
+			err_1 += dy2;
+			err_2 += dx2;
+			point[2] += z_inc;
+		}
 	}
+	return _find_cell(point[0],point[1],point[2]);
+
+}
 
-	update_configuration_warning();
+
+void BakedLight::set_cell_subdiv(int p_subdiv) {
+
+	cell_subdiv=p_subdiv;
+
+//	VS::get_singleton()->baked_light_set_subdivision(baked_light,p_subdiv);
 }
 
-Ref<BakedLight> BakedLightInstance::get_baked_light() const{
+int BakedLight::get_cell_subdiv() const {
 
-	return baked_light;
+	return cell_subdiv;
 }
 
-AABB BakedLightInstance::get_aabb() const {
+
+
+AABB BakedLight::get_aabb() const {
 
 	return AABB(Vector3(0,0,0),Vector3(1,1,1));
 }
-DVector<Face3> BakedLightInstance::get_faces(uint32_t p_usage_flags) const {
+DVector<Face3> BakedLight::get_faces(uint32_t p_usage_flags) const {
 
 	return DVector<Face3>();
 }
 
 
-String BakedLightInstance::get_configuration_warning() const {
-	if (get_baked_light().is_null()) {
-		return TTR("BakedLightInstance does not contain a BakedLight resource.");
-	}
+String BakedLight::get_configuration_warning() const {
 	return String();
 }
 
 
-void BakedLightInstance::_bind_methods() {
+void BakedLight::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref<MultiMesh> &p_multimesh,int &idx) {
+
+
+	if (p_level==cell_subdiv-1) {
+
+		Vector3 center = p_aabb.pos+p_aabb.size*0.5;
+		Transform xform;
+		xform.origin=center;
+		xform.basis.scale(p_aabb.size*0.5);
+		p_multimesh->set_instance_transform(idx,xform);
+		Color col;
+		switch(p_mode) {
+			case DEBUG_ALBEDO: {
+				col=Color(bake_cells_write[p_idx].albedo[0],bake_cells_write[p_idx].albedo[1],bake_cells_write[p_idx].albedo[2]);
+			} break;
+			case DEBUG_LIGHT: {
+				col=Color(bake_cells_write[p_idx].light[0],bake_cells_write[p_idx].light[1],bake_cells_write[p_idx].light[2]);
+				Color colr=Color(bake_cells_write[p_idx].radiance[0],bake_cells_write[p_idx].radiance[1],bake_cells_write[p_idx].radiance[2]);
+				col.r+=colr.r;
+				col.g+=colr.g;
+				col.b+=colr.b;
+			} break;
+
+		}
+		p_multimesh->set_instance_color(idx,col);
+
+
+		idx++;
+
+	} else {
+
+		for(int i=0;i<8;i++) {
+
+			if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY)
+				continue;
+
+			AABB aabb=p_aabb;
+			aabb.size*=0.5;
+
+			if (i&1)
+				aabb.pos.x+=aabb.size.x;
+			if (i&2)
+				aabb.pos.y+=aabb.size.y;
+			if (i&4)
+				aabb.pos.z+=aabb.size.z;
+
+			_debug_mesh(bake_cells_write[p_idx].childs[i],p_level+1,aabb,p_mode,p_multimesh,idx);
+		}
+
+	}
+
+}
+
+
+void BakedLight::create_debug_mesh(DebugMode p_mode) {
+
+	Ref<MultiMesh> mm;
+	mm.instance();
+
+	mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+	mm->set_color_format(MultiMesh::COLOR_8BIT);
+	mm->set_instance_count(bake_cells_level_used[cell_subdiv-1]);
+
+	Ref<Mesh> mesh;
+	mesh.instance();
+
+
+
+	{
+		Array arr;
+		arr.resize(Mesh::ARRAY_MAX);
+
+		DVector<Vector3> vertices;
+		DVector<Color> colors;
+
+		int vtx_idx=0;
+	#define ADD_VTX(m_idx);\
+		vertices.push_back( face_points[m_idx] );\
+		colors.push_back( Color(1,1,1,1) );\
+		vtx_idx++;\
+
+		for (int i=0;i<6;i++) {
+
+
+			Vector3 face_points[4];
+
+			for (int j=0;j<4;j++) {
+
+				float v[3];
+				v[0]=1.0;
+				v[1]=1-2*((j>>1)&1);
+				v[2]=v[1]*(1-2*(j&1));
+
+				for (int k=0;k<3;k++) {
+
+					if (i<3)
+						face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+					else
+						face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+				}
+			}
+
+		//tri 1
+			ADD_VTX(0);
+			ADD_VTX(1);
+			ADD_VTX(2);
+		//tri 2
+			ADD_VTX(2);
+			ADD_VTX(3);
+			ADD_VTX(0);
+
+		}
+
+
+		arr[Mesh::ARRAY_VERTEX]=vertices;
+		arr[Mesh::ARRAY_COLOR]=colors;
+		mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
+	}
+
+	{
+		Ref<FixedSpatialMaterial> fsm;
+		fsm.instance();
+		fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
+		fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
+		fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
+		fsm->set_albedo(Color(1,1,1,1));
+
+		mesh->surface_set_material(0,fsm);
+	}
+
+	mm->set_mesh(mesh);
+
+
+	bake_cells_write = bake_cells.write();
+
+
+
+	int idx=0;
+	_debug_mesh(0,0,bounds,p_mode,mm,idx);
+
+	print_line("written: "+itos(idx)+" total: "+itos(bake_cells_level_used[cell_subdiv-1]));
+
+
+	MultiMeshInstance *mmi = memnew( MultiMeshInstance );
+	mmi->set_multimesh(mm);
+	add_child(mmi);
+	if (get_tree()->get_edited_scene_root()==this){
+		mmi->set_owner(this);
+	} else {
+		mmi->set_owner(get_owner());
+
+	}
+
+}
+
+void BakedLight::_debug_mesh_albedo() {
+	create_debug_mesh(DEBUG_ALBEDO);
+}
+
+void BakedLight::_debug_mesh_light() {
+	create_debug_mesh(DEBUG_LIGHT);
+}
+
+
+void BakedLight::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_cell_subdiv","steps"),&BakedLight::set_cell_subdiv);
+	ObjectTypeDB::bind_method(_MD("get_cell_subdiv"),&BakedLight::get_cell_subdiv);
+
+	ObjectTypeDB::bind_method(_MD("bake"),&BakedLight::bake);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+	ObjectTypeDB::bind_method(_MD("bake_lights"),&BakedLight::bake_lights);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_lights"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+	ObjectTypeDB::bind_method(_MD("bake_radiance"),&BakedLight::bake_radiance);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_radiance"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+	ObjectTypeDB::bind_method(_MD("debug_mesh_albedo"),&BakedLight::_debug_mesh_albedo);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_albedo"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
 
-	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);
+	ObjectTypeDB::bind_method(_MD("debug_mesh_light"),&BakedLight::_debug_mesh_light);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_light"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
 
-	ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"baked_light",PROPERTY_HINT_RESOURCE_TYPE,"BakedLight"),_SCS("set_baked_light"),_SCS("get_baked_light"));
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"cell_subdiv"),_SCS("set_cell_subdiv"),_SCS("get_cell_subdiv"));
 	ADD_SIGNAL( MethodInfo("baked_light_changed"));
+
 }
 
-BakedLightInstance::BakedLightInstance() {
+BakedLight::BakedLight() {
 
+//	baked_light=VisualServer::get_singleton()->baked_light_create();
+	VS::get_singleton()->instance_set_base(get_instance(),baked_light);
 
+	cell_subdiv=8;
+	bake_texture_size=128;
+	color_scan_cell_width=8;
+	light_pass=0;
 }
-/////////////////////////
 
 
+BakedLight::~BakedLight() {
+
+	VS::get_singleton()->free(baked_light);
+}
+
+/////////////////////////
+
+#if 0
 void BakedLightSampler::set_param(Param p_param,float p_value) {
 	ERR_FAIL_INDEX(p_param,PARAM_MAX);
 	params[p_param]=p_value;

+ 113 - 9
scene/3d/baked_light_instance.h

@@ -31,38 +31,142 @@
 
 #include "scene/3d/visual_instance.h"
 #include "scene/resources/baked_light.h"
+#include "scene/3d/multimesh_instance.h"
+
 
-#if 0
 class BakedLightBaker;
+class Light;
+
+class BakedLight : public VisualInstance {
+	OBJ_TYPE(BakedLight,VisualInstance);
+
+public:
+	enum DebugMode {
+		DEBUG_ALBEDO,
+		DEBUG_LIGHT
+	};
+
+private:
+	RID baked_light;
+	int cell_subdiv;
+	AABB bounds;
+	int cells_per_axis;
+
+	enum {
+		CHILD_EMPTY=0xFFFFFFFF,
+	};
+
+
+	/* BAKE DATA */
+
+	struct BakeCell {
+
+		uint32_t childs[8];
+		float albedo[3]; //albedo in RGB24
+		float light[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+		float radiance[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+		uint32_t used_sides;
+		float alpha; //used for upsampling
+		uint32_t light_pass; //used for baking light
+
+		BakeCell() {
+			for(int i=0;i<8;i++) {
+				childs[i]=0xFFFFFFFF;
+			}
+
+			for(int i=0;i<3;i++) {
+				light[i]=0;
+				albedo[i]=0;
+				radiance[i]=0;
+			}
+			alpha=0;
+			light_pass=0;
+			used_sides=0;
+		}
+	};
+
+
+	int bake_texture_size;
+	int color_scan_cell_width;
+
+	struct MaterialCache {
+		//128x128 textures
+		Vector<Color> albedo;
+		Vector<Color> emission;
+	};
+
 
+	Vector<Color> _get_bake_texture(Image &p_image, const Color &p_color);
 
-class BakedLightInstance : public VisualInstance {
-	OBJ_TYPE(BakedLightInstance,VisualInstance);
 
-	Ref<BakedLight> baked_light;
 
+	Map<Ref<Material>,MaterialCache> material_cache;
+	MaterialCache _get_material_cache(Ref<Material> p_material);
 
+	int bake_cells_alloc;
+	int bake_cells_used;
+	int zero_alphas;
+	Vector<int> bake_cells_level_used;
+	DVector<BakeCell> bake_cells;
+	DVector<BakeCell>::Write bake_cells_write;
+
+
+
+	void _plot_face(int p_idx,int p_level,const Vector3 *p_vtx,const Vector2* p_uv, const MaterialCache& p_material,const AABB& p_aabb);
+	void _fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z);
+	void _bake_add_mesh(const Transform& p_xform,Ref<Mesh>& p_mesh);
+	void _bake_add_to_aabb(const Transform& p_xform,Ref<Mesh>& p_mesh,bool &first);
+
+	void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref<MultiMesh> &p_multimesh,int &idx);
+	void _debug_mesh_albedo();
+	void _debug_mesh_light();
+
+
+	_FORCE_INLINE_ int _find_cell(int x,int y, int z);
+	int _plot_ray(const Vector3& p_from, const Vector3& p_to);
+
+	uint32_t light_pass;
+
+
+	void _bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign);
+	void _upscale_light(int p_idx,int p_level);
+	void _bake_light(Light* p_light);
+
+	Color _cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle);
+	void _bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z);
+
+friend class GeometryInstance;
+
+	Set<GeometryInstance*> geometries;
+friend class Light;
+
+	Set<Light*> lights;
 protected:
 
 	static void _bind_methods();
 public:
 
+	void set_cell_subdiv(int p_subdiv);
+	int get_cell_subdiv() const;
+
+	void bake();
+	void bake_lights();
+	void bake_radiance();
 
-	RID get_baked_light_instance() const;
 
-	void set_baked_light(const Ref<BakedLight>& baked_light);
-	Ref<BakedLight> get_baked_light() const;
+	void create_debug_mesh(DebugMode p_mode);
 
 	virtual AABB get_aabb() const;
 	virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
 
 	String get_configuration_warning() const;
 
-	BakedLightInstance();
+	BakedLight();
+	~BakedLight();
 };
 
 
-
+#if 0
 class BakedLightSampler : public VisualInstance {
 	OBJ_TYPE(BakedLightSampler,VisualInstance);
 

+ 1248 - 0
scene/3d/gi_probe.cpp

@@ -0,0 +1,1248 @@
+#include "gi_probe.h"
+#include "mesh_instance.h"
+
+enum DataFormat {
+	DATA_RGBA8,
+	DATA_DXT5,
+	DATA_ETC2_EAC,
+};
+
+
+void GIProbeData::set_bounds(const AABB& p_bounds) {
+
+	VS::get_singleton()->gi_probe_set_bounds(probe,p_bounds);
+}
+
+AABB GIProbeData::get_bounds() const{
+
+	return VS::get_singleton()->gi_probe_get_bounds(probe);
+}
+
+void GIProbeData::set_cell_size(float p_size) {
+
+	VS::get_singleton()->gi_probe_set_cell_size(probe,p_size);
+
+}
+
+float GIProbeData::get_cell_size() const {
+
+	return VS::get_singleton()->gi_probe_get_cell_size(probe);
+
+}
+
+void GIProbeData::set_to_cell_xform(const Transform& p_xform) {
+
+	VS::get_singleton()->gi_probe_set_to_cell_xform(probe,p_xform);
+
+}
+
+Transform GIProbeData::get_to_cell_xform() const {
+
+	return VS::get_singleton()->gi_probe_get_to_cell_xform(probe);
+
+}
+
+
+void GIProbeData::set_dynamic_data(const DVector<int>& p_data){
+
+	VS::get_singleton()->gi_probe_set_dynamic_data(probe,p_data);
+
+}
+DVector<int> GIProbeData::get_dynamic_data() const{
+
+	return VS::get_singleton()->gi_probe_get_dynamic_data(probe);
+}
+
+void GIProbeData::set_dynamic_range(float p_range){
+
+	VS::get_singleton()->gi_probe_set_dynamic_range(probe,p_range);
+
+}
+float GIProbeData::get_dynamic_range() const{
+
+
+	return VS::get_singleton()->gi_probe_get_dynamic_range(probe);
+}
+
+void GIProbeData::set_static_data(const DVector<uint8_t>& p_data,DataFormat p_format,int p_width,int p_height,int p_depth){
+
+	VS::get_singleton()->gi_probe_set_static_data(probe,p_data,VS::GIProbeDataFormat(p_format),p_width,p_height,p_depth);
+
+}
+DVector<uint8_t> GIProbeData::get_static_data() const{
+
+	return VS::get_singleton()->gi_probe_get_static_data(probe);
+
+}
+GIProbeData::DataFormat GIProbeData::get_static_data_format() const{
+
+	return GIProbeData::DataFormat(VS::get_singleton()->gi_probe_get_static_data_format(probe));
+
+}
+int GIProbeData::get_static_data_width() const{
+
+	return VS::get_singleton()->gi_probe_get_static_data_width(probe);
+
+}
+int GIProbeData::get_static_data_height() const{
+
+	return VS::get_singleton()->gi_probe_get_static_data_height(probe);
+
+}
+int GIProbeData::get_static_data_depth() const{
+
+	return VS::get_singleton()->gi_probe_get_static_data_depth(probe);
+
+}
+
+RID GIProbeData::get_rid() const {
+
+	return probe;
+}
+
+GIProbeData::GIProbeData() {
+
+	probe=VS::get_singleton()->gi_probe_create();
+}
+
+GIProbeData::~GIProbeData() {
+
+	VS::get_singleton()->free(probe);
+}
+
+
+//////////////////////
+//////////////////////
+
+
+void GIProbe::set_probe_data(const Ref<GIProbeData>& p_data) {
+
+	if (p_data.is_valid()) {
+		VS::get_singleton()->instance_set_base(get_instance(),p_data->get_rid());
+	} else {
+		VS::get_singleton()->instance_set_base(get_instance(),RID());
+	}
+
+	probe_data=p_data;
+}
+
+Ref<GIProbeData> GIProbe::get_probe_data() const {
+
+	return probe_data;
+}
+
+void GIProbe::set_subdiv(Subdiv p_subdiv) {
+
+	ERR_FAIL_INDEX(p_subdiv,SUBDIV_MAX);
+	subdiv=p_subdiv;
+	update_gizmo();
+}
+
+GIProbe::Subdiv GIProbe::get_subdiv() const {
+
+	return subdiv;
+}
+
+void GIProbe::set_extents(const Vector3& p_extents) {
+
+	extents=p_extents;
+	update_gizmo();
+}
+
+Vector3 GIProbe::get_extents() const {
+
+	return extents;
+}
+
+void GIProbe::set_dynamic_range(float p_dynamic_range) {
+
+	dynamic_range=p_dynamic_range;
+}
+float GIProbe::get_dynamic_range() const {
+
+	return dynamic_range;
+}
+
+#include "math.h"
+
+#define FINDMINMAX(x0,x1,x2,min,max) \
+  min = max = x0;   \
+  if(x1<min) min=x1;\
+  if(x1>max) max=x1;\
+  if(x2<min) min=x2;\
+  if(x2>max) max=x2;
+
+static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox)
+{
+  int q;
+  Vector3 vmin,vmax;
+  for(q=0;q<=2;q++)
+  {
+    if(normal[q]>0.0f)
+    {
+      vmin[q]=-maxbox[q];
+      vmax[q]=maxbox[q];
+    }
+    else
+    {
+      vmin[q]=maxbox[q];
+      vmax[q]=-maxbox[q];
+    }
+  }
+  if(normal.dot(vmin)+d>0.0f) return false;
+  if(normal.dot(vmax)+d>=0.0f) return true;
+
+  return false;
+}
+
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb)             \
+    p0 = a*v0.y - b*v0.z;                    \
+    p2 = a*v2.y - b*v2.z;                    \
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+    rad = fa * boxhalfsize.y + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb)              \
+    p0 = a*v0.y - b*v0.z;                    \
+    p1 = a*v1.y - b*v1.z;                    \
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+    rad = fa * boxhalfsize.y + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb)             \
+    p0 = -a*v0.x + b*v0.z;                   \
+    p2 = -a*v2.x + b*v2.z;                       \
+	if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb)              \
+    p0 = -a*v0.x + b*v0.z;                   \
+    p1 = -a*v1.x + b*v1.z;                       \
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.z;   \
+    if(min>rad || max<-rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb)             \
+    p1 = a*v1.x - b*v1.y;                    \
+    p2 = a*v2.x - b*v2.y;                    \
+	if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;   \
+    if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb)              \
+    p0 = a*v0.x - b*v0.y;                \
+    p1 = a*v1.x - b*v1.y;                    \
+	if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+    rad = fa * boxhalfsize.x + fb * boxhalfsize.y;   \
+    if(min>rad || max<-rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) {
+
+  /*    use separating axis theorem to test overlap between triangle and box */
+  /*    need to test for overlap in these directions: */
+  /*    1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+  /*       we do not even need to test these) */
+  /*    2) normal of the triangle */
+  /*    3) crossproduct(edge from tri, {x,y,z}-directin) */
+  /*       this gives 3x3=9 more tests */
+   Vector3 v0,v1,v2;
+   float min,max,d,p0,p1,p2,rad,fex,fey,fez;
+   Vector3 normal,e0,e1,e2;
+
+   /* This is the fastest branch on Sun */
+   /* move everything so that the boxcenter is in (0,0,0) */
+
+   v0=triverts[0]-boxcenter;
+   v1=triverts[1]-boxcenter;
+   v2=triverts[2]-boxcenter;
+
+   /* compute triangle edges */
+   e0=v1-v0;      /* tri edge 0 */
+   e1=v2-v1;      /* tri edge 1 */
+   e2=v0-v2;      /* tri edge 2 */
+
+   /* Bullet 3:  */
+   /*  test the 9 tests first (this was faster) */
+   fex = Math::abs(e0.x);
+   fey = Math::abs(e0.y);
+   fez = Math::abs(e0.z);
+   AXISTEST_X01(e0.z, e0.y, fez, fey);
+   AXISTEST_Y02(e0.z, e0.x, fez, fex);
+   AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+   fex = Math::abs(e1.x);
+   fey = Math::abs(e1.y);
+   fez = Math::abs(e1.z);
+   AXISTEST_X01(e1.z, e1.y, fez, fey);
+   AXISTEST_Y02(e1.z, e1.x, fez, fex);
+   AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+   fex = Math::abs(e2.x);
+   fey = Math::abs(e2.y);
+   fez = Math::abs(e2.z);
+   AXISTEST_X2(e2.z, e2.y, fez, fey);
+   AXISTEST_Y1(e2.z, e2.x, fez, fex);
+   AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+   /* Bullet 1: */
+   /*  first test overlap in the {x,y,z}-directions */
+   /*  find min, max of the triangle each direction, and test for overlap in */
+   /*  that direction -- this is equivalent to testing a minimal AABB around */
+   /*  the triangle against the AABB */
+
+   /* test in X-direction */
+   FINDMINMAX(v0.x,v1.x,v2.x,min,max);
+   if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+   /* test in Y-direction */
+   FINDMINMAX(v0.y,v1.y,v2.y,min,max);
+   if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+   /* test in Z-direction */
+   FINDMINMAX(v0.z,v1.z,v2.z,min,max);
+   if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+   /* Bullet 2: */
+   /*  test if the box intersects the plane of the triangle */
+   /*  compute plane equation of triangle: normal*x+d=0 */
+   normal=e0.cross(e1);
+   d=-normal.dot(v0);  /* plane eq: normal.x+d=0 */
+   if(!planeBoxOverlap(normal,d,boxhalfsize)) return false;
+
+   return true;   /* box and triangle overlaps */
+}
+
+
+
+static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) {
+
+	if (p_pos.distance_squared_to(p_vtx[0])<CMP_EPSILON2)
+		return p_uv[0];
+	if (p_pos.distance_squared_to(p_vtx[1])<CMP_EPSILON2)
+		return p_uv[1];
+	if (p_pos.distance_squared_to(p_vtx[2])<CMP_EPSILON2)
+		return p_uv[2];
+
+	Vector3 v0 = p_vtx[1] - p_vtx[0];
+	Vector3 v1 = p_vtx[2] - p_vtx[0];
+	Vector3 v2 = p_pos - p_vtx[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 p_uv[0];
+	float v = (d11 * d20 - d01 * d21) / denom;
+	float w = (d00 * d21 - d01 * d20) / denom;
+	float u = 1.0f - v - w;
+
+	return p_uv[0]*u + p_uv[1]*v  + p_uv[2]*w;
+}
+
+void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker) {
+
+
+
+	if (p_level==p_baker->cell_subdiv-1) {
+		//plot the face by guessing it's albedo and emission value
+
+		//find best axis to map to, for scanning values
+		int closest_axis;
+		float closest_dot;
+
+		Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal;
+
+		for(int i=0;i<3;i++) {
+
+			Vector3 axis;
+			axis[i]=1.0;
+			float dot=ABS(normal.dot(axis));
+			if (i==0 || dot>closest_dot) {
+				closest_axis=i;
+				closest_dot=dot;
+			}
+		}
+
+		Vector3 axis;
+		axis[closest_axis]=1.0;
+		Vector3 t1;
+		t1[(closest_axis+1)%3]=1.0;
+		Vector3 t2;
+		t2[(closest_axis+2)%3]=1.0;
+
+		t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width);
+		t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width);
+
+		Color albedo_accum;
+		Color emission_accum;
+		float alpha=0.0;
+
+		//map to a grid average in the best axis for this face
+		for(int i=0;i<color_scan_cell_width;i++) {
+
+			Vector3 ofs_i=float(i)*t1;
+
+			for(int j=0;j<color_scan_cell_width;j++) {
+
+				Vector3 ofs_j=float(j)*t2;
+
+				Vector3 from = p_aabb.pos+ofs_i+ofs_j;
+				Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+				Vector3 half = (to-from)*0.5;
+
+				//is in this cell?
+				if (!fast_tri_box_overlap(from+half,half,p_vtx)) {
+					continue; //face does not span this cell
+				}
+
+				//go from -size to +size*2 to avoid skipping collisions
+				Vector3 ray_from = from + (t1+t2)*0.5 - axis * p_aabb.size[closest_axis];
+				Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis]*2;
+
+				Vector3 intersection;
+
+				if (!Geometry::ray_intersects_triangle(ray_from,ray_to,p_vtx[0],p_vtx[1],p_vtx[2],&intersection)) {
+					//no intersect? look in edges
+
+					float closest_dist=1e20;
+					for(int j=0;j<3;j++) {
+						Vector3 c;
+						Vector3 inters;
+						Geometry::get_closest_points_between_segments(p_vtx[j],p_vtx[(j+1)%3],ray_from,ray_to,inters,c);
+						float d=c.distance_to(intersection);
+						if (j==0 || d<closest_dist) {
+							closest_dist=d;
+							intersection=inters;
+						}
+					}
+				}
+
+				Vector2 uv = get_uv(intersection,p_vtx,p_uv);
+
+
+				int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+				int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+				int ofs = uv_y*bake_texture_size+uv_x;
+				albedo_accum.r+=p_material.albedo[ofs].r;
+				albedo_accum.g+=p_material.albedo[ofs].g;
+				albedo_accum.b+=p_material.albedo[ofs].b;
+				albedo_accum.a+=p_material.albedo[ofs].a;
+
+				emission_accum.r+=p_material.emission[ofs].r;
+				emission_accum.g+=p_material.emission[ofs].g;
+				emission_accum.b+=p_material.emission[ofs].b;
+				alpha+=1.0;
+
+			}
+		}
+
+
+		if (alpha==0) {
+			//could not in any way get texture information.. so use closest point to center
+
+			Face3 f( p_vtx[0],p_vtx[1],p_vtx[2]);
+			Vector3 inters = f.get_closest_point_to(p_aabb.pos+p_aabb.size*0.5);
+
+			Vector2 uv = get_uv(inters,p_vtx,p_uv);
+
+			int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+			int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+			int ofs = uv_y*bake_texture_size+uv_x;
+
+			alpha = 1.0/(color_scan_cell_width*color_scan_cell_width);
+
+			albedo_accum.r=p_material.albedo[ofs].r*alpha;
+			albedo_accum.g=p_material.albedo[ofs].g*alpha;
+			albedo_accum.b=p_material.albedo[ofs].b*alpha;
+			albedo_accum.a=p_material.albedo[ofs].a*alpha;
+
+			emission_accum.r=p_material.emission[ofs].r*alpha;
+			emission_accum.g=p_material.emission[ofs].g*alpha;
+			emission_accum.b=p_material.emission[ofs].b*alpha;
+
+
+
+		} else {
+
+			float accdiv = 1.0/(color_scan_cell_width*color_scan_cell_width);
+			alpha*=accdiv;
+
+			albedo_accum.r*=accdiv;
+			albedo_accum.g*=accdiv;
+			albedo_accum.b*=accdiv;
+			albedo_accum.a*=accdiv;
+
+			emission_accum.r*=accdiv;
+			emission_accum.g*=accdiv;
+			emission_accum.b*=accdiv;
+		}
+
+		//put this temporarily here, corrected in a later step
+		p_baker->bake_cells[p_idx].albedo[0]+=albedo_accum.r;
+		p_baker->bake_cells[p_idx].albedo[1]+=albedo_accum.g;
+		p_baker->bake_cells[p_idx].albedo[2]+=albedo_accum.b;
+		p_baker->bake_cells[p_idx].emission[0]+=emission_accum.r;
+		p_baker->bake_cells[p_idx].emission[1]+=emission_accum.g;
+		p_baker->bake_cells[p_idx].emission[2]+=emission_accum.b;
+		p_baker->bake_cells[p_idx].alpha+=alpha;
+
+		static const Vector3 side_normals[6]={
+			Vector3(-1, 0, 0),
+			Vector3( 1, 0, 0),
+			Vector3( 0,-1, 0),
+			Vector3( 0, 1, 0),
+			Vector3( 0, 0,-1),
+			Vector3( 0, 0, 1),
+		};
+
+		for(int i=0;i<6;i++) {
+			if (normal.dot(side_normals[i])>CMP_EPSILON) {
+				p_baker->bake_cells[p_idx].used_sides|=(1<<i);
+			}
+		}
+
+
+	} else {
+		//go down
+
+		int half = (1<<(p_baker->cell_subdiv-1)) >> (p_level+1);
+		for(int i=0;i<8;i++) {
+
+			AABB aabb=p_aabb;
+			aabb.size*=0.5;
+
+			int nx=p_x;
+			int ny=p_y;
+			int nz=p_z;
+
+			if (i&1) {
+				aabb.pos.x+=aabb.size.x;
+				nx+=half;
+			}
+			if (i&2) {
+				aabb.pos.y+=aabb.size.y;
+				ny+=half;
+			}
+			if (i&4) {
+				aabb.pos.z+=aabb.size.z;
+				nz+=half;
+			}
+			//make sure to not plot beyond limits
+			if (nx<0 || nx>=p_baker->axis_cell_size[0] || ny<0 || ny>=p_baker->axis_cell_size[1] || nz<0 || nz>=p_baker->axis_cell_size[2])
+				continue;
+
+			{
+				AABB test_aabb=aabb;
+				//test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+				Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test
+
+				if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) {
+				//if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+					//does not fit in child, go on
+					continue;
+				}
+
+			}
+
+			if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) {
+				//sub cell must be created
+
+				p_baker->bake_cells[p_idx].childs[i]=p_baker->bake_cells.size();
+				p_baker->bake_cells.resize( p_baker->bake_cells.size() + 1);
+
+			}
+
+
+			_plot_face(p_baker->bake_cells[p_idx].childs[i],p_level+1,nx,ny,nz,p_vtx,p_uv,p_material,aabb,p_baker);
+		}
+	}
+}
+
+
+
+void GIProbe::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker) {
+
+
+
+	if (p_level==p_baker->cell_subdiv-1) {
+
+		p_baker->leaf_voxel_count++;
+		float alpha = p_baker->bake_cells[p_idx].alpha;
+
+		p_baker->bake_cells[p_idx].albedo[0]/=alpha;
+		p_baker->bake_cells[p_idx].albedo[1]/=alpha;
+		p_baker->bake_cells[p_idx].albedo[2]/=alpha;
+
+		//transfer emission to light
+		p_baker->bake_cells[p_idx].emission[0]/=alpha;
+		p_baker->bake_cells[p_idx].emission[1]/=alpha;
+		p_baker->bake_cells[p_idx].emission[2]/=alpha;
+
+		p_baker->bake_cells[p_idx].alpha=1.0;
+
+		//remove neighbours from used sides
+
+		for(int n=0;n<6;n++) {
+
+			int ofs[3]={0,0,0};
+
+			ofs[n/2]=(n&1)?1:-1;
+
+			//convert to x,y,z on this level
+			int x=p_x;
+			int y=p_y;
+			int z=p_z;
+
+			x+=ofs[0];
+			y+=ofs[1];
+			z+=ofs[2];
+
+			int ofs_x=0;
+			int ofs_y=0;
+			int ofs_z=0;
+			int size = 1<<p_level;
+			int half=size/2;
+
+
+			if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) {
+				//neighbour is out, can't use it
+				p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n));
+				continue;
+			}
+
+			uint32_t neighbour=0;
+
+			for(int i=0;i<p_baker->cell_subdiv-1;i++) {
+
+				Baker::Cell *bc = &p_baker->bake_cells[neighbour];
+
+				int child = 0;
+				if (x >= ofs_x + half) {
+					child|=1;
+					ofs_x+=half;
+				}
+				if (y >= ofs_y + half) {
+					child|=2;
+					ofs_y+=half;
+				}
+				if (z >= ofs_z + half) {
+					child|=4;
+					ofs_z+=half;
+				}
+
+				neighbour = bc->childs[child];
+				if (neighbour==Baker::CHILD_EMPTY) {
+					break;
+				}
+
+				half>>=1;
+			}
+
+			if (neighbour!=Baker::CHILD_EMPTY) {
+				p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n));
+			}
+		}
+	} else {
+
+
+		//go down
+
+		float alpha_average=0;
+		int half = (1<<(p_baker->cell_subdiv-1)) >> (p_level+1);
+		for(int i=0;i<8;i++) {
+
+			uint32_t child = p_baker->bake_cells[p_idx].childs[i];
+
+			if (child==Baker::CHILD_EMPTY)
+				continue;
+
+
+			int nx=p_x;
+			int ny=p_y;
+			int nz=p_z;
+
+			if (i&1)
+				nx+=half;
+			if (i&2)
+				ny+=half;
+			if (i&4)
+				nz+=half;
+
+			_fixup_plot(child,p_level+1,nx,ny,nz,p_baker);
+			alpha_average+=p_baker->bake_cells[child].alpha;
+		}
+
+		p_baker->bake_cells[p_idx].alpha=alpha_average/8.0;
+		p_baker->bake_cells[p_idx].emission[0]=0;
+		p_baker->bake_cells[p_idx].emission[1]=0;
+		p_baker->bake_cells[p_idx].emission[2]=0;
+		p_baker->bake_cells[p_idx].albedo[0]=0;
+		p_baker->bake_cells[p_idx].albedo[1]=0;
+		p_baker->bake_cells[p_idx].albedo[2]=0;
+
+	}
+
+}
+
+
+
+Vector<Color> GIProbe::_get_bake_texture(Image &p_image,const Color& p_color) {
+
+	Vector<Color> ret;
+
+	if (p_image.empty()) {
+
+		ret.resize(bake_texture_size*bake_texture_size);
+		for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+			ret[i]=p_color;
+		}
+
+		return ret;
+	}
+
+	p_image.convert(Image::FORMAT_RGBA8);
+	p_image.resize(bake_texture_size,bake_texture_size,Image::INTERPOLATE_CUBIC);
+
+
+	DVector<uint8_t>::Read r = p_image.get_data().read();
+	ret.resize(bake_texture_size*bake_texture_size);
+
+	for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+		Color c;
+		c.r = r[i*4+0]/255.0;
+		c.g = r[i*4+1]/255.0;
+		c.b = r[i*4+2]/255.0;
+		c.a = r[i*4+3]/255.0;
+		ret[i]=c;
+
+	}
+
+	return ret;
+}
+
+
+GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_material,Baker *p_baker) {
+
+	//this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+	Ref<FixedSpatialMaterial> mat = p_material;
+
+	Ref<Material> material = mat; //hack for now
+
+	if (p_baker->material_cache.has(material)) {
+		return p_baker->material_cache[material];
+	}
+
+	Baker::MaterialCache mc;
+
+	if (mat.is_valid()) {
+
+
+		Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+
+		Image img_albedo;
+		if (albedo_tex.is_valid()) {
+
+			img_albedo = albedo_tex->get_data();
+		}
+
+		mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo());
+
+		Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+
+		Color emission_col = mat->get_emission();
+		emission_col.r*=mat->get_emission_energy();
+		emission_col.g*=mat->get_emission_energy();
+		emission_col.b*=mat->get_emission_energy();
+
+		Image img_emission;
+
+		if (emission_tex.is_valid()) {
+
+			img_emission = emission_tex->get_data();
+		}
+
+		mc.emission=_get_bake_texture(img_emission,emission_col);
+
+	} else {
+		Image empty;
+
+		mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7));
+		mc.emission=_get_bake_texture(empty,Color(0,0,0));
+
+
+	}
+
+	p_baker->material_cache[p_material]=mc;
+	return mc;
+
+
+}
+
+void GIProbe::_plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker) {
+
+
+	for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+		if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+			continue; //only triangles
+
+		Baker::MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i),p_baker);
+
+		Array a = p_mesh->surface_get_arrays(i);
+
+
+		DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+		DVector<Vector3>::Read vr=vertices.read();
+		DVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+		DVector<Vector2>::Read uvr;
+		DVector<int> index = a[Mesh::ARRAY_INDEX];
+
+		bool read_uv=false;
+
+		if (uv.size()) {
+
+			uvr=uv.read();
+			read_uv=true;
+		}
+
+		if (index.size()) {
+
+			int facecount = index.size()/3;
+			DVector<int>::Read ir=index.read();
+
+			for(int j=0;j<facecount;j++) {
+
+				Vector3 vtxs[3];
+				Vector2 uvs[3];
+
+				for(int k=0;k<3;k++) {
+					vtxs[k]=p_xform.xform(vr[ir[j*3+k]]);
+				}
+
+				if (read_uv) {
+					for(int k=0;k<3;k++) {
+						uvs[k]=uvr[ir[j*3+k]];
+					}
+				}
+
+				//test against original bounds
+				if (!fast_tri_box_overlap(-extents,extents*2,vtxs))
+					continue;
+				//plot
+				_plot_face(0,0,0,0,0,vtxs,uvs,material,p_baker->po2_bounds,p_baker);
+			}
+
+
+
+		} else {
+
+			int facecount = vertices.size()/3;
+
+			for(int j=0;j<facecount;j++) {
+
+				Vector3 vtxs[3];
+				Vector2 uvs[3];
+
+				for(int k=0;k<3;k++) {
+					vtxs[k]=p_xform.xform(vr[j*3+k]);
+				}
+
+				if (read_uv) {
+					for(int k=0;k<3;k++) {
+						uvs[k]=uvr[j*3+k];
+					}
+				}
+
+				//test against original bounds
+				if (!fast_tri_box_overlap(-extents,extents*2,vtxs))
+					continue;
+				//plot face
+				_plot_face(0,0,0,0,0,vtxs,uvs,material,p_baker->po2_bounds,p_baker);
+			}
+
+		}
+	}
+}
+
+
+
+void GIProbe::_find_meshes(Node *p_at_node,Baker *p_baker){
+
+	MeshInstance *mi = p_at_node->cast_to<MeshInstance>();
+	if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT)) {
+		Ref<Mesh> mesh = mi->get_mesh();
+		if (mesh.is_valid()) {
+
+			AABB aabb = mesh->get_aabb();
+
+			Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+			if (AABB(-extents,extents*2).intersects(xf.xform(aabb))) {
+				Baker::PlotMesh pm;
+				pm.local_xform=xf;
+				pm.mesh=mesh;
+				p_baker->mesh_list.push_back(pm);
+
+			}
+		}
+	}
+
+	for(int i=0;i<p_at_node->get_child_count();i++) {
+
+		Node *child = p_at_node->get_child(i);
+		if (!child->get_owner())
+			continue; //maybe a helper
+
+		_find_meshes(child,p_baker);
+
+	}
+}
+
+
+
+
+void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){
+
+	Baker baker;
+
+	static const int subdiv_value[SUBDIV_MAX]={7,8,9,10};
+
+	baker.cell_subdiv=subdiv_value[subdiv];
+	baker.bake_cells.resize(1);
+
+	//find out the actual real bounds, power of 2, which gets the highest subdivision
+	baker.po2_bounds=AABB(-extents,extents*2.0);
+	int longest_axis = baker.po2_bounds.get_longest_axis_index();
+	baker.axis_cell_size[longest_axis]=(1<<(baker.cell_subdiv-1));
+	baker.leaf_voxel_count=0;
+
+	for(int i=0;i<3;i++) {
+
+		if (i==longest_axis)
+			continue;
+
+		baker.axis_cell_size[i]=baker.axis_cell_size[longest_axis];
+		float axis_size = baker.po2_bounds.size[longest_axis];
+
+		//shrink until fit subdiv
+		while (axis_size/2.0 >= baker.po2_bounds.size[i]) {
+			axis_size/=2.0;
+			baker.axis_cell_size[i]>>=1;
+		}
+
+		baker.po2_bounds.size[i]=baker.po2_bounds.size[longest_axis];
+	}
+
+
+
+	Transform to_bounds;
+	to_bounds.basis.scale(Vector3(baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis]));
+	to_bounds.origin=baker.po2_bounds.pos;
+
+	Transform to_grid;
+	to_grid.basis.scale(Vector3(baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis]));
+
+	baker.to_cell_space = to_grid * to_bounds.affine_inverse();
+
+
+	_find_meshes(p_from_node?p_from_node:get_parent(),&baker);
+
+
+
+	int pmc=0;
+
+	for(List<Baker::PlotMesh>::Element *E=baker.mesh_list.front();E;E=E->next()) {
+
+		print_line("plotting mesh "+itos(pmc++)+"/"+itos(baker.mesh_list.size()));
+
+		_plot_mesh(E->get().local_xform,E->get().mesh,&baker);
+	}
+
+	_fixup_plot(0,0,0,0,0,&baker);
+
+	//create the data for visual server
+
+	DVector<int> data;
+
+	data.resize( 16+(8+1+1+1+1)*baker.bake_cells.size() ); //4 for header, rest for rest.
+
+	{
+		DVector<int>::Write w = data.write();
+
+		uint32_t * w32 = (uint32_t*)w.ptr();
+
+		w32[0]=0;//version
+		w32[1]=baker.cell_subdiv; //subdiv
+		w32[2]=baker.axis_cell_size[0];
+		w32[3]=baker.axis_cell_size[1];
+		w32[4]=baker.axis_cell_size[2];
+		w32[5]=baker.bake_cells.size();
+		w32[6]=baker.leaf_voxel_count;
+
+		int ofs=16;
+
+		for(int i=0;i<baker.bake_cells.size();i++) {
+
+			for(int j=0;j<8;j++) {
+				w32[ofs++]=baker.bake_cells[i].childs[j];
+			}
+
+			{ //albedo
+				uint32_t rgba=uint32_t(CLAMP(baker.bake_cells[i].albedo[0]*255.0,0,255))<<16;
+				rgba|=uint32_t(CLAMP(baker.bake_cells[i].albedo[1]*255.0,0,255))<<8;
+				rgba|=uint32_t(CLAMP(baker.bake_cells[i].albedo[2]*255.0,0,255))<<0;
+
+				w32[ofs++]=rgba;
+
+
+			}
+			{ //emission
+
+				Vector3 e(baker.bake_cells[i].emission[0],baker.bake_cells[i].emission[1],baker.bake_cells[i].emission[2]);
+				float l = e.length();
+				if (l>0) {
+					e.normalize();
+					l=CLAMP(l/8.0,0,1.0);
+				}
+
+				uint32_t em=uint32_t(CLAMP(e[0]*255,0,255))<<24;
+				em|=uint32_t(CLAMP(e[1]*255,0,255))<<16;
+				em|=uint32_t(CLAMP(e[2]*255,0,255))<<8;
+				em|=uint32_t(CLAMP(l*255,0,255));
+
+				w32[ofs++]=em;
+			}
+
+			w32[ofs++]=baker.bake_cells[i].used_sides;
+			w32[ofs++]=uint32_t(baker.bake_cells[i].alpha*65535.0);
+
+		}
+
+	}
+
+	Ref<GIProbeData> probe_data;
+	probe_data.instance();
+	probe_data->set_bounds(AABB(-extents,extents*2.0));
+	probe_data->set_cell_size(baker.po2_bounds.size[longest_axis]/baker.axis_cell_size[longest_axis]);
+	probe_data->set_dynamic_data(data);
+	probe_data->set_to_cell_xform(baker.to_cell_space);
+
+	set_probe_data(probe_data);
+
+
+	if (p_create_visual_debug) {
+	//	_create_debug_mesh(&baker);
+	}
+
+
+
+}
+
+
+void GIProbe::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref<MultiMesh> &p_multimesh,int &idx,Baker *p_baker) {
+
+
+	if (p_level==p_baker->cell_subdiv-1) {
+
+		Vector3 center = p_aabb.pos+p_aabb.size*0.5;
+		Transform xform;
+		xform.origin=center;
+		xform.basis.scale(p_aabb.size*0.5);
+		p_multimesh->set_instance_transform(idx,xform);
+		Color col=Color(p_baker->bake_cells[p_idx].albedo[0],p_baker->bake_cells[p_idx].albedo[1],p_baker->bake_cells[p_idx].albedo[2]);
+		p_multimesh->set_instance_color(idx,col);
+
+		idx++;
+
+	} else {
+
+		for(int i=0;i<8;i++) {
+
+			if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY)
+				continue;
+
+			AABB aabb=p_aabb;
+			aabb.size*=0.5;
+
+			if (i&1)
+				aabb.pos.x+=aabb.size.x;
+			if (i&2)
+				aabb.pos.y+=aabb.size.y;
+			if (i&4)
+				aabb.pos.z+=aabb.size.z;
+
+			_debug_mesh(p_baker->bake_cells[p_idx].childs[i],p_level+1,aabb,p_multimesh,idx,p_baker);
+		}
+
+	}
+
+}
+
+
+void GIProbe::_create_debug_mesh(Baker *p_baker) {
+
+	Ref<MultiMesh> mm;
+	mm.instance();
+
+	mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+	mm->set_color_format(MultiMesh::COLOR_8BIT);
+	print_line("leaf voxels: "+itos(p_baker->leaf_voxel_count));
+	mm->set_instance_count(p_baker->leaf_voxel_count);
+
+	Ref<Mesh> mesh;
+	mesh.instance();
+
+	{
+		Array arr;
+		arr.resize(Mesh::ARRAY_MAX);
+
+		DVector<Vector3> vertices;
+		DVector<Color> colors;
+
+		int vtx_idx=0;
+	#define ADD_VTX(m_idx);\
+		vertices.push_back( face_points[m_idx] );\
+		colors.push_back( Color(1,1,1,1) );\
+		vtx_idx++;\
+
+		for (int i=0;i<6;i++) {
+
+
+			Vector3 face_points[4];
+
+			for (int j=0;j<4;j++) {
+
+				float v[3];
+				v[0]=1.0;
+				v[1]=1-2*((j>>1)&1);
+				v[2]=v[1]*(1-2*(j&1));
+
+				for (int k=0;k<3;k++) {
+
+					if (i<3)
+						face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+					else
+						face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+				}
+			}
+
+		//tri 1
+			ADD_VTX(0);
+			ADD_VTX(1);
+			ADD_VTX(2);
+		//tri 2
+			ADD_VTX(2);
+			ADD_VTX(3);
+			ADD_VTX(0);
+
+		}
+
+
+		arr[Mesh::ARRAY_VERTEX]=vertices;
+		arr[Mesh::ARRAY_COLOR]=colors;
+		mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
+	}
+
+	{
+		Ref<FixedSpatialMaterial> fsm;
+		fsm.instance();
+		fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
+		fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
+		fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
+		fsm->set_albedo(Color(1,1,1,1));
+
+		mesh->surface_set_material(0,fsm);
+	}
+
+	mm->set_mesh(mesh);
+
+
+	int idx=0;
+	_debug_mesh(0,0,p_baker->po2_bounds,mm,idx,p_baker);
+
+	MultiMeshInstance *mmi = memnew( MultiMeshInstance );
+	mmi->set_multimesh(mm);
+	add_child(mmi);
+	if (get_tree()->get_edited_scene_root()==this){
+		mmi->set_owner(this);
+	} else {
+		mmi->set_owner(get_owner());
+
+	}
+
+}
+
+void GIProbe::_debug_bake() {
+
+	bake(NULL,true);
+}
+
+AABB GIProbe::get_aabb() const {
+
+	return AABB(-extents,extents*2);
+}
+
+DVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
+
+	return DVector<Face3>();
+}
+
+void GIProbe::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_probe_data","data"),&GIProbe::set_probe_data);
+	ObjectTypeDB::bind_method(_MD("get_probe_data"),&GIProbe::get_probe_data);
+
+	ObjectTypeDB::bind_method(_MD("set_subdiv","subdiv"),&GIProbe::set_subdiv);
+	ObjectTypeDB::bind_method(_MD("get_subdiv"),&GIProbe::get_subdiv);
+
+	ObjectTypeDB::bind_method(_MD("set_extents","extents"),&GIProbe::set_extents);
+	ObjectTypeDB::bind_method(_MD("get_extents"),&GIProbe::get_extents);
+
+	ObjectTypeDB::bind_method(_MD("set_dynamic_range","max"),&GIProbe::set_dynamic_range);
+	ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbe::get_dynamic_range);
+
+	ObjectTypeDB::bind_method(_MD("bake","from_node","create_visual_debug"),&GIProbe::bake,DEFVAL(Variant()),DEFVAL(false));
+	ObjectTypeDB::bind_method(_MD("debug_bake"),&GIProbe::_debug_bake);
+	ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+	ADD_PROPERTY( PropertyInfo(Variant::INT,"subdiv",PROPERTY_HINT_ENUM,"64,128,256,512"),_SCS("set_subdiv"),_SCS("get_subdiv"));
+	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"extents"),_SCS("set_extents"),_SCS("get_extents"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"dynamic_range",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range"));
+	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data"));
+
+
+	BIND_CONSTANT( SUBDIV_64 );
+	BIND_CONSTANT( SUBDIV_128 );
+	BIND_CONSTANT( SUBDIV_256 );
+	BIND_CONSTANT( SUBDIV_MAX );
+
+}
+
+GIProbe::GIProbe() {
+
+	subdiv=SUBDIV_128;
+	dynamic_range=1.0;
+	extents=Vector3(10,10,10);
+	color_scan_cell_width=4;
+	bake_texture_size=128;
+
+	gi_probe = VS::get_singleton()->gi_probe_create();
+
+
+}
+
+GIProbe::~GIProbe() {
+
+
+}

+ 174 - 0
scene/3d/gi_probe.h

@@ -0,0 +1,174 @@
+#ifndef GIPROBE_H
+#define GIPROBE_H
+
+#include "scene/3d/visual_instance.h"
+#include "multimesh_instance.h"
+
+class GIProbeData : public Resource {
+
+	OBJ_TYPE(GIProbeData,Resource);
+
+	RID probe;
+
+public:
+
+	enum DataFormat {
+		DATA_RGBA8,
+		DATA_DXT5,
+		DATA_ETC2_EAC,
+	};
+
+
+	void set_bounds(const AABB& p_bounds);
+	AABB get_bounds() const;
+
+	void set_cell_size(float p_size);
+	float get_cell_size() const;
+
+	void set_to_cell_xform(const Transform& p_xform);
+	Transform get_to_cell_xform() const;
+
+	void set_dynamic_data(const DVector<int>& p_data);
+	DVector<int> get_dynamic_data() const;
+
+	void set_dynamic_range(float p_range);
+	float get_dynamic_range() const;
+
+	void set_static_data(const DVector<uint8_t>& p_data,DataFormat p_format,int p_width,int p_height,int p_depth);
+	DVector<uint8_t> get_static_data() const;
+	DataFormat get_static_data_format() const;
+	int get_static_data_width() const;
+	int get_static_data_height() const;
+	int get_static_data_depth() const;
+
+	virtual RID get_rid() const;
+
+	GIProbeData();
+	~GIProbeData();
+};
+
+VARIANT_ENUM_CAST(GIProbeData::DataFormat);
+
+class GIProbe : public VisualInstance  {
+	OBJ_TYPE(GIProbe,VisualInstance);
+public:
+	enum Subdiv{
+		SUBDIV_64,
+		SUBDIV_128,
+		SUBDIV_256,
+		SUBDIV_512,
+		SUBDIV_MAX
+
+	};
+private:
+
+	//stuff used for bake
+	struct Baker {
+
+		enum {
+			CHILD_EMPTY=0xFFFFFFFF
+		};
+		struct Cell {
+
+			uint32_t childs[8];
+			float albedo[3]; //albedo in RGB24
+			float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+			uint32_t used_sides;
+			float alpha; //used for upsampling
+
+			Cell() {
+				for(int i=0;i<8;i++) {
+					childs[i]=CHILD_EMPTY;
+				}
+
+				for(int i=0;i<3;i++) {
+					emission[i]=0;
+					albedo[i]=0;
+				}
+				alpha=0;
+				used_sides=0;
+			}
+		};
+
+		Vector<Cell> bake_cells;
+		int cell_subdiv;
+
+		struct MaterialCache {
+			//128x128 textures
+			Vector<Color> albedo;
+			Vector<Color> emission;
+		};
+
+
+		Vector<Color> _get_bake_texture(Image &p_image, const Color &p_color);
+		Map<Ref<Material>,MaterialCache> material_cache;
+		MaterialCache _get_material_cache(Ref<Material> p_material);
+		int leaf_voxel_count;
+
+
+		AABB po2_bounds;
+		int axis_cell_size[3];
+
+		struct PlotMesh {
+			Ref<Mesh> mesh;
+			Transform local_xform;
+		};
+
+		Transform to_cell_space;
+
+		List<PlotMesh> mesh_list;
+	};
+
+
+	Ref<GIProbeData> probe_data;
+
+	RID gi_probe;
+
+	Subdiv subdiv;
+	Vector3 extents;
+	float dynamic_range;
+
+	int color_scan_cell_width;
+	int bake_texture_size;
+
+	Vector<Color> _get_bake_texture(Image &p_image,const Color& p_color);
+	Baker::MaterialCache _get_material_cache(Ref<Material> p_material,Baker *p_baker);
+	void _plot_face(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker);
+	void _plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker);
+	void _find_meshes(Node *p_at_node,Baker *p_baker);
+	void _fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker);
+
+	void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref<MultiMesh> &p_multimesh,int &idx,Baker *p_baker);
+	void _create_debug_mesh(Baker *p_baker);
+
+	void _debug_bake();
+
+protected:
+
+	static void _bind_methods();
+public:
+
+	void set_probe_data(const Ref<GIProbeData>& p_data);
+	Ref<GIProbeData> get_probe_data() const;
+
+	void set_subdiv(Subdiv p_subdiv);
+	Subdiv get_subdiv() const;
+
+	void set_extents(const Vector3& p_extents);
+	Vector3 get_extents() const;
+
+	void set_dynamic_range(float p_dynamic_range);
+	float get_dynamic_range() const;
+
+	void bake(Node *p_from_node=NULL,bool p_create_visual_debug=false);
+
+	virtual AABB get_aabb() const;
+	virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+	GIProbe();
+	~GIProbe();
+};
+
+VARIANT_ENUM_CAST(GIProbe::Subdiv)
+
+#endif // GIPROBE_H

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

@@ -30,7 +30,7 @@
 
 #include "globals.h"
 #include "scene/resources/surface_tool.h"
-
+#include "baked_light_instance.h"
 
 
 bool Light::_can_gizmo_scale() const {
@@ -168,9 +168,37 @@ void Light::_update_visibility() {
 
 void Light::_notification(int p_what) {
 
-	if (p_what==NOTIFICATION_ENTER_TREE || p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+	if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
 		_update_visibility();
+
+	}
+
+	if (p_what==NOTIFICATION_ENTER_TREE) {
+		_update_visibility();
+
+		Node *node = this;
+
+		while(node) {
+
+			baked_light=node->cast_to<BakedLight>();
+			if (baked_light) {
+				baked_light->lights.insert(this);
+				break;
+			}
+
+			node=node->get_parent();
+		}
 	}
+
+	if (p_what==NOTIFICATION_EXIT_TREE) {
+
+		if (baked_light) {
+			baked_light->lights.erase(this);
+		}
+	}
+
 }
 
 
@@ -247,6 +275,8 @@ Light::Light(VisualServer::LightType p_type) {
 	light=VisualServer::get_singleton()->light_create(p_type);
 	VS::get_singleton()->instance_set_base(get_instance(),light);
 
+	baked_light=NULL;
+
 	editor_only=false;
 	set_color(Color(1,1,1,1));
 	set_shadow(false);

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

@@ -37,6 +37,10 @@
 /**
 	@author Juan Linietsky <[email protected]>
 */
+
+
+class BakedLight;
+
 class Light : public VisualInstance {
 
 	OBJ_TYPE( Light, VisualInstance );
@@ -72,6 +76,8 @@ private:
 	VS::LightType type;
 	bool editor_only;
 	void _update_visibility();
+
+	BakedLight *baked_light;
 // bind helpers
 
 protected:

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

@@ -31,7 +31,6 @@
 #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 {
@@ -227,7 +226,6 @@ void GeometryInstance::_notification(int p_what) {
 
 		if (flags[FLAG_USE_BAKED_LIGHT]) {
 
-			_find_baked_light();
 		}
 
 		_update_visibility();
@@ -236,11 +234,6 @@ void GeometryInstance::_notification(int p_what) {
 
 		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();
 
 		}
 
@@ -252,37 +245,6 @@ void GeometryInstance::_notification(int p_what) {
 
 }
 
-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::_update_visibility() {
 
 	if (!is_inside_tree())
@@ -314,17 +276,6 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
 	}
 	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();
-			}
-		}*/
 	}
 }
 
@@ -357,17 +308,8 @@ GeometryInstance::ShadowCastingSetting GeometryInstance::get_cast_shadows_settin
 	return shadow_casting_setting;
 }
 
-void GeometryInstance::set_baked_light_texture_id(int p_id) {
 
-//	baked_light_texture_id=p_id;
-//	VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),baked_light_texture_id);
 
-}
-
-int GeometryInstance::get_baked_light_texture_id() const{
-
-	return baked_light_texture_id;
-}
 
 void GeometryInstance::set_extra_cull_margin(float p_margin) {
 
@@ -405,15 +347,11 @@ void GeometryInstance::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_lod_min_distance"), &GeometryInstance::get_lod_min_distance);
 
 
-	ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
-	ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
-
 	ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin);
 	ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
 
 	ObjectTypeDB::bind_method(_MD("get_aabb"),&GeometryInstance::get_aabb);
 
-	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"));
@@ -424,7 +362,6 @@ void GeometryInstance::_bind_methods() {
 	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_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_distance"), _SCS("get_lod_min_distance"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_hysteresis",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_hysteresis"), _SCS("get_lod_min_hysteresis"));
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/max_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_max_distance"), _SCS("get_lod_max_distance"));
@@ -461,8 +398,6 @@ GeometryInstance::GeometryInstance() {
 	flags[FLAG_CAST_SHADOW]=true;
 
 	shadow_casting_setting=SHADOW_CASTING_SETTING_ON;
-	baked_light_instance=NULL;
-	baked_light_texture_id=0;
 	extra_cull_margin=0;
 //	VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
 

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

@@ -79,7 +79,7 @@ public:
 
 };
 
-class BakedLightInstance;
+class BakedLight;
 
 class GeometryInstance : public VisualInstance {
 
@@ -114,12 +114,9 @@ private:
 	float lod_max_distance;
 	float lod_min_hysteresis;
 	float lod_max_hysteresis;
-	void _find_baked_light();
-	BakedLightInstance *baked_light_instance;
-	int baked_light_texture_id;
+
 	float extra_cull_margin;
 
-	void _baked_light_changed();
 	void _update_visibility();
 protected:
 
@@ -148,9 +145,6 @@ public:
 	void set_material_override(const Ref<Material>& p_material);
 	Ref<Material> get_material_override() const;
 
-	void set_baked_light_texture_id(int p_id);
-	int get_baked_light_texture_id() const;
-
 	void set_extra_cull_margin(float p_margin);
 	float get_extra_cull_margin() const;
 

+ 4 - 1
scene/register_scene_types.cpp

@@ -205,6 +205,7 @@
 #include "scene/3d/quad.h"
 #include "scene/3d/light.h"
 #include "scene/3d/reflection_probe.h"
+#include "scene/3d/gi_probe.h"
 #include "scene/3d/particles.h"
 #include "scene/3d/portal.h"
 #include "scene/resources/environment.h"
@@ -424,6 +425,8 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<OmniLight>();
 	ObjectTypeDB::register_type<SpotLight>();
 	ObjectTypeDB::register_type<ReflectionProbe>();
+	ObjectTypeDB::register_type<GIProbe>();
+	ObjectTypeDB::register_type<GIProbeData>();
 	ObjectTypeDB::register_type<AnimationTreePlayer>();
 	ObjectTypeDB::register_type<Portal>();
 	//ObjectTypeDB::register_type<Particles>();
@@ -455,7 +458,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<PathFollow>();
 	ObjectTypeDB::register_type<VisibilityNotifier>();
 	ObjectTypeDB::register_type<VisibilityEnabler>();
-	//ObjectTypeDB::register_type<BakedLightInstance>();
+	ObjectTypeDB::register_type<BakedLight>();
 	//ObjectTypeDB::register_type<BakedLightSampler>();
 	ObjectTypeDB::register_type<WorldEnvironment>();
 	ObjectTypeDB::register_type<RemoteTransform>();

+ 0 - 574
scene/resources/baked_light.cpp

@@ -29,577 +29,3 @@
 #include "baked_light.h"
 #include "servers/visual_server.h"
 
-#if 0
-
-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::set_light(const DVector<uint8_t>& p_light) {
-
-	VS::get_singleton()->baked_light_set_light(baked_light,p_light);
-}
-
-DVector<uint8_t> BakedLight::get_light() const {
-
-	return VS::get_singleton()->baked_light_get_light(baked_light);
-}
-
-
-void BakedLight::set_sampler_octree(const DVector<int>& p_sampler_octree) {
-
-	VS::get_singleton()->baked_light_set_sampler_octree(baked_light,p_sampler_octree);
-}
-
-DVector<int> BakedLight::get_sampler_octree() const {
-
-	return VS::get_singleton()->baked_light_get_sampler_octree(baked_light);
-}
-
-
-
-
-
-void BakedLight::add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size) {
-
-	LightMap lm;
-	lm.texture=p_texture;
-	lm.gen_size=p_gen_size;
-	lightmaps.push_back(lm);
-	_update_lightmaps();
-	_change_notify();
-}
-
-void BakedLight::set_lightmap_gen_size(int p_idx,const Size2& p_size){
-
-	ERR_FAIL_INDEX(p_idx,lightmaps.size());
-	lightmaps[p_idx].gen_size=p_size;
-	_update_lightmaps();
-}
-Size2 BakedLight::get_lightmap_gen_size(int p_idx) const{
-
-	ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Size2());
-	return lightmaps[p_idx].gen_size;
-
-}
-void BakedLight::set_lightmap_texture(int p_idx,const Ref<Texture> &p_texture){
-
-	ERR_FAIL_INDEX(p_idx,lightmaps.size());
-	lightmaps[p_idx].texture=p_texture;
-	_update_lightmaps();
-
-}
-Ref<Texture> BakedLight::get_lightmap_texture(int p_idx) const{
-
-	ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Ref<Texture>());
-	return lightmaps[p_idx].texture;
-
-}
-void BakedLight::erase_lightmap(int p_idx){
-
-	ERR_FAIL_INDEX(p_idx,lightmaps.size());
-	lightmaps.remove(p_idx);
-	_update_lightmaps();
-	_change_notify();
-
-}
-int  BakedLight::get_lightmaps_count() const{
-
-	return lightmaps.size();
-}
-void BakedLight::clear_lightmaps(){
-
-	lightmaps.clear();
-	_update_lightmaps();
-	_change_notify();
-}
-
-
-
-void BakedLight::_update_lightmaps() {
-
-	VS::get_singleton()->baked_light_clear_lightmaps(baked_light);
-	for(int i=0;i<lightmaps.size();i++) {
-
-		RID tid;
-		if (lightmaps[i].texture.is_valid())
-			tid=lightmaps[i].texture->get_rid();
-		VS::get_singleton()->baked_light_add_lightmap(baked_light,tid,i);
-	}
-}
-
-
-
-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(int i=0;i<lightmaps.size();i++) {
-
-		ret[idx++]=Size2(lightmaps[i].gen_size);
-		ret[idx++]=lightmaps[i].texture;
-	}
-	return ret;
-
-}
-
-void BakedLight::_set_lightmap_data(Array p_array){
-
-	lightmaps.clear();
-	for(int i=0;i<p_array.size();i+=2) {
-
-		Size2 size = p_array[i];
-		Ref<Texture> tex = p_array[i+1];
-//		ERR_CONTINUE(tex.is_null());
-		LightMap lm;
-		lm.gen_size=size;
-		lm.texture=tex;
-		lightmaps.push_back(lm);
-	}
-	_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_tint(float p_margin) {
-	tint=p_margin;
-}
-
-float BakedLight::get_tint() const {
-
-	return tint;
-}
-
-void BakedLight::set_saturation(float p_margin) {
-	saturation=p_margin;
-}
-
-float BakedLight::get_saturation() const {
-
-	return saturation;
-}
-
-void BakedLight::set_ao_radius(float p_ao_radius) {
-	ao_radius=p_ao_radius;
-}
-
-float BakedLight::get_ao_radius() const {
-	return ao_radius;
-}
-
-void BakedLight::set_ao_strength(float p_ao_strength) {
-
-	ao_strength=p_ao_strength;
-}
-
-float BakedLight::get_ao_strength() const {
-
-	return ao_strength;
-}
-
-void BakedLight::set_realtime_color_enabled(const bool p_realtime_color_enabled) {
-
-	VS::get_singleton()->baked_light_set_realtime_color_enabled(baked_light, p_realtime_color_enabled);
-}
-
-bool BakedLight::get_realtime_color_enabled() const {
-
-	return VS::get_singleton()->baked_light_get_realtime_color_enabled(baked_light);
-}
-
-
-void BakedLight::set_realtime_color(const Color &p_realtime_color) {
-
-	VS::get_singleton()->baked_light_set_realtime_color(baked_light, p_realtime_color);
-}
-
-Color BakedLight::get_realtime_color() const {
-
-	return VS::get_singleton()->baked_light_get_realtime_color(baked_light);
-}
-
-void BakedLight::set_realtime_energy(const float p_realtime_energy) {
-
-	VS::get_singleton()->baked_light_set_realtime_energy(baked_light, p_realtime_energy);
-}
-
-float BakedLight::get_realtime_energy() const {
-
-	return VS::get_singleton()->baked_light_get_realtime_energy(baked_light);
-}
-
-
-
-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::set_format(Format p_format) {
-
-	format=p_format;
-	VS::get_singleton()->baked_light_set_lightmap_multiplier(baked_light,format==FORMAT_HDR8?8.0:1.0);
-}
-
-BakedLight::Format BakedLight::get_format() const{
-
-	return format;
-}
-
-void BakedLight::set_transfer_lightmaps_only_to_uv2(bool p_enable) {
-
-	transfer_only_uv2=p_enable;
-}
-
-bool BakedLight::get_transfer_lightmaps_only_to_uv2() const{
-
-	return transfer_only_uv2;
-}
-
-
-bool BakedLight::_set(const StringName& p_name, const Variant& p_value) {
-
-	String n = p_name;
-	if (!n.begins_with("lightmap"))
-		return false;
-	int idx = n.get_slicec('/',1).to_int();
-	ERR_FAIL_COND_V(idx<0,false);
-	ERR_FAIL_COND_V(idx>lightmaps.size(),false);
-
-	String what = n.get_slicec('/',2);
-	Ref<Texture> tex;
-	Size2 gens;
-
-	if (what=="texture")
-		tex=p_value;
-	else if (what=="gen_size")
-		gens=p_value;
-
-	if (idx==lightmaps.size()) {
-		if (tex.is_valid() || gens!=Size2())
-			add_lightmap(tex,gens);
-	} else {
-		if (tex.is_valid())
-			set_lightmap_texture(idx,tex);
-		else if (gens!=Size2())
-			set_lightmap_gen_size(idx,gens);
-	}
-
-
-	return true;
-}
-
-bool BakedLight::_get(const StringName& p_name,Variant &r_ret) const{
-
-	String n = p_name;
-	if (!n.begins_with("lightmap"))
-		return false;
-	int idx = n.get_slicec('/',1).to_int();
-	ERR_FAIL_COND_V(idx<0,false);
-	ERR_FAIL_COND_V(idx>lightmaps.size(),false);
-
-	String what = n.get_slicec('/',2);
-
-	if (what=="texture") {
-		if (idx==lightmaps.size())
-			r_ret=Ref<Texture>();
-		else
-			r_ret=lightmaps[idx].texture;
-
-	} else if (what=="gen_size") {
-
-		if (idx==lightmaps.size())
-			r_ret=Size2();
-		else
-			r_ret=Size2(lightmaps[idx].gen_size);
-	} else
-		return false;
-
-	return true;
-
-
-}
-void BakedLight::_get_property_list( List<PropertyInfo> *p_list) const{
-
-	for(int i=0;i<=lightmaps.size();i++) {
-
-		p_list->push_back(PropertyInfo(Variant::VECTOR2,"lightmaps/"+itos(i)+"/gen_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR));
-		p_list->push_back(PropertyInfo(Variant::OBJECT,"lightmaps/"+itos(i)+"/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture",PROPERTY_USAGE_EDITOR));
-	}
-}
-
-
-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("set_light","light"),&BakedLight::set_light);
-	ObjectTypeDB::bind_method(_MD("get_light"),&BakedLight::get_light);
-
-	ObjectTypeDB::bind_method(_MD("set_sampler_octree","sampler_octree"),&BakedLight::set_sampler_octree);
-	ObjectTypeDB::bind_method(_MD("get_sampler_octree"),&BakedLight::get_sampler_octree);
-
-
-	ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","gen_size"),&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_tint","tint"),&BakedLight::set_tint);
-	ObjectTypeDB::bind_method(_MD("get_tint"),&BakedLight::get_tint);
-
-	ObjectTypeDB::bind_method(_MD("set_saturation","saturation"),&BakedLight::set_saturation);
-	ObjectTypeDB::bind_method(_MD("get_saturation"),&BakedLight::get_saturation);
-
-	ObjectTypeDB::bind_method(_MD("set_ao_radius","ao_radius"),&BakedLight::set_ao_radius);
-	ObjectTypeDB::bind_method(_MD("get_ao_radius"),&BakedLight::get_ao_radius);
-
-	ObjectTypeDB::bind_method(_MD("set_ao_strength","ao_strength"),&BakedLight::set_ao_strength);
-	ObjectTypeDB::bind_method(_MD("get_ao_strength"),&BakedLight::get_ao_strength);
-
-	ObjectTypeDB::bind_method(_MD("set_realtime_color_enabled", "enabled"), &BakedLight::set_realtime_color_enabled);
-	ObjectTypeDB::bind_method(_MD("get_realtime_color_enabled"), &BakedLight::get_realtime_color_enabled);
-
-	ObjectTypeDB::bind_method(_MD("set_realtime_color", "tint"), &BakedLight::set_realtime_color);
-	ObjectTypeDB::bind_method(_MD("get_realtime_color"), &BakedLight::get_realtime_color);
-
-	ObjectTypeDB::bind_method(_MD("set_realtime_energy", "energy"), &BakedLight::set_realtime_energy);
-	ObjectTypeDB::bind_method(_MD("get_realtime_energy"), &BakedLight::get_realtime_energy);
-
-	ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format);
-	ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format);
-
-	ObjectTypeDB::bind_method(_MD("set_transfer_lightmaps_only_to_uv2","enable"),&BakedLight::set_transfer_lightmaps_only_to_uv2);
-	ObjectTypeDB::bind_method(_MD("get_transfer_lightmaps_only_to_uv2"),&BakedLight::get_transfer_lightmaps_only_to_uv2);
-
-
-
-
-	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/format",PROPERTY_HINT_ENUM,"RGB,HDR8,HDR16"),_SCS("set_format"),_SCS("get_format"));
-	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_PROPERTY( PropertyInfo(Variant::REAL,"baking/saturation",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_saturation"),_SCS("get_saturation"));
-	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_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/linear_color"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_LINEAR_COLOR);
-	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2"));
-
-	ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree"));
-	ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"light",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_light"),_SCS("get_light"));
-	ADD_PROPERTY( PropertyInfo(Variant::INT_ARRAY,"sampler_octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_sampler_octree"),_SCS("get_sampler_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"));
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/light_tint",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_tint"),_SCS("get_tint"));
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_radius",PROPERTY_HINT_RANGE,"0.0,16.0,0.01"),_SCS("set_ao_radius"),_SCS("get_ao_radius"));
-	ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_strength",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_ao_strength"),_SCS("get_ao_strength"));
-
-	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "realtime/enabled"), _SCS("set_realtime_color_enabled"), _SCS("get_realtime_color_enabled"));
-	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "realtime/color", PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_realtime_color"), _SCS("get_realtime_color"));
-	ADD_PROPERTY(PropertyInfo(Variant::REAL, "realtime/energy", PROPERTY_HINT_RANGE, "0.01,4096.0,0.01"), _SCS("set_realtime_energy"), _SCS("get_realtime_energy"));
-
-
-	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=2.0;
-	gamma_adjust=0.7;
-	cell_extra_margin=0.05;
-	edge_damp=0.0;
-	normal_damp=0.0;
-	saturation=1;
-	tint=0.0;
-	ao_radius=2.5;
-	ao_strength=0.7;
-	format=FORMAT_RGB8;
-	transfer_only_uv2=false;
-
-
-	flags[BAKE_DIFFUSE]=true;
-	flags[BAKE_SPECULAR]=false;
-	flags[BAKE_TRANSLUCENT]=true;
-	flags[BAKE_CONSERVE_ENERGY]=false;
-	flags[BAKE_LINEAR_COLOR]=false;
-
-	mode=MODE_OCTREE;
-	baked_light=VS::get_singleton()->baked_light_create();
-}
-
-BakedLight::~BakedLight() {
-
-	VS::get_singleton()->free(baked_light);
-}
-#endif

+ 0 - 163
scene/resources/baked_light.h

@@ -32,169 +32,6 @@
 #include "resource.h"
 #include "scene/resources/texture.h"
 
-#if 0
-class BakedLight : public Resource {
 
-	OBJ_TYPE( BakedLight, Resource);
-public:
-	enum Mode {
 
-		MODE_OCTREE,
-		MODE_LIGHTMAPS
-	};
-
-	enum Format {
-
-		FORMAT_RGB8,
-		FORMAT_HDR8,
-		FORMAT_HDR16
-	};
-
-	enum BakeFlags {
-		BAKE_DIFFUSE,
-		BAKE_SPECULAR,
-		BAKE_TRANSLUCENT,
-		BAKE_CONSERVE_ENERGY,
-		BAKE_LINEAR_COLOR,
-		BAKE_MAX
-	};
-
-private:
-
-	RID baked_light;
-	Mode mode;
-	struct LightMap {
-		Size2i gen_size;
-		Ref<Texture> texture;
-	};
-
-
-	Vector< LightMap> 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;
-	float tint;
-	float ao_radius;
-	float ao_strength;
-	float saturation;
-	int bounces;
-	bool transfer_only_uv2;
-	Format format;
-	bool flags[BAKE_MAX];
-
-
-
-	void _update_lightmaps();
-
-	Array _get_lightmap_data() const;
-	void _set_lightmap_data(Array p_array);
-
-protected:
-
-	bool _set(const StringName& p_name, const Variant& p_value);
-	bool _get(const StringName& p_name,Variant &r_ret) const;
-	void _get_property_list( List<PropertyInfo> *p_list) const;
-
-	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_tint(float p_margin);
-	float get_tint() const;
-
-	void set_saturation(float p_saturation);
-	float get_saturation() const;
-
-	void set_ao_radius(float p_ao_radius);
-	float get_ao_radius() const;
-
-	void set_ao_strength(float p_ao_strength);
-	float get_ao_strength() const;
-
-	void set_realtime_color_enabled(const bool p_enabled);
-	bool get_realtime_color_enabled() const;
-
-	void set_realtime_color(const Color& p_realtime_color);
-	Color get_realtime_color() const;
-
-	void set_realtime_energy(const float p_realtime_energy);
-	float get_realtime_energy() const;
-
-	void set_bake_flag(BakeFlags p_flags,bool p_enable);
-	bool get_bake_flag(BakeFlags p_flags) const;
-
-	void set_format(Format p_margin);
-	Format get_format() const;
-
-	void set_transfer_lightmaps_only_to_uv2(bool p_enable);
-	bool get_transfer_lightmaps_only_to_uv2() 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 set_light(const DVector<uint8_t>& p_light);
-	DVector<uint8_t> get_light() const;
-
-	void set_sampler_octree(const DVector<int>& p_sampler_octree);
-	DVector<int> get_sampler_octree() const;
-
-
-
-	void add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size=Size2(256,256));
-	void set_lightmap_gen_size(int p_idx,const Size2& p_size);
-	Size2 get_lightmap_gen_size(int p_idx) const;
-	void set_lightmap_texture(int p_idx,const Ref<Texture> &p_texture);
-	Ref<Texture> get_lightmap_texture(int p_idx) const;
-	void erase_lightmap(int p_idx);
-	int  get_lightmaps_count() const;
-	void clear_lightmaps();
-
-	virtual RID get_rid() const;
-
-	BakedLight();
-	~BakedLight();
-};
-
-
-VARIANT_ENUM_CAST(BakedLight::Format);
-VARIANT_ENUM_CAST(BakedLight::Mode);
-VARIANT_ENUM_CAST(BakedLight::BakeFlags);
-#endif
 #endif // BAKED_LIGHT_H

+ 44 - 1
servers/visual/rasterizer.h

@@ -91,6 +91,7 @@ public:
 		Vector<RID> materials;
 		Vector<RID> light_instances;
 		Vector<RID> reflection_probe_instances;
+		Vector<RID> gi_probe_instances;
 
 		Vector<float> morph_values;
 
@@ -108,12 +109,14 @@ public:
 		float depth; //used for sorting
 
 		SelfList<InstanceBase> dependency_item;
+		InstanceBase *baked_light; //baked light to use
+		SelfList<InstanceBase> baked_light_item;
 
 		virtual void base_removed()=0;
 		virtual void base_changed()=0;
 		virtual void base_material_changed()=0;
 
-		InstanceBase() : dependency_item(this) {
+		InstanceBase() : dependency_item(this), baked_light_item(this) {
 
 			base_type=VS::INSTANCE_NONE;
 			cast_shadows=VS::SHADOW_CASTING_SETTING_ON;
@@ -123,6 +126,7 @@ public:
 			billboard_y=false;
 			depth_layer=0;
 			layer_mask=1;
+			baked_light=NULL;
 
 		}
 	};
@@ -144,6 +148,11 @@ public:
 	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas)=0;
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance)=0;
 
+	virtual RID gi_probe_instance_create()=0;
+	virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data)=0;
+	virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform)=0;
+	virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds)=0;
+
 	virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass)=0;
 	virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count)=0;
 
@@ -340,6 +349,7 @@ public:
 	virtual VS::LightType light_get_type(RID p_light) const=0;
 	virtual AABB light_get_aabb(RID p_light) const=0;
 	virtual float light_get_param(RID p_light,VS::LightParam p_param)=0;
+	virtual Color light_get_color(RID p_light)=0;
 	virtual uint64_t light_get_version(RID p_light) const=0;
 
 
@@ -392,6 +402,39 @@ public:
 	virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
 	virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
 
+	/* GI PROBE API */
+
+	virtual RID gi_probe_create()=0;
+
+	virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds)=0;
+	virtual AABB gi_probe_get_bounds(RID p_probe) const=0;
+
+	virtual void gi_probe_set_cell_size(RID p_probe,float p_range)=0;
+	virtual float gi_probe_get_cell_size(RID p_probe) const=0;
+
+	virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform)=0;
+	virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const=0;
+
+	virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data)=0;
+	virtual DVector<int> gi_probe_get_dynamic_data(RID p_probe) const=0;
+
+	virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0;
+	virtual float gi_probe_get_dynamic_range(RID p_probe) const=0;
+
+
+	virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0;
+	virtual DVector<uint8_t> gi_probe_get_static_data(RID p_gi_probe) const=0;
+	virtual  VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0;
+	virtual int gi_probe_get_static_data_width(RID p_probe) const=0;
+	virtual int gi_probe_get_static_data_height(RID p_probe) const=0;
+	virtual int gi_probe_get_static_data_depth(RID p_probe) const=0;
+
+	virtual RID gi_probe_get_data(RID p_probe)=0; //get data in case this is static
+	virtual uint32_t gi_probe_get_version(RID p_probe)=0;
+
+	virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth)=0;
+	virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0;
+
 	/* RENDER TARGET */
 
 	enum RenderTargetFlags {

+ 6 - 0
servers/visual/visual_server_light_baker.cpp

@@ -0,0 +1,6 @@
+#include "visual_server_light_baker.h"
+
+VisualServerLightBaker::VisualServerLightBaker()
+{
+
+}

+ 29 - 0
servers/visual/visual_server_light_baker.h

@@ -0,0 +1,29 @@
+#ifndef VISUALSERVERLIGHTBAKER_H
+#define VISUALSERVERLIGHTBAKER_H
+
+#include "servers/visual_server.h"
+
+class VisualServerLightBaker {
+public:
+
+	struct BakeCell {
+
+		uint32_t cells[8];
+		uint32_t neighbours[7]; //one unused
+		uint32_t albedo; //albedo in RGBE
+		uint32_t emission; //emissive light in RGBE
+		uint32_t light[4]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+		float alpha; //used for upsampling
+		uint32_t directional_pass; //used for baking directional
+
+	};
+
+
+
+
+
+
+	VisualServerLightBaker();
+};
+
+#endif // VISUALSERVERLIGHTBAKER_H

+ 2 - 1
servers/visual/visual_server_raster.cpp

@@ -90,9 +90,10 @@ void VisualServerRaster::draw(){
 
 	changes=0;
 
+	VSG::rasterizer->begin_frame();
+
 	VSG::scene->update_dirty_instances(); //update scene stuff
 
-	VSG::rasterizer->begin_frame();
 	VSG::viewport->draw_viewports();
 	VSG::scene->render_probes();
 	//_draw_cursors_and_margins();

+ 28 - 2
servers/visual/visual_server_raster.h

@@ -803,12 +803,39 @@ public:
 	BIND2(portal_set_disable_distance,RID , float )
 	BIND2(portal_set_disabled_color,RID , const Color& )
 
-	/* CAMERA API */
+	/* BAKED LIGHT API */
+
+	BIND0R(RID, gi_probe_create)
+
+	BIND2(gi_probe_set_bounds,RID,const AABB&)
+	BIND1RC(AABB,gi_probe_get_bounds,RID)
+
+	BIND2(gi_probe_set_cell_size,RID,float)
+	BIND1RC(float,gi_probe_get_cell_size,RID)
+
+	BIND2(gi_probe_set_to_cell_xform,RID,const Transform&)
+	BIND1RC(Transform,gi_probe_get_to_cell_xform,RID)
+
+	BIND2(gi_probe_set_dynamic_range,RID,float)
+	BIND1RC(float,gi_probe_get_dynamic_range,RID)
+
+	BIND2(gi_probe_set_dynamic_data,RID,const DVector<int>& )
+	BIND1RC( DVector<int>,gi_probe_get_dynamic_data,RID)
+
+	BIND6(gi_probe_set_static_data,RID,const DVector<uint8_t>&,GIProbeDataFormat,int,int,int)
+	BIND1RC(DVector<uint8_t>,gi_probe_get_static_data,RID)
+	BIND1RC(GIProbeDataFormat,gi_probe_get_static_data_format,RID)
+	BIND1RC(int,gi_probe_get_static_data_width,RID)
+	BIND1RC(int,gi_probe_get_static_data_height,RID)
+	BIND1RC(int,gi_probe_get_static_data_depth,RID)
+
 
 #undef BINDBASE
 //from now on, calls forwarded to this singleton
 #define BINDBASE VSG::scene
 
+	/* CAMERA API */
+
 
 	BIND0R(RID, camera_create)
 	BIND4(camera_set_perspective,RID,float, float , float )
@@ -936,7 +963,6 @@ public:
 	BIND5(instance_geometry_set_draw_range,RID,float ,float ,float ,float )
 	BIND2(instance_geometry_set_as_instance_lod,RID,RID )
 
-
 #undef BINDBASE
 //from now on, calls forwarded to this singleton
 #define BINDBASE VSG::canvas

Разлика између датотеке није приказан због своје велике величине
+ 783 - 60
servers/visual/visual_server_scene.cpp


+ 160 - 2
servers/visual/visual_server_scene.h

@@ -7,6 +7,9 @@
 #include "allocators.h"
 #include "octree.h"
 #include "self_list.h"
+#include "os/thread.h"
+#include "os/semaphore.h"
+#include "semaphore.h"
 
 class VisualServerScene {
 public:
@@ -69,6 +72,8 @@ public:
 #endif
 
 
+	/* CAMERA API */
+
 	struct Camera  : public RID_Data {
 
 		enum Type {
@@ -141,6 +146,7 @@ public:
 */
 
 
+
 	/* SCENARIO API */
 
 	struct Instance;
@@ -296,11 +302,15 @@ public:
 		List<Instance*> reflection_probes;
 		bool reflection_dirty;
 
+		List<Instance*> gi_probes;
+		bool gi_probes_dirty;
+
 		InstanceGeometryData() {
 
 			lighting_dirty=false;
 			reflection_dirty=true;
 			can_cast_shadows=true;
+			gi_probes_dirty=true;
 		}
 	};
 
@@ -310,7 +320,7 @@ public:
 		Instance *owner;
 
 		struct PairInfo {
-			List<Instance*>::Element *L; //light iterator in geometry
+			List<Instance*>::Element *L; //reflection iterator in geometry
 			Instance *geometry;
 		};
 		List<PairInfo> geometries;
@@ -346,14 +356,112 @@ public:
 
 		List<PairInfo> geometries;
 
+		Instance *baked_light;
+
 		InstanceLightData() {
 
 			shadow_dirty=true;
 			D=NULL;
 			last_version=0;
+			baked_light=NULL;
 		}
 	};
 
+	struct InstanceGIProbeData : public InstanceBaseData {
+
+
+		Instance *owner;
+
+		struct PairInfo {
+			List<Instance*>::Element *L; //gi probe iterator in geometry
+			Instance *geometry;
+		};
+
+		List<PairInfo> geometries;
+
+		Set<Instance*> lights;
+
+		struct LightCache {
+
+			VS::LightType type;
+			Transform transform;
+			Color color;
+			float energy;
+			float radius;
+			float attenuation;
+			float spot_angle;
+			float spot_attenuation;
+
+			bool operator==(const LightCache& p_cache) {
+
+				return	(type==p_cache.type &&
+					 transform==p_cache.transform &&
+					 color==p_cache.color &&
+					 energy==p_cache.energy &&
+					 radius==p_cache.radius &&
+					 attenuation==p_cache.attenuation &&
+					 spot_angle==p_cache.spot_angle &&
+					 spot_attenuation==p_cache.spot_attenuation);
+			}
+
+			LightCache() {
+
+				type=VS::LIGHT_DIRECTIONAL;
+				energy=1.0;
+				radius=1.0;
+				attenuation=1.0;
+				spot_angle=1.0;
+				spot_attenuation=1.0;
+
+			}
+
+		};
+
+		struct LocalData {
+			uint16_t pos[3];
+			uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights
+		};
+
+
+		struct Dynamic {
+
+			Map<RID,LightCache> light_cache;
+			Map<RID,LightCache> light_cache_changes;
+			DVector<int> light_data;
+			DVector<LocalData> local_data;
+			Vector<Vector<uint32_t> > level_cell_lists;
+			RID probe_data;
+			bool enabled;
+
+			Vector< DVector<uint8_t> > mipmaps_3d;
+
+			int updating_stage;
+
+			int grid_size[3];
+
+			Transform light_to_cell_xform;
+
+		} dynamic;
+
+
+		RID probe_instance;
+
+
+		bool invalid;
+		uint32_t base_version;
+
+		SelfList<InstanceGIProbeData> update_element;
+
+		InstanceGIProbeData() : update_element(this) {
+			invalid=true;
+			base_version=0;
+		}
+
+	};
+
+
+	SelfList<InstanceGIProbeData>::List gi_probe_update_list;
+
 
 	Instance *instance_cull_result[MAX_INSTANCE_CULL];
 	Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
@@ -410,11 +518,61 @@ public:
 	void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas);	
 	void update_dirty_instances();
 
-	bool _render_probe_step(Instance* p_instance,int p_step);
+	//probes
+	struct GIProbeDataHeader {
+
+		uint32_t version;
+		uint32_t cell_subdiv;
+		uint32_t width;
+		uint32_t height;
+		uint32_t depth;
+		uint32_t cell_count;
+		uint32_t leaf_cell_count;
+	};
+
+
+	struct GIProbeDataCell {
+
+		uint32_t children[8];
+		uint32_t albedo;
+		uint32_t emission;
+		uint32_t sides_used;
+		uint32_t alpha;
+	};
+
+	enum {
+		GI_UPDATE_STAGE_CHECK,
+		GI_UPDATE_STAGE_LIGHTING,
+		GI_UPDATE_STAGE_UPLOADING,
+	};
+
+	void _gi_probe_bake_thread();
+	static void _gi_probe_bake_threads(void*);
+
+	volatile bool probe_bake_thread_exit;
+	Thread *probe_bake_thread;
+	Semaphore *probe_bake_sem;
+	Mutex *probe_bake_mutex;
+	List<Instance*> probe_bake_list;
+
+	bool _render_reflection_probe_step(Instance* p_instance,int p_step);
+	void _gi_probe_fill_local_data(int p_idx,int p_level,int p_x,int p_y,int p_z,const GIProbeDataCell* p_cell,const GIProbeDataHeader *p_header,InstanceGIProbeData::LocalData *p_local_data,Vector<uint32_t> *prev_cell);
+
+	_FORCE_INLINE_ uint32_t _gi_bake_find_cell(const GIProbeDataCell *cells,int x,int y, int z,int p_cell_subdiv);
+	void _bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell* p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data);
+
+	void _bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int p_leaf_count, const InstanceGIProbeData::LightCache& light_cache,int p_sign);
+	void _bake_gi_probe(Instance *p_probe);
+	bool _check_gi_probe(Instance *p_gi_probe);
+	void _setup_gi_probe(Instance *p_instance);
+
 	void render_probes();
+
+
 	bool free(RID p_rid);
 
 	VisualServerScene();
+	~VisualServerScene();
 };
 
 #endif // VISUALSERVERSCENE_H

+ 35 - 3
servers/visual_server.h

@@ -445,7 +445,39 @@ public:
 	virtual void portal_set_disable_distance(RID p_portal, float p_distance)=0;
 	virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=0;
 
-	/* BAKED LIGHT API */
+	/* GI PROBE API */
+
+	virtual RID gi_probe_create()=0;
+
+	virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds)=0;
+	virtual AABB gi_probe_get_bounds(RID p_probe) const=0;
+
+	virtual void gi_probe_set_cell_size(RID p_probe,float p_range)=0;
+	virtual float gi_probe_get_cell_size(RID p_probe) const=0;
+
+	virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform)=0;
+	virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const=0;
+
+	virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data)=0;
+	virtual DVector<int> gi_probe_get_dynamic_data(RID p_probe) const=0;
+
+	virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0;
+	virtual float gi_probe_get_dynamic_range(RID p_probe) const=0;
+
+	enum GIProbeDataFormat {
+		GI_PROBE_DATA_RGBA8,
+		GI_PROBE_DATA_DXT5,
+		GI_PROBE_DATA_ETC2_EAC,
+	};
+
+	virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0;
+	virtual DVector<uint8_t> gi_probe_get_static_data(RID p_gi_probe) const=0;
+	virtual  GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0;
+	virtual int gi_probe_get_static_data_width(RID p_probe) const=0;
+	virtual int gi_probe_get_static_data_height(RID p_probe) const=0;
+	virtual int gi_probe_get_static_data_depth(RID p_probe) const=0;
+
+
 
 	/* CAMERA API */
 
@@ -600,9 +632,9 @@ public:
 		INSTANCE_REFLECTION_PROBE,
 		INSTANCE_ROOM,
 		INSTANCE_PORTAL,
+		INSTANCE_GI_PROBE,
 		INSTANCE_MAX,
-		/*INSTANCE_BAKED_LIGHT,
-		INSTANCE_BAKED_LIGHT_SAMPLER,*/
+		/*INSTANCE_BAKED_LIGHT_SAMPLER,*/
 
 		INSTANCE_GEOMETRY_MASK=(1<<INSTANCE_MESH)|(1<<INSTANCE_MULTIMESH)|(1<<INSTANCE_IMMEDIATE)
 	};

+ 13 - 4
tools/editor/io_plugins/editor_import_collada.cpp

@@ -394,7 +394,8 @@ Error ColladaImport::_create_material(const String& p_target) {
 			Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
 			if (texture.is_valid()) {
 
-//				material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,texture);
+				material->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,texture);
+				material->set_albedo(Color(1,1,1,1));
 //				material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1));
 			} else {
 				missing_textures.push_back(texfile.get_file());
@@ -413,6 +414,8 @@ Error ColladaImport::_create_material(const String& p_target) {
 
 			Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
 			if (texture.is_valid()) {
+				material->set_texture(FixedSpatialMaterial::TEXTURE_SPECULAR,texture);
+				material->set_specular(Color(1,1,1,1));
 
 //				material->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,texture);
 //				material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1));
@@ -435,7 +438,9 @@ Error ColladaImport::_create_material(const String& p_target) {
 			Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
 			if (texture.is_valid()) {
 
-//				material->set_texture(FixedSpatialMaterial::PARAM_EMISSION,texture);
+				material->set_texture(FixedSpatialMaterial::TEXTURE_EMISSION,texture);
+				material->set_emission(Color(1,1,1,1));
+
 //				material->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,Color(1,1,1,1));
 			}else {
 //				missing_textures.push_back(texfile.get_file());
@@ -455,6 +460,8 @@ Error ColladaImport::_create_material(const String& p_target) {
 
 			Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
 			if (texture.is_valid()) {
+				material->set_texture(FixedSpatialMaterial::TEXTURE_NORMAL,texture);
+//				material->set_emission(Color(1,1,1,1));
 
 	//			material->set_texture(FixedSpatialMaterial::PARAM_NORMAL,texture);
 			}else {
@@ -466,8 +473,10 @@ Error ColladaImport::_create_material(const String& p_target) {
 
 
 //	material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR_EXP,effect.shininess);
-//	material->set_flag(Material::FLAG_DOUBLE_SIDED,effect.double_sided);
-//	material->set_flag(Material::FLAG_UNSHADED,effect.unshaded);
+	if (effect.double_sided) {
+		material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
+	}
+	material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,effect.unshaded);
 
 
 

+ 1 - 1
tools/editor/io_plugins/editor_scene_import_plugin.cpp

@@ -1692,7 +1692,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 
 		String str=name;
 		int layer = str.substr(str.find("lm")+3,str.length()).to_int();
-		mi->set_baked_light_texture_id(layer);
+		//mi->set_baked_light_texture_id(layer);
 	}
 
 	if (p_flags&SCENE_FLAG_CREATE_COLLISIONS && _teststr(name,"colonly")) {

+ 167 - 3
tools/editor/spatial_editor_gizmos.cpp

@@ -2397,6 +2397,163 @@ ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe* p_probe){
 
 
 
+///
+
+
+String GIProbeGizmo::get_handle_name(int p_idx) const {
+
+	switch(p_idx) {
+		case 0: return "Extents X";
+		case 1: return "Extents Y";
+		case 2: return "Extents Z";
+	}
+
+	return "";
+}
+Variant GIProbeGizmo::get_handle_value(int p_idx) const{
+
+	return probe->get_extents();
+}
+void GIProbeGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
+
+	Transform gt = probe->get_global_transform();
+	//gt.orthonormalize();
+	Transform gi = gt.affine_inverse();
+
+
+	Vector3 extents = probe->get_extents();
+
+	Vector3 ray_from = p_camera->project_ray_origin(p_point);
+	Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+	Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*16384)};
+
+	Vector3 axis;
+	axis[p_idx]=1.0;
+
+	Vector3 ra,rb;
+	Geometry::get_closest_points_between_segments(Vector3(),axis*16384,sg[0],sg[1],ra,rb);
+	float d = ra[p_idx];
+	if (d<0.001)
+		d=0.001;
+
+	extents[p_idx]=d;
+	probe->set_extents(extents);
+
+}
+
+void GIProbeGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+
+	Vector3 restore = p_restore;
+
+	if (p_cancel) {
+		probe->set_extents(restore);
+		return;
+	}
+
+	UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+	ur->create_action(TTR("Change Probe Extents"));
+	ur->add_do_method(probe,"set_extents",probe->get_extents());
+	ur->add_undo_method(probe,"set_extents",restore);
+	ur->commit_action();
+
+}
+
+void GIProbeGizmo::redraw(){
+
+	clear();
+
+	Vector<Vector3> lines;
+	Vector3 extents = probe->get_extents();
+
+	static const int subdivs[GIProbe::SUBDIV_MAX]={64,128,256,512};
+
+	AABB aabb = AABB(-extents,extents*2);
+	int subdiv = subdivs[probe->get_subdiv()];
+	float cell_size = aabb.get_longest_axis_size()/subdiv;
+
+
+	for(int i=0;i<12;i++) {
+		Vector3 a,b;
+		aabb.get_edge(i,a,b);
+		lines.push_back(a);
+		lines.push_back(b);
+	}
+
+	add_lines(lines,SpatialEditorGizmos::singleton->gi_probe_material);
+	add_collision_segments(lines);
+
+	lines.clear();
+
+	for(int i=1;i<subdiv;i++) {
+
+		for(int j=0;j<3;j++) {
+
+
+
+			if (cell_size*i>aabb.size[j]) {
+				continue;
+			}
+
+			Vector2 dir;
+			dir[j]=1.0;
+			Vector2 ta,tb;
+			int j_n1=(j+1)%3;
+			int j_n2=(j+2)%3;
+			ta[j_n1]=1.0;
+			tb[j_n2]=1.0;
+
+
+			for(int k=0;k<4;k++) {
+
+				Vector3 from=aabb.pos,to=aabb.pos;
+				from[j]+= cell_size*i;
+				to[j]+=cell_size*i;
+
+				if (k&1) {
+					to[j_n1]+=aabb.size[j_n1];
+				} else {
+
+					to[j_n2]+=aabb.size[j_n2];
+				}
+
+				if (k&2) {
+					from[j_n1]+=aabb.size[j_n1];
+					from[j_n2]+=aabb.size[j_n2];
+				}
+
+				lines.push_back(from);
+				lines.push_back(to);
+			}
+
+		}
+
+	}
+
+	add_lines(lines,SpatialEditorGizmos::singleton->reflection_probe_material_internal);
+
+	Vector<Vector3> handles;
+
+
+	for(int i=0;i<3;i++) {
+
+		Vector3 ax;
+		ax[i]=aabb.pos[i]+aabb.size[i];
+		handles.push_back(ax);
+	}
+
+
+	add_handles(handles);
+
+}
+GIProbeGizmo::GIProbeGizmo(GIProbe* p_probe){
+
+	probe=p_probe;
+	set_spatial_node(p_probe);
+}
+
+////////
+
 
 void NavigationMeshSpatialGizmo::redraw() {
 
@@ -3093,6 +3250,11 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
 		Ref<ReflectionProbeGizmo> misg = memnew( ReflectionProbeGizmo(p_spatial->cast_to<ReflectionProbe>()) );
 		return misg;
 	}
+	if (p_spatial->cast_to<GIProbe>()) {
+
+		Ref<GIProbeGizmo> misg = memnew( GIProbeGizmo(p_spatial->cast_to<GIProbe>()) );
+		return misg;
+	}
 
 	if (p_spatial->cast_to<VehicleWheel>()) {
 
@@ -3146,8 +3308,8 @@ Ref<FixedSpatialMaterial> SpatialEditorGizmos::create_line_material(const Color&
 	line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
 	line_material->set_line_width(3.0);
 	line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
-	line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
-	line_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+	//line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+	//->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
 	line_material->set_albedo(p_base_color);
 
 	return line_material;
@@ -3298,7 +3460,9 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
 	car_wheel_material = create_line_material(Color(0.6,0.8,1.0));
 	visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0));
 	reflection_probe_material = create_line_material(Color(0.5,1.0,0.7));
-	reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.4));
+	reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.15));
+	gi_probe_material = create_line_material(Color(0.7,1.0,0.5));
+	gi_probe_material_internal = create_line_material(Color(0.5,0.8,0.3,0.4));
 	joint_material = create_line_material(Color(0.6,0.8,1.0));
 
 	stream_player_icon = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ));

+ 22 - 0
tools/editor/spatial_editor_gizmos.h

@@ -46,6 +46,7 @@
 #include "scene/3d/ray_cast.h"
 #include "scene/3d/navigation_mesh.h"
 #include "scene/3d/reflection_probe.h"
+#include "scene/3d/gi_probe.h"
 
 #include "scene/3d/vehicle_body.h"
 #include "scene/3d/collision_polygon.h"
@@ -327,6 +328,25 @@ public:
 
 };
 
+class GIProbeGizmo  : public EditorSpatialGizmo {
+
+	OBJ_TYPE(GIProbeGizmo ,EditorSpatialGizmo);
+
+
+	GIProbe* probe;
+
+public:
+
+	virtual String get_handle_name(int p_idx) const;
+	virtual Variant get_handle_value(int p_idx) const;
+	virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
+	virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
+
+	void redraw();
+	GIProbeGizmo(GIProbe* p_notifier=NULL);
+
+};
+
 
 class CollisionShapeSpatialGizmo  : public EditorSpatialGizmo {
 
@@ -496,6 +516,8 @@ public:
 	Ref<FixedSpatialMaterial> skeleton_material;
 	Ref<FixedSpatialMaterial> reflection_probe_material;
 	Ref<FixedSpatialMaterial> reflection_probe_material_internal;
+	Ref<FixedSpatialMaterial> gi_probe_material;
+	Ref<FixedSpatialMaterial> gi_probe_material_internal;
 	Ref<FixedSpatialMaterial> room_material;
 	Ref<FixedSpatialMaterial> portal_material;
 	Ref<FixedSpatialMaterial> raycast_material;

Неке датотеке нису приказане због велике количине промена