Bladeren bron

-Much improvement to baked light baker
-Fixed many bugs in stretch mode
-Fixes to camera project and unproject as consequence of the above
-added setget to script (documented in script doc)
-more fixes to collada exporter for blender

Juan Linietsky 11 jaren geleden
bovenliggende
commit
e82dc40205
61 gewijzigde bestanden met toevoegingen van 2148 en 339 verwijderingen
  1. 1 0
      SConstruct
  2. 4 2
      core/globals.cpp
  3. 5 2
      core/io/config_file.cpp
  4. 1 1
      core/math/quick_hull.cpp
  5. BIN
      demos/3d/platformer/tiles.res
  6. 19 0
      drivers/gles1/rasterizer_gles1.cpp
  7. 11 0
      drivers/gles1/rasterizer_gles1.h
  8. 168 12
      drivers/gles2/rasterizer_gles2.cpp
  9. 20 0
      drivers/gles2/rasterizer_gles2.h
  10. 36 8
      drivers/gles2/shaders/material.glsl
  11. 2 1
      drivers/ogg/SCsub
  12. 2 1
      drivers/theora/SCsub
  13. 12 2
      drivers/theoraplayer/SCsub
  14. 6 0
      drivers/vorbis/SCsub
  15. 1 1
      drivers/vorbis/audio_stream_ogg_vorbis.cpp
  16. 7 3
      modules/gdscript/gd_compiler.cpp
  17. 3 3
      modules/gdscript/gd_editor.cpp
  18. 81 48
      modules/gdscript/gd_parser.cpp
  19. 2 0
      modules/gdscript/gd_parser.h
  20. 24 9
      modules/gdscript/gd_script.cpp
  21. 9 2
      modules/gdscript/gd_script.h
  22. 3 1
      modules/gdscript/gd_tokenizer.cpp
  23. 1 0
      modules/gdscript/gd_tokenizer.h
  24. 2 2
      modules/gdscript/register_types.cpp
  25. 1 1
      modules/gridmap/grid_map.cpp
  26. 24 11
      platform/android/export/export.cpp
  27. 1 8
      platform/isim/SCsub
  28. 2 12
      platform/isim/detect.py
  29. 1 1
      platform/windows/detect.py
  30. 5 0
      platform/x11/detect.py
  31. 78 0
      scene/3d/baked_light_instance.cpp
  32. 42 0
      scene/3d/baked_light_instance.h
  33. 16 3
      scene/3d/camera.cpp
  34. 16 0
      scene/3d/skeleton.cpp
  35. 2 0
      scene/3d/skeleton.h
  36. 10 2
      scene/3d/visual_instance.cpp
  37. 1 0
      scene/3d/visual_instance.h
  38. 1 1
      scene/animation/animation_player.cpp
  39. 3 0
      scene/main/scene_main_loop.h
  40. 26 5
      scene/main/viewport.cpp
  41. 5 0
      scene/main/viewport.h
  42. 1 0
      scene/register_scene_types.cpp
  43. 92 2
      scene/resources/baked_light.cpp
  44. 25 0
      scene/resources/baked_light.h
  45. 4 0
      scene/resources/material.cpp
  46. 7 0
      servers/visual/rasterizer.h
  47. 20 0
      servers/visual/rasterizer_dummy.cpp
  48. 11 0
      servers/visual/rasterizer_dummy.h
  49. 632 7
      servers/visual/visual_server_raster.cpp
  50. 66 0
      servers/visual/visual_server_raster.h
  51. 17 0
      servers/visual/visual_server_wrap_mt.h
  52. 29 1
      servers/visual_server.h
  53. 2 0
      tools/collada/collada.cpp
  54. 1 1
      tools/docdump/makemd.py
  55. 439 167
      tools/editor/plugins/baked_light_baker.cpp
  56. 33 15
      tools/editor/plugins/baked_light_baker.h
  57. 84 0
      tools/editor/plugins/baked_light_baker_cmpxchg.cpp
  58. 16 2
      tools/editor/plugins/baked_light_editor_plugin.cpp
  59. 5 0
      tools/editor/plugins/baked_light_editor_plugin.h
  60. 1 1
      tools/editor/plugins/spatial_editor_plugin.cpp
  61. 9 1
      tools/export/blender25/io_scene_dae/export_dae.py

+ 1 - 0
SConstruct

@@ -99,6 +99,7 @@ opts.Add('vorbis','Build Ogg Vorbis Support: (yes/no)','yes')
 opts.Add('minizip','Build Minizip Archive Support: (yes/no)','yes')
 opts.Add('squish','Squish BC Texture Compression in editor (yes/no)','yes')
 opts.Add('theora','Theora Video (yes/no)','yes')
+opts.Add('use_theoraplayer_binary', "Use precompiled binaries from libtheoraplayer for ogg/theora/vorbis (yes/no)", "no")
 opts.Add('freetype','Freetype support in editor','yes')
 opts.Add('speex','Speex Audio (yes/no)','yes')
 opts.Add('xml','XML Save/Load support (yes/no)','yes')

+ 4 - 2
core/globals.cpp

@@ -566,9 +566,11 @@ static Variant _decode_variant(const String& p_string) {
 		ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
 		int scode=0;
 
-		if (params[0].is_numeric())
+		if (params[0].is_numeric()) {
 			scode=params[0].to_int();
-		else
+			if (scode<10)
+				scode+=KEY_0;
+		} else
 			scode=find_keycode(params[0]);
 
 		InputEvent ie;

+ 5 - 2
core/io/config_file.cpp

@@ -471,9 +471,12 @@ static Variant _decode_variant(const String& p_string) {
 		ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
 		int scode=0;
 
-		if (params[0].is_numeric())
+		if (params[0].is_numeric()) {
 			scode=params[0].to_int();
-		else
+			if (scode < 10) {
+				scode=KEY_0+scode;
+			}
+		} else
 			scode=find_keycode(params[0]);
 
 		InputEvent ie;

+ 1 - 1
core/math/quick_hull.cpp

@@ -63,7 +63,7 @@ Error QuickHull::build(const Vector<Vector3>& p_points, Geometry::MeshData &r_me
 		Vector3 sp = p_points[i].snapped(0.0001);
 		if (valid_cache.has(sp)) {
 			valid_points[i]=false;
-			print_line("INVALIDATED: "+itos(i));
+			//print_line("INVALIDATED: "+itos(i));
 		}else {
 			valid_points[i]=true;
 			valid_cache.insert(sp);

BIN
demos/3d/platformer/tiles.res


+ 19 - 0
drivers/gles1/rasterizer_gles1.cpp

@@ -5363,6 +5363,18 @@ Variant RasterizerGLES1::environment_fx_get_param(RID p_env,VS::EnvironmentFxPar
 	ERR_FAIL_COND_V(!env,Variant());
 	return env->fx_param[p_param];
 
+}
+
+/* SAMPLED LIGHT */
+
+RID RasterizerGLES1::sampled_light_dp_create(int p_width,int p_height) {
+
+	return sampled_light_owner.make_rid(memnew(SampledLight));
+}
+
+void RasterizerGLES1::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) {
+
+
 }
 
 /*MISC*/
@@ -5559,6 +5571,13 @@ void RasterizerGLES1::free(const RID& p_rid) {
 
 		environment_owner.free(p_rid);
 		memdelete( env );
+	} else if (sampled_light_owner.owns(p_rid)) {
+
+		SampledLight *sampled_light = sampled_light_owner.get( p_rid );
+		ERR_FAIL_COND(!sampled_light);
+
+		sampled_light_owner.free(p_rid);
+		memdelete( sampled_light );
 	};
 }
 

+ 11 - 0
drivers/gles1/rasterizer_gles1.h

@@ -488,6 +488,13 @@ class RasterizerGLES1 : public Rasterizer {
 
 	mutable RID_Owner<Environment> environment_owner;
 
+	struct SampledLight {
+
+		int w,h;
+	};
+
+	mutable RID_Owner<SampledLight> sampled_light_owner;
+
 	struct ShadowBuffer;
 
 	struct LightInstance {
@@ -1190,6 +1197,10 @@ public:
 	virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value);
 	virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const;
 
+	/* SAMPLED LIGHT */
+	virtual RID sampled_light_dp_create(int p_width,int p_height);
+	virtual void sampled_light_dp_update(RID p_sampled_light,const Color *p_data,float p_multiplier);
+
 
 	/*MISC*/
 

+ 168 - 12
drivers/gles2/rasterizer_gles2.cpp

@@ -5108,7 +5108,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
 
 	if (li->near_shadow_buffer) {
 
-		glActiveTexture(GL_TEXTURE7);
+		glActiveTexture(GL_TEXTURE0+max_texture_units-1);
 		//if (read_depth_supported) {
 
 			glBindTexture(GL_TEXTURE_2D,li->near_shadow_buffer->depth);
@@ -5119,7 +5119,7 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
 
 		material_shader.set_uniform(MaterialShaderGLES2::SHADOW_MATRIX,li->shadow_projection[0]);
 		material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXEL_SIZE,Vector2(1.0,1.0)/li->near_shadow_buffer->size);
-		material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXTURE,7);
+		material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXTURE,max_texture_units-1);
 		if (shadow_filter==SHADOW_FILTER_ESM)
 			material_shader.set_uniform(MaterialShaderGLES2::ESM_MULTIPLIER,float(li->base->vars[VS::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER]));
 
@@ -5739,9 +5739,10 @@ void RasterizerGLES2::_render(const Geometry *p_geometry,const Material *p_mater
 				float twd=(1.0/mm->tw)*4.0;
 				float thd=1.0/mm->th;
 				float parm[3]={0.0,01.0,(1.0f/mm->tw)};
-				glActiveTexture(GL_TEXTURE6);
+				glActiveTexture(GL_TEXTURE0+max_texture_units-2);
 				glDisableVertexAttribArray(6);
 				glBindTexture(GL_TEXTURE_2D,mm->tex_id);
+				material_shader.set_uniform(MaterialShaderGLES2::INSTANCE_MATRICES,GL_TEXTURE0+max_texture_units-2);
 
 				if (s->index_array_len>0) {
 
@@ -6042,7 +6043,7 @@ void RasterizerGLES2::_setup_skeleton(const Skeleton *p_skeleton) {
 	material_shader.set_conditional(MaterialShaderGLES2::USE_SKELETON,p_skeleton!=NULL);
 	if (p_skeleton && p_skeleton->tex_id) {
 
-		glActiveTexture(GL_TEXTURE6);
+		glActiveTexture(GL_TEXTURE0+max_texture_units-2);
 		glBindTexture(GL_TEXTURE_2D,p_skeleton->tex_id);
 	}
 
@@ -6091,7 +6092,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 
 
 	bool stores_glow = !shadow && (current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]) && !p_alpha_pass;
-
+	float sampled_light_dp_multiplier=1.0;
 
 	bool prev_blend=false;
 	glDisable(GL_BLEND);
@@ -6110,6 +6111,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		bool bind_baked_light_octree=false;
 		bool bind_baked_lightmap=false;
 		bool additive=false;
+		bool bind_dp_sampler=false;
 
 
 		if (!shadow) {
@@ -6231,6 +6233,22 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 
 			material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false);
 			material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
+			material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,false);
+
+			if (e->instance->sampled_light.is_valid()) {
+
+				SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light);
+				if (sl) {
+
+					baked_light=NULL; //can't mix
+					material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,true);
+					glActiveTexture(GL_TEXTURE0+max_texture_units-3);
+					glBindTexture(GL_TEXTURE_2D,sl->texture); //bind the texture
+					sampled_light_dp_multiplier=sl->multiplier;
+					bind_dp_sampler=true;
+				}
+			}
+
 
 			if (!additive && baked_light) {
 
@@ -6241,9 +6259,16 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 						Texture *tex=texture_owner.get(baked_light->octree_texture);
 						if (tex) {
 
-							glActiveTexture(GL_TEXTURE5);
+							glActiveTexture(GL_TEXTURE0+max_texture_units-3);
 							glBindTexture(tex->target,tex->tex_id); //bind the texture
 						}
+						if (baked_light->light_texture.is_valid()) {
+							Texture *texl=texture_owner.get(baked_light->light_texture);
+							if (texl) {
+								glActiveTexture(GL_TEXTURE0+max_texture_units-4);
+								glBindTexture(texl->target,texl->tex_id); //bind the light texture
+							}
+						}
 
 					}
 				} else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) {
@@ -6266,7 +6291,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 							Texture *tex = texture_owner.get(texid);
 							if (tex) {
 
-								glActiveTexture(GL_TEXTURE5);
+								glActiveTexture(GL_TEXTURE0+max_texture_units-3);
 								glBindTexture(tex->target,tex->tex_id); //bind the texture
 							}
 
@@ -6342,7 +6367,15 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_SIZE, baked_light->octree_lattice_size);
 			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LATTICE_DIVIDE, baked_light->octree_lattice_divide);
 			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_STEPS, baked_light->octree_steps);
-			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,5);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_TEX,max_texture_units-3);
+			if (baked_light->light_texture.is_valid()) {
+
+				material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_TEX,max_texture_units-4);
+				material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_PIX_SIZE,baked_light->light_tex_pixel_size);
+			} else {
+				material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_TEX,max_texture_units-3);
+				material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_LIGHT_PIX_SIZE,baked_light->octree_tex_pixel_size);
+			}
 			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_MULTIPLIER,baked_light->texture_multiplier);
 			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_OCTREE_PIX_SIZE,baked_light->octree_tex_pixel_size);
 
@@ -6351,11 +6384,16 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 
 		if (bind_baked_lightmap && (baked_light!=prev_baked_light || rebind)) {
 
-			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP, 5);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP, max_texture_units-3);
 			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP_MULTIPLIER, baked_light->lightmap_multiplier);
 
 		}
 
+		if (bind_dp_sampler) {
+
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_DP_SAMPLER_MULTIPLIER,sampled_light_dp_multiplier);
+			material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_DP_SAMPLER,max_texture_units-3);
+		}
 
 		_set_cull(e->mirror,p_reverse_cull);
 
@@ -6364,7 +6402,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 			material_shader.set_uniform(MaterialShaderGLES2::CAMERA_INVERSE_TRANSFORM, p_view_transform_inverse);
 			material_shader.set_uniform(MaterialShaderGLES2::PROJECTION_TRANSFORM, p_projection);
 			if (skeleton && use_hw_skeleton_xform) {
-				//material_shader.set_uniform(MaterialShaderGLES2::SKELETON_MATRICES,6);
+				material_shader.set_uniform(MaterialShaderGLES2::SKELETON_MATRICES,GL_TEXTURE0+max_texture_units-2);
 				material_shader.set_uniform(MaterialShaderGLES2::SKELTEX_PIXEL_SIZE,skeleton->pixel_size);
 			}
 			if (!shadow) {
@@ -7098,6 +7136,7 @@ void RasterizerGLES2::end_scene() {
 		_debug_shadows();
 	}
 //	_debug_luminances();
+	_debug_samplers();
 
 
 }
@@ -7498,6 +7537,38 @@ void RasterizerGLES2::_debug_luminances() {
 }
 
 
+void RasterizerGLES2::_debug_samplers() {
+	canvas_shader.set_conditional(CanvasShaderGLES2::DEBUG_ENCODED_32,false);
+	canvas_begin();
+	glDisable(GL_BLEND);
+	_set_color_attrib(Color(1,1,1,1));
+	canvas_shader.bind();
+
+
+	List<RID> samplers;
+	sampled_light_owner.get_owned_list(&samplers);
+
+	Size2 debug_size(128,128);
+	Size2 ofs;
+
+
+	for (List<RID>::Element *E=samplers.front();E;E=E->next()) {
+
+		SampledLight *sl=sampled_light_owner.get(E->get());
+
+		_debug_draw_shadow(sl->texture, Rect2( ofs, debug_size ));
+
+		ofs.x+=debug_size.x/2;
+		if ( (ofs.x+debug_size.x) > viewport.width ) {
+
+			ofs.x=0;
+			ofs.y+=debug_size.y;
+		}
+	}
+
+
+
+}
 void RasterizerGLES2::_debug_shadows() {
 
 	canvas_begin();
@@ -8115,6 +8186,78 @@ Variant RasterizerGLES2::environment_fx_get_param(RID p_env,VS::EnvironmentFxPar
 
 }
 
+
+
+RID RasterizerGLES2::sampled_light_dp_create(int p_width,int p_height) {
+
+	SampledLight *slight = memnew(SampledLight);
+	slight->w=p_width;
+	slight->h=p_height;
+	slight->multiplier=1.0;
+	slight->is_float=float_linear_supported;
+
+	glActiveTexture(GL_TEXTURE0);
+	glGenTextures(1,&slight->texture);
+	glBindTexture(GL_TEXTURE_2D, slight->texture);
+// for debug, but glitchy
+//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+//	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+	// Remove artifact on the edges of the shadowmap
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+
+	if (slight->is_float) {
+#ifdef GLEW_ENABLED
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_width, p_height, 0, GL_RGBA, GL_FLOAT,NULL);
+#else
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_width, p_height, 0, GL_RGBA, GL_FLOAT,NULL);
+#endif
+	} else {
+
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_width, p_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+	}
+
+	return sampled_light_owner.make_rid(slight);
+}
+
+void RasterizerGLES2::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) {
+
+	SampledLight *slight = sampled_light_owner.get(p_sampled_light);
+	ERR_FAIL_COND(!slight);
+
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, slight->texture);
+
+	if (slight->is_float) {
+
+#ifdef GLEW_ENABLED
+		glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,slight->w, slight->h, GL_RGBA, GL_FLOAT,p_data);
+#else
+		glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,slight->w, slight->h, GL_RGBA, GL_FLOAT,p_data);
+#endif
+
+	} else {
+		//convert to bytes
+		uint8_t *tex8 = (uint8_t*)alloca(slight->w*slight->h*4);
+		const float* src=(const float*)p_data;
+
+		for(int i=0;i<slight->w*slight->h*4;i++) {
+
+			tex8[i]=Math::fast_ftoi(CLAMP(src[i]*255.0,0.0,255.0));
+		}
+
+		glTexSubImage2D(GL_TEXTURE_2D, 0,0,0,slight->w, slight->h, GL_RGBA, GL_UNSIGNED_BYTE,p_data);
+	}
+
+	slight->multiplier=p_multiplier;
+
+}
+
 /*MISC*/
 
 bool RasterizerGLES2::is_texture(const RID& p_rid) const {
@@ -8334,6 +8477,13 @@ void RasterizerGLES2::free(const RID& p_rid) {
 		memdelete(render_target->texture_ptr);
 		render_target_owner.free(p_rid);
 		memdelete( render_target );
+	} else if (sampled_light_owner.owns(p_rid)) {
+
+		SampledLight *sampled_light = sampled_light_owner.get( p_rid );
+		ERR_FAIL_COND(!sampled_light);
+		glDeleteTextures(1,&sampled_light->texture);
+		sampled_light_owner.free(p_rid);
+		memdelete( sampled_light );
 
 	};
 }
@@ -8926,6 +9076,9 @@ void RasterizerGLES2::init() {
 	latc_supported=true;
 	s3tc_srgb_supported=true;
 	use_anisotropic_filter=true;
+	float_linear_supported=true;
+	float_supported=true;
+
 	glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,&anisotropic_level);
 	anisotropic_level=MIN(anisotropic_level,float(GLOBAL_DEF("rasterizer/anisotropic_filter_level",4.0)));
 #ifdef OSX_ENABLED
@@ -8970,7 +9123,10 @@ void RasterizerGLES2::init() {
 
 	GLint vtf;
 	glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,&vtf);
