From 2ee4ac183babedd679e901b0158f5268556deceb Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Thu, 14 Aug 2014 10:31:38 -0300 Subject: [PATCH] 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 --- core/variant_call.cpp | 6 +- drivers/gles2/rasterizer_gles2.cpp | 176 +- drivers/gles2/rasterizer_gles2.h | 5 +- drivers/gles2/shader_compiler_gles2.cpp | 26 + drivers/gles2/shaders/material.glsl | 86 +- modules/gdscript/gd_compiler.cpp | 2 +- .../java/src/com/android/godot/Godot.java | 12 +- .../godot/payments/GenericConsumeTask.java | 4 +- .../godot/payments/HandlePurchaseTask.java | 10 +- .../android/godot/payments/PaymentsCache.java | 4 +- .../payments/ReleaseAllConsumablesTask.java | 12 +- platform/android/java_glue.cpp | 4 +- scene/2d/collision_object_2d.cpp | 4 + scene/2d/screen_button.cpp | 3 + scene/3d/light.cpp | 10 +- scene/3d/light.h | 1 + scene/3d/navigation.cpp | 142 +- scene/3d/navigation.h | 9 +- scene/3d/physics_body.cpp | 14 + scene/3d/physics_body.h | 6 + scene/3d/skeleton.cpp | 10 + scene/3d/skeleton.h | 1 + scene/3d/spatial.cpp | 93 + scene/3d/spatial.h | 14 +- scene/3d/vehicle_body.cpp | 846 +++++ scene/3d/vehicle_body.h | 142 + scene/3d/visual_instance.cpp | 21 +- scene/3d/visual_instance.h | 1 + scene/animation/animation_player.cpp | 6 +- scene/main/viewport.cpp | 18 + scene/main/viewport.h | 4 + scene/register_scene_types.cpp | 3 + scene/resources/baked_light.cpp | 23 +- scene/resources/baked_light.h | 4 + servers/physics/body_pair_sw.cpp | 1 + servers/physics/body_sw.h | 1 + servers/physics/shape_sw.cpp | 3272 ++++++++--------- servers/physics_server.cpp | 1 + servers/physics_server.h | 1 + servers/visual/rasterizer.h | 2 + servers/visual/shader_language.cpp | 6 + servers/visual/visual_server_raster.cpp | 27 +- servers/visual/visual_server_raster.h | 8 +- servers/visual/visual_server_wrap_mt.h | 2 + servers/visual_server.h | 3 + tools/editor/icons/icon_light_map.png | Bin 0 -> 441 bytes .../io_plugins/editor_scene_import_plugin.cpp | 17 +- .../io_plugins/editor_scene_import_plugin.h | 1 + .../editor_texture_import_plugin.cpp | 2 + tools/editor/plugins/baked_light_baker.cpp | 528 ++- tools/editor/plugins/baked_light_baker.h | 18 +- .../plugins/baked_light_editor_plugin.cpp | 36 +- .../plugins/baked_light_editor_plugin.h | 3 + tools/editor/plugins/shader_editor_plugin.cpp | 4 +- tools/editor/scene_tree_editor.cpp | 38 +- .../blender25/io_scene_dae/export_dae.py | 7 +- 56 files changed, 3943 insertions(+), 1757 deletions(-) create mode 100644 scene/3d/vehicle_body.cpp create mode 100644 scene/3d/vehicle_body.h create mode 100644 tools/editor/icons/icon_light_map.png diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 75b1fb78c6..db6b3d9771 100644 --- a/core/variant_call.cpp +++ b/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()); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index a984589093..d55557bdbc 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/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 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; diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 520e1c00f6..a6df10f70b 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/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(); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 3ca632b963..b928d3709b 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/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"; diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl index 17365ea264..3aa27c98ff 100644 --- a/drivers/gles2/shaders/material.glsl +++ b/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 diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 9cbbaf2fcf..fc9040da18 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/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;ivariables.size();i++) { diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java index 57b0943a85..f6cd57f4f3 100644 --- a/platform/android/java/src/com/android/godot/Godot.java +++ b/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 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; iGetObjectArrayElement(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())); }; diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index ab8c4551ee..e5d9872a28 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/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) { diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp index 9d0c9f3d1a..92d6954d97 100644 --- a/scene/2d/screen_button.cpp +++ b/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) { diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 25f3b3d3a5..1efc74e672 100644 --- a/scene/3d/light.cpp +++ b/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 ); + + } diff --git a/scene/3d/light.h b/scene/3d/light.h index 6b1ea2d455..9fdd7295dc 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -69,6 +69,7 @@ public: BAKE_MODE_DISABLED, BAKE_MODE_INDIRECT, + BAKE_MODE_INDIRECT_AND_SHADOWS, BAKE_MODE_FULL }; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index 4b0d233fbe..d2abdad079 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -180,7 +180,7 @@ void Navigation::navmesh_remove(int p_id){ } -Vector Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end) { +Vector Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end, bool p_optimize) { Polygon *begin_poly=NULL; @@ -332,25 +332,113 @@ Vector Navigation::get_simple_path(const Vector3& p_start, const Vector if (found_route) { - //use midpoints for now - Polygon *p=end_poly; Vector 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; + + 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(); + + + + + } 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();; } - 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); } + diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index 40f474858c..e8a97a6591 100644 --- a/scene/3d/navigation.h +++ b/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 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& p_mesh,const Transform& p_xform); void navmesh_set_transform(int p_id, const Transform& p_xform); void navmesh_remove(int p_id); - Vector get_simple_path(const Vector3& p_start, const Vector3& p_end); + Vector 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); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 2a1a5972a9..721fd368e1 100644 --- a/scene/3d/physics_body.cpp +++ b/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) { diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 6695ee719a..616288e1f6 100644 --- a/scene/3d/physics_body.h +++ b/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; diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 323bfa4dc4..858ee4e4ad 100644 --- a/scene/3d/skeleton.cpp +++ b/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(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); diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index c95734fbf1..3e0ab0afd7 100644 --- a/scene/3d/skeleton.h +++ b/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; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index c52503870f..13094300d0 100644 --- a/scene/3d/spatial.cpp +++ b/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::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; diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index e1119be515..f2ec26eb58 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -91,6 +91,8 @@ class Spatial : public Node { bool ignore_notification; + bool visible; + #ifdef TOOLS_ENABLED Ref 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; diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp new file mode 100644 index 0000000000..7680c1d56c --- /dev/null +++ b/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(); + 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(); + 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(); + + + 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 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;iget_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;wheelget_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(); + + 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 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;iget_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"); + +} + diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h new file mode 100644 index 0000000000..97137da699 --- /dev/null +++ b/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 exclude; + + Vector m_forwardWS; + Vector m_axle; + Vector m_forwardImpulse; + Vector 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 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 diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index d6c46f9bf6..af535e139f 100644 --- a/scene/3d/visual_instance.cpp +++ b/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); } diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index 4b4e1e391b..bbb49a2e78 100644 --- a/scene/3d/visual_instance.h +++ b/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); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 15d3dccb71..030f3f27e0 100644 --- a/scene/animation/animation_player.cpp +++ b/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; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index defa7da6ae..ea78ece9dc 100644 --- a/scene/main/viewport.cpp +++ b/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; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index d54b489843..6feb89b084 100644 --- a/scene/main/viewport.h +++ b/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 get_render_target_texture() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index c7268a6650..f7d6a246e6 100644 --- a/scene/register_scene_types.cpp +++ b/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(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp index 72eacb51c5..647c8df5d4 100644 --- a/scene/resources/baked_light.cpp +++ b/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 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; diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h index 942f6eab1a..57ed7d7aee 100644 --- a/scene/resources/baked_light.h +++ b/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; diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp index 094f56a421..c50bfac472 100644 --- a/servers/physics/body_pair_sw.cpp +++ b/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) { diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index 8923899278..8d30069777 100644 --- a/servers/physics/body_sw.h +++ b/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(); } diff --git a/servers/physics/shape_sw.cpp b/servers/physics/shape_sw.cpp index 70e5c00b92..1312b7da95 100644 --- a/servers/physics/shape_sw.cpp +++ b/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::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::Element *E=owners.find(p_owner); - if (E) { - E->get()++; - } else { - owners[p_owner]=1; - } -} - -void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){ - - Map::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& 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 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 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 max) { - max=d; - vtx=i; - } - } - - - for(int i=0;i_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 0) - continue; //opposing face - - int ic = faces[i].indices.size(); - const int *ind=faces[i].indices.ptr(); - - for(int j=1;j& p_vertices) { - - Error err = QuickHull::build(p_vertices,mesh); - AABB _aabb; - - for(int i=0;i 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 ConcavePolygonShapeSW::get_faces() const { - - - DVector rfaces; - rfaces.resize(faces.size()*3); - - for(int i=0;i::Read r=vertices.read(); - const Vector3 *vptr=r.ptr(); - - for (int i=0;i 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::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 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 && dmin_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::Read fr=faces.read(); - DVector::Read vr=vertices.read(); - DVector::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,¶ms); - - 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::Read fr=faces.read(); - DVector::Read vr=vertices.read(); - DVector::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,¶ms); - -} - -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.xaabb=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;iaabb=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 p_faces) { - - int src_face_count=p_faces.size(); - ERR_FAIL_COND(src_face_count%3); - src_face_count/=3; - - DVector::Read r = p_faces.read(); - const Vector3 * facesr= r.ptr(); - -#if 0 - Map point_map; - List face_list; - - - for(int i=0;i::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::Write vw = vertices.write(); - Vector3 *verticesw=vw.ptr(); - - AABB _aabb; - - for( Map::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::Write w = faces.write(); - Face *facesw=w.ptr(); - - int fc=0; - - for( List::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::Write(); - vw=DVector::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::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::Write w = faces.write(); - Face *facesw=w.ptr(); - - vertices.resize( src_face_count*3 ); - - DVector::Write vw = vertices.write(); - Vector3 *verticesw=vw.ptr(); - - AABB _aabb; - - - for(int i=0;i::Write(); - vw=DVector::Write(); - - int count=0; - _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count); - - bvh.resize( count+1 ); - - DVector::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 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 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::Read r = heights. read(); - - AABB aabb; - - for(int i=0;i 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::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::Element *E=owners.find(p_owner); + if (E) { + E->get()++; + } else { + owners[p_owner]=1; + } +} + +void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){ + + Map::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& 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 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 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 max) { + max=d; + vtx=i; + } + } + + + for(int i=0;i_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 0) + continue; //opposing face + + int ic = faces[i].indices.size(); + const int *ind=faces[i].indices.ptr(); + + for(int j=1;j& p_vertices) { + + Error err = QuickHull::build(p_vertices,mesh); + AABB _aabb; + + for(int i=0;i 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 ConcavePolygonShapeSW::get_faces() const { + + + DVector rfaces; + rfaces.resize(faces.size()*3); + + for(int i=0;i::Read r=vertices.read(); + const Vector3 *vptr=r.ptr(); + + for (int i=0;i 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::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 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 && dmin_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::Read fr=faces.read(); + DVector::Read vr=vertices.read(); + DVector::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,¶ms); + + 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::Read fr=faces.read(); + DVector::Read vr=vertices.read(); + DVector::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,¶ms); + +} + +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.xaabb=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;iaabb=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 p_faces) { + + int src_face_count=p_faces.size(); + ERR_FAIL_COND(src_face_count%3); + src_face_count/=3; + + DVector::Read r = p_faces.read(); + const Vector3 * facesr= r.ptr(); + +#if 0 + Map point_map; + List face_list; + + + for(int i=0;i::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::Write vw = vertices.write(); + Vector3 *verticesw=vw.ptr(); + + AABB _aabb; + + for( Map::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::Write w = faces.write(); + Face *facesw=w.ptr(); + + int fc=0; + + for( List::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::Write(); + vw=DVector::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::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::Write w = faces.write(); + Face *facesw=w.ptr(); + + vertices.resize( src_face_count*3 ); + + DVector::Write vw = vertices.write(); + Vector3 *verticesw=vw.ptr(); + + AABB _aabb; + + + for(int i=0;i::Write(); + vw=DVector::Write(); + + int count=0; + _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count); + + bvh.resize( count+1 ); + + DVector::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 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 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::Read r = heights. read(); + + AABB aabb; + + for(int i=0;i 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; +} + + + diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index 69c82519dd..070bc5e062 100644 --- a/servers/physics_server.cpp +++ b/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); diff --git a/servers/physics_server.h b/servers/physics_server.h index da51dbc8e1..955caffe5b 100644 --- a/servers/physics_server.h +++ b/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; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 2b02a81a44..77d4da81d9 100644 --- a/servers/visual/rasterizer.h +++ b/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 morph_values; BakedLightData *baked_light; Transform *baked_light_octree_xform; + int baked_lightmap_id; bool mirror :8; bool depth_scale :8; bool billboard :8; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 16a725010d..489b5c3771 100644 --- a/servers/visual/shader_language.cpp +++ b/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}, diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 7c1f03b71b..66862ece65 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/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 *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 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; } diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 0368780bfb..2620225cc2 100644 --- a/servers/visual/visual_server_raster.h +++ b/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 p_octree); virtual DVector 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); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index d577ca0c59..f1ba4c453b 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -909,6 +909,8 @@ public: FUNC2(baked_light_set_octree,RID,DVector); FUNC1RC(DVector,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); diff --git a/servers/visual_server.h b/servers/visual_server.h index 9cad173903..7d7b10bed2 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -585,6 +585,9 @@ public: virtual void baked_light_set_octree(RID p_baked_light,const DVector p_octree)=0; virtual DVector 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; diff --git a/tools/editor/icons/icon_light_map.png b/tools/editor/icons/icon_light_map.png new file mode 100644 index 0000000000000000000000000000000000000000..96d3f6e11c8038ca9c112931fb899cdfdbde7d6f GIT binary patch literal 441 zcmV;q0Y?6bP)OZg$OVd~h!c|AWtBjwG znq+Mzu$){-?)GhVn3;EH_TAYPTB68H--e$M0qdJ<0*G}+fJE0_;0!ni_9`(^4iZBF z>x>k6Io(fy1K_HXdIDT(+*@ZT^3q39AV9}DGtuI|f&Ux0u+9K<7QTWaFMWf%4)Z0- z49wBQMAru(3zY$$-d;Y#oMuBfs|oAOsL0CVO zo`HK{M}3b#sj>LaFhp;oI|g2Xe&D_ZhRIU$uYoj>Pv(_Va1*^c8+F4yv8nd{5M&aIvYTs32i#4#osYBcV`)UvBlA?UYZTM-V;s0sK%UUadd_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 } - if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR) && p_node->cast_to()) { + if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR|SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS) && p_node->cast_to()) { MeshInstance *mi = p_node->cast_to(); @@ -1061,6 +1063,10 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map 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 col->set_name("col"); p_node->add_child(col); - - StaticBody *sb = col->cast_to(); + StaticBody *sb=col->cast_to(); 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()) { @@ -1892,8 +1898,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c Ref 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); diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.h b/tools/editor/io_plugins/editor_scene_import_plugin.h index 114233df80..3b39f0c962 100644 --- a/tools/editor/io_plugins/editor_scene_import_plugin.h +++ b/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, }; diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index c7593625ff..760651bbfd 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -725,6 +725,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Refget_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& } -void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform) { +void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform,int p_baked_texture) { for(int i=0;iget_surface_count();i++) { @@ -55,6 +55,7 @@ void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& p_m Ref 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& p_mesh,const Ref& p_m DVector::Read vr=vertices.read(); DVector uv; DVector::Read uvr; + DVector uv2; + DVector::Read uv2r; DVector normal; DVector::Read normalr; bool read_uv=false; @@ -122,6 +125,18 @@ void BakedLightBaker::_add_mesh(const Ref& p_mesh,const Ref& 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& p_mesh,const Ref& 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& p_mesh,const Ref& 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(); Ref 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()) { @@ -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 &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;iget_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;jget_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;ivertices[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 norm_arr; + norm_arr.resize(lights.size()); + + for(int i=0;iget_gamma_adjust(); + float mult = baked_light->get_energy_multiplier(); + + + const double *normptr=norm_arr.ptr(); + for(int i=0;i=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 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;x0) { + //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 = ©_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 = ©_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 dv; + dv.resize(baked_textures[i].data.size()); + { + DVector::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 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 norm_arr; + norm_arr.resize(lights.size()); + + for(int i=0;i 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 triangles; + Vector baked_textures; Transform base_inv; int leaf_list; int octree_depth; @@ -255,13 +266,14 @@ public: MeshTexture* _get_mat_tex(const Ref& p_tex); - void _add_mesh(const Ref& p_mesh,const Ref& p_mat_override,const Transform& p_xform); + void _add_mesh(const Ref& p_mesh,const Ref& 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 &p_image); Ref get_baked_light() { return baked_light; } diff --git a/tools/editor/plugins/baked_light_editor_plugin.cpp b/tools/editor/plugins/baked_light_editor_plugin.cpp index a1383f22fe..3d48f2e732 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.cpp +++ b/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; diff --git a/tools/editor/plugins/baked_light_editor_plugin.h b/tools/editor/plugins/baked_light_editor_plugin.h index 4ecc0b458f..7912bd92e5 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.h +++ b/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(); diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp index 73b6265819..17c4291378 100644 --- a/tools/editor/plugins/shader_editor_plugin.cpp +++ b/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() { diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp index 4d0ed3e1dd..e0202be84e 100644 --- a/tools/editor/scene_tree_editor.cpp +++ b/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(); + 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"); } diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py index 15ec77cf8f..ec907a998d 100644 --- a/tools/export/blender25/io_scene_dae/export_dae.py +++ b/tools/export/blender25/io_scene_dae/export_dae.py @@ -292,6 +292,9 @@ class DaeExporter: self.writel(S_FX,7,'') self.writel(S_FX,6,'') + self.writel(S_FX,5,'') + self.writel(S_FX,5,'') + self.writel(S_FX,6,''+["0","1"][double_sided_hint]+"") self.writel(S_FX,5,'') self.writel(S_FX,4,'') @@ -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,'') self.writel(S_LAMPS,3,'') - if (light.type=="POINT" or light.type=="HEMI"): + if (light.type=="POINT"): self.writel(S_LAMPS,4,'') self.writel(S_LAMPS,5,''+strarr(light.color)+'') att_by_distance = 2.0 / light.distance # convert to linear attenuation