Browse Source

Little Bits
-=-=-=-=-=-

-Fixed small bugs all around
-Added ability to show/hide entire sections of the spatial (3D) tree
-WIP new vehicle (not ready yet) based on Bullet

Juan Linietsky 11 years ago
parent
commit
2ee4ac183b
56 changed files with 3941 additions and 1755 deletions
  1. 3 3
      core/variant_call.cpp
  2. 149 27
      drivers/gles2/rasterizer_gles2.cpp
  3. 4 1
      drivers/gles2/rasterizer_gles2.h
  4. 26 0
      drivers/gles2/shader_compiler_gles2.cpp
  5. 83 3
      drivers/gles2/shaders/material.glsl
  6. 1 1
      modules/gdscript/gd_compiler.cpp
  7. 5 7
      platform/android/java/src/com/android/godot/Godot.java
  8. 2 2
      platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java
  9. 5 5
      platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java
  10. 2 2
      platform/android/java/src/com/android/godot/payments/PaymentsCache.java
  11. 6 6
      platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java
  12. 2 2
      platform/android/java_glue.cpp
  13. 4 0
      scene/2d/collision_object_2d.cpp
  14. 3 0
      scene/2d/screen_button.cpp
  15. 8 2
      scene/3d/light.cpp
  16. 1 0
      scene/3d/light.h
  17. 122 16
      scene/3d/navigation.cpp
  18. 8 1
      scene/3d/navigation.h
  19. 14 0
      scene/3d/physics_body.cpp
  20. 6 0
      scene/3d/physics_body.h
  21. 10 0
      scene/3d/skeleton.cpp
  22. 1 0
      scene/3d/skeleton.h
  23. 93 0
      scene/3d/spatial.cpp
  24. 13 1
      scene/3d/spatial.h
  25. 846 0
      scene/3d/vehicle_body.cpp
  26. 142 0
      scene/3d/vehicle_body.h
  27. 18 3
      scene/3d/visual_instance.cpp
  28. 1 0
      scene/3d/visual_instance.h
  29. 4 2
      scene/animation/animation_player.cpp
  30. 18 0
      scene/main/viewport.cpp
  31. 4 0
      scene/main/viewport.h
  32. 3 0
      scene/register_scene_types.cpp
  33. 21 2
      scene/resources/baked_light.cpp
  34. 4 0
      scene/resources/baked_light.h
  35. 1 0
      servers/physics/body_pair_sw.cpp
  36. 1 0
      servers/physics/body_sw.h
  37. 1636 1636
      servers/physics/shape_sw.cpp
  38. 1 0
      servers/physics_server.cpp
  39. 1 0
      servers/physics_server.h
  40. 2 0
      servers/visual/rasterizer.h
  41. 6 0
      servers/visual/shader_language.cpp
  42. 24 3
      servers/visual/visual_server_raster.cpp
  43. 6 2
      servers/visual/visual_server_raster.h
  44. 2 0
      servers/visual/visual_server_wrap_mt.h
  45. 3 0
      servers/visual_server.h
  46. BIN
      tools/editor/icons/icon_light_map.png
  47. 11 6
      tools/editor/io_plugins/editor_scene_import_plugin.cpp
  48. 1 0
      tools/editor/io_plugins/editor_scene_import_plugin.h
  49. 2 0
      tools/editor/io_plugins/editor_texture_import_plugin.cpp
  50. 524 4
      tools/editor/plugins/baked_light_baker.cpp
  51. 16 2
      tools/editor/plugins/baked_light_baker.h
  52. 34 2
      tools/editor/plugins/baked_light_editor_plugin.cpp
  53. 3 0
      tools/editor/plugins/baked_light_editor_plugin.h
  54. 3 1
      tools/editor/plugins/shader_editor_plugin.cpp
  55. 27 11
      tools/editor/scene_tree_editor.cpp
  56. 5 2
      tools/export/blender25/io_scene_dae/export_dae.py

+ 3 - 3
core/variant_call.cpp

@@ -264,6 +264,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 	//VCALL_LOCALMEM2R(String,erase);
 	VCALL_LOCALMEM0R(String,hash);
 	VCALL_LOCALMEM0R(String,md5_text);
+	VCALL_LOCALMEM0R(String,md5_buffer);
 	VCALL_LOCALMEM0R(String,empty);
 	VCALL_LOCALMEM0R(String,is_abs_path);
 	VCALL_LOCALMEM0R(String,is_rel_path);
@@ -573,7 +574,6 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
 	VCALL_PTR0R( Matrix32, affine_inverse );
 	VCALL_PTR0R( Matrix32, get_rotation );
 	VCALL_PTR0R( Matrix32, get_origin );
-	VCALL_PTR0R( Matrix32, get_scale );
 	VCALL_PTR0R( Matrix32, orthonormalized );
 	VCALL_PTR1R( Matrix32, rotated );
 	VCALL_PTR1R( Matrix32, scaled );
@@ -1167,7 +1167,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
 	ADDFUNC1(STRING,STRING,String,ord_at,INT,"at",varray());
 //	ADDFUNC2(STRING,String,erase,INT,INT,varray());
 	ADDFUNC0(STRING,INT,String,hash,varray());
-	ADDFUNC0(STRING,STRING,String,md5_text,varray());
+	ADDFUNC0(STRING,INT,String,md5_text,varray());
+	ADDFUNC0(STRING,INT,String,md5_buffer,varray());
 	ADDFUNC0(STRING,BOOL,String,empty,varray());
 	ADDFUNC0(STRING,BOOL,String,is_abs_path,varray());
 	ADDFUNC0(STRING,BOOL,String,is_rel_path,varray());
@@ -1390,7 +1391,6 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
 	ADDFUNC0(MATRIX32,MATRIX32,Matrix32,affine_inverse,varray());
 	ADDFUNC0(MATRIX32,REAL,Matrix32,get_rotation,varray());
 	ADDFUNC0(MATRIX32,VECTOR2,Matrix32,get_origin,varray());
-	ADDFUNC0(MATRIX32,VECTOR2,Matrix32,get_scale,varray());
 	ADDFUNC0(MATRIX32,MATRIX32,Matrix32,orthonormalized,varray());
 	ADDFUNC1(MATRIX32,MATRIX32,Matrix32,rotated,REAL,"phi",varray());
 	ADDFUNC1(MATRIX32,MATRIX32,Matrix32,scaled,VECTOR2,"scale",varray());

+ 149 - 27
drivers/gles2/rasterizer_gles2.cpp

@@ -82,6 +82,8 @@
 
 #endif
 
+static RasterizerGLES2* _singleton = NULL;
+
 static const GLenum prim_type[]={GL_POINTS,GL_LINES,GL_TRIANGLES,GL_TRIANGLE_FAN};
 
 _FORCE_INLINE_ static void _set_color_attrib(const Color& p_color) {
@@ -381,39 +383,96 @@ Image RasterizerGLES2::_get_gl_image_and_format(const Image& p_image, Image::For
 		} break;
 		case Image::FORMAT_BC1: {
 
-			r_gl_components=1; //doesn't matter much
-			r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-			r_compressed=true;
+			if (!s3tc_supported) {
+
+				if (!image.empty()) {
+					image.decompress();
+				}
+				r_gl_components=4;
+				r_gl_format=GL_RGBA;
+				r_has_alpha_cache=true;
+
+			} else {
+
+				r_gl_components=1; //doesn't matter much
+				r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+				r_compressed=true;
+			};
 
 		} break;
 		case Image::FORMAT_BC2: {
-			r_gl_components=1; //doesn't matter much
-			r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-			r_has_alpha_cache=true;
-			r_compressed=true;
+
+			if (!s3tc_supported) {
+
+				if (!image.empty()) {
+					image.decompress();
+				}
+				r_gl_components=4;
+				r_gl_format=GL_RGBA;
+				r_has_alpha_cache=true;
+
+			} else {
+				r_gl_components=1; //doesn't matter much
+				r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+				r_has_alpha_cache=true;
+				r_compressed=true;
+			};
 
 		} break;
 		case Image::FORMAT_BC3: {
 
-			r_gl_components=1; //doesn't matter much
-			r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-			r_has_alpha_cache=true;
-			r_compressed=true;
+			if (!s3tc_supported) {
+
+				if (!image.empty()) {
+					image.decompress();
+				}
+				r_gl_components=4;
+				r_gl_format=GL_RGBA;
+				r_has_alpha_cache=true;
+
+			} else {
+				r_gl_components=1; //doesn't matter much
+				r_gl_format=_EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+				r_has_alpha_cache=true;
+				r_compressed=true;
+			};
 
 		} break;
 		case Image::FORMAT_BC4: {
 
-			r_gl_format=_EXT_COMPRESSED_RED_RGTC1;
-			r_gl_components=1; //doesn't matter much
-			r_compressed=true;
+			if (!s3tc_supported) {
+
+				if (!image.empty()) {
+					image.decompress();
+				}
+				r_gl_components=4;
+				r_gl_format=GL_RGBA;
+				r_has_alpha_cache=true;
+
+			} else {
+
+				r_gl_format=_EXT_COMPRESSED_RED_RGTC1;
+				r_gl_components=1; //doesn't matter much
+				r_compressed=true;
+			};
 
 		} break;
 		case Image::FORMAT_BC5: {
 
+			if (!s3tc_supported) {
 
-			r_gl_format=_EXT_COMPRESSED_RG_RGTC2;
-			r_gl_components=1; //doesn't matter much
-			r_compressed=true;
+				if (!image.empty()) {
+					image.decompress();
+				}
+				r_gl_components=4;
+				r_gl_format=GL_RGBA;
+				r_has_alpha_cache=true;
+
+			} else {
+				r_gl_format=_EXT_COMPRESSED_RG_RGTC2;
+				r_gl_components=1; //doesn't matter much
+				r_compressed=true;
+			};
 		} break;
 		case Image::FORMAT_PVRTC2: {
 
@@ -1078,6 +1137,15 @@ void RasterizerGLES2::texture_set_reload_hook(RID p_texture,ObjectID p_owner,con
 }
 
 
+GLuint RasterizerGLES2::_texture_get_name(RID p_tex) {
+
+	Texture * texture = texture_owner.get(p_tex);
+	ERR_FAIL_COND_V(!texture, 0);
+
+	return texture->tex_id;
+};
+
+
 /* SHADER API */
 
 RID RasterizerGLES2::shader_create(VS::ShaderMode p_mode) {
@@ -3995,17 +4063,17 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
 	if (p_shader->mode==VS::SHADER_MATERIAL) {
 		//print_line("setting code to id.. "+itos(p_shader->custom_code_id));
 		Vector<const char*> enablers;
-		if (fragment_flags.use_color_interp)
+		if (fragment_flags.use_color_interp || vertex_flags.use_color_interp)
 			enablers.push_back("#define ENABLE_COLOR_INTERP\n");
-		if (fragment_flags.use_uv_interp)
+		if (fragment_flags.use_uv_interp || vertex_flags.use_uv_interp)
 			enablers.push_back("#define ENABLE_UV_INTERP\n");
-		if (fragment_flags.use_uv2_interp)
+		if (fragment_flags.use_uv2_interp || vertex_flags.use_uv2_interp)
 			enablers.push_back("#define ENABLE_UV2_INTERP\n");
-		if (fragment_flags.use_tangent_interp)
+		if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp)
 			enablers.push_back("#define ENABLE_TANGENT_INTERP\n");
-		if (fragment_flags.use_var1_interp)
+		if (fragment_flags.use_var1_interp || vertex_flags.use_var1_interp)
 			enablers.push_back("#define ENABLE_VAR1_INTERP\n");
-		if (fragment_flags.use_var2_interp)
+		if (fragment_flags.use_var2_interp || vertex_flags.use_var2_interp)
 			enablers.push_back("#define ENABLE_VAR2_INTERP\n");
 		if (fragment_flags.uses_texscreen) {
 			enablers.push_back("#define ENABLE_TEXSCREEN\n");
@@ -4444,6 +4512,7 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material
 	material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF,shadow_filter==SHADOW_FILTER_PCF5 || shadow_filter==SHADOW_FILTER_PCF13);
 	material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF_HQ,shadow_filter==SHADOW_FILTER_PCF13);
 	material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM);
+	material_shader.set_conditional(MaterialShaderGLES2::USE_LIGHTMAP_ON_UV2,p_material->flags[VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2]);
 
 	if (p_opaque_pass && p_material->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA && p_material->shader_cache && p_material->shader_cache->has_alpha) {
 
@@ -4716,7 +4785,8 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) {
 
 			}
 			//print_line("shadow split: "+rtos(li->shadow_split));
-		} else
+		}
+
 		material_shader.set_uniform(MaterialShaderGLES2::SHADOW_DARKENING,li->base->vars[VS::LIGHT_PARAM_SHADOW_DARKENING]);
 		//matrix
 
@@ -5545,6 +5615,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 	const Skeleton *prev_skeleton =NULL;
 	uint8_t prev_sort_flags=0xFF;
 	const BakedLightData *prev_baked_light=NULL;
+	RID prev_baked_light_texture;
 
 	Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID;
 
@@ -5561,6 +5632,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 		material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false);
 		material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false);
 		material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false);
+		material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
 //		material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,false);
 
 	}
@@ -5585,6 +5657,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 
 		bool rebind=false;
 		bool bind_baked_light_octree=false;
+		bool bind_baked_lightmap=false;
 		bool additive=false;
 
 
@@ -5704,7 +5777,7 @@ 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::USE_AMBIENT_TEXTURE,false);
+			material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
 
 			if (!additive && baked_light) {
 
@@ -5722,7 +5795,37 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
 					}
 				} else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) {
 
-					//material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,true);
+
+					int lightmap_idx = e->instance->baked_lightmap_id;
+
+					material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
+					bind_baked_lightmap=false;
+
+
+					if (baked_light->lightmaps.has(lightmap_idx)) {
+
+
+						RID texid = baked_light->lightmaps[lightmap_idx];
+
+						if (prev_baked_light!=baked_light || texid!=prev_baked_light_texture) {
+
+
+							Texture *tex = texture_owner.get(texid);
+							if (tex) {
+
+								glActiveTexture(GL_TEXTURE5);
+								glBindTexture(tex->target,tex->tex_id); //bind the texture
+							}
+
+							prev_baked_light_texture=texid;
+						}
+
+						if (texid.is_valid()) {
+							material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,true);
+							bind_baked_lightmap=true;
+						}
+
+					}
 				}
 			}
 
@@ -5793,6 +5896,14 @@ 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_MULTIPLIER, baked_light->lightmap_multiplier);
+
+		}
+
+
 		_set_cull(e->mirror,p_reverse_cull);
 
 
@@ -8212,9 +8323,13 @@ void RasterizerGLES2::_update_framebuffer() {
 
 }
 
-void RasterizerGLES2::set_base_framebuffer(GLuint p_id) {
+void RasterizerGLES2::set_base_framebuffer(GLuint p_id, Vector2 p_size) {
 
 	base_framebuffer=p_id;
+
+	if (p_size.x != 0) {
+		window_size = p_size;
+	};
 }
 
 #if 0
@@ -8753,8 +8868,15 @@ void RasterizerGLES2::set_use_framebuffers(bool p_use) {
 	use_framebuffers=p_use;
 }
 
+RasterizerGLES2* RasterizerGLES2::get_singleton() {
+
+	return _singleton;
+};
+
 RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,bool p_default_fragment_lighting,bool p_use_reload_hooks) {
 
+	_singleton = this;
+
 	keep_copies=p_keep_ram_copy;
 	use_reload_hooks=p_use_reload_hooks;
 	pack_arrays=p_compress_arrays;

+ 4 - 1
drivers/gles2/rasterizer_gles2.h

@@ -1175,6 +1175,8 @@ public:
 	virtual void texture_set_size_override(RID p_texture,int p_width, int p_height);
 	virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const;
 
+	GLuint _texture_get_name(RID p_tex);
+
 	/* SHADER API */
 
 	virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL);
@@ -1508,7 +1510,7 @@ public:
 
 	virtual int get_render_info(VS::RenderInfo p_info);
 
-	void set_base_framebuffer(GLuint p_id);
+	void set_base_framebuffer(GLuint p_id, Vector2 p_size = Vector2(0, 0));
 
 	virtual void flush_frame(); //not necesary in most cases
 	void set_extensions(const char *p_strings);
@@ -1520,6 +1522,7 @@ public:
 
 	virtual bool has_feature(VS::Features p_feature) const;
 
+	static RasterizerGLES2* get_singleton();
 
 	RasterizerGLES2(bool p_compress_arrays=false,bool p_keep_ram_copy=true,bool p_default_fragment_lighting=true,bool p_use_reload_hooks=false);
 	virtual ~RasterizerGLES2();

+ 26 - 0
drivers/gles2/shader_compiler_gles2.cpp

@@ -150,6 +150,26 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
 				if (vnode->name==vname_vertex && p_assign_left) {
 					vertex_code_writes_vertex=true;
 				}