-	use_hw_skeleton_xform=vtf>0 && extensions.has("GL_OES_texture_float");
+	float_supported = extensions.has("GL_OES_texture_float");
+	use_hw_skeleton_xform=vtf>0 && float_supported;
+	float_linear_supported = extensions.has("GL_OES_texture_float_linear");
+
 	//if (extensions.has("GL_QCOM_tiled_rendering"))
 	//	use_hw_skeleton_xform=false;
 	GLint mva;
@@ -9008,7 +9164,7 @@ void RasterizerGLES2::init() {
 
 
 
-
+	glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_units);
 	//read_depth_supported=false;
 
 	{

+ 20 - 0
drivers/gles2/rasterizer_gles2.h

@@ -86,6 +86,8 @@ class RasterizerGLES2 : public Rasterizer {
 	bool use_shadow_mapping;
 	bool use_fp16_fb;
 	bool srgb_supported;
+	bool float_supported;
+	bool float_linear_supported;
 
 	ShadowFilterTechnique shadow_filter;
 
@@ -704,6 +706,18 @@ class RasterizerGLES2 : public Rasterizer {
 
 	mutable RID_Owner<Environment> environment_owner;
 
+
+	struct SampledLight {
+
+		int w,h;
+		GLuint texture;
+		float multiplier;
+		bool is_float;
+	};
+
+	mutable RID_Owner<SampledLight> sampled_light_owner;
+
+
 	struct ViewportData {
 
 		//1x1 fbo+texture for storing previous HDR value
@@ -801,6 +815,7 @@ class RasterizerGLES2 : public Rasterizer {
 	RID shadow_material;
 	Material *shadow_mat_ptr;
 
+	int max_texture_units;
 	GLuint base_framebuffer;
 
 	GLuint gui_quad_buffer;
@@ -1071,6 +1086,8 @@ class RasterizerGLES2 : public Rasterizer {
 	void _debug_draw_shadows_type(Vector<ShadowBuffer>& p_shadows,Point2& ofs);
 	void _debug_shadows();
 	void _debug_luminances();
+	void _debug_samplers();
+
 
 
 	/***********/
@@ -1531,6 +1548,9 @@ public:
 	virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value);
 	virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const;
 
+	/* SAMPLED LIGHT */
+	virtual RID sampled_light_dp_create(int p_width,int p_height);
+	virtual void sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier);
 
 	/*MISC*/
 

+ 36 - 8
drivers/gles2/shaders/material.glsl

@@ -60,7 +60,7 @@ uniform float normal_mult;
 #ifdef USE_SKELETON
 attribute vec4 bone_indices; // attrib:6
 attribute vec4 bone_weights; // attrib:7
-uniform highp sampler2D skeleton_matrices; // texunit:6
+uniform highp sampler2D skeleton_matrices;
 uniform highp float skeltex_pixel_size;
 #endif
 
@@ -76,7 +76,7 @@ attribute highp vec4 instance_row3; // attrib:11
 #ifdef USE_TEXTURE_INSTANCING
 
 attribute highp vec3 instance_uv; // attrib:6
-uniform highp sampler2D instance_matrices; // texunit:6
+uniform highp sampler2D instance_matrices;
 
 #endif
 
@@ -595,8 +595,10 @@ uniform float time;
 varying highp vec3 ambient_octree_coords;
 uniform highp float ambient_octree_lattice_size;
 uniform highp vec2 ambient_octree_pix_size;
+uniform highp vec2 ambient_octree_light_pix_size;
 uniform highp float ambient_octree_lattice_divide;
 uniform highp sampler2D ambient_octree_tex;
+uniform highp sampler2D ambient_octree_light_tex;
 uniform float ambient_octree_multiplier;
 uniform int ambient_octree_steps;
 
@@ -609,6 +611,12 @@ uniform float ambient_lightmap_multiplier;
 
 #endif
 
+#ifdef ENABLE_AMBIENT_DP_SAMPLER
+
+uniform highp sampler2D ambient_dp_sampler;
+uniform float ambient_dp_sampler_multiplier;
+
+#endif
 
 FRAGMENT_SHADER_GLOBALS
 
@@ -918,12 +926,12 @@ FRAGMENT_SHADER_CODE
 		}
 
 		//sample color
-		octant_uv=(octant_uv+0.5)*ambient_octree_pix_size;
+		octant_uv=(octant_uv+0.5)*ambient_octree_light_pix_size;
 		highp vec3 sub=(mod(ambient_octree_coords,ld)/ld);
-		octant_uv.xy+=sub.xy*ambient_octree_pix_size.xy;
-		vec3 col_up=texture2D(ambient_octree_tex,octant_uv).rgb;
-		octant_uv.y+=ambient_octree_pix_size.y*2.0;
-		vec3 col_down=texture2D(ambient_octree_tex,octant_uv).rgb;
+		octant_uv.xy+=sub.xy*ambient_octree_light_pix_size.xy;
+		vec3 col_up=texture2D(ambient_octree_light_tex,octant_uv).rgb;
+		octant_uv.y+=ambient_octree_light_pix_size.y*2.0;
+		vec3 col_down=texture2D(ambient_octree_light_tex,octant_uv).rgb;
 		ambientmap_color=mix(col_up,col_down,sub.z)*ambient_octree_multiplier;
 
 		ambientmap_color*=diffuse.rgb;
@@ -934,6 +942,26 @@ FRAGMENT_SHADER_CODE
 
 
 
+#ifdef ENABLE_AMBIENT_DP_SAMPLER
+
+	vec3 ambientmap_color = vec3(0.0,0.0,0.0);
+
+	{
+
+		vec3 dp_normal = normalize((vec4(normal,0) * camera_inverse_transform).xyz);
+		vec2 ambient_uv = (dp_normal.xy / (1.0+abs(dp_normal.z)))*0.5+0.5; //dual paraboloid
+		ambient_uv.y*=0.5;
+		if (dp_normal.z<0) {
+
+			ambient_uv.y=(0.5-ambient_uv.y)+0.5;
+
+		}
+
+		ambientmap_color = texture2D(ambient_dp_sampler,ambient_uv ).rgb * ambient_dp_sampler_multiplier;
+		ambientmap_color*=diffuse.rgb;
+	}
+
+#endif
 
 
 
@@ -1224,7 +1252,7 @@ LIGHT_SHADER_CODE
 #endif
 
 
-#if defined(ENABLE_AMBIENT_OCTREE) || defined(ENABLE_AMBIENT_LIGHTMAP)
+#if defined(ENABLE_AMBIENT_OCTREE) || defined(ENABLE_AMBIENT_LIGHTMAP) || defined(ENABLE_AMBIENT_DP_SAMPLER)
 
 	diffuse.rgb+=ambientmap_color;
 #endif

+ 2 - 1
drivers/ogg/SCsub

@@ -6,5 +6,6 @@ ogg_sources = [
 	"ogg/framing.c",
 ]
 
-env.drivers_sources+=ogg_sources
+if env['theora'] != "yes" or env['use_theoraplayer_binary'] != "yes":
+	env.drivers_sources+=ogg_sources
 

+ 2 - 1
drivers/theora/SCsub

@@ -32,6 +32,7 @@ sources = [
 	"theora/video_stream_theora.cpp",
 ]
 
-env.drivers_sources += sources
+if env['use_theoraplayer_binary'] != "yes":
+	env.drivers_sources += sources
 
 

+ 12 - 2
drivers/theoraplayer/SCsub

@@ -59,7 +59,6 @@ src/YUV/C/yuv420_grey_c.c
 src/YUV/C/yuv420_yuv_c.c
 src/YUV/C/yuv420_rgb_c.c
 src/TheoraVideoFrame.cpp
-video_stream_theoraplayer.cpp
 """)
 
 if env["platform"] == "iphone":
@@ -79,7 +78,18 @@ if env["platform"] == "android":
 env_theora.Append(CPPPATH=["#drivers/theoraplayer/include/theoraplayer", "#drivers/theoraplayer/src/YUV", "#drivers/theoraplayer/src/YUV/libyuv/include", "#drivers/theoraplayer/src/Theora", "#drivers/theoraplayer/src/AVFoundation"])
 
 objs = []
-env_theora.add_source_files(objs, sources)
+
+env_theora.add_source_files(objs, ["video_stream_theoraplayer.cpp"])
+
+if env['use_theoraplayer_binary'] == "yes":
+	if env["platform"] == "iphone":
+		env.Append(LIBPATH=['#drivers/theoraplayer/lib/ios'])
+		env.Append(LIBS=['theoraplayer', 'ogg', 'theora', 'tremor'])
+	if env["platform"] == "windows":
+		env.Append(LIBPATH=['#drivers/theoraplayer/lib/windows'])
+		env.Append(LINKFLAGS=['libtheoraplayer_static.lib', 'libogg.lib', 'libtheora.lib', 'libvorbis.lib'])
+else:
+	env_theora.add_source_files(objs, sources)
 
 env.drivers_sources += objs
 

+ 6 - 0
drivers/vorbis/SCsub

@@ -3,6 +3,9 @@ Import('env')
 
 sources = [
 	"vorbis/audio_stream_ogg_vorbis.cpp",
+]
+
+sources_lib = [
 	"vorbis/analysis.c",
 	#"vorbis/barkmel.c",
 	"vorbis/bitrate.c",
@@ -32,3 +35,6 @@ sources = [
 
 env.drivers_sources += sources
 
+if env['theora'] != "yes" or env['use_theoraplayer_binary'] != "yes":
+	env.drivers_sources += sources_lib
+

+ 1 - 1
drivers/vorbis/audio_stream_ogg_vorbis.cpp

@@ -215,7 +215,7 @@ AudioStreamOGGVorbis::UpdateMode AudioStreamOGGVorbis::get_update_mode() const {
 bool AudioStreamOGGVorbis::is_playing() const {
 
 
-	return playing;
+	return playing || (get_total() - get_todo() -1 > 0);
 }
 
 float AudioStreamOGGVorbis::get_pos() const {

+ 7 - 3
modules/gdscript/gd_compiler.cpp

@@ -179,7 +179,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
 				//static function
 				if (codegen.script->member_indices.has(identifier)) {
 
-					int idx = codegen.script->member_indices[identifier];
+					int idx = codegen.script->member_indices[identifier].index;
 					return idx|(GDFunction::ADDR_TYPE_MEMBER<<GDFunction::ADDR_BITS); //argument (stack root)
 				}
 			}
@@ -1507,8 +1507,12 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
 #endif
 		}
 
-		int new_idx = p_script->member_indices.size();
-		p_script->member_indices[name]=new_idx;
+		//int new_idx = p_script->member_indices.size();
+		GDScript::MemberInfo minfo;
+		minfo.index = p_script->member_indices.size();
+		minfo.setter = p_class->variables[i].setter;
+		minfo.getter = p_class->variables[i].getter;
+		p_script->member_indices[name]=minfo;
 		p_script->members.insert(name);
 
 	}

+ 3 - 3
modules/gdscript/gd_editor.cpp

@@ -250,12 +250,12 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p
     ERR_FAIL_COND( script.is_null() );
 
 
-    const Map<StringName,int>& mi = script->debug_get_member_indices();
+    const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
 
-    for(const Map<StringName,int>::Element *E=mi.front();E;E=E->next()) {
+    for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
 
 	p_members->push_back(E->key());
-	p_values->push_back( instance->debug_get_member_by_index(E->get()));
+	p_values->push_back( instance->debug_get_member_by_index(E->get().index));
     }
 
 }

+ 81 - 48
modules/gdscript/gd_parser.cpp

@@ -2376,80 +2376,113 @@ void GDParser::_parse_class(ClassNode *p_class) {
 				member._export.name=member.identifier;
 				tokenizer->advance();
 
-				p_class->variables.push_back(member);
+				if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) {
 
-				if (tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) {
+#ifdef DEBUG_ENABLED
+					int line = tokenizer->get_token_line();
+#endif
+					tokenizer->advance();
 
-					if (autoexport) {
+					Node *subexpr=NULL;
 
-						_set_error("Type-less export needs a constant expression assigned to infer type.");
+					subexpr = _parse_and_reduce_expression(p_class,false);
+					if (!subexpr)
 						return;
-					}
-					break;
-				}
-#ifdef DEBUG_ENABLED
-				int line = tokenizer->get_token_line();
-#endif
-				tokenizer->advance();
 
-				Node *subexpr=NULL;
+					if (autoexport) {
+						if (subexpr->type==Node::TYPE_ARRAY) {
 
-				subexpr = _parse_and_reduce_expression(p_class,false);
-				if (!subexpr)
-					return;
+							member._export.type=Variant::ARRAY;
 
-				if (autoexport) {
-					if (subexpr->type==Node::TYPE_ARRAY) {
+						} else if (subexpr->type==Node::TYPE_DICTIONARY) {
 
-						p_class->variables[p_class->variables.size()-1]._export.type=Variant::ARRAY;
+							member._export.type=Variant::DICTIONARY;
 
-					} else if (subexpr->type==Node::TYPE_DICTIONARY) {
+						} else {
 
-						p_class->variables[p_class->variables.size()-1]._export.type=Variant::DICTIONARY;
+							if (subexpr->type!=Node::TYPE_CONSTANT) {
 
-					} else {
+								_set_error("Type-less export needs a constant expression assigned to infer type.");
+								return;
+							}
 
-						if (subexpr->type!=Node::TYPE_CONSTANT) {
+							ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
+							if (cn->value.get_type()==Variant::NIL) {
 
-							_set_error("Type-less export needs a constant expression assigned to infer type.");
-							return;
+								_set_error("Can't accept a null constant expression for infering export type.");
+								return;
+							}
+							member._export.type=cn->value.get_type();
 						}
+					}
+#ifdef TOOLS_ENABLED
+					if (subexpr->type==Node::TYPE_CONSTANT && member._export.type!=Variant::NIL) {
 
 						ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
-						if (cn->value.get_type()==Variant::NIL) {
-
-							_set_error("Can't accept a null constant expression for infering export type.");
-							return;
+						if (cn->value.get_type()!=Variant::NIL) {
+							member.default_value=cn->value;
 						}
-						p_class->variables[p_class->variables.size()-1]._export.type=cn->value.get_type();
 					}
-				}
-#ifdef TOOLS_ENABLED
-				if (subexpr->type==Node::TYPE_CONSTANT && p_class->variables[p_class->variables.size()-1]._export.type!=Variant::NIL) {
+#endif
+
+					IdentifierNode *id = alloc_node<IdentifierNode>();
+					id->name=member.identifier;
+
+					OperatorNode *op = alloc_node<OperatorNode>();
+					op->op=OperatorNode::OP_ASSIGN;
+					op->arguments.push_back(id);
+					op->arguments.push_back(subexpr);
+
+#ifdef DEBUG_ENABLED
+					NewLineNode *nl = alloc_node<NewLineNode>();
+					nl->line=line;
+					p_class->initializer->statements.push_back(nl);
+#endif
+					p_class->initializer->statements.push_back(op);
+
+
+
+				} else {
+
+					if (autoexport) {
 
-					ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
-					if (cn->value.get_type()!=Variant::NIL) {
-						p_class->variables[p_class->variables.size()-1].default_value=cn->value;
+						_set_error("Type-less export needs a constant expression assigned to infer type.");
+						return;
 					}
+
 				}
-#endif
 
+				if (tokenizer->get_token()==GDTokenizer::TK_PR_SETGET) {
 
 
-				IdentifierNode *id = alloc_node<IdentifierNode>();
-				id->name=member.identifier;
+					tokenizer->advance();
 
-				OperatorNode *op = alloc_node<OperatorNode>();
-				op->op=OperatorNode::OP_ASSIGN;
-				op->arguments.push_back(id);
-				op->arguments.push_back(subexpr);
+					if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
+						//just comma means using only getter
+						if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+							_set_error("Expected identifier for setter function after 'notify'.");
+						}
 
-#ifdef DEBUG_ENABLED
-				NewLineNode *nl = alloc_node<NewLineNode>();
-				nl->line=line;
-				p_class->initializer->statements.push_back(nl);
-#endif
-				p_class->initializer->statements.push_back(op);
+						member.setter=tokenizer->get_token_identifier();
+
+						tokenizer->advance();
+					}
+
+					if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+						//there is a getter
+						tokenizer->advance();
+
+						if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+							_set_error("Expected identifier for getter function after ','.");
+						}
+
+						member.getter=tokenizer->get_token_identifier();
+						tokenizer->advance();
+
+					}
+				}
+
+				p_class->variables.push_back(member);
 
 				_end_statement();
 

+ 2 - 0
modules/gdscript/gd_parser.h

@@ -82,6 +82,8 @@ public:
 			Variant default_value;
 #endif
 			StringName identifier;
+			StringName setter;
+			StringName getter;
 		};
 		struct Constant {
 			StringName identifier;

+ 24 - 9
modules/gdscript/gd_script.cpp

@@ -1537,7 +1537,7 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
 
 			_GDScriptMemberSort ms;
 			ERR_CONTINUE(!scr->member_indices.has(E->key()));
-			ms.index=scr->member_indices[E->key()];
+			ms.index=scr->member_indices[E->key()].index;
 			ms.name=E->key();
 
 			msort.push_back(ms);
@@ -1961,9 +1961,9 @@ const Map<StringName,GDFunction>& GDScript::debug_get_member_functions() const {
 StringName GDScript::debug_get_member_by_index(int p_idx) const {
 
 
-	for(const Map<StringName,int>::Element *E=member_indices.front();E;E=E->next()) {
+	for(const Map<StringName,MemberInfo>::Element *E=member_indices.front();E;E=E->next()) {
 
-		if (E->get()==p_idx)
+		if (E->get().index==p_idx)
 			return E->key();
 	}
 
@@ -2002,11 +2002,18 @@ bool GDInstance::set(const StringName& p_name, const Variant& p_value) {
 
 	//member
 	{
-		const Map<StringName,int>::Element *E = script->member_indices.find(p_name);
+		const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
 		if (E) {
-			members[E->get()]=p_value;
+			members[E->get().index]=p_value;
+			if (E->get().setter) {
+				const Variant *val=&p_value;
+				Variant::CallError err;
+				call(E->get().setter,&val,1,err);
+				if (err.error==Variant::CallError::CALL_OK) {
+					return true; //function exists, call was successful
+				}
+			}
 			return true;
-
 		}
 	}
 
@@ -2039,9 +2046,16 @@ bool GDInstance::get(const StringName& p_name, Variant &r_ret) const {
 	while(sptr) {
 
 		{
-			const Map<StringName,int>::Element *E = script->member_indices.find(p_name);
+			const Map<StringName,GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
 			if (E) {
-				r_ret=members[E->get()];
+				if (E->get().getter) {
+					Variant::CallError err;
+					r_ret=const_cast<GDInstance*>(this)->call(E->get().getter,NULL,0,err);
+					if (err.error==Variant::CallError::CALL_OK) {
+						return true;
+					}
+				}
+				r_ret=members[E->get().index];
 				return true; //index found
 
 			}
@@ -2131,7 +2145,7 @@ void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const {
 
 			_GDScriptMemberSort ms;
 			ERR_CONTINUE(!sptr->member_indices.has(E->key()));
-			ms.index=sptr->member_indices[E->key()];
+			ms.index=sptr->member_indices[E->key()].index;
 			ms.name=E->key();
 			msort.push_back(ms);
 
@@ -2441,6 +2455,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const  {
 		"false"	,
 		"tool",
 		"var",
+		"setget",
 		"pass",
 		"and",
 		"or",

+ 9 - 2
modules/gdscript/gd_script.h

@@ -220,11 +220,18 @@ class GDScript : public Script {
 	bool valid;
 
 
+	struct MemberInfo {
+		int index;
+		StringName setter;
+		StringName getter;
+	};
 
 friend class GDInstance;
 friend class GDFunction;
 friend class GDCompiler;
 friend class GDFunctions;
+friend class GDScriptLanguage;
+
 	Variant _static_ref; //used for static call
 	Ref<GDNativeClass> native;
 	Ref<GDScript> base;
@@ -234,7 +241,7 @@ friend class GDFunctions;
 	Set<StringName> members; //members are just indices to the instanced script.
 	Map<StringName,Variant> constants;
 	Map<StringName,GDFunction> member_functions;
-	Map<StringName,int> member_indices; //members are just indices to the instanced script.
+	Map<StringName,MemberInfo> member_indices; //members are just indices to the instanced script.
 	Map<StringName,Ref<GDScript> > subclasses;	
 
 #ifdef TOOLS_ENABLED
@@ -288,7 +295,7 @@ public:
 	bool is_tool() const { return tool; }
 	Ref<GDScript> get_base() const;
 
-	const Map<StringName,int>& debug_get_member_indices() const { return member_indices; }
+	const Map<StringName,MemberInfo>& debug_get_member_indices() const { return member_indices; }
 	const Map<StringName,GDFunction>& debug_get_member_functions() const; //this is debug only
 	StringName debug_get_member_by_index(int p_idx) const;
 

+ 3 - 1
modules/gdscript/gd_tokenizer.cpp

@@ -91,6 +91,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
 "tool",
 "static",
 "export",
+"setget",
 "const",
 "var",
 "preload",
@@ -831,6 +832,7 @@ void GDTokenizerText::_advance() {
 								{TK_PR_TOOL,"tool"},
 								{TK_PR_STATIC,"static"},
 								{TK_PR_EXPORT,"export"},
+								{TK_PR_SETGET,"setget"},
 								{TK_PR_VAR,"var"},
 								{TK_PR_PRELOAD,"preload"},
 								{TK_PR_ASSERT,"assert"},
@@ -1015,7 +1017,7 @@ void GDTokenizerText::advance(int p_amount) {
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 
-#define BYTECODE_VERSION 2
+#define BYTECODE_VERSION 3
 
 Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
 

+ 1 - 0
modules/gdscript/gd_tokenizer.h

@@ -98,6 +98,7 @@ public:
 		TK_PR_TOOL,
 		TK_PR_STATIC,
 		TK_PR_EXPORT,
+		TK_PR_SETGET,
 		TK_PR_CONST,
 		TK_PR_VAR,
 		TK_PR_PRELOAD,

+ 2 - 2
modules/gdscript/register_types.cpp

@@ -121,16 +121,16 @@ static void register_editor_plugin() {
 
 void register_gdscript_types() {
 
+	ObjectTypeDB::register_type<GDScript>();
+	ObjectTypeDB::register_virtual_type<GDFunctionState>();
 
 	script_language_gd=memnew( GDScriptLanguage );
 	script_language_gd->init();
 	ScriptServer::register_language(script_language_gd);
-	ObjectTypeDB::register_type<GDScript>();
 	resource_loader_gd=memnew( ResourceFormatLoaderGDScript );
 	ResourceLoader::add_resource_format_loader(resource_loader_gd);
 	resource_saver_gd=memnew( ResourceFormatSaverGDScript );
 	ResourceSaver::add_resource_format_saver(resource_saver_gd);
-	ObjectTypeDB::register_virtual_type<GDFunctionState>();
 
 #ifdef TOOLS_ENABLED
 

+ 1 - 1
modules/gridmap/grid_map.cpp

@@ -1041,7 +1041,7 @@ void GridMap::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_clip","enabled","clipabove","floor","axis"),&GridMap::set_clip,DEFVAL(true),DEFVAL(0),DEFVAL(Vector3::AXIS_X));
 
-	ObjectTypeDB::bind_method(_MD("crate_area","id","area"),&GridMap::create_area);
+	ObjectTypeDB::bind_method(_MD("create_area","id","area"),&GridMap::create_area);
 	ObjectTypeDB::bind_method(_MD("area_get_bounds","area","bounds"),&GridMap::area_get_bounds);
 	ObjectTypeDB::bind_method(_MD("area_set_exterior_portal","area","enable"),&GridMap::area_set_exterior_portal);
 	ObjectTypeDB::bind_method(_MD("area_set_name","area","name"),&GridMap::area_set_name);

+ 24 - 11
platform/android/export/export.cpp

@@ -184,6 +184,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 	String cmdline;
 	bool _signed;
 	bool apk_expansion;
+	bool remove_prev;
 	String apk_expansion_salt;
 	String apk_expansion_pkey;
 	int orientation;
@@ -258,7 +259,9 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
 
 	String n=p_name;
 
-	if (n=="custom_package/debug")
+	if (n=="one_click_deploy/clear_previous_install")
+		remove_prev=p_value;
+	else if (n=="custom_package/debug")
 		custom_debug_package=p_value;
 	else if (n=="custom_package/release")
 		custom_release_package=p_value;
@@ -321,7 +324,9 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
 bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret) const{
 
 	String n=p_name;
-	if (n=="custom_package/debug")
+	if (n=="one_click_deploy/clear_previous_install")
+		r_ret=remove_prev;
+	else if (n=="custom_package/debug")
 		r_ret=custom_debug_package;
 	else if (n=="custom_package/release")
 		r_ret=custom_release_package;
@@ -378,6 +383,7 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret)
 
 void EditorExportPlatformAndroid::_get_property_list( List<PropertyInfo> *p_list) const{
 
+	p_list->push_back( PropertyInfo( Variant::BOOL, "one_click_deploy/clear_previous_install"));
 	p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"apk"));
 	p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"apk"));
 	p_list->push_back( PropertyInfo( Variant::STRING, "command_line/extra_args"));
@@ -1448,16 +1454,20 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 		return err;
 	}
 
-	ep.step("Uninstalling..",1);
-
-	print_line("Uninstalling previous version: "+devices[p_device].name);
 	List<String> args;
-	args.push_back("-s");
-	args.push_back(devices[p_device].id);
-	args.push_back("uninstall");
-	args.push_back(package);
 	int rv;
-	err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
+
+	if (remove_prev) {
+		ep.step("Uninstalling..",1);
+
+		print_line("Uninstalling previous version: "+devices[p_device].name);
+
+		args.push_back("-s");
+		args.push_back(devices[p_device].id);
+		args.push_back("uninstall");
+		args.push_back(package);
+
+		err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
 #if 0
 	if (err || rv!=0) {
 		EditorNode::add_io_error("Could not install to device.");
@@ -1465,6 +1475,8 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 		return ERR_CANT_CREATE;
 	}
 #endif
+	}
+
 	print_line("Installing into device (please wait..): "+devices[p_device].name);
 	ep.step("Installing to Device (please wait..)..",2);
 
@@ -1473,7 +1485,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
 	args.push_back(devices[p_device].id);
 	args.push_back("install");
 	args.push_back(export_to);
-	rv;
+
 	err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
 	if (err || rv!=0) {
 		EditorNode::add_io_error("Could not install to device.");
@@ -1515,6 +1527,7 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
 	device_lock = Mutex::create();
 	quit_request=false;
 	orientation=0;
+	remove_prev=false;
 
 	device_thread=Thread::create(_device_poll_thread,this);
 	devices_changed=true;

+ 1 - 8
platform/isim/SCsub

@@ -34,11 +34,4 @@ if env['ios_appirater'] == "yes":
 obj = env_ios.Object('#platform/iphone/godot_iphone.cpp')
 
 prog = None
-if env["target"]=="release":
-	prog = env_ios.Program('#bin/godot_opt', [obj] + iphone_lib)
-	#action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
-	#env.AddPostAction(prog, action)
-else:
-	prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
-	#action = "dsymutil "+File(prog)[0].path+" -o ../build/script_exec/build/Debug-iphoneos/script_exec.app.dSYM"
-	#env.AddPostAction(prog, action)
+prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)

+ 2 - 12
platform/isim/detect.py

@@ -22,7 +22,7 @@ def get_opts():
 	return [
 		('ISIMPLATFORM', 'name of the iphone platform', 'iPhoneSimulator'),
 		('ISIMPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Platforms/${ISIMPLATFORM}.platform'),
-		('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/Developer/SDKs/${ISIMPLATFORM}7.0.sdk'),
+		('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/Developer/SDKs/${ISIMPLATFORM}7.1.sdk'),
 		('game_center', 'Support for game center', 'yes'),
 		('store_kit', 'Support for in-app store', 'yes'),
 		('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
@@ -34,9 +34,7 @@ def get_opts():
 def get_flags():
 
 	return [
-		('lua', 'no'),
 		('tools', 'yes'),
-		('nedmalloc', 'no'),
 		('webp', 'yes'),
 	]
 
@@ -46,10 +44,6 @@ def configure(env):
 
 	env.Append(CPPPATH=['#platform/iphone'])
 
-	env['OBJSUFFIX'] = ".isim.o"
-	env['LIBSUFFIX'] = ".isim.a"
-	env['PROGSUFFIX'] = ".isim"
-
 	env['ENV']['PATH'] = env['ISIMPATH']+"/Developer/usr/bin/:"+env['ENV']['PATH']
 
 	env['CC'] = '$ISIMPATH/Developer/usr/bin/gcc'
@@ -83,8 +77,6 @@ def configure(env):
 
 		env.Append(CCFLAGS=['-O3', '-ffast-math'])
 		env.Append(LINKFLAGS=['-O3', '-ffast-math'])
-		env['OBJSUFFIX'] = "_opt"+env['OBJSUFFIX']
-		env['LIBSUFFIX'] = "_opt"+env['LIBSUFFIX']
 
 	elif (env["target"]=="debug"):
 
@@ -99,8 +91,6 @@ def configure(env):
 
 	env['ENV']['MACOSX_DEPLOYMENT_TARGET'] = '10.6'
 	env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
-	env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-fno-exceptions'])
+	env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-fexceptions'])
 
-	if env['lua'] == "yes":
-		env.Append(CCFLAGS=['-DLUA_USE_FLOAT'])
 

+ 1 - 1
platform/windows/detect.py

@@ -64,7 +64,7 @@ def get_flags():
 	return [
 		('freetype','builtin'), #use builtin freetype
 		('openssl','builtin'), #use builtin openssl
-		('theora','no'), #use builtin openssl
+		('theora','no'),
 	]
 			
 

+ 5 - 0
platform/x11/detect.py

@@ -54,6 +54,7 @@ def get_flags():
 	return [
 	('builtin_zlib', 'no'),
 	("openssl", "yes"),
+	("theora","no"),
         ]
 			
 
@@ -77,6 +78,10 @@ def configure(env):
 		if (env["use_sanitizer"]=="yes"):
 			env.Append(CXXFLAGS=['-fsanitize=address','-fno-omit-frame-pointer'])
 			env.Append(LINKFLAGS=['-fsanitize=address'])
+			env.extra_suffix=".llvms"
+		else:
+			env.extra_suffix=".llvm"
+
 
 
 

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

@@ -63,3 +63,81 @@ BakedLightInstance::BakedLightInstance() {
 
 
 }
+/////////////////////////
+
+
+void BakedLightSampler::set_param(Param p_param,float p_value) {
+	ERR_FAIL_INDEX(p_param,PARAM_MAX);
+	params[p_param]=p_value;
+	VS::get_singleton()->baked_light_sampler_set_param(base,VS::BakedLightSamplerParam(p_param),p_value);
+}
+
+float BakedLightSampler::get_param(Param p_param) const{
+
+	ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0);
+	return params[p_param];
+
+}
+
+void BakedLightSampler::set_resolution(int p_resolution){
+
+	ERR_FAIL_COND(p_resolution<4 && p_resolution>32);
+	resolution=p_resolution;
+	VS::get_singleton()->baked_light_sampler_set_resolution(base,resolution);
+}
+int BakedLightSampler::get_resolution() const {
+
+	return resolution;
+}
+
+AABB BakedLightSampler::get_aabb() const {
+
+	float r = get_param(PARAM_RADIUS);
+	return AABB( Vector3(-r,-r,-r),Vector3(r*2,r*2,r*2));
+}
+DVector<Face3> BakedLightSampler::get_faces(uint32_t p_usage_flags) const {
+	return DVector<Face3>();
+}
+
+void BakedLightSampler::_bind_methods() {
+
+	ObjectTypeDB::bind_method(_MD("set_param","param","value"),&BakedLightSampler::set_param);
+	ObjectTypeDB::bind_method(_MD("get_param","param"),&BakedLightSampler::get_param);
+
+	ObjectTypeDB::bind_method(_MD("set_resolution","resolution"),&BakedLightSampler::set_resolution);
+	ObjectTypeDB::bind_method(_MD("get_resolution"),&BakedLightSampler::get_resolution);
+
+
+	BIND_CONSTANT( PARAM_RADIUS );
+	BIND_CONSTANT( PARAM_STRENGTH );
+	BIND_CONSTANT( PARAM_ATTENUATION );
+	BIND_CONSTANT( PARAM_DETAIL_RATIO );
+	BIND_CONSTANT( PARAM_MAX );
+
+	ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/radius",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_RADIUS);
+	ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/strength",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_STRENGTH);
+	ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/attenuation",PROPERTY_HINT_EXP_EASING),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION);
+	ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/detail_ratio",PROPERTY_HINT_RANGE,"0.01,1.0,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_DETAIL_RATIO);
+//	ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/detail_ratio",PROPERTY_HINT_RANGE,"0,20,1"),_SCS("set_param"),_SCS("get_param"),PARAM_DETAIL_RATIO);
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"params/resolution",PROPERTY_HINT_RANGE,"4,32,1"),_SCS("set_resolution"),_SCS("get_resolution"));
+
+}
+
+BakedLightSampler::BakedLightSampler() {
+
+	base = VS::get_singleton()->baked_light_sampler_create();
+	set_base(base);
+
+	params[PARAM_RADIUS]=1.0;
+	params[PARAM_STRENGTH]=1.0;
+	params[PARAM_ATTENUATION]=1.0;
+	params[PARAM_DETAIL_RATIO]=0.1;
+	resolution=16;
+
+
+}
+
+BakedLightSampler::~BakedLightSampler(){
+
+	VS::get_singleton()->free(base);
+}

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

@@ -30,4 +30,46 @@ public:
 	BakedLightInstance();
 };
 
+
+
+class BakedLightSampler : public VisualInstance {
+	OBJ_TYPE(BakedLightSampler,VisualInstance);
+
+
+public:
+
+	enum Param {
+		PARAM_RADIUS=VS::BAKED_LIGHT_SAMPLER_RADIUS,
+		PARAM_STRENGTH=VS::BAKED_LIGHT_SAMPLER_STRENGTH,
+		PARAM_ATTENUATION=VS::BAKED_LIGHT_SAMPLER_ATTENUATION,
+		PARAM_DETAIL_RATIO=VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO,
+		PARAM_MAX=VS::BAKED_LIGHT_SAMPLER_MAX
+	};
+
+
+
+protected:
+
+	RID base;
+	float params[PARAM_MAX];
+	int resolution;
+	static void _bind_methods();
+public:
+
+	virtual AABB get_aabb() const;
+	virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+	void set_param(Param p_param,float p_value);
+	float get_param(Param p_param) const;
+
+	void set_resolution(int p_resolution);
+	int get_resolution() const;
+
+	BakedLightSampler();
+	~BakedLightSampler();
+};
+
+VARIANT_ENUM_CAST( BakedLightSampler::Param );
+
+
 #endif // BAKED_LIGHT_H

+ 16 - 3
scene/3d/camera.cpp

@@ -467,7 +467,15 @@ Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const {
 		ERR_FAIL_COND_V(!is_inside_scene(),Vector3());
 	}
 
+
+#if 0
 	Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+	Vector2 cpos = p_pos;
+#else
+
+	Size2 viewport_size = viewport_ptr->get_camera_rect_size();
+	Vector2 cpos = viewport_ptr->get_camera_coords(p_pos);
+#endif
 
 	Vector3 ray;
 
@@ -479,10 +487,9 @@ Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const {
 		cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
 		float screen_w,screen_h;
 		cm.get_viewport_size(screen_w,screen_h);
-		ray=Vector3( ((p_pos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(p_pos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized();
+		ray=Vector3( ((cpos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(cpos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized();
 	}
 
-
 	return ray;
 };
 
@@ -494,8 +501,14 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
 		ERR_FAIL_COND_V(!is_inside_scene(),Vector3());
 	}
 
+#if 0
 	Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+	Vector2 cpos = p_pos;
+#else
 
+	Size2 viewport_size = viewport_ptr->get_camera_rect_size();
+	Vector2 cpos = viewport_ptr->get_camera_coords(p_pos);
+#endif
 
 	ERR_FAIL_COND_V( viewport_size.y == 0, Vector3() );
 //	float aspect = viewport_size.x / viewport_size.y;
@@ -505,7 +518,7 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
 		return get_camera_transform().origin;
 	} else {
 
-		Vector2 pos = p_pos / viewport_size;
+		Vector2 pos = cpos / viewport_size;
 		float vsize,hsize;
 		if (keep_aspect==KEEP_WIDTH) {
 			vsize = size/viewport_size.get_aspect();

+ 16 - 0
scene/3d/skeleton.cpp

@@ -237,6 +237,21 @@ Transform Skeleton::get_bone_transform(int p_bone) const {
 	return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse;
 }
 
+
+void Skeleton::set_bone_global_pose(int p_bone,const Transform& p_pose) {
+
+	ERR_FAIL_INDEX(p_bone,bones.size());
+	if (bones[p_bone].parent==-1) {
+
+		set_bone_pose(p_bone,bones[p_bone].rest.inverse() * p_pose);
+	} else {
+
+		set_bone_pose(p_bone, bones[p_bone].rest.inverse() * (get_bone_global_pose(bones[p_bone].parent).affine_inverse() * p_pose));
+
+	}
+
+}
+
 Transform Skeleton::get_bone_global_pose(int p_bone) const {
 
 	ERR_FAIL_INDEX_V(p_bone,bones.size(),Transform());
@@ -519,6 +534,7 @@ void Skeleton::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_bone_pose","bone_idx"),&Skeleton::get_bone_pose);
 	ObjectTypeDB::bind_method(_MD("set_bone_pose","bone_idx","pose"),&Skeleton::set_bone_pose);
 
+	ObjectTypeDB::bind_method(_MD("set_bone_global_pose","bone_idx","pose"),&Skeleton::set_bone_global_pose);
 	ObjectTypeDB::bind_method(_MD("get_bone_global_pose","bone_idx"),&Skeleton::get_bone_global_pose);
 
 	ObjectTypeDB::bind_method(_MD("get_bone_custom_pose","bone_idx"),&Skeleton::get_bone_custom_pose);

+ 2 - 0
scene/3d/skeleton.h

@@ -118,6 +118,8 @@ public:
 	Transform get_bone_transform(int p_bone) const;
 	Transform get_bone_global_pose(int p_bone) const;
 
+	void set_bone_global_pose(int p_bone,const Transform& p_pose);
+
 	void set_bone_enabled(int p_bone, bool p_enabled);
 	bool is_bone_enabled(int p_bone) const;
 	

+ 10 - 2
scene/3d/visual_instance.cpp

@@ -50,17 +50,24 @@ void VisualInstance::_notification(int p_what) {
 			// CHECK ROOM
 			Spatial * parent = get_parent_spatial();
 			Room *room=NULL;
+			bool is_geom = cast_to<GeometryInstance>();
 
 			while(parent) {
 
 				room = parent->cast_to<Room>();
 				if (room)
 					break;
-				else
-					parent=parent->get_parent_spatial();
+
+				if (is_geom && parent->cast_to<BakedLightSampler>()) {
+					VS::get_singleton()->instance_geometry_set_baked_light_sampler(get_instance(),parent->cast_to<BakedLightSampler>()->get_instance());
+					break;
+				}
+
+				parent=parent->get_parent_spatial();
 			}
 
 
+
 			if (room) {
 
 				VisualServer::get_singleton()->instance_set_room(instance,room->get_instance());
@@ -85,6 +92,7 @@ void VisualInstance::_notification(int p_what) {
 			VisualServer::get_singleton()->instance_set_scenario( instance, RID() );
 			VisualServer::get_singleton()->instance_set_room(instance,RID());
 			VisualServer::get_singleton()->instance_attach_skeleton( instance, RID() );
+			VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() );
 
 
 		} break;

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

@@ -47,6 +47,7 @@ class VisualInstance : public Spatial {
 
 	RID _get_visual_instance_rid() const;
 
+
 protected:
 
 

+ 1 - 1
scene/animation/animation_player.cpp

@@ -927,7 +927,7 @@ void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float
 
 
 	StringName next=animation_get_next(p_name);
-	if (next!=StringName()) {
+	if (next!=StringName() && animation_set.has(next)) {
 		queue(next);
 	}
 }

+ 3 - 0
scene/main/scene_main_loop.h

@@ -226,6 +226,9 @@ public:
 
 	void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize);
 
+	//void change_scene(const String& p_path);
+	//Node *get_loaded_scene();
+
 #ifdef TOOLS_ENABLED
 	void set_edited_scene_root(Node *p_node);
 	Node *get_edited_scene_root() const;

+ 26 - 5
scene/main/viewport.cpp

@@ -95,8 +95,8 @@ void Viewport::_update_stretch_transform() {
 
 	if (size_override_stretch && size_override) {
 
-		print_line("sive override size "+size_override_size);
-		print_line("rect size "+rect.size);
+		//print_line("sive override size "+size_override_size);
+		//print_line("rect size "+rect.size);
 		stretch_transform=Matrix32();
 		Size2 scale = rect.size/(size_override_size+size_override_margin*2);
 		stretch_transform.scale(scale);
@@ -135,7 +135,9 @@ void Viewport::_update_rect() {
 	}
 	vr.width=rect.size.width;
 	vr.height=rect.size.height;
+
 	VisualServer::get_singleton()->viewport_set_rect(viewport,vr);
+	last_vp_rect=rect;
 
 	if (canvas_item.is_valid()) {
 		VisualServer::get_singleton()->canvas_item_set_custom_rect(canvas_item,true,rect);
@@ -513,6 +515,7 @@ void Viewport::set_rect(const Rect2& p_rect) {
 	if (rect==p_rect)
 		return;
 	rect=p_rect;
+
 	_update_rect();
 	_update_stretch_transform();
 
@@ -1029,13 +1032,16 @@ void Viewport::_make_input_local(InputEvent& ev) {
 			Matrix32 ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
 			Vector2 g = ai.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y));
 			Vector2 l = ai.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y));
-			Vector2 r = ai.xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
+			Vector2 r = ai.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
+			Vector2 s = ai.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y));
 			ev.mouse_motion.x=l.x;
 			ev.mouse_motion.y=l.y;
 			ev.mouse_motion.global_x=g.x;
 			ev.mouse_motion.global_y=g.y;
 			ev.mouse_motion.relative_x=r.x;
 			ev.mouse_motion.relative_y=r.y;
+			ev.mouse_motion.speed_x=s.x;
+			ev.mouse_motion.speed_y=s.y;
 
 		} break;
 		case InputEvent::SCREEN_TOUCH: {
@@ -1050,8 +1056,8 @@ void Viewport::_make_input_local(InputEvent& ev) {
 
 			Matrix32 ai = get_final_transform().affine_inverse() * _get_input_pre_xform();
 			Vector2 t = ai.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y));
-			Vector2 r = ai.xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
-			Vector2 s = ai.xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
+			Vector2 r = ai.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
+			Vector2 s = ai.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
 			ev.screen_drag.x=t.x;
 			ev.screen_drag.y=t.y;
 			ev.screen_drag.relative_x=r.x;
@@ -1185,6 +1191,21 @@ void Viewport::set_physics_object_picking(bool p_enable) {
 
 }
 
+
+Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
+
+	Matrix32 xf = get_final_transform();
+	return xf.xform(p_viewport_coords);
+
+
+}
+
+Vector2 Viewport::get_camera_rect_size() const {
+
+	return last_vp_rect.size;
+}
+
+
 bool Viewport::get_physics_object_picking() {
 
 

+ 5 - 0
scene/main/viewport.h

@@ -110,6 +110,7 @@ friend class RenderTargetTexture;
 	Size2 size_override_size;
 	Size2 size_override_margin;
 
+	Rect2 last_vp_rect;
 
 	bool transparent_bg;
 	bool render_target_vflip;
@@ -229,6 +230,10 @@ public:
 	RenderTargetUpdateMode get_render_target_update_mode() const;
 	Ref<RenderTargetTexture> get_render_target_texture() const;
 
+
+	Vector2 get_camera_coords(const Vector2& p_viewport_coords) const;
+	Vector2 get_camera_rect_size() const;
+
 	void queue_screen_capture();
 	Image get_screen_capture() const;
 

+ 1 - 0
scene/register_scene_types.cpp

@@ -394,6 +394,7 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<VisibilityNotifier>();
 	ObjectTypeDB::register_type<VisibilityEnabler>();
 	ObjectTypeDB::register_type<BakedLightInstance>();
+	ObjectTypeDB::register_type<BakedLightSampler>();
 	ObjectTypeDB::register_type<WorldEnvironment>();
 
 	//scenariofx	

+ 92 - 2
scene/resources/baked_light.cpp

@@ -23,6 +23,27 @@ 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);
+}
+
 
 
 
@@ -199,6 +220,43 @@ 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_energy_multiplier(float p_multiplier){
 
 	energy_multiply=p_multiplier;
@@ -329,6 +387,13 @@ void BakedLight::_bind_methods(){
 	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);
@@ -357,6 +422,18 @@ void BakedLight::_bind_methods(){
 	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_format","format"),&BakedLight::set_format);
 	ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format);
 
@@ -384,17 +461,24 @@ void BakedLight::_bind_methods(){
 	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"));
 
 	BIND_CONSTANT(  MODE_OCTREE );
 	BIND_CONSTANT(  MODE_LIGHTMAPS );
@@ -415,18 +499,24 @@ BakedLight::BakedLight() {
 	lattice_subdiv=4;
 	plot_size=2.5;
 	bounces=1;
-	energy_multiply=1.0;
-	gamma_adjust=1.0;
+	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_RGB;
 	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();

+ 25 - 0
scene/resources/baked_light.h

@@ -26,6 +26,7 @@ public:
 		BAKE_SPECULAR,
 		BAKE_TRANSLUCENT,
 		BAKE_CONSERVE_ENERGY,
+		BAKE_LINEAR_COLOR,
 		BAKE_MAX
 	};
 
@@ -50,6 +51,10 @@ private:
 	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;
@@ -99,6 +104,18 @@ public:
 	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_bake_flag(BakeFlags p_flags,bool p_enable);
 	bool get_bake_flag(BakeFlags p_flags) const;
 
@@ -114,6 +131,14 @@ public:
 	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;

+ 4 - 0
scene/resources/material.cpp

@@ -550,6 +550,10 @@ void ShaderMaterial::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"), &ShaderMaterial::set_shader );
 	ObjectTypeDB::bind_method(_MD("get_shader:Shader"), &ShaderMaterial::get_shader );
+
+	ObjectTypeDB::bind_method(_MD("set_shader_param","param","value:var"), &ShaderMaterial::set_shader_param);
+	ObjectTypeDB::bind_method(_MD("get_shader_param:var","param"), &ShaderMaterial::get_shader_param);
+
 	ObjectTypeDB::bind_method(_MD("_shader_changed"), &ShaderMaterial::_shader_changed );
 }
 

+ 7 - 0
servers/visual/rasterizer.h

@@ -503,6 +503,7 @@ public:
 
 		VS::BakedLightMode mode;
 		RID octree_texture;
+		RID light_texture;
 		float color_multiplier; //used for both lightmaps and octree
 		Transform octree_transform;
 		Map<int,RID> lightmaps;
@@ -514,6 +515,7 @@ public:
 		float lightmap_multiplier;
 		int octree_steps;
 		Vector2 octree_tex_pixel_size;
+		Vector2 light_tex_pixel_size;
 	};
 
 	struct InstanceData {
@@ -521,6 +523,7 @@ public:
 		Transform transform;
 		RID skeleton;
 		RID material_override;
+		RID sampled_light;
 		Vector<RID> light_instances;
 		Vector<float> morph_values;
 		BakedLightData *baked_light;
@@ -586,6 +589,10 @@ public:
 	virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value)=0;
 	virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const=0;
 
+	/* SAMPLED LIGHT */
+	virtual RID sampled_light_dp_create(int p_width,int p_height)=0;
+	virtual void sampled_light_dp_update(RID p_sampled_light,const Color *p_data,float p_multiplier)=0;
+
 		
 	/*MISC*/
 	

+ 20 - 0
servers/visual/rasterizer_dummy.cpp

@@ -1679,6 +1679,18 @@ Variant RasterizerDummy::environment_fx_get_param(RID p_env,VS::EnvironmentFxPar
 
 }
 
+
+RID RasterizerDummy::sampled_light_dp_create(int p_width,int p_height) {
+
+	return sampled_light_owner.make_rid(memnew(SampledLight));
+}
+
+void RasterizerDummy::sampled_light_dp_update(RID p_sampled_light, const Color *p_data, float p_multiplier) {
+
+
+}
+
+
 /*MISC*/
 
 bool RasterizerDummy::is_texture(const RID& p_rid) const {
@@ -1816,6 +1828,14 @@ void RasterizerDummy::free(const RID& p_rid) {
 		Environment *env = environment_owner.get( p_rid );
 		environment_owner.free(p_rid);
 		memdelete( env );
+	} else if (sampled_light_owner.owns(p_rid)) {
+
+		SampledLight *sampled_light = sampled_light_owner.get( p_rid );
+		ERR_FAIL_COND(!sampled_light);
+
+		sampled_light_owner.free(p_rid);
+		memdelete( sampled_light );
+
 	};
 }
 

+ 11 - 0
servers/visual/rasterizer_dummy.h

@@ -353,6 +353,13 @@ class RasterizerDummy : public Rasterizer {
 
 	mutable RID_Owner<Environment> environment_owner;
 
+	struct SampledLight {
+
+		int w,h;
+	};
+
+	mutable RID_Owner<SampledLight> sampled_light_owner;
+
 	struct ShadowBuffer;
 
 	struct LightInstance {
@@ -713,6 +720,10 @@ public:
 	virtual void environment_fx_set_param(RID p_env,VS::EnvironmentFxParam p_param,const Variant& p_value);
 	virtual Variant environment_fx_get_param(RID p_env,VS::EnvironmentFxParam p_param) const;
 
+	/* SAMPLED LIGHT */
+	virtual RID sampled_light_dp_create(int p_width,int p_height);
+	virtual void sampled_light_dp_update(RID p_sampled_light,const Color *p_data,float p_multiplier);
+
 
 	/*MISC*/
 

+ 632 - 7
servers/visual/visual_server_raster.cpp

@@ -1109,8 +1109,12 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
 
 		int tex_w;
 		int tex_h;
+		int light_tex_w;
+		int light_tex_h;
 		bool is16;
+		bool has_light_tex=false;
 		{
+
 			DVector<uint8_t>::Read r=p_octree.read();
 			tex_w = decode_uint32(&r[0]);
 			tex_h = decode_uint32(&r[4]);
@@ -1123,7 +1127,22 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
 			baked_light->data.octree_steps=decode_uint32(&r[16]);
 			baked_light->data.octree_tex_pixel_size.x=1.0/tex_w;
 			baked_light->data.octree_tex_pixel_size.y=1.0/tex_h;
+
 			baked_light->data.texture_multiplier=decode_uint32(&r[20]);
+			light_tex_w=decode_uint16(&r[24]);
+			light_tex_h=decode_uint16(&r[26]);
+			print_line("ltexw "+itos(light_tex_w));
+			print_line("ltexh "+itos(light_tex_h));
+
+			if (light_tex_w>0 && light_tex_h>0) {
+				baked_light->data.light_tex_pixel_size.x=1.0/light_tex_w;
+				baked_light->data.light_tex_pixel_size.y=1.0/light_tex_h;
+				has_light_tex=true;
+			} else {
+				baked_light->data.light_tex_pixel_size=baked_light->data.octree_tex_pixel_size;
+
+			}
+
 
 
 			baked_light->octree_aabb.pos.x=decode_float(&r[32]);
@@ -1141,12 +1160,33 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
 
 				rasterizer->free(baked_light->data.octree_texture);
 				baked_light->data.octree_texture=RID();
+				baked_light->octree_tex_size.x=0;
+				baked_light->octree_tex_size.y=0;
+			}
+		}
+
+		if (baked_light->data.light_texture.is_valid()) {
+			if (!has_light_tex || light_tex_w!=baked_light->light_tex_size.x || light_tex_h!=baked_light->light_tex_size.y) {
+				rasterizer->free(baked_light->data.light_texture);
+				baked_light->data.light_texture=RID();
+				baked_light->light_tex_size.x=0;
+				baked_light->light_tex_size.y=0;
 			}
 		}
 
 		if (!baked_light->data.octree_texture.is_valid()) {
 			baked_light->data.octree_texture=rasterizer->texture_create();
 			rasterizer->texture_allocate(baked_light->data.octree_texture,tex_w,tex_h,Image::FORMAT_RGBA,TEXTURE_FLAG_FILTER);
+			baked_light->octree_tex_size.x=tex_w;
+			baked_light->octree_tex_size.y=tex_h;
+		}
+
+		if (!baked_light->data.light_texture.is_valid() && has_light_tex) {
+			baked_light->data.light_texture=rasterizer->texture_create();
+			rasterizer->texture_allocate(baked_light->data.light_texture,light_tex_w,light_tex_h,Image::FORMAT_RGBA,TEXTURE_FLAG_FILTER);
+			baked_light->light_tex_size.x=light_tex_w;
+			baked_light->light_tex_size.y=light_tex_h;
+
 		}
 
 		Image img(tex_w,tex_h,0,Image::FORMAT_RGBA,p_octree);
@@ -1159,6 +1199,7 @@ void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<
 
 }
 
+
 DVector<uint8_t> VisualServerRaster::baked_light_get_octree(RID p_baked_light) const{
 
 
@@ -1174,6 +1215,67 @@ DVector<uint8_t> VisualServerRaster::baked_light_get_octree(RID p_baked_light) c
 	}
 }
 
+void VisualServerRaster::baked_light_set_light(RID p_baked_light,const DVector<uint8_t> p_light) {
+
+	VS_CHANGED;
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+	ERR_FAIL_COND(p_light.size()==0);
+
+	int tex_w=baked_light->light_tex_size.x;
+	int tex_h=baked_light->light_tex_size.y;
+
+	ERR_FAIL_COND(tex_w==0 && tex_h==0);
+	ERR_FAIL_COND(!baked_light->data.light_texture.is_valid());
+
+
+
+	print_line("w: "+itos(tex_w)+" h: "+itos(tex_h)+" lightsize: "+itos(p_light.size()));
+
+	Image img(tex_w,tex_h,0,Image::FORMAT_RGBA,p_light);
+	rasterizer->texture_set_data(baked_light->data.light_texture,img);
+
+
+
+}
+
+DVector<uint8_t> VisualServerRaster::baked_light_get_light(RID p_baked_light) const{
+
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND_V(!baked_light,DVector<uint8_t>());
+
+	if (rasterizer->is_texture(baked_light->data.light_texture)) {
+
+		Image img = rasterizer->texture_get_data(baked_light->data.light_texture);
+		return img.get_data();
+	} else {
+		return DVector<uint8_t>();
+	}
+}
+
+
+
+void VisualServerRaster::baked_light_set_sampler_octree(RID p_baked_light, const DVector<int> &p_sampler) {
+
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+
+	baked_light->sampler=p_sampler;
+
+
+
+}
+
+DVector<int> VisualServerRaster::baked_light_get_sampler_octree(RID p_baked_light) const {
+
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND_V(!baked_light,DVector<int>());
+
+	return baked_light->sampler;
+
+}
+
+
 void VisualServerRaster::baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id){
 
 	VS_CHANGED;
@@ -1192,6 +1294,84 @@ void VisualServerRaster::baked_light_clear_lightmaps(RID p_baked_light){
 }
 
 
+/* BAKED LIGHT SAMPLER */
+
+RID VisualServerRaster::baked_light_sampler_create() {
+
+	BakedLightSampler * blsamp = memnew( BakedLightSampler );
+	RID rid = baked_light_sampler_owner.make_rid(blsamp);
+	_update_baked_light_sampler_dp_cache(blsamp);
+	return rid;
+}
+
+void VisualServerRaster::baked_light_sampler_set_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param,float p_value){
+
+	VS_CHANGED;
+	BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+	ERR_FAIL_COND(!blsamp);
+	ERR_FAIL_INDEX(p_param,BAKED_LIGHT_SAMPLER_MAX);
+	blsamp->params[p_param]=p_value;
+	_dependency_queue_update(p_baked_light_sampler,true);
+}
+
+float VisualServerRaster::baked_light_sampler_get_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param) const{
+
+
+	BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+	ERR_FAIL_COND_V(!blsamp,0);
+	ERR_FAIL_INDEX_V(p_param,BAKED_LIGHT_SAMPLER_MAX,0);
+	return blsamp->params[p_param];
+}
+
+void VisualServerRaster::_update_baked_light_sampler_dp_cache(BakedLightSampler * blsamp) {
+
+	int res = blsamp->resolution;
+	blsamp->dp_cache.resize(res*res*2);
+	Vector3 *dp_normals=blsamp->dp_cache.ptr();
+
+	for(int p=0;p<2;p++) {
+		float sign = p==0?1:-1;
+		int ofs = res*res*p;
+		for(int i=0;i<res;i++) {
+			for(int j=0;j<res;j++) {
+
+				Vector2 v(
+					(i/float(res))*2.0-1.0,
+					(j/float(res))*2.0-1.0
+				);
+
+				float l=v.length();
+				if (l>1.0) {
+					v/=l;
+					l=1.0; //clamp to avoid imaginary
+				}
+				v*=(2*l)/(l*l+1); //inverse of the dual paraboloid function
+				Vector3 n = Vector3(v.x,v.y,sign*sqrtf(MAX(1 - v.dot(v),0))); //reconstruction of z
+				n.y*=sign;
+				dp_normals[j*res+i+ofs]=n;
+			}
+		}
+	}
+
+}
+
+void VisualServerRaster::baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution){
+
+	ERR_FAIL_COND(p_resolution<4 && p_resolution>64);
+	VS_CHANGED;
+	BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+	ERR_FAIL_COND(!blsamp);
+	blsamp->resolution=p_resolution;
+	_update_baked_light_sampler_dp_cache(blsamp);
+
+}
+int VisualServerRaster::baked_light_sampler_get_resolution(RID p_baked_light_sampler) const{
+
+	BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
+	ERR_FAIL_COND_V(!blsamp,0);
+	return blsamp->resolution;
+}
+
 /* CAMERA API */
 
 RID VisualServerRaster::camera_create() {
@@ -1943,6 +2123,20 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) {
 
 		}
 
+		if (instance->baked_light_sampler_info) {
+
+			while (instance->baked_light_sampler_info->owned_instances.size()) {
+
+				instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID());
+			}
+
+			if (instance->baked_light_sampler_info->sampled_light.is_valid()) {
+				rasterizer->free(instance->baked_light_sampler_info->sampled_light);
+			}
+			memdelete( instance->baked_light_sampler_info );
+			instance->baked_light_sampler_info=NULL;
+		}
+
 		instance->data.morph_values.clear();
 
 	}
@@ -1992,6 +2186,16 @@ void VisualServerRaster::instance_set_base(RID p_instance, RID p_base) {
 
 			//instance->portal_info = memnew(Instance::PortalInfo);
 			//instance->portal_info->portal=portal_owner.get(p_base);
+		} else if (baked_light_sampler_owner.owns(p_base)) {
+
+
+			instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER;
+			instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo);
+			instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base);
+
+			//instance->portal_info = memnew(Instance::PortalInfo);
+			//instance->portal_info->portal=portal_owner.get(p_base);
+
 		} else {
 			ERR_EXPLAIN("Invalid base RID for instance!")
 			ERR_FAIL();
@@ -2607,11 +2811,50 @@ RID VisualServerRaster::instance_geometry_get_baked_light(RID p_instance) const{
 	const Instance *instance = instance_owner.get( p_instance );
 	ERR_FAIL_COND_V( !instance,RID() );
 	if (instance->baked_light)
-		instance->baked_light->self;
+		return instance->baked_light->self;
 	return RID();
 
 }
 
+
+void VisualServerRaster::instance_geometry_set_baked_light_sampler(RID p_instance,RID p_baked_light_sampler) {
+
+	VS_CHANGED;
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND( !instance );
+
+	if (instance->sampled_light) {
+		instance->sampled_light->baked_light_sampler_info->owned_instances.erase(instance);
+		instance->data.sampled_light=RID();
+	}
+
+	if(p_baked_light_sampler.is_valid()) {
+		Instance *sampler_instance = instance_owner.get( p_baked_light_sampler );
+		ERR_FAIL_COND( !sampler_instance );
+		ERR_FAIL_COND( sampler_instance->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER );
+		instance->sampled_light=sampler_instance;
+		instance->sampled_light->baked_light_sampler_info->owned_instances.insert(instance);
+	} else {
+		instance->sampled_light=NULL;
+	}
+
+	instance->data.sampled_light=RID();
+
+}
+
+RID VisualServerRaster::instance_geometry_get_baked_light_sampler(RID p_instance) const {
+
+	Instance *instance = instance_owner.get( p_instance );
+	ERR_FAIL_COND_V( !instance,RID() );
+
+	if (instance->sampled_light)
+		return instance->sampled_light->self;
+	else
+		return RID();
+
+}
+
+
 void VisualServerRaster::instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id){
 
 	VS_CHANGED;
@@ -2747,6 +2990,13 @@ void VisualServerRaster::_update_instance(Instance *p_instance) {
 			pairable=true;
 		}
 
+		if (p_instance->base_type == INSTANCE_BAKED_LIGHT_SAMPLER) {
+
+			pairable_mask=(1<<INSTANCE_BAKED_LIGHT);
+			pairable=true;
+		}
+
+
 		if (!p_instance->room && (1<<p_instance->base_type)&INSTANCE_GEOMETRY_MASK) {
 
 			base_type|=INSTANCE_ROOMLESS_MASK;
@@ -2859,6 +3109,16 @@ void VisualServerRaster::_update_instance_aabb(Instance *p_instance) {
 			new_aabb=baked_light->octree_aabb;
 
 		} break;
+		case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: {
+
+			BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base_rid );
+			ERR_FAIL_COND(!baked_light_sampler);
+			float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+
+			new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2));
+
+		} break;
+
 		default: {}
 	}
 
@@ -3762,6 +4022,17 @@ void VisualServerRaster::free( RID p_rid ) {
 		baked_light_owner.free(p_rid);
 		memdelete(baked_light);
 
+	} else if (baked_light_sampler_owner.owns(p_rid)) {
+
+		_free_attached_instances(p_rid);
+
+		BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get(p_rid);
+		ERR_FAIL_COND(!baked_light_sampler);
+		//if (baked_light->data.octree_texture.is_valid())
+		//	rasterizer->free(baked_light->data.octree_texture);
+		baked_light_sampler_owner.free(p_rid);
+		memdelete(baked_light_sampler);
+
 	} else if (camera_owner.owns(p_rid)) {
 		// delete te camera
 		
@@ -3813,7 +4084,9 @@ void VisualServerRaster::free( RID p_rid ) {
 		instance_set_room(p_rid,RID());
 		instance_set_scenario(p_rid,RID());
 		instance_geometry_set_baked_light(p_rid,RID());
+		instance_geometry_set_baked_light_sampler(p_rid,RID());
 		instance_set_base(p_rid,RID());
+
 		if (instance->data.skeleton.is_valid())
 			instance_attach_skeleton(p_rid,RID());
 
@@ -4957,6 +5230,15 @@ void* VisualServerRaster::instance_pair(void *p_self, OctreeElementID, Instance
 		//attempt to conncet portal A (will go through B anyway)
 		//this is a little hackish, but works fine in practice
 
+	} else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+		if (B->base_type==INSTANCE_BAKED_LIGHT) {
+			SWAP(A,B);
+		}
+
+		ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL);
+		B->baked_light_sampler_info->baked_lights.insert(A);
+
 	} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
 
 		if (B->base_type==INSTANCE_ROOM)
@@ -5006,6 +5288,15 @@ void VisualServerRaster::instance_unpair(void *p_self, OctreeElementID, Instance
 		self->_portal_attempt_connect(A);
 		self->_portal_attempt_connect(B);
 
+	} else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+
+		if (B->base_type==INSTANCE_BAKED_LIGHT) {
+			SWAP(A,B);
+		}
+
+		ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER);
+		B->baked_light_sampler_info->baked_lights.erase(A);
+
 	} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
 
 		if (B->base_type==INSTANCE_ROOM)
@@ -5197,6 +5488,308 @@ void VisualServerRaster::_cull_room(Camera *p_camera, Instance *p_room,Instance
 	
 }
 
+void VisualServerRaster::_process_sampled_light(const Transform& p_camera,Instance *p_sampled_light,bool p_linear_colorspace) {
+
+
+	BakedLightSampler *sampler_opts = p_sampled_light->baked_light_sampler_info->sampler;
+	int res = sampler_opts->resolution;
+	int dp_size = res*res*2;
+	Color * dp_map = (Color*)alloca( sizeof(Color)*dp_size); //allocate the dual parabolloid colors
+	Vector3 * dp_normals = (Vector3*)alloca( sizeof(Vector3)*dp_size); //allocate the dual parabolloid normals
+	const Vector3 * dp_src_normals = p_sampled_light->baked_light_sampler_info->sampler->dp_cache.ptr();
+
+
+	if (!p_sampled_light->baked_light_sampler_info->sampled_light.is_valid() || p_sampled_light->baked_light_sampler_info->resolution!=sampler_opts->resolution) {
+		if (p_sampled_light->baked_light_sampler_info->sampled_light.is_valid()) {
+			rasterizer->free(p_sampled_light->baked_light_sampler_info->sampled_light);
+		}
+
+		p_sampled_light->baked_light_sampler_info->resolution=sampler_opts->resolution;
+		p_sampled_light->baked_light_sampler_info->sampled_light=rasterizer->sampled_light_dp_create(sampler_opts->resolution,sampler_opts->resolution*2);
+
+
+	}
+
+
+	zeromem(dp_map,sizeof(Color)*dp_size);
+	bool valid=false;
+	int samples=0;
+
+
+	for(Set<Instance*>::Element *E=p_sampled_light->baked_light_sampler_info->baked_lights.front();E;E=E->next()) {
+
+		Instance *bl = E->get();
+		if (bl->baked_light_info->baked_light->sampler.size()==0)
+			continue; //not usable
+
+
+		Matrix3 norm_xform = bl->baked_light_info->affine_inverse.basis;//.inverse();
+		for(int i=0;i<dp_size;i++) {
+			dp_normals[i]=norm_xform.xform(dp_src_normals[i]).normalized();
+		}
+
+		//normals in place
+
+
+		//sample octree
+
+		float r = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+		float att = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_ATTENUATION];
+		float str = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_STRENGTH];
+		Vector3 s = p_sampled_light->data.transform.basis.get_scale();
+
+		r*=MAX(MAX(s.x,s.y),s.z);
+		AABB sample_aabb= bl->data.transform.affine_inverse().xform(AABB(Vector3(-r,-r,-r)+p_sampled_light->data.transform.origin,Vector3(r*2,r*2,r*2)));
+		//ok got octree local AABB
+
+		DVector<int>::Read rp = bl->baked_light_info->baked_light->sampler.read();
+		const int *rptr = rp.ptr();
+
+		int first = rptr[1];
+		int depth = rptr[2];
+		bool islinear = rptr[3]&1;
+		depth+=1;
+
+		AABB aabb;
+		aabb.pos.x=decode_float((const uint8_t*)&rptr[4]);
+		aabb.pos.y=decode_float((const uint8_t*)&rptr[5]);
+		aabb.pos.z=decode_float((const uint8_t*)&rptr[6]);
+		aabb.size.x=decode_float((const uint8_t*)&rptr[7]);
+		aabb.size.y=decode_float((const uint8_t*)&rptr[8]);
+		aabb.size.z=decode_float((const uint8_t*)&rptr[9]);
+
+		uint32_t *stack=(uint32_t*)alloca(depth*sizeof(uint32_t));
+		int *stack_ptr=(int*)alloca(depth*sizeof(int));
+		AABB *aabb_stack=(AABB*)alloca(depth*sizeof(AABB));
+
+		stack[0]=0;
+		stack_ptr[0]=first;
+		aabb_stack[0]=aabb;
+		Vector3 center = sample_aabb.pos + sample_aabb.size * 0.5;
+
+
+		int stack_pos=0;
+		Color max_col;
+
+		//int reso = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO];
+
+		int lalimit = sample_aabb.get_longest_axis_index();
+		float limit = sampler_opts->params[VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO]*sample_aabb.size[lalimit];
+
+
+		while(true) {
+
+
+			bool leaf = (rptr[ stack_ptr[stack_pos] ]>>16)==0;
+
+			if (aabb_stack[stack_pos].size[lalimit]<limit) {
+				leaf=true;
+			}
+
+
+			if (leaf) {
+
+				Vector3 from = aabb_stack[stack_pos].pos + aabb_stack[stack_pos].size * 0.5;
+				Vector3 norm = (from-center).normalized();
+
+
+				Color col;
+				col.r = ((rptr[ stack_ptr[stack_pos] ]&0xFFFF)/256.0);
+				col.g = ((rptr[ stack_ptr[stack_pos]+1 ]>>16)/256.0);
+				col.b = ((rptr[ stack_ptr[stack_pos]+1 ]&0xFFFF)/256.0);
+
+
+				max_col.r = MAX(max_col.r,col.r);
+				max_col.g = MAX(max_col.g,col.g);
+				max_col.b = MAX(max_col.b,col.b);
+
+				if (!islinear && p_linear_colorspace) {
+					col=col.to_linear();
+				}
+
+				float distance;
+
+				if (aabb_stack[stack_pos].has_point(center)) {
+					distance=0;
+				} else {
+
+					Vector3 support = aabb_stack[stack_pos].get_support(norm);
+					distance = Math::absf(norm.dot(support)-norm.dot(center));
+
+				}
+
+				if (distance>r)
+					distance=r;
+
+				float mult = powf(1.0-distance/r,att)*str;
+				if (mult>0) {
+					col.r*=mult;
+					col.g*=mult;
+					col.b*=mult;
+
+
+
+					for(int i=0;i<dp_size;i++) {
+						float mult2 = norm.dot(dp_normals[i]);
+						if (mult2<0)
+							mult2=0;
+						Color col2(col.r*mult2,col.g*mult2,col.b*mult2,1.0);
+						dp_map[i].r=MAX(dp_map[i].r,col2.r);
+						dp_map[i].g=MAX(dp_map[i].g,col2.g);
+						dp_map[i].b=MAX(dp_map[i].b,col2.b);
+					}
+
+				}
+
+				samples++;
+				//nothing is valid unless you hit a leaf
+				valid=true;
+				stack_pos--;
+			} else if ((stack[stack_pos]&0xFF)<8) {
+
+				int i = stack[stack_pos]&0xFF;
+				int base = (stack[stack_pos]>>8);
+
+				if (!((rptr[ stack_ptr[stack_pos] ]>>16)&(1<<i))) {
+					//no bit, no test
+					stack[stack_pos]=(base<<8)+(i+1);
+					continue;
+				}
+
+				stack[stack_pos]=((base+1)<<8)+(i+1);
+
+				AABB child_aabb = aabb_stack[stack_pos];
+				child_aabb.size*=0.5;
+				if (i&1)
+					child_aabb.pos.x+=child_aabb.size.x;
+				if (i&2)
+					child_aabb.pos.y+=child_aabb.size.y;
+				if (i&4)
+					child_aabb.pos.z+=child_aabb.size.z;
+
+				if (!child_aabb.intersects(sample_aabb)) {
+					continue;
+				}
+
+				if (child_aabb.encloses(sample_aabb)) {
+					stack[stack_pos]=(base<<8)|8; //don't test the rest
+				}
+
+				stack_pos++;
+				ERR_FAIL_COND(stack_pos>=depth);
+
+				stack[stack_pos]=0;
+				stack_ptr[stack_pos]=rptr[ stack_ptr[stack_pos-1]+2+base ];
+				aabb_stack[stack_pos]=child_aabb;
+			} else {
+				stack_pos--;
+				if (stack_pos<0)
+					break;
+			}
+		}
+
+
+	}
+
+	//print_line("samples "+itos(samples) );
+
+	if (valid) {
+
+		for(int i=0;i<res;i++) {
+			//average seams to avoid aliasing
+			{
+				//top
+				int ofs1 = i;
+				int ofs2 = dp_size-res+i;
+				Color avg(
+					(dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+					(dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+					(dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+					1.0
+				);
+				dp_map[ofs1]=avg;
+				dp_map[ofs2]=avg;
+			}
+			{
+				//bottom
+				int ofs1 = res*res-res+i;
+				int ofs2 = res*res+i;
+				Color avg(
+					(dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+					(dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+					(dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+					1.0
+				);
+				dp_map[ofs1]=avg;
+				dp_map[ofs2]=avg;
+			}
+			{
+				//left
+				int ofs1 = i*res;
+				int ofs2 = res*res+(res-i-1)*res;
+				Color avg(
+					(dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+					(dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+					(dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+					1.0
+				);
+				dp_map[ofs1]=avg;
+				dp_map[ofs2]=avg;
+			}
+			{
+				//right
+				int ofs1 = i*res+(res-1);
+				int ofs2 = res*res+(res-i-1)*res+(res-1);
+				Color avg(
+					(dp_map[ofs1].r+dp_map[ofs2].r)*0.5,
+					(dp_map[ofs1].g+dp_map[ofs2].g)*0.5,
+					(dp_map[ofs1].b+dp_map[ofs2].b)*0.5,
+					1.0
+				);
+				dp_map[ofs1]=avg;
+				dp_map[ofs2]=avg;
+			}
+
+		}
+
+		rasterizer->sampled_light_dp_update(p_sampled_light->baked_light_sampler_info->sampled_light,dp_map,1.0);
+		for(Set<Instance*>::Element *F=p_sampled_light->baked_light_sampler_info->owned_instances.front();F;F=F->next()) {
+
+			F->get()->data.sampled_light=p_sampled_light->baked_light_sampler_info->sampled_light;
+		}
+
+
+	} else {
+
+		for(Set<Instance*>::Element *F=p_sampled_light->baked_light_sampler_info->owned_instances.front();F;F=F->next()) {
+
+			F->get()->data.sampled_light=RID(); //do not use because nothing close
+		}
+	}
+
+
+
+
+/*
+		highp vec3 vtx = vertex_interp;
+		vtx.z*=dual_paraboloid.y; //side to affect
+		vtx.z+=0.01;
+		dp_clip=vtx.z;
+		highp float len=length( vtx );
+		vtx=normalize(vtx);
+		vtx.xy/=1.0+vtx.z;
+		vtx.z = len*dual_paraboloid.x; // it's a reciprocal(len - z_near) / (z_far - z_near);
+		vtx+=normalize(vtx)*0.025;
+		vtx.z = vtx.z * 2.0 - 1.0; // fit to clipspace
+		vertex_interp=vtx;
+*/
+
+
+
+
+}
+
+
 void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario) {
 
 
@@ -5248,6 +5841,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 	/* STEP 2 - CULL */
 	int cull_count = p_scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL);
 	light_cull_count=0;
+	light_samplers_culled=0;
 
 /*	print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0));
 	print_line("OTO: "+itos(p_scenario->octree.get_octant_count()));
@@ -5408,6 +6002,8 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 
 					keep=true;
 				}
+
+
 			}
 
 
@@ -5420,6 +6016,13 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 					cull_range.min=min;
 				if (max>cull_range.max)
 					cull_range.max=max;
+
+				if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) {
+					if (light_samplers_culled<MAX_LIGHT_SAMPLERS) {
+						light_sampler_cull_result[light_samplers_culled++]=ins->sampled_light;
+						ins->sampled_light->baked_light_sampler_info->last_pass=render_pass;
+					}
+				}
 			}
 			
 		}
@@ -5499,7 +6102,7 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 		
 	}
 
-	{
+	{ //this should eventually change to
 		//assign shadows by distance to camera
 		SortArray<Instance*,_InstanceLightsort> sorter;
 		sorter.sort(light_cull_result,light_cull_count);
@@ -5520,10 +6123,8 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 		}
 	}
 
+	/* ENVIRONMENT */
 
-
-	/* STEP 6 - PROCESS GEOMETRY AND DRAW SCENE*/
-		
 	RID environment;
 	if (p_camera->env.is_valid()) //camera has more environment priority
 		environment=p_camera->env;
@@ -5532,6 +6133,22 @@ void VisualServerRaster::_render_camera(Viewport *p_viewport,Camera *p_camera, S
 	else
 		environment=p_scenario->fallback_environment;
 
+
+	/* STEP 6 - SAMPLE BAKED LIGHT */
+
+	bool islinear =false;
+	if (environment.is_valid()) {
+		islinear = rasterizer->environment_is_fx_enabled(environment,VS::ENV_FX_SRGB);
+	}
+
+	for(int i=0;i<light_samplers_culled;i++) {
+
+		_process_sampled_light(p_camera->transform,light_sampler_cull_result[i],islinear);
+	}
+
+	/* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/
+		
+
 	rasterizer->begin_scene(p_viewport->viewport_data,environment,p_scenario->debug);
 	rasterizer->set_viewport(viewport_rect);	
 	
@@ -5838,6 +6455,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 	desired_rect.x+=p_ofs_x;
 	desired_rect.y+=p_ofs_y;
 
+
 	// if the viewport is different than the actual one, change it
 
 	if ( p_viewport->render_target.is_valid() || viewport_rect.x != desired_rect.x ||
@@ -5847,7 +6465,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
 
 
 		viewport_rect=desired_rect;
-		rasterizer->set_viewport(viewport_rect);		
+		rasterizer->set_viewport(viewport_rect);
 
 	}
 
@@ -5995,7 +6613,14 @@ void VisualServerRaster::_draw_viewports() {
 		int window_w = OS::get_singleton()->get_video_mode(E->get()).width;
 		int window_h = OS::get_singleton()->get_video_mode(E->get()).height;
 
-		_draw_viewport(vp,0,0,window_w,window_h);
+		Rect2 r(0,0,vp->rect.width,vp->rect.height);
+		if (r.size.width==0)
+			r.size.width=window_w;
+		if (r.size.height==0)
+			r.size.height=window_w;
+
+
+		_draw_viewport(vp,r.pos.x,r.pos.y,r.size.width,r.size.height);
 	}
 
 

+ 66 - 0
servers/visual/visual_server_raster.h

@@ -51,6 +51,7 @@ class VisualServerRaster : public VisualServer {
 		MAX_LIGHTS_CULLED=256,
 		MAX_ROOM_CULL=32,
 		MAX_EXTERIOR_PORTALS=128,
+		MAX_LIGHT_SAMPLERS=256,
 		INSTANCE_ROOMLESS_MASK=(1<<20)
 
 
@@ -90,12 +91,29 @@ class VisualServerRaster : public VisualServer {
 	struct BakedLight {
 
 		Rasterizer::BakedLightData data;
+		DVector<int> sampler;
 		AABB octree_aabb;
 		Size2i octree_tex_size;
+		Size2i light_tex_size;
 
 	};
 
+	struct BakedLightSampler {
 
+		float params[BAKED_LIGHT_SAMPLER_MAX];
+		int resolution;
+		Vector<Vector3> dp_cache;
+
+		BakedLightSampler() {
+			params[BAKED_LIGHT_SAMPLER_STRENGTH]=1.0;
+			params[BAKED_LIGHT_SAMPLER_ATTENUATION]=1.0;
+			params[BAKED_LIGHT_SAMPLER_RADIUS]=1.0;
+			params[BAKED_LIGHT_SAMPLER_DETAIL_RATIO]=0.1;
+			resolution=16;
+		}
+	};
+
+	void _update_baked_light_sampler_dp_cache(BakedLightSampler * blsamp);
 	struct Camera  {
  
 		enum Type {
@@ -169,6 +187,7 @@ class VisualServerRaster : public VisualServer {
 		List<Instance*>::Element *RE;
 		Instance *baked_light;
 		List<Instance*>::Element *BLE;
+		Instance *sampled_light;
 		bool exterior;
 
 		uint64_t last_render_pass;
@@ -179,6 +198,8 @@ class VisualServerRaster : public VisualServer {
 		InstanceSet lights;
 		bool light_cache_dirty;
 
+
+
 		struct RoomInfo {
 
 			Transform affine_inverse;
@@ -235,6 +256,23 @@ class VisualServerRaster : public VisualServer {
 			Transform affine_inverse;
 			List<Instance*> owned_instances;
 		};
+
+		struct BakedLightSamplerInfo {
+
+			Set<Instance*> baked_lights;
+			Set<Instance*> owned_instances;
+			BakedLightSampler *sampler;
+			int resolution;
+			Vector<Color> light_bufer;
+			RID sampled_light;
+			uint64_t last_pass;
+			Transform xform; // viewspace normal to lightspace, might not use one.
+			BakedLightSamplerInfo() {
+				sampler=NULL;
+				last_pass=0;
+				resolution=0;
+			}
+		};
 		
 		struct ParticlesInfo {
 			
@@ -247,6 +285,7 @@ class VisualServerRaster : public VisualServer {
 		ParticlesInfo *particles_info;
 		PortalInfo * portal_info;
 		BakedLightInfo * baked_light_info;
+		BakedLightSamplerInfo * baked_light_sampler_info;
 
 
 		Instance() { 
@@ -282,6 +321,8 @@ class VisualServerRaster : public VisualServer {
 
 			baked_light=NULL;
 			baked_light_info=NULL;
+			baked_light_sampler_info=NULL;
+			sampled_light=NULL;
 			BLE=NULL;
 
 			light_cache_dirty=true;
@@ -603,6 +644,9 @@ class VisualServerRaster : public VisualServer {
 	int exterior_portal_cull_count;
 	bool exterior_visited;	
 
+	Instance *light_sampler_cull_result[MAX_LIGHT_SAMPLERS];
+	int light_samplers_culled;
+
 	Instance *room_cull_result[MAX_ROOM_CULL];
 	int room_cull_count;
 	bool room_cull_enabled;
@@ -638,6 +682,7 @@ class VisualServerRaster : public VisualServer {
 	mutable RID_Owner<Portal> portal_owner;
 
 	mutable RID_Owner<BakedLight> baked_light_owner;
+	mutable RID_Owner<BakedLightSampler> baked_light_sampler_owner;
 
 	mutable RID_Owner<Camera> camera_owner;
 	mutable RID_Owner<Viewport> viewport_owner;
@@ -658,6 +703,8 @@ class VisualServerRaster : public VisualServer {
 	bool _test_portal_cull(Camera *p_camera, Instance *p_portal_from, Instance *p_portal_to);
 	void _cull_portal(Camera *p_camera, Instance *p_portal,Instance *p_from_portal);
 	void _cull_room(Camera *p_camera, Instance *p_room,Instance *p_from_portal=NULL);
+	void _process_sampled_light(const Transform &p_camera, Instance *p_sampled_light, bool p_linear_colorspace);
+
 	void _render_camera(Viewport *p_viewport,Camera *p_camera, Scenario *p_scenario);
 	void _render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect,float p_opacity);
 	void _render_canvas(Canvas *p_canvas,const Matrix32 &p_transform);
@@ -953,12 +1000,28 @@ public:
 	virtual void baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree);
 	virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const;
 
+	virtual void baked_light_set_light(RID p_baked_light,const DVector<uint8_t> p_light);
+	virtual DVector<uint8_t> baked_light_get_light(RID p_baked_light) const;
+
+	virtual void baked_light_set_sampler_octree(RID p_baked_light,const DVector<int> &p_sampler);
+	virtual DVector<int> baked_light_get_sampler_octree(RID p_baked_light) const;
+
 	virtual void baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier);
 	virtual float baked_light_get_lightmap_multiplier(RID p_baked_light) const;
 
 	virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id);
 	virtual void baked_light_clear_lightmaps(RID p_baked_light);
 
+	/* BAKED LIGHT SAMPLER */
+
+	virtual RID baked_light_sampler_create();
+
+	virtual void baked_light_sampler_set_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param,float p_value);
+	virtual float baked_light_sampler_get_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param) const;
+
+	virtual void baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution);
+	virtual int baked_light_sampler_get_resolution(RID p_baked_light_sampler) const;
+
 	/* CAMERA API */
 	
 	virtual RID camera_create();
@@ -1096,6 +1159,9 @@ public:
 	virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light);
 	virtual RID instance_geometry_get_baked_light(RID p_instance) const;
 
+	virtual void instance_geometry_set_baked_light_sampler(RID p_instance,RID p_baked_light_sampler);
+	virtual RID instance_geometry_get_baked_light_sampler(RID p_instance) const;
+
 	virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id);
 	virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const;
 

+ 17 - 0
servers/visual/visual_server_wrap_mt.h

@@ -909,6 +909,12 @@ public:
 	FUNC2(baked_light_set_octree,RID,DVector<uint8_t>);
 	FUNC1RC(DVector<uint8_t>,baked_light_get_octree,RID);
 
+	FUNC2(baked_light_set_light,RID,DVector<uint8_t>);
+	FUNC1RC(DVector<uint8_t>,baked_light_get_light,RID);
+
+	FUNC2(baked_light_set_sampler_octree,RID,const DVector<int>&);
+	FUNC1RC(DVector<int>,baked_light_get_sampler_octree,RID);
+
 	FUNC2(baked_light_set_lightmap_multiplier,RID,float);
 	FUNC1RC(float,baked_light_get_lightmap_multiplier,RID);
 
@@ -916,6 +922,14 @@ public:
 	FUNC1(baked_light_clear_lightmaps,RID);
 
 
+	FUNC0R(RID,baked_light_sampler_create);
+
+	FUNC3(baked_light_sampler_set_param,RID, BakedLightSamplerParam , float );
+	FUNC2RC(float,baked_light_sampler_get_param,RID, BakedLightSamplerParam );
+
+	FUNC2(baked_light_sampler_set_resolution,RID,int);
+	FUNC1RC(int,baked_light_sampler_get_resolution,RID);
+
 	/* CAMERA API */
 
 	FUNC0R(RID,camera_create);
@@ -1055,6 +1069,9 @@ public:
 	FUNC2(instance_geometry_set_baked_light,RID, RID );
 	FUNC1RC(RID,instance_geometry_get_baked_light,RID);
 
+	FUNC2(instance_geometry_set_baked_light_sampler,RID, RID );
+	FUNC1RC(RID,instance_geometry_get_baked_light_sampler,RID);
+
 	FUNC2(instance_geometry_set_baked_light_texture_index,RID, int);
 	FUNC1RC(int,instance_geometry_get_baked_light_texture_index,RID);
 

+ 29 - 1
servers/visual_server.h

@@ -590,12 +590,35 @@ public:
 	virtual void baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree)=0;
 	virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const=0;
 
+	virtual void baked_light_set_light(RID p_baked_light,const DVector<uint8_t> p_light)=0;
+	virtual DVector<uint8_t> baked_light_get_light(RID p_baked_light) const=0;
+
+	virtual void baked_light_set_sampler_octree(RID p_baked_light,const DVector<int> &p_sampler)=0;
+	virtual DVector<int> baked_light_get_sampler_octree(RID p_baked_light) const=0;
+
 	virtual void baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier)=0;
 	virtual float baked_light_get_lightmap_multiplier(RID p_baked_light) const=0;
 
 	virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id)=0;
 	virtual void baked_light_clear_lightmaps(RID p_baked_light)=0;
 
+	/* BAKED LIGHT SAMPLER */
+
+	virtual RID baked_light_sampler_create()=0;
+
+	enum BakedLightSamplerParam {
+		BAKED_LIGHT_SAMPLER_RADIUS,
+		BAKED_LIGHT_SAMPLER_STRENGTH,
+		BAKED_LIGHT_SAMPLER_ATTENUATION,
+		BAKED_LIGHT_SAMPLER_DETAIL_RATIO,
+		BAKED_LIGHT_SAMPLER_MAX
+	};
+
+	virtual void baked_light_sampler_set_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param,float p_value)=0;
+	virtual float baked_light_sampler_get_param(RID p_baked_light_sampler,BakedLightSamplerParam p_param) const=0;
+
+	virtual void baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution)=0;
+	virtual int baked_light_sampler_get_resolution(RID p_baked_light_sampler) const=0;
 
 	/* CAMERA API */
 	
@@ -824,7 +847,8 @@ public:
 		INSTANCE_ROOM,
 		INSTANCE_PORTAL,
 		INSTANCE_BAKED_LIGHT,
-		
+		INSTANCE_BAKED_LIGHT_SAMPLER,
+
 		INSTANCE_GEOMETRY_MASK=(1<<INSTANCE_MESH)|(1<<INSTANCE_MULTIMESH)|(1<<INSTANCE_IMMEDIATE)|(1<<INSTANCE_PARTICLES)
 	};
 	
@@ -898,9 +922,13 @@ public:
 	virtual void instance_geometry_set_baked_light(RID p_instance,RID p_baked_light)=0;
 	virtual RID instance_geometry_get_baked_light(RID p_instance) const=0;
 
+	virtual void instance_geometry_set_baked_light_sampler(RID p_instance,RID p_baked_light_sampler)=0;
+	virtual RID instance_geometry_get_baked_light_sampler(RID p_instance) const=0;
+
 	virtual void instance_geometry_set_baked_light_texture_index(RID p_instance,int p_tex_id)=0;
 	virtual int instance_geometry_get_baked_light_texture_index(RID p_instance) const=0;
 
+
 	virtual void instance_light_set_enabled(RID p_instance,bool p_enabled)=0;
 	virtual bool instance_light_is_enabled(RID p_instance) const=0;
 

+ 2 - 0
tools/collada/collada.cpp

@@ -2106,6 +2106,8 @@ void Collada::_parse_animation_clip(XMLParser& parser) {
 
 	if (parser.has_attribute("name"))
 		clip.name=parser.get_attribute_value("name");
+	else if (parser.has_attribute("id"))
+		clip.name=parser.get_attribute_value("id");
 	if (parser.has_attribute("start"))
 		clip.begin=parser.get_attribute_value("start").to_double();
 	if (parser.has_attribute("end"))

+ 1 - 1
tools/docdump/makemd.py

@@ -337,7 +337,7 @@ for file in input_list:
 
 class_names.sort()
 
-make_class_list(class_names, 3)
+make_class_list(class_names, 2)
 
 for cn in class_names:
 	c = classes[cn]

+ 439 - 167
tools/editor/plugins/baked_light_baker.cpp

@@ -4,8 +4,17 @@
 #include <cmath>
 #include "io/marshalls.h"
 #include "tools/editor/editor_node.h"
+#include "tools/editor/editor_settings.h"
 
 
+void baked_light_baker_add_64f(double *dst,double value);
+void baked_light_baker_add_64i(int64_t *dst,int64_t value);
+
+//-separar en 2 testuras?
+//*mejorar performance y threads
+//*modos lineales
+//*saturacion
+
 _FORCE_INLINE_ static uint64_t get_uv_normal_bit(const Vector3& p_vector) {
 
 	int lat = Math::fast_ftoi(Math::floor(Math::acos(p_vector.dot(Vector3(0,1,0)))*6.0/Math_PI+0.5));
@@ -66,6 +75,12 @@ BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>&
 				image.convert(Image::FORMAT_RGBA);
 		}
 
+		if (imgtex->get_flags()&Texture::FLAG_CONVERT_TO_LINEAR) {
+			Image copy = image;
+			copy.srgb_to_linear();
+			image=copy;
+		}
+
 		DVector<uint8_t> dvt=image.get_data();
 		DVector<uint8_t>::Read r=dvt.read();
 		MeshTexture mt;
@@ -105,8 +120,13 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 				if (fm.is_valid()) {
 					//fixed route
 					mm.diffuse.color=fm->get_parameter(FixedMaterial::PARAM_DIFFUSE);
+					if (linear_color)
+						mm.diffuse.color=mm.diffuse.color.to_linear();
 					mm.diffuse.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_DIFFUSE));
 					mm.specular.color=fm->get_parameter(FixedMaterial::PARAM_SPECULAR);
+					if (linear_color)
+						mm.specular.color=mm.specular.color.to_linear();
+
 					mm.specular.tex=_get_mat_tex(fm->get_texture(FixedMaterial::PARAM_SPECULAR));
 				} else {
 
@@ -270,6 +290,11 @@ void BakedLightBaker::_parse_geometry(Node* p_node) {
 			dirl.type=VS::LightType(dl->get_light_type());
 			dirl.diffuse=dl->get_color(DirectionalLight::COLOR_DIFFUSE);
 			dirl.specular=dl->get_color(DirectionalLight::COLOR_SPECULAR);
+			if (linear_color)
+				dirl.diffuse=dirl.diffuse.to_linear();
+			if (linear_color)
+				dirl.specular=dirl.specular.to_linear();
+
 			dirl.energy=dl->get_parameter(DirectionalLight::PARAM_ENERGY);
 			dirl.pos=dl->get_global_transform().origin;
 			dirl.up=dl->get_global_transform().basis.get_axis(1).normalized();
@@ -472,8 +497,11 @@ void BakedLightBaker::_make_bvh() {
 	}
 
 	bvh=_parse_bvh(bases.ptr(),bases.size(),1,max_depth);
+
 	ray_stack = memnew_arr(uint32_t,max_depth);
 	bvh_stack = memnew_arr(BVH*,max_depth);
+
+	bvh_depth = max_depth;
 }
 
 void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_depth) {
@@ -563,6 +591,12 @@ void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_de
 					child->aabb.pos.z+=child->aabb.size.z;
 
 
+				child->full_accum[0]=0;
+				child->full_accum[1]=0;
+				child->full_accum[2]=0;
+				child->sampler_ofs=0;
+
+
 
 				if (stack_pos==octree_depth-1) {
 					child->leaf=true;
@@ -585,14 +619,10 @@ void BakedLightBaker::_octree_insert(int p_octant,Triangle* p_triangle, int p_de
 					cell_count++;
 
 					int lz = lights.size();
-					child->light = memnew_arr(OctantLight,lz);
-
-					for(int li=0;li<lz;li++) {
-						for(int ci=0;ci<8;ci++) {
-							child->light[li].accum[ci][0]=0;
-							child->light[li].accum[ci][1]=0;
-							child->light[li].accum[ci][2]=0;
-						}
+					for(int ci=0;ci<8;ci++) {
+						child->light_accum[ci][0]=0;
+						child->light_accum[ci][1]=0;
+						child->light_accum[ci][2]=0;
 					}
 
 					child->parent=ptr_stack[stack_pos];
@@ -797,12 +827,12 @@ void BakedLightBaker::_make_octree() {
 
 
 
-void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light, const Plane& p_plane) {
+void BakedLightBaker::_plot_light(ThreadStack& thread_stack,const Vector3& p_plot_pos, const AABB& p_plot_aabb, const Color& p_light,const Color& p_tint_light,bool p_only_full, const Plane& p_plane) {
 
 	//stackless version
 
-	uint32_t *stack=octant_stack;
-	uint32_t *ptr_stack=octantptr_stack;
+	uint32_t *stack=thread_stack.octant_stack;
+	uint32_t *ptr_stack=thread_stack.octantptr_stack;
 	Octant *octants=octant_pool.ptr();
 
 	stack[0]=0;
@@ -815,6 +845,29 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
 
 		Octant &octant=octants[ptr_stack[stack_pos]];
 
+		if (stack[stack_pos]==0) {
+
+
+			Vector3 pos = octant.aabb.pos + octant.aabb.size*0.5;
+			float md = 1<<(octree_depth - stack_pos );
+			float r=cell_size*plot_size*md;
+			float div = 1.0/(md*md*md);
+			//div=1.0;
+
+
+			float d = p_plot_pos.distance_to(pos);
+
+			if ((p_plane.distance_to(pos)>-cell_size*1.75*md) && d<=r) {
+
+
+				float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
+
+				baked_light_baker_add_64f(&octant.full_accum[0],p_tint_light.r*intensity*div);
+				baked_light_baker_add_64f(&octant.full_accum[1],p_tint_light.g*intensity*div);
+				baked_light_baker_add_64f(&octant.full_accum[2],p_tint_light.b*intensity*div);
+			}
+		}
+
 		if (octant.leaf) {
 
 
@@ -822,41 +875,44 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
 			//if (p_plane.normal.dot(octant.aabb.get_support(p_plane.normal)) < p_plane.d-CMP_EPSILON) { //octants behind are no go
 
 
-
-			float r=cell_size*plot_size;
-			for(int i=0;i<8;i++) {
-				Vector3 pos=octant.aabb.pos;
-				if (i&1)
-					pos.x+=octant.aabb.size.x;
-				if (i&2)
-					pos.y+=octant.aabb.size.y;
-				if (i&4)
-					pos.z+=octant.aabb.size.z;
+			if (!p_only_full) {
+				float r=cell_size*plot_size;
+				for(int i=0;i<8;i++) {
+					Vector3 pos=octant.aabb.pos;
+					if (i&1)
+						pos.x+=octant.aabb.size.x;
+					if (i&2)
+						pos.y+=octant.aabb.size.y;
+					if (i&4)
+						pos.z+=octant.aabb.size.z;
 
 
 
-				float d = p_plot_pos.distance_to(pos);
+					float d = p_plot_pos.distance_to(pos);
 
-				if ((p_plane.distance_to(pos)>-cell_size*1.75) && d<=r) {
+					if ((p_plane.distance_to(pos)>-cell_size*1.75) && d<=r) {
 
 
-					float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
-					if (edge_damp>0) {
-						Vector3 normal = Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]);
-						if (normal.x>0 || normal.y>0 || normal.z>0) {
+						float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
+						if (edge_damp>0) {
+							Vector3 normal = Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]);
+							if (normal.x>0 || normal.y>0 || normal.z>0) {
 
-							float damp = Math::abs(p_plane.normal.dot(normal));
-							intensity*=pow(damp,edge_damp);
+								float damp = Math::abs(p_plane.normal.dot(normal));
+								intensity*=pow(damp,edge_damp);
 
+							}
 						}
-					}
 
-					//intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
-					//intensity = Math::cos(d*Math_PI*0.5/r);
+						//intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
+						//intensity = Math::cos(d*Math_PI*0.5/r);
+
+						baked_light_baker_add_64f(&octant.light_accum[i][0],p_light.r*intensity);
+						baked_light_baker_add_64f(&octant.light_accum[i][1],p_light.g*intensity);
+						baked_light_baker_add_64f(&octant.light_accum[i][2],p_light.b*intensity);
+
 
-					octant.light[p_light_index].accum[i][0]+=p_light.r*intensity;
-					octant.light[p_light_index].accum[i][1]+=p_light.g*intensity;
-					octant.light[p_light_index].accum[i][2]+=p_light.b*intensity;
+					}
 				}
 			}
 
@@ -893,11 +949,11 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
 }
 
 
-float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce,bool p_only_dist) {
+float BakedLightBaker::_throw_ray(ThreadStack& thread_stack,bool p_bake_direct,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce,bool p_only_dist) {
 
 
-	uint32_t* stack = ray_stack;
-	BVH **bstack = bvh_stack;
+	uint32_t* stack = thread_stack.ray_stack;
+	BVH **bstack = thread_stack.bvh_stack;
 
 	enum {
 		TEST_AABB_BIT=0,
@@ -915,6 +971,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
 	n/=len;
 
 
+
 	real_t d=1e10;
 	bool inters=false;
 	Vector3 r_normal;
@@ -1139,7 +1196,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
 #endif
 
 
-				ret=_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
+				ret=_throw_ray(thread_stack,p_bake_direct,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
 			}
 
 			if (use_specular && (specular_at_point.r>CMP_EPSILON || specular_at_point.g>CMP_EPSILON || specular_at_point.b>CMP_EPSILON)) {
@@ -1150,7 +1207,7 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
 
 				Vector3 rn = n - r_normal *r_normal.dot(n) * 2.0;
 
-				_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
+				_throw_ray(thread_stack,p_bake_direct,r_point,r_point+rn*p_rest,p_rest,specular_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1);
 			}
 		}
 
@@ -1158,19 +1215,25 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
 //		_plot_light_point(r_point,octree,octree_aabb,p_light);
 
 
-		Color plot_light=diffuse_at_point;
+		Color plot_light=res_light.linear_interpolate(diffuse_at_point,tint);
 		plot_light.r*=att;
 		plot_light.g*=att;
 		plot_light.b*=att;
+		Color tint_light=diffuse_at_point;
+		tint_light.r*=att;
+		tint_light.g*=att;
+		tint_light.b*=att;
+
+		bool skip=false;
 
-		if (!p_first_bounce) {
+		if (!p_first_bounce || p_bake_direct) {
 
 
 			float r = plot_size * cell_size*2;
 			if (dist<r) {
 				//avoid accumulaiton of light on corners
 				//plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size);
-				plot_light=Color(0,0,0,0);
+				skip-true;
 
 			} else {
 
@@ -1181,12 +1244,12 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
 				double r2 = double(rand())/RAND_MAX;
 				double r3 = double(rand())/RAND_MAX;
 				Vector3 rn = ((c1*(r1-0.5)) + (c2*(r2-0.5)) + (r_normal*r3*0.25)).normalized();
-				float d =_throw_ray(p_light_index,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1,false,true);
-				r = plot_size*cell_size*0.7;
+				float d =_throw_ray(thread_stack,p_bake_direct,r_point,r_point+rn*p_rest,p_rest,diffuse_at_point,p_att_curve,p_att_pos,p_att_curve_len,p_bounces-1,false,true);
+				r = plot_size*cell_size*ao_radius;
 				if (d>0 && d<r) {
 					//avoid accumulaiton of light on corners
 					//plot_light=plot_light.linear_interpolate(Color(0,0,0,0),1.0-sd/plot_size*plot_size);
-					plot_light=Color(0,0,0,0);
+					skip=true;
 
 				} else {
 					//plot_light=Color(0,0,0,0);
@@ -1195,11 +1258,9 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons
 		}
 
 
-		if (!p_first_bounce || lights[p_light_index].bake_direct) {
-			Plane plane(r_point,r_normal);
-			//print_line(String(plot_light)+String(" ")+rtos(att));
-			_plot_light(p_light_index,r_point,aabb,plot_light,plane);
-		}
+		Plane plane(r_point,r_normal);
+		if (!skip)
+			_plot_light(thread_stack,r_point,aabb,plot_light,tint_light,!(!p_first_bounce || p_bake_direct),plane);
 
 
 		return dist;
@@ -1305,79 +1366,100 @@ void BakedLightBaker::_make_octree_texture() {
 
 	//ok let's try to just create a texture
 
-	{
+	int otex_w=256;
 
-		int otex_w=(1<<lattice_size)*(1<<lattice_size)*2; //make sure lattice fits horizontally
-		Vector3 lattice_cell_size=octree_aabb.size;
-		for(int i=0;i<lattice_size;i++) {
+	while (true) {
 
-			lattice_cell_size*=0.5;
-		}
 
 
+		uint32_t oct_idx=leaf_list;
 
-		while(true) {
+		int row=0;
 
-			//let's plot the leafs first, given the octree is not so obvious which size it will have
-			int row=4+4*(1<<lattice_size);
 
+		print_line("begin at row "+itos(row));
+		int longest_line_reused=0;
+		int col=0;
+		int processed=0;
+
+		//reset
+		while(oct_idx) {
 
-			uint32_t oct_idx=leaf_list;
+			BakedLightBaker::Octant *oct = &octants[oct_idx];
+			oct->texture_x=0;
+			oct->texture_y=0;
+			oct_idx=oct->next_leaf;
 
-			//untag
-			while(oct_idx) {
+		}
 
-				BakedLightBaker::Octant *oct = &octants[oct_idx];
-				//0,0 also means unprocessed
-				oct->texture_x=0;
-				oct->texture_y=0;
-				oct_idx=oct->next_leaf;
+		oct_idx=leaf_list;
+		//assign
+		while(oct_idx) {
 
+			BakedLightBaker::Octant *oct = &octants[oct_idx];
+			if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) {
+				//was not processed
+				uint32_t current_idx=oct_idx;
+				int reused=0;
+
+				while(current_idx) {
+					BakedLightBaker::Octant *o = &octants[current_idx];
+					if (col+1 >= otex_w) {
+						col=0;
+						row+=4;
+					}
+					o->texture_x=col;
+					o->texture_y=row;
+					processed++;
+
+					if (o->bake_neighbour) {
+						reused++;
+					}
+					col+=o->bake_neighbour ? 1 : 2; //reuse neighbour
+					current_idx=o->bake_neighbour;
+				}
+
+				if (reused>longest_line_reused) {
+					longest_line_reused=reused;
+				}
 			}
+			oct_idx=oct->next_leaf;
+		}
 
-			oct_idx=leaf_list;
+		row+=4;
 
+		if (otex_w < row) {
 
-			print_line("begin at row "+itos(row));
-			int longest_line_reused=0;
-			int col=0;
-			int processed=0;
+			otex_w*=2;
+		} else {
+
+			baked_light_texture_w=otex_w;
+			baked_light_texture_h=nearest_power_of_2(row);
+			print_line("w: "+itos(otex_w));
+			print_line("h: "+itos(row));
+			break;
+		}
 
-			while(oct_idx) {
 
-				BakedLightBaker::Octant *oct = &octants[oct_idx];
-				if (oct->first_neighbour && oct->texture_x==0 && oct->texture_y==0) {
-					//was not processed
-					uint32_t current_idx=oct_idx;
-					int reused=0;
+	}
 
-					while(current_idx) {
-						BakedLightBaker::Octant *o = &octants[current_idx];
-						if (col+1 >= otex_w) {
-							col=0;
-							row+=4;
-						}
-						o->texture_x=col;
-						o->texture_y=row;
-						processed++;
 
-						if (o->bake_neighbour) {
-							reused++;
-						}
-						col+=o->bake_neighbour ? 1 : 2; //reuse neighbour
-						current_idx=o->bake_neighbour;
-					}
+	{
 
-					if (reused>longest_line_reused) {
-						longest_line_reused=reused;
-					}
-				}
-				oct_idx=oct->next_leaf;
-			}
+		otex_w=(1<<lattice_size)*(1<<lattice_size)*2; //make sure lattice fits horizontally
+		Vector3 lattice_cell_size=octree_aabb.size;
+		for(int i=0;i<lattice_size;i++) {
+
+			lattice_cell_size*=0.5;
+		}
 
-			print_line("processed "+itos(processed));
 
-			print_line("longest reused: "+itos(longest_line_reused));
+
+		while(true) {
+
+			//let's plot the leafs first, given the octree is not so obvious which size it will have
+			int row=4+4*(1<<lattice_size);
+			int col=0;
 
 			col=0;
 			row+=4;
@@ -1478,7 +1560,25 @@ double BakedLightBaker::get_normalization(int p_light_idx) const {
 	return nrg;
 }
 
-void BakedLightBaker::throw_rays(int p_amount) {
+
+
+double BakedLightBaker::get_modifier(int p_light_idx) const {
+
+	double nrg=0;
+
+	const LightData &dl=lights[p_light_idx];
+	double cell_area = cell_size*cell_size;;
+	//nrg+= /*dl.energy */ (dl.rays_thrown * cell_area / dl.area);
+	nrg=cell_area;
+	nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel
+	nrg*=dl.constant;
+	//nrg*=5;
+
+
+	return nrg;
+}
+
+void BakedLightBaker::throw_rays(ThreadStack& thread_stack,int p_amount) {
 
 
 
@@ -1488,6 +1588,8 @@ void BakedLightBaker::throw_rays(int p_amount) {
 
 
 		int amount = p_amount * total_light_area / dl.area;
+		double mod = 1.0/double(get_modifier(i));
+		mod*=p_amount/float(amount);
 
 		switch(dl.type) {
 
@@ -1502,12 +1604,15 @@ void BakedLightBaker::throw_rays(int p_amount) {
 					from+=dl.left*(r2*2.0-1.0);
 					Vector3 to = from+dl.dir*dl.length;
 					Color col=dl.diffuse;
-					col.r*=dl.energy;
-					col.g*=dl.energy;
-					col.b*=dl.energy;
+					float m = mod*dl.energy;
+					col.r*=m;
+					col.g*=m;
+					col.b*=m;
+
 					dl.rays_thrown++;
-					total_rays++;
-					_throw_ray(i,from,to,dl.length,col,NULL,0,0,max_bounces,true);
+					baked_light_baker_add_64i(&total_rays,1);
+
+					_throw_ray(thread_stack,dl.bake_direct,from,to,dl.length,col,NULL,0,0,max_bounces,true);
 				}
 			} break;
 			case VS::LIGHT_OMNI: {
@@ -1543,13 +1648,14 @@ void BakedLightBaker::throw_rays(int p_amount) {
 #endif
 					Vector3 to = dl.pos+dir*dl.radius;
 					Color col=dl.diffuse;
-					col.r*=dl.energy;
-					col.g*=dl.energy;
-					col.b*=dl.energy;
+					float m = mod*dl.energy;
+					col.r*=m;
+					col.g*=m;
+					col.b*=m;
 
 					dl.rays_thrown++;
-					total_rays++;
-					_throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
+					baked_light_baker_add_64i(&total_rays,1);
+					_throw_ray(thread_stack,dl.bake_direct,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
 //					_throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true);
 				}
 
@@ -1574,13 +1680,14 @@ void BakedLightBaker::throw_rays(int p_amount) {
 
 					Vector3 to = dl.pos+dir*dl.radius;
 					Color col=dl.diffuse;
-					col.r*=dl.energy;
-					col.g*=dl.energy;
-					col.b*=dl.energy;
+					float m = mod*dl.energy;
+					col.r*=m;
+					col.g*=m;
+					col.b*=m;
 
 					dl.rays_thrown++;
-					total_rays++;
-					_throw_ray(i,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
+					baked_light_baker_add_64i(&total_rays,1);
+					_throw_ray(thread_stack,dl.bake_direct,from,to,dl.radius,col,dl.attenuation_table.ptr(),0,dl.radius,max_bounces,true);
 	//					_throw_ray(i,from,to,dl.radius,col,NULL,0,dl.radius,max_bounces,true);
 				}
 
@@ -1622,6 +1729,10 @@ void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) {
 	edge_damp=baked_light->get_edge_damp();
 	normal_damp=baked_light->get_normal_damp();
 	octree_extra_margin=baked_light->get_cell_extra_margin();
+	tint=baked_light->get_tint();
+	ao_radius=baked_light->get_ao_radius();
+	ao_strength=baked_light->get_ao_strength();
+	linear_color=baked_light->get_bake_flag(BakedLight::BAKE_LINEAR_COLOR);
 
 	baked_textures.clear();
 	for(int i=0;i<baked_light->get_lightmaps_count();i++) {
@@ -1651,13 +1762,134 @@ void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) {
 }
 
 
-void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
+void BakedLightBaker::update_octree_sampler(DVector<int> &p_sampler) {
+
+	BakedLightBaker::Octant *octants=octant_pool.ptr();
+	double norm = 1.0/double(total_rays);
+
+
+
+	if (p_sampler.size()==0 || first_bake_to_map) {
+
+		Vector<int> tmp_smp;
+		tmp_smp.resize(32); //32 for header
+
+		for(int i=0;i<32;i++) {
+			tmp_smp[i]=0;
+		}
+
+		for(int i=octant_pool_size-1;i>=0;i--) {
+
+			if (i==0)
+				tmp_smp[1]=tmp_smp.size();
+
+			Octant &octant=octants[i];
+			octant.sampler_ofs = tmp_smp.size();
+			int idxcol[2]={0,0};
+
+			int r = CLAMP((octant.full_accum[0]*norm)*2048,0,32767);
+			int g = CLAMP((octant.full_accum[1]*norm)*2048,0,32767);
+			int b = CLAMP((octant.full_accum[2]*norm)*2048,0,32767);
+
+			idxcol[0]|=r;
+			idxcol[1]|=(g<<16)|b;
+
+			if (octant.leaf) {
+				tmp_smp.push_back(idxcol[0]);
+				tmp_smp.push_back(idxcol[1]);
+			} else {
+
+				for(int j=0;j<8;j++) {
+					if (octant.children[j]) {
+						idxcol[0]|=(1<<(j+16));
+					}
+				}
+				tmp_smp.push_back(idxcol[0]);
+				tmp_smp.push_back(idxcol[1]);
+				for(int j=0;j<8;j++) {
+					if (octant.children[j]) {
+						tmp_smp.push_back(octants[octant.children[j]].sampler_ofs);
+						if (octants[octant.children[j]].sampler_ofs==0) {
+							print_line("FUUUUUUUUCK");
+						}
+					}
+				}
+			}
+
+		}
+
+		p_sampler.resize(tmp_smp.size());
+		DVector<int>::Write w = p_sampler.write();
+		int ss = tmp_smp.size();
+		for(int i=0;i<ss;i++) {
+			w[i]=tmp_smp[i];
+		}
+
+		first_bake_to_map=false;
+
+	}
+
+	double gamma = baked_light->get_gamma_adjust();
+	double mult = baked_light->get_energy_multiplier();
+	float saturation = baked_light->get_saturation();
+
+	DVector<int>::Write w = p_sampler.write();
+
+	encode_uint32(octree_depth,(uint8_t*)&w[2]);
+	encode_uint32(linear_color,(uint8_t*)&w[3]);
+
+	encode_float(octree_aabb.pos.x,(uint8_t*)&w[4]);
+	encode_float(octree_aabb.pos.y,(uint8_t*)&w[5]);
+	encode_float(octree_aabb.pos.z,(uint8_t*)&w[6]);
+	encode_float(octree_aabb.size.x,(uint8_t*)&w[7]);
+	encode_float(octree_aabb.size.y,(uint8_t*)&w[8]);
+	encode_float(octree_aabb.size.z,(uint8_t*)&w[9]);
+
+	//norm*=multiplier;
+
+	for(int i=octant_pool_size-1;i>=0;i--) {
+
+		Octant &octant=octants[i];
+		int idxcol[2]={w[octant.sampler_ofs],w[octant.sampler_ofs+1]};
+
+		double rf=pow(octant.full_accum[0]*norm*mult,gamma);
+		double gf=pow(octant.full_accum[1]*norm*mult,gamma);
+		double bf=pow(octant.full_accum[2]*norm*mult,gamma);
+
+		double gray = (rf+gf+bf)/3.0;
+		rf = gray + (rf-gray)*saturation;
+		gf = gray + (gf-gray)*saturation;
+		bf = gray + (bf-gray)*saturation;
+
+
+		int r = CLAMP((rf)*2048,0,32767);
+		int g = CLAMP((gf)*2048,0,32767);
+		int b = CLAMP((bf)*2048,0,32767);
+
+		idxcol[0]=((idxcol[0]>>16)<<16)|r;
+		idxcol[1]=(g<<16)|b;
+		w[octant.sampler_ofs]=idxcol[0];
+		w[octant.sampler_ofs+1]=idxcol[1];
+	}
+
+}
+
+void BakedLightBaker::update_octree_images(DVector<uint8_t> &p_octree,DVector<uint8_t> &p_light) {
 
 
 	int len = baked_octree_texture_w*baked_octree_texture_h*4;
-	p_image.resize(len);
-	DVector<uint8_t>::Write w = p_image.write();
+	p_octree.resize(len);
+
+	int ilen = baked_light_texture_w*baked_light_texture_h*4;
+	p_light.resize(ilen);
+
+
+	DVector<uint8_t>::Write w = p_octree.write();
 	zeromem(w.ptr(),len);
+
+	DVector<uint8_t>::Write iw = p_light.write();
+	zeromem(iw.ptr(),ilen);
+
 	float gamma = baked_light->get_gamma_adjust();
 	float mult = baked_light->get_energy_multiplier();
 
@@ -1668,6 +1900,13 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
 		w[i+3]=0xFF;
 	}
 
+	for(int i=0;i<ilen;i+=4) {
+		iw[i+0]=0xFF;
+		iw[i+1]=0;
+		iw[i+2]=0xFF;
+		iw[i+3]=0xFF;
+	}
+
 	float multiplier=1.0;
 
 	if (baked_light->get_format()==BakedLight::FORMAT_HDR8)
@@ -1678,6 +1917,9 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
 	encode_float(1<<lattice_size,&w[12]);
 	encode_uint32(octree_depth-lattice_size,&w[16]);
 	encode_uint32(multiplier,&w[20]);
+	encode_uint16(baked_light_texture_w,&w[24]); //if present, use the baked light texture
+	encode_uint16(baked_light_texture_h,&w[26]);
+	encode_uint32(0,&w[28]); //baked light texture format
 
 	encode_float(octree_aabb.pos.x,&w[32]);
 	encode_float(octree_aabb.pos.y,&w[36]);
@@ -1690,6 +1932,7 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
 	BakedLightBaker::Octant *octants=octant_pool.ptr();
 	int octant_count=octant_pool_size;
 	uint8_t *ptr = w.ptr();
+	uint8_t *lptr = iw.ptr();
 
 
 	int child_offsets[8]={
@@ -1703,7 +1946,18 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
 		baked_octree_texture_w*8+baked_octree_texture_w*4+4,
 	};
 
-	Vector<double> norm_arr;
+	int lchild_offsets[8]={
+		0,
+		4,
+		baked_light_texture_w*4,
+		baked_light_texture_w*4+4,
+		baked_light_texture_w*8+0,
+		baked_light_texture_w*8+4,
+		baked_light_texture_w*8+baked_light_texture_w*4,
+		baked_light_texture_w*8+baked_light_texture_w*4+4,
+	};
+
+	/*Vector<double> norm_arr;
 	norm_arr.resize(lights.size());
 
 	for(int i=0;i<lights.size();i++) {
@@ -1711,39 +1965,43 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
 	}
 
 	const double *normptr=norm_arr.ptr();
-
+*/
+	double norm = 1.0/double(total_rays);
 	int lz=lights.size();
 	mult/=multiplier;
+	double saturation = baked_light->get_saturation();
 
 	for(int i=0;i<octant_count;i++) {
 
 		Octant &oct=octants[i];
 		if (oct.texture_x==0 && oct.texture_y==0)
 			continue;
-		int ofs = (oct.texture_y * baked_octree_texture_w + oct.texture_x)<<2;
+
 
 		if (oct.leaf) {
 
+			int ofs = (oct.texture_y * baked_light_texture_w + oct.texture_x)<<2;
+			ERR_CONTINUE(ofs<0 || ofs >ilen);
 			//write colors
 			for(int j=0;j<8;j++) {
 
 				//if (!oct.children[j])
 				//	continue;
-				uint8_t *iptr=&ptr[ofs+child_offsets[j]];
-				float r=0;
-				float g=0;
-				float b=0;
-
-				for(int k=0;k<lz;k++) {
-					r+=oct.light[k].accum[j][0]*normptr[k];
-					g+=oct.light[k].accum[j][1]*normptr[k];
-					b+=oct.light[k].accum[j][2]*normptr[k];
-				}
+				uint8_t *iptr=&lptr[ofs+lchild_offsets[j]];
+
+				float r=oct.light_accum[j][0]*norm;
+				float g=oct.light_accum[j][1]*norm;
+				float b=oct.light_accum[j][2]*norm;
 
 				r=pow(r*mult,gamma);
 				g=pow(g*mult,gamma);
 				b=pow(b*mult,gamma);
 
+				double gray = (r+g+b)/3.0;
+				r = gray + (r-gray)*saturation;
+				g = gray + (g-gray)*saturation;
+				b = gray + (b-gray)*saturation;
+
 				float ic[3]={
 					r,
 					g,
@@ -1757,6 +2015,8 @@ void BakedLightBaker::update_octree_image(DVector<uint8_t> &p_image) {
 
 		} else {
 
+			int ofs = (oct.texture_y * baked_octree_texture_w + oct.texture_x)<<2;
+			ERR_CONTINUE(ofs<0 || ofs >len);
 
 			//write indices
 			for(int j=0;j<8;j++) {
@@ -1822,49 +2082,61 @@ void BakedLightBaker::_bake_thread_func(void *arg) {
 
 	BakedLightBaker *ble = (BakedLightBaker*)arg;
 
-	ble->rays_at_snap_time=ble->total_rays;
-	ble->snap_time=OS::get_singleton()->get_ticks_usec();
 
-	while(!ble->bake_thread_exit) {
 
-		ble->throw_rays(1000);
-		uint64_t t=OS::get_singleton()->get_ticks_usec();
-		if (t-ble->snap_time>1000000) {
+	ThreadStack thread_stack;
 
-			double time = (t-ble->snap_time)/1000000.0;
+	thread_stack.ray_stack = memnew_arr(uint32_t,ble->bvh_depth);
+	thread_stack.bvh_stack = memnew_arr(BVH*,ble->bvh_depth);
+	thread_stack.octant_stack = memnew_arr(uint32_t,ble->octree_depth*2 );
+	thread_stack.octantptr_stack = memnew_arr(uint32_t,ble->octree_depth*2 );
 
-			int rays=ble->total_rays-ble->rays_at_snap_time;
-			ble->rays_sec=int(rays/time);
-			ble->snap_time=OS::get_singleton()->get_ticks_usec();
-			ble->rays_at_snap_time=ble->total_rays;
-		}
+	while(!ble->bake_thread_exit) {
+
+		ble->throw_rays(thread_stack,1000);
 	}
 
+	memdelete_arr(thread_stack.ray_stack );
+	memdelete_arr(thread_stack.bvh_stack );
+	memdelete_arr(thread_stack.octant_stack );
+	memdelete_arr(thread_stack.octantptr_stack );
+
 }
 
 void BakedLightBaker::_start_thread() {
 
-	if (thread!=NULL)
+	if (threads.size()!=0)
 		return;
 	bake_thread_exit=false;
-	thread=Thread::create(_bake_thread_func,this);
 
+	int thread_count = EDITOR_DEF("light_baker/custom_bake_threads",0);
+	if (thread_count<=0 || thread_count>64)
+		thread_count=OS::get_singleton()->get_processor_count();
+
+	//thread_count=1;
+	threads.resize(thread_count);
+	for(int i=0;i<threads.size();i++) {
+		threads[i]=Thread::create(_bake_thread_func,this);
+	}
 }
 
 void BakedLightBaker::_stop_thread() {
 
-	if (thread==NULL)
+	if (threads.size()==0)
 		return;
 	bake_thread_exit=true;
-	Thread::wait_to_finish(thread);
-	thread=NULL;
+	for(int i=0;i<threads.size();i++) {
+		Thread::wait_to_finish(threads[i]);
+	}
+	threads.clear();
 }
 
 void BakedLightBaker::_plot_pixel_to_lightmap(int x, int y, int width, int height, uint8_t *image, const Vector3& p_pos,const Vector3& p_normal,double *p_norm_ptr,float mult,float gamma) {
 
 
 	uint8_t *ptr = &image[(y*width+x)*4];
-	int lc = lights.size();
+	//int lc = lights.size();
+	double norm = 1.0/double(total_rays);
 
 
 	Color color;
@@ -1888,11 +2160,9 @@ void BakedLightBaker::_plot_pixel_to_lightmap(int x, int y, int width, int heigh
 
 			for(int i=0;i<8;i++) {
 
-				for(int j=0;j<lc;j++) {
-					cols[i].x+=octant.light[j].accum[i][0]*p_norm_ptr[j];
-					cols[i].y+=octant.light[j].accum[i][1]*p_norm_ptr[j];
-					cols[i].z+=octant.light[j].accum[i][2]*p_norm_ptr[j];
-				}
+				cols[i].x+=octant.light_accum[i][0]*norm;
+				cols[i].y+=octant.light_accum[i][1]*norm;
+				cols[i].z+=octant.light_accum[i][2]*norm;
 			}
 
 
@@ -2355,12 +2625,13 @@ void BakedLightBaker::clear() {
 		memdelete_arr(octantptr_stack);
 	if (bvh_stack)
 		memdelete_arr(bvh_stack);
-
+/*
+ * ???
 	for(int i=0;i<octant_pool.size();i++) {
-		if (octant_pool[i].leaf) {
-			memdelete_arr( octant_pool[i].light );
-		}	Vector<double> norm_arr;
-		norm_arr.resize(lights.size());
+		//if (octant_pool[i].leaf) {
+		//	memdelete_arr( octant_pool[i].light );
+		//}	Vector<double> norm_arr;
+		//norm_arr.resize(lights.size());
 
 		for(int i=0;i<lights.size();i++) {
 			norm_arr[i] =  1.0/get_normalization(i);
@@ -2368,6 +2639,7 @@ void BakedLightBaker::clear() {
 
 		const double *normptr=norm_arr.ptr();
 	}
+*/
 	octant_pool.clear();
 	octant_pool_size=0;
 	bvh=NULL;
@@ -2388,8 +2660,9 @@ void BakedLightBaker::clear() {
 	baked_octree_texture_h=0;
 	paused=false;
 	baking=false;
-	thread=NULL;
+
 	bake_thread_exit=false;
+	first_bake_to_map=true;
 	baked_light=Ref<BakedLight>();
 	total_rays=0;
 
@@ -2414,12 +2687,11 @@ BakedLightBaker::BakedLightBaker() {
 	baked_octree_texture_h=0;
 	paused=false;
 	baking=false;
-	thread=NULL;
+
 	bake_thread_exit=false;
-	rays_at_snap_time=0;
-	snap_time=0;
-	rays_sec=0;
 	total_rays=0;
+	first_bake_to_map=true;
+	linear_color=false;
 
 }
 

+ 33 - 15
tools/editor/plugins/baked_light_baker.h

@@ -15,17 +15,19 @@ public:
 		OCTANT_POOL_CHUNK=1000000
 	};
 
-	struct OctantLight {
+	//struct OctantLight {
 
-		double accum[8][3];
-	};
+	//	double accum[8][3];
+	//};
 
 	struct Octant {
 		bool leaf;
 		AABB aabb;
 		uint16_t texture_x;
 		uint16_t texture_y;
+		int sampler_ofs;
 		float normal_accum[8][3];
+		double full_accum[3];
 		int parent;
 		union {
 			struct {
@@ -33,7 +35,7 @@ public:
 				float offset[3];
 				int bake_neighbour;
 				bool first_neighbour;
-				OctantLight *light;
+				double light_accum[8][3];
 			};
 			int children[8];
 		};
@@ -234,32 +236,49 @@ public:
 	Transform base_inv;
 	int leaf_list;
 	int octree_depth;
+	int bvh_depth;
 	int cell_count;
 	uint32_t *ray_stack;
+	BVH **bvh_stack;
 	uint32_t *octant_stack;
 	uint32_t *octantptr_stack;
+
+	struct ThreadStack {
+		uint32_t *octant_stack;
+		uint32_t *octantptr_stack;
+		uint32_t *ray_stack;
+		BVH **bvh_stack;
+	};
+
 	Map<Vector3,Vector3> endpoint_normal;
 	Map<Vector3,uint64_t> endpoint_normal_bits;
-	BVH **bvh_stack;
+
 	float cell_size;
 	float plot_size; //multiplied by cell size
 	float octree_extra_margin;
 
 	int max_bounces;
-	uint64_t total_rays;
+	int64_t total_rays;
 	bool use_diffuse;
 	bool use_specular;
 	bool use_translucency;
+	bool linear_color;
 
 
 	int baked_octree_texture_w;
 	int baked_octree_texture_h;
+	int baked_light_texture_w;
+	int baked_light_texture_h;
 	int lattice_size;
 	float edge_damp;
 	float normal_damp;
+	float tint;
+	float ao_radius;
+	float ao_strength;
 
 	bool paused;
 	bool baking;
+	bool first_bake_to_map;
 
 	Map<Ref<Material>,MeshMaterial*> mat_map;
 	Map<Ref<Texture>,MeshTexture*> tex_map;
@@ -285,19 +304,16 @@ public:
 
 
 	//void _plot_light(const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,int p_octant=0);
-	void _plot_light(int p_light_index,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Plane& p_plane);
+	void _plot_light(ThreadStack& thread_stack,const Vector3& p_plot_pos,const AABB& p_plot_aabb,const Color& p_light,const Color& p_tint_light,bool p_only_full,const Plane& p_plane);
 	//void _plot_light_point(const Vector3& p_plot_pos, Octant *p_octant, const AABB& p_aabb,const Color& p_light);
 
-	float _throw_ray(int p_light_index,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false,bool p_only_dist=false);
+	float _throw_ray(ThreadStack& thread_stack,bool p_bake_direct,const Vector3& p_begin, const Vector3& p_end,float p_rest,const Color& p_light,float *p_att_curve,float p_att_pos,int p_att_curve_len,int p_bounces,bool p_first_bounce=false,bool p_only_dist=false);
 
 
 	float total_light_area;
-	uint64_t rays_at_snap_time;
-	uint64_t snap_time;
-	int rays_sec;
 
+	Vector<Thread*> threads;
 
-	Thread *thread;
 	bool bake_thread_exit;
 	static void _bake_thread_func(void *arg);
 
@@ -306,18 +322,20 @@ public:
 public:
 
 
-	void throw_rays(int p_amount);
+	void throw_rays(ThreadStack &thread_stack, int p_amount);
 	double get_normalization(int p_light_idx) const;
+	double get_modifier(int p_light_idx) const;
 
 	void bake(const Ref<BakedLight>& p_light,Node *p_base);
 	bool is_baking();
 	void set_pause(bool p_pause);
 	bool is_paused();
-	int get_rays_sec() { return rays_sec; }
+	uint64_t get_rays_thrown() { return total_rays; }
 
 	Error transfer_to_lightmaps();
 
-	void update_octree_image(DVector<uint8_t> &p_image);
+	void update_octree_sampler(DVector<int> &p_sampler);
+	void update_octree_images(DVector<uint8_t> &p_octree,DVector<uint8_t> &p_light);
 
 	Ref<BakedLight> get_baked_light() { return baked_light; }
 

+ 84 - 0
tools/editor/plugins/baked_light_baker_cmpxchg.cpp

@@ -0,0 +1,84 @@
+
+#include "typedefs.h"
+
+
+#ifdef WINDOWS_ENABLED
+
+#include "windows.h"
+
+void baked_light_baker_add_64f(double *dst,double value) {
+
+	union {
+		int64_t i;
+		double f;
+	} swapy;
+
+
+	while(true) {
+		swapy.f=*dst;
+		int64_t from = swapy.i;
+		swapy.f+=value;
+		int64_t to=swapy.i;
+		int64_t result = InterlockedCompareExchange64((int64_t*)dst,to,from);
+		if (result==from)
+			break;
+	}
+
+}
+
+void baked_light_baker_add_64i(int64_t *dst,int64_t value) {
+
+	while(true) {
+		int64_t from = *dst;
+		int64_t to = from+value;
+		int64_t result = InterlockedCompareExchange64(dst,to,from);
+		if (result==from)
+			break;
+	}
+}
+
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
+
+void baked_light_baker_add_64f(double *dst,double value) {
+
+
+	union {
+		int64_t i;
+		double f;
+	} swapy;
+
+
+	while(true) {
+		swapy.f=*dst;
+		int64_t from = swapy.i;
+		swapy.f+=value;
+		int64_t to=swapy.i;
+		if (__sync_bool_compare_and_swap((int64_t*)dst,from,to))
+			break;
+	}
+}
+
+void baked_light_baker_add_64i(int64_t *dst,int64_t value) {
+
+	while(!__sync_bool_compare_and_swap(dst,*dst,(*dst)+value)) {}
+
+}
+
+#else
+
+//in goder (the god of programmers) we trust
+#warning seems this platform or compiler does not support safe cmpxchg, your baked lighting may be funny
+
+void baked_light_baker_add_64f(double *dst,double value) {
+
+	*dst+=value;
+
+}
+
+void baked_light_baker_add_64i(int64_t *dst,int64_t value) {
+
+	*dst+=value;
+
+}
+
+#endif

+ 16 - 2
tools/editor/plugins/baked_light_editor_plugin.cpp

@@ -111,7 +111,10 @@ void BakedLightEditor::_notification(int p_option) {
 #endif
 				ERR_FAIL_COND(node->get_baked_light().is_null());
 
-				baker->update_octree_image(octree_texture);
+				baker->update_octree_images(octree_texture,light_texture);
+				baker->update_octree_sampler(octree_sampler);
+			//	print_line("sampler size: "+itos(octree_sampler.size()*4));
+
 #if 1
 //debug
 				Image img(baker->baked_octree_texture_w,baker->baked_octree_texture_h,0,Image::FORMAT_RGBA,octree_texture);
@@ -121,11 +124,19 @@ void BakedLightEditor::_notification(int p_option) {
 
 
 #endif
-				bake_info->set_text("rays/s: "+itos(baker->get_rays_sec()));
+
+
+				uint64_t rays_snap = baker->get_rays_thrown();
+				int rays_sec = (rays_snap-last_rays_time)*1.0-(update_timeout);
+				last_rays_time=rays_snap;
+
+				bake_info->set_text("rays/s: "+itos(rays_sec));
 				update_timeout=1;				
 				print_line("MSUPDATE: "+itos(OS::get_singleton()->get_ticks_msec()-t));
 				t=OS::get_singleton()->get_ticks_msec();
 				node->get_baked_light()->set_octree(octree_texture);
+				node->get_baked_light()->set_light(light_texture);
+				node->get_baked_light()->set_sampler_octree(octree_sampler);
 				node->get_baked_light()->set_edited(true);
 
 				print_line("MSSET: "+itos(OS::get_singleton()->get_ticks_msec()-t));
@@ -195,6 +206,9 @@ void BakedLightEditor::_bake_pressed() {
 		baker->bake(node->get_baked_light(),node);
 		node->get_baked_light()->set_mode(BakedLight::MODE_OCTREE);
 		update_timeout=0;
+
+		last_rays_time=0;
+
 		set_process(true);
 	}
 

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

@@ -23,6 +23,8 @@ class BakedLightEditor : public Control {
 
 	float update_timeout;
 	DVector<uint8_t> octree_texture;
+	DVector<uint8_t> light_texture;
+	DVector<int> octree_sampler;
 
 	BakedLightBaker *baker;
 	AcceptDialog *err_dialog;
@@ -33,6 +35,9 @@ class BakedLightEditor : public Control {
 	Button *button_make_lightmaps;
 	Label *bake_info;
 
+	uint64_t last_rays_time;
+
+
 
 	BakedLightInstance *node;
 

+ 1 - 1
tools/editor/plugins/spatial_editor_plugin.cpp

@@ -1971,7 +1971,7 @@ void SpatialEditorViewport::_preview_exited_scene() {
 
 void SpatialEditorViewport::_init_gizmo_instance(int p_idx) {
 
-	uint32_t layer=1<<(GIZMO_BASE_LAYER+p_idx)|(1<<GIZMO_GRID_LAYER);
+	uint32_t layer=1<<(GIZMO_BASE_LAYER+p_idx);//|(1<<GIZMO_GRID_LAYER);
 
 	for(int i=0;i<3;i++) {
 		move_gizmo_instance[i]=VS::get_singleton()->instance_create();

+ 9 - 1
tools/export/blender25/io_scene_dae/export_dae.py

@@ -485,9 +485,17 @@ class DaeExporter:
 
 		uv_layer_count=len(mesh.uv_textures)
 		if (len(mesh.uv_textures)):
-			mesh.calc_tangents()
+			try:
+				mesh.calc_tangents()
+			except:
+				print("Warning, blender API is fucked up, not exporting UVs for this object.")
+				uv_layer_count=0
+				mesh.calc_normals_split()
+				has_tangents=False
+
 		else:
 			mesh.calc_normals_split()
+			has_tangents=False
 
 
 		for fi in range(len(mesh.polygons)):