diff options
56 files changed, 3941 insertions, 1755 deletions
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<const char*> enablers; - if (fragment_flags.use_color_interp) + if (fragment_flags.use_color_interp || vertex_flags.use_color_interp) enablers.push_back("#define ENABLE_COLOR_INTERP\n"); - if (fragment_flags.use_uv_interp) + if (fragment_flags.use_uv_interp || vertex_flags.use_uv_interp) enablers.push_back("#define ENABLE_UV_INTERP\n"); - if (fragment_flags.use_uv2_interp) + if (fragment_flags.use_uv2_interp || vertex_flags.use_uv2_interp) enablers.push_back("#define ENABLE_UV2_INTERP\n"); - if (fragment_flags.use_tangent_interp) + if (fragment_flags.use_tangent_interp || vertex_flags.use_tangent_interp) enablers.push_back("#define ENABLE_TANGENT_INTERP\n"); - if (fragment_flags.use_var1_interp) + if (fragment_flags.use_var1_interp || vertex_flags.use_var1_interp) enablers.push_back("#define ENABLE_VAR1_INTERP\n"); - if (fragment_flags.use_var2_interp) + if (fragment_flags.use_var2_interp || vertex_flags.use_var2_interp) enablers.push_back("#define ENABLE_VAR2_INTERP\n"); if (fragment_flags.uses_texscreen) { enablers.push_back("#define ENABLE_TEXSCREEN\n"); @@ -4444,6 +4512,7 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF,shadow_filter==SHADOW_FILTER_PCF5 || shadow_filter==SHADOW_FILTER_PCF13); material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF_HQ,shadow_filter==SHADOW_FILTER_PCF13); material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_ESM,shadow_filter==SHADOW_FILTER_ESM); + material_shader.set_conditional(MaterialShaderGLES2::USE_LIGHTMAP_ON_UV2,p_material->flags[VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2]); if (p_opaque_pass && p_material->depth_draw_mode==VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA && p_material->shader_cache && p_material->shader_cache->has_alpha) { @@ -4716,7 +4785,8 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) { } //print_line("shadow split: "+rtos(li->shadow_split)); - } else + } + material_shader.set_uniform(MaterialShaderGLES2::SHADOW_DARKENING,li->base->vars[VS::LIGHT_PARAM_SHADOW_DARKENING]); //matrix @@ -5545,6 +5615,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans const Skeleton *prev_skeleton =NULL; uint8_t prev_sort_flags=0xFF; const BakedLightData *prev_baked_light=NULL; + RID prev_baked_light_texture; Geometry::Type prev_geometry_type=Geometry::GEOMETRY_INVALID; @@ -5561,6 +5632,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans material_shader.set_conditional(MaterialShaderGLES2::LIGHT_USE_PSSM4,false); material_shader.set_conditional(MaterialShaderGLES2::SHADELESS,false); material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false); // material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,false); } @@ -5585,6 +5657,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans bool rebind=false; bool bind_baked_light_octree=false; + bool bind_baked_lightmap=false; bool additive=false; @@ -5704,7 +5777,7 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans } material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,false); -// material_shader.set_conditional(MaterialShaderGLES2::USE_AMBIENT_TEXTURE,false); + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false); if (!additive && baked_light) { @@ -5722,7 +5795,37 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans } } else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) { - //material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_TEXTURE,true); + + int lightmap_idx = e->instance->baked_lightmap_id; + + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false); + bind_baked_lightmap=false; + + + if (baked_light->lightmaps.has(lightmap_idx)) { + + + RID texid = baked_light->lightmaps[lightmap_idx]; + + if (prev_baked_light!=baked_light || texid!=prev_baked_light_texture) { + + + Texture *tex = texture_owner.get(texid); + if (tex) { + + glActiveTexture(GL_TEXTURE5); + glBindTexture(tex->target,tex->tex_id); //bind the texture + } + + prev_baked_light_texture=texid; + } + + if (texid.is_valid()) { + material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,true); + bind_baked_lightmap=true; + } + + } } } @@ -5793,6 +5896,14 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans } + if (bind_baked_lightmap && (baked_light!=prev_baked_light || rebind)) { + + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP, 5); + material_shader.set_uniform(MaterialShaderGLES2::AMBIENT_LIGHTMAP_MULTIPLIER, baked_light->lightmap_multiplier); + + } + + _set_cull(e->mirror,p_reverse_cull); @@ -8212,9 +8323,13 @@ void RasterizerGLES2::_update_framebuffer() { } -void RasterizerGLES2::set_base_framebuffer(GLuint p_id) { +void RasterizerGLES2::set_base_framebuffer(GLuint p_id, Vector2 p_size) { base_framebuffer=p_id; + + if (p_size.x != 0) { + window_size = p_size; + }; } #if 0 @@ -8753,8 +8868,15 @@ void RasterizerGLES2::set_use_framebuffers(bool p_use) { use_framebuffers=p_use; } +RasterizerGLES2* RasterizerGLES2::get_singleton() { + + return _singleton; +}; + RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,bool p_default_fragment_lighting,bool p_use_reload_hooks) { + _singleton = this; + keep_copies=p_keep_ram_copy; use_reload_hooks=p_use_reload_hooks; pack_arrays=p_compress_arrays; 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;i<p_class->variables.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 <command_line.length;w++){ Log.d("GODOT"," " + command_line[w]); } - } + }*/ GodotLib.initialize(this,io.needsReloadHooks(),command_line); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); @@ -418,12 +418,10 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } if (new_args.isEmpty()){ - Log.d("GODOT", "new_args is empty"); command_line=null; }else{ - Log.d("GODOT", "new_args is not empty"); + command_line = new_args.toArray(new String[new_args.size()]); - Log.d("GODOT", "command line is null? " + ( (command_line == null) ? "yes":"no")); } if (use_apk_expansion && main_pack_md5!=null && main_pack_key!=null) { //check that environment is ok! @@ -461,7 +459,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC } if (!pack_valid) { - Log.d("GODOT", "Tengo que bajarme el apk"); + Log.d("GODOT", "Pack Invalid, try re-downloading."); Intent notifierIntent = new Intent(this, this.getClass()); notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | @@ -472,7 +470,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC int startResult; try { - Log.d("GODOT", "INICIANDO DOWNLOAD SERVICE"); + Log.d("GODOT", "INITIALIZING DOWNLOAD"); startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired( getApplicationContext(), pendingIntent, diff --git a/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java index 88cf28798e..d68f029246 100644 --- a/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java +++ b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java @@ -32,9 +32,9 @@ abstract public class GenericConsumeTask extends AsyncTask<String, String, Strin @Override protected String doInBackground(String... params) { try { - Log.d("godot", "Requesting to consume an item with token ." + token); +// Log.d("godot", "Requesting to consume an item with token ." + token); int response = mService.consumePurchase(3, context.getPackageName(), token); - Log.d("godot", "consumePurchase response: " + response); +// Log.d("godot", "consumePurchase response: " + response); if(response == 0 || response == 8){ return null; } diff --git a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java index 24eec9f30b..4c31704cc8 100644 --- a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java +++ b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java @@ -28,19 +28,19 @@ abstract public class HandlePurchaseTask { public void handlePurchaseRequest(int resultCode, Intent data){ - Log.d("XXX", "Handling purchase response"); +// Log.d("XXX", "Handling purchase response"); // int responseCode = data.getIntExtra("RESPONSE_CODE", 0); PaymentsCache pc = new PaymentsCache(context); String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); - Log.d("XXX", "Purchase data:" + purchaseData); +// Log.d("XXX", "Purchase data:" + purchaseData); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); - Log.d("XXX", "Purchase signature:" + dataSignature); + //Log.d("XXX", "Purchase signature:" + dataSignature); if (resultCode == Activity.RESULT_OK) { try { - Log.d("SARLANGA", purchaseData); +// Log.d("SARLANGA", purchaseData); JSONObject jo = new JSONObject(purchaseData); @@ -58,7 +58,7 @@ abstract public class HandlePurchaseTask { error("Untrusted callback"); return; } - Log.d("XXX", "Este es el product ID:" + productId); +// Log.d("XXX", "Este es el product ID:" + productId); pc.setConsumableValue("ticket_signautre", productId, dataSignature); pc.setConsumableValue("ticket", productId, purchaseData); pc.setConsumableFlag("block", productId, true); diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java b/platform/android/java/src/com/android/godot/payments/PaymentsCache.java index 7337acc0b8..1de772bf28 100644 --- a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java +++ b/platform/android/java/src/com/android/godot/payments/PaymentsCache.java @@ -31,14 +31,14 @@ public class PaymentsCache { SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putString(sku, value); - Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); +// Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); editor.commit(); } public String getConsumableValue(String set, String sku){ SharedPreferences sharedPref = context.getSharedPreferences( "consumables_" + set, Context.MODE_PRIVATE); - Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); +// Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); return sharedPref.getString(sku, null); } diff --git a/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java index 2f590a4e68..c1a9c5d421 100644 --- a/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java +++ b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java @@ -28,13 +28,13 @@ abstract public class ReleaseAllConsumablesTask { public void consumeItAll(){ try{ - Log.d("godot", "consumeItall for " + context.getPackageName()); +// Log.d("godot", "consumeItall for " + context.getPackageName()); Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null); for (String key : bundle.keySet()) { Object value = bundle.get(key); - Log.d("godot", String.format("%s %s (%s)", key, - value.toString(), value.getClass().getName())); +// Log.d("godot", String.format("%s %s (%s)", key, +// value.toString(), value.getClass().getName())); } @@ -45,13 +45,13 @@ abstract public class ReleaseAllConsumablesTask { if (myPurchases == null || myPurchases.size() == 0){ - Log.d("godot", "No purchases!"); +// Log.d("godot", "No purchases!"); notRequired(); return; } - Log.d("godot", "# products to be consumed:" + myPurchases.size()); +// Log.d("godot", "# products to be consumed:" + myPurchases.size()); for (int i=0;i<myPurchases.size();i++) { @@ -61,7 +61,7 @@ abstract public class ReleaseAllConsumablesTask { String sku = inappPurchaseData.getString("productId"); String token = inappPurchaseData.getString("purchaseToken"); String signature = mySignatures.get(i); - Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); +// Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); new GenericConsumeTask(context, mService, sku, receipt,signature, token) { @Override diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp index f948095c62..ae8174c35a 100644 --- a/platform/android/java_glue.cpp +++ b/platform/android/java_glue.cpp @@ -1577,14 +1577,14 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env int count = env->GetArrayLength(params); Variant args[VARIANT_ARG_MAX]; - print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count)); +// print_line("Java->GD call: "+obj->get_type()+"::"+str_method+" argc "+itos(count)); for (int i=0; i<MIN(count,VARIANT_ARG_MAX); i++) { jobject obj = env->GetObjectArrayElement(params, i); if (obj) args[i] = _jobject_to_variant(env, obj); - print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type())); +// print_line("\targ"+itos(i)+": "+Variant::get_type_name(args[i].get_type())); }; 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<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end) { +Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end, bool p_optimize) { Polygon *begin_poly=NULL; @@ -332,24 +332,112 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector if (found_route) { - //use midpoints for now - Polygon *p=end_poly; Vector<Vector3> path; - path.push_back(end_point); - while(true) { - int prev = p->prev_edge; - int prev_n = (p->prev_edge+1)%p->edges.size(); - Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5; - path.push_back(point); - p = p->edges[prev].C; - if (p==begin_poly) - break; - } - path.push_back(begin_point); + if (p_optimize) { + //string pulling + + Polygon *apex_poly=end_poly; + Vector3 apex_point=end_point; + Vector3 portal_left=apex_point; + Vector3 portal_right=apex_point; + Polygon *left_poly=end_poly; + Polygon *right_poly=end_poly; + Polygon *p=end_poly; + path.push_back(end_point); + + while(p) { + + Vector3 left; + Vector3 right; + +#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) ) + + if (p==begin_poly) { + left=begin_point; + right=begin_point; + } else { + int prev = p->prev_edge; + int prev_n = (p->prev_edge+1)%p->edges.size(); + left = _get_vertex(p->edges[prev].point); + right = _get_vertex(p->edges[prev_n].point); + + if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){ + SWAP(left,right); + } + } + + bool skip=false; + + + if (CLOCK_TANGENT(apex_point,portal_left,left).dot(up) >= 0){ + //process + if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right).dot(up) > 0) { + left_poly=p; + portal_left=left; + } else { + + apex_point=portal_right; + p=right_poly; + left_poly=p; + portal_left=apex_point; + portal_right=apex_point; + path.push_back(apex_point); + skip=true; + } + } + + if (!skip && CLOCK_TANGENT(apex_point,portal_right,right).dot(up) <= 0){ + //process + if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left).dot(up) < 0) { + right_poly=p; + portal_right=right; + } else { + + apex_point=portal_left; + p=left_poly; + right_poly=p; + portal_right=apex_point; + portal_left=apex_point; + path.push_back(apex_point); + } + } + + if (p!=begin_poly) + p=p->edges[p->prev_edge].C; + else + p=NULL; + + } + if (path[path.size()-1]!=begin_point) + path.push_back(begin_point); - path.invert();; + path.invert(); + + + + + } else { + //midpoints + Polygon *p=end_poly; + + path.push_back(end_point); + while(true) { + int prev = p->prev_edge; + int prev_n = (p->prev_edge+1)%p->edges.size(); + Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5; + path.push_back(point); + p = p->edges[prev].C; + if (p==begin_poly) + break; + } + + path.push_back(begin_point); + + + path.invert();; + } return path; } @@ -475,17 +563,33 @@ Vector3 Navigation::get_closest_point_normal(const Vector3& p_point){ } +void Navigation::set_up_vector(const Vector3& p_up) { + + + up=p_up; +} + +Vector3 Navigation::get_up_vector() const{ + + return up; +} + + void Navigation::_bind_methods() { ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform"),&Navigation::navmesh_create); ObjectTypeDB::bind_method(_MD("navmesh_set_transform","id","xform"),&Navigation::navmesh_set_transform); ObjectTypeDB::bind_method(_MD("navmesh_remove","id"),&Navigation::navmesh_remove); - ObjectTypeDB::bind_method(_MD("get_simple_path","start","end"),&Navigation::get_simple_path); + ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation::get_simple_path,DEFVAL(true)); ObjectTypeDB::bind_method(_MD("get_closest_point_to_segment","start","end"),&Navigation::get_closest_point_to_segment); ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation::get_closest_point); ObjectTypeDB::bind_method(_MD("get_closest_point_normal","to_point"),&Navigation::get_closest_point_normal); + ObjectTypeDB::bind_method(_MD("set_up_vector","up"),&Navigation::set_up_vector); + ObjectTypeDB::bind_method(_MD("get_up_vector"),&Navigation::get_up_vector); + + ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"up_vector"),_SCS("set_up_vector"),_SCS("get_up_vector")); } Navigation::Navigation() { @@ -493,5 +597,7 @@ Navigation::Navigation() { ERR_FAIL_COND( sizeof(Point)!=8 ); cell_size=0.01; //one centimeter last_id=1; + up=Vector3(0,1,0); } + 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<int,NavMesh> navmesh_map; int last_id; + Vector3 up; + protected: static void _bind_methods(); public: + void set_up_vector(const Vector3& p_up); + Vector3 get_up_vector() const; + //API should be as dynamic as possible int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform); void navmesh_set_transform(int p_id, const Transform& p_xform); void navmesh_remove(int p_id); - Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end); + Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end,bool p_optimize=true); Vector3 get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to); Vector3 get_closest_point(const Vector3& p_point); Vector3 get_closest_point_normal(const Vector3& p_point); 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<Skeleton*>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + return bones[p_bone].pose_global; +} + RID Skeleton::get_skeleton() const { return skeleton; @@ -511,6 +519,8 @@ void Skeleton::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_bone_pose","bone_idx"),&Skeleton::get_bone_pose); ObjectTypeDB::bind_method(_MD("set_bone_pose","bone_idx","pose"),&Skeleton::set_bone_pose); + ObjectTypeDB::bind_method(_MD("get_bone_global_pose","bone_idx"),&Skeleton::get_bone_global_pose); + ObjectTypeDB::bind_method(_MD("get_bone_custom_pose","bone_idx"),&Skeleton::get_bone_custom_pose); ObjectTypeDB::bind_method(_MD("set_bone_custom_pose","bone_idx","custom_pose"),&Skeleton::set_bone_custom_pose); 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<Spatial*>::Element*E=data.children.front();E;E=E->next()) { + + Spatial *c=E->get(); + if (!c || !c->data.visible) + continue; + c->_propagate_visibility_changed(); + } +} + + +void Spatial::show() { + + if (data.visible) + return; + + data.visible=true; + + if (!is_inside_scene()) + return; + + if (!data.parent || is_visible()) { + + _propagate_visibility_changed(); + } +} + +void Spatial::hide(){ + + if (!data.visible) + return; + + bool was_visible = is_visible(); + data.visible=false; + + if (!data.parent || was_visible) { + + _propagate_visibility_changed(); + } + +} +bool Spatial::is_visible() const{ + + const Spatial *s=this; + + while(s) { + if (!s->data.visible) { + return false; + } + s=s->data.parent; + } + + return true; +} + + +bool Spatial::is_hidden() const{ + + return !data.visible; +} + +void Spatial::_set_visible_(bool p_visible) { + + if (p_visible) + show(); + else + hide(); +} + +bool Spatial::_is_visible_() const { + + return !is_hidden(); +} + + void Spatial::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_transform","local"), &Spatial::set_transform); @@ -537,9 +617,18 @@ void Spatial::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_gizmo","gizmo:SpatialGizmo"), &Spatial::set_gizmo); ObjectTypeDB::bind_method(_MD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo); + ObjectTypeDB::bind_method(_MD("show"), &Spatial::show); + ObjectTypeDB::bind_method(_MD("hide"), &Spatial::hide); + ObjectTypeDB::bind_method(_MD("is_visible"), &Spatial::is_visible); + ObjectTypeDB::bind_method(_MD("is_hidden"), &Spatial::is_hidden); + + ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_); + ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_); + BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED ); BIND_CONSTANT( NOTIFICATION_ENTER_WORLD ); BIND_CONSTANT( NOTIFICATION_EXIT_WORLD ); + BIND_CONSTANT( NOTIFICATION_VISIBILITY_CHANGED ); //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") ); ADD_PROPERTYNZ( PropertyInfo(Variant::TRANSFORM,"transform/local",PROPERTY_HINT_NONE,""), _SCS("set_transform"), _SCS("get_transform") ); @@ -547,8 +636,11 @@ void Spatial::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") ); //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") ); + ADD_SIGNAL( MethodInfo("visibility_changed" ) ); + } @@ -564,6 +656,7 @@ Spatial::Spatial() : xform_change(this) data.scale=Vector3(1,1,1); data.viewport=NULL; data.inside_world=false; + data.visible=true; #ifdef TOOLS_ENABLED data.gizmo_disabled=false; data.gizmo_dirty=false; 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<SpatialGizmo> gizmo; bool gizmo_disabled; @@ -109,6 +111,8 @@ class Spatial : public Node { void _set_rotation_deg(const Vector3& p_deg); Vector3 _get_rotation_deg() const; + void _propagate_visibility_changed(); + protected: @@ -118,7 +122,9 @@ protected: void _notification(int p_what); static void _bind_methods(); - + + void _set_visible_(bool p_visible); + bool _is_visible_() const; public: enum { @@ -126,6 +132,7 @@ public: NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, NOTIFICATION_ENTER_WORLD=41, NOTIFICATION_EXIT_WORLD=42, + NOTIFICATION_VISIBILITY_CHANGED=43, }; Spatial *get_parent_spatial() const; @@ -159,6 +166,11 @@ public: Transform get_relative_transform(const Node *p_parent) const; + void show(); + void hide(); + bool is_visible() const; + bool is_hidden() const; + #ifdef TOOLS_ENABLED void set_import_transform(const Transform& p_transform) ; Transform get_import_transform() const; 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<VehicleBody>(); + if (!cb) + return; + body=cb; + local_xform=get_transform(); + cb->wheels.push_back(this); + + m_chassisConnectionPointCS = get_transform().origin; + m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); + m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); + + } + if (p_what==NOTIFICATION_EXIT_SCENE) { + + if (!get_parent()) + return; + VehicleBody *cb = get_parent()->cast_to<VehicleBody>(); + if (!cb) + return; + cb->wheels.erase(this); + body=NULL; + } + +} + + +void VehicleWheel::_update(PhysicsDirectBodyState *s) { + + + + if (m_raycastInfo.m_isInContact) + + { + real_t project= m_raycastInfo.m_contactNormalWS.dot( m_raycastInfo.m_wheelDirectionWS ); + Vector3 chassis_velocity_at_contactPoint; + Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin; + + chassis_velocity_at_contactPoint = s->get_linear_velocity() + + (s->get_angular_velocity()).cross(relpos);// * mPos); + + real_t projVel = m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); + if ( project >= real_t(-0.1)) + { + m_suspensionRelativeVelocity = real_t(0.0); + m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1); + } + else + { + real_t inv = real_t(-1.) / project; + m_suspensionRelativeVelocity = projVel * inv; + m_clippedInvContactDotSuspension = inv; + } + + } + + else // Not in contact : position wheel in a nice (rest length) position + { + m_raycastInfo.m_suspensionLength = m_suspensionRestLength; + m_suspensionRelativeVelocity = real_t(0.0); + m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS; + m_clippedInvContactDotSuspension = real_t(1.0); + } +} + +void VehicleWheel::_bind_methods() { + + + +} + + +VehicleWheel::VehicleWheel() { + + + + m_steering = real_t(0.); + m_engineForce = real_t(0.); + m_rotation = real_t(0.); + m_deltaRotation = real_t(0.); + m_brake = real_t(0.); + m_rollInfluence = real_t(0.1); + + m_suspensionRestLength = 0.15; + m_wheelRadius = 0.5;//0.28; + m_suspensionStiffness = 5.88; + m_wheelsDampingCompression = 0.83; + m_wheelsDampingRelaxation = 0.88; + m_frictionSlip = 10.5; + m_bIsFrontWheel = false; + m_maxSuspensionTravelCm = 500; + m_maxSuspensionForce = 6000; + + m_suspensionRelativeVelocity=0; + m_clippedInvContactDotSuspension=1.0; + m_raycastInfo.m_isInContact=false; + + body=NULL; +} + + +void VehicleBody::_update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s) { + + wheel.m_raycastInfo.m_isInContact = false; + + Transform chassisTrans = s->get_transform(); + //if (interpolatedTransform && (getRigidBody()->getMotionState())) + //{ + // getRigidBody()->getMotionState()->getWorldTransform(chassisTrans); + //} + + wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform( wheel.m_chassisConnectionPointCS ); + wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform( wheel.m_wheelDirectionCS).normalized(); + wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform( wheel.m_wheelAxleCS ).normalized(); +} + +void VehicleBody::_update_wheel(int p_idx,PhysicsDirectBodyState *s) { + + VehicleWheel& wheel = *wheels[p_idx]; + _update_wheel_transform(wheel,s); + + Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS; + const Vector3& right = wheel.m_raycastInfo.m_wheelAxleWS; + Vector3 fwd = up.cross(right); + fwd = fwd.normalized(); +// up = right.cross(fwd); +// up.normalize(); + + //rotate around steering over de wheelAxleWS + real_t steering = wheel.m_steering; + + Matrix3 steeringMat(up,steering); + + Matrix3 rotatingMat(right,-wheel.m_rotation); + + Matrix3 basis2( + right[0],up[0],fwd[0], + right[1],up[1],fwd[1], + right[2],up[2],fwd[2] + ); + + wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2); + wheel.m_worldTransform.set_origin( + wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength + ); +} + + +real_t VehicleBody::_ray_cast(int p_idx,PhysicsDirectBodyState *s) { + + + VehicleWheel& wheel = *wheels[p_idx]; + + _update_wheel_transform(wheel,s); + + + real_t depth = -1; + + real_t raylen = wheel.m_suspensionRestLength+wheel.m_wheelRadius; + + Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen); + const Vector3& source = wheel.m_raycastInfo.m_hardPointWS; + wheel.m_raycastInfo.m_contactPointWS = source + rayvector; + const Vector3& target = wheel.m_raycastInfo.m_contactPointWS; + + real_t param = real_t(0.); + + + PhysicsDirectSpaceState::RayResult rr; + + + PhysicsDirectSpaceState *ss=s->get_space_state(); + + bool col = ss->intersect_ray(source,target,rr,exclude); + + + wheel.m_raycastInfo.m_groundObject = 0; + + if (col) + { + //print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target); + //print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col)); + param = source.distance_to(rr.position)/source.distance_to(target); + depth = raylen * param; + wheel.m_raycastInfo.m_contactNormalWS = rr.normal; + + wheel.m_raycastInfo.m_isInContact = true; + if (rr.collider) + wheel.m_raycastInfo.m_groundObject=rr.collider->cast_to<PhysicsBody>(); + + + real_t hitDistance = param*raylen; + wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius; + //clamp on max suspension travel + + real_t minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm*real_t(0.01); + real_t maxSuspensionLength = wheel.m_suspensionRestLength+ wheel.m_maxSuspensionTravelCm*real_t(0.01); + if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) + { + wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength; + } + if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) + { + wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength; + } + + wheel.m_raycastInfo.m_contactPointWS = rr.position; + + real_t denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS ); + + Vector3 chassis_velocity_at_contactPoint; + //Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition(); + + //chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos); + + chassis_velocity_at_contactPoint = s->get_linear_velocity() + + (s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS-s->get_transform().origin);// * mPos); + + + real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); + + if ( denominator >= real_t(-0.1)) + { + wheel.m_suspensionRelativeVelocity = real_t(0.0); + wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1); + } + else + { + real_t inv = real_t(-1.) / denominator; + wheel.m_suspensionRelativeVelocity = projVel * inv; + wheel.m_clippedInvContactDotSuspension = inv; + } + + } else + { + wheel.m_raycastInfo.m_isInContact = false; + //put wheel info as in rest position + wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength; + wheel.m_suspensionRelativeVelocity = real_t(0.0); + wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS; + wheel.m_clippedInvContactDotSuspension = real_t(1.0); + } + + return depth; +} + + +void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) +{ + + real_t deltaTime = s->get_step(); + real_t chassisMass = mass; + + for (int w_it=0; w_it<wheels.size(); w_it++) + { + VehicleWheel& wheel_info = *wheels[w_it]; + + + if ( wheel_info.m_raycastInfo.m_isInContact ) + { + real_t force; + // Spring + { + real_t susp_length = wheel_info.m_suspensionRestLength; + real_t current_length = wheel_info.m_raycastInfo.m_suspensionLength; + + real_t length_diff = (susp_length - current_length); + + force = wheel_info.m_suspensionStiffness + * length_diff * wheel_info.m_clippedInvContactDotSuspension; + } + + // Damper + { + real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity; + { + real_t susp_damping; + if ( projected_rel_vel < real_t(0.0) ) + { + susp_damping = wheel_info.m_wheelsDampingCompression; + } + else + { + susp_damping = wheel_info.m_wheelsDampingRelaxation; + } + force -= susp_damping * projected_rel_vel; + } + } + + // RESULT + wheel_info.m_wheelsSuspensionForce = force * chassisMass; + if (wheel_info.m_wheelsSuspensionForce < real_t(0.)) + { + wheel_info.m_wheelsSuspensionForce = real_t(0.); + } + } + else + { + wheel_info.m_wheelsSuspensionForce = real_t(0.0); + } + } + +} + + +//bilateral constraint between two dynamic objects +void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1, + PhysicsBody* body2, const Vector3& pos2, const Vector3& normal,real_t& impulse) +{ + + real_t normalLenSqr = normal.length_squared(); + //ERR_FAIL_COND( normalLenSqr < real_t(1.1)); + + if (normalLenSqr > real_t(1.1)) + { + impulse = real_t(0.); + return; + } + + Vector3 rel_pos1 = pos1 - s->get_transform().origin; + Vector3 rel_pos2; + if (body2) + rel_pos2 = pos2 - body2->get_global_transform().origin; + //this jacobian entry could be re-used for all iterations + + Vector3 vel1 = s->get_linear_velocity() + (s->get_angular_velocity()).cross(rel_pos1);// * mPos); + Vector3 vel2; + + if (body2) + vel2=body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2); + + Vector3 vel = vel1 - vel2; + + Matrix3 b2trans; + float b2invmass=0; + Vector3 b2lv; + Vector3 b2av; + Vector3 b2invinertia; //todo + + if (body2) { + b2trans = body2->get_global_transform().basis.transposed(); + b2invmass = body2->get_inverse_mass(); + b2lv = body2->get_linear_velocity(); + b2av = body2->get_angular_velocity(); + } + + + + btVehicleJacobianEntry jac(s->get_transform().basis.transposed(), + b2trans, + rel_pos1, + rel_pos2, + normal, + s->get_inverse_inertia(), + 1.0/mass, + b2invinertia, + b2invmass); + + real_t jacDiagAB = jac.getDiagonal(); + real_t jacDiagABInv = real_t(1.) / jacDiagAB; + + real_t rel_vel = jac.getRelativeVelocity( + s->get_linear_velocity(), + s->get_transform().basis.transposed().xform(s->get_angular_velocity()), + b2lv, + b2trans.xform(b2av)); + real_t a; + a=jacDiagABInv; + + + rel_vel = normal.dot(vel); + + //todo: move this into proper structure + real_t contactDamping = real_t(0.4); +#define ONLY_USE_LINEAR_MASS +#ifdef ONLY_USE_LINEAR_MASS + real_t massTerm = real_t(1.) / ((1.0/mass) + b2invmass); + impulse = - contactDamping * rel_vel * massTerm; +#else + real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv; + impulse = velocityImpulse; +#endif + +} + + + +VehicleBody::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse) + :m_s(s), + m_body1(body1), + m_frictionPositionWorld(frictionPosWorld), + m_frictionDirectionWorld(frictionDirectionWorld), + m_maxImpulse(maxImpulse) +{ + float denom0=0; + float denom1=0; + + { + Vector3 r0 = frictionPosWorld - s->get_transform().origin; + Vector3 c0 = (r0).cross(frictionDirectionWorld); + Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0); + denom0= s->get_inverse_mass() + frictionDirectionWorld.dot(vec); + } + + if (body1) { + + Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin; + Vector3 c0 = (r0).cross(frictionDirectionWorld); + Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0); + //denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec); + denom1=0; + + } + + + real_t relaxation = 1.f; + m_jacDiagABInv = relaxation/(denom0+denom1); +} + + +real_t VehicleBody::_calc_rolling_friction(btVehicleWheelContactPoint& contactPoint) { + + real_t j1=0.f; + + const Vector3& contactPosWorld = contactPoint.m_frictionPositionWorld; + + Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin; + Vector3 rel_pos2; + if (contactPoint.m_body1) + rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin; + + real_t maxImpulse = contactPoint.m_maxImpulse; + + Vector3 vel1 = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1);// * mPos); + + Vector3 vel2; + if (contactPoint.m_body1) { + vel2=contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2); + + } + + Vector3 vel = vel1 - vel2; + + real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel); + + // calculate j that moves us to zero relative velocity + j1 = -vrel * contactPoint.m_jacDiagABInv; + + return CLAMP(j1,-maxImpulse,maxImpulse); +} + + +static const real_t sideFrictionStiffness2 = real_t(1.0); +void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { + + //calculate the impulse, so that the wheels don't move sidewards + int numWheel = wheels.size(); + if (!numWheel) + return; + + m_forwardWS.resize(numWheel); + m_axle.resize(numWheel); + m_forwardImpulse.resize(numWheel); + m_sideImpulse.resize(numWheel); + + int numWheelsOnGround = 0; + + + //collapse all those loops into one! + for (int i=0;i<wheels.size();i++) + { + VehicleWheel& wheelInfo = *wheels[i]; + if (wheelInfo.m_raycastInfo.m_isInContact) + numWheelsOnGround++; + m_sideImpulse[i] = real_t(0.); + m_forwardImpulse[i] = real_t(0.); + + } + + { + + for (int i=0;i<wheels.size();i++) + { + + VehicleWheel& wheelInfo = *wheels[i]; + + + if (wheelInfo.m_raycastInfo.m_isInContact) + { + + //const btTransform& wheelTrans = getWheelTransformWS( i ); + + Matrix3 wheelBasis0 = wheelInfo.get_global_transform().basis; + m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X); + m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS; + + const Vector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS; + real_t proj = m_axle[i].dot(surfNormalWS); + m_axle[i] -= surfNormalWS * proj; + m_axle[i] = m_axle[i].normalized(); + + m_forwardWS[i] = surfNormalWS.cross(m_axle[i]); + m_forwardWS[i].normalize(); + + + _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS, + wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS, + m_axle[i],m_sideImpulse[i]); + + m_sideImpulse[i] *= sideFrictionStiffness2; + + + } + } + } + + real_t sideFactor = real_t(1.); + real_t fwdFactor = 0.5; + + bool sliding = false; + { + for (int wheel =0;wheel <wheels.size();wheel++) + { + VehicleWheel& wheelInfo = *wheels[wheel]; + + + //class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject; + + real_t rollingFriction = 0.f; + + if (wheelInfo.m_raycastInfo.m_isInContact) + { + if (wheelInfo.m_engineForce != 0.f) + { + rollingFriction = wheelInfo.m_engineForce* s->get_step(); + } else + { + real_t defaultRollingFrictionImpulse = 0.f; + real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse; + btVehicleWheelContactPoint contactPt(s,wheelInfo.m_raycastInfo.m_groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse); + rollingFriction = _calc_rolling_friction(contactPt); + } + } + + //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break) + + + + + m_forwardImpulse[wheel] = real_t(0.); + wheelInfo.m_skidInfo= real_t(1.); + + if (wheelInfo.m_raycastInfo.m_isInContact) + { + wheelInfo.m_skidInfo= real_t(1.); + + real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip; + real_t maximpSide = maximp; + + real_t maximpSquared = maximp * maximpSide; + + + m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep; + + real_t x = (m_forwardImpulse[wheel] ) * fwdFactor; + real_t y = (m_sideImpulse[wheel] ) * sideFactor; + + real_t impulseSquared = (x*x + y*y); + + if (impulseSquared > maximpSquared) + { + sliding = true; + + real_t factor = maximp / Math::sqrt(impulseSquared); + + wheelInfo.m_skidInfo *= factor; + } + } + + } + } + + + + + if (sliding) + { + for (int wheel = 0;wheel < wheels.size(); wheel++) + { + if (m_sideImpulse[wheel] != real_t(0.)) + { + if (wheels[wheel]->m_skidInfo< real_t(1.)) + { + m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo; + m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo; + } + } + } + } + + // apply the impulses + { + for (int wheel = 0;wheel<wheels.size(); wheel++) + { + VehicleWheel& wheelInfo = *wheels[wheel]; + + Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS - + s->get_transform().origin; + + if (m_forwardImpulse[wheel] != real_t(0.)) + { + s->apply_impulse(rel_pos,m_forwardWS[wheel]*(m_forwardImpulse[wheel])); + } + if (m_sideImpulse[wheel] != real_t(0.)) + { + PhysicsBody* groundObject = wheelInfo.m_raycastInfo.m_groundObject; + + Vector3 rel_pos2; + if (groundObject) { + rel_pos2=wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin; + } + + + Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; + +#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT. + Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1];//getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis); + rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence)); +#else + rel_pos[1] *= wheelInfo.m_rollInfluence; //? +#endif + s->apply_impulse(rel_pos,sideImp); + + //apply friction impulse on the ground + //todo + //groundObject->applyImpulse(-sideImp,rel_pos2); + } + } + } + + +} + + +void VehicleBody::_direct_state_changed(Object *p_state) { + + + PhysicsDirectBodyState *s = p_state->cast_to<PhysicsDirectBodyState>(); + + set_ignore_transform_notification(true); + set_global_transform(s->get_transform()); + set_ignore_transform_notification(false); + + + float step = s->get_step(); + + for(int i=0;i<wheels.size();i++) { + + _update_wheel(i,s); + } + + for(int i=0;i<wheels.size();i++) { + + _ray_cast(i,s); + } + + _update_suspension(s); + + for(int i=0;i<wheels.size();i++) { + + //apply suspension force + VehicleWheel& wheel = *wheels[i]; + + real_t suspensionForce = wheel.m_wheelsSuspensionForce; + + if (suspensionForce > wheel.m_maxSuspensionForce) + { + suspensionForce = wheel.m_maxSuspensionForce; + } + Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step; + Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin; + + s->apply_impulse(relpos,impulse); + //getRigidBody()->applyImpulse(impulse, relpos); + + } + + + _update_friction(s); + + + for (int i=0;i<wheels.size();i++) + { + VehicleWheel& wheel = *wheels[i]; + Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - s->get_transform().origin; + Vector3 vel = s->get_linear_velocity() + (s->get_angular_velocity()).cross(relpos);// * mPos); + + if (wheel.m_raycastInfo.m_isInContact) + { + const Transform& chassisWorldTransform = s->get_transform(); + + Vector3 fwd ( + chassisWorldTransform.basis[0][Vector3::AXIS_Z], + chassisWorldTransform.basis[1][Vector3::AXIS_Z], + chassisWorldTransform.basis[2][Vector3::AXIS_Z]); + + real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); + fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; + + real_t proj2 = fwd.dot(vel); + + wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius); + wheel.m_rotation += wheel.m_deltaRotation; + + } else + { + wheel.m_rotation += wheel.m_deltaRotation; + } + + wheel.m_deltaRotation *= real_t(0.99);//damping of rotation when not in contact + + } + +} + +void VehicleBody::set_mass(real_t p_mass) { + + mass=p_mass; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass); +} + +real_t VehicleBody::get_mass() const{ + + return mass; +} + + +void VehicleBody::set_friction(real_t p_friction) { + + friction=p_friction; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction); +} + +real_t VehicleBody::get_friction() const{ + + return friction; +} + +void VehicleBody::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_mass","mass"),&VehicleBody::set_mass); + ObjectTypeDB::bind_method(_MD("get_mass"),&VehicleBody::get_mass); + + ObjectTypeDB::bind_method(_MD("set_friction","friction"),&VehicleBody::set_friction); + ObjectTypeDB::bind_method(_MD("get_friction"),&VehicleBody::get_friction); + + ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&VehicleBody::_direct_state_changed); + + ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); + + +} + + + +VehicleBody::VehicleBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) { + + + m_pitchControl=0; + m_currentVehicleSpeedKmHour = real_t(0.); + m_steeringValue = real_t(0.); + + + mass=1; + friction=1; + + ccd=false; + + exclude.insert(get_rid()); + PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed"); + +} + 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<RID> exclude; + + Vector<Vector3> m_forwardWS; + Vector<Vector3> m_axle; + Vector<real_t> m_forwardImpulse; + Vector<real_t> m_sideImpulse; + + struct btVehicleWheelContactPoint { + PhysicsDirectBodyState *m_s; + PhysicsBody* m_body1; + Vector3 m_frictionPositionWorld; + Vector3 m_frictionDirectionWorld; + real_t m_jacDiagABInv; + real_t m_maxImpulse; + + + btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse); + }; + + void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1, PhysicsBody* body2, const Vector3& pos2, const Vector3& normal, real_t& impulse); + real_t _calc_rolling_friction(btVehicleWheelContactPoint& contactPoint); + + void _update_friction(PhysicsDirectBodyState *s); + void _update_suspension(PhysicsDirectBodyState *s); + real_t _ray_cast(int p_idx,PhysicsDirectBodyState *s); + void _update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s); + void _update_wheel(int p_idx,PhysicsDirectBodyState *s); + + + +friend class VehicleWheel; + Vector<VehicleWheel*> wheels; + + static void _bind_methods(); + + void _direct_state_changed(Object *p_state); +public: + + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_friction(real_t p_friction); + real_t get_friction() const; + + + VehicleBody(); +}; + +#endif // VEHICLE_BODY_H 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<RenderTargetTexture> 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<RigidBody>(); ObjectTypeDB::register_type<CarBody>(); ObjectTypeDB::register_type<CarWheel>(); + ObjectTypeDB::register_type<VehicleBody>(); + ObjectTypeDB::register_type<VehicleWheel>(); ObjectTypeDB::register_type<Area>(); ObjectTypeDB::register_type<ProximityGroup>(); ObjectTypeDB::register_type<CollisionShape>(); 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<Texture> tex = p_array[i+1]; - ERR_CONTINUE(tex.is_null()); +// ERR_CONTINUE(tex.is_null()); LightMap lm; lm.gen_size=size; lm.texture=tex; @@ -228,7 +229,7 @@ bool BakedLight::get_bake_flag(BakeFlags p_flags) const{ void BakedLight::set_format(Format p_format) { format=p_format; - + VS::get_singleton()->baked_light_set_lightmap_multiplier(baked_light,format==FORMAT_HDR8?8.0:1.0); } BakedLight::Format BakedLight::get_format() const{ @@ -236,6 +237,17 @@ BakedLight::Format BakedLight::get_format() const{ return format; } +void BakedLight::set_transfer_lightmaps_only_to_uv2(bool p_enable) { + + transfer_only_uv2=p_enable; +} + +bool BakedLight::get_transfer_lightmaps_only_to_uv2() const{ + + return transfer_only_uv2; +} + + bool BakedLight::_set(const StringName& p_name, const Variant& p_value) { String n = p_name; @@ -348,6 +360,11 @@ void BakedLight::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format); ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format); + ObjectTypeDB::bind_method(_MD("set_transfer_lightmaps_only_to_uv2","enable"),&BakedLight::set_transfer_lightmaps_only_to_uv2); + ObjectTypeDB::bind_method(_MD("get_transfer_lightmaps_only_to_uv2"),&BakedLight::get_transfer_lightmaps_only_to_uv2); + + + ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier); ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier); @@ -371,6 +388,7 @@ void BakedLight::_bind_methods(){ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2")); ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree")); ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data")); @@ -403,6 +421,7 @@ BakedLight::BakedLight() { edge_damp=0.0; normal_damp=0.0; format=FORMAT_RGB; + transfer_only_uv2=false; flags[BAKE_DIFFUSE]=true; flags[BAKE_SPECULAR]=false; 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<ShapeOwnerSW*,int>::Element *E=owners.front();E;E=E->next()) {
- ShapeOwnerSW* co=(ShapeOwnerSW*)E->key();
- co->_shape_changed();
- }
-}
-
-
-Vector3 ShapeSW::get_support(const Vector3& p_normal) const {
-
- Vector3 res;
- int amnt;
- get_supports(p_normal,1,&res,amnt);
- return res;
-}
-
-void ShapeSW::add_owner(ShapeOwnerSW *p_owner) {
-
- Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
- if (E) {
- E->get()++;
- } else {
- owners[p_owner]=1;
- }
-}
-
-void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){
-
- Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner);
- ERR_FAIL_COND(!E);
- E->get()--;
- if (E->get()==0) {
- owners.erase(E);
- }
-
-}
-
-bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const{
-
- return owners.has(p_owner);
-
-}
-
-const Map<ShapeOwnerSW*,int>& ShapeSW::get_owners() const{
- return owners;
-}
-
-
-ShapeSW::ShapeSW() {
-
- custom_bias=0;
- configured=false;
-}
-
-
-ShapeSW::~ShapeSW() {
-
- ERR_FAIL_COND(owners.size());
-}
-
-
-
-Plane PlaneShapeSW::get_plane() const {
-
- return plane;
-}
-
-void PlaneShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- // gibberish, a plane is infinity
- r_min=-1e7;
- r_max=1e7;
-}
-
-Vector3 PlaneShapeSW::get_support(const Vector3& p_normal) const {
-
- return p_normal*1e15;
-}
-
-
-bool PlaneShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- bool inters=plane.intersects_segment(p_begin,p_end,&r_result);
- if(inters)
- r_normal=plane.normal;
- return inters;
-}
-
-Vector3 PlaneShapeSW::get_moment_of_inertia(float p_mass) const {
-
- return Vector3(); //wtf
-}
-
-void PlaneShapeSW::_setup(const Plane& p_plane) {
-
- plane=p_plane;
- configure(AABB(Vector3(-1e4,-1e4,-1e4),Vector3(1e4*2,1e4*2,1e4*2)));
-}
-
-void PlaneShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-
-}
-
-Variant PlaneShapeSW::get_data() const {
-
- return plane;
-}
-
-PlaneShapeSW::PlaneShapeSW() {
-
-
-}
-
-//
-
-float RayShapeSW::get_length() const {
-
- return length;
-}
-
-void RayShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- // don't think this will be even used
- r_min=0;
- r_max=1;
-}
-
-Vector3 RayShapeSW::get_support(const Vector3& p_normal) const {
-
- if (p_normal.z>0)
- return Vector3(0,0,length);
- else
- return Vector3(0,0,0);
-}
-
-void RayShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount=2;
- r_supports[0]=Vector3(0,0,0);
- r_supports[1]=Vector3(0,0,length);
- } if (p_normal.z>0) {
- r_amount=1;
- *r_supports=Vector3(0,0,length);
- } else {
- r_amount=1;
- *r_supports=Vector3(0,0,0);
- }
-}
-
-
-bool RayShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- return false; //simply not possible
-}
-
-Vector3 RayShapeSW::get_moment_of_inertia(float p_mass) const {
-
- return Vector3();
-}
-
-void RayShapeSW::_setup(float p_length) {
-
- length=p_length;
- configure(AABB(Vector3(0,0,0),Vector3(0.1,0.1,length)));
-}
-
-void RayShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-
-}
-
-Variant RayShapeSW::get_data() const {
-
- return length;
-}
-
-RayShapeSW::RayShapeSW() {
-
- length=1;
-}
-
-
-
-/********** SPHERE *************/
-
-real_t SphereShapeSW::get_radius() const {
-
- return radius;
-}
-
-void SphereShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- float d = p_normal.dot( p_transform.origin );
-
- // figure out scale at point
- Vector3 local_normal = p_transform.basis.xform_inv(p_normal);
- float scale = local_normal.length();
-
- r_min = d - (radius) * scale;
- r_max = d + (radius) * scale;
-
-}
-
-Vector3 SphereShapeSW::get_support(const Vector3& p_normal) const {
-
- return p_normal*radius;
-}
-
-void SphereShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- *r_supports=p_normal*radius;
- r_amount=1;
-}
-
-bool SphereShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- return Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(),radius,&r_result,&r_normal);
-}
-
-Vector3 SphereShapeSW::get_moment_of_inertia(float p_mass) const {
-
- float s = 0.4 * p_mass * radius * radius;
- return Vector3(s,s,s);
-}
-
-void SphereShapeSW::_setup(real_t p_radius) {
-
-
- radius=p_radius;
- configure(AABB( Vector3(-radius,-radius,-radius), Vector3(radius*2.0,radius*2.0,radius*2.0)));
-
-}
-
-void SphereShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-}
-
-Variant SphereShapeSW::get_data() const {
-
- return radius;
-}
-
-SphereShapeSW::SphereShapeSW() {
-
- radius=0;
-}
-
-
-/********** BOX *************/
-
-
-void BoxShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- // no matter the angle, the box is mirrored anyway
- Vector3 local_normal=p_transform.basis.xform_inv(p_normal);
-
- float length = local_normal.abs().dot(half_extents);
- float distance = p_normal.dot( p_transform.origin );
-
- r_min = distance - length;
- r_max = distance + length;
-
-
-}
-
-Vector3 BoxShapeSW::get_support(const Vector3& p_normal) const {
-
-
- Vector3 point(
- (p_normal.x<0) ? -half_extents.x : half_extents.x,
- (p_normal.y<0) ? -half_extents.y : half_extents.y,
- (p_normal.z<0) ? -half_extents.z : half_extents.z
- );
-
- return point;
-}
-
-void BoxShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- static const int next[3]={1,2,0};
- static const int next2[3]={2,0,1};
-
- for (int i=0;i<3;i++) {
-
- Vector3 axis;
- axis[i]=1.0;
- float dot = p_normal.dot( axis );
- if ( Math::abs( dot ) > _FACE_IS_VALID_SUPPORT_TRESHOLD ) {
-
- //Vector3 axis_b;
-
- bool neg = dot<0;
- r_amount = 4;
-
- Vector3 point;
- point[i]=half_extents[i];
-
- int i_n=next[i];
- int i_n2=next2[i];
-
- static const float sign[4][2]={
-
- {-1.0, 1.0},
- { 1.0, 1.0},
- { 1.0,-1.0},
- {-1.0,-1.0},
- };
-
- for (int j=0;j<4;j++) {
-
- point[i_n]=sign[j][0]*half_extents[i_n];
- point[i_n2]=sign[j][1]*half_extents[i_n2];
- r_supports[j]=neg?-point:point;
-
- }
-
- if (neg) {
- SWAP( r_supports[1], r_supports[2] );
- SWAP( r_supports[0], r_supports[3] );
- }
-
- return;
- }
-
- r_amount=0;
-
- }
-
- for (int i=0;i<3;i++) {
-
- Vector3 axis;
- axis[i]=1.0;
-
- if (Math::abs(p_normal.dot(axis))<_EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount= 2;
-
- int i_n=next[i];
- int i_n2=next2[i];
-
- Vector3 point=half_extents;
-
- if (p_normal[i_n]<0) {
- point[i_n]=-point[i_n];
- }
- if (p_normal[i_n2]<0) {
- point[i_n2]=-point[i_n2];
- }
-
- r_supports[0] = point;
- point[i]=-point[i];
- r_supports[1] = point;
- return;
- }
- }
- /* USE POINT */
-
- Vector3 point(
- (p_normal.x<0) ? -half_extents.x : half_extents.x,
- (p_normal.y<0) ? -half_extents.y : half_extents.y,
- (p_normal.z<0) ? -half_extents.z : half_extents.z
- );
-
- r_amount=1;
- r_supports[0]=point;
-}
-
-bool BoxShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- AABB aabb(-half_extents,half_extents*2.0);
-
- return aabb.intersects_segment(p_begin,p_end,&r_result,&r_normal);
-
-}
-
-Vector3 BoxShapeSW::get_moment_of_inertia(float p_mass) const {
-
- float lx=half_extents.x;
- float ly=half_extents.y;
- float lz=half_extents.z;
-
- return Vector3( (p_mass/3.0) * (ly*ly + lz*lz), (p_mass/3.0) * (lx*lx + lz*lz), (p_mass/3.0) * (lx*lx + ly*ly) );
-
-}
-
-void BoxShapeSW::_setup(const Vector3& p_half_extents) {
-
- half_extents=p_half_extents.abs();
-
- configure(AABB(-half_extents,half_extents*2));
-
-
-}
-
-void BoxShapeSW::set_data(const Variant& p_data) {
-
-
- _setup(p_data);
-}
-
-Variant BoxShapeSW::get_data() const {
-
- return half_extents;
-}
-
-BoxShapeSW::BoxShapeSW() {
-
-
-}
-
-
-/********** CAPSULE *************/
-
-
-void CapsuleShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- Vector3 n=p_transform.basis.xform_inv(p_normal).normalized();
- float h = (n.z > 0) ? height : -height;
-
- n *= radius;
- n.z += h * 0.5;
-
- r_max=p_normal.dot(p_transform.xform(n));
- r_min=p_normal.dot(p_transform.xform(-n));
- return;
-
- n = p_transform.basis.xform(n);
-
- float distance = p_normal.dot( p_transform.origin );
- float length = Math::abs(p_normal.dot(n));
- r_min = distance - length;
- r_max = distance + length;
-
- ERR_FAIL_COND( r_max < r_min );
-
-}
-
-Vector3 CapsuleShapeSW::get_support(const Vector3& p_normal) const {
-
- Vector3 n=p_normal;
-
- float h = (n.z > 0) ? height : -height;
-
- n*=radius;
- n.z += h*0.5;
- return n;
-}
-
-void CapsuleShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
-
- Vector3 n=p_normal;
-
- float d = n.z;
-
- if (Math::abs( d )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
-
- // make it flat
- n.z=0.0;
- n.normalize();
- n*=radius;
-
- r_amount=2;
- r_supports[0]=n;
- r_supports[0].z+=height*0.5;
- r_supports[1]=n;
- r_supports[1].z-=height*0.5;
-
- } else {
-
- float h = (d > 0) ? height : -height;
-
- n*=radius;
- n.z += h*0.5;
- r_amount=1;
- *r_supports=n;
-
- }
-
-}
-
-
-bool CapsuleShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- Vector3 norm=(p_end-p_begin).normalized();
- float min_d=1e20;
-
-
- Vector3 res,n;
- bool collision=false;
-
- Vector3 auxres,auxn;
- bool collided;
-
- // test against cylinder and spheres :-|
-
- collided = Geometry::segment_intersects_cylinder(p_begin,p_end,height,radius,&auxres,&auxn);
-
- if (collided) {
- float d=norm.dot(auxres);
- if (d<min_d) {
- min_d=d;
- res=auxres;
- n=auxn;
- collision=true;
- }
- }
-
- collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*0.5),radius,&auxres,&auxn);
-
- if (collided) {
- float d=norm.dot(auxres);
- if (d<min_d) {
- min_d=d;
- res=auxres;
- n=auxn;
- collision=true;
- }
- }
-
- collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*-0.5),radius,&auxres,&auxn);
-
- if (collided) {
- float d=norm.dot(auxres);
-
- if (d<min_d) {
- min_d=d;
- res=auxres;
- n=auxn;
- collision=true;
- }
- }
-
- if (collision) {
-
- r_result=res;
- r_normal=n;
- }
- return collision;
-}
-
-Vector3 CapsuleShapeSW::get_moment_of_inertia(float p_mass) const {
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-
-}
-
-
-
-
-void CapsuleShapeSW::_setup(real_t p_height,real_t p_radius) {
-
- height=p_height;
- radius=p_radius;
- configure(AABB(Vector3(-radius,-radius,-height*0.5-radius),Vector3(radius*2,radius*2,height+radius*2.0)));
-
-}
-
-void CapsuleShapeSW::set_data(const Variant& p_data) {
-
- Dictionary d = p_data;
- ERR_FAIL_COND(!d.has("radius"));
- ERR_FAIL_COND(!d.has("height"));
- _setup(d["height"],d["radius"]);
-
-}
-
-Variant CapsuleShapeSW::get_data() const {
-
- Dictionary d;
- d["radius"]=radius;
- d["height"]=height;
- return d;
-
-}
-
-
-CapsuleShapeSW::CapsuleShapeSW() {
-
- height=radius=0;
-
-}
-
-/********** CONVEX POLYGON *************/
-
-
-void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
-
- int vertex_count=mesh.vertices.size();
- if (vertex_count==0)
- return;
-
- const Vector3 *vrts=&mesh.vertices[0];
-
- for (int i=0;i<vertex_count;i++) {
-
- float d=p_normal.dot( p_transform.xform( vrts[i] ) );
-
- if (i==0 || d > r_max)
- r_max=d;
- if (i==0 || d < r_min)
- r_min=d;
- }
-}
-
-Vector3 ConvexPolygonShapeSW::get_support(const Vector3& p_normal) const {
-
- Vector3 n=p_normal;
-
- int vert_support_idx=-1;
- float support_max;
-
- int vertex_count=mesh.vertices.size();
- if (vertex_count==0)
- return Vector3();
-
- const Vector3 *vrts=&mesh.vertices[0];
-
- for (int i=0;i<vertex_count;i++) {
-
- float d=n.dot(vrts[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
- return vrts[vert_support_idx];
-
-}
-
-
-
-void ConvexPolygonShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- const Geometry::MeshData::Edge *edges = mesh.edges.ptr();
- int ec = mesh.edges.size();
-
- const Vector3 *vertices = mesh.vertices.ptr();
- int vc = mesh.vertices.size();
-
- //find vertex first
- real_t max;
- int vtx;
-
- for (int i=0;i<vc;i++) {
-
- float d=p_normal.dot(vertices[i]);
-
- if (i==0 || d > max) {
- max=d;
- vtx=i;
- }
- }
-
-
- for(int i=0;i<fc;i++) {
-
- if (faces[i].plane.normal.dot(p_normal)>_FACE_IS_VALID_SUPPORT_TRESHOLD) {
-
- int ic = faces[i].indices.size();
- const int *ind=faces[i].indices.ptr();
-
- bool valid=false;
- for(int j=0;j<ic;j++) {
- if (ind[j]==vtx) {
- valid=true;
- break;
- }
- }
-
- if (!valid)
- continue;
-
- int m = MIN(p_max,ic);
- for(int j=0;j<m;j++) {
-
- r_supports[j]=vertices[ind[j]];
- }
- r_amount=m;
- return;
- }
- }
-
- for(int i=0;i<ec;i++) {
-
-
- float dot=(vertices[edges[i].a]-vertices[edges[i].b]).normalized().dot(p_normal);
- dot=ABS(dot);
- if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD && (edges[i].a==vtx || edges[i].b==vtx)) {
-
- r_amount=2;
- r_supports[0]=vertices[edges[i].a];
- r_supports[1]=vertices[edges[i].b];
- return;
- }
- }
-
-
- r_supports[0]=vertices[vtx];
- r_amount=1;
-}
-
-bool ConvexPolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-
-
- const Geometry::MeshData::Face *faces = mesh.faces.ptr();
- int fc = mesh.faces.size();
-
- const Vector3 *vertices = mesh.vertices.ptr();
- int vc = mesh.vertices.size();
-
- Vector3 n = p_end-p_begin;
- float min = 1e20;
- bool col=false;
-
- for(int i=0;i<fc;i++) {
-
- if (faces[i].plane.normal.dot(n) > 0)
- continue; //opposing face
-
- int ic = faces[i].indices.size();
- const int *ind=faces[i].indices.ptr();
-
- for(int j=1;j<ic-1;j++) {
-
- Face3 f(vertices[ind[0]],vertices[ind[i]],vertices[ind[i+1]]);
- Vector3 result;
- if (f.intersects_segment(p_begin,p_end,&result)) {
- float d = n.dot(result);
- if (d<min) {
- min=d;
- r_result=result;
- r_normal=faces[i].plane.normal;
- col=true;
- }
-
- break;
- }
-
- }
- }
-
- return col;
-
-}
-
-Vector3 ConvexPolygonShapeSW::get_moment_of_inertia(float p_mass) const {
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-
-}
-
-void ConvexPolygonShapeSW::_setup(const Vector<Vector3>& p_vertices) {
-
- Error err = QuickHull::build(p_vertices,mesh);
- AABB _aabb;
-
- for(int i=0;i<mesh.vertices.size();i++) {
-
- if (i==0)
- _aabb.pos=mesh.vertices[i];
- else
- _aabb.expand_to(mesh.vertices[i]);
- }
-
- configure(_aabb);
-
-
-}
-
-void ConvexPolygonShapeSW::set_data(const Variant& p_data) {
-
- _setup(p_data);
-
-}
-
-Variant ConvexPolygonShapeSW::get_data() const {
-
- return mesh.vertices;
-}
-
-
-ConvexPolygonShapeSW::ConvexPolygonShapeSW() {
-
-
-}
-
-
-/********** FACE POLYGON *************/
-
-
-void FaceShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- for (int i=0;i<3;i++) {
-
- Vector3 v=p_transform.xform(vertex[i]);
- float d=p_normal.dot(v);
-
- if (i==0 || d > r_max)
- r_max=d;
-
- if (i==0 || d < r_min)
- r_min=d;
- }
-}
-
-Vector3 FaceShapeSW::get_support(const Vector3& p_normal) const {
-
-
- Vector3 n=p_normal;
-
- int vert_support_idx=-1;
- float support_max;
-
- for (int i=0;i<3;i++) {
-
- //float d=n.dot(vertex[i]);
- float d=p_normal.dot(vertex[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
- return vertex[vert_support_idx];
-}
-
-void FaceShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const {
-
- Vector3 n=p_normal;
-
- /** TEST FACE AS SUPPORT **/
- if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount=3;
- for (int i=0;i<3;i++) {
-
- r_supports[i]=vertex[i];
- }
- return;
-
- }
-
- /** FIND SUPPORT VERTEX **/
-
- int vert_support_idx=-1;
- float support_max;
-
- for (int i=0;i<3;i++) {
-
- float d=n.dot(vertex[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
- /** TEST EDGES AS SUPPORT **/
-
- for (int i=0;i<3;i++) {
-
- int nx=(i+1)%3;
- //if (i!=vert_support_idx && nx!=vert_support_idx)
- // continue;
-
- // check if edge is valid as a support
- float dot=(vertex[i]-vertex[nx]).normalized().dot(n);
- dot=ABS(dot);
- if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) {
-
- r_amount=2;
- r_supports[0]=vertex[i];
- r_supports[1]=vertex[nx];
- return;
- }
- }
-
- r_amount=1;
- r_supports[0]=vertex[vert_support_idx];
-}
-
-bool FaceShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
-
- bool c=Geometry::segment_intersects_triangle(p_begin,p_end,vertex[0],vertex[1],vertex[2],&r_result);
- if (c)
- r_normal=Plane(vertex[0],vertex[1],vertex[2]).normal;
-
- return c;
-}
-
-Vector3 FaceShapeSW::get_moment_of_inertia(float p_mass) const {
-
- return Vector3(); // Sorry, but i don't think anyone cares, FaceShape!
-
-}
-
-FaceShapeSW::FaceShapeSW() {
-
- configure(AABB());
-
-}
-
-
-
-DVector<Vector3> ConcavePolygonShapeSW::get_faces() const {
-
-
- DVector<Vector3> rfaces;
- rfaces.resize(faces.size()*3);
-
- for(int i=0;i<faces.size();i++) {
-
- Face f=faces.get(i);
-
- for(int j=0;j<3;j++) {
-
- rfaces.set(i*3+j, vertices.get( f.indices[j] ) );
- }
- }
-
- return rfaces;
-}
-
-void ConcavePolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- int count=vertices.size();
- DVector<Vector3>::Read r=vertices.read();
- const Vector3 *vptr=r.ptr();
-
- for (int i=0;i<count;i++) {
-
- float d=p_normal.dot( p_transform.xform( vptr[i] ) );
-
- if (i==0 || d > r_max)
- r_max=d;
- if (i==0 || d < r_min)
- r_min=d;
-
- }
-}
-
-Vector3 ConcavePolygonShapeSW::get_support(const Vector3& p_normal) const {
-
-
- int count=vertices.size();
- DVector<Vector3>::Read r=vertices.read();
- const Vector3 *vptr=r.ptr();
-
- Vector3 n=p_normal;
-
- int vert_support_idx=-1;
- float support_max;
-
- for (int i=0;i<count;i++) {
-
- float d=n.dot(vptr[i]);
-
- if (i==0 || d > support_max) {
- support_max=d;
- vert_support_idx=i;
- }
- }
-
-
- return vptr[vert_support_idx];
-
-}
-
-void ConcavePolygonShapeSW::_cull_segment(int p_idx,_SegmentCullParams *p_params) const {
-
- const BVH *bvh=&p_params->bvh[p_idx];
-
-
- //if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d)
- // return; //test against whole AABB, which isn't very costly
-
-
- //printf("addr: %p\n",bvh);
- if (!bvh->aabb.intersects_segment(p_params->from,p_params->to)) {
-
- return;
- }
-
-
- if (bvh->face_index>=0) {
-
-
- Vector3 res;
- Vector3 vertices[3]={
- p_params->vertices[ p_params->faces[ bvh->face_index ].indices[0] ],
- p_params->vertices[ p_params->faces[ bvh->face_index ].indices[1] ],
- p_params->vertices[ p_params->faces[ bvh->face_index ].indices[2] ]
- };
-
- if (Geometry::segment_intersects_triangle(
- p_params->from,
- p_params->to,
- vertices[0],
- vertices[1],
- vertices[2],
- &res)) {
-
-
- float d=p_params->normal.dot(res) - p_params->normal.dot(p_params->from);
- //TODO, seems segmen/triangle intersection is broken :(
- if (d>0 && d<p_params->min_d) {
-
- p_params->min_d=d;
- p_params->result=res;
- p_params->normal=Plane(vertices[0],vertices[1],vertices[2]).normal;
- p_params->collisions++;
- }
-
- }
-
-
-
- } else {
-
- if (bvh->left>=0)
- _cull_segment(bvh->left,p_params);
- if (bvh->right>=0)
- _cull_segment(bvh->right,p_params);
-
-
- }
-}
-
-bool ConcavePolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const {
-
- // unlock data
- DVector<Face>::Read fr=faces.read();
- DVector<Vector3>::Read vr=vertices.read();
- DVector<BVH>::Read br=bvh.read();
-
-
- _SegmentCullParams params;
- params.from=p_begin;
- params.to=p_end;
- params.collisions=0;
- params.normal=(p_end-p_begin).normalized();
-
- params.faces=fr.ptr();
- params.vertices=vr.ptr();
- params.bvh=br.ptr();
-
- params.min_d=1e20;
- // cull
- _cull_segment(0,¶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<Face>::Read fr=faces.read();
- DVector<Vector3>::Read vr=vertices.read();
- DVector<BVH>::Read br=bvh.read();
-
- FaceShapeSW face; // use this to send in the callback
-
- _CullParams params;
- params.aabb=local_aabb;
- params.face=&face;
- params.faces=fr.ptr();
- params.vertices=vr.ptr();
- params.bvh=br.ptr();
- params.callback=p_callback;
- params.userdata=p_userdata;
-
- // cull
- _cull(0,¶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.x<b.center.x;
- }
-};
-
-
-struct _VolumeSW_BVH_CompareY {
-
- _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
- return a.center.y<b.center.y;
- }
-};
-
-struct _VolumeSW_BVH_CompareZ {
-
- _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const {
-
- return a.center.z<b.center.z;
- }
-};
-
-struct _VolumeSW_BVH {
-
- AABB aabb;
- _VolumeSW_BVH *left;
- _VolumeSW_BVH *right;
-
- int face_index;
-};
-
-
-_VolumeSW_BVH* _volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements,int p_size,int &count) {
-
- _VolumeSW_BVH* bvh = memnew( _VolumeSW_BVH );
-
- if (p_size==1) {
- //leaf
- bvh->aabb=p_elements[0].aabb;
- bvh->left=NULL;
- bvh->right=NULL;
- bvh->face_index=p_elements->face_index;
- count++;
- return bvh;
- } else {
-
- bvh->face_index=-1;
- }
-
- AABB aabb;
- for(int i=0;i<p_size;i++) {
-
- if (i==0)
- aabb=p_elements[i].aabb;
- else
- aabb.merge_with(p_elements[i].aabb);
- }
- bvh->aabb=aabb;
- switch(aabb.get_longest_axis_index()) {
-
- case 0: {
-
- SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareX> sort_x;
- sort_x.sort(p_elements,p_size);
-
- } break;
- case 1: {
-
- SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareY> sort_y;
- sort_y.sort(p_elements,p_size);
- } break;
- case 2: {
-
- SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareZ> sort_z;
- sort_z.sort(p_elements,p_size);
- } break;
- }
-
- int split=p_size/2;
- bvh->left=_volume_sw_build_bvh(p_elements,split,count);
- bvh->right=_volume_sw_build_bvh(&p_elements[split],p_size-split,count);
-
-// printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index);
- count++;
- return bvh;
-}
-
-
-void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx) {
-
- int idx=p_idx;
-
-
- p_bvh_array[idx].aabb=p_bvh_tree->aabb;
- p_bvh_array[idx].face_index=p_bvh_tree->face_index;
-// printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right);
-
-
- if (p_bvh_tree->left) {
- p_bvh_array[idx].left=++p_idx;
- _fill_bvh(p_bvh_tree->left,p_bvh_array,p_idx);
-
- } else {
-
- p_bvh_array[p_idx].left=-1;
- }
-
- if (p_bvh_tree->right) {
- p_bvh_array[idx].right=++p_idx;
- _fill_bvh(p_bvh_tree->right,p_bvh_array,p_idx);
-
- } else {
-
- p_bvh_array[p_idx].right=-1;
- }
-
- memdelete(p_bvh_tree);
-
-}
-
-void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) {
-
- int src_face_count=p_faces.size();
- ERR_FAIL_COND(src_face_count%3);
- src_face_count/=3;
-
- DVector<Vector3>::Read r = p_faces.read();
- const Vector3 * facesr= r.ptr();
-
-#if 0
- Map<Vector3,int> point_map;
- List<Face> face_list;
-
-
- for(int i=0;i<src_face_count;i++) {
-
- Face3 faceaux;
-
- for(int j=0;j<3;j++) {
-
- faceaux.vertex[j]=facesr[i*3+j].snapped(_POINT_SNAP);
- //faceaux.vertex[j]=facesr[i*3+j];//facesr[i*3+j].snapped(_POINT_SNAP);
- }
-
- ERR_CONTINUE( faceaux.is_degenerate() );
-
- Face face;
-
- for(int j=0;j<3;j++) {
-
-
- Map<Vector3,int>::Element *E=point_map.find(faceaux.vertex[j]);
- if (E) {
-
- face.indices[j]=E->value();
- } else {
-
- face.indices[j]=point_map.size();
- point_map.insert(faceaux.vertex[j],point_map.size());
-
- }
- }
-
- face_list.push_back(face);
- }
-
- vertices.resize( point_map.size() );
-
- DVector<Vector3>::Write vw = vertices.write();
- Vector3 *verticesw=vw.ptr();
-
- AABB _aabb;
-
- for( Map<Vector3,int>::Element *E=point_map.front();E;E=E->next()) {
-
- if (E==point_map.front()) {
- _aabb.pos=E->key();
- } else {
-
- _aabb.expand_to(E->key());
- }
- verticesw[E->value()]=E->key();
- }
-
- point_map.clear(); // not needed anymore
-
- faces.resize(face_list.size());
- DVector<Face>::Write w = faces.write();
- Face *facesw=w.ptr();
-
- int fc=0;
-
- for( List<Face>::Element *E=face_list.front();E;E=E->next()) {
-
- facesw[fc++]=E->get();
- }
-
- face_list.clear();
-
-
- DVector<_VolumeSW_BVH_Element> bvh_array;
- bvh_array.resize( fc );
-
- DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
- _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
-
-
- for(int i=0;i<fc;i++) {
-
- AABB face_aabb;
- face_aabb.pos=verticesw[facesw[i].indices[0]];
- face_aabb.expand_to( verticesw[facesw[i].indices[1]] );
- face_aabb.expand_to( verticesw[facesw[i].indices[2]] );
-
- bvh_arrayw[i].face_index=i;
- bvh_arrayw[i].aabb=face_aabb;
- bvh_arrayw[i].center=face_aabb.pos+face_aabb.size*0.5;
-
- }
-
- w=DVector<Face>::Write();
- vw=DVector<Vector3>::Write();
-
-
- int count=0;
- _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,fc,count);
-
- ERR_FAIL_COND(count==0);
-
- bvhw=DVector<_VolumeSW_BVH_Element>::Write();
-
- bvh.resize( count+1 );
-
- DVector<BVH>::Write bvhw2 = bvh.write();
- BVH*bvh_arrayw2=bvhw2.ptr();
-
- int idx=0;
- _fill_bvh(bvh_tree,bvh_arrayw2,idx);
-
- set_aabb(_aabb);
-
-#else
- DVector<_VolumeSW_BVH_Element> bvh_array;
- bvh_array.resize( src_face_count );
-
- DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write();
- _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr();
-
- faces.resize(src_face_count);
- DVector<Face>::Write w = faces.write();
- Face *facesw=w.ptr();
-
- vertices.resize( src_face_count*3 );
-
- DVector<Vector3>::Write vw = vertices.write();
- Vector3 *verticesw=vw.ptr();
-
- AABB _aabb;
-
-
- for(int i=0;i<src_face_count;i++) {
-
- Face3 face( facesr[i*3+0], facesr[i*3+1], facesr[i*3+2] );
-
- bvh_arrayw[i].aabb=face.get_aabb();
- bvh_arrayw[i].center = bvh_arrayw[i].aabb.pos + bvh_arrayw[i].aabb.size * 0.5;
- bvh_arrayw[i].face_index=i;
- facesw[i].indices[0]=i*3+0;
- facesw[i].indices[1]=i*3+1;
- facesw[i].indices[2]=i*3+2;
- facesw[i].normal=face.get_plane().normal;
- verticesw[i*3+0]=face.vertex[0];
- verticesw[i*3+1]=face.vertex[1];
- verticesw[i*3+2]=face.vertex[2];
- if (i==0)
- _aabb=bvh_arrayw[i].aabb;
- else
- _aabb.merge_with(bvh_arrayw[i].aabb);
-
- }
-
- w=DVector<Face>::Write();
- vw=DVector<Vector3>::Write();
-
- int count=0;
- _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count);
-
- bvh.resize( count+1 );
-
- DVector<BVH>::Write bvhw2 = bvh.write();
- BVH*bvh_arrayw2=bvhw2.ptr();
-
- int idx=0;
- _fill_bvh(bvh_tree,bvh_arrayw2,idx);
-
- configure(_aabb); // this type of shape has no margin
-
-
-#endif
-}
-
-
-void ConcavePolygonShapeSW::set_data(const Variant& p_data) {
-
-
- _setup(p_data);
-}
-
-Variant ConcavePolygonShapeSW::get_data() const {
-
- return get_faces();
-}
-
-ConcavePolygonShapeSW::ConcavePolygonShapeSW() {
-
-
-}
-
-
-
-/* HEIGHT MAP SHAPE */
-
-DVector<float> HeightMapShapeSW::get_heights() const {
-
- return heights;
-}
-int HeightMapShapeSW::get_width() const {
-
- return width;
-}
-int HeightMapShapeSW::get_depth() const {
-
- return depth;
-}
-float HeightMapShapeSW::get_cell_size() const {
-
- return cell_size;
-}
-
-
-void HeightMapShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const {
-
- //not very useful, but not very used either
- p_transform.xform(get_aabb()).project_range_in_plane( Plane(p_normal,0),r_min,r_max );
-
-}
-
-Vector3 HeightMapShapeSW::get_support(const Vector3& p_normal) const {
-
-
- //not very useful, but not very used either
- return get_aabb().get_support(p_normal);
-
-}
-
-bool HeightMapShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const {
-
-
- return false;
-}
-
-
-void HeightMapShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const {
-
-
-
-}
-
-
-Vector3 HeightMapShapeSW::get_moment_of_inertia(float p_mass) const {
-
-
- // use crappy AABB approximation
- Vector3 extents=get_aabb().size*0.5;
-
- return Vector3(
- (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z),
- (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z),
- (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y)
- );
-}
-
-
-void HeightMapShapeSW::_setup(DVector<real_t> p_heights,int p_width,int p_depth,real_t p_cell_size) {
-
- heights=p_heights;
- width=p_width;
- depth=p_depth;;
- cell_size=p_cell_size;
-
- DVector<real_t>::Read r = heights. read();
-
- AABB aabb;
-
- for(int i=0;i<depth;i++) {
-
- for(int j=0;j<width;j++) {
-
- float h = r[i*width+j];
-
- Vector3 pos( j*cell_size, h, i*cell_size );
- if (i==0 || j==0)
- aabb.pos=pos;
- else
- aabb.expand_to(pos);
-
- }
- }
-
-
- configure(aabb);
-}
-
-void HeightMapShapeSW::set_data(const Variant& p_data) {
-
- ERR_FAIL_COND( p_data.get_type()!=Variant::DICTIONARY );
- Dictionary d=p_data;
- ERR_FAIL_COND( !d.has("width") );
- ERR_FAIL_COND( !d.has("depth") );
- ERR_FAIL_COND( !d.has("cell_size") );
- ERR_FAIL_COND( !d.has("heights") );
-
- int width=d["width"];
- int depth=d["depth"];
- float cell_size=d["cell_size"];
- DVector<float> heights=d["heights"];
-
- ERR_FAIL_COND( width<= 0);
- ERR_FAIL_COND( depth<= 0);
- ERR_FAIL_COND( cell_size<= CMP_EPSILON);
- ERR_FAIL_COND( heights.size() != (width*depth) );
- _setup(heights, width, depth, cell_size );
-
-}
-
-Variant HeightMapShapeSW::get_data() const {
-
- ERR_FAIL_V(Variant());
-
-}
-
-HeightMapShapeSW::HeightMapShapeSW() {
-
- width=0;
- depth=0;
- cell_size=0;
-}
-
-
-
+#include "shape_sw.h" +#include "geometry.h" +#include "sort.h" +#include "quick_hull.h" +#define _POINT_SNAP 0.001953125 +#define _EDGE_IS_VALID_SUPPORT_TRESHOLD 0.0002 +#define _FACE_IS_VALID_SUPPORT_TRESHOLD 0.9998 + + +void ShapeSW::configure(const AABB& p_aabb) { + aabb=p_aabb; + configured=true; + for (Map<ShapeOwnerSW*,int>::Element *E=owners.front();E;E=E->next()) { + ShapeOwnerSW* co=(ShapeOwnerSW*)E->key(); + co->_shape_changed(); + } +} + + +Vector3 ShapeSW::get_support(const Vector3& p_normal) const { + + Vector3 res; + int amnt; + get_supports(p_normal,1,&res,amnt); + return res; +} + +void ShapeSW::add_owner(ShapeOwnerSW *p_owner) { + + Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner); + if (E) { + E->get()++; + } else { + owners[p_owner]=1; + } +} + +void ShapeSW::remove_owner(ShapeOwnerSW *p_owner){ + + Map<ShapeOwnerSW*,int>::Element *E=owners.find(p_owner); + ERR_FAIL_COND(!E); + E->get()--; + if (E->get()==0) { + owners.erase(E); + } + +} + +bool ShapeSW::is_owner(ShapeOwnerSW *p_owner) const{ + + return owners.has(p_owner); + +} + +const Map<ShapeOwnerSW*,int>& ShapeSW::get_owners() const{ + return owners; +} + + +ShapeSW::ShapeSW() { + + custom_bias=0; + configured=false; +} + + +ShapeSW::~ShapeSW() { + + ERR_FAIL_COND(owners.size()); +} + + + +Plane PlaneShapeSW::get_plane() const { + + return plane; +} + +void PlaneShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + // gibberish, a plane is infinity + r_min=-1e7; + r_max=1e7; +} + +Vector3 PlaneShapeSW::get_support(const Vector3& p_normal) const { + + return p_normal*1e15; +} + + +bool PlaneShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + bool inters=plane.intersects_segment(p_begin,p_end,&r_result); + if(inters) + r_normal=plane.normal; + return inters; +} + +Vector3 PlaneShapeSW::get_moment_of_inertia(float p_mass) const { + + return Vector3(); //wtf +} + +void PlaneShapeSW::_setup(const Plane& p_plane) { + + plane=p_plane; + configure(AABB(Vector3(-1e4,-1e4,-1e4),Vector3(1e4*2,1e4*2,1e4*2))); +} + +void PlaneShapeSW::set_data(const Variant& p_data) { + + _setup(p_data); + +} + +Variant PlaneShapeSW::get_data() const { + + return plane; +} + +PlaneShapeSW::PlaneShapeSW() { + + +} + +// + +float RayShapeSW::get_length() const { + + return length; +} + +void RayShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + // don't think this will be even used + r_min=0; + r_max=1; +} + +Vector3 RayShapeSW::get_support(const Vector3& p_normal) const { + + if (p_normal.z>0) + return Vector3(0,0,length); + else + return Vector3(0,0,0); +} + +void RayShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { + + if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_TRESHOLD) { + + r_amount=2; + r_supports[0]=Vector3(0,0,0); + r_supports[1]=Vector3(0,0,length); + } if (p_normal.z>0) { + r_amount=1; + *r_supports=Vector3(0,0,length); + } else { + r_amount=1; + *r_supports=Vector3(0,0,0); + } +} + + +bool RayShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + return false; //simply not possible +} + +Vector3 RayShapeSW::get_moment_of_inertia(float p_mass) const { + + return Vector3(); +} + +void RayShapeSW::_setup(float p_length) { + + length=p_length; + configure(AABB(Vector3(0,0,0),Vector3(0.1,0.1,length))); +} + +void RayShapeSW::set_data(const Variant& p_data) { + + _setup(p_data); + +} + +Variant RayShapeSW::get_data() const { + + return length; +} + +RayShapeSW::RayShapeSW() { + + length=1; +} + + + +/********** SPHERE *************/ + +real_t SphereShapeSW::get_radius() const { + + return radius; +} + +void SphereShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + float d = p_normal.dot( p_transform.origin ); + + // figure out scale at point + Vector3 local_normal = p_transform.basis.xform_inv(p_normal); + float scale = local_normal.length(); + + r_min = d - (radius) * scale; + r_max = d + (radius) * scale; + +} + +Vector3 SphereShapeSW::get_support(const Vector3& p_normal) const { + + return p_normal*radius; +} + +void SphereShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { + + *r_supports=p_normal*radius; + r_amount=1; +} + +bool SphereShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + return Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(),radius,&r_result,&r_normal); +} + +Vector3 SphereShapeSW::get_moment_of_inertia(float p_mass) const { + + float s = 0.4 * p_mass * radius * radius; + return Vector3(s,s,s); +} + +void SphereShapeSW::_setup(real_t p_radius) { + + + radius=p_radius; + configure(AABB( Vector3(-radius,-radius,-radius), Vector3(radius*2.0,radius*2.0,radius*2.0))); + +} + +void SphereShapeSW::set_data(const Variant& p_data) { + + _setup(p_data); +} + +Variant SphereShapeSW::get_data() const { + + return radius; +} + +SphereShapeSW::SphereShapeSW() { + + radius=0; +} + + +/********** BOX *************/ + + +void BoxShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + // no matter the angle, the box is mirrored anyway + Vector3 local_normal=p_transform.basis.xform_inv(p_normal); + + float length = local_normal.abs().dot(half_extents); + float distance = p_normal.dot( p_transform.origin ); + + r_min = distance - length; + r_max = distance + length; + + +} + +Vector3 BoxShapeSW::get_support(const Vector3& p_normal) const { + + + Vector3 point( + (p_normal.x<0) ? -half_extents.x : half_extents.x, + (p_normal.y<0) ? -half_extents.y : half_extents.y, + (p_normal.z<0) ? -half_extents.z : half_extents.z + ); + + return point; +} + +void BoxShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { + + static const int next[3]={1,2,0}; + static const int next2[3]={2,0,1}; + + for (int i=0;i<3;i++) { + + Vector3 axis; + axis[i]=1.0; + float dot = p_normal.dot( axis ); + if ( Math::abs( dot ) > _FACE_IS_VALID_SUPPORT_TRESHOLD ) { + + //Vector3 axis_b; + + bool neg = dot<0; + r_amount = 4; + + Vector3 point; + point[i]=half_extents[i]; + + int i_n=next[i]; + int i_n2=next2[i]; + + static const float sign[4][2]={ + + {-1.0, 1.0}, + { 1.0, 1.0}, + { 1.0,-1.0}, + {-1.0,-1.0}, + }; + + for (int j=0;j<4;j++) { + + point[i_n]=sign[j][0]*half_extents[i_n]; + point[i_n2]=sign[j][1]*half_extents[i_n2]; + r_supports[j]=neg?-point:point; + + } + + if (neg) { + SWAP( r_supports[1], r_supports[2] ); + SWAP( r_supports[0], r_supports[3] ); + } + + return; + } + + r_amount=0; + + } + + for (int i=0;i<3;i++) { + + Vector3 axis; + axis[i]=1.0; + + if (Math::abs(p_normal.dot(axis))<_EDGE_IS_VALID_SUPPORT_TRESHOLD) { + + r_amount= 2; + + int i_n=next[i]; + int i_n2=next2[i]; + + Vector3 point=half_extents; + + if (p_normal[i_n]<0) { + point[i_n]=-point[i_n]; + } + if (p_normal[i_n2]<0) { + point[i_n2]=-point[i_n2]; + } + + r_supports[0] = point; + point[i]=-point[i]; + r_supports[1] = point; + return; + } + } + /* USE POINT */ + + Vector3 point( + (p_normal.x<0) ? -half_extents.x : half_extents.x, + (p_normal.y<0) ? -half_extents.y : half_extents.y, + (p_normal.z<0) ? -half_extents.z : half_extents.z + ); + + r_amount=1; + r_supports[0]=point; +} + +bool BoxShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + AABB aabb(-half_extents,half_extents*2.0); + + return aabb.intersects_segment(p_begin,p_end,&r_result,&r_normal); + +} + +Vector3 BoxShapeSW::get_moment_of_inertia(float p_mass) const { + + float lx=half_extents.x; + float ly=half_extents.y; + float lz=half_extents.z; + + return Vector3( (p_mass/3.0) * (ly*ly + lz*lz), (p_mass/3.0) * (lx*lx + lz*lz), (p_mass/3.0) * (lx*lx + ly*ly) ); + +} + +void BoxShapeSW::_setup(const Vector3& p_half_extents) { + + half_extents=p_half_extents.abs(); + + configure(AABB(-half_extents,half_extents*2)); + + +} + +void BoxShapeSW::set_data(const Variant& p_data) { + + + _setup(p_data); +} + +Variant BoxShapeSW::get_data() const { + + return half_extents; +} + +BoxShapeSW::BoxShapeSW() { + + +} + + +/********** CAPSULE *************/ + + +void CapsuleShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + Vector3 n=p_transform.basis.xform_inv(p_normal).normalized(); + float h = (n.z > 0) ? height : -height; + + n *= radius; + n.z += h * 0.5; + + r_max=p_normal.dot(p_transform.xform(n)); + r_min=p_normal.dot(p_transform.xform(-n)); + return; + + n = p_transform.basis.xform(n); + + float distance = p_normal.dot( p_transform.origin ); + float length = Math::abs(p_normal.dot(n)); + r_min = distance - length; + r_max = distance + length; + + ERR_FAIL_COND( r_max < r_min ); + +} + +Vector3 CapsuleShapeSW::get_support(const Vector3& p_normal) const { + + Vector3 n=p_normal; + + float h = (n.z > 0) ? height : -height; + + n*=radius; + n.z += h*0.5; + return n; +} + +void CapsuleShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { + + + Vector3 n=p_normal; + + float d = n.z; + + if (Math::abs( d )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) { + + // make it flat + n.z=0.0; + n.normalize(); + n*=radius; + + r_amount=2; + r_supports[0]=n; + r_supports[0].z+=height*0.5; + r_supports[1]=n; + r_supports[1].z-=height*0.5; + + } else { + + float h = (d > 0) ? height : -height; + + n*=radius; + n.z += h*0.5; + r_amount=1; + *r_supports=n; + + } + +} + + +bool CapsuleShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + Vector3 norm=(p_end-p_begin).normalized(); + float min_d=1e20; + + + Vector3 res,n; + bool collision=false; + + Vector3 auxres,auxn; + bool collided; + + // test against cylinder and spheres :-| + + collided = Geometry::segment_intersects_cylinder(p_begin,p_end,height,radius,&auxres,&auxn); + + if (collided) { + float d=norm.dot(auxres); + if (d<min_d) { + min_d=d; + res=auxres; + n=auxn; + collision=true; + } + } + + collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*0.5),radius,&auxres,&auxn); + + if (collided) { + float d=norm.dot(auxres); + if (d<min_d) { + min_d=d; + res=auxres; + n=auxn; + collision=true; + } + } + + collided = Geometry::segment_intersects_sphere(p_begin,p_end,Vector3(0,0,height*-0.5),radius,&auxres,&auxn); + + if (collided) { + float d=norm.dot(auxres); + + if (d<min_d) { + min_d=d; + res=auxres; + n=auxn; + collision=true; + } + } + + if (collision) { + + r_result=res; + r_normal=n; + } + return collision; +} + +Vector3 CapsuleShapeSW::get_moment_of_inertia(float p_mass) const { + + // use crappy AABB approximation + Vector3 extents=get_aabb().size*0.5; + + return Vector3( + (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z), + (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z), + (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y) + ); + +} + + + + +void CapsuleShapeSW::_setup(real_t p_height,real_t p_radius) { + + height=p_height; + radius=p_radius; + configure(AABB(Vector3(-radius,-radius,-height*0.5-radius),Vector3(radius*2,radius*2,height+radius*2.0))); + +} + +void CapsuleShapeSW::set_data(const Variant& p_data) { + + Dictionary d = p_data; + ERR_FAIL_COND(!d.has("radius")); + ERR_FAIL_COND(!d.has("height")); + _setup(d["height"],d["radius"]); + +} + +Variant CapsuleShapeSW::get_data() const { + + Dictionary d; + d["radius"]=radius; + d["height"]=height; + return d; + +} + + +CapsuleShapeSW::CapsuleShapeSW() { + + height=radius=0; + +} + +/********** CONVEX POLYGON *************/ + + +void ConvexPolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + + int vertex_count=mesh.vertices.size(); + if (vertex_count==0) + return; + + const Vector3 *vrts=&mesh.vertices[0]; + + for (int i=0;i<vertex_count;i++) { + + float d=p_normal.dot( p_transform.xform( vrts[i] ) ); + + if (i==0 || d > r_max) + r_max=d; + if (i==0 || d < r_min) + r_min=d; + } +} + +Vector3 ConvexPolygonShapeSW::get_support(const Vector3& p_normal) const { + + Vector3 n=p_normal; + + int vert_support_idx=-1; + float support_max; + + int vertex_count=mesh.vertices.size(); + if (vertex_count==0) + return Vector3(); + + const Vector3 *vrts=&mesh.vertices[0]; + + for (int i=0;i<vertex_count;i++) { + + float d=n.dot(vrts[i]); + + if (i==0 || d > support_max) { + support_max=d; + vert_support_idx=i; + } + } + + return vrts[vert_support_idx]; + +} + + + +void ConvexPolygonShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { + + const Geometry::MeshData::Face *faces = mesh.faces.ptr(); + int fc = mesh.faces.size(); + + const Geometry::MeshData::Edge *edges = mesh.edges.ptr(); + int ec = mesh.edges.size(); + + const Vector3 *vertices = mesh.vertices.ptr(); + int vc = mesh.vertices.size(); + + //find vertex first + real_t max; + int vtx; + + for (int i=0;i<vc;i++) { + + float d=p_normal.dot(vertices[i]); + + if (i==0 || d > max) { + max=d; + vtx=i; + } + } + + + for(int i=0;i<fc;i++) { + + if (faces[i].plane.normal.dot(p_normal)>_FACE_IS_VALID_SUPPORT_TRESHOLD) { + + int ic = faces[i].indices.size(); + const int *ind=faces[i].indices.ptr(); + + bool valid=false; + for(int j=0;j<ic;j++) { + if (ind[j]==vtx) { + valid=true; + break; + } + } + + if (!valid) + continue; + + int m = MIN(p_max,ic); + for(int j=0;j<m;j++) { + + r_supports[j]=vertices[ind[j]]; + } + r_amount=m; + return; + } + } + + for(int i=0;i<ec;i++) { + + + float dot=(vertices[edges[i].a]-vertices[edges[i].b]).normalized().dot(p_normal); + dot=ABS(dot); + if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD && (edges[i].a==vtx || edges[i].b==vtx)) { + + r_amount=2; + r_supports[0]=vertices[edges[i].a]; + r_supports[1]=vertices[edges[i].b]; + return; + } + } + + + r_supports[0]=vertices[vtx]; + r_amount=1; +} + +bool ConvexPolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + + + const Geometry::MeshData::Face *faces = mesh.faces.ptr(); + int fc = mesh.faces.size(); + + const Vector3 *vertices = mesh.vertices.ptr(); + int vc = mesh.vertices.size(); + + Vector3 n = p_end-p_begin; + float min = 1e20; + bool col=false; + + for(int i=0;i<fc;i++) { + + if (faces[i].plane.normal.dot(n) > 0) + continue; //opposing face + + int ic = faces[i].indices.size(); + const int *ind=faces[i].indices.ptr(); + + for(int j=1;j<ic-1;j++) { + + Face3 f(vertices[ind[0]],vertices[ind[j]],vertices[ind[j+1]]); + Vector3 result; + if (f.intersects_segment(p_begin,p_end,&result)) { + float d = n.dot(result); + if (d<min) { + min=d; + r_result=result; + r_normal=faces[i].plane.normal; + col=true; + } + + break; + } + + } + } + + return col; + +} + +Vector3 ConvexPolygonShapeSW::get_moment_of_inertia(float p_mass) const { + + // use crappy AABB approximation + Vector3 extents=get_aabb().size*0.5; + + return Vector3( + (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z), + (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z), + (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y) + ); + +} + +void ConvexPolygonShapeSW::_setup(const Vector<Vector3>& p_vertices) { + + Error err = QuickHull::build(p_vertices,mesh); + AABB _aabb; + + for(int i=0;i<mesh.vertices.size();i++) { + + if (i==0) + _aabb.pos=mesh.vertices[i]; + else + _aabb.expand_to(mesh.vertices[i]); + } + + configure(_aabb); + + +} + +void ConvexPolygonShapeSW::set_data(const Variant& p_data) { + + _setup(p_data); + +} + +Variant ConvexPolygonShapeSW::get_data() const { + + return mesh.vertices; +} + + +ConvexPolygonShapeSW::ConvexPolygonShapeSW() { + + +} + + +/********** FACE POLYGON *************/ + + +void FaceShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + for (int i=0;i<3;i++) { + + Vector3 v=p_transform.xform(vertex[i]); + float d=p_normal.dot(v); + + if (i==0 || d > r_max) + r_max=d; + + if (i==0 || d < r_min) + r_min=d; + } +} + +Vector3 FaceShapeSW::get_support(const Vector3& p_normal) const { + + + Vector3 n=p_normal; + + int vert_support_idx=-1; + float support_max; + + for (int i=0;i<3;i++) { + + //float d=n.dot(vertex[i]); + float d=p_normal.dot(vertex[i]); + + if (i==0 || d > support_max) { + support_max=d; + vert_support_idx=i; + } + } + + return vertex[vert_support_idx]; +} + +void FaceShapeSW::get_supports(const Vector3& p_normal,int p_max,Vector3 *r_supports,int & r_amount) const { + + Vector3 n=p_normal; + + /** TEST FACE AS SUPPORT **/ + if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_TRESHOLD) { + + r_amount=3; + for (int i=0;i<3;i++) { + + r_supports[i]=vertex[i]; + } + return; + + } + + /** FIND SUPPORT VERTEX **/ + + int vert_support_idx=-1; + float support_max; + + for (int i=0;i<3;i++) { + + float d=n.dot(vertex[i]); + + if (i==0 || d > support_max) { + support_max=d; + vert_support_idx=i; + } + } + + /** TEST EDGES AS SUPPORT **/ + + for (int i=0;i<3;i++) { + + int nx=(i+1)%3; + //if (i!=vert_support_idx && nx!=vert_support_idx) + // continue; + + // check if edge is valid as a support + float dot=(vertex[i]-vertex[nx]).normalized().dot(n); + dot=ABS(dot); + if (dot < _EDGE_IS_VALID_SUPPORT_TRESHOLD) { + + r_amount=2; + r_supports[0]=vertex[i]; + r_supports[1]=vertex[nx]; + return; + } + } + + r_amount=1; + r_supports[0]=vertex[vert_support_idx]; +} + +bool FaceShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + + bool c=Geometry::segment_intersects_triangle(p_begin,p_end,vertex[0],vertex[1],vertex[2],&r_result); + if (c) + r_normal=Plane(vertex[0],vertex[1],vertex[2]).normal; + + return c; +} + +Vector3 FaceShapeSW::get_moment_of_inertia(float p_mass) const { + + return Vector3(); // Sorry, but i don't think anyone cares, FaceShape! + +} + +FaceShapeSW::FaceShapeSW() { + + configure(AABB()); + +} + + + +DVector<Vector3> ConcavePolygonShapeSW::get_faces() const { + + + DVector<Vector3> rfaces; + rfaces.resize(faces.size()*3); + + for(int i=0;i<faces.size();i++) { + + Face f=faces.get(i); + + for(int j=0;j<3;j++) { + + rfaces.set(i*3+j, vertices.get( f.indices[j] ) ); + } + } + + return rfaces; +} + +void ConcavePolygonShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + int count=vertices.size(); + DVector<Vector3>::Read r=vertices.read(); + const Vector3 *vptr=r.ptr(); + + for (int i=0;i<count;i++) { + + float d=p_normal.dot( p_transform.xform( vptr[i] ) ); + + if (i==0 || d > r_max) + r_max=d; + if (i==0 || d < r_min) + r_min=d; + + } +} + +Vector3 ConcavePolygonShapeSW::get_support(const Vector3& p_normal) const { + + + int count=vertices.size(); + DVector<Vector3>::Read r=vertices.read(); + const Vector3 *vptr=r.ptr(); + + Vector3 n=p_normal; + + int vert_support_idx=-1; + float support_max; + + for (int i=0;i<count;i++) { + + float d=n.dot(vptr[i]); + + if (i==0 || d > support_max) { + support_max=d; + vert_support_idx=i; + } + } + + + return vptr[vert_support_idx]; + +} + +void ConcavePolygonShapeSW::_cull_segment(int p_idx,_SegmentCullParams *p_params) const { + + const BVH *bvh=&p_params->bvh[p_idx]; + + + //if (p_params->dir.dot(bvh->aabb.get_support(-p_params->dir))>p_params->min_d) + // return; //test against whole AABB, which isn't very costly + + + //printf("addr: %p\n",bvh); + if (!bvh->aabb.intersects_segment(p_params->from,p_params->to)) { + + return; + } + + + if (bvh->face_index>=0) { + + + Vector3 res; + Vector3 vertices[3]={ + p_params->vertices[ p_params->faces[ bvh->face_index ].indices[0] ], + p_params->vertices[ p_params->faces[ bvh->face_index ].indices[1] ], + p_params->vertices[ p_params->faces[ bvh->face_index ].indices[2] ] + }; + + if (Geometry::segment_intersects_triangle( + p_params->from, + p_params->to, + vertices[0], + vertices[1], + vertices[2], + &res)) { + + + float d=p_params->normal.dot(res) - p_params->normal.dot(p_params->from); + //TODO, seems segmen/triangle intersection is broken :( + if (d>0 && d<p_params->min_d) { + + p_params->min_d=d; + p_params->result=res; + p_params->normal=Plane(vertices[0],vertices[1],vertices[2]).normal; + p_params->collisions++; + } + + } + + + + } else { + + if (bvh->left>=0) + _cull_segment(bvh->left,p_params); + if (bvh->right>=0) + _cull_segment(bvh->right,p_params); + + + } +} + +bool ConcavePolygonShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_result, Vector3 &r_normal) const { + + // unlock data + DVector<Face>::Read fr=faces.read(); + DVector<Vector3>::Read vr=vertices.read(); + DVector<BVH>::Read br=bvh.read(); + + + _SegmentCullParams params; + params.from=p_begin; + params.to=p_end; + params.collisions=0; + params.normal=(p_end-p_begin).normalized(); + + params.faces=fr.ptr(); + params.vertices=vr.ptr(); + params.bvh=br.ptr(); + + params.min_d=1e20; + // cull + _cull_segment(0,¶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<Face>::Read fr=faces.read(); + DVector<Vector3>::Read vr=vertices.read(); + DVector<BVH>::Read br=bvh.read(); + + FaceShapeSW face; // use this to send in the callback + + _CullParams params; + params.aabb=local_aabb; + params.face=&face; + params.faces=fr.ptr(); + params.vertices=vr.ptr(); + params.bvh=br.ptr(); + params.callback=p_callback; + params.userdata=p_userdata; + + // cull + _cull(0,¶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.x<b.center.x; + } +}; + + +struct _VolumeSW_BVH_CompareY { + + _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const { + + return a.center.y<b.center.y; + } +}; + +struct _VolumeSW_BVH_CompareZ { + + _FORCE_INLINE_ bool operator ()(const _VolumeSW_BVH_Element& a, const _VolumeSW_BVH_Element& b) const { + + return a.center.z<b.center.z; + } +}; + +struct _VolumeSW_BVH { + + AABB aabb; + _VolumeSW_BVH *left; + _VolumeSW_BVH *right; + + int face_index; +}; + + +_VolumeSW_BVH* _volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements,int p_size,int &count) { + + _VolumeSW_BVH* bvh = memnew( _VolumeSW_BVH ); + + if (p_size==1) { + //leaf + bvh->aabb=p_elements[0].aabb; + bvh->left=NULL; + bvh->right=NULL; + bvh->face_index=p_elements->face_index; + count++; + return bvh; + } else { + + bvh->face_index=-1; + } + + AABB aabb; + for(int i=0;i<p_size;i++) { + + if (i==0) + aabb=p_elements[i].aabb; + else + aabb.merge_with(p_elements[i].aabb); + } + bvh->aabb=aabb; + switch(aabb.get_longest_axis_index()) { + + case 0: { + + SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareX> sort_x; + sort_x.sort(p_elements,p_size); + + } break; + case 1: { + + SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareY> sort_y; + sort_y.sort(p_elements,p_size); + } break; + case 2: { + + SortArray<_VolumeSW_BVH_Element,_VolumeSW_BVH_CompareZ> sort_z; + sort_z.sort(p_elements,p_size); + } break; + } + + int split=p_size/2; + bvh->left=_volume_sw_build_bvh(p_elements,split,count); + bvh->right=_volume_sw_build_bvh(&p_elements[split],p_size-split,count); + +// printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index); + count++; + return bvh; +} + + +void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array,int& p_idx) { + + int idx=p_idx; + + + p_bvh_array[idx].aabb=p_bvh_tree->aabb; + p_bvh_array[idx].face_index=p_bvh_tree->face_index; +// printf("%p - %i: %i(%p) -- %p:%p\n",%p_bvh_array[idx],p_idx,p_bvh_array[i]->face_index,&p_bvh_tree->face_index,p_bvh_tree->left,p_bvh_tree->right); + + + if (p_bvh_tree->left) { + p_bvh_array[idx].left=++p_idx; + _fill_bvh(p_bvh_tree->left,p_bvh_array,p_idx); + + } else { + + p_bvh_array[p_idx].left=-1; + } + + if (p_bvh_tree->right) { + p_bvh_array[idx].right=++p_idx; + _fill_bvh(p_bvh_tree->right,p_bvh_array,p_idx); + + } else { + + p_bvh_array[p_idx].right=-1; + } + + memdelete(p_bvh_tree); + +} + +void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) { + + int src_face_count=p_faces.size(); + ERR_FAIL_COND(src_face_count%3); + src_face_count/=3; + + DVector<Vector3>::Read r = p_faces.read(); + const Vector3 * facesr= r.ptr(); + +#if 0 + Map<Vector3,int> point_map; + List<Face> face_list; + + + for(int i=0;i<src_face_count;i++) { + + Face3 faceaux; + + for(int j=0;j<3;j++) { + + faceaux.vertex[j]=facesr[i*3+j].snapped(_POINT_SNAP); + //faceaux.vertex[j]=facesr[i*3+j];//facesr[i*3+j].snapped(_POINT_SNAP); + } + + ERR_CONTINUE( faceaux.is_degenerate() ); + + Face face; + + for(int j=0;j<3;j++) { + + + Map<Vector3,int>::Element *E=point_map.find(faceaux.vertex[j]); + if (E) { + + face.indices[j]=E->value(); + } else { + + face.indices[j]=point_map.size(); + point_map.insert(faceaux.vertex[j],point_map.size()); + + } + } + + face_list.push_back(face); + } + + vertices.resize( point_map.size() ); + + DVector<Vector3>::Write vw = vertices.write(); + Vector3 *verticesw=vw.ptr(); + + AABB _aabb; + + for( Map<Vector3,int>::Element *E=point_map.front();E;E=E->next()) { + + if (E==point_map.front()) { + _aabb.pos=E->key(); + } else { + + _aabb.expand_to(E->key()); + } + verticesw[E->value()]=E->key(); + } + + point_map.clear(); // not needed anymore + + faces.resize(face_list.size()); + DVector<Face>::Write w = faces.write(); + Face *facesw=w.ptr(); + + int fc=0; + + for( List<Face>::Element *E=face_list.front();E;E=E->next()) { + + facesw[fc++]=E->get(); + } + + face_list.clear(); + + + DVector<_VolumeSW_BVH_Element> bvh_array; + bvh_array.resize( fc ); + + DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write(); + _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr(); + + + for(int i=0;i<fc;i++) { + + AABB face_aabb; + face_aabb.pos=verticesw[facesw[i].indices[0]]; + face_aabb.expand_to( verticesw[facesw[i].indices[1]] ); + face_aabb.expand_to( verticesw[facesw[i].indices[2]] ); + + bvh_arrayw[i].face_index=i; + bvh_arrayw[i].aabb=face_aabb; + bvh_arrayw[i].center=face_aabb.pos+face_aabb.size*0.5; + + } + + w=DVector<Face>::Write(); + vw=DVector<Vector3>::Write(); + + + int count=0; + _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,fc,count); + + ERR_FAIL_COND(count==0); + + bvhw=DVector<_VolumeSW_BVH_Element>::Write(); + + bvh.resize( count+1 ); + + DVector<BVH>::Write bvhw2 = bvh.write(); + BVH*bvh_arrayw2=bvhw2.ptr(); + + int idx=0; + _fill_bvh(bvh_tree,bvh_arrayw2,idx); + + set_aabb(_aabb); + +#else + DVector<_VolumeSW_BVH_Element> bvh_array; + bvh_array.resize( src_face_count ); + + DVector<_VolumeSW_BVH_Element>::Write bvhw = bvh_array.write(); + _VolumeSW_BVH_Element *bvh_arrayw=bvhw.ptr(); + + faces.resize(src_face_count); + DVector<Face>::Write w = faces.write(); + Face *facesw=w.ptr(); + + vertices.resize( src_face_count*3 ); + + DVector<Vector3>::Write vw = vertices.write(); + Vector3 *verticesw=vw.ptr(); + + AABB _aabb; + + + for(int i=0;i<src_face_count;i++) { + + Face3 face( facesr[i*3+0], facesr[i*3+1], facesr[i*3+2] ); + + bvh_arrayw[i].aabb=face.get_aabb(); + bvh_arrayw[i].center = bvh_arrayw[i].aabb.pos + bvh_arrayw[i].aabb.size * 0.5; + bvh_arrayw[i].face_index=i; + facesw[i].indices[0]=i*3+0; + facesw[i].indices[1]=i*3+1; + facesw[i].indices[2]=i*3+2; + facesw[i].normal=face.get_plane().normal; + verticesw[i*3+0]=face.vertex[0]; + verticesw[i*3+1]=face.vertex[1]; + verticesw[i*3+2]=face.vertex[2]; + if (i==0) + _aabb=bvh_arrayw[i].aabb; + else + _aabb.merge_with(bvh_arrayw[i].aabb); + + } + + w=DVector<Face>::Write(); + vw=DVector<Vector3>::Write(); + + int count=0; + _VolumeSW_BVH *bvh_tree=_volume_sw_build_bvh(bvh_arrayw,src_face_count,count); + + bvh.resize( count+1 ); + + DVector<BVH>::Write bvhw2 = bvh.write(); + BVH*bvh_arrayw2=bvhw2.ptr(); + + int idx=0; + _fill_bvh(bvh_tree,bvh_arrayw2,idx); + + configure(_aabb); // this type of shape has no margin + + +#endif +} + + +void ConcavePolygonShapeSW::set_data(const Variant& p_data) { + + + _setup(p_data); +} + +Variant ConcavePolygonShapeSW::get_data() const { + + return get_faces(); +} + +ConcavePolygonShapeSW::ConcavePolygonShapeSW() { + + +} + + + +/* HEIGHT MAP SHAPE */ + +DVector<float> HeightMapShapeSW::get_heights() const { + + return heights; +} +int HeightMapShapeSW::get_width() const { + + return width; +} +int HeightMapShapeSW::get_depth() const { + + return depth; +} +float HeightMapShapeSW::get_cell_size() const { + + return cell_size; +} + + +void HeightMapShapeSW::project_range(const Vector3& p_normal, const Transform& p_transform, real_t &r_min, real_t &r_max) const { + + //not very useful, but not very used either + p_transform.xform(get_aabb()).project_range_in_plane( Plane(p_normal,0),r_min,r_max ); + +} + +Vector3 HeightMapShapeSW::get_support(const Vector3& p_normal) const { + + + //not very useful, but not very used either + return get_aabb().get_support(p_normal); + +} + +bool HeightMapShapeSW::intersect_segment(const Vector3& p_begin,const Vector3& p_end,Vector3 &r_point, Vector3 &r_normal) const { + + + return false; +} + + +void HeightMapShapeSW::cull(const AABB& p_local_aabb,Callback p_callback,void* p_userdata) const { + + + +} + + +Vector3 HeightMapShapeSW::get_moment_of_inertia(float p_mass) const { + + + // use crappy AABB approximation + Vector3 extents=get_aabb().size*0.5; + + return Vector3( + (p_mass/3.0) * (extents.y*extents.y + extents.z*extents.z), + (p_mass/3.0) * (extents.x*extents.x + extents.z*extents.z), + (p_mass/3.0) * (extents.y*extents.y + extents.y*extents.y) + ); +} + + +void HeightMapShapeSW::_setup(DVector<real_t> p_heights,int p_width,int p_depth,real_t p_cell_size) { + + heights=p_heights; + width=p_width; + depth=p_depth;; + cell_size=p_cell_size; + + DVector<real_t>::Read r = heights. read(); + + AABB aabb; + + for(int i=0;i<depth;i++) { + + for(int j=0;j<width;j++) { + + float h = r[i*width+j]; + + Vector3 pos( j*cell_size, h, i*cell_size ); + if (i==0 || j==0) + aabb.pos=pos; + else + aabb.expand_to(pos); + + } + } + + + configure(aabb); +} + +void HeightMapShapeSW::set_data(const Variant& p_data) { + + ERR_FAIL_COND( p_data.get_type()!=Variant::DICTIONARY ); + Dictionary d=p_data; + ERR_FAIL_COND( !d.has("width") ); + ERR_FAIL_COND( !d.has("depth") ); + ERR_FAIL_COND( !d.has("cell_size") ); + ERR_FAIL_COND( !d.has("heights") ); + + int width=d["width"]; + int depth=d["depth"]; + float cell_size=d["cell_size"]; + DVector<float> heights=d["heights"]; + + ERR_FAIL_COND( width<= 0); + ERR_FAIL_COND( depth<= 0); + ERR_FAIL_COND( cell_size<= CMP_EPSILON); + ERR_FAIL_COND( heights.size() != (width*depth) ); + _setup(heights, width, depth, cell_size ); + +} + +Variant HeightMapShapeSW::get_data() const { + + ERR_FAIL_V(Variant()); + +} + +HeightMapShapeSW::HeightMapShapeSW() { + + width=0; + depth=0; + cell_size=0; +} + + + 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<float> morph_values; BakedLightData *baked_light; Transform *baked_light_octree_xform; + int baked_lightmap_id; bool mirror :8; bool depth_scale :8; bool billboard :8; 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<PropertyInfo> *p_param_list) const { @@ -1038,6 +1038,7 @@ RID VisualServerRaster::baked_light_create() { baked_light->data.octree_lattice_size=0; baked_light->data.octree_lattice_divide=0; baked_light->data.octree_steps=1; + baked_light->data.lightmap_multiplier=1.0; return baked_light_owner.make_rid( baked_light ); @@ -1063,6 +1064,26 @@ VisualServer::BakedLightMode VisualServerRaster::baked_light_get_mode(RID p_bake } +void VisualServerRaster::baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier) { + + VS_CHANGED; + BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND(!baked_light); + + baked_light->data.lightmap_multiplier=p_multiplier; + +} + +float VisualServerRaster::baked_light_get_lightmap_multiplier(RID p_baked_light) const{ + + const BakedLight *baked_light = baked_light_owner.get(p_baked_light); + ERR_FAIL_COND_V(!baked_light,0); + + return baked_light->data.lightmap_multiplier; + +} + + void VisualServerRaster::baked_light_set_octree(RID p_baked_light,const DVector<uint8_t> p_octree){ VS_CHANGED; @@ -2568,7 +2589,7 @@ void VisualServerRaster::instance_geometry_set_baked_light_texture_index(RID p_i Instance *instance = instance_owner.get( p_instance ); ERR_FAIL_COND( !instance ); - instance->lightmap_texture_index=p_tex_id; + instance->data.baked_lightmap_id=p_tex_id; } @@ -2577,7 +2598,7 @@ int VisualServerRaster::instance_geometry_get_baked_light_texture_index(RID p_in const Instance *instance = instance_owner.get( p_instance ); ERR_FAIL_COND_V( !instance,0 ); - return instance->lightmap_texture_index; + return instance->data.baked_lightmap_id; } 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<uint8_t> p_octree); virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const; + virtual void baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier); + virtual float baked_light_get_lightmap_multiplier(RID p_baked_light) const; + virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id); virtual void baked_light_clear_lightmaps(RID p_baked_light); 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<uint8_t>); FUNC1RC(DVector<uint8_t>,baked_light_get_octree,RID); + FUNC2(baked_light_set_lightmap_multiplier,RID,float); + FUNC1RC(float,baked_light_get_lightmap_multiplier,RID); FUNC3(baked_light_add_lightmap,RID,RID,int); FUNC1(baked_light_clear_lightmaps,RID); 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<uint8_t> p_octree)=0; virtual DVector<uint8_t> baked_light_get_octree(RID p_baked_light) const=0; + virtual void baked_light_set_lightmap_multiplier(RID p_baked_light,float p_multiplier)=0; + virtual float baked_light_get_lightmap_multiplier(RID p_baked_light) const=0; + virtual void baked_light_add_lightmap(RID p_baked_light,const RID p_texture,int p_id)=0; virtual void baked_light_clear_lightmaps(RID p_baked_light)=0; diff --git a/tools/editor/icons/icon_light_map.png b/tools/editor/icons/icon_light_map.png Binary files differnew file mode 100644 index 0000000000..96d3f6e11c --- /dev/null +++ b/tools/editor/icons/icon_light_map.png diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp index 3cc8ffd151..170598291a 100644 --- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp @@ -407,6 +407,7 @@ void EditorSceneImportDialog::_import(bool p_and_open) { rim->add_source(EditorImportPlugin::validate_source_path(import_path->get_text())); rim->set_option("flags",flags); + print_line("GET FLAGS: "+itos(texture_options->get_flags())); rim->set_option("texture_flags",texture_options->get_flags()); rim->set_option("texture_format",texture_options->get_format()); rim->set_option("texture_quality",texture_options->get_quality()); @@ -640,6 +641,7 @@ const EditorSceneImportDialog::FlagInfo EditorSceneImportDialog::scene_flag_name {EditorSceneImportPlugin::SCENE_FLAG_DETECT_ALPHA,"Materials","Set Alpha in Materials (-alpha)",true}, {EditorSceneImportPlugin::SCENE_FLAG_DETECT_VCOLOR,"Materials","Set Vert. Color in Materials (-vcol)",true}, {EditorSceneImportPlugin::SCENE_FLAG_LINEARIZE_DIFFUSE_TEXTURES,"Actions","SRGB->Linear Of Diffuse Textures",false}, + {EditorSceneImportPlugin::SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS,"Actions","Set Material Lightmap to UV2 if Tex2Array Exists",true}, {EditorSceneImportPlugin::SCENE_FLAG_CREATE_COLLISIONS,"Create","Create Collisions (-col},-colonly)",true}, {EditorSceneImportPlugin::SCENE_FLAG_CREATE_PORTALS,"Create","Create Portals (-portal)",true}, {EditorSceneImportPlugin::SCENE_FLAG_CREATE_ROOMS,"Create","Create Rooms (-room)",true}, @@ -1036,7 +1038,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh> } - if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR) && p_node->cast_to<MeshInstance>()) { + if (p_flags&(SCENE_FLAG_DETECT_ALPHA|SCENE_FLAG_DETECT_VCOLOR|SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS) && p_node->cast_to<MeshInstance>()) { MeshInstance *mi = p_node->cast_to<MeshInstance>(); @@ -1061,6 +1063,10 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh> mat->set_name(_fixstr(mat->get_name(),"vcol")); } + if (p_flags&SCENE_FLAG_SET_LIGHTMAP_TO_UV2_IF_EXISTS && m->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV2) { + mat->set_flag(Material::FLAG_LIGHTMAP_ON_UV2,true); + } + } } } @@ -1224,13 +1230,13 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh> col->set_name("col"); p_node->add_child(col); - - StaticBody *sb = col->cast_to<StaticBody>(); + StaticBody *sb=col->cast_to<StaticBody>(); CollisionShape *colshape = memnew( CollisionShape); colshape->set_shape(sb->get_shape(0)); colshape->set_name("shape"); - sb->add_child(colshape); + col->add_child(colshape); colshape->set_owner(p_node->get_owner()); + sb->set_owner(p_node->get_owner()); } else if (p_flags&SCENE_FLAG_CREATE_NAVMESH &&_teststr(name,"navmesh") && p_node->cast_to<MeshInstance>()) { @@ -1892,8 +1898,7 @@ Error EditorSceneImportPlugin::import2(Node *scene, const String& p_dest_path, c Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata ); print_line("flags: "+itos(image_flags)); uint32_t flags = image_flags; - if (E->get()) - flags|=EditorTextureImportPlugin::IMAGE_FLAG_CONVERT_TO_LINEAR; + imd->set_option("flags",flags); imd->set_option("format",image_format); imd->set_option("quality",image_quality); 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 Ref<Resourc bool atlas = from->get_option("atlas"); int flags=from->get_option("flags"); + print_line("GET FLAGS: "+itos(flags)); uint32_t tex_flags=0; if (flags&EditorTextureImportPlugin::IMAGE_FLAG_REPEAT) @@ -993,6 +994,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc if ((image.get_format()==Image::FORMAT_RGB || image.get_format()==Image::FORMAT_RGBA) && flags&IMAGE_FLAG_CONVERT_TO_LINEAR) { + print_line("CONVERT BECAUSE: "+itos(flags)); image.srgb_to_linear(); } diff --git a/tools/editor/plugins/baked_light_baker.cpp b/tools/editor/plugins/baked_light_baker.cpp index 2be6d3da24..1574ce81d7 100644 --- a/tools/editor/plugins/baked_light_baker.cpp +++ b/tools/editor/plugins/baked_light_baker.cpp @@ -45,7 +45,7 @@ BakedLightBaker::MeshTexture* BakedLightBaker::_get_mat_tex(const Ref<Texture>& } -void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform) { +void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture) { for(int i=0;i<p_mesh->get_surface_count();i++) { @@ -55,6 +55,7 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m Ref<Material> mat = p_mat_override.is_valid()?p_mat_override:p_mesh->surface_get_material(i); MeshMaterial *matptr=NULL; + int baked_tex=p_baked_texture; if (mat.is_valid()) { @@ -112,6 +113,8 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m DVector<Vector3>::Read vr=vertices.read(); DVector<Vector2> uv; DVector<Vector2>::Read uvr; + DVector<Vector2> uv2; + DVector<Vector2>::Read uv2r; DVector<Vector3> normal; DVector<Vector3>::Read normalr; bool read_uv=false; @@ -122,6 +125,18 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m uv=a[Mesh::ARRAY_TEX_UV]; uvr=uv.read(); read_uv=true; + + if (mat.is_valid() && mat->get_flag(Material::FLAG_LIGHTMAP_ON_UV2) && p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_TEX_UV2) { + + uv2=a[Mesh::ARRAY_TEX_UV2]; + uv2r=uv2.read(); + + } else { + uv2r=uv.read(); + if (baked_light->get_transfer_lightmaps_only_to_uv2()) { + baked_tex=-1; + } + } } if (p_mesh->surface_get_format(i)&Mesh::ARRAY_FORMAT_NORMAL) { @@ -145,11 +160,16 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m t.vertices[1]=p_xform.xform(vr[ ir[i*3+1] ]); t.vertices[2]=p_xform.xform(vr[ ir[i*3+2] ]); t.material=matptr; + t.baked_texture=baked_tex; if (read_uv) { t.uvs[0]=uvr[ ir[i*3+0] ]; t.uvs[1]=uvr[ ir[i*3+1] ]; t.uvs[2]=uvr[ ir[i*3+2] ]; + + t.bake_uvs[0]=uv2r[ ir[i*3+0] ]; + t.bake_uvs[1]=uv2r[ ir[i*3+1] ]; + t.bake_uvs[2]=uv2r[ ir[i*3+2] ]; } if (read_normal) { @@ -167,11 +187,17 @@ void BakedLightBaker::_add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_m t.vertices[1]=p_xform.xform(vr[ i*3+1 ]); t.vertices[2]=p_xform.xform(vr[ i*3+2 ]); t.material=matptr; + t.baked_texture=baked_tex; if (read_uv) { t.uvs[0]=uvr[ i*3+0 ]; t.uvs[1]=uvr[ i*3+1 ]; t.uvs[2]=uvr[ i*3+2 ]; + + t.bake_uvs[0]=uv2r[ i*3+0 ]; + t.bake_uvs[1]=uv2r[ i*3+1 ]; + t.bake_uvs[2]=uv2r[ i*3+2 ]; + } if (read_normal) { @@ -193,7 +219,7 @@ void BakedLightBaker::_parse_geometry(Node* p_node) { MeshInstance *meshi=p_node->cast_to<MeshInstance>(); Ref<Mesh> mesh=meshi->get_mesh(); if (mesh.is_valid()) { - _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform()); + _add_mesh(mesh,meshi->get_material_override(),base_inv * meshi->get_global_transform(),meshi->get_baked_light_texture_id()); } } else if (p_node->cast_to<Light>()) { @@ -214,9 +240,11 @@ void BakedLightBaker::_parse_geometry(Node* p_node) { dirl.spot_angle=dl->get_parameter(DirectionalLight::PARAM_SPOT_ANGLE); dirl.spot_attenuation=dl->get_parameter(DirectionalLight::PARAM_SPOT_ATTENUATION); dirl.attenuation=dl->get_parameter(DirectionalLight::PARAM_ATTENUATION); + dirl.darkening=dl->get_parameter(DirectionalLight::PARAM_SHADOW_DARKENING); dirl.radius=dl->get_parameter(DirectionalLight::PARAM_RADIUS); dirl.bake_direct=dl->get_bake_mode()==Light::BAKE_MODE_FULL; dirl.rays_thrown=0; + dirl.bake_shadow=dl->get_bake_mode()==Light::BAKE_MODE_INDIRECT_AND_SHADOWS; lights.push_back(dirl); } @@ -720,7 +748,7 @@ void BakedLightBaker::_plot_light(int p_light_index, const Vector3& p_plot_pos, float intensity = 1.0 - (d/r)*(d/r); //not gauss but.. float damp = Math::abs(p_plane.normal.dot(Vector3(octant.normal_accum[i][0],octant.normal_accum[i][1],octant.normal_accum[i][2]))); intensity*=pow(damp,edge_damp); - intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); + //intensity*=1.0-Math::abs(p_plane.distance_to(pos))/(plot_size*cell_size); octant.light[p_light_index].accum[i][0]+=p_light.r*intensity; octant.light[p_light_index].accum[i][1]+=p_light.g*intensity; octant.light[p_light_index].accum[i][2]+=p_light.b*intensity; @@ -1310,7 +1338,7 @@ double BakedLightBaker::get_normalization(int p_light_idx) const { nrg*=(Math_PI*plot_size*plot_size)*0.5; // damping of radial linear gradient kernel nrg*=dl.constant; //nrg*=5; - print_line("CS: "+rtos(cell_size)); + return nrg; } @@ -1460,6 +1488,13 @@ void BakedLightBaker::bake(const Ref<BakedLight> &p_light, Node* p_node) { normal_damp=baked_light->get_normal_damp(); octree_extra_margin=baked_light->get_cell_extra_margin(); + baked_textures.clear(); + for(int i=0;i<baked_light->get_lightmaps_count();i++) { + BakeTexture bt; + bt.width=baked_light->get_lightmap_gen_size(i).x; + bt.height=baked_light->get_lightmap_gen_size(i).y; + baked_textures.push_back(bt); + } ep.step("Parsing Geometry",0); @@ -1690,6 +1725,484 @@ void BakedLightBaker::_stop_thread() { thread=NULL; } +void BakedLightBaker::_plot_pixel_to_lightmap(int x, int y, int width, int height, uint8_t *image, const Vector3& p_pos,const Vector3& p_normal,double *p_norm_ptr,float mult,float gamma) { + + + uint8_t *ptr = &image[(y*width+x)*4]; + int lc = lights.size(); + + + Color color; + + Octant *octants=octant_pool.ptr(); + + + int octant_idx=0; + + + while(true) { + + Octant &octant=octants[octant_idx]; + + if (octant.leaf) { + + Vector3 lpos = p_pos-octant.aabb.pos; + lpos/=octant.aabb.size; + + Vector3 cols[8]; + + for(int i=0;i<8;i++) { + + for(int j=0;j<lc;j++) { + cols[i].x+=octant.light[j].accum[i][0]*p_norm_ptr[j]; + cols[i].y+=octant.light[j].accum[i][1]*p_norm_ptr[j]; + cols[i].z+=octant.light[j].accum[i][2]*p_norm_ptr[j]; + } + } + + + /*Vector3 final = (cols[0] + (cols[1] - cols[0]) * lpos.y); + final = final + ((cols[2] + (cols[3] - cols[2]) * lpos.y) - final)*lpos.x; + + Vector3 final2 = (cols[4+0] + (cols[4+1] - cols[4+0]) * lpos.y); + final2 = final2 + ((cols[4+2] + (cols[4+3] - cols[4+2]) * lpos.y) - final2)*lpos.x;*/ + + Vector3 finala = cols[0].linear_interpolate(cols[1],lpos.x); + Vector3 finalb = cols[2].linear_interpolate(cols[3],lpos.x); + Vector3 final = finala.linear_interpolate(finalb,lpos.y); + + Vector3 final2a = cols[4+0].linear_interpolate(cols[4+1],lpos.x); + Vector3 final2b = cols[4+2].linear_interpolate(cols[4+3],lpos.x); + Vector3 final2 = final2a.linear_interpolate(final2b,lpos.y); + + final = final.linear_interpolate(final2,lpos.z); + if (baked_light->get_format()==BakedLight::FORMAT_HDR8) + final*=8.0; + + + color.r=pow(final.x*mult,gamma); + color.g=pow(final.y*mult,gamma); + color.b=pow(final.z*mult,gamma); + color.a=1.0; + + int lc = lights.size(); + LightData *lv = lights.ptr(); + for(int i=0;i<lc;i++) { + //shadow baking + if (!lv[i].bake_shadow) + continue; + Vector3 from = p_pos+p_normal*0.01; + Vector3 to; + float att=0; + switch(lv[i].type) { + case VS::LIGHT_DIRECTIONAL: { + to=from-lv[i].dir*lv[i].length; + } break; + case VS::LIGHT_OMNI: { + to=lv[i].pos; + float d = MIN(lv[i].radius,to.distance_to(from))/lv[i].radius; + att=d;//1.0-d; + } break; + default: continue; + } + + uint32_t* stack = ray_stack; + BVH **bstack = bvh_stack; + + enum { + TEST_RAY_BIT=0, + VISIT_LEFT_BIT=1, + VISIT_RIGHT_BIT=2, + VISIT_DONE_BIT=3, + + + }; + + bool intersected=false; + + int level=0; + + Vector3 n = (to-from); + float len=n.length(); + if (len==0) + continue; + n/=len; + + const BVH *bvhptr = bvh; + + bstack[0]=bvh; + stack[0]=TEST_RAY_BIT; + + + while(!intersected) { + + uint32_t mode = stack[level]; + const BVH &b = *bstack[level]; + bool done=false; + + switch(mode) { + case TEST_RAY_BIT: { + + if (b.leaf) { + + + Face3 f3(b.leaf->vertices[0],b.leaf->vertices[1],b.leaf->vertices[2]); + + + Vector3 res; + + if (f3.intersects_segment(from,to)) { + intersected=true; + done=true; + } + + stack[level]=VISIT_DONE_BIT; + } else { + + + bool valid = b.aabb.smits_intersect_ray(from,n,0,len); + //bool valid = b.aabb.intersects_segment(p_begin,p_end); + // bool valid = b.aabb.intersects(ray_aabb); + + if (!valid) { + + stack[level]=VISIT_DONE_BIT; + + } else { + + stack[level]=VISIT_LEFT_BIT; + } + } + + } continue; + case VISIT_LEFT_BIT: { + + stack[level]=VISIT_RIGHT_BIT; + bstack[level+1]=b.children[0]; + stack[level+1]=TEST_RAY_BIT; + level++; + + } continue; + case VISIT_RIGHT_BIT: { + + stack[level]=VISIT_DONE_BIT; + bstack[level+1]=b.children[1]; + stack[level+1]=TEST_RAY_BIT; + level++; + } continue; + case VISIT_DONE_BIT: { + + if (level==0) { + done=true; + break; + } else + level--; + + } continue; + } + + + if (done) + break; + } + + + + if (intersected) { + + color.a=Math::lerp(MAX(0.01,lv[i].darkening),1.0,att); + } + + } + + break; + } else { + + Vector3 lpos = p_pos - octant.aabb.pos; + Vector3 half = octant.aabb.size * 0.5; + + int ofs=0; + + if (lpos.x >= half.x) + ofs|=1; + if (lpos.y >= half.y) + ofs|=2; + if (lpos.z >= half.z) + ofs|=4; + + octant_idx = octant.children[ofs]; + + if (octant_idx==0) + return; + + } + } + + ptr[0]=CLAMP(color.r*255.0,0,255); + ptr[1]=CLAMP(color.g*255.0,0,255); + ptr[2]=CLAMP(color.b*255.0,0,255); + ptr[3]=CLAMP(color.a*255.0,0,255); + +} + + +Error BakedLightBaker::transfer_to_lightmaps() { + + if (!triangles.size() || baked_textures.size()==0) + return ERR_UNCONFIGURED; + + EditorProgress ep("transfer_to_lightmaps","Transfer to Lightmaps:",baked_textures.size()*2+triangles.size()); + + for(int i=0;i<baked_textures.size();i++) { + + ERR_FAIL_COND_V( baked_textures[i].width<=0 || baked_textures[i].height<=0,ERR_UNCONFIGURED ); + + baked_textures[i].data.resize( baked_textures[i].width*baked_textures[i].height*4 ); + zeromem(baked_textures[i].data.ptr(),baked_textures[i].data.size()); + ep.step("Allocating Texture #"+itos(i+1),i); + } + + Vector<double> norm_arr; + norm_arr.resize(lights.size()); + + for(int i=0;i<lights.size();i++) { + norm_arr[i] = 1.0/get_normalization(i); + } + float gamma = baked_light->get_gamma_adjust(); + float mult = baked_light->get_energy_multiplier(); + + + const double *normptr=norm_arr.ptr(); + for(int i=0;i<triangles.size();i++) { + + if (i%200==0) { + ep.step("Baking Triangle #"+itos(i),i+baked_textures.size()); + } + Triangle &t=triangles[i]; + if (t.baked_texture<0 || t.baked_texture>=baked_textures.size()) + continue; + + BakeTexture &bt=baked_textures[t.baked_texture]; + Vector3 normal = Plane(t.vertices[0],t.vertices[1],t.vertices[2]).normal; + + + int x[3]; + int y[3]; + + Vector3 vertices[3]={ + t.vertices[0], + t.vertices[1], + t.vertices[2] + }; + + for(int j=0;j<3;j++) { + + x[j]=t.bake_uvs[j].x*bt.width; + y[j]=t.bake_uvs[j].y*bt.height; + x[j]=CLAMP(x[j],0,bt.width-1); + y[j]=CLAMP(y[j],0,bt.height-1); + } + + + { + + // sort the points vertically + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + SWAP(vertices[1],vertices[2]); + } + if (y[0] > y[1]) { + SWAP(x[0], x[1]); + SWAP(y[0], y[1]); + SWAP(vertices[0],vertices[1]); + } + if (y[1] > y[2]) { + SWAP(x[1], x[2]); + SWAP(y[1], y[2]); + SWAP(vertices[1],vertices[2]); + } + + double dx_far = double(x[2] - x[0]) / (y[2] - y[0] + 1); + double dx_upper = double(x[1] - x[0]) / (y[1] - y[0] + 1); + double dx_low = double(x[2] - x[1]) / (y[2] - y[1] + 1); + double xf = x[0]; + double xt = x[0] + dx_upper; // if y[0] == y[1], special case + for (int yi = y[0]; yi <= (y[2] > bt.height-1 ? bt.height-1 : y[2]); yi++) + { + if (yi >= 0) { + for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < bt.width ? xt : bt.width-1) ; xi++) { + //pixels[int(x + y * width)] = color; + + Vector2 v0 = Vector2(x[1]-x[0],y[1]-y[0]); + Vector2 v1 = Vector2(x[2]-x[0],y[2]-y[0]); + //vertices[2] - vertices[0]; + Vector2 v2 = Vector2(xi-x[0],yi-y[0]); + float d00 = v0.dot( v0); + float d01 = v0.dot( v1); + float d11 = v1.dot( v1); + float d20 = v2.dot( v0); + float d21 = v2.dot( v1); + float denom = (d00 * d11 - d01 * d01); + Vector3 pos; + if (denom==0) { + pos=t.vertices[0]; + } else { + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + pos = vertices[0]*u + vertices[1]*v + vertices[2]*w; + } + _plot_pixel_to_lightmap(xi,yi,bt.width,bt.height,bt.data.ptr(),pos,normal,norm_arr.ptr(),mult,gamma); + + } + + for (int xi = (xf < bt.width ? int(xf) : bt.width-1); xi >= (xt > 0 ? xt : 0); xi--) { + //pixels[int(x + y * width)] = color; + Vector2 v0 = Vector2(x[1]-x[0],y[1]-y[0]); + Vector2 v1 = Vector2(x[2]-x[0],y[2]-y[0]); + //vertices[2] - vertices[0]; + Vector2 v2 = Vector2(xi-x[0],yi-y[0]); + float d00 = v0.dot( v0); + float d01 = v0.dot( v1); + float d11 = v1.dot( v1); + float d20 = v2.dot( v0); + float d21 = v2.dot( v1); + float denom = (d00 * d11 - d01 * d01); + Vector3 pos; + if (denom==0) { + pos=t.vertices[0]; + } else { + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0f - v - w; + pos = vertices[0]*u + vertices[1]*v + vertices[2]*w; + } + + _plot_pixel_to_lightmap(xi,yi,bt.width,bt.height,bt.data.ptr(),pos,normal,norm_arr.ptr(),mult,gamma); + + } + } + xf += dx_far; + if (yi < y[1]) + xt += dx_upper; + else + xt += dx_low; + } + } + + } + + + for(int i=0;i<baked_textures.size();i++) { + + + { + + ep.step("Post-Processing Texture #"+itos(i),i+baked_textures.size()+triangles.size()); + + BakeTexture &bt=baked_textures[i]; + + Vector<uint8_t> copy_data=bt.data; + uint8_t *data=bt.data.ptr(); + uint8_t *src_data=copy_data.ptr(); + const int max_radius=8; + const int shadow_radius=2; + const int max_dist=0x7FFFFFFF; + + for(int x=0;x<bt.width;x++) { + + for(int y=0;y<bt.height;y++) { + + + uint8_t a = copy_data[(y*bt.width+x)*4+3]; + + if (a>0) { + //blur shadow + + int from_x = MAX(0,x-shadow_radius); + int to_x = MIN(bt.width-1,x+shadow_radius); + int from_y = MAX(0,y-shadow_radius); + int to_y = MIN(bt.height-1,y+shadow_radius); + + int sum=0; + int sumc=0; + + for(int k=from_y;k<=to_y;k++) { + for(int l=from_x;l<=to_x;l++) { + + const uint8_t * rp = ©_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<uint8_t> dv; + dv.resize(baked_textures[i].data.size()); + { + DVector<uint8_t>::Write w = dv.write(); + copymem(w.ptr(),baked_textures[i].data.ptr(),baked_textures[i].data.size()); + } + + Image img(baked_textures[i].width,baked_textures[i].height,0,Image::FORMAT_RGBA,dv); + Ref<ImageTexture> tex = memnew( ImageTexture ); + tex->create_from_image(img); + baked_light->set_lightmap_texture(i,tex); + } + + + return OK; +} + void BakedLightBaker::clear() { @@ -1711,7 +2224,14 @@ void BakedLightBaker::clear() { for(int i=0;i<octant_pool.size();i++) { if (octant_pool[i].leaf) { memdelete_arr( octant_pool[i].light ); + } Vector<double> norm_arr; + norm_arr.resize(lights.size()); + + for(int i=0;i<lights.size();i++) { + norm_arr[i] = 1.0/get_normalization(i); } + + const double *normptr=norm_arr.ptr(); } octant_pool.clear(); octant_pool_size=0; diff --git a/tools/editor/plugins/baked_light_baker.h b/tools/editor/plugins/baked_light_baker.h index 99c8211eed..722255a565 100644 --- a/tools/editor/plugins/baked_light_baker.h +++ b/tools/editor/plugins/baked_light_baker.h @@ -94,11 +94,13 @@ public: struct Triangle { - AABB aabb; + AABB aabb; Vector3 vertices[3]; Vector2 uvs[3]; + Vector2 bake_uvs[3]; Vector3 normals[3]; MeshMaterial *material; + int baked_texture; _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos) { @@ -180,6 +182,12 @@ public: } }; + struct BakeTexture { + + Vector<uint8_t> data; + int width,height; + }; + struct LightData { @@ -194,10 +202,12 @@ public: float energy; float length; int rays_thrown; + bool bake_shadow; float radius; float attenuation; float spot_angle; + float darkening; float spot_attenuation; float area; @@ -220,6 +230,7 @@ public: int octant_pool_size; BVH*bvh; Vector<Triangle> triangles; + Vector<BakeTexture> baked_textures; Transform base_inv; int leaf_list; int octree_depth; @@ -255,13 +266,14 @@ public: MeshTexture* _get_mat_tex(const Ref<Texture>& p_tex); - void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform); + void _add_mesh(const Ref<Mesh>& p_mesh,const Ref<Material>& p_mat_override,const Transform& p_xform,int p_baked_texture=-1); void _parse_geometry(Node* p_node); BVH* _parse_bvh(BVH** p_children,int p_size,int p_depth,int& max_depth); void _make_bvh(); void _make_octree(); void _make_octree_texture(); void _octree_insert(int p_octant, Triangle* p_triangle, int p_depth); + _FORCE_INLINE_ void _plot_pixel_to_lightmap(int x, int y, int width, int height, uint8_t *image, const Vector3& p_pos,const Vector3& p_normal,double *p_norm_ptr,float mult,float gamma); void _free_bvh(BVH* p_bvh); @@ -302,6 +314,8 @@ public: bool is_paused(); int get_rays_sec() { return rays_sec; } + Error transfer_to_lightmaps(); + void update_octree_image(DVector<uint8_t> &p_image); Ref<BakedLight> get_baked_light() { return baked_light; } 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<Spatial>(); + if (!ci->is_visible() && ci->get_parent_spatial() && !ci->get_parent_spatial()->is_visible()) { + error->set_text("This item cannot be made visible because the parent is hidden. Unhide the parent first."); + error->popup_centered_minsize(Size2(400,80)); + return; + } + + bool v = !bool(n->call("is_hidden")); + undo_redo->create_action("Toggle Spatial Visible"); + undo_redo->add_do_method(n,"_set_visible_",!v); + undo_redo->add_undo_method(n,"_set_visible_",v); undo_redo->commit_action(); } else if (n->is_type("CanvasItem")) { @@ -189,9 +197,9 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { if (!p_node->is_connected("visibility_changed",this,"_node_visibility_changed")) p_node->connect("visibility_changed",this,"_node_visibility_changed",varray(p_node)); - } else if (p_node->is_type("GeometryInstance")) { + } else if (p_node->is_type("Spatial")) { - bool h = !p_node->call("get_flag",VS::INSTANCE_FLAG_VISIBLE); + bool h = p_node->call("is_hidden"); if (h) item->add_button(0,get_icon("Hidden","EditorIcons"),BUTTON_VISIBILITY); else @@ -226,7 +234,16 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) { void SceneTreeEditor::_node_visibility_changed(Node *p_node) { + + if (p_node!=get_scene_node() && !p_node->get_owner()) { + + return; + } TreeItem* item=p_node?_find(tree->get_root(),p_node->get_path()):NULL; + if (!item) { + + return; + } int idx=item->get_button_by_id(0,BUTTON_VISIBILITY); ERR_FAIL_COND(idx==-1); @@ -234,11 +251,10 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) { if (p_node->is_type("CanvasItem")) { visible = !p_node->call("is_hidden"); - } else if (p_node->is_type("GeometryInstance")) { - visible = p_node->call("get_flag",VS::INSTANCE_FLAG_VISIBLE); + } else if (p_node->is_type("Spatial")) { + visible = !p_node->call("is_hidden"); } - if (!visible) item->set_button(0,idx,get_icon("Hidden","EditorIcons")); else @@ -274,7 +290,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) { if (p_node->is_connected("script_changed",this,"_node_script_changed")) p_node->disconnect("script_changed",this,"_node_script_changed"); - if (p_node->is_type("GeometryInstance") || p_node->is_type("CanvasItem")) { + if (p_node->is_type("Spatial") || p_node->is_type("CanvasItem")) { if (p_node->is_connected("visibility_changed",this,"_node_visibility_changed")) p_node->disconnect("visibility_changed",this,"_node_visibility_changed"); } 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 @@ -293,6 +293,9 @@ class DaeExporter: self.writel(S_FX,6,'</bump>') self.writel(S_FX,5,'</technique>') + self.writel(S_FX,5,'<technique profile="GOOGLEEARTH">') + self.writel(S_FX,6,'<double_sided>'+["0","1"][double_sided_hint]+"</double_sided>") + self.writel(S_FX,5,'</technique>') self.writel(S_FX,4,'</extra>') self.writel(S_FX,3,'</technique>') @@ -359,7 +362,7 @@ class DaeExporter: mat= None if (mat!=None): - materials[f.material_index]=self.export_material( mat ) + materials[f.material_index]=self.export_material( mat,mesh.show_double_sided ) else: materials[f.material_index]=None #weird, has no material? @@ -730,7 +733,7 @@ class DaeExporter: self.writel(S_LAMPS,2,'<optics>') self.writel(S_LAMPS,3,'<technique_common>') - if (light.type=="POINT" or light.type=="HEMI"): + if (light.type=="POINT"): self.writel(S_LAMPS,4,'<point>') self.writel(S_LAMPS,5,'<color>'+strarr(light.color)+'</color>') att_by_distance = 2.0 / light.distance # convert to linear attenuation |