+				if (vnode->name==vname_color_interp) {
+					flags->use_color_interp=true;
+				}
+				if (vnode->name==vname_uv_interp) {
+					flags->use_uv_interp=true;
+				}
+				if (vnode->name==vname_uv2_interp) {
+					flags->use_uv2_interp=true;
+				}
+				if (vnode->name==vname_var1_interp) {
+					flags->use_var1_interp=true;
+				}
+				if (vnode->name==vname_var2_interp) {
+					flags->use_var2_interp=true;
+				}
+				if (vnode->name==vname_tangent_interp || vnode->name==vname_binormal_interp) {
+					flags->use_tangent_interp=true;
+				}
+
+
 			}
 			if (type==ShaderLanguage::SHADER_MATERIAL_FRAGMENT) {
 
@@ -614,6 +634,11 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	replace_table["texscreen"]= "texscreen";
 	replace_table["texpos"]= "texpos";
 
+	mode_replace_table[0]["SRC_VERTEX"]="vertex_in.xyz";
+	mode_replace_table[0]["SRC_NORMAL"]="normal_in";
+	mode_replace_table[0]["SRC_TANGENT"]="tangent_in";
+	mode_replace_table[0]["SRC_BINORMALF"]="binormalf";
+
 	mode_replace_table[0]["VERTEX"]="vertex_interp";
 	mode_replace_table[0]["NORMAL"]="normal_interp";
 	mode_replace_table[0]["TANGENT"]="tangent_interp";
@@ -626,6 +651,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
 	mode_replace_table[0]["WORLD_MATRIX"]="world_transform";
 	mode_replace_table[0]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
 	mode_replace_table[0]["PROJECTION_MATRIX"]="projection_transform";
+	mode_replace_table[0]["MODELVIEW_MATRIX"]="modelview";
 	mode_replace_table[0]["POINT_SIZE"]="gl_PointSize";
 	mode_replace_table[0]["VAR1"]="var1_interp";
 	mode_replace_table[0]["VAR2"]="var2_interp";

+ 83 - 3
drivers/gles2/shaders/material.glsl

@@ -8,6 +8,9 @@
 precision mediump float;
 precision mediump int;
 #endif
+
+
+
 /*
 from VisualServer:
 
@@ -22,6 +25,26 @@ ARRAY_WEIGHTS=7,
 ARRAY_INDEX=8,
 */
 
+//hack to use uv if no uv present so it works with lightmap
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+#ifdef USE_LIGHTMAP_ON_UV2
+
+#ifndef ENABLE_UV2_INTERP
+#define ENABLE_UV2_INTERP
+#endif
+
+#else
+
+#ifndef ENABLE_UV_INTERP
+#define ENABLE_UV_INTERP
+#endif
+
+#endif
+
+#endif
+
+
 /* INPUT ATTRIBS */
 
 attribute highp vec4 vertex_attrib; // attrib:0
@@ -238,6 +261,7 @@ void main() {
 #if defined(ENABLE_TANGENT_INTERP)
 	vec3 tangent_in = tangent_attrib.xyz;
 	tangent_in*=normal_mult;
+	float binormalf = tangent_attrib.a;
 #endif
 
 #ifdef USE_SKELETON
@@ -272,7 +296,7 @@ void main() {
 
 #if defined(ENABLE_TANGENT_INTERP)
 	tangent_interp=normalize(tangent_in);
-	binormal_interp = normalize( cross(normal_interp,tangent_interp) * tangent_attrib.a );
+	binormal_interp = normalize( cross(normal_interp,tangent_interp) * binormalf );
 #endif
 
 #if defined(ENABLE_UV_INTERP)
@@ -453,6 +477,27 @@ precision mediump int;
 
 #endif
 
+
+//hack to use uv if no uv present so it works with lightmap
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+#ifdef USE_LIGHTMAP_ON_UV2
+
+#ifndef ENABLE_UV2_INTERP
+#define ENABLE_UV2_INTERP
+#endif
+
+#else
+
+#ifndef ENABLE_UV_INTERP
+#define ENABLE_UV_INTERP
+#endif
+
+#endif
+
+#endif
+
+
 /* Varyings */
 
 #if defined(ENABLE_COLOR_INTERP)
@@ -545,6 +590,13 @@ uniform int ambient_octree_steps;
 
 #endif
 
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+uniform highp sampler2D ambient_lightmap;
+uniform float ambient_lightmap_multiplier;
+
+#endif
+
 
 FRAGMENT_SHADER_GLOBALS
 
@@ -783,6 +835,34 @@ FRAGMENT_SHADER_CODE
 	}
 #endif
 
+	float shadow_attenuation = 1.0;
+
+#ifdef ENABLE_AMBIENT_LIGHTMAP
+
+	vec3 ambientmap_color = vec3(0.0,0.0,0.0);
+	vec2 ambientmap_uv = vec2(0.0,0.0);
+
+#ifdef USE_LIGHTMAP_ON_UV2
+
+	ambientmap_uv = uv2_interp;
+
+#else
+
+	ambientmap_uv = uv_interp;
+
+#endif
+
+	vec4 amcol = texture2D(ambient_lightmap,ambientmap_uv);
+	shadow_attenuation=amcol.a;
+	ambientmap_color = amcol.rgb;
+	ambientmap_color*=ambient_lightmap_multiplier;
+	ambientmap_color*=diffuse.rgb;
+
+
+
+#endif
+
+
 #ifdef ENABLE_AMBIENT_OCTREE
 
 	vec3 ambientmap_color = vec3(0.0,0.0,0.0);
@@ -828,7 +908,7 @@ FRAGMENT_SHADER_CODE
 
 #endif
 
-        float shadow_attenuation = 1.0;
+
 
 
 
@@ -1120,7 +1200,7 @@ LIGHT_SHADER_CODE
 #endif
 
 
-#ifdef ENABLE_AMBIENT_OCTREE
+#if defined(ENABLE_AMBIENT_OCTREE) || defined(ENABLE_AMBIENT_LIGHTMAP)
 
 	diffuse.rgb+=ambientmap_color;
 #endif

+ 1 - 1
modules/gdscript/gd_compiler.cpp

@@ -1443,7 +1443,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
 	}
 
 
-	print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size()));
+	//print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size()));
 
 
 	for(int i=0;i<p_class->variables.size();i++) {

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

@@ -349,12 +349,12 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 		io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
 		GodotLib.io=io;
 		Log.d("GODOT", "command_line is null? " + ((command_line == null)?"yes":"no"));
-		if(command_line != null){
+		/*if(command_line != null){
 		    Log.d("GODOT", "Command Line:");
 		    for(int w=0;w <command_line.length;w++){
 		        Log.d("GODOT","   " + command_line[w]);
 		    }
-		}
+		}*/
 		GodotLib.initialize(this,io.needsReloadHooks(),command_line);
 		mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
 		mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
@@ -418,12 +418,10 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 			}
 
 			if (new_args.isEmpty()){
-        			Log.d("GODOT", "new_args is empty");
 				command_line=null;
 			}else{
-        			Log.d("GODOT", "new_args is not empty");
+
 				command_line = new_args.toArray(new String[new_args.size()]);
-        			Log.d("GODOT", "command line is null? " + ( (command_line == null) ? "yes":"no"));
                         }
 			if (use_apk_expansion && main_pack_md5!=null && main_pack_key!=null) {
 				//check that environment is ok!
@@ -461,7 +459,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 				}
 
 				if (!pack_valid) {
-					Log.d("GODOT", "Tengo que bajarme el apk");
+					Log.d("GODOT", "Pack Invalid, try re-downloading.");
 					
 					Intent notifierIntent = new Intent(this, this.getClass());
 					notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
@@ -472,7 +470,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 					
 			        int startResult;
 					try {
-						Log.d("GODOT", "INICIANDO DOWNLOAD SERVICE");
+						Log.d("GODOT", "INITIALIZING DOWNLOAD");
 						startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
 								getApplicationContext(), 
 								pendingIntent, 

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

@@ -32,9 +32,9 @@ abstract public class GenericConsumeTask extends AsyncTask<String, String, Strin
 	@Override
 	protected String doInBackground(String... params) {
 		try {
-			Log.d("godot", "Requesting to consume an item with token ." + token);
+//			Log.d("godot", "Requesting to consume an item with token ." + token);
 			int response = mService.consumePurchase(3, context.getPackageName(), token);
-			Log.d("godot", "consumePurchase response: " + response);
+//			Log.d("godot", "consumePurchase response: " + response);
 			if(response == 0 || response == 8){
 				return null;
 			}

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

@@ -28,19 +28,19 @@ abstract public class HandlePurchaseTask {
 	
 	
 	public void handlePurchaseRequest(int resultCode, Intent data){
-		Log.d("XXX", "Handling purchase response");
+//		Log.d("XXX", "Handling purchase response");
 //		int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
 		PaymentsCache pc = new PaymentsCache(context);
 		
 		String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
-		Log.d("XXX", "Purchase data:" + purchaseData);
+//		Log.d("XXX", "Purchase data:" + purchaseData);
 		String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
-		Log.d("XXX", "Purchase signature:" + dataSignature);
+		//Log.d("XXX", "Purchase signature:" + dataSignature);
 		
 		if (resultCode == Activity.RESULT_OK) {
 			
 			try {
-				Log.d("SARLANGA", purchaseData);
+//				Log.d("SARLANGA", purchaseData);
 				
 				
 				JSONObject jo = new JSONObject(purchaseData);
@@ -58,7 +58,7 @@ abstract public class HandlePurchaseTask {
 					error("Untrusted callback");
 					return;
 				}
-				Log.d("XXX", "Este es el product ID:" + productId);
+//				Log.d("XXX", "Este es el product ID:" + productId);
 				pc.setConsumableValue("ticket_signautre", productId, dataSignature);
 				pc.setConsumableValue("ticket", productId, purchaseData);
 				pc.setConsumableFlag("block", productId, true);

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

@@ -31,14 +31,14 @@ public class PaymentsCache {
 		SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); 
 	    SharedPreferences.Editor editor = sharedPref.edit();
 	    editor.putString(sku, value);
-	    Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
+//	    Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
 	    editor.commit();
 	}
 
 	public String getConsumableValue(String set, String sku){
 	    SharedPreferences sharedPref = context.getSharedPreferences(
 	    		"consumables_" + set, Context.MODE_PRIVATE);
-	    Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
+//	    Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
 	    return sharedPref.getString(sku, null);
 	}
 

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

@@ -28,13 +28,13 @@ abstract public class ReleaseAllConsumablesTask {
 
 	public void consumeItAll(){
 		try{
-			Log.d("godot", "consumeItall for " + context.getPackageName());
+//			Log.d("godot", "consumeItall for " + context.getPackageName());
 			Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null);
 			
 			for (String key : bundle.keySet()) {
 			    Object value = bundle.get(key);
-			    Log.d("godot", String.format("%s %s (%s)", key,  
-			        value.toString(), value.getClass().getName()));
+//			    Log.d("godot", String.format("%s %s (%s)", key,  
+//			        value.toString(), value.getClass().getName()));
 			}
 			
 			
@@ -45,13 +45,13 @@ abstract public class ReleaseAllConsumablesTask {
 				
 
 				if (myPurchases == null || myPurchases.size() == 0){
-					Log.d("godot", "No purchases!");
+//					Log.d("godot", "No purchases!");
 					notRequired();
 					return;
 				}
 		
 				
-				Log.d("godot", "# products to be consumed:" + myPurchases.size());
+//				Log.d("godot", "# products to be consumed:" + myPurchases.size());
 				for (int i=0;i<myPurchases.size();i++)
 				{
 					
@@ -61,7 +61,7 @@ abstract public class ReleaseAllConsumablesTask {
 						String sku = inappPurchaseData.getString("productId");
 						String token = inappPurchaseData.getString("purchaseToken");
 						String signature = mySignatures.get(i);
-						Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt);
+//						Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt);
 						new GenericConsumeTask(context, mService, sku, receipt,signature, token) {
 							
 							@Override

+ 2 - 2
platform/android/java_glue.cpp

@@ -1577,14 +1577,14 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env
 	int count = env->GetArrayLength(params);
 	Variant args[VARIANT_ARG_MAX];
 
-	print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count));
+//	print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count));
 
 	for (int i=0; i<MIN(count,VARIANT_ARG_MAX); i++) {
 
 		jobject obj = env->GetObjectArrayElement(params, i);
 		if (obj)
 			args[i] = _jobject_to_variant(env, obj);
-		print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type()));
+//		print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type()));
 
 	};
 

+ 4 - 0
scene/2d/collision_object_2d.cpp

@@ -47,6 +47,10 @@ void CollisionObject2D::_notification(int p_what) {
 
 		case NOTIFICATION_ENTER_SCENE: {
 
+			if (area)
+				Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform());
+			else
+				Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform());
 
 			RID space = get_world_2d()->get_space();
 			if (area) {

+ 3 - 0
scene/2d/screen_button.cpp

@@ -129,6 +129,9 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
 	if (!get_scene())
 		return;
 
+	if (p_event.device != 0)
+		return;
+
 	if (passby_press) {
 
 		if (p_event.type==InputEvent::SCREEN_TOUCH && !p_event.screen_touch.pressed && finger_pressed==p_event.screen_touch.index) {

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

@@ -460,7 +460,7 @@ void Light::_bind_methods() {
 
 
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled"));
-	ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
+	ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Indirect+Shadows,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY );
 	/*
 	if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
@@ -477,7 +477,7 @@ void Light::_bind_methods() {
 	ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/diffuse"), _SCS("set_color"), _SCS("get_color"),COLOR_DIFFUSE);
 	ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/specular"), _SCS("set_color"), _SCS("get_color"),COLOR_SPECULAR);
 	ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/shadow"), _SCS("set_project_shadows"), _SCS("has_project_shadows"));
-	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
+	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_offset", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_OFFSET);
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_slope_scale", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_SLOPE_SCALE);
 	ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/esm_multiplier", PROPERTY_HINT_RANGE, "1.0,512.0,0.1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_ESM_MULTIPLIER);
@@ -498,6 +498,12 @@ void Light::_bind_methods() {
 	BIND_CONSTANT( COLOR_DIFFUSE );
 	BIND_CONSTANT( COLOR_SPECULAR );	
 
+	BIND_CONSTANT( BAKE_MODE_DISABLED );
+	BIND_CONSTANT( BAKE_MODE_INDIRECT );
+	BIND_CONSTANT( BAKE_MODE_INDIRECT_AND_SHADOWS );
+	BIND_CONSTANT( BAKE_MODE_FULL );
+
+
 }
 
 

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

@@ -69,6 +69,7 @@ public:
 
 		BAKE_MODE_DISABLED,
 		BAKE_MODE_INDIRECT,
+		BAKE_MODE_INDIRECT_AND_SHADOWS,
 		BAKE_MODE_FULL
 
 	};

+ 122 - 16
scene/3d/navigation.cpp

@@ -180,7 +180,7 @@ void Navigation::navmesh_remove(int p_id){
 
 }
 
-Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end) {
+Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end, bool p_optimize) {
 
 
 	Polygon *begin_poly=NULL;
@@ -332,24 +332,112 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector
 
 	if (found_route) {
 
-		//use midpoints for now
-		Polygon *p=end_poly;
 		Vector<Vector3> path;
-		path.push_back(end_point);
-		while(true) {
-			int prev = p->prev_edge;
-			int prev_n = (p->prev_edge+1)%p->edges.size();
-			Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
-			path.push_back(point);
-			p = p->edges[prev].C;
-			if (p==begin_poly)
-				break;
-		}
 
-		path.push_back(begin_point);
+		if (p_optimize) {
+			//string pulling
+
+			Polygon *apex_poly=end_poly;
+			Vector3 apex_point=end_point;
+			Vector3 portal_left=apex_point;
+			Vector3 portal_right=apex_point;
+			Polygon *left_poly=end_poly;
+			Polygon *right_poly=end_poly;
+			Polygon *p=end_poly;
+			path.push_back(end_point);
+
+			while(p) {
+
+				Vector3 left;
+				Vector3 right;
+
+#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) )
+
+				if (p==begin_poly) {
+					left=begin_point;
+					right=begin_point;
+				} else {
+					int prev = p->prev_edge;
+					int prev_n = (p->prev_edge+1)%p->edges.size();
+					left = _get_vertex(p->edges[prev].point);
+					right = _get_vertex(p->edges[prev_n].point);
+
+					if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){
+						SWAP(left,right);
+					}
+				}
+
+				bool skip=false;
+
+
+				if (CLOCK_TANGENT(apex_point,portal_left,left).dot(up) >= 0){
+					//process
+					if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right).dot(up) > 0) {
+						left_poly=p;
+						portal_left=left;
+					} else {
+
+						apex_point=portal_right;
+						p=right_poly;
+						left_poly=p;
+						portal_left=apex_point;
+						portal_right=apex_point;
+						path.push_back(apex_point);
+						skip=true;
+					}
+				}
+
+				if (!skip && CLOCK_TANGENT(apex_point,portal_right,right).dot(up) <= 0){
+					//process
+					if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left).dot(up) < 0) {
+						right_poly=p;
+						portal_right=right;
+					} else {
+
+						apex_point=portal_left;
+						p=left_poly;
+						right_poly=p;
+						portal_right=apex_point;
+						portal_left=apex_point;
+						path.push_back(apex_point);
+					}
+				}
+
+				if (p!=begin_poly)
+					p=p->edges[p->prev_edge].C;
+				else
+					p=NULL;
+
+			}
 
+			if (path[path.size()-1]!=begin_point)
+				path.push_back(begin_point);
 
-		path.invert();;
+			path.invert();
+
+
+
+
+		} else {
+			//midpoints
+			Polygon *p=end_poly;
+
+			path.push_back(end_point);
+			while(true) {
+				int prev = p->prev_edge;
+				int prev_n = (p->prev_edge+1)%p->edges.size();
+				Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
+				path.push_back(point);
+				p = p->edges[prev].C;
+				if (p==begin_poly)
+					break;
+			}
+
+			path.push_back(begin_point);
+
+
+			path.invert();;
+		}
 
 		return path;
 	}
@@ -475,17 +563,33 @@ Vector3 Navigation::get_closest_point_normal(const Vector3& p_point){
 }
 
 
+void Navigation::set_up_vector(const Vector3& p_up) {
+
+
+	up=p_up;
+}
+
+Vector3 Navigation::get_up_vector() const{
+
+	return up;
+}
+
+
 void Navigation::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform"),&Navigation::navmesh_create);
 	ObjectTypeDB::bind_method(_MD("navmesh_set_transform","id","xform"),&Navigation::navmesh_set_transform);
 	ObjectTypeDB::bind_method(_MD("navmesh_remove","id"),&Navigation::navmesh_remove);
 
-	ObjectTypeDB::bind_method(_MD("get_simple_path","start","end"),&Navigation::get_simple_path);
+	ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation::get_simple_path,DEFVAL(true));
 	ObjectTypeDB::bind_method(_MD("get_closest_point_to_segment","start","end"),&Navigation::get_closest_point_to_segment);
 	ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation::get_closest_point);
 	ObjectTypeDB::bind_method(_MD("get_closest_point_normal","to_point"),&Navigation::get_closest_point_normal);
 
+	ObjectTypeDB::bind_method(_MD("set_up_vector","up"),&Navigation::set_up_vector);
+	ObjectTypeDB::bind_method(_MD("get_up_vector"),&Navigation::get_up_vector);
+
+	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"up_vector"),_SCS("set_up_vector"),_SCS("get_up_vector"));
 }
 
 Navigation::Navigation() {
@@ -493,5 +597,7 @@ Navigation::Navigation() {
 	ERR_FAIL_COND( sizeof(Point)!=8 );
 	cell_size=0.01; //one centimeter
 	last_id=1;
+	up=Vector3(0,1,0);
 }
 
+

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

@@ -103,6 +103,8 @@ class Navigation : public Spatial {
 		return Vector3(p_point.x,p_point.y,p_point.z)*cell_size;
 	}
 
+
+
 	void _navmesh_link(int p_id);
 	void _navmesh_unlink(int p_id);
 
@@ -110,18 +112,23 @@ class Navigation : public Spatial {
 	Map<int,NavMesh> navmesh_map;
 	int last_id;
 
+	Vector3 up;
+
 protected:
 
 	static void _bind_methods();
 
 public:
 
+	void set_up_vector(const Vector3& p_up);
+	Vector3 get_up_vector() const;
+
 	//API should be as dynamic as possible
 	int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform);
 	void navmesh_set_transform(int p_id, const Transform& p_xform);
 	void navmesh_remove(int p_id);
 
-	Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end);
+	Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end,bool p_optimize=true);
 	Vector3 get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to);
 	Vector3 get_closest_point(const Vector3& p_point);
 	Vector3 get_closest_point_normal(const Vector3& p_point);

+ 14 - 0
scene/3d/physics_body.cpp

@@ -43,6 +43,20 @@ void PhysicsBody::_notification(int p_what) {
 	*/
 }
 
+Vector3 PhysicsBody::get_linear_velocity() const {
+
+	return Vector3();
+}
+Vector3 PhysicsBody::get_angular_velocity() const {
+
+	return Vector3();
+}
+
+float PhysicsBody::get_inverse_mass() const {
+
+	return 0;
+}
+
 PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) {
 
 

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

@@ -44,6 +44,10 @@ protected:
 	PhysicsBody(PhysicsServer::BodyMode p_mode);
 public:
 
+	virtual Vector3 get_linear_velocity() const;
+	virtual Vector3 get_angular_velocity() const;
+	virtual float get_inverse_mass() const;
+
 	PhysicsBody();
 
 };
@@ -183,6 +187,8 @@ public:
 	void set_mass(real_t p_mass);
 	real_t get_mass() const;
 
+	virtual float get_inverse_mass() const { return 1.0/mass; }
+
 	void set_weight(real_t p_weight);
 	real_t get_weight() const;
 

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

@@ -237,6 +237,14 @@ Transform Skeleton::get_bone_transform(int p_bone) const {
 	return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse;
 }
 
+Transform Skeleton::get_bone_global_pose(int p_bone) const {
+
+	ERR_FAIL_INDEX_V(p_bone,bones.size(),Transform());
+	if (dirty)
+		const_cast<Skeleton*>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+	return bones[p_bone].pose_global;
+}
+
 RID Skeleton::get_skeleton() const {
 
 	return skeleton;
@@ -511,6 +519,8 @@ 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("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);
 	ObjectTypeDB::bind_method(_MD("set_bone_custom_pose","bone_idx","custom_pose"),&Skeleton::set_bone_custom_pose);
 

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

@@ -116,6 +116,7 @@ public:
 	void set_bone_rest(int p_bone, const Transform& p_rest);
 	Transform get_bone_rest(int p_bone) const;
 	Transform get_bone_transform(int p_bone) const;
+	Transform get_bone_global_pose(int p_bone) const;
 
 	void set_bone_enabled(int p_bone, bool p_enabled);
 	bool is_bone_enabled(int p_bone) const;

+ 93 - 0
scene/3d/spatial.cpp

@@ -506,6 +506,86 @@ Transform Spatial::get_import_transform() const {
 #endif
 
 
+void Spatial::_propagate_visibility_changed() {
+
+	notification(NOTIFICATION_VISIBILITY_CHANGED);
+	emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+	_change_notify("visibility/visible");
+
+	for (List<Spatial*>::Element*E=data.children.front();E;E=E->next()) {
+
+		Spatial *c=E->get();
+		if (!c || !c->data.visible)
+			continue;
+		c->_propagate_visibility_changed();
+	}
+}
+
+
+void Spatial::show() {
+
+	if (data.visible)
+		return;
+
+	data.visible=true;
+
+	if (!is_inside_scene())
+		return;
+
+	if (!data.parent || is_visible()) {
+
+		_propagate_visibility_changed();
+	}
+}
+
+void Spatial::hide(){
+
+	if (!data.visible)
+		return;
+
+	bool was_visible = is_visible();
+	data.visible=false;
+
+	if (!data.parent || was_visible) {
+
+		_propagate_visibility_changed();
+	}
+
+}
+bool Spatial::is_visible() const{
+
+	const Spatial *s=this;
+
+	while(s) {
+		if (!s->data.visible) {
+			return false;
+		}
+		s=s->data.parent;
+	}
+
+	return true;
+}
+
+
+bool Spatial::is_hidden() const{
+
+	return !data.visible;
+}
+
+void Spatial::_set_visible_(bool p_visible) {
+
+	if (p_visible)
+		show();
+	else
+		hide();
+}
+
+bool Spatial::_is_visible_() const {
+
+	return !is_hidden();
+}
+
+
 void Spatial::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("set_transform","local"), &Spatial::set_transform);
@@ -537,9 +617,18 @@ void Spatial::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_gizmo","gizmo:SpatialGizmo"), &Spatial::set_gizmo);
 	ObjectTypeDB::bind_method(_MD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo);
 
+	ObjectTypeDB::bind_method(_MD("show"), &Spatial::show);
+	ObjectTypeDB::bind_method(_MD("hide"), &Spatial::hide);
+	ObjectTypeDB::bind_method(_MD("is_visible"), &Spatial::is_visible);
+	ObjectTypeDB::bind_method(_MD("is_hidden"), &Spatial::is_hidden);
+
+	ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_);
+	ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_);
+
 	BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED );
 	BIND_CONSTANT( NOTIFICATION_ENTER_WORLD );
 	BIND_CONSTANT( NOTIFICATION_EXIT_WORLD );
+	BIND_CONSTANT( NOTIFICATION_VISIBILITY_CHANGED );
 
 	//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") );
 	ADD_PROPERTYNZ( PropertyInfo(Variant::TRANSFORM,"transform/local",PROPERTY_HINT_NONE,""), _SCS("set_transform"), _SCS("get_transform") );
@@ -547,8 +636,11 @@ void Spatial::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") );
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") );
 	ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") );
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") );
 	//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") );
 
+	ADD_SIGNAL( MethodInfo("visibility_changed" ) );
+
 }
 
 
@@ -564,6 +656,7 @@ Spatial::Spatial() : xform_change(this)
 	data.scale=Vector3(1,1,1);
 	data.viewport=NULL;
 	data.inside_world=false;
+	data.visible=true;
 #ifdef TOOLS_ENABLED
 	data.gizmo_disabled=false;
 	data.gizmo_dirty=false;

+ 13 - 1
scene/3d/spatial.h

@@ -91,6 +91,8 @@ class Spatial : public Node {
 		
 		bool ignore_notification;
 
+		bool visible;
+
 #ifdef TOOLS_ENABLED
 		Ref<SpatialGizmo> gizmo;
 		bool gizmo_disabled;
@@ -109,6 +111,8 @@ class Spatial : public Node {
 	void _set_rotation_deg(const Vector3& p_deg);
 	Vector3 _get_rotation_deg() const;
 
+	void _propagate_visibility_changed();
+
 
 protected:
 
@@ -118,7 +122,9 @@ protected:
 
 	void _notification(int p_what);
 	static void _bind_methods();
-	
+
+	void _set_visible_(bool p_visible);
+	bool _is_visible_() const;
 public:
 
 	enum {
@@ -126,6 +132,7 @@ public:
 		NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED,
 		NOTIFICATION_ENTER_WORLD=41,
 		NOTIFICATION_EXIT_WORLD=42,
+		NOTIFICATION_VISIBILITY_CHANGED=43,
 	};
 
 	Spatial *get_parent_spatial() const;
@@ -159,6 +166,11 @@ public:
 
 	Transform get_relative_transform(const Node *p_parent) const;
 
+	void show();
+	void hide();
+	bool is_visible() const;
+	bool is_hidden() const;
+
 #ifdef TOOLS_ENABLED
 	void set_import_transform(const Transform& p_transform)	;
 	Transform get_import_transform() const;

+ 846 - 0
scene/3d/vehicle_body.cpp

@@ -0,0 +1,846 @@
+#include "vehicle_body.h"
+
+#define ROLLING_INFLUENCE_FIX
+
+class btVehicleJacobianEntry
+{
+public:
+
+	Vector3	m_linearJointAxis;
+	Vector3	m_aJ;
+	Vector3	m_bJ;
+	Vector3	m_0MinvJt;
+	Vector3	m_1MinvJt;
+	//Optimization: can be stored in the w/last component of one of the vectors
+	real_t	m_Adiag;
+
+	real_t getDiagonal() const { return m_Adiag; }
+
+	btVehicleJacobianEntry() {};
+		//constraint between two different rigidbodies
+		btVehicleJacobianEntry(
+			const Matrix3& world2A,
+			const Matrix3& world2B,
+			const Vector3& rel_pos1,
+			const Vector3& rel_pos2,
+			const Vector3& jointAxis,
+			const Vector3& inertiaInvA,
+			const real_t massInvA,
+			const Vector3& inertiaInvB,
+			const real_t massInvB)
+			:m_linearJointAxis(jointAxis)
+		{
+			m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
+			m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
+			m_0MinvJt	= inertiaInvA * m_aJ;
+			m_1MinvJt = inertiaInvB * m_bJ;
+			m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
+
+			//btAssert(m_Adiag > real_t(0.0));
+		}
+
+		real_t getRelativeVelocity(const Vector3& linvelA,const Vector3& angvelA,const Vector3& linvelB,const Vector3& angvelB)
+			{
+				Vector3 linrel = linvelA - linvelB;
+				Vector3 angvela  = angvelA * m_aJ;
+				Vector3 angvelb  = angvelB * m_bJ;
+				linrel *= m_linearJointAxis;
+				angvela += angvelb;
+				angvela += linrel;
+				real_t rel_vel2 = angvela[0]+angvela[1]+angvela[2];
+				return rel_vel2 + CMP_EPSILON;
+			}
+
+
+};
+
+void VehicleWheel::_notification(int p_what) {
+
+
+	if (p_what==NOTIFICATION_ENTER_SCENE) {
+
+		if (!get_parent())
+			return;
+		VehicleBody *cb = get_parent()->cast_to<VehicleBody>();
+		if (!cb)
+			return;
+		body=cb;
+		local_xform=get_transform();
+		cb->wheels.push_back(this);
+
+		m_chassisConnectionPointCS = get_transform().origin;
+		m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
+		m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
+
+	}
+	if (p_what==NOTIFICATION_EXIT_SCENE) {
+
+		if (!get_parent())
+			return;
+		VehicleBody *cb = get_parent()->cast_to<VehicleBody>();
+		if (!cb)
+			return;
+		cb->wheels.erase(this);
+		body=NULL;
+	}
+
+}
+
+
+void VehicleWheel::_update(PhysicsDirectBodyState *s) {
+
+
+
+	if (m_raycastInfo.m_isInContact)
+
+	{
+		real_t	project= m_raycastInfo.m_contactNormalWS.dot( m_raycastInfo.m_wheelDirectionWS );
+		Vector3	 chassis_velocity_at_contactPoint;
+		Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+		chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+				(s->get_angular_velocity()).cross(relpos);// * mPos);
+
+		real_t projVel = m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint );
+		if ( project >= real_t(-0.1))
+		{
+			m_suspensionRelativeVelocity = real_t(0.0);
+			m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+		}
+		else
+		{
+			real_t inv = real_t(-1.) / project;
+			m_suspensionRelativeVelocity = projVel * inv;
+			m_clippedInvContactDotSuspension = inv;
+		}
+
+	}
+
+	else	// Not in contact : position wheel in a nice (rest length) position
+	{
+		m_raycastInfo.m_suspensionLength = m_suspensionRestLength;
+		m_suspensionRelativeVelocity = real_t(0.0);
+		m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS;
+		m_clippedInvContactDotSuspension = real_t(1.0);
+	}
+}
+
+void VehicleWheel::_bind_methods() {
+
+
+
+}
+
+
+VehicleWheel::VehicleWheel() {
+
+
+
+	m_steering = real_t(0.);
+	m_engineForce = real_t(0.);
+	m_rotation = real_t(0.);
+	m_deltaRotation = real_t(0.);
+	m_brake = real_t(0.);
+	m_rollInfluence = real_t(0.1);
+
+	m_suspensionRestLength = 0.15;
+	m_wheelRadius = 0.5;//0.28;
+	m_suspensionStiffness = 5.88;
+	m_wheelsDampingCompression = 0.83;
+	m_wheelsDampingRelaxation = 0.88;
+	m_frictionSlip = 10.5;
+	m_bIsFrontWheel = false;
+	m_maxSuspensionTravelCm = 500;
+	m_maxSuspensionForce = 6000;
+
+	m_suspensionRelativeVelocity=0;
+	m_clippedInvContactDotSuspension=1.0;
+	m_raycastInfo.m_isInContact=false;
+
+	body=NULL;
+}
+
+
+void VehicleBody::_update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s) {
+
+	wheel.m_raycastInfo.m_isInContact = false;
+
+	Transform chassisTrans = s->get_transform();
+	//if (interpolatedTransform && (getRigidBody()->getMotionState()))
+	//{
+	//	getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
+	//}
+
+	wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform( wheel.m_chassisConnectionPointCS );
+	wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform( wheel.m_wheelDirectionCS).normalized();
+	wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform( wheel.m_wheelAxleCS ).normalized();
+}
+
+void VehicleBody::_update_wheel(int p_idx,PhysicsDirectBodyState *s) {
+
+	VehicleWheel& wheel = *wheels[p_idx];
+	_update_wheel_transform(wheel,s);
+
+	Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
+	const Vector3& right = wheel.m_raycastInfo.m_wheelAxleWS;
+	Vector3 fwd = up.cross(right);
+	fwd = fwd.normalized();
+//	up = right.cross(fwd);
+//	up.normalize();
+
+	//rotate around steering over de wheelAxleWS
+	real_t steering = wheel.m_steering;
+
+	Matrix3 steeringMat(up,steering);
+
+	Matrix3 rotatingMat(right,-wheel.m_rotation);
+
+	Matrix3 basis2(
+		right[0],up[0],fwd[0],
+		right[1],up[1],fwd[1],
+		right[2],up[2],fwd[2]
+	);
+
+	wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2);
+	wheel.m_worldTransform.set_origin(
+		wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength
+	);
+}
+
+
+real_t VehicleBody::_ray_cast(int p_idx,PhysicsDirectBodyState *s) {
+
+
+	VehicleWheel& wheel = *wheels[p_idx];
+
+	_update_wheel_transform(wheel,s);
+
+
+	real_t depth = -1;
+
+	real_t raylen = wheel.m_suspensionRestLength+wheel.m_wheelRadius;
+
+	Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
+	const Vector3& source = wheel.m_raycastInfo.m_hardPointWS;
+	wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
+	const Vector3& target = wheel.m_raycastInfo.m_contactPointWS;
+
+	real_t param = real_t(0.);
+
+
+	PhysicsDirectSpaceState::RayResult rr;
+
+
+	PhysicsDirectSpaceState *ss=s->get_space_state();
+
+	bool col = ss->intersect_ray(source,target,rr,exclude);
+
+
+	wheel.m_raycastInfo.m_groundObject = 0;
+
+	if (col)
+	{
+		//print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target);
+		//print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col));
+		param = source.distance_to(rr.position)/source.distance_to(target);
+		depth = raylen * param;
+		wheel.m_raycastInfo.m_contactNormalWS  = rr.normal;
+
+		wheel.m_raycastInfo.m_isInContact = true;
+		if (rr.collider)
+			wheel.m_raycastInfo.m_groundObject=rr.collider->cast_to<PhysicsBody>();
+
+
+		real_t hitDistance = param*raylen;
+		wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius;
+		//clamp on max suspension travel
+
+		real_t  minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm*real_t(0.01);
+		real_t maxSuspensionLength = wheel.m_suspensionRestLength+ wheel.m_maxSuspensionTravelCm*real_t(0.01);
+		if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength)
+		{
+			wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
+		}
+		if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength)
+		{
+			wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
+		}
+
+		wheel.m_raycastInfo.m_contactPointWS = rr.position;
+
+		real_t denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS );
+
+		Vector3 chassis_velocity_at_contactPoint;
+		//Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition();
+
+		//chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
+
+		chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+				(s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS-s->get_transform().origin);// * mPos);
+
+
+		real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint );
+
+		if ( denominator >= real_t(-0.1))
+		{
+			wheel.m_suspensionRelativeVelocity = real_t(0.0);
+			wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+		}
+		else
+		{
+			real_t inv = real_t(-1.) / denominator;
+			wheel.m_suspensionRelativeVelocity = projVel * inv;
+			wheel.m_clippedInvContactDotSuspension = inv;
+		}
+
+	} else
+	{
+		wheel.m_raycastInfo.m_isInContact = false;
+		//put wheel info as in rest position
+		wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength;
+		wheel.m_suspensionRelativeVelocity = real_t(0.0);
+		wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS;
+		wheel.m_clippedInvContactDotSuspension = real_t(1.0);
+	}
+
+	return depth;
+}
+
+
+void	VehicleBody::_update_suspension(PhysicsDirectBodyState *s)
+{
+
+	real_t deltaTime = s->get_step();
+	real_t chassisMass = mass;
+
+	for (int w_it=0; w_it<wheels.size(); w_it++)
+	{
+		VehicleWheel& wheel_info = *wheels[w_it];
+
+
+		if ( wheel_info.m_raycastInfo.m_isInContact )
+		{
+			real_t force;
+			//	Spring
+			{
+				real_t	susp_length			= wheel_info.m_suspensionRestLength;
+				real_t	current_length = wheel_info.m_raycastInfo.m_suspensionLength;
+
+				real_t length_diff = (susp_length - current_length);
+
+				force = wheel_info.m_suspensionStiffness
+					* length_diff * wheel_info.m_clippedInvContactDotSuspension;
+			}
+
+			// Damper
+			{
+				real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
+				{
+					real_t	susp_damping;
+					if ( projected_rel_vel < real_t(0.0) )
+					{
+						susp_damping = wheel_info.m_wheelsDampingCompression;
+					}
+					else
+					{
+						susp_damping = wheel_info.m_wheelsDampingRelaxation;
+					}
+					force -= susp_damping * projected_rel_vel;
+				}
+			}
+
+			// RESULT
+			wheel_info.m_wheelsSuspensionForce = force * chassisMass;
+			if (wheel_info.m_wheelsSuspensionForce < real_t(0.))
+			{
+				wheel_info.m_wheelsSuspensionForce = real_t(0.);
+			}
+		}
+		else
+		{
+			wheel_info.m_wheelsSuspensionForce = real_t(0.0);
+		}
+	}
+
+}
+
+
+//bilateral constraint between two dynamic objects
+void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1,
+		      PhysicsBody* body2, const Vector3& pos2, const Vector3& normal,real_t& impulse)
+{
+
+	real_t normalLenSqr = normal.length_squared();
+	//ERR_FAIL_COND( normalLenSqr < real_t(1.1));
+
+	if (normalLenSqr > real_t(1.1))
+	{
+		impulse = real_t(0.);
+		return;
+	}
+
+	Vector3 rel_pos1 = pos1 - s->get_transform().origin;
+	Vector3 rel_pos2;
+	if (body2)
+		rel_pos2 = pos2 - body2->get_global_transform().origin;
+	//this jacobian entry could be re-used for all iterations
+
+	Vector3 vel1 = s->get_linear_velocity() +  (s->get_angular_velocity()).cross(rel_pos1);// * mPos);
+	Vector3 vel2;
+
+	if (body2)
+		vel2=body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2);
+
+	Vector3 vel = vel1 - vel2;
+
+	Matrix3 b2trans;
+	float b2invmass=0;
+	Vector3 b2lv;
+	Vector3 b2av;
+	Vector3 b2invinertia; //todo
+
+	if (body2) {
+		b2trans = body2->get_global_transform().basis.transposed();
+		b2invmass = body2->get_inverse_mass();
+		b2lv = body2->get_linear_velocity();
+		b2av = body2->get_angular_velocity();
+	}
+
+
+
+	btVehicleJacobianEntry jac(s->get_transform().basis.transposed(),
+			    b2trans,
+			    rel_pos1,
+			    rel_pos2,
+			    normal,
+			    s->get_inverse_inertia(),
+			    1.0/mass,
+			    b2invinertia,
+			    b2invmass);
+
+	real_t jacDiagAB = jac.getDiagonal();
+	real_t jacDiagABInv = real_t(1.) / jacDiagAB;
+
+	real_t rel_vel = jac.getRelativeVelocity(
+				s->get_linear_velocity(),
+				s->get_transform().basis.transposed().xform(s->get_angular_velocity()),
+				b2lv,
+				b2trans.xform(b2av));
+	real_t a;
+	a=jacDiagABInv;
+
+
+	rel_vel = normal.dot(vel);
+
+	//todo: move this into proper structure
+	real_t contactDamping = real_t(0.4);
+#define ONLY_USE_LINEAR_MASS
+#ifdef ONLY_USE_LINEAR_MASS
+	real_t massTerm = real_t(1.) / ((1.0/mass) + b2invmass);
+	impulse = - contactDamping * rel_vel * massTerm;
+#else
+	real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
+	impulse = velocityImpulse;
+#endif
+
+}
+
+
+
+VehicleBody::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse)
+	:m_s(s),
+	m_body1(body1),
+	m_frictionPositionWorld(frictionPosWorld),
+	m_frictionDirectionWorld(frictionDirectionWorld),
+	m_maxImpulse(maxImpulse)
+{
+	float denom0=0;
+	float denom1=0;
+
+	{
+		Vector3 r0 = frictionPosWorld - s->get_transform().origin;
+		Vector3 c0 = (r0).cross(frictionDirectionWorld);
+		Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+		denom0= s->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+	}
+
+	if (body1) {
+
+		Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
+		Vector3 c0 = (r0).cross(frictionDirectionWorld);
+		Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+		//denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+		denom1=0;
+
+	}
+
+
+	real_t	relaxation = 1.f;
+	m_jacDiagABInv = relaxation/(denom0+denom1);
+}
+
+
+real_t VehicleBody::_calc_rolling_friction(btVehicleWheelContactPoint& contactPoint) {
+
+	real_t j1=0.f;
+
+	const Vector3& contactPosWorld = contactPoint.m_frictionPositionWorld;
+
+	Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin;
+	Vector3 rel_pos2;
+	if (contactPoint.m_body1)
+		rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin;
+
+	real_t maxImpulse  = contactPoint.m_maxImpulse;
+
+	Vector3 vel1  = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1);// * mPos);
+
+	Vector3 vel2;
+	if (contactPoint.m_body1) {
+		vel2=contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2);
+
+	}
+
+	Vector3 vel = vel1 - vel2;
+
+	real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
+
+	// calculate j that moves us to zero relative velocity
+	j1 = -vrel * contactPoint.m_jacDiagABInv;
+
+	return CLAMP(j1,-maxImpulse,maxImpulse);
+}
+
+
+static const real_t sideFrictionStiffness2 = real_t(1.0);
+void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
+
+	//calculate the impulse, so that the wheels don't move sidewards
+	int numWheel = wheels.size();
+	if (!numWheel)
+		return;
+
+	m_forwardWS.resize(numWheel);
+	m_axle.resize(numWheel);
+	m_forwardImpulse.resize(numWheel);
+	m_sideImpulse.resize(numWheel);
+
+	int numWheelsOnGround = 0;
+
+
+	//collapse all those loops into one!
+	for (int i=0;i<wheels.size();i++)
+	{
+		VehicleWheel& wheelInfo = *wheels[i];
+		if (wheelInfo.m_raycastInfo.m_isInContact)
+			numWheelsOnGround++;
+		m_sideImpulse[i] = real_t(0.);
+		m_forwardImpulse[i] = real_t(0.);
+
+	}
+
+	{
+
+		for (int i=0;i<wheels.size();i++)
+		{
+
+			VehicleWheel& wheelInfo = *wheels[i];
+
+
+			if (wheelInfo.m_raycastInfo.m_isInContact)
+			{
+
+				//const btTransform& wheelTrans = getWheelTransformWS( i );
+
+				Matrix3 wheelBasis0 = wheelInfo.get_global_transform().basis;
+				m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
+				m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
+
+				const Vector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
+				real_t proj = m_axle[i].dot(surfNormalWS);
+				m_axle[i] -= surfNormalWS * proj;
+				m_axle[i] = m_axle[i].normalized();
+
+				m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
+				m_forwardWS[i].normalize();
+
+
+				_resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
+						       wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
+							m_axle[i],m_sideImpulse[i]);
+
+				m_sideImpulse[i] *= sideFrictionStiffness2;
+
+
+			}
+		}
+	}
+
+	real_t sideFactor = real_t(1.);
+	real_t fwdFactor = 0.5;
+
+	bool sliding = false;
+	{
+		for (int wheel =0;wheel <wheels.size();wheel++)
+		{
+			VehicleWheel& wheelInfo = *wheels[wheel];
+
+
+			//class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
+
+			real_t	rollingFriction = 0.f;
+
+			if (wheelInfo.m_raycastInfo.m_isInContact)
+			{
+				if (wheelInfo.m_engineForce != 0.f)
+				{
+					rollingFriction = wheelInfo.m_engineForce* s->get_step();
+				} else
+				{
+					real_t defaultRollingFrictionImpulse = 0.f;
+					real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
+					btVehicleWheelContactPoint contactPt(s,wheelInfo.m_raycastInfo.m_groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse);
+					rollingFriction = _calc_rolling_friction(contactPt);
+				}
+			}
+
+			//switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
+
+
+
+
+			m_forwardImpulse[wheel] = real_t(0.);
+			wheelInfo.m_skidInfo= real_t(1.);
+
+			if (wheelInfo.m_raycastInfo.m_isInContact)
+			{
+				wheelInfo.m_skidInfo= real_t(1.);
+
+				real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip;
+				real_t maximpSide = maximp;
+
+				real_t maximpSquared = maximp * maximpSide;
+
+
+				m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep;
+
+				real_t x = (m_forwardImpulse[wheel] ) * fwdFactor;
+				real_t y = (m_sideImpulse[wheel] ) * sideFactor;
+
+				real_t impulseSquared = (x*x + y*y);
+
+				if (impulseSquared > maximpSquared)
+				{
+					sliding = true;
+
+					real_t factor = maximp / Math::sqrt(impulseSquared);
+
+					wheelInfo.m_skidInfo *= factor;
+				}
+			}
+
+		}
+	}
+
+
+
+
+	if (sliding)
+	{
+		for (int wheel = 0;wheel < wheels.size(); wheel++)
+		{
+			if (m_sideImpulse[wheel] != real_t(0.))
+			{
+				if (wheels[wheel]->m_skidInfo< real_t(1.))
+				{
+					m_forwardImpulse[wheel] *=	wheels[wheel]->m_skidInfo;
+					m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+				}
+			}
+		}
+	}
+
+	// apply the impulses
+	{
+		for (int wheel = 0;wheel<wheels.size(); wheel++)
+		{
+			VehicleWheel& wheelInfo = *wheels[wheel];
+
+			Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
+					s->get_transform().origin;
+
+			if (m_forwardImpulse[wheel] != real_t(0.))
+			{
+				s->apply_impulse(rel_pos,m_forwardWS[wheel]*(m_forwardImpulse[wheel]));
+			}
+			if (m_sideImpulse[wheel] != real_t(0.))
+			{
+				PhysicsBody* groundObject = wheelInfo.m_raycastInfo.m_groundObject;
+
+				Vector3 rel_pos2;
+				if (groundObject) {
+					rel_pos2=wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin;
+				}
+
+
+				Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
+
+#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
+				Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1];//getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
+				rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence));
+#else
+				rel_pos[1] *= wheelInfo.m_rollInfluence; //?
+#endif
+				s->apply_impulse(rel_pos,sideImp);
+
+				//apply friction impulse on the ground
+				//todo
+				//groundObject->applyImpulse(-sideImp,rel_pos2);
+			}
+		}
+	}
+
+
+}
+
+
+void VehicleBody::_direct_state_changed(Object *p_state) {
+
+
+	PhysicsDirectBodyState *s = p_state->cast_to<PhysicsDirectBodyState>();
+
+	set_ignore_transform_notification(true);
+	set_global_transform(s->get_transform());
+	set_ignore_transform_notification(false);
+
+
+	float step = s->get_step();
+
+	for(int i=0;i<wheels.size();i++) {
+
+		_update_wheel(i,s);
+	}
+
+	for(int i=0;i<wheels.size();i++) {
+
+		_ray_cast(i,s);
+	}
+
+	_update_suspension(s);
+
+	for(int i=0;i<wheels.size();i++) {
+
+		//apply suspension force
+		VehicleWheel& wheel = *wheels[i];
+
+		real_t suspensionForce = wheel.m_wheelsSuspensionForce;
+
+		if (suspensionForce > wheel.m_maxSuspensionForce)
+		{
+			suspensionForce = wheel.m_maxSuspensionForce;
+		}
+		Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
+		Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+		s->apply_impulse(relpos,impulse);
+		//getRigidBody()->applyImpulse(impulse, relpos);
+
+	}
+
+
+	_update_friction(s);
+
+
+	for (int i=0;i<wheels.size();i++)
+	{
+		VehicleWheel& wheel = *wheels[i];
+		Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - s->get_transform().origin;
+		Vector3 vel  = s->get_linear_velocity() + (s->get_angular_velocity()).cross(relpos);// * mPos);
+
+		if (wheel.m_raycastInfo.m_isInContact)
+		{
+			const Transform&	chassisWorldTransform = s->get_transform();
+
+			Vector3 fwd (
+				chassisWorldTransform.basis[0][Vector3::AXIS_Z],
+				chassisWorldTransform.basis[1][Vector3::AXIS_Z],
+				chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
+
+			real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
+			fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
+
+			real_t proj2 = fwd.dot(vel);
+
+			wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
+			wheel.m_rotation += wheel.m_deltaRotation;
+
+		} else
+		{
+			wheel.m_rotation += wheel.m_deltaRotation;
+		}
+
+		wheel.m_deltaRotation *= real_t(0.99);//damping of rotation when not in contact
+
+	}
+
+}
+
+void VehicleBody::set_mass(real_t p_mass) {
+
+	mass=p_mass;
+	PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass);
+}
+
+real_t VehicleBody::get_mass() const{
+
+	return mass;
+}
+
+
+void VehicleBody::set_friction(real_t p_friction) {
+
+	friction=p_friction;
+	PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction);
+}
+
+real_t VehicleBody::get_friction() const{
+
+	return friction;
+}
+
+void VehicleBody::_bind_methods(){
+
+	ObjectTypeDB::bind_method(_MD("set_mass","mass"),&VehicleBody::set_mass);
+	ObjectTypeDB::bind_method(_MD("get_mass"),&VehicleBody::get_mass);
+
+	ObjectTypeDB::bind_method(_MD("set_friction","friction"),&VehicleBody::set_friction);
+	ObjectTypeDB::bind_method(_MD("get_friction"),&VehicleBody::get_friction);
+
+	ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&VehicleBody::_direct_state_changed);
+
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass"));
+	ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction"));
+
+
+}
+
+
+
+VehicleBody::VehicleBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
+
+
+	m_pitchControl=0;
+	m_currentVehicleSpeedKmHour = real_t(0.);
+	m_steeringValue = real_t(0.);
+
+
+	mass=1;
+	friction=1;
+
+	ccd=false;
+
+	exclude.insert(get_rid());
+	PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed");
+
+}
+

+ 142 - 0
scene/3d/vehicle_body.h

@@ -0,0 +1,142 @@
+#ifndef VEHICLE_BODY_H
+#define VEHICLE_BODY_H
+
+#include "scene/3d/physics_body.h"
+
+class VehicleBody;
+
+class VehicleWheel : public Spatial {
+
+	OBJ_TYPE(VehicleWheel,Spatial);
+
+friend class VehicleBody;
+
+
+	Transform m_worldTransform;
+	Transform local_xform;
+
+
+	Vector3	m_chassisConnectionPointCS; //const
+	Vector3	m_wheelDirectionCS;//const
+	Vector3	m_wheelAxleCS; // const or modified by steering
+
+	real_t m_suspensionRestLength;
+	real_t m_maxSuspensionTravelCm;
+	real_t m_wheelRadius;
+
+	real_t m_suspensionStiffness;
+	real_t m_wheelsDampingCompression;
+	real_t m_wheelsDampingRelaxation;
+	real_t m_frictionSlip;
+	real_t m_maxSuspensionForce;
+	bool m_bIsFrontWheel;
+
+	VehicleBody *body;
+
+//	btVector3	m_wheelAxleCS; // const or modified by steering ?
+
+	real_t	m_steering;
+	real_t	m_rotation;
+	real_t	m_deltaRotation;
+	real_t	m_rollInfluence;
+	real_t	m_engineForce;
+	real_t	m_brake;
+
+	real_t	m_clippedInvContactDotSuspension;
+	real_t	m_suspensionRelativeVelocity;
+	//calculated by suspension
+	real_t	m_wheelsSuspensionForce;
+	real_t	m_skidInfo;
+
+
+	struct RaycastInfo {
+		//set by raycaster
+		Vector3	m_contactNormalWS;//contactnormal
+		Vector3	m_contactPointWS;//raycast hitpoint
+		real_t	m_suspensionLength;
+		Vector3	m_hardPointWS;//raycast starting point
+		Vector3	m_wheelDirectionWS; //direction in worldspace
+		Vector3	m_wheelAxleWS; // axle in worldspace
+		bool m_isInContact;
+		PhysicsBody* m_groundObject; //could be general void* ptr
+	} m_raycastInfo;
+
+	void _update(PhysicsDirectBodyState *s);
+
+protected:
+	void _notification(int p_what);
+	static void _bind_methods();
+
+public:
+
+
+	VehicleWheel();
+
+};
+
+
+class VehicleBody : public PhysicsBody {
+
+	OBJ_TYPE(VehicleBody,PhysicsBody);
+
+	real_t mass;
+	real_t friction;
+
+	Vector3 linear_velocity;
+	Vector3  angular_velocity;
+	bool ccd;
+
+	real_t	m_pitchControl;
+	real_t	m_steeringValue;
+	real_t  m_currentVehicleSpeedKmHour;
+
+	Set<RID> exclude;
+
+	Vector<Vector3>	m_forwardWS;
+	Vector<Vector3>	m_axle;
+	Vector<real_t>	m_forwardImpulse;
+	Vector<real_t>	m_sideImpulse;
+
+	struct btVehicleWheelContactPoint {
+		PhysicsDirectBodyState *m_s;
+		PhysicsBody* m_body1;
+		Vector3	m_frictionPositionWorld;
+		Vector3	m_frictionDirectionWorld;
+		real_t	m_jacDiagABInv;
+		real_t	m_maxImpulse;
+
+
+		btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse);
+	};
+
+	void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1, PhysicsBody* body2, const Vector3& pos2, const Vector3& normal, real_t& impulse);
+	real_t _calc_rolling_friction(btVehicleWheelContactPoint& contactPoint);
+
+	void _update_friction(PhysicsDirectBodyState *s);
+	void _update_suspension(PhysicsDirectBodyState *s);
+	real_t _ray_cast(int p_idx,PhysicsDirectBodyState *s);
+	void _update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s);
+	void _update_wheel(int p_idx,PhysicsDirectBodyState *s);
+
+
+
+friend class VehicleWheel;
+	Vector<VehicleWheel*> wheels;
+
+	static void _bind_methods();
+
+	void _direct_state_changed(Object *p_state);
+public:
+
+
+	void set_mass(real_t p_mass);
+	real_t get_mass() const;
+
+	void set_friction(real_t p_friction);
+	real_t get_friction() const;
+
+
+	VehicleBody();
+};
+
+#endif // VEHICLE_BODY_H

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

@@ -195,6 +195,7 @@ void GeometryInstance::_notification(int p_what) {
 			_find_baked_light();
 		}
 
+		_update_visibility();
 
 	} else if (p_what==NOTIFICATION_EXIT_WORLD) {
 
@@ -207,8 +208,13 @@ void GeometryInstance::_notification(int p_what) {
 			_baked_light_changed();
 
 		}
+
+	} if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+		_update_visibility();
 	}
 
+
 }
 
 void GeometryInstance::_baked_light_changed() {
@@ -241,6 +247,15 @@ void GeometryInstance::_find_baked_light() {
 	_baked_light_changed();
 }
 
+void GeometryInstance::_update_visibility() {
+
+	if (!is_inside_scene())
+		return;
+
+	_change_notify("geometry/visible");
+	VS::get_singleton()->instance_geometry_set_flag(get_instance(),VS::INSTANCE_FLAG_VISIBLE,is_visible() && flags[FLAG_VISIBLE]);
+}
+
 void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
 
 	ERR_FAIL_INDEX(p_flag,FLAG_MAX);
@@ -250,8 +265,7 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
 	flags[p_flag]=p_value;
 	VS::get_singleton()->instance_geometry_set_flag(get_instance(),(VS::InstanceFlags)p_flag,p_value);
 	if (p_flag==FLAG_VISIBLE) {
-		_change_notify("geometry/visible");
-		emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+		_update_visibility();
 	}
 	if (p_flag==FLAG_USE_BAKED_LIGHT) {
 
@@ -321,7 +335,7 @@ void GeometryInstance::_bind_methods() {
 	ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
 
-	ADD_SIGNAL( MethodInfo("visibility_changed"));
+//	ADD_SIGNAL( MethodInfo("visibility_changed"));
 
 	BIND_CONSTANT(FLAG_VISIBLE );
 	BIND_CONSTANT(FLAG_CAST_SHADOW );
@@ -346,6 +360,7 @@ GeometryInstance::GeometryInstance() {
 	flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
 	baked_light_instance=NULL;
 	baked_light_texture_id=0;
+	VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
 
 
 }

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

@@ -109,6 +109,7 @@ private:
 	int baked_light_texture_id;
 
 	void _baked_light_changed();
+	void _update_visibility();
 protected:
 
 	void _notification(int p_what);

+ 4 - 2
scene/animation/animation_player.cpp

@@ -637,14 +637,15 @@ void AnimationPlayer::_animation_process(float p_delta) {
 				play(queued.front()->get());
 				String new_name = playback.assigned;
 				queued.pop_front();
+				end_notify=false;
 				emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);
 			} else {
                 //stop();
 				playing = false;
 				_set_process(false);
+				end_notify=false;
 				emit_signal(SceneStringNames::get_singleton()->finished);
 			}
-
 		}
 
 	} else {
@@ -912,7 +913,8 @@ void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float
 	c.current.speed_scale=p_custom_scale;
 	c.assigned=p_name;
 
-	queued.clear();
+	if (!end_notify)
+		queued.clear();
 	_set_process(true); // always process when starting an animation
 	playing = true;
 

+ 18 - 0
scene/main/viewport.cpp

@@ -786,6 +786,19 @@ bool Viewport::get_render_target_filter() const{
 	return (render_target_texture->get_flags()&Texture::FLAG_FILTER)!=0;
 }
 
+void Viewport::set_render_target_gen_mipmaps(bool p_enable) {
+
+	//render_target_texture->set_flags(p_enable?int(Texture::FLAG_FILTER):int(0));
+	render_target_gen_mipmaps=p_enable;
+
+}
+
+bool Viewport::get_render_target_gen_mipmaps() const{
+
+	//return (render_target_texture->get_flags()&Texture::FLAG_FILTER)!=0;
+	return render_target_gen_mipmaps;
+}
+
 
 Matrix32 Viewport::_get_input_pre_xform() const {
 
@@ -1007,6 +1020,9 @@ void Viewport::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_render_target_filter","enable"), &Viewport::set_render_target_filter);
 	ObjectTypeDB::bind_method(_MD("get_render_target_filter"), &Viewport::get_render_target_filter);
 
+	ObjectTypeDB::bind_method(_MD("set_render_target_gen_mipmaps","enable"), &Viewport::set_render_target_gen_mipmaps);
+	ObjectTypeDB::bind_method(_MD("get_render_target_gen_mipmaps"), &Viewport::get_render_target_gen_mipmaps);
+
 	ObjectTypeDB::bind_method(_MD("set_render_target_update_mode","mode"), &Viewport::set_render_target_update_mode);
 	ObjectTypeDB::bind_method(_MD("get_render_target_update_mode"), &Viewport::get_render_target_update_mode);
 
@@ -1038,6 +1054,7 @@ void Viewport::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/enabled"), _SCS("set_as_render_target"), _SCS("is_set_as_render_target") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/v_flip"), _SCS("set_render_target_vflip"), _SCS("get_render_target_vflip") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/filter"), _SCS("set_render_target_filter"), _SCS("get_render_target_filter") );
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"render_target/gen_mipmaps"), _SCS("set_render_target_gen_mipmaps"), _SCS("get_render_target_gen_mipmaps") );
 	ADD_PROPERTY( PropertyInfo(Variant::INT,"render_target/update_mode",PROPERTY_HINT_ENUM,"Disabled,Once,When Visible,Always"), _SCS("set_render_target_update_mode"), _SCS("get_render_target_update_mode") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"audio_listener/enable_2d"), _SCS("set_as_audio_listener_2d"), _SCS("is_audio_listener_2d") );
 	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"audio_listener/enable_3d"), _SCS("set_as_audio_listener"), _SCS("is_audio_listener") );
@@ -1070,6 +1087,7 @@ Viewport::Viewport() {
 	size_override=false;
 	size_override_stretch=false;
 	size_override_size=Size2(1,1);
+	render_target_gen_mipmaps=false;
 	render_target=false;
 	render_target_vflip=false;
 	render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE;

+ 4 - 0
scene/main/viewport.h

@@ -114,6 +114,7 @@ friend class RenderTargetTexture;
 	bool transparent_bg;
 	bool render_target_vflip;
 	bool render_target_filter;
+	bool render_target_gen_mipmaps;
 
 	void _update_rect();
 
@@ -214,6 +215,9 @@ public:
 	void set_render_target_filter(bool p_enable);
 	bool get_render_target_filter() const;
 
+	void set_render_target_gen_mipmaps(bool p_enable);
+	bool get_render_target_gen_mipmaps() const;
+
 	void set_render_target_update_mode(RenderTargetUpdateMode p_mode);
 	RenderTargetUpdateMode get_render_target_update_mode() const;
 	Ref<RenderTargetTexture> get_render_target_texture() const;

+ 3 - 0
scene/register_scene_types.cpp

@@ -185,6 +185,7 @@
 #include "scene/resources/environment.h"
 #include "scene/3d/physics_body.h"
 #include "scene/3d/car_body.h"
+#include "scene/3d/vehicle_body.h"
 #include "scene/3d/body_shape.h"
 #include "scene/3d/area.h"
 #include "scene/3d/physics_joint.h"
@@ -402,6 +403,8 @@ void register_scene_types() {
 	ObjectTypeDB::register_type<RigidBody>();
 	ObjectTypeDB::register_type<CarBody>();
 	ObjectTypeDB::register_type<CarWheel>();
+	ObjectTypeDB::register_type<VehicleBody>();
+	ObjectTypeDB::register_type<VehicleWheel>();
 	ObjectTypeDB::register_type<Area>();
 	ObjectTypeDB::register_type<ProximityGroup>();
 	ObjectTypeDB::register_type<CollisionShape>();

+ 21 - 2
scene/resources/baked_light.cpp

@@ -5,6 +5,7 @@ void BakedLight::set_mode(Mode p_mode) {
 
 	mode=p_mode;
 	VS::get_singleton()->baked_light_set_mode(baked_light,(VS::BakedLightMode(p_mode)));
+
 }
 
 BakedLight::Mode BakedLight::get_mode() const{
@@ -123,7 +124,7 @@ void BakedLight::_set_lightmap_data(Array p_array){
 
 		Size2 size = p_array[i];
 		Ref<Texture> tex = p_array[i+1];
-		ERR_CONTINUE(tex.is_null());
+//		ERR_CONTINUE(tex.is_null());
 		LightMap lm;
 		lm.gen_size=size;
 		lm.texture=tex;
@@ -228,7 +229,7 @@ bool BakedLight::get_bake_flag(BakeFlags p_flags) const{
 void BakedLight::set_format(Format p_format) {
 
 	format=p_format;
-
+	VS::get_singleton()->baked_light_set_lightmap_multiplier(baked_light,format==FORMAT_HDR8?8.0:1.0);
 }
 
 BakedLight::Format BakedLight::get_format() const{
@@ -236,6 +237,17 @@ BakedLight::Format BakedLight::get_format() const{
 	return format;
 }
 
+void BakedLight::set_transfer_lightmaps_only_to_uv2(bool p_enable) {
+
+	transfer_only_uv2=p_enable;
+}
+
+bool BakedLight::get_transfer_lightmaps_only_to_uv2() const{
+
+	return transfer_only_uv2;
+}
+
+
 bool BakedLight::_set(const StringName& p_name, const Variant& p_value) {
 
 	String n = p_name;
@@ -348,6 +360,11 @@ void BakedLight::_bind_methods(){
 	ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format);
 	ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format);
 
+	ObjectTypeDB::bind_method(_MD("set_transfer_lightmaps_only_to_uv2","enable"),&BakedLight::set_transfer_lightmaps_only_to_uv2);
+	ObjectTypeDB::bind_method(_MD("get_transfer_lightmaps_only_to_uv2"),&BakedLight::get_transfer_lightmaps_only_to_uv2);
+
+
+
 
 	ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier);
 	ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier);
@@ -371,6 +388,7 @@ void BakedLight::_bind_methods(){
 	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR);
 	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT);
 	ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY);
+	ADD_PROPERTY( PropertyInfo(Variant::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::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data"));
@@ -403,6 +421,7 @@ BakedLight::BakedLight() {
 	edge_damp=0.0;
 	normal_damp=0.0;
 	format=FORMAT_RGB;
+	transfer_only_uv2=false;
 
 	flags[BAKE_DIFFUSE]=true;
 	flags[BAKE_SPECULAR]=false;

+ 4 - 0
scene/resources/baked_light.h

@@ -51,6 +51,7 @@ private:
 	float edge_damp;
 	float normal_damp;
 	int bounces;
+	bool transfer_only_uv2;
 	Format format;
 	bool flags[BAKE_MAX];
 
@@ -104,6 +105,9 @@ public:
 	void set_format(Format p_margin);
 	Format get_format() const;
 
+	void set_transfer_lightmaps_only_to_uv2(bool p_enable);
+	bool get_transfer_lightmaps_only_to_uv2() const;
+
 	void set_mode(Mode p_mode);
 	Mode get_mode() const;
 

+ 1 - 0
servers/physics/body_pair_sw.cpp

@@ -227,6 +227,7 @@ bool BodyPairSW::setup(float p_step) {
 		Vector3 global_A = xform_Au.xform(c.local_A);
 		Vector3 global_B = xform_Bu.xform(c.local_B);
 
+
 		real_t depth = c.normal.dot(global_A - global_B);
 
 		if (depth<=0) {

+ 1 - 0
servers/physics/body_sw.h

@@ -323,6 +323,7 @@ public:
 	virtual Transform get_transform() const {  return body->get_transform();  }
 
 	virtual void add_force(const Vector3& p_force, const Vector3& p_pos) {  body->add_force(p_force,p_pos); }
+	virtual void apply_impulse(const Vector3& p_pos, const Vector3& p_j) { body->apply_impulse(p_pos,p_j); }
 
 	virtual void set_sleep_state(bool p_enable) {  body->set_active(!p_enable);  }
 	virtual bool is_sleeping() const {  return !body->is_active();  }

+ 1636 - 1636
servers/physics/shape_sw.cpp

@@ -26,1639 +26,1639 @@
 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
-#include "shape_sw.h"
-#include "geometry.h"
-#include "sort.h"
-#include "quick_hull.h"
-#define _POINT_SNAP 0.001953125
-#define _EDGE_IS_VALID_SUPPORT_TRESHOLD 0.0002
-#define _FACE_IS_VALID_SUPPORT_TRESHOLD 0.9998
-
-
-void ShapeSW::configure(const AABB& p_aabb) {
-	aabb=p_aabb;
-	configured=true;
-	for (Map<ShapeOwnerSW*,int>::Element *E=owners.front();E;E=E->next()) {
-		ShapeOwnerSW* co=(ShapeOwnerSW*)E->key();
-		co->_shape_changed();
-	}
-}
-
-
-Vector3 ShapeSW::get_support(const Vector3& p_normal) const {
-
-	Vector3 res;
-	int amnt;
-	get_supports(p_normal,1,&res,amnt);
-	return res;
-}
-
-void ShapeSW::add_owner(ShapeOwnerSW *p_owner) {
-
-	Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
-	if (E) {
-		E->get()++;
-	} else {
-		owners[p_owner]=1;
-	}
-}
-
-void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){
-
-	Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
-	ERR_FAIL_COND(!E);
-	E->get()--;
-	if (E->get()==0) {
-		owners.erase(E);
-	}
-
-}
-
-bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const{
-
-	return owners.has(p_owner);
-
-}
-
-const Map<ShapeOwnerSW*,int>& ShapeSW::get_owners() const{
-	return owners;
-}
-
-
-ShapeSW::ShapeSW() {
-
-	custom_bias=0;
-	configured=false;
-}
-
-
-ShapeSW::~ShapeSW() {
-
-	ERR_FAIL_COND(owners.size());
-}
-
-
-
-Plane PlaneShapeSW::get_plane() const {
-
-	return plane;
-}
-
-void PlaneShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	// gibberish, a plane is infinity
-	r_min=-1e7;
-	r_max=1e7;
-}
-
-Vector3 PlaneShapeSW::get_support(const Vector3& p_normal) const {
-
-	return p_normal*1e15;
-}
-
-
-bool PlaneShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-	bool inters=plane.intersects_segment(p_begin,p_end,&r_result);
-	if(inters)
-		r_normal=plane.normal;
-	return inters;
-}
-
-Vector3 PlaneShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	return Vector3(); //wtf
-}
-
-void PlaneShapeSW::_setup(const Plane& p_plane)  {
-
-	plane=p_plane;
-	configure(AABB(Vector3(-1e4,-1e4,-1e4),Vector3(1e4*2,1e4*2,1e4*2)));
-}
-
-void PlaneShapeSW::set_data(const Variant& p_data) {
-
-	_setup(p_data);
-
-}
-
-Variant PlaneShapeSW::get_data() const {
-
-	return plane;
-}
-
-PlaneShapeSW::PlaneShapeSW()  {
-
-
-}
-
-//
-
-float RayShapeSW::get_length() const {
-
-	return length;
-}
-
-void RayShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	// don't think this will be even used
-	r_min=0;
-	r_max=1;
-}
-
-Vector3 RayShapeSW::get_support(const Vector3& p_normal) const {
-
-	if (p_normal.z>0)
-		return Vector3(0,0,length);
-	else
-		return Vector3(0,0,0);
-}
-
-void RayShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-	if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
-		r_amount=2;
-		r_supports[0]=Vector3(0,0,0);
-		r_supports[1]=Vector3(0,0,length);
-	} if (p_normal.z>0) {
-		r_amount=1;
-		*r_supports=Vector3(0,0,length);
-	} else {
-		r_amount=1;
-		*r_supports=Vector3(0,0,0);
-	}
-}
-
-
-bool RayShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-	return false; //simply not possible
-}
-
-Vector3 RayShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	return Vector3();
-}
-
-void RayShapeSW::_setup(float p_length)  {
-
-	length=p_length;
-	configure(AABB(Vector3(0,0,0),Vector3(0.1,0.1,length)));
-}
-
-void RayShapeSW::set_data(const Variant& p_data) {
-
-	_setup(p_data);
-
-}
-
-Variant RayShapeSW::get_data() const {
-
-	return length;
-}
-
-RayShapeSW::RayShapeSW()  {
-
-	length=1;
-}
-
-
-
-/********** SPHERE *************/
-
-real_t SphereShapeSW::get_radius() const {
-
-	return radius;
-}
-
-void SphereShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	float d = p_normal.dot( p_transform.origin );
-
-	// figure out scale at point
-	Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
-	float scale = local_normal.length();
-
-	r_min = d - (radius) * scale;
-	r_max = d + (radius) * scale;
-
-}
-
-Vector3 SphereShapeSW::get_support(const Vector3& p_normal) const {
-
-	return p_normal*radius;
-}
-
-void SphereShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-	*r_supports=p_normal*radius;
-	r_amount=1;
-}
-
-bool SphereShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-	return Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(),radius,&r_result,&r_normal);
-}
-
-Vector3 SphereShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	float s = 0.4 * p_mass * radius * radius;
-	return Vector3(s,s,s);
-}
-
-void SphereShapeSW::_setup(real_t p_radius) {
-
-
-	radius=p_radius;
-	configure(AABB( Vector3(-radius,-radius,-radius), Vector3(radius*2.0,radius*2.0,radius*2.0)));
-
-}
-
-void SphereShapeSW::set_data(const Variant& p_data) {
-
-	_setup(p_data);
-}
-
-Variant SphereShapeSW::get_data() const {
-
-	return radius;
-}
-
-SphereShapeSW::SphereShapeSW() {
-
-	radius=0;
-}
-
-
-/********** BOX *************/
-
-
-void BoxShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	// no matter the angle, the box is mirrored anyway
-	Vector3 local_normal=p_transform.basis.xform_inv(p_normal);
-
-	float length = local_normal.abs().dot(half_extents);
-	float distance = p_normal.dot( p_transform.origin );
-
-	r_min = distance - length;
-	r_max = distance + length;
-
-
-}
-
-Vector3 BoxShapeSW::get_support(const Vector3& p_normal) const {
-
-
-	Vector3 point(
-		(p_normal.x<0) ? -half_extents.x : half_extents.x,
-		(p_normal.y<0) ? -half_extents.y : half_extents.y,
-		(p_normal.z<0) ? -half_extents.z : half_extents.z
-	);
-
-	return point;
-}
-
-void BoxShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-	static const int next[3]={1,2,0};
-	static const int next2[3]={2,0,1};
-
-	for (int i=0;i<3;i++) {
-
-		Vector3 axis;
-		axis[i]=1.0;
-		float dot = p_normal.dot( axis );
-		if ( Math::abs( dot ) >  _FACE_IS_VALID_SUPPORT_TRESHOLD ) {
-
-			//Vector3 axis_b;
-
-			bool neg = dot<0;
-			r_amount = 4;
-
-			Vector3 point;
-			point[i]=half_extents[i];
-
-			int i_n=next[i];
-			int i_n2=next2[i];
-
-			static const float sign[4][2]={
-
-				{-1.0, 1.0},
-				{ 1.0, 1.0},
-				{ 1.0,-1.0},
-				{-1.0,-1.0},
-			};
-
-			for (int j=0;j<4;j++) {
-
-				point[i_n]=sign[j][0]*half_extents[i_n];
-				point[i_n2]=sign[j][1]*half_extents[i_n2];
-				r_supports[j]=neg?-point:point;
-
-			}
-
-			if (neg) {
-				SWAP( r_supports[1], r_supports[2] );
-				SWAP( r_supports[0], r_supports[3] );
-			}
-
-			return;
-		}
-
-		r_amount=0;
-
-	}
-
-	for (int i=0;i<3;i++) {
-
-		Vector3 axis;
-		axis[i]=1.0;
-
-		if (Math::abs(p_normal.dot(axis))<_EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
-			r_amount= 2;
-
-			int i_n=next[i];
-			int i_n2=next2[i];
-
-			Vector3 point=half_extents;
-
-			if (p_normal[i_n]<0) {
-				point[i_n]=-point[i_n];
-			}
-			if (p_normal[i_n2]<0) {
-				point[i_n2]=-point[i_n2];
-			}
-
-			r_supports[0] = point;
-			point[i]=-point[i];
-			r_supports[1] = point;
-			return;
-		}
-	}
-	/* USE POINT */
-
-	Vector3 point(
-		(p_normal.x<0) ? -half_extents.x : half_extents.x,
-		(p_normal.y<0) ? -half_extents.y : half_extents.y,
-		(p_normal.z<0) ? -half_extents.z : half_extents.z
-	);
-
-	r_amount=1;
-	r_supports[0]=point;
-}
-
-bool BoxShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-	AABB aabb(-half_extents,half_extents*2.0);
-
-	return aabb.intersects_segment(p_begin,p_end,&r_result,&r_normal);
-
-}
-
-Vector3 BoxShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	float lx=half_extents.x;
-	float ly=half_extents.y;
-	float lz=half_extents.z;
-
-	return Vector3(	(p_mass/3.0) * (ly*ly + lz*lz), (p_mass/3.0) * (lx*lx + lz*lz), (p_mass/3.0) * (lx*lx + ly*ly) );
-
-}
-
-void BoxShapeSW::_setup(const Vector3& p_half_extents)  {
-
-	half_extents=p_half_extents.abs();
-
-	configure(AABB(-half_extents,half_extents*2));
-
-
-}
-
-void BoxShapeSW::set_data(const Variant& p_data) {
-
-
-	_setup(p_data);
-}
-
-Variant BoxShapeSW::get_data() const {
-
-	return half_extents;
-}
-
-BoxShapeSW::BoxShapeSW()  {
-
-
-}
-
-
-/********** CAPSULE *************/
-
-
-void CapsuleShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	Vector3 n=p_transform.basis.xform_inv(p_normal).normalized();
-	float h = (n.z > 0) ? height : -height;
-
-	n *= radius;
-	n.z += h * 0.5;
-
-	r_max=p_normal.dot(p_transform.xform(n));
-	r_min=p_normal.dot(p_transform.xform(-n));
-	return;
-
-	n = p_transform.basis.xform(n);
-
-	float distance = p_normal.dot( p_transform.origin );
-	float length = Math::abs(p_normal.dot(n));
-	r_min = distance - length;
-	r_max = distance + length;
-
-	ERR_FAIL_COND( r_max < r_min );
-
-}
-
-Vector3 CapsuleShapeSW::get_support(const Vector3& p_normal) const {
-
-	Vector3 n=p_normal;
-
-	float h = (n.z > 0) ? height : -height;
-
-	n*=radius;
-	n.z += h*0.5;
-	return n;
-}
-
-void CapsuleShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-
-	Vector3 n=p_normal;
-
-	float d = n.z;
-
-	if (Math::abs( d )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
-
-		// make it flat
-		n.z=0.0;
-		n.normalize();
-		n*=radius;
-
-		r_amount=2;
-		r_supports[0]=n;
-		r_supports[0].z+=height*0.5;
-		r_supports[1]=n;
-		r_supports[1].z-=height*0.5;
-
-	} else {
-
-		float h = (d > 0) ? height : -height;
-
-		n*=radius;
-		n.z += h*0.5;
-		r_amount=1;
-		*r_supports=n;
-
-	}
-
-}
-
-
-bool CapsuleShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-	Vector3 norm=(p_end-p_begin).normalized();
-	float min_d=1e20;
-
-
-	Vector3 res,n;
-	bool collision=false;
-
-	Vector3 auxres,auxn;
-	bool collided;
-
-	// test against cylinder and spheres :-|
-
-	collided = Geometry::segment_intersects_cylinder(p_begin,p_end,height,radius,&auxres,&auxn);
-
-	if (collided) {
-		float d=norm.dot(auxres);
-		if (d<min_d) {
-			min_d=d;
-			res=auxres;
-			n=auxn;
-			collision=true;
-		}
-	}
-
-	collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*0.5),radius,&auxres,&auxn);
-
-	if (collided) {
-		float d=norm.dot(auxres);
-		if (d<min_d) {
-			min_d=d;
-			res=auxres;
-			n=auxn;
-			collision=true;
-		}
-	}
-
-	collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*-0.5),radius,&auxres,&auxn);
-
-	if (collided) {
-		float d=norm.dot(auxres);
-
-		if (d<min_d) {
-			min_d=d;
-			res=auxres;
-			n=auxn;
-			collision=true;
-		}
-	}
-
-	if (collision) {
-
-		r_result=res;
-		r_normal=n;
-	}
-	return collision;
-}
-
-Vector3 CapsuleShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	// use crappy AABB approximation
-	Vector3 extents=get_aabb().size*0.5;
-
-	return Vector3(
-		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
-		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
-		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
-	);
-
-}
-
-
-
-
-void CapsuleShapeSW::_setup(real_t p_height,real_t p_radius)  {
-
-	height=p_height;
-	radius=p_radius;
-	configure(AABB(Vector3(-radius,-radius,-height*0.5-radius),Vector3(radius*2,radius*2,height+radius*2.0)));
-
-}
-
-void CapsuleShapeSW::set_data(const Variant& p_data) {
-
-	Dictionary d = p_data;
-	ERR_FAIL_COND(!d.has("radius"));
-	ERR_FAIL_COND(!d.has("height"));
-	_setup(d["height"],d["radius"]);
-
-}
-
-Variant CapsuleShapeSW::get_data() const {
-
-	Dictionary d;
-	d["radius"]=radius;
-	d["height"]=height;
-	return d;
-
-}
-
-
-CapsuleShapeSW::CapsuleShapeSW()  {
-
-	height=radius=0;
-
-}
-
-/********** CONVEX POLYGON *************/
-
-
-void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-
-	int vertex_count=mesh.vertices.size();
-	if (vertex_count==0)
-		return;
-
-	const Vector3 *vrts=&mesh.vertices[0];
-
-	for (int i=0;i<vertex_count;i++) {
-
-		float d=p_normal.dot( p_transform.xform( vrts[i] ) );
-
-		if (i==0 || d > r_max)
-			r_max=d;
-		if (i==0 || d < r_min)
-			r_min=d;
-	}
-}
-
-Vector3 ConvexPolygonShapeSW::get_support(const Vector3& p_normal) const {
-
-	Vector3 n=p_normal;
-
-	int vert_support_idx=-1;
-	float support_max;
-
-	int vertex_count=mesh.vertices.size();
-	if (vertex_count==0)
-		return Vector3();
-
-	const Vector3 *vrts=&mesh.vertices[0];
-
-	for (int i=0;i<vertex_count;i++) {
-
-		float d=n.dot(vrts[i]);
-
-		if (i==0 || d > support_max) {
-			support_max=d;
-			vert_support_idx=i;
-		}
-	}
-
-	return  vrts[vert_support_idx];
-
-}
-
-
-
-void ConvexPolygonShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-	const Geometry::MeshData::Face *faces = mesh.faces.ptr();
-	int fc = mesh.faces.size();
-
-	const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
-	int ec = mesh.edges.size();
-
-	const Vector3 *vertices = mesh.vertices.ptr();
-	int vc = mesh.vertices.size();
-
-	//find vertex first
-	real_t max;
-	int vtx;
-
-	for (int i=0;i<vc;i++) {
-
-		float d=p_normal.dot(vertices[i]);
-
-		if (i==0 || d > max) {
-			max=d;
-			vtx=i;
-		}
-	}
-
-
-	for(int i=0;i<fc;i++) {
-
-		if (faces[i].plane.normal.dot(p_normal)>_FACE_IS_VALID_SUPPORT_TRESHOLD) {
-
-			int ic = faces[i].indices.size();
-			const int *ind=faces[i].indices.ptr();
-
-			bool valid=false;
-			for(int j=0;j<ic;j++) {
-				if (ind[j]==vtx) {
-					valid=true;
-					break;
-				}
-			}
-
-			if (!valid)
-				continue;
-
-			int m = MIN(p_max,ic);
-			for(int j=0;j<m;j++) {
-
-				r_supports[j]=vertices[ind[j]];
-			}
-			r_amount=m;
-			return;
-		}
-	}
-
-	for(int i=0;i<ec;i++) {
-
-
-		float dot=(vertices[edges[i].a]-vertices[edges[i].b]).normalized().dot(p_normal);
-		dot=ABS(dot);
-		if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD && (edges[i].a==vtx || edges[i].b==vtx)) {
-
-			r_amount=2;
-			r_supports[0]=vertices[edges[i].a];
-			r_supports[1]=vertices[edges[i].b];
-			return;
-		}
-	}
-
-
-	r_supports[0]=vertices[vtx];
-	r_amount=1;
-}
-
-bool ConvexPolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-
-
-	const Geometry::MeshData::Face *faces = mesh.faces.ptr();
-	int fc = mesh.faces.size();
-
-	const Vector3 *vertices = mesh.vertices.ptr();
-	int vc = mesh.vertices.size();
-
-	Vector3 n = p_end-p_begin;
-	float min = 1e20;
-	bool col=false;
-
-	for(int i=0;i<fc;i++) {
-
-		if (faces[i].plane.normal.dot(n) > 0)
-			continue; //opposing face
-
-		int ic = faces[i].indices.size();
-		const int *ind=faces[i].indices.ptr();
-
-		for(int j=1;j<ic-1;j++) {
-
-			Face3 f(vertices[ind[0]],vertices[ind[i]],vertices[ind[i+1]]);
-			Vector3 result;
-			if (f.intersects_segment(p_begin,p_end,&result)) {
-				float d = n.dot(result);
-				if (d<min) {
-					min=d;
-					r_result=result;
-					r_normal=faces[i].plane.normal;
-					col=true;
-				}
-
-				break;
-			}
-
-		}
-	}
-
-	return col;
-
-}
-
-Vector3 ConvexPolygonShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	// use crappy AABB approximation
-	Vector3 extents=get_aabb().size*0.5;
-
-	return  Vector3(
-		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
-		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
-		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
-	);
-
-}
-
-void ConvexPolygonShapeSW::_setup(const Vector<Vector3>& p_vertices)  {
-
-	Error err = QuickHull::build(p_vertices,mesh);
-	AABB _aabb;
-
-	for(int i=0;i<mesh.vertices.size();i++) {
-
-		if (i==0)
-			_aabb.pos=mesh.vertices[i];
-		else
-			_aabb.expand_to(mesh.vertices[i]);
-	}
-
-	configure(_aabb);
-
-
-}
-
-void ConvexPolygonShapeSW::set_data(const Variant& p_data) {
-
-	_setup(p_data);
-
-}
-
-Variant ConvexPolygonShapeSW::get_data() const {
-
-	return mesh.vertices;
-}
-
-
-ConvexPolygonShapeSW::ConvexPolygonShapeSW()  {
-
-
-}
-
-
-/********** FACE POLYGON *************/
-
-
-void FaceShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	for (int i=0;i<3;i++) {
-
-		Vector3 v=p_transform.xform(vertex[i]);
-		float d=p_normal.dot(v);
-
-		if (i==0 || d > r_max)
-			r_max=d;
-
-		if (i==0 || d < r_min)
-			r_min=d;
-	}
-}
-
-Vector3 FaceShapeSW::get_support(const Vector3& p_normal) const {
-
-
-	Vector3 n=p_normal;
-
-	int vert_support_idx=-1;
-	float support_max;
-
-	for (int i=0;i<3;i++) {
-
-		//float d=n.dot(vertex[i]);
-		float d=p_normal.dot(vertex[i]);
-
-		if (i==0 || d > support_max) {
-			support_max=d;
-			vert_support_idx=i;
-		}
-	}
-
-	return vertex[vert_support_idx];
-}
-
-void FaceShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-	Vector3 n=p_normal;
-
-	/** TEST FACE AS SUPPORT **/
-	if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_TRESHOLD) {
-
-		r_amount=3;
-		for (int i=0;i<3;i++) {
-
-			r_supports[i]=vertex[i];
-		}
-		return;
-
-	}
-
-	/** FIND SUPPORT VERTEX **/
-
-	int vert_support_idx=-1;
-	float support_max;
-
-	for (int i=0;i<3;i++) {
-
-		float d=n.dot(vertex[i]);
-
-		if (i==0 || d > support_max) {
-			support_max=d;
-			vert_support_idx=i;
-		}
-	}
-
-	/** TEST EDGES AS SUPPORT **/
-
-	for (int i=0;i<3;i++) {
-
-		int nx=(i+1)%3;
-		//if (i!=vert_support_idx && nx!=vert_support_idx)
-		//	continue;
-
-	// check if edge is valid as a support
-		float dot=(vertex[i]-vertex[nx]).normalized().dot(n);
-		dot=ABS(dot);
-		if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
-			r_amount=2;
-			r_supports[0]=vertex[i];
-			r_supports[1]=vertex[nx];
-			return;
-		}
-	}
-
-	r_amount=1;
-	r_supports[0]=vertex[vert_support_idx];
-}
-
-bool FaceShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-
-	bool c=Geometry::segment_intersects_triangle(p_begin,p_end,vertex[0],vertex[1],vertex[2],&r_result);
-	if (c)
-		r_normal=Plane(vertex[0],vertex[1],vertex[2]).normal;
-
-	return c;
-}
-
-Vector3 FaceShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
-
-}
-
-FaceShapeSW::FaceShapeSW()  {
-
-	configure(AABB());
-
-}
-
-
-
-DVector<Vector3> ConcavePolygonShapeSW::get_faces() const {
-
-
-	DVector<Vector3> rfaces;
-	rfaces.resize(faces.size()*3);
-
-	for(int i=0;i<faces.size();i++) {
-
-		Face f=faces.get(i);
-
-		for(int j=0;j<3;j++) {
-
-			rfaces.set(i*3+j, vertices.get( f.indices[j] ) );
-		}
-	}
-
-	return rfaces;
-}
-
-void ConcavePolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	int count=vertices.size();
-	DVector<Vector3>::Read r=vertices.read();
-	const Vector3 *vptr=r.ptr();
-
-	for (int i=0;i<count;i++) {
-
-		float d=p_normal.dot( p_transform.xform( vptr[i] ) );
-
-		if (i==0 || d > r_max)
-			r_max=d;
-		if (i==0 || d < r_min)
-			r_min=d;
-
-	}
-}
-
-Vector3 ConcavePolygonShapeSW::get_support(const Vector3& p_normal) const {
-
-
-	int count=vertices.size();
-	DVector<Vector3>::Read r=vertices.read();
-	const Vector3 *vptr=r.ptr();
-
-	Vector3 n=p_normal;
-
-	int vert_support_idx=-1;
-	float support_max;
-
-	for (int i=0;i<count;i++) {
-
-		float d=n.dot(vptr[i]);
-
-		if (i==0 || d > support_max) {
-			support_max=d;
-			vert_support_idx=i;
-		}
-	}
-
-
-	return vptr[vert_support_idx];
-
-}
-
-void ConcavePolygonShapeSW::_cull_segment(int p_idx,_SegmentCullParams *p_params) const {
-
-	const BVH *bvh=&p_params->bvh[p_idx];
-
-
-	//if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
-	//	return; //test against whole AABB, which isn't very costly
-
-
-	//printf("addr: %p\n",bvh);
-	if (!bvh->aabb.intersects_segment(p_params->from,p_params->to)) {
-
-		return;
-	}
-
-
-	if (bvh->face_index>=0) {
-
-
-		Vector3 res;
-		Vector3 vertices[3]={
-			p_params->vertices[ p_params->faces[ bvh->face_index ].indices[0] ],
-			p_params->vertices[ p_params->faces[ bvh->face_index ].indices[1] ],
-			p_params->vertices[ p_params->faces[ bvh->face_index ].indices[2] ]
-		};
-
-		if (Geometry::segment_intersects_triangle(
-				p_params->from,
-				p_params->to,
-				vertices[0],
-				vertices[1],
-				vertices[2],
-				&res)) {
-
-
-			float d=p_params->normal.dot(res) - p_params->normal.dot(p_params->from);
-			//TODO, seems segmen/triangle intersection is broken :(
-			if (d>0 && d<p_params->min_d) {
-
-				p_params->min_d=d;
-				p_params->result=res;
-				p_params->normal=Plane(vertices[0],vertices[1],vertices[2]).normal;
-				p_params->collisions++;
-			}
-
-		}
-
-
-
-	} else {
-
-		if (bvh->left>=0)
-			_cull_segment(bvh->left,p_params);
-		if (bvh->right>=0)
-			_cull_segment(bvh->right,p_params);
-
-
-	}
-}
-
-bool ConcavePolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-	// unlock data
-	DVector<Face>::Read fr=faces.read();
-	DVector<Vector3>::Read vr=vertices.read();
-	DVector<BVH>::Read br=bvh.read();
-
-
-	_SegmentCullParams params;
-	params.from=p_begin;
-	params.to=p_end;
-	params.collisions=0;
-	params.normal=(p_end-p_begin).normalized();
-
-	params.faces=fr.ptr();
-	params.vertices=vr.ptr();
-	params.bvh=br.ptr();
-
-	params.min_d=1e20;
-	// cull
-	_cull_segment(0,&params);
-
-	if (params.collisions>0) {
-
-
-		r_result=params.result;
-		r_normal=params.normal;
-		return true;
-	} else {
-
-		return false;
-	}
-}
-
-void ConcavePolygonShapeSW::_cull(int p_idx,_CullParams *p_params) const {
-
-	const BVH* bvh=&p_params->bvh[p_idx];
-
-	if (!p_params->aabb.intersects( bvh->aabb ))
-		return;
-
-	if (bvh->face_index>=0) {
-
-		const Face *f=&p_params->faces[ bvh->face_index ];
-		FaceShapeSW *face=p_params->face;
-		face->normal=f->normal;
-		face->vertex[0]=p_params->vertices[f->indices[0]];
-		face->vertex[1]=p_params->vertices[f->indices[1]];
-		face->vertex[2]=p_params->vertices[f->indices[2]];
-		p_params->callback(p_params->userdata,face);
-
-	} else {
-
-		if (bvh->left>=0) {
-
-			_cull(bvh->left,p_params);
-
-		}
-
-		if (bvh->right>=0) {
-
-			_cull(bvh->right,p_params);
-		}
-
-	}
-}
-
-void ConcavePolygonShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
-
-	// make matrix local to concave
-
-	AABB local_aabb=p_local_aabb;
-
-	// unlock data
-	DVector<Face>::Read fr=faces.read();
-	DVector<Vector3>::Read vr=vertices.read();
-	DVector<BVH>::Read br=bvh.read();
-
-	FaceShapeSW face; // use this to send in the callback
-
-	_CullParams params;
-	params.aabb=local_aabb;
-	params.face=&face;
-	params.faces=fr.ptr();
-	params.vertices=vr.ptr();
-	params.bvh=br.ptr();
-	params.callback=p_callback;
-	params.userdata=p_userdata;
-
-	// cull
-	_cull(0,&params);
-
-}
-
-Vector3 ConcavePolygonShapeSW::get_moment_of_inertia(float p_mass) const {
-
-	// use crappy AABB approximation
-	Vector3 extents=get_aabb().size*0.5;
-
-	return Vector3(
-		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
-		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
-		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
-	);
-}
-
-
-struct _VolumeSW_BVH_Element {
-
-	AABB aabb;
-	Vector3 center;
-	int face_index;
-};
-
-struct _VolumeSW_BVH_CompareX {
-
-	_FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
-		return a.center.x<b.center.x;
-	}
-};
-
-
-struct _VolumeSW_BVH_CompareY {
-
-	_FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
-		return a.center.y<b.center.y;
-	}
-};
-
-struct _VolumeSW_BVH_CompareZ {
-
-	_FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
-		return a.center.z<b.center.z;
-	}
-};
-
-struct _VolumeSW_BVH {
-
-	AABB aabb;
-	_VolumeSW_BVH *left;
-	_VolumeSW_BVH *right;
-
-	int face_index;
-};
-
-
-_VolumeSW_BVH* _volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements,int p_size,int &count) {
-
-	_VolumeSW_BVH* bvh = memnew( _VolumeSW_BVH );
-
-	if (p_size==1) {
-		//leaf
-		bvh->aabb=p_elements[0].aabb;
-		bvh->left=NULL;
-		bvh->right=NULL;
-		bvh->face_index=p_elements->face_index;
-		count++;
-		return bvh;
-	} else {
-
-		bvh->face_index=-1;
-	}
-
-	AABB aabb;
-	for(int i=0;i<p_size;i++) {
-
-		if (i==0)
-			aabb=p_elements[i].aabb;
-		else
-			aabb.merge_with(p_elements[i].aabb);
-	}
-	bvh->aabb=aabb;
-	switch(aabb.get_longest_axis_index()) {
-
-		case 0: {
-
-			SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareX> sort_x;
-			sort_x.sort(p_elements,p_size);
-
-		} break;
-		case 1: {
-
-			SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareY> sort_y;
-			sort_y.sort(p_elements,p_size);
-		} break;
-		case 2: {
-
-			SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareZ> sort_z;
-			sort_z.sort(p_elements,p_size);
-		} break;
-	}
-
-	int split=p_size/2;
-	bvh->left=_volume_sw_build_bvh(p_elements,split,count);
-	bvh->right=_volume_sw_build_bvh(&p_elements[split],p_size-split,count);
-
-//	printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
-	count++;
-	return bvh;
-}
-
-
-void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx) {
-
-	int idx=p_idx;
-
-
-	p_bvh_array[idx].aabb=p_bvh_tree->aabb;
-	p_bvh_array[idx].face_index=p_bvh_tree->face_index;
-//	printf("%p - %i: %i(%p)  -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
-
-
-	if (p_bvh_tree->left) {
-		p_bvh_array[idx].left=++p_idx;
-		_fill_bvh(p_bvh_tree->left,p_bvh_array,p_idx);
-
-	} else {
-
-		p_bvh_array[p_idx].left=-1;
-	}
-
-	if (p_bvh_tree->right) {
-		p_bvh_array[idx].right=++p_idx;
-		_fill_bvh(p_bvh_tree->right,p_bvh_array,p_idx);
-
-	} else {
-
-		p_bvh_array[p_idx].right=-1;
-	}
-
-	memdelete(p_bvh_tree);
-
-}
-
-void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) {
-
-	int src_face_count=p_faces.size();
-	ERR_FAIL_COND(src_face_count%3);
-	src_face_count/=3;
-
-	DVector<Vector3>::Read r = p_faces.read();
-	const Vector3 * facesr= r.ptr();
-
-#if 0
-	Map<Vector3,int> point_map;
-	List<Face> face_list;
-
-
-	for(int i=0;i<src_face_count;i++) {
-
-		Face3 faceaux;
-
-		for(int j=0;j<3;j++) {
-
-			faceaux.vertex[j]=facesr[i*3+j].snapped(_POINT_SNAP);
-			//faceaux.vertex[j]=facesr[i*3+j];//facesr[i*3+j].snapped(_POINT_SNAP);
-		}
-
-		ERR_CONTINUE( faceaux.is_degenerate() );
-
-		Face face;
-
-		for(int j=0;j<3;j++) {
-
-
-			Map<Vector3,int>::Element *E=point_map.find(faceaux.vertex[j]);
-			if (E) {
-
-				face.indices[j]=E->value();
-			} else {
-
-				face.indices[j]=point_map.size();
-				point_map.insert(faceaux.vertex[j],point_map.size());
-
-			}
-		}
-
-		face_list.push_back(face);
-	}
-
-	vertices.resize( point_map.size() );
-
-	DVector<Vector3>::Write vw = vertices.write();
-	Vector3 *verticesw=vw.ptr();
-
-	AABB _aabb;
-
-	for( Map<Vector3,int>::Element *E=point_map.front();E;E=E->next()) {
-
-		if (E==point_map.front()) {
-			_aabb.pos=E->key();
-		} else {
-
-			_aabb.expand_to(E->key());
-		}
-		verticesw[E->value()]=E->key();
-	}
-
-	point_map.clear(); // not needed anymore
-
-	faces.resize(face_list.size());
-	DVector<Face>::Write w = faces.write();
-	Face *facesw=w.ptr();
-
-	int fc=0;
-
-	for( List<Face>::Element *E=face_list.front();E;E=E->next()) {
-
-		facesw[fc++]=E->get();
-	}
-
-	face_list.clear();
-
-
-	DVector<_VolumeSW_BVH_Element> bvh_array;
-	bvh_array.resize( fc );
-
-	DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
-	_VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
-
-
-	for(int i=0;i<fc;i++) {
-
-		AABB face_aabb;
-		face_aabb.pos=verticesw[facesw[i].indices[0]];
-		face_aabb.expand_to( verticesw[facesw[i].indices[1]] );
-		face_aabb.expand_to( verticesw[facesw[i].indices[2]] );
-
-		bvh_arrayw[i].face_index=i;
-		bvh_arrayw[i].aabb=face_aabb;
-		bvh_arrayw[i].center=face_aabb.pos+face_aabb.size*0.5;
-
-	}
-
-	w=DVector<Face>::Write();
-	vw=DVector<Vector3>::Write();
-
-
-	int count=0;
-	_VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,fc,count);
-
-	ERR_FAIL_COND(count==0);
-
-	bvhw=DVector<_VolumeSW_BVH_Element>::Write();
-
-	bvh.resize( count+1 );
-
-	DVector<BVH>::Write bvhw2 = bvh.write();
-	BVH*bvh_arrayw2=bvhw2.ptr();
-
-	int idx=0;
-	_fill_bvh(bvh_tree,bvh_arrayw2,idx);
-
-	set_aabb(_aabb);
-
-#else
-	DVector<_VolumeSW_BVH_Element> bvh_array;
-	bvh_array.resize( src_face_count );
-
-	DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
-	_VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
-
-	faces.resize(src_face_count);
-	DVector<Face>::Write w = faces.write();
-	Face *facesw=w.ptr();
-
-	vertices.resize( src_face_count*3 );
-
-	DVector<Vector3>::Write vw = vertices.write();
-	Vector3 *verticesw=vw.ptr();
-
-	AABB _aabb;
-
-
-	for(int i=0;i<src_face_count;i++) {
-
-		Face3 face( facesr[i*3+0], facesr[i*3+1], facesr[i*3+2] );
-
-		bvh_arrayw[i].aabb=face.get_aabb();
-		bvh_arrayw[i].center = bvh_arrayw[i].aabb.pos + bvh_arrayw[i].aabb.size * 0.5;
-		bvh_arrayw[i].face_index=i;
-		facesw[i].indices[0]=i*3+0;
-		facesw[i].indices[1]=i*3+1;
-		facesw[i].indices[2]=i*3+2;
-		facesw[i].normal=face.get_plane().normal;
-		verticesw[i*3+0]=face.vertex[0];
-		verticesw[i*3+1]=face.vertex[1];
-		verticesw[i*3+2]=face.vertex[2];
-		if (i==0)
-			_aabb=bvh_arrayw[i].aabb;
-		else
-			_aabb.merge_with(bvh_arrayw[i].aabb);
-
-	}
-
-	w=DVector<Face>::Write();
-	vw=DVector<Vector3>::Write();
-
-	int count=0;
-	_VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count);
-
-	bvh.resize( count+1 );
-
-	DVector<BVH>::Write bvhw2 = bvh.write();
-	BVH*bvh_arrayw2=bvhw2.ptr();
-
-	int idx=0;
-	_fill_bvh(bvh_tree,bvh_arrayw2,idx);
-
-	configure(_aabb); // this type of shape has no margin
-
-
-#endif
-}
-
-
-void ConcavePolygonShapeSW::set_data(const Variant& p_data) {
-
-
-	_setup(p_data);
-}
-
-Variant ConcavePolygonShapeSW::get_data() const {
-
-	return get_faces();
-}
-
-ConcavePolygonShapeSW::ConcavePolygonShapeSW() {
-
-
-}
-
-
-
-/* HEIGHT MAP SHAPE */
-
-DVector<float> HeightMapShapeSW::get_heights() const {
-
-	return heights;
-}
-int HeightMapShapeSW::get_width() const {
-
-	return width;
-}
-int HeightMapShapeSW::get_depth() const {
-
-	return depth;
-}
-float HeightMapShapeSW::get_cell_size() const {
-
-	return cell_size;
-}
-
-
-void HeightMapShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-	//not very useful, but not very used either
-	p_transform.xform(get_aabb()).project_range_in_plane( Plane(p_normal,0),r_min,r_max );
-
-}
-
-Vector3 HeightMapShapeSW::get_support(const Vector3& p_normal) const {
-
-
-	//not very useful, but not very used either
-	return get_aabb().get_support(p_normal);
-
-}
-
-bool HeightMapShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
-
-
-	return false;
-}
-
-
-void HeightMapShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
-
-
-
-}
-
-
-Vector3 HeightMapShapeSW::get_moment_of_inertia(float p_mass) const {
-
-
-	// use crappy AABB approximation
-	Vector3 extents=get_aabb().size*0.5;
-
-	return Vector3(
-		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
-		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
-		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
-	);
-}
-
-
-void HeightMapShapeSW::_setup(DVector<real_t> p_heights,int p_width,int p_depth,real_t p_cell_size) {
-
-	heights=p_heights;
-	width=p_width;
-	depth=p_depth;;
-	cell_size=p_cell_size;
-
-	DVector<real_t>::Read r = heights. read();
-
-	AABB aabb;
-
-	for(int i=0;i<depth;i++) {
-
-		for(int j=0;j<width;j++) {
-
-			float h = r[i*width+j];
-
-			Vector3 pos( j*cell_size, h, i*cell_size );
-			if (i==0 || j==0)
-				aabb.pos=pos;
-			else
-				aabb.expand_to(pos);
-
-		}
-	}
-
-
-	configure(aabb);
-}
-
-void HeightMapShapeSW::set_data(const Variant& p_data) {
-
-	ERR_FAIL_COND( p_data.get_type()!=Variant::DICTIONARY );
-	Dictionary d=p_data;
-	ERR_FAIL_COND( !d.has("width") );
-	ERR_FAIL_COND( !d.has("depth") );
-	ERR_FAIL_COND( !d.has("cell_size") );
-	ERR_FAIL_COND( !d.has("heights") );
-
-	int width=d["width"];
-	int depth=d["depth"];
-	float cell_size=d["cell_size"];
-	DVector<float> heights=d["heights"];
-
-	ERR_FAIL_COND( width<= 0);
-	ERR_FAIL_COND( depth<= 0);
-	ERR_FAIL_COND( cell_size<= CMP_EPSILON);
-	ERR_FAIL_COND( heights.size() != (width*depth) );
-	_setup(heights, width, depth, cell_size );
-
-}
-
-Variant HeightMapShapeSW::get_data() const {
-
-	ERR_FAIL_V(Variant());
-
-}
-
-HeightMapShapeSW::HeightMapShapeSW() {
-
-	width=0;
-	depth=0;
-	cell_size=0;
-}
-
-
-
+#include "shape_sw.h"
+#include "geometry.h"
+#include "sort.h"
+#include "quick_hull.h"
+#define _POINT_SNAP 0.001953125
+#define _EDGE_IS_VALID_SUPPORT_TRESHOLD 0.0002
+#define _FACE_IS_VALID_SUPPORT_TRESHOLD 0.9998
+
+
+void ShapeSW::configure(const AABB& p_aabb) {
+	aabb=p_aabb;
+	configured=true;
+	for (Map<ShapeOwnerSW*,int>::Element *E=owners.front();E;E=E->next()) {
+		ShapeOwnerSW* co=(ShapeOwnerSW*)E->key();
+		co->_shape_changed();
+	}
+}
+
+
+Vector3 ShapeSW::get_support(const Vector3& p_normal) const {
+
+	Vector3 res;
+	int amnt;
+	get_supports(p_normal,1,&res,amnt);
+	return res;
+}
+
+void ShapeSW::add_owner(ShapeOwnerSW *p_owner) {
+
+	Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
+	if (E) {
+		E->get()++;
+	} else {
+		owners[p_owner]=1;
+	}
+}
+
+void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){
+
+	Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
+	ERR_FAIL_COND(!E);
+	E->get()--;
+	if (E->get()==0) {
+		owners.erase(E);
+	}
+
+}
+
+bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const{
+
+	return owners.has(p_owner);
+
+}
+
+const Map<ShapeOwnerSW*,int>& ShapeSW::get_owners() const{
+	return owners;
+}
+
+
+ShapeSW::ShapeSW() {
+
+	custom_bias=0;
+	configured=false;
+}
+
+
+ShapeSW::~ShapeSW() {
+
+	ERR_FAIL_COND(owners.size());
+}
+
+
+
+Plane PlaneShapeSW::get_plane() const {
+
+	return plane;
+}
+
+void PlaneShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	// gibberish, a plane is infinity
+	r_min=-1e7;
+	r_max=1e7;
+}
+
+Vector3 PlaneShapeSW::get_support(const Vector3& p_normal) const {
+
+	return p_normal*1e15;
+}
+
+
+bool PlaneShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+	bool inters=plane.intersects_segment(p_begin,p_end,&r_result);
+	if(inters)
+		r_normal=plane.normal;
+	return inters;
+}
+
+Vector3 PlaneShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	return Vector3(); //wtf
+}
+
+void PlaneShapeSW::_setup(const Plane& p_plane)  {
+
+	plane=p_plane;
+	configure(AABB(Vector3(-1e4,-1e4,-1e4),Vector3(1e4*2,1e4*2,1e4*2)));
+}
+
+void PlaneShapeSW::set_data(const Variant& p_data) {
+
+	_setup(p_data);
+
+}
+
+Variant PlaneShapeSW::get_data() const {
+
+	return plane;
+}
+
+PlaneShapeSW::PlaneShapeSW()  {
+
+
+}
+
+//
+
+float RayShapeSW::get_length() const {
+
+	return length;
+}
+
+void RayShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	// don't think this will be even used
+	r_min=0;
+	r_max=1;
+}
+
+Vector3 RayShapeSW::get_support(const Vector3& p_normal) const {
+
+	if (p_normal.z>0)
+		return Vector3(0,0,length);
+	else
+		return Vector3(0,0,0);
+}
+
+void RayShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+	if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
+
+		r_amount=2;
+		r_supports[0]=Vector3(0,0,0);
+		r_supports[1]=Vector3(0,0,length);
+	} if (p_normal.z>0) {
+		r_amount=1;
+		*r_supports=Vector3(0,0,length);
+	} else {
+		r_amount=1;
+		*r_supports=Vector3(0,0,0);
+	}
+}
+
+
+bool RayShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+	return false; //simply not possible
+}
+
+Vector3 RayShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	return Vector3();
+}
+
+void RayShapeSW::_setup(float p_length)  {
+
+	length=p_length;
+	configure(AABB(Vector3(0,0,0),Vector3(0.1,0.1,length)));
+}
+
+void RayShapeSW::set_data(const Variant& p_data) {
+
+	_setup(p_data);
+
+}
+
+Variant RayShapeSW::get_data() const {
+
+	return length;
+}
+
+RayShapeSW::RayShapeSW()  {
+
+	length=1;
+}
+
+
+
+/********** SPHERE *************/
+
+real_t SphereShapeSW::get_radius() const {
+
+	return radius;
+}
+
+void SphereShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	float d = p_normal.dot( p_transform.origin );
+
+	// figure out scale at point
+	Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
+	float scale = local_normal.length();
+
+	r_min = d - (radius) * scale;
+	r_max = d + (radius) * scale;
+
+}
+
+Vector3 SphereShapeSW::get_support(const Vector3& p_normal) const {
+
+	return p_normal*radius;
+}
+
+void SphereShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+	*r_supports=p_normal*radius;
+	r_amount=1;
+}
+
+bool SphereShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+	return Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(),radius,&r_result,&r_normal);
+}
+
+Vector3 SphereShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	float s = 0.4 * p_mass * radius * radius;
+	return Vector3(s,s,s);
+}
+
+void SphereShapeSW::_setup(real_t p_radius) {
+
+
+	radius=p_radius;
+	configure(AABB( Vector3(-radius,-radius,-radius), Vector3(radius*2.0,radius*2.0,radius*2.0)));
+
+}
+
+void SphereShapeSW::set_data(const Variant& p_data) {
+
+	_setup(p_data);
+}
+
+Variant SphereShapeSW::get_data() const {
+
+	return radius;
+}
+
+SphereShapeSW::SphereShapeSW() {
+
+	radius=0;
+}
+
+
+/********** BOX *************/
+
+
+void BoxShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	// no matter the angle, the box is mirrored anyway
+	Vector3 local_normal=p_transform.basis.xform_inv(p_normal);
+
+	float length = local_normal.abs().dot(half_extents);
+	float distance = p_normal.dot( p_transform.origin );
+
+	r_min = distance - length;
+	r_max = distance + length;
+
+
+}
+
+Vector3 BoxShapeSW::get_support(const Vector3& p_normal) const {
+
+
+	Vector3 point(
+		(p_normal.x<0) ? -half_extents.x : half_extents.x,
+		(p_normal.y<0) ? -half_extents.y : half_extents.y,
+		(p_normal.z<0) ? -half_extents.z : half_extents.z
+	);
+
+	return point;
+}
+
+void BoxShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+	static const int next[3]={1,2,0};
+	static const int next2[3]={2,0,1};
+
+	for (int i=0;i<3;i++) {
+
+		Vector3 axis;
+		axis[i]=1.0;
+		float dot = p_normal.dot( axis );
+		if ( Math::abs( dot ) >  _FACE_IS_VALID_SUPPORT_TRESHOLD ) {
+
+			//Vector3 axis_b;
+
+			bool neg = dot<0;
+			r_amount = 4;
+
+			Vector3 point;
+			point[i]=half_extents[i];
+
+			int i_n=next[i];
+			int i_n2=next2[i];
+
+			static const float sign[4][2]={
+
+				{-1.0, 1.0},
+				{ 1.0, 1.0},
+				{ 1.0,-1.0},
+				{-1.0,-1.0},
+			};
+
+			for (int j=0;j<4;j++) {
+
+				point[i_n]=sign[j][0]*half_extents[i_n];
+				point[i_n2]=sign[j][1]*half_extents[i_n2];
+				r_supports[j]=neg?-point:point;
+
+			}
+
+			if (neg) {
+				SWAP( r_supports[1], r_supports[2] );
+				SWAP( r_supports[0], r_supports[3] );
+			}
+
+			return;
+		}
+
+		r_amount=0;
+
+	}
+
+	for (int i=0;i<3;i++) {
+
+		Vector3 axis;
+		axis[i]=1.0;
+
+		if (Math::abs(p_normal.dot(axis))<_EDGE_IS_VALID_SUPPORT_TRESHOLD) {
+
+			r_amount= 2;
+
+			int i_n=next[i];
+			int i_n2=next2[i];
+
+			Vector3 point=half_extents;
+
+			if (p_normal[i_n]<0) {
+				point[i_n]=-point[i_n];
+			}
+			if (p_normal[i_n2]<0) {
+				point[i_n2]=-point[i_n2];
+			}
+
+			r_supports[0] = point;
+			point[i]=-point[i];
+			r_supports[1] = point;
+			return;
+		}
+	}
+	/* USE POINT */
+
+	Vector3 point(
+		(p_normal.x<0) ? -half_extents.x : half_extents.x,
+		(p_normal.y<0) ? -half_extents.y : half_extents.y,
+		(p_normal.z<0) ? -half_extents.z : half_extents.z
+	);
+
+	r_amount=1;
+	r_supports[0]=point;
+}
+
+bool BoxShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+	AABB aabb(-half_extents,half_extents*2.0);
+
+	return aabb.intersects_segment(p_begin,p_end,&r_result,&r_normal);
+
+}
+
+Vector3 BoxShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	float lx=half_extents.x;
+	float ly=half_extents.y;
+	float lz=half_extents.z;
+
+	return Vector3(	(p_mass/3.0) * (ly*ly + lz*lz), (p_mass/3.0) * (lx*lx + lz*lz), (p_mass/3.0) * (lx*lx + ly*ly) );
+
+}
+
+void BoxShapeSW::_setup(const Vector3& p_half_extents)  {
+
+	half_extents=p_half_extents.abs();
+
+	configure(AABB(-half_extents,half_extents*2));
+
+
+}
+
+void BoxShapeSW::set_data(const Variant& p_data) {
+
+
+	_setup(p_data);
+}
+
+Variant BoxShapeSW::get_data() const {
+
+	return half_extents;
+}
+
+BoxShapeSW::BoxShapeSW()  {
+
+
+}
+
+
+/********** CAPSULE *************/
+
+
+void CapsuleShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	Vector3 n=p_transform.basis.xform_inv(p_normal).normalized();
+	float h = (n.z > 0) ? height : -height;
+
+	n *= radius;
+	n.z += h * 0.5;
+
+	r_max=p_normal.dot(p_transform.xform(n));
+	r_min=p_normal.dot(p_transform.xform(-n));
+	return;
+
+	n = p_transform.basis.xform(n);
+
+	float distance = p_normal.dot( p_transform.origin );
+	float length = Math::abs(p_normal.dot(n));
+	r_min = distance - length;
+	r_max = distance + length;
+
+	ERR_FAIL_COND( r_max < r_min );
+
+}
+
+Vector3 CapsuleShapeSW::get_support(const Vector3& p_normal) const {
+
+	Vector3 n=p_normal;
+
+	float h = (n.z > 0) ? height : -height;
+
+	n*=radius;
+	n.z += h*0.5;
+	return n;
+}
+
+void CapsuleShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+
+	Vector3 n=p_normal;
+
+	float d = n.z;
+
+	if (Math::abs( d )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
+
+		// make it flat
+		n.z=0.0;
+		n.normalize();
+		n*=radius;
+
+		r_amount=2;
+		r_supports[0]=n;
+		r_supports[0].z+=height*0.5;
+		r_supports[1]=n;
+		r_supports[1].z-=height*0.5;
+
+	} else {
+
+		float h = (d > 0) ? height : -height;
+
+		n*=radius;
+		n.z += h*0.5;
+		r_amount=1;
+		*r_supports=n;
+
+	}
+
+}
+
+
+bool CapsuleShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+	Vector3 norm=(p_end-p_begin).normalized();
+	float min_d=1e20;
+
+
+	Vector3 res,n;
+	bool collision=false;
+
+	Vector3 auxres,auxn;
+	bool collided;
+
+	// test against cylinder and spheres :-|
+
+	collided = Geometry::segment_intersects_cylinder(p_begin,p_end,height,radius,&auxres,&auxn);
+
+	if (collided) {
+		float d=norm.dot(auxres);
+		if (d<min_d) {
+			min_d=d;
+			res=auxres;
+			n=auxn;
+			collision=true;
+		}
+	}
+
+	collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*0.5),radius,&auxres,&auxn);
+
+	if (collided) {
+		float d=norm.dot(auxres);
+		if (d<min_d) {
+			min_d=d;
+			res=auxres;
+			n=auxn;
+			collision=true;
+		}
+	}
+
+	collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*-0.5),radius,&auxres,&auxn);
+
+	if (collided) {
+		float d=norm.dot(auxres);
+
+		if (d<min_d) {
+			min_d=d;
+			res=auxres;
+			n=auxn;
+			collision=true;
+		}
+	}
+
+	if (collision) {
+
+		r_result=res;
+		r_normal=n;
+	}
+	return collision;
+}
+
+Vector3 CapsuleShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	// use crappy AABB approximation
+	Vector3 extents=get_aabb().size*0.5;
+
+	return Vector3(
+		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+	);
+
+}
+
+
+
+
+void CapsuleShapeSW::_setup(real_t p_height,real_t p_radius)  {
+
+	height=p_height;
+	radius=p_radius;
+	configure(AABB(Vector3(-radius,-radius,-height*0.5-radius),Vector3(radius*2,radius*2,height+radius*2.0)));
+
+}
+
+void CapsuleShapeSW::set_data(const Variant& p_data) {
+
+	Dictionary d = p_data;
+	ERR_FAIL_COND(!d.has("radius"));
+	ERR_FAIL_COND(!d.has("height"));
+	_setup(d["height"],d["radius"]);
+
+}
+
+Variant CapsuleShapeSW::get_data() const {
+
+	Dictionary d;
+	d["radius"]=radius;
+	d["height"]=height;
+	return d;
+
+}
+
+
+CapsuleShapeSW::CapsuleShapeSW()  {
+
+	height=radius=0;
+
+}
+
+/********** CONVEX POLYGON *************/
+
+
+void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+
+	int vertex_count=mesh.vertices.size();
+	if (vertex_count==0)
+		return;
+
+	const Vector3 *vrts=&mesh.vertices[0];
+
+	for (int i=0;i<vertex_count;i++) {
+
+		float d=p_normal.dot( p_transform.xform( vrts[i] ) );
+
+		if (i==0 || d > r_max)
+			r_max=d;
+		if (i==0 || d < r_min)
+			r_min=d;
+	}
+}
+
+Vector3 ConvexPolygonShapeSW::get_support(const Vector3& p_normal) const {
+
+	Vector3 n=p_normal;
+
+	int vert_support_idx=-1;
+	float support_max;
+
+	int vertex_count=mesh.vertices.size();
+	if (vertex_count==0)
+		return Vector3();
+
+	const Vector3 *vrts=&mesh.vertices[0];
+
+	for (int i=0;i<vertex_count;i++) {
+
+		float d=n.dot(vrts[i]);
+
+		if (i==0 || d > support_max) {
+			support_max=d;
+			vert_support_idx=i;
+		}
+	}
+
+	return  vrts[vert_support_idx];
+
+}
+
+
+
+void ConvexPolygonShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+	const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+	int fc = mesh.faces.size();
+
+	const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
+	int ec = mesh.edges.size();
+
+	const Vector3 *vertices = mesh.vertices.ptr();
+	int vc = mesh.vertices.size();
+
+	//find vertex first
+	real_t max;
+	int vtx;
+
+	for (int i=0;i<vc;i++) {
+
+		float d=p_normal.dot(vertices[i]);
+
+		if (i==0 || d > max) {
+			max=d;
+			vtx=i;
+		}
+	}
+
+
+	for(int i=0;i<fc;i++) {
+
+		if (faces[i].plane.normal.dot(p_normal)>_FACE_IS_VALID_SUPPORT_TRESHOLD) {
+
+			int ic = faces[i].indices.size();
+			const int *ind=faces[i].indices.ptr();
+
+			bool valid=false;
+			for(int j=0;j<ic;j++) {
+				if (ind[j]==vtx) {
+					valid=true;
+					break;
+				}
+			}
+
+			if (!valid)
+				continue;
+
+			int m = MIN(p_max,ic);
+			for(int j=0;j<m;j++) {
+
+				r_supports[j]=vertices[ind[j]];
+			}
+			r_amount=m;
+			return;
+		}
+	}
+
+	for(int i=0;i<ec;i++) {
+
+
+		float dot=(vertices[edges[i].a]-vertices[edges[i].b]).normalized().dot(p_normal);
+		dot=ABS(dot);
+		if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD && (edges[i].a==vtx || edges[i].b==vtx)) {
+
+			r_amount=2;
+			r_supports[0]=vertices[edges[i].a];
+			r_supports[1]=vertices[edges[i].b];
+			return;
+		}
+	}
+
+
+	r_supports[0]=vertices[vtx];
+	r_amount=1;
+}
+
+bool ConvexPolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+
+
+	const Geometry::MeshData::Face *faces = mesh.faces.ptr();
+	int fc = mesh.faces.size();
+
+	const Vector3 *vertices = mesh.vertices.ptr();
+	int vc = mesh.vertices.size();
+
+	Vector3 n = p_end-p_begin;
+	float min = 1e20;
+	bool col=false;
+
+	for(int i=0;i<fc;i++) {
+
+		if (faces[i].plane.normal.dot(n) > 0)
+			continue; //opposing face
+
+		int ic = faces[i].indices.size();
+		const int *ind=faces[i].indices.ptr();
+
+		for(int j=1;j<ic-1;j++) {
+
+			Face3 f(vertices[ind[0]],vertices[ind[j]],vertices[ind[j+1]]);
+			Vector3 result;
+			if (f.intersects_segment(p_begin,p_end,&result)) {
+				float d = n.dot(result);
+				if (d<min) {
+					min=d;
+					r_result=result;
+					r_normal=faces[i].plane.normal;
+					col=true;
+				}
+
+				break;
+			}
+
+		}
+	}
+
+	return col;
+
+}
+
+Vector3 ConvexPolygonShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	// use crappy AABB approximation
+	Vector3 extents=get_aabb().size*0.5;
+
+	return  Vector3(
+		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+	);
+
+}
+
+void ConvexPolygonShapeSW::_setup(const Vector<Vector3>& p_vertices)  {
+
+	Error err = QuickHull::build(p_vertices,mesh);
+	AABB _aabb;
+
+	for(int i=0;i<mesh.vertices.size();i++) {
+
+		if (i==0)
+			_aabb.pos=mesh.vertices[i];
+		else
+			_aabb.expand_to(mesh.vertices[i]);
+	}
+
+	configure(_aabb);
+
+
+}
+
+void ConvexPolygonShapeSW::set_data(const Variant& p_data) {
+
+	_setup(p_data);
+
+}
+
+Variant ConvexPolygonShapeSW::get_data() const {
+
+	return mesh.vertices;
+}
+
+
+ConvexPolygonShapeSW::ConvexPolygonShapeSW()  {
+
+
+}
+
+
+/********** FACE POLYGON *************/
+
+
+void FaceShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	for (int i=0;i<3;i++) {
+
+		Vector3 v=p_transform.xform(vertex[i]);
+		float d=p_normal.dot(v);
+
+		if (i==0 || d > r_max)
+			r_max=d;
+
+		if (i==0 || d < r_min)
+			r_min=d;
+	}
+}
+
+Vector3 FaceShapeSW::get_support(const Vector3& p_normal) const {
+
+
+	Vector3 n=p_normal;
+
+	int vert_support_idx=-1;
+	float support_max;
+
+	for (int i=0;i<3;i++) {
+
+		//float d=n.dot(vertex[i]);
+		float d=p_normal.dot(vertex[i]);
+
+		if (i==0 || d > support_max) {
+			support_max=d;
+			vert_support_idx=i;
+		}
+	}
+
+	return vertex[vert_support_idx];
+}
+
+void FaceShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
+
+	Vector3 n=p_normal;
+
+	/** TEST FACE AS SUPPORT **/
+	if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_TRESHOLD) {
+
+		r_amount=3;
+		for (int i=0;i<3;i++) {
+
+			r_supports[i]=vertex[i];
+		}
+		return;
+
+	}
+
+	/** FIND SUPPORT VERTEX **/
+
+	int vert_support_idx=-1;
+	float support_max;
+
+	for (int i=0;i<3;i++) {
+
+		float d=n.dot(vertex[i]);
+
+		if (i==0 || d > support_max) {
+			support_max=d;
+			vert_support_idx=i;
+		}
+	}
+
+	/** TEST EDGES AS SUPPORT **/
+
+	for (int i=0;i<3;i++) {
+
+		int nx=(i+1)%3;
+		//if (i!=vert_support_idx && nx!=vert_support_idx)
+		//	continue;
+
+	// check if edge is valid as a support
+		float dot=(vertex[i]-vertex[nx]).normalized().dot(n);
+		dot=ABS(dot);
+		if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
+
+			r_amount=2;
+			r_supports[0]=vertex[i];
+			r_supports[1]=vertex[nx];
+			return;
+		}
+	}
+
+	r_amount=1;
+	r_supports[0]=vertex[vert_support_idx];
+}
+
+bool FaceShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+
+	bool c=Geometry::segment_intersects_triangle(p_begin,p_end,vertex[0],vertex[1],vertex[2],&r_result);
+	if (c)
+		r_normal=Plane(vertex[0],vertex[1],vertex[2]).normal;
+
+	return c;
+}
+
+Vector3 FaceShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
+
+}
+
+FaceShapeSW::FaceShapeSW()  {
+
+	configure(AABB());
+
+}
+
+
+
+DVector<Vector3> ConcavePolygonShapeSW::get_faces() const {
+
+
+	DVector<Vector3> rfaces;
+	rfaces.resize(faces.size()*3);
+
+	for(int i=0;i<faces.size();i++) {
+
+		Face f=faces.get(i);
+
+		for(int j=0;j<3;j++) {
+
+			rfaces.set(i*3+j, vertices.get( f.indices[j] ) );
+		}
+	}
+
+	return rfaces;
+}
+
+void ConcavePolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	int count=vertices.size();
+	DVector<Vector3>::Read r=vertices.read();
+	const Vector3 *vptr=r.ptr();
+
+	for (int i=0;i<count;i++) {
+
+		float d=p_normal.dot( p_transform.xform( vptr[i] ) );
+
+		if (i==0 || d > r_max)
+			r_max=d;
+		if (i==0 || d < r_min)
+			r_min=d;
+
+	}
+}
+
+Vector3 ConcavePolygonShapeSW::get_support(const Vector3& p_normal) const {
+
+
+	int count=vertices.size();
+	DVector<Vector3>::Read r=vertices.read();
+	const Vector3 *vptr=r.ptr();
+
+	Vector3 n=p_normal;
+
+	int vert_support_idx=-1;
+	float support_max;
+
+	for (int i=0;i<count;i++) {
+
+		float d=n.dot(vptr[i]);
+
+		if (i==0 || d > support_max) {
+			support_max=d;
+			vert_support_idx=i;
+		}
+	}
+
+
+	return vptr[vert_support_idx];
+
+}
+
+void ConcavePolygonShapeSW::_cull_segment(int p_idx,_SegmentCullParams *p_params) const {
+
+	const BVH *bvh=&p_params->bvh[p_idx];
+
+
+	//if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
+	//	return; //test against whole AABB, which isn't very costly
+
+
+	//printf("addr: %p\n",bvh);
+	if (!bvh->aabb.intersects_segment(p_params->from,p_params->to)) {
+
+		return;
+	}
+
+
+	if (bvh->face_index>=0) {
+
+
+		Vector3 res;
+		Vector3 vertices[3]={
+			p_params->vertices[ p_params->faces[ bvh->face_index ].indices[0] ],
+			p_params->vertices[ p_params->faces[ bvh->face_index ].indices[1] ],
+			p_params->vertices[ p_params->faces[ bvh->face_index ].indices[2] ]
+		};
+
+		if (Geometry::segment_intersects_triangle(
+				p_params->from,
+				p_params->to,
+				vertices[0],
+				vertices[1],
+				vertices[2],
+				&res)) {
+
+
+			float d=p_params->normal.dot(res) - p_params->normal.dot(p_params->from);
+			//TODO, seems segmen/triangle intersection is broken :(
+			if (d>0 && d<p_params->min_d) {
+
+				p_params->min_d=d;
+				p_params->result=res;
+				p_params->normal=Plane(vertices[0],vertices[1],vertices[2]).normal;
+				p_params->collisions++;
+			}
+
+		}
+
+
+
+	} else {
+
+		if (bvh->left>=0)
+			_cull_segment(bvh->left,p_params);
+		if (bvh->right>=0)
+			_cull_segment(bvh->right,p_params);
+
+
+	}
+}
+
+bool ConcavePolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
+
+	// unlock data
+	DVector<Face>::Read fr=faces.read();
+	DVector<Vector3>::Read vr=vertices.read();
+	DVector<BVH>::Read br=bvh.read();
+
+
+	_SegmentCullParams params;
+	params.from=p_begin;
+	params.to=p_end;
+	params.collisions=0;
+	params.normal=(p_end-p_begin).normalized();
+
+	params.faces=fr.ptr();
+	params.vertices=vr.ptr();
+	params.bvh=br.ptr();
+
+	params.min_d=1e20;
+	// cull
+	_cull_segment(0,&params);
+
+	if (params.collisions>0) {
+
+
+		r_result=params.result;
+		r_normal=params.normal;
+		return true;
+	} else {
+
+		return false;
+	}
+}
+
+void ConcavePolygonShapeSW::_cull(int p_idx,_CullParams *p_params) const {
+
+	const BVH* bvh=&p_params->bvh[p_idx];
+
+	if (!p_params->aabb.intersects( bvh->aabb ))
+		return;
+
+	if (bvh->face_index>=0) {
+
+		const Face *f=&p_params->faces[ bvh->face_index ];
+		FaceShapeSW *face=p_params->face;
+		face->normal=f->normal;
+		face->vertex[0]=p_params->vertices[f->indices[0]];
+		face->vertex[1]=p_params->vertices[f->indices[1]];
+		face->vertex[2]=p_params->vertices[f->indices[2]];
+		p_params->callback(p_params->userdata,face);
+
+	} else {
+
+		if (bvh->left>=0) {
+
+			_cull(bvh->left,p_params);
+
+		}
+
+		if (bvh->right>=0) {
+
+			_cull(bvh->right,p_params);
+		}
+
+	}
+}
+
+void ConcavePolygonShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
+
+	// make matrix local to concave
+
+	AABB local_aabb=p_local_aabb;
+
+	// unlock data
+	DVector<Face>::Read fr=faces.read();
+	DVector<Vector3>::Read vr=vertices.read();
+	DVector<BVH>::Read br=bvh.read();
+
+	FaceShapeSW face; // use this to send in the callback
+
+	_CullParams params;
+	params.aabb=local_aabb;
+	params.face=&face;
+	params.faces=fr.ptr();
+	params.vertices=vr.ptr();
+	params.bvh=br.ptr();
+	params.callback=p_callback;
+	params.userdata=p_userdata;
+
+	// cull
+	_cull(0,&params);
+
+}
+
+Vector3 ConcavePolygonShapeSW::get_moment_of_inertia(float p_mass) const {
+
+	// use crappy AABB approximation
+	Vector3 extents=get_aabb().size*0.5;
+
+	return Vector3(
+		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+	);
+}
+
+
+struct _VolumeSW_BVH_Element {
+
+	AABB aabb;
+	Vector3 center;
+	int face_index;
+};
+
+struct _VolumeSW_BVH_CompareX {
+
+	_FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
+
+		return a.center.x<b.center.x;
+	}
+};
+
+
+struct _VolumeSW_BVH_CompareY {
+
+	_FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
+
+		return a.center.y<b.center.y;
+	}
+};
+
+struct _VolumeSW_BVH_CompareZ {
+
+	_FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
+
+		return a.center.z<b.center.z;
+	}
+};
+
+struct _VolumeSW_BVH {
+
+	AABB aabb;
+	_VolumeSW_BVH *left;
+	_VolumeSW_BVH *right;
+
+	int face_index;
+};
+
+
+_VolumeSW_BVH* _volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements,int p_size,int &count) {
+
+	_VolumeSW_BVH* bvh = memnew( _VolumeSW_BVH );
+
+	if (p_size==1) {
+		//leaf
+		bvh->aabb=p_elements[0].aabb;
+		bvh->left=NULL;
+		bvh->right=NULL;
+		bvh->face_index=p_elements->face_index;
+		count++;
+		return bvh;
+	} else {
+
+		bvh->face_index=-1;
+	}
+
+	AABB aabb;
+	for(int i=0;i<p_size;i++) {
+
+		if (i==0)
+			aabb=p_elements[i].aabb;
+		else
+			aabb.merge_with(p_elements[i].aabb);
+	}
+	bvh->aabb=aabb;
+	switch(aabb.get_longest_axis_index()) {
+
+		case 0: {
+
+			SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareX> sort_x;
+			sort_x.sort(p_elements,p_size);
+
+		} break;
+		case 1: {
+
+			SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareY> sort_y;
+			sort_y.sort(p_elements,p_size);
+		} break;
+		case 2: {
+
+			SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareZ> sort_z;
+			sort_z.sort(p_elements,p_size);
+		} break;
+	}
+
+	int split=p_size/2;
+	bvh->left=_volume_sw_build_bvh(p_elements,split,count);
+	bvh->right=_volume_sw_build_bvh(&p_elements[split],p_size-split,count);
+
+//	printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
+	count++;
+	return bvh;
+}
+
+
+void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx) {
+
+	int idx=p_idx;
+
+
+	p_bvh_array[idx].aabb=p_bvh_tree->aabb;
+	p_bvh_array[idx].face_index=p_bvh_tree->face_index;
+//	printf("%p - %i: %i(%p)  -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
+
+
+	if (p_bvh_tree->left) {
+		p_bvh_array[idx].left=++p_idx;
+		_fill_bvh(p_bvh_tree->left,p_bvh_array,p_idx);
+
+	} else {
+
+		p_bvh_array[p_idx].left=-1;
+	}
+
+	if (p_bvh_tree->right) {
+		p_bvh_array[idx].right=++p_idx;
+		_fill_bvh(p_bvh_tree->right,p_bvh_array,p_idx);
+
+	} else {
+
+		p_bvh_array[p_idx].right=-1;
+	}
+
+	memdelete(p_bvh_tree);
+
+}
+
+void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) {
+
+	int src_face_count=p_faces.size();
+	ERR_FAIL_COND(src_face_count%3);
+	src_face_count/=3;
+
+	DVector<Vector3>::Read r = p_faces.read();
+	const Vector3 * facesr= r.ptr();
+
+#if 0
+	Map<Vector3,int> point_map;
+	List<Face> face_list;
+
+
+	for(int i=0;i<src_face_count;i++) {
+
+		Face3 faceaux;
+
+		for(int j=0;j<3;j++) {
+
+			faceaux.vertex[j]=facesr[i*3+j].snapped(_POINT_SNAP);
+			//faceaux.vertex[j]=facesr[i*3+j];//facesr[i*3+j].snapped(_POINT_SNAP);
+		}
+
+		ERR_CONTINUE( faceaux.is_degenerate() );
+
+		Face face;
+
+		for(int j=0;j<3;j++) {
+
+
+			Map<Vector3,int>::Element *E=point_map.find(faceaux.vertex[j]);
+			if (E) {
+
+				face.indices[j]=E->value();
+			} else {
+
+				face.indices[j]=point_map.size();
+				point_map.insert(faceaux.vertex[j],point_map.size());
+
+			}
+		}
+
+		face_list.push_back(face);
+	}
+
+	vertices.resize( point_map.size() );
+
+	DVector<Vector3>::Write vw = vertices.write();
+	Vector3 *verticesw=vw.ptr();
+
+	AABB _aabb;
+
+	for( Map<Vector3,int>::Element *E=point_map.front();E;E=E->next()) {
+
+		if (E==point_map.front()) {
+			_aabb.pos=E->key();
+		} else {
+
+			_aabb.expand_to(E->key());
+		}
+		verticesw[E->value()]=E->key();
+	}
+
+	point_map.clear(); // not needed anymore
+
+	faces.resize(face_list.size());
+	DVector<Face>::Write w = faces.write();
+	Face *facesw=w.ptr();
+
+	int fc=0;
+
+	for( List<Face>::Element *E=face_list.front();E;E=E->next()) {
+
+		facesw[fc++]=E->get();
+	}
+
+	face_list.clear();
+
+
+	DVector<_VolumeSW_BVH_Element> bvh_array;
+	bvh_array.resize( fc );
+
+	DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
+	_VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
+
+
+	for(int i=0;i<fc;i++) {
+
+		AABB face_aabb;
+		face_aabb.pos=verticesw[facesw[i].indices[0]];
+		face_aabb.expand_to( verticesw[facesw[i].indices[1]] );
+		face_aabb.expand_to( verticesw[facesw[i].indices[2]] );
+
+		bvh_arrayw[i].face_index=i;
+		bvh_arrayw[i].aabb=face_aabb;
+		bvh_arrayw[i].center=face_aabb.pos+face_aabb.size*0.5;
+
+	}
+
+	w=DVector<Face>::Write();
+	vw=DVector<Vector3>::Write();
+
+
+	int count=0;
+	_VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,fc,count);
+
+	ERR_FAIL_COND(count==0);
+
+	bvhw=DVector<_VolumeSW_BVH_Element>::Write();
+
+	bvh.resize( count+1 );
+
+	DVector<BVH>::Write bvhw2 = bvh.write();
+	BVH*bvh_arrayw2=bvhw2.ptr();
+
+	int idx=0;
+	_fill_bvh(bvh_tree,bvh_arrayw2,idx);
+
+	set_aabb(_aabb);
+
+#else
+	DVector<_VolumeSW_BVH_Element> bvh_array;
+	bvh_array.resize( src_face_count );
+
+	DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
+	_VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
+
+	faces.resize(src_face_count);
+	DVector<Face>::Write w = faces.write();
+	Face *facesw=w.ptr();
+
+	vertices.resize( src_face_count*3 );
+
+	DVector<Vector3>::Write vw = vertices.write();
+	Vector3 *verticesw=vw.ptr();
+
+	AABB _aabb;
+
+
+	for(int i=0;i<src_face_count;i++) {
+
+		Face3 face( facesr[i*3+0], facesr[i*3+1], facesr[i*3+2] );
+
+		bvh_arrayw[i].aabb=face.get_aabb();
+		bvh_arrayw[i].center = bvh_arrayw[i].aabb.pos + bvh_arrayw[i].aabb.size * 0.5;
+		bvh_arrayw[i].face_index=i;
+		facesw[i].indices[0]=i*3+0;
+		facesw[i].indices[1]=i*3+1;
+		facesw[i].indices[2]=i*3+2;
+		facesw[i].normal=face.get_plane().normal;
+		verticesw[i*3+0]=face.vertex[0];
+		verticesw[i*3+1]=face.vertex[1];
+		verticesw[i*3+2]=face.vertex[2];
+		if (i==0)
+			_aabb=bvh_arrayw[i].aabb;
+		else
+			_aabb.merge_with(bvh_arrayw[i].aabb);
+
+	}
+
+	w=DVector<Face>::Write();
+	vw=DVector<Vector3>::Write();
+
+	int count=0;
+	_VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count);
+
+	bvh.resize( count+1 );
+
+	DVector<BVH>::Write bvhw2 = bvh.write();
+	BVH*bvh_arrayw2=bvhw2.ptr();
+
+	int idx=0;
+	_fill_bvh(bvh_tree,bvh_arrayw2,idx);
+
+	configure(_aabb); // this type of shape has no margin
+
+
+#endif
+}
+
+
+void ConcavePolygonShapeSW::set_data(const Variant& p_data) {
+
+
+	_setup(p_data);
+}
+
+Variant ConcavePolygonShapeSW::get_data() const {
+
+	return get_faces();
+}
+
+ConcavePolygonShapeSW::ConcavePolygonShapeSW() {
+
+
+}
+
+
+
+/* HEIGHT MAP SHAPE */
+
+DVector<float> HeightMapShapeSW::get_heights() const {
+
+	return heights;
+}
+int HeightMapShapeSW::get_width() const {
+
+	return width;
+}
+int HeightMapShapeSW::get_depth() const {
+
+	return depth;
+}
+float HeightMapShapeSW::get_cell_size() const {
+
+	return cell_size;
+}
+
+
+void HeightMapShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
+
+	//not very useful, but not very used either
+	p_transform.xform(get_aabb()).project_range_in_plane( Plane(p_normal,0),r_min,r_max );
+
+}
+
+Vector3 HeightMapShapeSW::get_support(const Vector3& p_normal) const {
+
+
+	//not very useful, but not very used either
+	return get_aabb().get_support(p_normal);
+
+}
+
+bool HeightMapShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
+
+
+	return false;
+}
+
+
+void HeightMapShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
+
+
+
+}
+
+
+Vector3 HeightMapShapeSW::get_moment_of_inertia(float p_mass) const {
+
+
+	// use crappy AABB approximation
+	Vector3 extents=get_aabb().size*0.5;
+
+	return Vector3(
+		(p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
+		(p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
+		(p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
+	);
+}
+
+
+void HeightMapShapeSW::_setup(DVector<real_t> p_heights,int p_width,int p_depth,real_t p_cell_size) {
+
+	heights=p_heights;
+	width=p_width;
+	depth=p_depth;;
+	cell_size=p_cell_size;
+
+	DVector<real_t>::Read r = heights. read();
+
+	AABB aabb;
+
+	for(int i=0;i<depth;i++) {
+
+		for(int j=0;j<width;j++) {
+
+			float h = r[i*width+j];
+
+			Vector3 pos( j*cell_size, h, i*cell_size );
+			if (i==0 || j==0)
+				aabb.pos=pos;
+			else
+				aabb.expand_to(pos);
+
+		}
+	}
+
+
+	configure(aabb);
+}
+
+void HeightMapShapeSW::set_data(const Variant& p_data) {
+
+	ERR_FAIL_COND( p_data.get_type()!=Variant::DICTIONARY );
+	Dictionary d=p_data;
+	ERR_FAIL_COND( !d.has("width") );
+	ERR_FAIL_COND( !d.has("depth") );
+	ERR_FAIL_COND( !d.has("cell_size") );
+	ERR_FAIL_COND( !d.has("heights") );
+
+	int width=d["width"];
+	int depth=d["depth"];
+	float cell_size=d["cell_size"];
+	DVector<float> heights=d["heights"];
+
+	ERR_FAIL_COND( width<= 0);
+	ERR_FAIL_COND( depth<= 0);
+	ERR_FAIL_COND( cell_size<= CMP_EPSILON);
+	ERR_FAIL_COND( heights.size() != (width*depth) );
+	_setup(heights, width, depth, cell_size );
+
+}
+
+Variant HeightMapShapeSW::get_data() const {
+
+	ERR_FAIL_V(Variant());
+
+}
+
+HeightMapShapeSW::HeightMapShapeSW() {
+
+	width=0;
+	depth=0;
+	cell_size=0;
+}
+
+
+

+ 1 - 0
servers/physics_server.cpp

@@ -85,6 +85,7 @@ void PhysicsDirectBodyState::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_transform"),&PhysicsDirectBodyState::get_transform);
 
 	ObjectTypeDB::bind_method(_MD("add_force","force","pos"),&PhysicsDirectBodyState::add_force);
+	ObjectTypeDB::bind_method(_MD("apply_impulse","pos","j"),&PhysicsDirectBodyState::apply_impulse);
 
 	ObjectTypeDB::bind_method(_MD("set_sleep_state","enabled"),&PhysicsDirectBodyState::set_sleep_state);
 	ObjectTypeDB::bind_method(_MD("is_sleeping"),&PhysicsDirectBodyState::is_sleeping);

+ 1 - 0
servers/physics_server.h

@@ -58,6 +58,7 @@ public:
 	virtual Transform get_transform() const=0;
 
 	virtual void add_force(const Vector3& p_force, const Vector3& p_pos)=0;
+	virtual void apply_impulse(const Vector3& p_pos, const Vector3& p_j)=0;
 
 	virtual void set_sleep_state(bool p_enable)=0;
 	virtual bool is_sleeping() const=0;

+ 2 - 0
servers/visual/rasterizer.h

@@ -507,6 +507,7 @@ public:
 		float octree_lattice_size;
 		float octree_lattice_divide;
 		float texture_multiplier;
+		float lightmap_multiplier;
 		int octree_steps;
 		Vector2 octree_tex_pixel_size;
 	};
@@ -520,6 +521,7 @@ public:
 		Vector<float> morph_values;
 		BakedLightData *baked_light;
 		Transform *baked_light_octree_xform;
+		int baked_lightmap_id;
 		bool mirror :8;
 		bool depth_scale :8;
 		bool billboard :8;

+ 6 - 0
servers/visual/shader_language.cpp

@@ -1005,6 +1005,11 @@ const ShaderLanguage::OperatorDef ShaderLanguage::operator_defs[]={
 
 const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
 
+	{ "SRC_VERTEX", TYPE_VEC3},
+	{ "SRC_NORMAL", TYPE_VEC3},
+	{ "SRC_TANGENT", TYPE_VEC3},
+	{ "SRC_BINORMALF", TYPE_FLOAT},
+
 	{ "VERTEX", TYPE_VEC3},
 	{ "NORMAL", TYPE_VEC3},
 	{ "TANGENT", TYPE_VEC3},
@@ -1023,6 +1028,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
 	{ "WORLD_MATRIX", TYPE_MAT4},
 	{ "INV_CAMERA_MATRIX", TYPE_MAT4},
 	{ "PROJECTION_MATRIX", TYPE_MAT4},
+	{ "MODELVIEW_MATRIX", TYPE_MAT4},
 	{ "INSTANCE_ID", TYPE_FLOAT},
 	{ "TIME", TYPE_FLOAT},
 	{ NULL, TYPE_VOID},

+ 24 - 3
servers/visual/visual_server_raster.cpp

@@ -148,7 +148,7 @@ String VisualServerRaster::shader_get_fragment_code(RID p_shader) const{
 
 String VisualServerRaster::shader_get_light_code(RID p_shader) const{
 
-	return rasterizer->shader_get_fragment_code(p_shader);
+	return rasterizer->shader_get_light_code(p_shader);
 }
 
 void VisualServerRaster::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
@@ -1038,6 +1038,7 @@ RID VisualServerRaster::baked_light_create() {
 	baked_light->data.octree_lattice_size=0;
 	baked_light->data.octree_lattice_divide=0;
 	baked_light->data.octree_steps=1;
+	baked_light->data.lightmap_multiplier=1.0;
 
 	return baked_light_owner.make_rid( baked_light );
 
@@ -1063,6 +1064,26 @@ VisualServer::BakedLightMode VisualServerRaster::baked_light_get_mode(RID p_bake
 
 }
 
+void VisualServerRaster::baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier) {
+
+	VS_CHANGED;
+	BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND(!baked_light);
+
+	baked_light->data.lightmap_multiplier=p_multiplier;
+
+}
+
+float VisualServerRaster::baked_light_get_lightmap_multiplier(RID p_baked_light) const{
+
+	const BakedLight *baked_light = baked_light_owner.get(p_baked_light);
+	ERR_FAIL_COND_V(!baked_light,0);
+
+	return baked_light->data.lightmap_multiplier;
+
+}
+
+
 void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree){
 
 	VS_CHANGED;
@@ -2568,7 +2589,7 @@ void VisualServerRaster::instance_geometry_set_baked_light_texture_index(RID p_i
 	Instance *instance = instance_owner.get( p_instance );
 	ERR_FAIL_COND( !instance );
 
-	instance->lightmap_texture_index=p_tex_id;
+	instance->data.baked_lightmap_id=p_tex_id;
 
 
 }
@@ -2577,7 +2598,7 @@ int VisualServerRaster::instance_geometry_get_baked_light_texture_index(RID p_in
 	const Instance *instance = instance_owner.get( p_instance );
 	ERR_FAIL_COND_V( !instance,0 );
 
-	return instance->lightmap_texture_index;
+	return instance->data.baked_lightmap_id;
 
 }
 

+ 6 - 2
servers/visual/visual_server_raster.h

@@ -157,7 +157,7 @@ class VisualServerRaster : public VisualServer {
 		float draw_range_begin;
 		float draw_range_end;
 		float extra_margin;
-		int lightmap_texture_index;
+
 
 
 		Rasterizer::InstanceData data;
@@ -267,6 +267,7 @@ class VisualServerRaster : public VisualServer {
 			data.billboard_y=false;
 			data.baked_light=NULL;
 			data.baked_light_octree_xform=NULL;
+			data.baked_lightmap_id=-1;
 			version=1;
 			room_info=NULL;
 			room=NULL;
@@ -278,7 +279,7 @@ class VisualServerRaster : public VisualServer {
 			draw_range_end=0;
 			extra_margin=0;
 			visible_in_all_rooms=false;
-			lightmap_texture_index=-1;
+
 			baked_light=NULL;
 			baked_light_info=NULL;
 			BLE=NULL;
@@ -942,6 +943,9 @@ 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_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);
 

+ 2 - 0
servers/visual/visual_server_wrap_mt.h

@@ -909,6 +909,8 @@ public:
 	FUNC2(baked_light_set_octree,RID,DVector<uint8_t>);
 	FUNC1RC(DVector<uint8_t>,baked_light_get_octree,RID);
 
+	FUNC2(baked_light_set_lightmap_multiplier,RID,float);
+	FUNC1RC(float,baked_light_get_lightmap_multiplier,RID);
 
 	FUNC3(baked_light_add_lightmap,RID,RID,int);
 	FUNC1(baked_light_clear_lightmaps,RID);

+ 3 - 0
servers/visual_server.h

@@ -585,6 +585,9 @@ 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_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;
 

BIN
tools/editor/icons/icon_light_map.png


+ 11 - 6
tools/editor/io_plugins/editor_scene_import_plugin.cpp

@@ -407,6 +407,7 @@ void EditorSceneImportDialog::_import(bool p_and_open) {
 
 	rim->add_source(EditorImportPlugin::validate_source_path(import_path->get_text()));
 	rim->set_option("flags",flags);
+	print_line("GET FLAGS: "+itos(texture_options->get_flags()));
 	rim->set_option("texture_flags",texture_options->get_flags());
 	rim->set_option("texture_format",texture_options->get_format());
 	rim->set_option("texture_quality",texture_options->get_quality());
@@ -640,6 +641,7 @@ const EditorSceneImportDialog::FlagInfo EditorSceneImportDialog::scene_flag_name
 	{EditorSceneImportPlugin::SCENE_FLAG_DETECT_ALPHA,"Materials","Set Alpha in Materials (-alpha)",true},
 	{EditorSceneImportPlugin::SCENE_FLAG_DETECT_VCOLOR,"Materials","Set Vert. Color in Materials (-vcol)",true},
 	{EditorSceneImportPlugin::SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES,"Actions","SRGB->Linear Of Diffuse Textures",false},
+	{EditorSceneImportPlugin::SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS,"Actions","Set Material Lightmap to UV2 if Tex2Array Exists",true},
 	{EditorSceneImportPlugin::SCENE_FLAG_CREATE_COLLISIONS,"Create","Create Collisions (-col},-colonly)",true},
 	{EditorSceneImportPlugin::SCENE_FLAG_CREATE_PORTALS,"Create","Create Portals (-portal)",true},
 	{EditorSceneImportPlugin::SCENE_FLAG_CREATE_ROOMS,"Create","Create Rooms (-room)",true},
@@ -1036,7 +1038,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 	}
 
 
-	if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR) && p_node->cast_to<MeshInstance>()) {
+	if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR|SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS) && p_node->cast_to<MeshInstance>()) {
 
 		MeshInstance *mi = p_node->cast_to<MeshInstance>();
 
@@ -1061,6 +1063,10 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 					mat->set_name(_fixstr(mat->get_name(),"vcol"));
 				}
 
+				if (p_flags&SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS && m->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV2) {
+					mat->set_flag(Material::FLAG_LIGHTMAP_ON_UV2,true);
+				}
+
 			}
 		}
 	}
@@ -1224,13 +1230,13 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
 		col->set_name("col");
 		p_node->add_child(col);
 
-
-		StaticBody *sb = col->cast_to<StaticBody>();
+		StaticBody *sb=col->cast_to<StaticBody>();
 		CollisionShape *colshape = memnew( CollisionShape);
 		colshape->set_shape(sb->get_shape(0));
 		colshape->set_name("shape");
-		sb->add_child(colshape);
+		col->add_child(colshape);
 		colshape->set_owner(p_node->get_owner());
+		sb->set_owner(p_node->get_owner());
 
 	} else if (p_flags&SCENE_FLAG_CREATE_NAVMESH &&_teststr(name,"navmesh") && p_node->cast_to<MeshInstance>()) {
 
@@ -1892,8 +1898,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c
 			Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
 			print_line("flags: "+itos(image_flags));
 			uint32_t flags = image_flags;
-			if (E->get())
-				flags|=EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR;
+
 			imd->set_option("flags",flags);
 			imd->set_option("format",image_format);
 			imd->set_option("quality",image_quality);

+ 1 - 0
tools/editor/io_plugins/editor_scene_import_plugin.h

@@ -131,6 +131,7 @@ public:
 		SCENE_FLAG_COMPRESS_GEOMETRY=1<<26,
 		SCENE_FLAG_GENERATE_TANGENT_ARRAYS=1<<27,
 		SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES=1<<28,
+		SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS=1<<29,
 	};
 
 

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

@@ -725,6 +725,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 	bool atlas = from->get_option("atlas");
 
 	int flags=from->get_option("flags");
+	print_line("GET FLAGS: "+itos(flags));
 	uint32_t tex_flags=0;
 
 	if (flags&EditorTextureImportPlugin::IMAGE_FLAG_REPEAT)
@@ -993,6 +994,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
 
 		if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) {
 
+			print_line("CONVERT BECAUSE: "+itos(flags));
 			image.srgb_to_linear();
 		}
 

+ 524 - 4
tools/editor/plugins/baked_light_baker.cpp

@@ -45,7 +45,7 @@ BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>&
 }
 
 
-void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform) {
+void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture) {
 
 
 	for(int i=0;i<p_mesh->get_surface_count();i++) {
@@ -55,6 +55,7 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 		Ref<Material> mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i);
 
 		MeshMaterial *matptr=NULL;
+		int baked_tex=p_baked_texture;
 
 		if (mat.is_valid()) {
 
@@ -112,6 +113,8 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 		DVector<Vector3>::Read vr=vertices.read();
 		DVector<Vector2> uv;
 		DVector<Vector2>::Read uvr;
+		DVector<Vector2> uv2;
+		DVector<Vector2>::Read uv2r;
 		DVector<Vector3> normal;
 		DVector<Vector3>::Read normalr;
 		bool read_uv=false;
@@ -122,6 +125,18 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 			uv=a[Mesh::ARRAY_TEX_UV];
 			uvr=uv.read();
 			read_uv=true;
+
+			if (mat.is_valid() && mat->get_flag(Material::FLAG_LIGHTMAP_ON_UV2) && p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV2) {
+
+				uv2=a[Mesh::ARRAY_TEX_UV2];
+				uv2r=uv2.read();
+
+			} else {
+				uv2r=uv.read();
+				if (baked_light->get_transfer_lightmaps_only_to_uv2()) {
+					baked_tex=-1;
+				}
+			}
 		}
 
 		if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) {
@@ -145,11 +160,16 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 				t.vertices[1]=p_xform.xform(vr[ ir[i*3+1] ]);
 				t.vertices[2]=p_xform.xform(vr[ ir[i*3+2] ]);
 				t.material=matptr;
+				t.baked_texture=baked_tex;
 				if (read_uv) {
 
 					t.uvs[0]=uvr[ ir[i*3+0] ];
 					t.uvs[1]=uvr[ ir[i*3+1] ];
 					t.uvs[2]=uvr[ ir[i*3+2] ];
+
+					t.bake_uvs[0]=uv2r[ ir[i*3+0] ];
+					t.bake_uvs[1]=uv2r[ ir[i*3+1] ];
+					t.bake_uvs[2]=uv2r[ ir[i*3+2] ];
 				}
 				if (read_normal) {
 
@@ -167,11 +187,17 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m
 				t.vertices[1]=p_xform.xform(vr[ i*3+1 ]);
 				t.vertices[2]=p_xform.xform(vr[ i*3+2 ]);
 				t.material=matptr;
+				t.baked_texture=baked_tex;
 				if (read_uv) {
 
 					t.uvs[0]=uvr[ i*3+0 ];
 					t.uvs[1]=uvr[ i*3+1 ];
 					t.uvs[2]=uvr[ i*3+2 ];
+
+					t.bake_uvs[0]=uv2r[ i*3+0 ];
+					t.bake_uvs[1]=uv2r[ i*3+1 ];
+					t.bake_uvs[2]=uv2r[ i*3+2 ];
+
 				}
 				if (read_normal) {
 
@@ -193,7 +219,7 @@ void BakedLightBaker::_parse_geometry(Node* p_node) {
 		MeshInstance *meshi=p_node->cast_to<MeshInstance>();
 		Ref<Mesh> mesh=meshi->get_mesh();
 		if (mesh.is_valid()) {
-			_add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform());
+			_add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform(),meshi->get_baked_light_texture_id());
 		}
 	} else if (p_node->cast_to<Light>()) {
 
@@ -214,9 +240,11 @@ void BakedLightBaker::_parse_geometry(Node* p_node) {
 			dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE);
 			dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION);
 			dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION);
+			dirl.darkening=dl->get_parameter(DirectionalLight::PARAM_SHADOW_DARKENING);
 			dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS);
 			dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL;
 			dirl.rays_thrown=0;
+			dirl.bake_shadow=dl->get_bake_mode()==Light::BAKE_MODE_INDIRECT_AND_SHADOWS;
 			lights.push_back(dirl);
 		}
 
@@ -720,7 +748,7 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos,
 					float intensity = 1.0 - (d/r)*(d/r); //not gauss but..
 					float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2])));
 					intensity*=pow(damp,edge_damp);
-					intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
+					//intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size);
 					octant.light[p_light_index].accum[i][0]+=p_light.r*intensity;
 					octant.light[p_light_index].accum[i][1]+=p_light.g*intensity;
 					octant.light[p_light_index].accum[i][2]+=p_light.b*intensity;
@@ -1310,7 +1338,7 @@ double BakedLightBaker::get_normalization(int p_light_idx) const {
 	nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel
 	nrg*=dl.constant;
 	//nrg*=5;
-	print_line("CS: "+rtos(cell_size));
+
 
 	return nrg;
 }
@@ -1460,6 +1488,13 @@ void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) {
 	normal_damp=baked_light->get_normal_damp();
 	octree_extra_margin=baked_light->get_cell_extra_margin();
 
+	baked_textures.clear();
+	for(int i=0;i<baked_light->get_lightmaps_count();i++) {
+		BakeTexture bt;
+		bt.width=baked_light->get_lightmap_gen_size(i).x;
+		bt.height=baked_light->get_lightmap_gen_size(i).y;
+		baked_textures.push_back(bt);
+	}
 
 
 	ep.step("Parsing Geometry",0);
@@ -1690,6 +1725,484 @@ void BakedLightBaker::_stop_thread() {
 	thread=NULL;
 }
 
+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();
+
+
+	Color color;
+
+	Octant *octants=octant_pool.ptr();
+
+
+	int octant_idx=0;
+
+
+	while(true) {
+
+		Octant &octant=octants[octant_idx];
+
+		if (octant.leaf) {
+
+			Vector3 lpos = p_pos-octant.aabb.pos;
+			lpos/=octant.aabb.size;
+
+			Vector3 cols[8];
+
+			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];
+				}
+			}
+
+
+			/*Vector3 final = (cols[0] + (cols[1] - cols[0]) * lpos.y);
+			final = final + ((cols[2] + (cols[3] - cols[2]) * lpos.y) - final)*lpos.x;
+
+			Vector3 final2 = (cols[4+0] + (cols[4+1] - cols[4+0]) * lpos.y);
+			final2 = final2 + ((cols[4+2] + (cols[4+3] - cols[4+2]) * lpos.y) - final2)*lpos.x;*/
+
+			Vector3 finala = cols[0].linear_interpolate(cols[1],lpos.x);
+			Vector3 finalb = cols[2].linear_interpolate(cols[3],lpos.x);
+			Vector3 final = finala.linear_interpolate(finalb,lpos.y);
+
+			Vector3 final2a = cols[4+0].linear_interpolate(cols[4+1],lpos.x);
+			Vector3 final2b = cols[4+2].linear_interpolate(cols[4+3],lpos.x);
+			Vector3 final2 = final2a.linear_interpolate(final2b,lpos.y);
+
+			final = final.linear_interpolate(final2,lpos.z);
+			if (baked_light->get_format()==BakedLight::FORMAT_HDR8)
+				final*=8.0;
+
+
+			color.r=pow(final.x*mult,gamma);
+			color.g=pow(final.y*mult,gamma);
+			color.b=pow(final.z*mult,gamma);
+			color.a=1.0;
+
+			int lc = lights.size();
+			LightData *lv = lights.ptr();
+			for(int i=0;i<lc;i++) {
+				//shadow baking
+				if (!lv[i].bake_shadow)
+					continue;
+				Vector3 from = p_pos+p_normal*0.01;
+				Vector3 to;
+				float att=0;
+				switch(lv[i].type) {
+					case VS::LIGHT_DIRECTIONAL: {
+						to=from-lv[i].dir*lv[i].length;
+					} break;
+					case VS::LIGHT_OMNI: {
+						to=lv[i].pos;
+						float d = MIN(lv[i].radius,to.distance_to(from))/lv[i].radius;
+						att=d;//1.0-d;
+					} break;
+					default: continue;
+				}
+
+				uint32_t* stack = ray_stack;
+				BVH **bstack = bvh_stack;
+
+				enum {
+					TEST_RAY_BIT=0,
+					VISIT_LEFT_BIT=1,
+					VISIT_RIGHT_BIT=2,
+					VISIT_DONE_BIT=3,
+
+
+				};
+
+				bool intersected=false;
+
+				int level=0;
+
+				Vector3 n = (to-from);
+				float len=n.length();
+				if (len==0)
+					continue;
+				n/=len;
+
+				const BVH *bvhptr = bvh;
+
+				bstack[0]=bvh;
+				stack[0]=TEST_RAY_BIT;
+
+
+				while(!intersected) {
+
+					uint32_t mode = stack[level];
+					const BVH &b = *bstack[level];
+					bool done=false;
+
+					switch(mode) {
+						case TEST_RAY_BIT: {
+
+							if (b.leaf) {
+
+
+								Face3 f3(b.leaf->vertices[0],b.leaf->vertices[1],b.leaf->vertices[2]);
+
+
+								Vector3 res;
+
+								if (f3.intersects_segment(from,to)) {
+									intersected=true;
+									done=true;
+								}
+
+								stack[level]=VISIT_DONE_BIT;
+							} else {
+
+
+								bool valid = b.aabb.smits_intersect_ray(from,n,0,len);
+								//bool valid = b.aabb.intersects_segment(p_begin,p_end);
+				//				bool valid = b.aabb.intersects(ray_aabb);
+
+								if (!valid) {
+
+									stack[level]=VISIT_DONE_BIT;
+
+								} else {
+
+									stack[level]=VISIT_LEFT_BIT;
+								}
+							}
+
+						} continue;
+						case VISIT_LEFT_BIT: {
+
+							stack[level]=VISIT_RIGHT_BIT;
+							bstack[level+1]=b.children[0];
+							stack[level+1]=TEST_RAY_BIT;
+							level++;
+
+						} continue;
+						case VISIT_RIGHT_BIT: {
+
+							stack[level]=VISIT_DONE_BIT;
+							bstack[level+1]=b.children[1];
+							stack[level+1]=TEST_RAY_BIT;
+							level++;
+						} continue;
+						case VISIT_DONE_BIT: {
+
+							if (level==0) {
+								done=true;
+								break;
+							} else
+								level--;
+
+						} continue;
+					}
+
+
+					if (done)
+						break;
+				}
+
+
+
+				if (intersected) {
+
+					color.a=Math::lerp(MAX(0.01,lv[i].darkening),1.0,att);
+				}
+
+			}
+
+			break;
+		} else {
+
+			Vector3 lpos = p_pos - octant.aabb.pos;
+			Vector3 half = octant.aabb.size * 0.5;
+
+			int ofs=0;
+
+			if (lpos.x >= half.x)
+				ofs|=1;
+			if (lpos.y >= half.y)
+				ofs|=2;
+			if (lpos.z >= half.z)
+				ofs|=4;
+
+			octant_idx = octant.children[ofs];
+
+			if (octant_idx==0)
+				return;
+
+		}
+	}
+
+	ptr[0]=CLAMP(color.r*255.0,0,255);
+	ptr[1]=CLAMP(color.g*255.0,0,255);
+	ptr[2]=CLAMP(color.b*255.0,0,255);
+	ptr[3]=CLAMP(color.a*255.0,0,255);
+
+}
+
+
+Error BakedLightBaker::transfer_to_lightmaps() {
+
+	if (!triangles.size() || baked_textures.size()==0)
+		return ERR_UNCONFIGURED;
+
+	EditorProgress ep("transfer_to_lightmaps","Transfer to Lightmaps:",baked_textures.size()*2+triangles.size());
+
+	for(int i=0;i<baked_textures.size();i++) {
+
+		ERR_FAIL_COND_V( baked_textures[i].width<=0 || baked_textures[i].height<=0,ERR_UNCONFIGURED );
+
+		baked_textures[i].data.resize( baked_textures[i].width*baked_textures[i].height*4 );
+		zeromem(baked_textures[i].data.ptr(),baked_textures[i].data.size());
+		ep.step("Allocating Texture #"+itos(i+1),i);
+	}
+
+	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);
+	}
+	float gamma = baked_light->get_gamma_adjust();
+	float mult = baked_light->get_energy_multiplier();
+
+
+	const double *normptr=norm_arr.ptr();
+	for(int i=0;i<triangles.size();i++) {
+
+		if (i%200==0) {
+			ep.step("Baking Triangle #"+itos(i),i+baked_textures.size());
+		}
+		Triangle &t=triangles[i];
+		if (t.baked_texture<0 || t.baked_texture>=baked_textures.size())
+			continue;
+
+		BakeTexture &bt=baked_textures[t.baked_texture];
+		Vector3 normal = Plane(t.vertices[0],t.vertices[1],t.vertices[2]).normal;
+
+
+		int x[3];
+		int y[3];
+
+		Vector3 vertices[3]={
+			t.vertices[0],
+			t.vertices[1],
+			t.vertices[2]
+		};
+
+		for(int j=0;j<3;j++) {
+
+			x[j]=t.bake_uvs[j].x*bt.width;
+			y[j]=t.bake_uvs[j].y*bt.height;
+			x[j]=CLAMP(x[j],0,bt.width-1);
+			y[j]=CLAMP(y[j],0,bt.height-1);
+		}
+
+
+		{
+
+			// sort the points vertically
+			if (y[1] > y[2])  {
+				SWAP(x[1], x[2]);
+				SWAP(y[1], y[2]);
+				SWAP(vertices[1],vertices[2]);
+			}
+			if (y[0] > y[1]) {
+				SWAP(x[0], x[1]);
+				SWAP(y[0], y[1]);
+				SWAP(vertices[0],vertices[1]);
+			}
+			if (y[1] > y[2]) {
+				SWAP(x[1], x[2]);
+				SWAP(y[1], y[2]);
+				SWAP(vertices[1],vertices[2]);
+			}
+
+			double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1);
+			double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1);
+			double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1);
+			double xf = x[0];
+			double xt = x[0] + dx_upper; // if y[0] == y[1], special case
+			for (int yi = y[0]; yi <= (y[2] > bt.height-1 ? bt.height-1 : y[2]); yi++)
+			{
+				if (yi >= 0) {
+					for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < bt.width ? xt : bt.width-1) ; xi++) {
+						//pixels[int(x + y * width)] = color;
+
+						Vector2 v0 = Vector2(x[1]-x[0],y[1]-y[0]);
+						Vector2 v1 = Vector2(x[2]-x[0],y[2]-y[0]);
+						//vertices[2] - vertices[0];
+						Vector2 v2 = Vector2(xi-x[0],yi-y[0]);
+						float d00 = v0.dot( v0);
+						float d01 = v0.dot( v1);
+						float d11 = v1.dot( v1);
+						float d20 = v2.dot( v0);
+						float d21 = v2.dot( v1);
+						float denom = (d00 * d11 - d01 * d01);
+						Vector3 pos;
+						if (denom==0) {
+							pos=t.vertices[0];
+						} else {
+							float v = (d11 * d20 - d01 * d21) / denom;
+							float w = (d00 * d21 - d01 * d20) / denom;
+							float u = 1.0f - v - w;
+							pos = vertices[0]*u + vertices[1]*v  + vertices[2]*w;
+						}
+						_plot_pixel_to_lightmap(xi,yi,bt.width,bt.height,bt.data.ptr(),pos,normal,norm_arr.ptr(),mult,gamma);
+
+					}
+
+					for (int xi = (xf < bt.width ? int(xf) : bt.width-1); xi >= (xt > 0 ? xt : 0); xi--) {
+						//pixels[int(x + y * width)] = color;
+						Vector2 v0 = Vector2(x[1]-x[0],y[1]-y[0]);
+						Vector2 v1 = Vector2(x[2]-x[0],y[2]-y[0]);
+						//vertices[2] - vertices[0];
+						Vector2 v2 = Vector2(xi-x[0],yi-y[0]);
+						float d00 = v0.dot( v0);
+						float d01 = v0.dot( v1);
+						float d11 = v1.dot( v1);
+						float d20 = v2.dot( v0);
+						float d21 = v2.dot( v1);
+						float denom = (d00 * d11 - d01 * d01);
+						Vector3 pos;
+						if (denom==0) {
+							pos=t.vertices[0];
+						} else {
+							float v = (d11 * d20 - d01 * d21) / denom;
+							float w = (d00 * d21 - d01 * d20) / denom;
+							float u = 1.0f - v - w;
+							pos = vertices[0]*u + vertices[1]*v  + vertices[2]*w;
+						}
+
+						_plot_pixel_to_lightmap(xi,yi,bt.width,bt.height,bt.data.ptr(),pos,normal,norm_arr.ptr(),mult,gamma);
+
+					}
+				}
+				xf += dx_far;
+				if (yi < y[1])
+					xt += dx_upper;
+				else
+					xt += dx_low;
+			}
+		}
+
+	}
+
+
+	for(int i=0;i<baked_textures.size();i++) {
+
+
+		{
+
+			ep.step("Post-Processing Texture #"+itos(i),i+baked_textures.size()+triangles.size());
+
+			BakeTexture &bt=baked_textures[i];
+
+			Vector<uint8_t> copy_data=bt.data;
+			uint8_t *data=bt.data.ptr();
+			uint8_t *src_data=copy_data.ptr();
+			const int max_radius=8;
+			const int shadow_radius=2;
+			const int max_dist=0x7FFFFFFF;
+
+			for(int x=0;x<bt.width;x++) {
+
+				for(int y=0;y<bt.height;y++) {
+
+
+					uint8_t a = copy_data[(y*bt.width+x)*4+3];
+
+					if (a>0) {
+						//blur shadow
+
+						int from_x = MAX(0,x-shadow_radius);
+						int to_x = MIN(bt.width-1,x+shadow_radius);
+						int from_y = MAX(0,y-shadow_radius);
+						int to_y = MIN(bt.height-1,y+shadow_radius);
+
+						int sum=0;
+						int sumc=0;
+
+						for(int k=from_y;k<=to_y;k++) {
+							for(int l=from_x;l<=to_x;l++) {
+
+								const uint8_t * rp = &copy_data[(k*bt.width+l)<<2];
+
+								sum+=rp[3];
+								sumc++;
+							}
+						}
+
+						sum/=sumc;
+						data[(y*bt.width+x)*4+3]=sum;
+
+					} else {
+
+						int closest_dist=max_dist;
+						uint8_t closest_color[4];
+
+						int from_x = MAX(0,x-max_radius);
+						int to_x = MIN(bt.width-1,x+max_radius);
+						int from_y = MAX(0,y-max_radius);
+						int to_y = MIN(bt.height-1,y+max_radius);
+
+						for(int k=from_y;k<=to_y;k++) {
+							for(int l=from_x;l<=to_x;l++) {
+
+								int dy = y-k;
+								int dx = x-l;
+								int dist = dy*dy+dx*dx;
+								if (dist>=closest_dist)
+									continue;
+
+								const uint8_t * rp = &copy_data[(k*bt.width+l)<<2];
+
+								if (rp[3]==0)
+									continue;
+
+								closest_dist=dist;
+								closest_color[0]=rp[0];
+								closest_color[1]=rp[1];
+								closest_color[2]=rp[2];
+								closest_color[3]=rp[3];
+							}
+						}
+
+
+						if (closest_dist!=max_dist) {
+
+							data[(y*bt.width+x)*4+0]=closest_color[0];
+							data[(y*bt.width+x)*4+1]=closest_color[1];
+							data[(y*bt.width+x)*4+2]=closest_color[2];
+							data[(y*bt.width+x)*4+3]=closest_color[3];
+						}
+					}
+				}
+			}
+		}
+
+		DVector<uint8_t> dv;
+		dv.resize(baked_textures[i].data.size());
+		{
+			DVector<uint8_t>::Write w = dv.write();
+			copymem(w.ptr(),baked_textures[i].data.ptr(),baked_textures[i].data.size());
+		}
+
+		Image img(baked_textures[i].width,baked_textures[i].height,0,Image::FORMAT_RGBA,dv);
+		Ref<ImageTexture> tex = memnew( ImageTexture );
+		tex->create_from_image(img);
+		baked_light->set_lightmap_texture(i,tex);
+	}
+
+
+	return OK;
+}
+
 void BakedLightBaker::clear() {
 
 
@@ -1711,7 +2224,14 @@ void BakedLightBaker::clear() {
 	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());
+
+		for(int i=0;i<lights.size();i++) {
+			norm_arr[i] =  1.0/get_normalization(i);
 		}
+
+		const double *normptr=norm_arr.ptr();
 	}
 	octant_pool.clear();
 	octant_pool_size=0;

+ 16 - 2
tools/editor/plugins/baked_light_baker.h

@@ -94,11 +94,13 @@ public:
 
 	struct Triangle {
 
-		AABB aabb;
+		AABB aabb;	
 		Vector3 vertices[3];
 		Vector2 uvs[3];
+		Vector2 bake_uvs[3];
 		Vector3 normals[3];
 		MeshMaterial *material;
+		int baked_texture;
 
 		_FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) {
 
@@ -180,6 +182,12 @@ public:
 		}
 	};
 
+	struct BakeTexture {
+
+		Vector<uint8_t> data;
+		int width,height;
+	};
+
 
 	struct LightData {
 
@@ -194,10 +202,12 @@ public:
 		float energy;
 		float length;
 		int rays_thrown;
+		bool bake_shadow;
 
 		float radius;
 		float attenuation;
 		float spot_angle;
+		float darkening;
 		float spot_attenuation;
 		float area;
 
@@ -220,6 +230,7 @@ public:
 	int octant_pool_size;
 	BVH*bvh;
 	Vector<Triangle> triangles;
+	Vector<BakeTexture> baked_textures;
 	Transform base_inv;
 	int leaf_list;
 	int octree_depth;
@@ -255,13 +266,14 @@ public:
 
 
 	MeshTexture* _get_mat_tex(const Ref<Texture>& p_tex);
-	void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform);
+	void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture=-1);
 	void _parse_geometry(Node* p_node);
 	BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth);
 	void _make_bvh();
 	void _make_octree();
 	void _make_octree_texture();
 	void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth);
+	_FORCE_INLINE_ void _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);
 
 
 	void _free_bvh(BVH* p_bvh);
@@ -302,6 +314,8 @@ public:
 	bool is_paused();
 	int get_rays_sec() { return rays_sec; }
 
+	Error transfer_to_lightmaps();
+
 	void update_octree_image(DVector<uint8_t> &p_image);
 
 	Ref<BakedLight> get_baked_light() { return baked_light; }

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

@@ -38,6 +38,7 @@ void BakedLightEditor::_notification(int p_option) {
 
 		button_bake->set_icon(get_icon("Bake","EditorIcons"));
 		button_reset->set_icon(get_icon("Reload","EditorIcons"));
+		button_make_lightmaps->set_icon(get_icon("LightMap","EditorIcons"));
 	}
 
 	if (p_option==NOTIFICATION_PROCESS) {
@@ -148,7 +149,7 @@ void BakedLightEditor::_menu_option(int p_option) {
 			ERR_FAIL_COND(!node);
 			ERR_FAIL_COND(node->get_baked_light().is_null());
 			baker->bake(node->get_baked_light(),node);
-
+			node->get_baked_light()->set_mode(BakedLight::MODE_OCTREE);
 			update_timeout=0;
 			set_process(true);
 
@@ -180,14 +181,19 @@ void BakedLightEditor::_bake_pressed() {
 
 			set_process(false);
 			bake_info->set_text("");
+			button_reset->show();
+			button_make_lightmaps->show();
+
 		} else {
 
 			update_timeout=0;
 			set_process(true);
+			button_make_lightmaps->hide();
+			button_reset->hide();
 		}
-
 	} else {
 		baker->bake(node->get_baked_light(),node);
+		node->get_baked_light()->set_mode(BakedLight::MODE_OCTREE);
 		update_timeout=0;
 		set_process(true);
 	}
@@ -216,13 +222,27 @@ void BakedLightEditor::edit(BakedLightInstance *p_baked_light) {
 
 }
 
+void BakedLightEditor::_bake_lightmaps() {
+
+	Error err = baker->transfer_to_lightmaps();
+	if (err) {
+
+		err_dialog->set_text("Error baking to lightmaps!\nMake sure that a bake has just\n happened and that lightmaps are\n configured. ");
+		err_dialog->popup_centered(Size2(350,70));
+		return;
+	}
 
+	node->get_baked_light()->set_mode(BakedLight::MODE_LIGHTMAPS);
+
+
+}
 
 void BakedLightEditor::_bind_methods() {
 
 	ObjectTypeDB::bind_method("_menu_option",&BakedLightEditor::_menu_option);
 	ObjectTypeDB::bind_method("_bake_pressed",&BakedLightEditor::_bake_pressed);
 	ObjectTypeDB::bind_method("_clear_pressed",&BakedLightEditor::_clear_pressed);
+	ObjectTypeDB::bind_method("_bake_lightmaps",&BakedLightEditor::_bake_lightmaps);
 }
 
 BakedLightEditor::BakedLightEditor() {
@@ -233,6 +253,11 @@ BakedLightEditor::BakedLightEditor() {
 	button_bake->set_text("Bake!");
 	button_bake->set_toggle_mode(true);
 	button_reset = memnew( Button );
+	button_make_lightmaps = memnew( Button );
+	button_bake->set_tooltip("Start/Unpause the baking process.\nThis bakes lighting into the lightmap octree.");
+	button_make_lightmaps ->set_tooltip("Convert the lightmap octree to lightmap textures\n(must have set up UV/Lightmaps properly before!).");
+
+
 	bake_info = memnew( Label );
 	bake_hbox->add_child( button_bake );
 	bake_hbox->add_child( button_reset );
@@ -243,8 +268,15 @@ BakedLightEditor::BakedLightEditor() {
 	node=NULL;
 	baker = memnew( BakedLightBaker );
 
+	bake_hbox->add_child(button_make_lightmaps);
+	button_make_lightmaps->hide();
+
 	button_bake->connect("pressed",this,"_bake_pressed");
 	button_reset->connect("pressed",this,"_clear_pressed");
+	button_make_lightmaps->connect("pressed",this,"_bake_lightmaps");
+	button_reset->hide();
+	button_reset->set_tooltip("Reset the lightmap octree baking process (start over).");
+
 
 	update_timeout=0;
 

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

@@ -30,6 +30,7 @@ class BakedLightEditor : public Control {
 	HBoxContainer *bake_hbox;
 	Button *button_bake;
 	Button *button_reset;
+	Button *button_make_lightmaps;
 	Label *bake_info;
 
 
@@ -41,6 +42,8 @@ class BakedLightEditor : public Control {
 		MENU_OPTION_CLEAR
 	};
 
+	void _bake_lightmaps();
+
 	void _bake_pressed();
 	void _clear_pressed();
 

+ 3 - 1
tools/editor/plugins/shader_editor_plugin.cpp

@@ -436,8 +436,10 @@ void ShaderEditor::save_external_data() {
 void ShaderEditor::apply_shaders()  {
 
 
-	if (shader.is_valid())
+	if (shader.is_valid()) {
 		shader->set_code(vertex_editor->get_text_edit()->get_text(),fragment_editor->get_text_edit()->get_text(),light_editor->get_text_edit()->get_text(),0,0);
+		shader->set_edited(true);
+	}
 }
 
 void ShaderEditor::_close_callback() {

+ 27 - 11
tools/editor/scene_tree_editor.cpp

@@ -66,11 +66,19 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
 	} else if (p_id==BUTTON_VISIBILITY) {
 
 
-		if (n->is_type("GeometryInstance")) {
-			bool v = n->call("get_flag",VS::INSTANCE_FLAG_VISIBLE);
-			undo_redo->create_action("Toggle Geometry Visible");
-			undo_redo->add_do_method(n,"set_flag",VS::INSTANCE_FLAG_VISIBLE,!v);
-			undo_redo->add_undo_method(n,"set_flag",VS::INSTANCE_FLAG_VISIBLE,v);
+		if (n->is_type("Spatial")) {
+
+			Spatial *ci = n->cast_to<Spatial>();
+			if (!ci->is_visible() && ci->get_parent_spatial() && !ci->get_parent_spatial()->is_visible()) {
+				error->set_text("This item cannot be made visible because the parent is hidden. Unhide the parent first.");
+				error->popup_centered_minsize(Size2(400,80));
+				return;
+			}
+
+			bool v = !bool(n->call("is_hidden"));
+			undo_redo->create_action("Toggle Spatial Visible");
+			undo_redo->add_do_method(n,"_set_visible_",!v);
+			undo_redo->add_undo_method(n,"_set_visible_",v);
 			undo_redo->commit_action();
 		} else if (n->is_type("CanvasItem")) {
 
@@ -189,9 +197,9 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
 			if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed"))
 				p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node));
 
-		} else if (p_node->is_type("GeometryInstance")) {
+		} else if (p_node->is_type("Spatial")) {
 
-			bool h = !p_node->call("get_flag",VS::INSTANCE_FLAG_VISIBLE);
+			bool h = p_node->call("is_hidden");
 			if (h)
 				item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY);
 			else
@@ -226,7 +234,16 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
 
 void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
 
+
+	if (p_node!=get_scene_node() && !p_node->get_owner()) {
+
+		return;
+	}
 	TreeItem* item=p_node?_find(tree->get_root(),p_node->get_path()):NULL;
+	if (!item) {
+
+		return;
+	}
 	int idx=item->get_button_by_id(0,BUTTON_VISIBILITY);
 	ERR_FAIL_COND(idx==-1);
 
@@ -234,11 +251,10 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
 
 	if (p_node->is_type("CanvasItem")) {
 		visible = !p_node->call("is_hidden");
-	} else if (p_node->is_type("GeometryInstance")) {
-		visible = p_node->call("get_flag",VS::INSTANCE_FLAG_VISIBLE);
+	} else if (p_node->is_type("Spatial")) {
+		visible = !p_node->call("is_hidden");
 	}
 
-
 	if (!visible)
 		item->set_button(0,idx,get_icon("Hidden","EditorIcons"));
 	else
@@ -274,7 +290,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) {
 	if (p_node->is_connected("script_changed",this,"_node_script_changed"))
 		p_node->disconnect("script_changed",this,"_node_script_changed");
 
-	if (p_node->is_type("GeometryInstance") || p_node->is_type("CanvasItem")) {
+	if (p_node->is_type("Spatial") || p_node->is_type("CanvasItem")) {
 		if (p_node->is_connected("visibility_changed",this,"_node_visibility_changed"))
 			p_node->disconnect("visibility_changed",this,"_node_visibility_changed");
 	}

+ 5 - 2
tools/export/blender25/io_scene_dae/export_dae.py

@@ -292,6 +292,9 @@ class DaeExporter:
 			self.writel(S_FX,7,'<texture texture="'+normal_tex+'" texcoord="CHANNEL1"/>')
 			self.writel(S_FX,6,'</bump>')
 
+		self.writel(S_FX,5,'</technique>')
+		self.writel(S_FX,5,'<technique profile="GOOGLEEARTH">')
+		self.writel(S_FX,6,'<double_sided>'+["0","1"][double_sided_hint]+"</double_sided>")
 		self.writel(S_FX,5,'</technique>')
 		self.writel(S_FX,4,'</extra>')
 
@@ -359,7 +362,7 @@ class DaeExporter:
 					mat= None
 
 				if (mat!=None):
-					materials[f.material_index]=self.export_material( mat )
+					materials[f.material_index]=self.export_material( mat,mesh.show_double_sided )
 				else:
 					materials[f.material_index]=None #weird, has no material?
 
@@ -730,7 +733,7 @@ class DaeExporter:
 		self.writel(S_LAMPS,2,'<optics>')
 		self.writel(S_LAMPS,3,'<technique_common>')
 
-		if (light.type=="POINT" or light.type=="HEMI"):
+		if (light.type=="POINT"):
 			self.writel(S_LAMPS,4,'<point>')
 			self.writel(S_LAMPS,5,'<color>'+strarr(light.color)+'</color>')
 			att_by_distance = 2.0 / light.distance # convert to linear attenuation