From 703004f830f39adcde9b9565f1aa49d1b10e8d27 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 16 Jun 2014 10:22:26 -0300 Subject: [PATCH] More 3D Work -=-=-=-=-=- -ESM Shadow Mapping for softer and less glitchy shadows -HDR Pipeline (convert to Linear on texture import, convert to SRGB at the end) -Fix to xml parse bug --- core/color.h | 11 + core/image.cpp | 39 ++ core/image.h | 1 + demos/3d/platformer/engine.cfg | 4 +- demos/3d/platformer/stage.xml | 23 +- demos/3d/platformer/texture.tex | Bin 17820 -> 17792 bytes drivers/gles1/rasterizer_gles1.cpp | 5 + drivers/gles1/rasterizer_gles1.h | 2 +- drivers/gles2/rasterizer_gles2.cpp | 295 ++++++++++--- drivers/gles2/rasterizer_gles2.h | 8 +- drivers/gles2/shader_gles2.h | 2 + drivers/gles2/shaders/copy.glsl | 157 ++++++- drivers/gles2/shaders/material.glsl | 61 ++- modules/gdscript/gd_compiler.cpp | 10 +- modules/gdscript/gd_functions.cpp | 13 + modules/gdscript/gd_functions.h | 1 + modules/gdscript/gd_script.cpp | 2 + modules/gdscript/gd_script.h | 1 + platform/flash/rasterizer_flash.h | 2 +- scene/3d/light.cpp | 8 +- scene/3d/light.h | 2 + scene/main/node.cpp | 13 + scene/main/node.h | 1 + scene/register_scene_types.cpp | 2 + scene/resources/environment.cpp | 9 +- scene/resources/environment.h | 3 +- scene/resources/polygon_path_finder.cpp | 413 ++++++++++++++++++ scene/resources/polygon_path_finder.h | 58 +++ servers/visual/rasterizer.h | 2 + servers/visual/rasterizer_dummy.cpp | 6 + servers/visual/rasterizer_dummy.h | 3 +- servers/visual/visual_server_raster.cpp | 6 +- servers/visual/visual_server_wrap_mt.cpp | 2 + servers/visual/visual_server_wrap_mt.h | 28 +- servers/visual_server.h | 5 +- tools/editor/editor_node.cpp | 2 +- .../editor_texture_import_plugin.cpp | 11 + .../io_plugins/editor_texture_import_plugin.h | 3 +- tools/editor/plugins/baked_light_baker.cpp | 14 +- .../plugins/baked_light_editor_plugin.cpp | 2 +- 40 files changed, 1114 insertions(+), 116 deletions(-) create mode 100644 scene/resources/polygon_path_finder.cpp create mode 100644 scene/resources/polygon_path_finder.h diff --git a/core/color.h b/core/color.h index 9b5850f56b6e..491c72d4495a 100644 --- a/core/color.h +++ b/core/color.h @@ -30,6 +30,7 @@ #define COLOR_H #include "ustring.h" +#include "math_funcs.h" /** @author Juan Linietsky */ @@ -97,6 +98,16 @@ struct Color { return res; } + _FORCE_INLINE_ Color to_linear() const { + + return Color( + r<0.04045 ? r * (1.0 / 12.92) : Math::pow((r + 0.055) * (1.0 / (1 + 0.055)), 2.4), + g<0.04045 ? g * (1.0 / 12.92) : Math::pow((g + 0.055) * (1.0 / (1 + 0.055)), 2.4), + b<0.04045 ? b * (1.0 / 12.92) : Math::pow((b + 0.055) * (1.0 / (1 + 0.055)), 2.4), + a + ); + } + static Color hex(uint32_t p_hex); static Color html(const String& p_color); static bool html_is_valid(const String& p_color); diff --git a/core/image.cpp b/core/image.cpp index b577117f1e27..e5489c06fa8b 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1664,6 +1664,45 @@ void Image::set_compress_bc_func(void (*p_compress_func)(Image *)) { +void Image::srgb_to_linear() { + + if (data.size()==0) + return; + + static const uint8_t srgb2lin[256]={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, 155, 157, 159, 160, 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, 250, 252}; + + + ERR_FAIL_COND( format!=FORMAT_RGB && format!=FORMAT_RGBA ); + + if (format==FORMAT_RGBA) { + + int len = data.size()/4; + DVector::Write wp = data.write(); + unsigned char *data_ptr=wp.ptr(); + + for(int i=0;i::Write wp = data.write(); + unsigned char *data_ptr=wp.ptr(); + + for(int i=0;i + + - - False 4 @@ -50,13 +50,14 @@ "names" - + "world" "Spatial" "__meta__" "GridMap" "theme/theme" "theme/bake" + "lighting/bake" "cell/size" "cell/octant_size" "cell/center_x" @@ -67,6 +68,8 @@ "DirectionalLight" "transform/local" "layers" + "params/enabled" + "params/bake_mode" "params/energy" "colors/ambient" "colors/diffuse" @@ -172,17 +175,17 @@ "distance" - 6.622579 + 4.173348 "x_rot" - 0.358295 + 0.558294 "y_rot" - 0.45 + 1.049999 "use_orthogonal" False "use_environment" False "pos" - 9.41795, 2.98588, 13.6496 + 13.4293, 5.68289, 13.9717 "distance" @@ -267,14 +270,14 @@ 0.522923, 0.663002, -0.535706, -0.24539, 0.718971, 0.650281, 0.816294, -0.20859, 0.53866, 0, 0, 0 1 + 0 1.5 0.159092, 0.219774, 0.52093, 1 1, 1, 1, 1 0 0.08 0.5 - 0 - 2 + 2 40 0.410558 @@ -336,7 +339,7 @@ 0.0160676, 0, -0.999871, 0, 1, 0, 0.999871, 0, 0.0160676, 8.50167, 4.15811, 15.9334 "nodes" - -1, -1, 1, 0, -1, 1, 2, 0, 0, 0, 0, 3, 3, -1, 10, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 5, 10, 5, 11, 6, 12, 7, 2, 8, 0, 0, 0, 13, 13, -1, 16, 14, 9, 15, 10, 16, 11, 17, 12, 18, 13, 19, 13, 20, 5, 21, 14, 22, 15, 23, 16, 24, 17, 25, 18, 26, 19, 27, 20, 28, 21, 29, 3, 0, 0, 0, 31, 30, -1, 1, 30, 22, 0, 0, 0, 33, 32, -1, 1, 2, 23, 0, 4, 0, 35, 34, 24, 1, 14, 25, 0, 4, 0, 35, 36, 24, 1, 14, 26, 0, 4, 0, 35, 37, 24, 1, 14, 27, 0, 4, 0, 35, 38, 24, 1, 14, 28, 0, 4, 0, 35, 39, 24, 1, 14, 29, 0, 4, 0, 35, 40, 24, 1, 14, 30, 0, 4, 0, 35, 41, 24, 1, 14, 31, 0, 4, 0, 35, 42, 24, 1, 14, 32, 0, 4, 0, 35, 43, 24, 1, 14, 33, 0, 4, 0, 35, 44, 24, 1, 14, 34, 0, 4, 0, 35, 45, 24, 1, 14, 35, 0, 4, 0, 35, 46, 24, 1, 14, 36, 0, 4, 0, 35, 47, 24, 1, 14, 37, 0, 4, 0, 35, 48, 24, 1, 14, 38, 0, 4, 0, 35, 49, 24, 1, 14, 39, 0, 4, 0, 35, 50, 24, 1, 14, 40, 0, 4, 0, 35, 51, 24, 1, 14, 41, 0, 4, 0, 35, 52, 24, 1, 14, 42, 0, 4, 0, 35, 53, 24, 1, 14, 43, 0, 4, 0, 35, 54, 24, 1, 14, 44, 0, 4, 0, 35, 55, 24, 1, 14, 45, 0, 4, 0, 35, 56, 24, 1, 14, 46, 0, 4, 0, 35, 57, 24, 1, 14, 47, 0, 4, 0, 35, 58, 24, 1, 14, 48, 0, 4, 0, 35, 59, 24, 1, 14, 49, 0, 4, 0, 35, 60, 24, 1, 14, 50, 0, 4, 0, 35, 61, 24, 1, 14, 51, 0, 4, 0, 35, 62, 24, 1, 14, 52, 0, 4, 0, 35, 63, 24, 1, 14, 53, 0, 4, 0, 35, 64, 24, 1, 14, 54, 0, 4, 0, 35, 65, 24, 1, 14, 55, 0, 4, 0, 35, 66, 24, 1, 14, 56, 0, 4, 0, 35, 67, 24, 1, 14, 57, 0, 4, 0, 35, 68, 24, 1, 14, 58, 0, 4, 0, 35, 69, 24, 1, 14, 59, 0, 4, 0, 35, 70, 24, 1, 14, 60, 0, 4, 0, 35, 71, 24, 1, 14, 61, 0, 4, 0, 35, 72, 24, 1, 14, 62, 0, 4, 0, 35, 73, 24, 1, 14, 63, 0, 4, 0, 35, 74, 24, 1, 14, 64, 0, 4, 0, 35, 75, 24, 1, 14, 65, 0, 4, 0, 35, 76, 24, 1, 14, 66, 0, 4, 0, 35, 77, 24, 1, 14, 67, 0, 4, 0, 35, 78, 24, 1, 14, 68, 0, 0, 0, 33, 79, -1, 0, 0, 49, 0, 81, 80, 69, 1, 14, 70, 0, 49, 0, 81, 82, 69, 1, 14, 71, 0, 49, 0, 81, 83, 69, 1, 14, 72, 0, 49, 0, 81, 84, 69, 1, 14, 73, 0, 0, 0, 81, 85, 74, 1, 14, 75, 0 + -1, -1, 1, 0, -1, 1, 2, 0, 0, 0, 0, 3, 3, -1, 11, 4, 1, 5, 2, 6, 2, 7, 3, 8, 4, 9, 5, 10, 5, 11, 5, 12, 6, 13, 7, 2, 8, 0, 0, 0, 14, 14, -1, 18, 15, 9, 16, 10, 17, 5, 18, 11, 19, 12, 20, 13, 21, 14, 22, 14, 23, 5, 24, 15, 25, 16, 26, 17, 27, 18, 28, 11, 29, 19, 30, 20, 31, 21, 32, 3, 0, 0, 0, 34, 33, -1, 1, 33, 22, 0, 0, 0, 36, 35, -1, 1, 2, 23, 0, 4, 0, 38, 37, 24, 1, 15, 25, 0, 4, 0, 38, 39, 24, 1, 15, 26, 0, 4, 0, 38, 40, 24, 1, 15, 27, 0, 4, 0, 38, 41, 24, 1, 15, 28, 0, 4, 0, 38, 42, 24, 1, 15, 29, 0, 4, 0, 38, 43, 24, 1, 15, 30, 0, 4, 0, 38, 44, 24, 1, 15, 31, 0, 4, 0, 38, 45, 24, 1, 15, 32, 0, 4, 0, 38, 46, 24, 1, 15, 33, 0, 4, 0, 38, 47, 24, 1, 15, 34, 0, 4, 0, 38, 48, 24, 1, 15, 35, 0, 4, 0, 38, 49, 24, 1, 15, 36, 0, 4, 0, 38, 50, 24, 1, 15, 37, 0, 4, 0, 38, 51, 24, 1, 15, 38, 0, 4, 0, 38, 52, 24, 1, 15, 39, 0, 4, 0, 38, 53, 24, 1, 15, 40, 0, 4, 0, 38, 54, 24, 1, 15, 41, 0, 4, 0, 38, 55, 24, 1, 15, 42, 0, 4, 0, 38, 56, 24, 1, 15, 43, 0, 4, 0, 38, 57, 24, 1, 15, 44, 0, 4, 0, 38, 58, 24, 1, 15, 45, 0, 4, 0, 38, 59, 24, 1, 15, 46, 0, 4, 0, 38, 60, 24, 1, 15, 47, 0, 4, 0, 38, 61, 24, 1, 15, 48, 0, 4, 0, 38, 62, 24, 1, 15, 49, 0, 4, 0, 38, 63, 24, 1, 15, 50, 0, 4, 0, 38, 64, 24, 1, 15, 51, 0, 4, 0, 38, 65, 24, 1, 15, 52, 0, 4, 0, 38, 66, 24, 1, 15, 53, 0, 4, 0, 38, 67, 24, 1, 15, 54, 0, 4, 0, 38, 68, 24, 1, 15, 55, 0, 4, 0, 38, 69, 24, 1, 15, 56, 0, 4, 0, 38, 70, 24, 1, 15, 57, 0, 4, 0, 38, 71, 24, 1, 15, 58, 0, 4, 0, 38, 72, 24, 1, 15, 59, 0, 4, 0, 38, 73, 24, 1, 15, 60, 0, 4, 0, 38, 74, 24, 1, 15, 61, 0, 4, 0, 38, 75, 24, 1, 15, 62, 0, 4, 0, 38, 76, 24, 1, 15, 63, 0, 4, 0, 38, 77, 24, 1, 15, 64, 0, 4, 0, 38, 78, 24, 1, 15, 65, 0, 4, 0, 38, 79, 24, 1, 15, 66, 0, 4, 0, 38, 80, 24, 1, 15, 67, 0, 4, 0, 38, 81, 24, 1, 15, 68, 0, 0, 0, 36, 82, -1, 0, 0, 49, 0, 84, 83, 69, 1, 15, 70, 0, 49, 0, 84, 85, 69, 1, 15, 71, 0, 49, 0, 84, 86, 69, 1, 15, 72, 0, 49, 0, 84, 87, 69, 1, 15, 73, 0, 0, 0, 84, 88, 74, 1, 15, 75, 0 "conns" diff --git a/demos/3d/platformer/texture.tex b/demos/3d/platformer/texture.tex index 92749fc98bb66a235c232b2d556f220a3ab77002..439a007d26248dfbdcb2d3b1022dd29992d50106 100644 GIT binary patch literal 17792 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 literal 17820 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 +} + void RasterizerGLES2::light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { LightInstance *lighti = light_instance_owner.get( p_light_instance ); @@ -3590,9 +3600,10 @@ void RasterizerGLES2::begin_frame() { glFrontFace(GL_CW); //fragment_lighting=Globals::get_singleton()->get("rasterizer/use_fragment_lighting"); +#ifdef TOOLS_ENABLED canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false)); shadow_filter=ShadowFilterTechnique(int(Globals::get_singleton()->get("rasterizer/shadow_filter"))); - +#endif window_size = Size2( OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height ); @@ -4302,6 +4313,13 @@ void RasterizerGLES2::add_particles( const RID& p_particle_instance, const Insta } +Color RasterizerGLES2::_convert_color(const Color& p_color) { + + if (current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]) + return p_color.to_linear(); + else + return p_color; +} void RasterizerGLES2::_set_cull(bool p_front,bool p_reverse_cull) { @@ -4383,9 +4401,9 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material //all goes to false by default material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PASS,shadow!=NULL); - material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF,shadow_filter!=SHADOW_FILTER_NONE); - material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_PCF_HQ,shadow_filter>SHADOW_FILTER_PCF5); - //material_shader.set_conditional(MaterialShaderGLES2::USE_SHADOW_ESM,true); + 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); if (p_opaque_pass && p_material->hints[VS::MATERIAL_HINT_OPAQUE_PRE_PASS] && p_material->shader_cache && p_material->shader_cache->has_alpha) { @@ -4484,6 +4502,9 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material glBindTexture(GL_TEXTURE_2D,white_tex); //no texture texcoord++; + } else if (E->get().value.get_type()==Variant::COLOR){ + Color c = E->get().value; + material_shader.set_custom_uniform(E->get().index,_convert_color(c)); } else { material_shader.set_custom_uniform(E->get().index,E->get().value); } @@ -4534,6 +4555,8 @@ bool RasterizerGLES2::_setup_material(const Geometry *p_geometry,const Material Color col_begin = current_env->fx_param[VS::ENV_FX_PARAM_FOG_BEGIN_COLOR]; Color col_end = current_env->fx_param[VS::ENV_FX_PARAM_FOG_END_COLOR]; + col_begin=_convert_color(col_begin); + col_end=_convert_color(col_end); float from = current_env->fx_param[VS::ENV_FX_PARAM_FOG_BEGIN]; float zf = camera_z_far; float curve = current_env->fx_param[VS::ENV_FX_PARAM_FOG_ATTENUATION]; @@ -4588,11 +4611,14 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) { LightInstance *li=light_instances[p_light]; Light *l=li->base; + Color col_ambient=_convert_color(l->colors[VS::LIGHT_COLOR_AMBIENT]); + Color col_diffuse=_convert_color(l->colors[VS::LIGHT_COLOR_DIFFUSE]); + Color col_specular=_convert_color(l->colors[VS::LIGHT_COLOR_SPECULAR]); for(int j=0;j<3;j++) { - light_data[VL_LIGHT_AMBIENT][j]=l->colors[VS::LIGHT_COLOR_AMBIENT][j]; - light_data[VL_LIGHT_DIFFUSE][j]=l->colors[VS::LIGHT_COLOR_DIFFUSE][j]; - light_data[VL_LIGHT_SPECULAR][j]=l->colors[VS::LIGHT_COLOR_SPECULAR][j]; + light_data[VL_LIGHT_AMBIENT][j]=col_ambient[j]; + light_data[VL_LIGHT_DIFFUSE][j]=col_diffuse[j]; + light_data[VL_LIGHT_SPECULAR][j]=col_specular[j]; } if (l->type!=VS::LIGHT_OMNI) { @@ -4626,6 +4652,8 @@ void RasterizerGLES2::_setup_light(uint16_t p_light) { material_shader.set_uniform(MaterialShaderGLES2::SHADOW_MATRIX,li->shadow_projection[0]); material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXEL_SIZE,Vector2(1.0,1.0)/li->near_shadow_buffer->size); material_shader.set_uniform(MaterialShaderGLES2::SHADOW_TEXTURE,7); + if (shadow_filter==SHADOW_FILTER_ESM) + material_shader.set_uniform(MaterialShaderGLES2::ESM_MULTIPLIER,float(li->base->vars[VS::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER])); if (li->base->type==VS::LIGHT_DIRECTIONAL) { @@ -6064,7 +6092,7 @@ void RasterizerGLES2::_draw_tex_bg() { } float nrg =float(current_env->bg_param[VS::ENV_BG_PARAM_ENERGY]); - if (current_env->fx_enabled[VS::ENV_FX_HDR]) + if (current_env->fx_enabled[VS::ENV_FX_HDR] && !use_fp16_fb) nrg*=0.25; //go down a quarter for hdr copy_shader.set_uniform(CopyShaderGLES2::ENERGY,nrg); copy_shader.set_uniform(CopyShaderGLES2::CUSTOM_ALPHA,float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW])); @@ -6178,7 +6206,7 @@ void RasterizerGLES2::end_scene() { glViewport( 0,0,viewport.width / framebuffer.scale, viewport.height / framebuffer.scale ); glScissor( 0,0,viewport.width / framebuffer.scale, viewport.height / framebuffer.scale ); - material_shader.set_conditional(MaterialShaderGLES2::USE_HDR,current_env && current_env->fx_enabled[VS::ENV_FX_HDR]); + material_shader.set_conditional(MaterialShaderGLES2::USE_8BIT_HDR,!use_fp16_fb && current_env && current_env->fx_enabled[VS::ENV_FX_HDR]); } else { if (current_rt) { @@ -6218,6 +6246,7 @@ void RasterizerGLES2::end_scene() { bgcolor = current_env->bg_param[VS::ENV_BG_PARAM_COLOR]; else bgcolor = Globals::get_singleton()->get("render/default_clear_color"); + bgcolor = _convert_color(bgcolor); float a = use_fb ? float(current_env->bg_param[VS::ENV_BG_PARAM_GLOW]) : 1.0; glClearColor(bgcolor.r,bgcolor.g,bgcolor.b,a); _glClearDepth(1.0); @@ -6237,7 +6266,8 @@ void RasterizerGLES2::end_scene() { } } else { - glClearColor(0.3,0.3,0.3,1.0); + Color c = _convert_color(Color(0.3,0.3,0.3)); + glClearColor(c.r,c.g,c.b,0.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); } @@ -6340,7 +6370,7 @@ void RasterizerGLES2::end_scene() { //time to copy!!! copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,current_env && current_env->fx_enabled[VS::ENV_FX_BCS]); - copy_shader.set_conditional(CopyShaderGLES2::USE_GAMMA,current_env && current_env->fx_enabled[VS::ENV_FX_GAMMA]); + copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,current_env && current_env->fx_enabled[VS::ENV_FX_SRGB]); copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,current_env && current_env->fx_enabled[VS::ENV_FX_GLOW]); copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,current_env && current_env->fx_enabled[VS::ENV_FX_HDR]); copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,true); @@ -6378,9 +6408,7 @@ void RasterizerGLES2::end_scene() { bcs.z=current_env->fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]; copy_shader.set_uniform(CopyShaderGLES2::BCS,bcs); } - if (current_env && current_env->fx_enabled[VS::ENV_FX_GAMMA]) { - copy_shader.set_uniform(CopyShaderGLES2::GAMMA,float(current_env->fx_param[VS::ENV_FX_PARAM_GAMMA])); - } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, framebuffer.color ); glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0); @@ -6388,7 +6416,7 @@ void RasterizerGLES2::end_scene() { _copy_screen_quad(); copy_shader.set_conditional(CopyShaderGLES2::USE_BCS,false); - copy_shader.set_conditional(CopyShaderGLES2::USE_GAMMA,false); + copy_shader.set_conditional(CopyShaderGLES2::USE_SRGB,false); copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW,false); copy_shader.set_conditional(CopyShaderGLES2::USE_HDR,false); copy_shader.set_conditional(CopyShaderGLES2::USE_NO_ALPHA,false); @@ -6396,7 +6424,7 @@ void RasterizerGLES2::end_scene() { copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SCREEN,false); copy_shader.set_conditional(CopyShaderGLES2::USE_GLOW_SOFTLIGHT,false); - material_shader.set_conditional(MaterialShaderGLES2::USE_HDR,false); + material_shader.set_conditional(MaterialShaderGLES2::USE_8BIT_HDR,false); if (current_env && current_env->fx_enabled[VS::ENV_FX_HDR] && GLOBAL_DEF("rasterizer/debug_hdr",false)) { @@ -6443,6 +6471,7 @@ void RasterizerGLES2::end_shadow_map() { float dp_direction=0.0; bool flip_facing=false; + Rect2 vp_rect; switch(shadow->base->type) { @@ -6455,24 +6484,30 @@ void RasterizerGLES2::end_shadow_map() { if (shadow_pass==0) { - glViewport(0, sb->size*0.5, sb->size*0.5, sb->size*0.5); - glScissor(0, sb->size*0.5, sb->size*0.5, sb->size*0.5); + vp_rect=Rect2(0, sb->size/2, sb->size/2, sb->size/2); + glViewport(0, sb->size/2, sb->size/2, sb->size/2); + glScissor(0, sb->size/2, sb->size/2, sb->size/2); } else if (shadow_pass==1) { - glViewport(0, 0, sb->size*0.5, sb->size*0.5); - glScissor(0, 0, sb->size*0.5, sb->size*0.5); + vp_rect=Rect2(0, 0, sb->size/2, sb->size/2); + glViewport(0, 0, sb->size/2, sb->size/2); + glScissor(0, 0, sb->size/2, sb->size/2); } else if (shadow_pass==2) { - glViewport(sb->size*0.5, sb->size*0.5, sb->size*0.5, sb->size*0.5); - glScissor(sb->size*0.5, sb->size*0.5, sb->size*0.5, sb->size*0.5); + vp_rect=Rect2(sb->size/2, sb->size/2, sb->size/2, sb->size/2); + glViewport(sb->size/2, sb->size/2, sb->size/2, sb->size/2); + glScissor(sb->size/2, sb->size/2, sb->size/2, sb->size/2); } else if (shadow_pass==3) { - glViewport(sb->size*0.5, 0, sb->size*0.5, sb->size*0.5); - glScissor(sb->size*0.5, 0, sb->size*0.5, sb->size*0.5); + vp_rect=Rect2(sb->size/2, 0, sb->size/2, sb->size/2); + glViewport(sb->size/2, 0, sb->size/2, sb->size/2); + glScissor(sb->size/2, 0, sb->size/2, sb->size/2); } + + glEnable(GL_SCISSOR_TEST); } else if (shadow->base->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { @@ -6481,14 +6516,16 @@ void RasterizerGLES2::end_shadow_map() { cm = shadow->custom_projection[0]; light_transform=shadow->custom_transform[0]; - glViewport(0, sb->size*0.5, sb->size, sb->size*0.5); - glScissor(0, sb->size*0.5, sb->size, sb->size*0.5); + vp_rect=Rect2(0, sb->size/2, sb->size, sb->size/2); + glViewport(0, sb->size/2, sb->size, sb->size/2); + glScissor(0, sb->size/2, sb->size, sb->size/2); } else { cm = shadow->custom_projection[1]; light_transform=shadow->custom_transform[1]; - glViewport(0, 0, sb->size, sb->size*0.5); - glScissor(0, 0, sb->size, sb->size*0.5); + vp_rect=Rect2(0, 0, sb->size, sb->size/2); + glViewport(0, 0, sb->size, sb->size/2); + glScissor(0, 0, sb->size, sb->size/2); } @@ -6497,6 +6534,7 @@ void RasterizerGLES2::end_shadow_map() { } else { cm = shadow->custom_projection[0]; light_transform=shadow->custom_transform[0]; + vp_rect=Rect2(0, 0, sb->size, sb->size); glViewport(0, 0, sb->size, sb->size); } @@ -6527,11 +6565,13 @@ void RasterizerGLES2::end_shadow_map() { shadow->dp.y=dp_direction; if (shadow_pass==0) { - glViewport(0, sb->size*0.5, sb->size, sb->size*0.5); - glScissor(0, sb->size*0.5, sb->size, sb->size*0.5); + vp_rect=Rect2(0, sb->size/2, sb->size, sb->size/2); + glViewport(0, sb->size/2, sb->size, sb->size/2); + glScissor(0, sb->size/2, sb->size, sb->size/2); } else { - glViewport(0, 0, sb->size, sb->size*0.5); - glScissor(0, 0, sb->size, sb->size*0.5); + vp_rect=Rect2(0, 0, sb->size, sb->size/2); + glViewport(0, 0, sb->size, sb->size/2); + glScissor(0, 0, sb->size, sb->size/2); } glEnable(GL_SCISSOR_TEST); shadow->projection=cm; @@ -6565,6 +6605,7 @@ void RasterizerGLES2::end_shadow_map() { z_far=cm.get_z_far(); glViewport(0, 0, sb->size, sb->size); + vp_rect=Rect2(0, 0, sb->size, sb->size); _glClearDepth(1.0f); glClearColor(1,1,1,1); if (use_rgba_shadowmaps) @@ -6583,16 +6624,124 @@ void RasterizerGLES2::end_shadow_map() { material_shader.set_conditional(MaterialShaderGLES2::USE_DUAL_PARABOLOID,false); - glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer); - //glDisable(GL_POLYGON_OFFSET_FILL); - //if (!use_rgba_shadowmaps) - glColorMask(1, 1, 1, 1); + + if (shadow_filter==SHADOW_FILTER_ESM) { + + copy_shader.set_conditional(CopyShaderGLES2::USE_RGBA_DEPTH,use_rgba_shadowmaps); + copy_shader.set_conditional(CopyShaderGLES2::USE_HIGHP_SOURCE,!use_rgba_shadowmaps); + + Vector2 psize(1.0/sb->size,1.0/sb->size); + float pscale = 1.0; + int passes=shadow->base->vars[VS::LIGHT_PARAM_SHADOW_BLUR_PASSES]; + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); +#ifdef GLEW_ENABLED + glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); +#endif + + for(int i=0;isize, + (vp_rect.pos+vp_rect.size)/sb->size, + (vp_rect.pos+Vector2(vp_rect.size.x,0))/sb->size, + (vp_rect.pos)/sb->size + }; +/* + Vector2 src_uv[4]={ + Vector2( 0, 1), + Vector2( 1, 1), + Vector2( 1, 0), + Vector2( 0, 0) + }; +*/ + static const Vector2 dst_pos[4]={ + Vector2(-1, 1), + Vector2( 1, 1), + Vector2( 1,-1), + Vector2(-1,-1) + }; + + glBindFramebuffer(GL_FRAMEBUFFER, blur_shadow_buffer.fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, sb->depth); +#ifdef GLEW_ENABLED + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); +#endif + + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_V_PASS,true); + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,false); + + copy_shader.bind(); + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,psize); + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SCALE,pscale); + copy_shader.set_uniform(CopyShaderGLES2::BLUR_MAGNITUDE,1); + //copy_shader.set_uniform(CopyShaderGLES2::SOURCE,0); + glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0); + + + _draw_gui_primitive(4,dst_pos,NULL,src_sb_uv); + + + Vector2 src_bb_uv[4]={ + (vp_rect.pos+Vector2(0,vp_rect.size.y))/blur_shadow_buffer.size, + (vp_rect.pos+vp_rect.size)/blur_shadow_buffer.size, + (vp_rect.pos+Vector2(vp_rect.size.x,0))/blur_shadow_buffer.size, + (vp_rect.pos)/blur_shadow_buffer.size, + }; + + glBindFramebuffer(GL_FRAMEBUFFER, sb->fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, blur_shadow_buffer.depth); +#ifdef GLEW_ENABLED + + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); +#endif + + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_V_PASS,false); + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,true); + copy_shader.bind(); + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SIZE,psize); + copy_shader.set_uniform(CopyShaderGLES2::PIXEL_SCALE,pscale); + copy_shader.set_uniform(CopyShaderGLES2::BLUR_MAGNITUDE,1); + glUniform1i(copy_shader.get_uniform_location(CopyShaderGLES2::SOURCE),0); + + _draw_gui_primitive(4,dst_pos,NULL,src_bb_uv); + + + } + + glDepthFunc(GL_LEQUAL); + copy_shader.set_conditional(CopyShaderGLES2::USE_RGBA_DEPTH,false); + copy_shader.set_conditional(CopyShaderGLES2::USE_HIGHP_SOURCE,false); + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_V_PASS,false); + copy_shader.set_conditional(CopyShaderGLES2::SHADOW_BLUR_H_PASS,false); + + } DEBUG_TEST_ERROR("Drawing Shadow"); shadow=NULL; - + glBindFramebuffer(GL_FRAMEBUFFER, current_rt?current_rt->fbo:base_framebuffer); + glColorMask(1, 1, 1, 1); + //glDisable(GL_POLYGON_OFFSET_FILL); } @@ -6635,23 +6784,14 @@ void RasterizerGLES2::_debug_draw_shadows_type(Vector& p_shadows,P // Size2 debug_size(512,512); - for (int i=0;iowner) + if (!sb->owner && i!=p_shadows.size()) continue; - - if (sb->owner->base->type==VS::LIGHT_DIRECTIONAL) { - - //if (sb->owner->shadow_pass!=scene_pass-1) - // continue; - } else { - - //if (sb->owner->shadow_pass!=frame) - // continue; - } _debug_draw_shadow(sb->depth, Rect2( ofs, debug_size )); ofs.x+=debug_size.x; if ( (ofs.x+debug_size.x) > viewport.width ) { @@ -7560,6 +7700,11 @@ bool RasterizerGLES2::ShadowBuffer::init(int p_size,bool p_use_depth) { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size, size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); +#ifdef GLEW_ENABLED + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#endif + // Attach the depth texture to FBO depth attachment point glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); @@ -7778,9 +7923,17 @@ void RasterizerGLES2::_update_framebuffer() { #endif //color + + GLuint format_rgba = use_fp16_fb?_GL_RGBA16F_EXT:GL_RGBA; + GLuint format_rgb = use_fp16_fb?_GL_RGB16F_EXT:GL_RGB; + GLuint format_type = use_fp16_fb?_GL_HALF_FLOAT_OES:GL_UNSIGNED_BYTE; + GLuint format_luminance = use_fp16_fb?_GL_R32F_EXT:GL_RGBA; + GLuint format_luminance_type = use_fp16_fb?GL_FLOAT:GL_UNSIGNED_BYTE; + GLuint format_luminance_components = use_fp16_fb?GL_RED:GL_RGBA; + glGenTextures(1, &framebuffer.color); glBindTexture(GL_TEXTURE_2D, framebuffer.color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, framebuffer.width, framebuffer.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, framebuffer.width, framebuffer.height, 0, GL_RGBA, format_type, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -7814,7 +7967,7 @@ void RasterizerGLES2::_update_framebuffer() { glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.sample_fbo); glGenTextures(1, &framebuffer.sample_color); glBindTexture(GL_TEXTURE_2D, framebuffer.sample_color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, framebuffer.width, framebuffer.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, framebuffer.width, framebuffer.height, 0, GL_RGBA, format_type, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -7873,8 +8026,8 @@ void RasterizerGLES2::_update_framebuffer() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, size, size, 0, + GL_RGBA, format_type, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer.blur[i].color, 0); @@ -7922,8 +8075,8 @@ void RasterizerGLES2::_update_framebuffer() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lb.size, lb.size, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, format_luminance, lb.size, lb.size, 0, + format_luminance_components, format_luminance_type, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lb.color, 0); @@ -8052,6 +8205,7 @@ void RasterizerGLES2::init() { // framebuffer.blur[1].fbo=false; framebuffer.active=false; + //do a single initial clear glClearColor(0,0,0,1); //glClearDepth(1.0); @@ -8086,8 +8240,9 @@ void RasterizerGLES2::init() { use_attribute_instancing=true; #ifdef OSX_ENABLED use_rgba_shadowmaps=true; + use_fp16_fb=false; #else - use_rgba_shadowmaps=false; + #endif use_half_float=true; @@ -8098,6 +8253,9 @@ void RasterizerGLES2::init() { } read_depth_supported=extensions.has("GL_OES_depth_texture"); use_rgba_shadowmaps=!read_depth_supported; + if (shadow_filter>=SHADOW_FILTER_ESM && !extensions.has("GL_EXT_frag_depth")) { + use_rgba_shadowmaps=true; //no other way, go back to rgba + } pvr_supported=extensions.has("GL_IMG_texture_compression_pvrtc"); etc_supported=extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); use_depth24 = extensions.has("GL_OES_depth24"); @@ -8131,6 +8289,10 @@ void RasterizerGLES2::init() { use_attribute_instancing=false; } + if (use_fp16_fb) { + use_fp16_fb=extensions.has("GL_OES_texture_half_float") && extensions.has("GL_EXT_color_buffer_half_float"); + } + //etc_supported=false; use_hw_skeleton_xform=false; @@ -8150,15 +8312,19 @@ void RasterizerGLES2::init() { //don't use a shadowbuffer too big in GLES, this should be the maximum int max_shadow_size = GLOBAL_DEF("rasterizer/max_shadow_buffer_size",1024);//nearest_power_of_2(MIN(vm.width,vm.height))/2; - while(max_shadow_size>=16) { + int smsize=max_shadow_size; + while(smsize>=16) { ShadowBuffer sb; - bool s = sb.init(max_shadow_size,!use_rgba_shadowmaps); + bool s = sb.init(smsize,!use_rgba_shadowmaps); if (s) near_shadow_buffers.push_back(sb); - max_shadow_size/=2; + smsize/=2; } + blur_shadow_buffer.init(max_shadow_size,!use_rgba_shadowmaps); + + //material_shader material_shader.set_conditional(MaterialShaderGLES2::USE_DEPTH_SHADOWS,!use_rgba_shadowmaps); @@ -8168,6 +8334,9 @@ void RasterizerGLES2::init() { shadow_material = material_create(); //empty with nothing shadow_mat_ptr = material_owner.get(shadow_material); overdraw_material = create_overdraw_debug_material(); + copy_shader.set_conditional(CopyShaderGLES2::USE_8BIT_HDR,!use_fp16_fb); + + canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false)); npo2_textures_available=true; //fragment_lighting=false; @@ -8423,6 +8592,8 @@ void RasterizerGLES2::reload_vram() { near_shadow_buffers[i].init(near_shadow_buffers[i].size,!use_rgba_shadowmaps); } + blur_shadow_buffer.init(near_shadow_buffers[0].size,!use_rgba_shadowmaps); + canvas_shader.clear_caches(); @@ -8473,8 +8644,8 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo fragment_lighting=GLOBAL_DEF("rasterizer/use_fragment_lighting",true); read_depth_supported=true; //todo check for extension shadow_filter=ShadowFilterTechnique((int)(GLOBAL_DEF("rasterizer/shadow_filter",SHADOW_FILTER_PCF5))); - Globals::get_singleton()->set_custom_property_info("rasterizer/shadow_filter",PropertyInfo(Variant::INT,"rasterizer/shadow_filter",PROPERTY_HINT_ENUM,"None,PCF5,PCF13,ESM,VSM")); - + Globals::get_singleton()->set_custom_property_info("rasterizer/shadow_filter",PropertyInfo(Variant::INT,"rasterizer/shadow_filter",PROPERTY_HINT_ENUM,"None,PCF5,PCF13,ESM")); + use_fp16_fb=bool(GLOBAL_DEF("rasterizer/fp16_framebuffer",true)); use_shadow_mapping=true; use_fast_texture_filter=!bool(GLOBAL_DEF("rasterizer/trilinear_mipmap_filter",true)); skel_default.resize(1024*4); diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 0fee8bf91830..dce096b29e86 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -80,6 +80,7 @@ class RasterizerGLES2 : public Rasterizer { bool read_depth_supported; bool use_framebuffers; bool use_shadow_mapping; + bool use_fp16_fb; ShadowFilterTechnique shadow_filter; bool use_shadow_esm; @@ -585,6 +586,8 @@ class RasterizerGLES2 : public Rasterizer { vars[VS::LIGHT_PARAM_SHADOW_DARKENING]=0.0; vars[VS::LIGHT_PARAM_SHADOW_Z_OFFSET]=0.2; vars[VS::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE]=1.4; + vars[VS::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER]=60.0; + vars[VS::LIGHT_PARAM_SHADOW_BLUR_PASSES]=1; colors[VS::LIGHT_COLOR_AMBIENT]=Color(0,0,0); colors[VS::LIGHT_COLOR_DIFFUSE]=Color(1,1,1); colors[VS::LIGHT_COLOR_SPECULAR]=Color(1,1,1); @@ -645,7 +648,6 @@ class RasterizerGLES2 : public Rasterizer { fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]=1.0; - fx_param[VS::ENV_FX_PARAM_GAMMA]=1.0; } @@ -998,6 +1000,8 @@ class RasterizerGLES2 : public Rasterizer { }; Vector near_shadow_buffers; + ShadowBuffer blur_shadow_buffer; + Vector far_shadow_buffers; LightInstance *shadow; @@ -1100,6 +1104,7 @@ class RasterizerGLES2 : public Rasterizer { bool cull_front; bool lights_use_shadow; _FORCE_INLINE_ void _set_cull(bool p_front,bool p_reverse_cull=false); + _FORCE_INLINE_ Color _convert_color(const Color& p_color); void _process_glow_bloom(); void _process_hdr(); @@ -1376,6 +1381,7 @@ public: virtual ShadowType light_instance_get_shadow_type(RID p_light_instance,bool p_far=false) const; virtual int light_instance_get_shadow_passes(RID p_light_instance) const; + virtual bool light_instance_get_pssm_shadow_overlap(RID p_light_instance) const; virtual void light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0); virtual int light_instance_get_shadow_size(RID p_light_instance, int p_index=0) const; diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index bb99862b9e8f..17d893e349e1 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -308,6 +308,8 @@ public: uniforms_dirty = true; }; + uint32_t get_version() const { return new_conditional_version.version; } + void set_uniform_camera(int p_idx, const CameraMatrix& p_mat) { uniform_cameras[p_idx] = p_mat; diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl index 2f1b349618f6..6d78c69e50ae 100644 --- a/drivers/gles2/shaders/copy.glsl +++ b/drivers/gles2/shaders/copy.glsl @@ -54,8 +54,12 @@ varying vec3 cube_interp; uniform samplerCube source_cube; #else varying vec2 uv_interp; +#ifdef HIGHP_SOURCE +uniform highp sampler2D source; +#else uniform sampler2D source; #endif +#endif varying vec2 uv2_interp; #ifdef USE_GLOW @@ -83,12 +87,6 @@ uniform vec3 bcs; #endif -#ifdef USE_GAMMA - -uniform float gamma; - -#endif - #ifdef USE_GLOW_COPY uniform float bloom; @@ -96,7 +94,7 @@ uniform float bloom_treshold; #endif -#if defined(BLUR_V_PASS) || defined(BLUR_H_PASS) || defined(USE_HDR_REDUCE) +#if defined(SHADOW_BLUR_V_PASS) || defined(SHADOW_BLUR_H_PASS) || defined(BLUR_V_PASS) || defined(BLUR_H_PASS) || defined(USE_HDR_REDUCE) uniform vec2 pixel_size; uniform float pixel_scale; @@ -133,6 +131,17 @@ uniform float custom_alpha; void main() { //vec4 color = color_interp; +#ifdef USE_HIGHP_SOURCE + +#ifdef USE_CUBEMAP + highp vec4 color = textureCube( source_cube, normalize(cube_interp) ); + +#else + highp vec4 color = texture2D( source, uv_interp ); +#endif + +#else + #ifdef USE_CUBEMAP vec4 color = textureCube( source_cube, normalize(cube_interp) ); @@ -141,6 +150,8 @@ void main() { #endif +#endif + #ifdef USE_FXAA #define FXAA_REDUCE_MIN (1.0/ 128.0) @@ -226,17 +237,103 @@ void main() { #endif +#ifdef SHADOW_BLUR_V_PASS + +#ifdef USE_RGBA_DEPTH + +#define VEC42DEPTH(m_vec4) dot(m_vec4,vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1)) + + highp float depth = VEC42DEPTH(color)*0.383; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(0.0,pixel_size.y*-3.0)*pixel_scale))*0.006; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(0.0,pixel_size.y*-2.0)*pixel_scale))*0.061; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(0.0,pixel_size.y*-1.0)*pixel_scale))*0.242; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(0.0,pixel_size.y*1.0)*pixel_scale))*0.242; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(0.0,pixel_size.y*2.0)*pixel_scale))*0.061; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(0.0,pixel_size.y*3.0)*pixel_scale))*0.006; + highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); + comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + color=comp; + +#else + + highp float depth = color.r*0.383; + depth+=texture2D(source,uv_interp+vec2(0.0,pixel_size.y*-3.0)*pixel_scale).r*0.006; + depth+=texture2D(source,uv_interp+vec2(0.0,pixel_size.y*-2.0)*pixel_scale).r*0.061; + depth+=texture2D(source,uv_interp+vec2(0.0,pixel_size.y*-1.0)*pixel_scale).r*0.242; + depth+=texture2D(source,uv_interp+vec2(0.0,pixel_size.y*1.0)*pixel_scale).r*0.242; + depth+=texture2D(source,uv_interp+vec2(0.0,pixel_size.y*2.0)*pixel_scale).r*0.061; + depth+=texture2D(source,uv_interp+vec2(0.0,pixel_size.y*3.0)*pixel_scale).r*0.006; + +#ifdef USE_GLES_OVER_GL + gl_FragDepth = depth; + +#else + gl_FragDepthEXT = depth; +#endif + + return; +#endif + +#endif + +#ifdef SHADOW_BLUR_H_PASS + + +#ifdef USE_RGBA_DEPTH + +#define VEC42DEPTH(m_vec4) dot(m_vec4,vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1)) + + highp float depth = VEC42DEPTH(color)*0.383; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(pixel_size.x*-3.0,0.0)*pixel_scale))*0.006; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(pixel_size.x*-2.0,0.0)*pixel_scale))*0.061; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(pixel_size.x*-1.0,0.0)*pixel_scale))*0.242; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(pixel_size.x*1.0,0.0)*pixel_scale))*0.242; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(pixel_size.x*2.0,0.0)*pixel_scale))*0.061; + depth+=VEC42DEPTH(texture2D(source,uv_interp+vec2(pixel_size.x*3.0,0.0)*pixel_scale))*0.006; + highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); + comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + color=comp; +#else + + + highp float depth = color.r*0.383; + depth+=texture2D(source,uv_interp+vec2(pixel_size.x*-3.0,0.0)*pixel_scale).r*0.006; + depth+=texture2D(source,uv_interp+vec2(pixel_size.x*-2.0,0.0)*pixel_scale).r*0.061; + depth+=texture2D(source,uv_interp+vec2(pixel_size.x*-1.0,0.0)*pixel_scale).r*0.242; + depth+=texture2D(source,uv_interp+vec2(pixel_size.x*1.0,0.0)*pixel_scale).r*0.242; + depth+=texture2D(source,uv_interp+vec2(pixel_size.x*2.0,0.0)*pixel_scale).r*0.061; + depth+=texture2D(source,uv_interp+vec2(pixel_size.x*3.0,0.0)*pixel_scale).r*0.006; + +#ifdef USE_GLES_OVER_GL + gl_FragDepth = depth; +#else + gl_FragDepthEXT = depth; +#endif + + return; + +#endif + +#endif + #ifdef USE_HDR + +#ifdef USE_8BIT_HDR highp vec4 _mult = vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1); highp float hdr_lum = dot(texture2D( hdr_source, vec2(0.0) ), _mult ); color.rgb*=LUM_RANGE; hdr_lum*=LUM_RANGE; //restore to full range +#else + highp float hdr_lum = texture2D( hdr_source, vec2(0.0) ).r; +#endif + highp float tone_scale = tonemap_exposure / hdr_lum; //only linear supported color.rgb*=tone_scale; #endif + #ifdef USE_GLOW_COPY highp vec3 glowcol = color.rgb*color.a+step(bloom_treshold,dot(vec3(0.3333,0.3333,0.3333),color.rgb))*bloom*color.rgb; @@ -281,10 +378,15 @@ void main() { #endif -#ifdef USE_GAMMA - - color.rgb = pow(color.rgb,gamma); +#ifdef USE_SRGB + { //i have my doubts about how fast this is + color.rgb = min(color.rgb,vec3(1.0)); //clamp just in case + vec3 S1 = sqrt(color.rgb); + vec3 S2 = sqrt(S1); + vec3 S3 = sqrt(S2); + color.rgb = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.225411470 * color.rgb; + } #endif @@ -292,13 +394,20 @@ void main() { //highp float lum = dot(color.rgb,highp vec3(1.0/3.0,1.0/3.0,1.0/3.0)); highp float lum = max(color.r,max(color.g,color.b)); +#ifdef USE_8BIT_HDR highp vec4 comp = fract(lum * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); comp -= comp.xxyz * vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); color=comp; +#else + color.rgb=vec3(lum); +#endif + + #endif #ifdef USE_HDR_REDUCE +#ifdef USE_8BIT_HDR highp vec4 _multcv = vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0, 1.0); highp float lum_accum = dot(color,_multcv ); lum_accum += dot(texture2D( source, uv_interp+vec2(-pixel_size.x,-pixel_size.y) ),_multcv ); @@ -310,16 +419,42 @@ void main() { lum_accum += dot(texture2D( source, uv_interp+vec2(0.0,pixel_size.y) ),_multcv ); lum_accum += dot(texture2D( source, uv_interp+vec2(pixel_size.x,pixel_size.y) ),_multcv ); lum_accum/=9.0; +#else + + highp float lum_accum = color.r; + lum_accum += texture2D( source, uv_interp+vec2(-pixel_size.x,-pixel_size.y) ).r; + lum_accum += texture2D( source, uv_interp+vec2(0.0,-pixel_size.y) ).r; + lum_accum += texture2D( source, uv_interp+vec2(pixel_size.x,-pixel_size.y) ).r; + lum_accum += texture2D( source, uv_interp+vec2(-pixel_size.x,0.0) ).r; + lum_accum += texture2D( source, uv_interp+vec2(pixel_size.x,0.0) ).r; + lum_accum += texture2D( source, uv_interp+vec2(-pixel_size.x,pixel_size.y) ).r; + lum_accum += texture2D( source, uv_interp+vec2(0.0,pixel_size.y) ).r; + lum_accum += texture2D( source, uv_interp+vec2(pixel_size.x,pixel_size.y) ).r; + lum_accum/=9.0; + +#endif #ifdef USE_HDR_STORE +#ifdef USE_8BIT_HDR highp float vd_lum = dot(texture2D( source_vd_lum, vec2(0.0) ), _multcv ); lum_accum = clamp( vd_lum + (lum_accum-vd_lum)*hdr_time_delta*hdr_exp_adj_speed,min_luminance*(1.0/LUM_RANGE),max_luminance*(1.0/LUM_RANGE)); +#else + highp float vd_lum=texture2D( source_vd_lum, vec2(0.0) ); + lum_accum = clamp( vd_lum + (lum_accum-vd_lum)*hdr_time_delta*hdr_exp_adj_speed,min_luminance,max_luminance); #endif +#endif + +#ifdef USE_8BIT_HDR highp vec4 comp = fract(lum_accum * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); comp -= comp.xxyz * vec4(0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); color=comp; +#else + color.rgb=vec3(lum_accum); +#endif + + #endif #ifdef USE_RGBE @@ -338,6 +473,8 @@ void main() { #ifdef USE_CUSTOM_ALPHA color.a=custom_alpha; #endif + + gl_FragColor = color; } diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl index 7ed59ae9cd2a..3aed9820edcb 100644 --- a/drivers/gles2/shaders/material.glsl +++ b/drivers/gles2/shaders/material.glsl @@ -342,7 +342,7 @@ VERTEX_SHADER_CODE #ifdef USE_FOG - fog_interp.a = pow( clamp( (-vertex_interp.z-fog_params.x)/(fog_params.y-fog_params.x), 0.0, 1.0 ), fog_params.z ); + fog_interp.a = pow( clamp( (length(vertex_interp)-fog_params.x)/(fog_params.y-fog_params.x), 0.0, 1.0 ), fog_params.z ); fog_interp.rgb = mix( fog_color_begin, fog_color_end, fog_interp.a ); #endif @@ -666,9 +666,14 @@ float SAMPLE_SHADOW_TEX( highp vec2 coord, highp float refdepth) { #ifdef USE_SHADOW_ESM +uniform float esm_multiplier; float SAMPLE_SHADOW_TEX(vec2 p_uv,float p_depth) { +#if defined (USE_DEPTH_SHADOWS) + //these only are used if interpolation exists + highp float occluder = SHADOW_DEPTH(shadow_texture, p_uv); +#else vec2 unnormalized = p_uv/shadow_texel_size; vec2 fractional = fract(unnormalized); unnormalized = floor(unnormalized); @@ -681,7 +686,8 @@ float SAMPLE_SHADOW_TEX(vec2 p_uv,float p_depth) { highp float occluder = (exponent.w + (exponent.x - exponent.w) * fractional.y); occluder = occluder + ((exponent.z + (exponent.y - exponent.z) * fractional.y) - occluder)*fractional.x; - return clamp(exp(28.0 * ( occluder - p_depth )),0.0,1.0); +#endif + return clamp(exp(esm_multiplier* ( occluder - p_depth )),0.0,1.0); } @@ -818,7 +824,7 @@ FRAGMENT_SHADER_CODE vec3 col_up=texture2D(ambient_octree_tex,octant_uv).rgb; octant_uv.y+=ambient_octree_pix_size.y*2.0; vec3 col_down=texture2D(ambient_octree_tex,octant_uv).rgb; - ambientmap_color=mix(col_down,col_up,1.0-sub.z); + ambientmap_color=mix(col_up,col_down,sub.z); ambientmap_color*=diffuse.rgb; @@ -866,6 +872,15 @@ FRAGMENT_SHADER_CODE vec2 pssm_coord; float pssm_z; +#if defined(LIGHT_USE_PSSM) && defined(USE_SHADOW_ESM) +#define USE_PSSM_BLEND + float pssm_blend; + vec2 pssm_coord_2; + float pssm_z_2; + vec3 light_pssm_split_inv = 1.0/light_pssm_split; + float w_inv = 1.0/gl_FragCoord.w; +#endif + #ifdef LIGHT_USE_PSSM4 @@ -874,10 +889,21 @@ FRAGMENT_SHADER_CODE if (gl_FragCoord.w > light_pssm_split.x) { pssm_coord=shadow_coord.xy; pssm_z=shadow_coord.z; +#if defined(USE_PSSM_BLEND) + pssm_coord_2=shadow_coord2.xy; + pssm_z_2=shadow_coord2.z; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif } else { pssm_coord=shadow_coord2.xy; pssm_z=shadow_coord2.z; +#if defined(USE_PSSM_BLEND) + pssm_coord_2=shadow_coord3.xy; + pssm_z_2=shadow_coord3.z; + pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv); +#endif + } } else { @@ -885,9 +911,21 @@ FRAGMENT_SHADER_CODE if (gl_FragCoord.w > light_pssm_split.z) { pssm_coord=shadow_coord3.xy; pssm_z=shadow_coord3.z; +#if defined(USE_PSSM_BLEND) + pssm_coord_2=shadow_coord4.xy; + pssm_z_2=shadow_coord4.z; + pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv); +#endif + } else { pssm_coord=shadow_coord4.xy; pssm_z=shadow_coord4.z; +#if defined(USE_PSSM_BLEND) + pssm_coord_2=shadow_coord4.xy; + pssm_z_2=shadow_coord4.z; + pssm_blend=0.0; +#endif + } } @@ -896,16 +934,31 @@ FRAGMENT_SHADER_CODE if (gl_FragCoord.w > light_pssm_split.x) { pssm_coord=shadow_coord.xy; pssm_z=shadow_coord.z; +#if defined(USE_PSSM_BLEND) + pssm_coord_2=shadow_coord2.xy; + pssm_z_2=shadow_coord2.z; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif } else { pssm_coord=shadow_coord2.xy; pssm_z=shadow_coord2.z; +#if defined(USE_PSSM_BLEND) + pssm_coord_2=shadow_coord2.xy; + pssm_z_2=shadow_coord2.z; + pssm_blend=0.0; +#endif + } #endif //one one sample shadow_attenuation=SAMPLE_SHADOW_TEX(pssm_coord,pssm_z); +#if defined(USE_PSSM_BLEND) + shadow_attenuation=mix(shadow_attenuation,SAMPLE_SHADOW_TEX(pssm_coord_2,pssm_z_2),pssm_blend); +#endif + #endif @@ -1054,7 +1107,7 @@ FRAGMENT_SHADER_CODE diffuse.a=glow; #endif -#ifdef USE_HDR +#ifdef USE_8BIT_HDR diffuse.rgb*=0.25; #endif diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index f1b7ad009697..9cbbaf2fcf4e 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -1330,12 +1330,17 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars } path=base.get_base_dir().plus_file(path); } - script = ResourceLoader::load(path); if (script.is_null()) { _set_error("Could not load base class: "+path,p_class); return ERR_FILE_NOT_FOUND; } + if (!script->valid) { + + _set_error("Script not fully loaded (cyclic preload?): "+path,p_class); + return ERR_BUSY; + } + //print_line("EXTENDS PATH: "+path+" script is "+itos(script.is_valid())+" indices is "+itos(script->member_indices.size())+" valid? "+itos(script->valid)); if (p_class->extends_class.size()) { @@ -1438,6 +1443,9 @@ 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())); + + for(int i=0;ivariables.size();i++) { StringName name = p_class->variables[i].identifier; diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index f789493ae866..0d11734bbd2d 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -93,6 +93,7 @@ const char *GDFunctions::get_func_name(Function p_func) { "load", "inst2dict", "dict2inst", + "hash", "print_stack", }; @@ -863,6 +864,12 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va r_ret = gdscr->_new(NULL,0,r_error); + } break; + case HASH: { + + VALIDATE_ARG_COUNT(1); + r_ret=p_args[0]->hash(); + } break; case PRINT_STACK: { @@ -1238,6 +1245,12 @@ MethodInfo GDFunctions::get_info(Function p_func) { mi.return_val.type=Variant::OBJECT; return mi; } break; + case HASH: { + + MethodInfo mi("hash",PropertyInfo(Variant::NIL,"var:var")); + mi.return_val.type=Variant::INT; + return mi; + } break; case PRINT_STACK: { MethodInfo mi("print_stack"); diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h index 9255e5e2c510..340763fb8c2c 100644 --- a/modules/gdscript/gd_functions.h +++ b/modules/gdscript/gd_functions.h @@ -89,6 +89,7 @@ public: RESOURCE_LOAD, INST2DICT, DICT2INST, + HASH, PRINT_STACK, FUNC_MAX diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 2885b754be7b..cc7aa7023448 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -1451,6 +1451,7 @@ Error GDScript::reload() { + valid=false; GDParser parser; Error err = parser.parse(source,basedir); @@ -1721,6 +1722,7 @@ GDScript::GDScript() { _base=NULL; _owner=NULL; tool=false; + } diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index 56da0bb2e390..3300ee77c8ed 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -183,6 +183,7 @@ class GDScript : public Script { bool valid; + friend class GDInstance; friend class GDFunction; friend class GDCompiler; diff --git a/platform/flash/rasterizer_flash.h b/platform/flash/rasterizer_flash.h index 5a4190c0faf5..af231f79540b 100644 --- a/platform/flash/rasterizer_flash.h +++ b/platform/flash/rasterizer_flash.h @@ -441,7 +441,7 @@ class RasterizerFlash : public Rasterizer { fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]=1.0; - fx_param[VS::ENV_FX_PARAM_GAMMA]=1.0; + fx_param[VS::ENV_FX_PARAM_SRGB_CONVERT]=1.0; } diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 7cc1d12daacd..b79fd8617f06 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -40,7 +40,9 @@ static const char* _light_param_names[VS::LIGHT_PARAM_MAX]={ "params/attenuation", "shadow/darkening", "shadow/z_offset", - "shadow/z_slope_scale" + "shadow/z_slope_scale", + "shadow/esm_multiplier", + "shadow/blur_passes" }; void Light::set_parameter(Parameter p_param, float p_value) { @@ -479,6 +481,8 @@ void Light::_bind_methods() { 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/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); + ADD_PROPERTYI( PropertyInfo( Variant::INT, "shadow/blur_passes", PROPERTY_HINT_RANGE, "0,4,1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_BLUR_PASSES); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "projector",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_projector"), _SCS("get_projector")); ADD_PROPERTY( PropertyInfo( Variant::INT, "operator",PROPERTY_HINT_ENUM,"Add,Sub"), _SCS("set_operator"), _SCS("get_operator")); @@ -511,6 +515,8 @@ Light::Light(VisualServer::LightType p_type) { set_parameter(PARAM_SHADOW_DARKENING,0.0); set_parameter(PARAM_SHADOW_Z_OFFSET,0.05); set_parameter(PARAM_SHADOW_Z_SLOPE_SCALE,0); + set_parameter(PARAM_SHADOW_ESM_MULTIPLIER,60); + set_parameter(PARAM_SHADOW_BLUR_PASSES,1); set_color( COLOR_AMBIENT, Color(0,0,0)); set_color( COLOR_DIFFUSE, Color(1,1,1)); diff --git a/scene/3d/light.h b/scene/3d/light.h index 76b44c87127d..f090ae5782d9 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -53,6 +53,8 @@ public: PARAM_SHADOW_DARKENING=VisualServer::LIGHT_PARAM_SHADOW_DARKENING, PARAM_SHADOW_Z_OFFSET=VisualServer::LIGHT_PARAM_SHADOW_Z_OFFSET, PARAM_SHADOW_Z_SLOPE_SCALE=VisualServer::LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE, + PARAM_SHADOW_ESM_MULTIPLIER=VisualServer::LIGHT_PARAM_SHADOW_ESM_MULTIPLIER, + PARAM_SHADOW_BLUR_PASSES=VisualServer::LIGHT_PARAM_SHADOW_BLUR_PASSES, PARAM_MAX=VisualServer::LIGHT_PARAM_MAX }; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index d4f043c53832..042666988ac8 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1078,6 +1078,18 @@ void Node::remove_from_group(const StringName& p_identifier) { } +Array Node::_get_groups() const { + + Array groups; + List gi; + get_groups(&gi); + for (List::Element *E=gi.front();E;E=E->next()) { + groups.push_back(E->get().name); + } + + return groups; +} + void Node::get_groups(List *p_groups) const { const StringName *K=NULL; @@ -1712,6 +1724,7 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("remove_from_group","group"),&Node::remove_from_group); ObjectTypeDB::bind_method(_MD("is_in_group","group"),&Node::is_in_group); ObjectTypeDB::bind_method(_MD("move_child","child_node:Node","to_pos"),&Node::move_child); + ObjectTypeDB::bind_method(_MD("get_groups"),&Node::_get_groups); ObjectTypeDB::bind_method(_MD("raise"),&Node::raise); ObjectTypeDB::bind_method(_MD("set_owner","owner:Node"),&Node::set_owner); ObjectTypeDB::bind_method(_MD("get_owner:Node"),&Node::get_owner); diff --git a/scene/main/node.h b/scene/main/node.h index b8981d3307b1..32c5d8ef3836 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -125,6 +125,7 @@ private: void _duplicate_and_reown(Node* p_new_parent, const Map& p_reown_map) const; Array _get_children() const; + Array _get_groups() const; friend class SceneMainLoop; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 30e6e0184212..9a6454e4167f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -140,6 +140,7 @@ #include "scene/resources/mesh_library.h" #include "scene/resources/image_path_finder.h" +#include "scene/resources/polygon_path_finder.h" #include "scene/resources/sample.h" #include "scene/audio/sample_player.h" @@ -536,6 +537,7 @@ void register_scene_types() { ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); + ObjectTypeDB::register_type(); ObjectTypeDB::register_type(); OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 99447c0a0e7b..5c1d190b2ed9 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -140,8 +140,8 @@ void Environment::_bind_methods() { ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bcs/brightness",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_BCS_BRIGHTNESS); ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bcs/contrast",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_BCS_CONTRAST); ADD_PROPERTYI( PropertyInfo(Variant::REAL,"bcs/saturation",PROPERTY_HINT_RANGE,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_BCS_SATURATION); - ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"gamma/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_GAMMA); - ADD_PROPERTYI( PropertyInfo(Variant::REAL,"gamma/gamma",PROPERTY_HINT_EXP_EASING,"0.01,8,0.01"),_SCS("fx_set_param"),_SCS("fx_get_param"), FX_PARAM_GAMMA); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"srgb/enabled"),_SCS("set_enable_fx"),_SCS("is_fx_enabled"), FX_SRGB); + @@ -194,7 +194,7 @@ void Environment::_bind_methods() { BIND_CONSTANT( FX_HDR ); BIND_CONSTANT( FX_FOG ); BIND_CONSTANT( FX_BCS); - BIND_CONSTANT( FX_GAMMA ); + BIND_CONSTANT( FX_SRGB ); BIND_CONSTANT( FX_MAX ); @@ -226,7 +226,6 @@ void Environment::_bind_methods() { BIND_CONSTANT( FX_PARAM_BCS_BRIGHTNESS ); BIND_CONSTANT( FX_PARAM_BCS_CONTRAST ); BIND_CONSTANT( FX_PARAM_BCS_SATURATION ); - BIND_CONSTANT( FX_PARAM_GAMMA ); BIND_CONSTANT( FX_PARAM_MAX ); } @@ -269,7 +268,7 @@ Environment::Environment() { fx_set_param(FX_PARAM_BCS_BRIGHTNESS,1.0); fx_set_param(FX_PARAM_BCS_CONTRAST,1.0); fx_set_param(FX_PARAM_BCS_SATURATION,1.0); - fx_set_param(FX_PARAM_GAMMA,1.0); + } Environment::~Environment() { diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 627fbb7cc09b..b72d6d74bec3 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -67,7 +67,7 @@ public: FX_HDR=VS::ENV_FX_HDR, FX_FOG=VS::ENV_FX_FOG, FX_BCS=VS::ENV_FX_BCS, - FX_GAMMA=VS::ENV_FX_GAMMA, + FX_SRGB=VS::ENV_FX_SRGB, FX_MAX=VS::ENV_FX_MAX, }; @@ -102,7 +102,6 @@ public: FX_PARAM_BCS_BRIGHTNESS=VS::ENV_FX_PARAM_BCS_BRIGHTNESS, FX_PARAM_BCS_CONTRAST=VS::ENV_FX_PARAM_BCS_CONTRAST, FX_PARAM_BCS_SATURATION=VS::ENV_FX_PARAM_BCS_SATURATION, - FX_PARAM_GAMMA=VS::ENV_FX_PARAM_GAMMA, FX_PARAM_MAX=VS::ENV_FX_PARAM_MAX }; private: diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp new file mode 100644 index 000000000000..9f7b6d5b9e79 --- /dev/null +++ b/scene/resources/polygon_path_finder.cpp @@ -0,0 +1,413 @@ +#include "polygon_path_finder.h" +#include "geometry.h" + + +bool PolygonPathFinder::_is_point_inside(const Vector2& p_point) { + + int crosses=0; + + + for (Set::Element *E=edges.front();E;E=E->next()) { + + + const Edge& e=E->get(); + + Vector2 a = points[e.points[0]].pos; + Vector2 b = points[e.points[1]].pos; + + + if (Geometry::segment_intersects_segment_2d(a,b,p_point,outside_point,NULL)) { + crosses++; + } + } + + return crosses&1; +} + +void PolygonPathFinder::setup(const Vector& p_points, const Vector& p_connections) { + + + ERR_FAIL_COND(p_connections.size()&1); + + points.clear(); + edges.clear(); + + //insert points + + int point_count=p_points.size(); + points.resize(point_count+2); + + for(int i=0;i::Element *E=edges.front();E;E=E->next()) { + + const Edge& e=E->get(); + if (e.points[0]==i || e.points[1]==i || e.points[0]==j || e.points[1]==j ) + continue; + + + Vector2 a = points[e.points[0]].pos; + Vector2 b = points[e.points[1]].pos; + + + if (Geometry::segment_intersects_segment_2d(a,b,from,to,NULL)) { + valid=false; + break; + } + + } + + if (valid) { + points[i].connections.insert(j); + points[j].connections.insert(i); + } + } + } +} + + +Vector PolygonPathFinder::find_path(const Vector2& p_from, const Vector2& p_to) { + + Vector path; + if (!_is_point_inside(p_from)) + return path; + if (!_is_point_inside(p_to)) + return path; + + //test direct connection + { + + bool can_see_eachother=true; + + for (Set::Element *E=edges.front();E;E=E->next()) { + + const Edge& e=E->get(); + Vector2 a = points[e.points[0]].pos; + Vector2 b = points[e.points[1]].pos; + + + if (Geometry::segment_intersects_segment_2d(a,b,p_from,p_to,NULL)) { + can_see_eachother=false; + break; + } + + } + + if (can_see_eachother) { + + path.push_back(p_from); + path.push_back(p_to); + return path; + } + } + + //add to graph + + int aidx = points.size()-2; + int bidx = points.size()-1; + points[aidx].pos=p_from; + points[bidx].pos=p_to; + points[aidx].distance=0; + points[bidx].distance=0; + points[aidx].distance=0; + points[bidx].distance=0; + + + for(int i=0;i::Element *E=edges.front();E;E=E->next()) { + + const Edge& e=E->get(); + + if (e.points[0]==i || e.points[1]==i) + continue; + + Vector2 a = points[e.points[0]].pos; + Vector2 b = points[e.points[1]].pos; + + if (valid_a) { + + if (Geometry::segment_intersects_segment_2d(a,b,p_from,points[i].pos,NULL)) { + valid_a=false; + } + } + + if (valid_b) { + + if (Geometry::segment_intersects_segment_2d(a,b,p_to,points[i].pos,NULL)) { + valid_b=false; + } + } + + if (!valid_a && !valid_b) + continue; + + } + + if (valid_a) { + points[i].connections.insert(aidx); + points[aidx].connections.insert(i); + } + + if (valid_b) { + points[i].connections.insert(bidx); + points[bidx].connections.insert(i); + } + + } + //solve graph + + Set open_list; + + points[aidx].distance=0; + points[aidx].prev=aidx; + for(Set::Element *E=points[aidx].connections.front();E;E=E->next()) { + + open_list.insert(E->get()); + points[E->get()].distance=p_from.distance_to(points[E->get()].pos); + points[E->get()].prev=aidx; + + } + + + bool found_route=false; + + while(true) { + + if (open_list.size()==0) { + break; + } + //check open list + + int least_cost_point=-1; + float least_cost=1e30; + + //this could be faster (cache previous results) + for (Set::Element *E=open_list.front();E;E=E->next()) { + + const Point& p =points[E->get()]; + float cost = p.distance; + cost+=p.pos.distance_to(p_to); + if (costget(); + least_cost=cost; + } + } + + + Point &np = points[least_cost_point]; + //open the neighbours for search + + for(Set::Element *E=np.connections.front();E;E=E->next()) { + + Point& p =points[E->get()]; + float distance = np.pos.distance_to(p.pos) + np.distance; + + if (p.prev!=-1) { + //oh this was visited already, can we win the cost? + + if (p.distance>distance) { + + p.prev=least_cost_point; //reasign previous + p.distance=distance; + } + } else { + //add to open neighbours + + p.prev=least_cost_point; + p.distance=distance; + open_list.insert(E->get()); + + if (E->get()==bidx) { + //oh my reached end! stop algorithm + found_route=true; + break; + + } + + } + } + + if (found_route) + break; + + open_list.erase(least_cost_point); + } + + if (found_route) { + int at = bidx; + path.push_back(points[at].pos); + do { + at=points[at].prev; + path.push_back(points[at].pos); + } while (at!=aidx); + + path.invert();; + } + + for(int i=0;i p=p_data["points"]; + Array c=p_data["connections"]; + + ERR_FAIL_COND(c.size()!=p.size()); + if (c.size()) + return; + + int pc = p.size(); + points.resize(pc+2); + + DVector::Read pr=p.read(); + for(int i=0;i con=c[i]; + DVector::Read cr=con.read(); + int cc=con.size(); + for(int j=0;j segs=p_data["segments"]; + int sc=segs.size(); + ERR_FAIL_COND(sc&1); + DVector::Read sr = segs.read(); + for(int i=0;i p; + DVector ind; + Array connections; + p.resize(points.size()-2); + connections.resize(points.size()-2); + ind.resize(edges.size()*2); + { + DVector::Write wp=p.write(); + for(int i=0;i c; + c.resize(points[i].connections.size()); + { + DVector::Write cw=c.write(); + int idx=0; + for (Set::Element *E=points[i].connections.front();E;E=E->next()) { + cw[idx++]=E->get(); + } + } + connections[i]=c; + } + } + { + + DVector::Write iw=ind.write(); + int idx=0; + for (Set::Element *E=edges.front();E;E=E->next()) { + iw[idx++]=E->get().points[0]; + iw[idx++]=E->get().points[1]; + } + + } + + d["points"]=p; + d["connections"]=connections; + d["segments"]=ind; + + return d; + +} + +void PolygonPathFinder::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("setup","points","connections"),&PolygonPathFinder::setup); + ObjectTypeDB::bind_method(_MD("find_path","from","to"),&PolygonPathFinder::find_path); + ObjectTypeDB::bind_method(_MD("_set_data"),&PolygonPathFinder::_set_data); + ObjectTypeDB::bind_method(_MD("_get_data"),&PolygonPathFinder::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_data"),_SCS("_get_data")); + +} + +PolygonPathFinder::PolygonPathFinder() +{ +} + + diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h new file mode 100644 index 000000000000..31253e3177b0 --- /dev/null +++ b/scene/resources/polygon_path_finder.h @@ -0,0 +1,58 @@ +#ifndef POLYGON_PATH_FINDER_H +#define POLYGON_PATH_FINDER_H + +#include "resource.h" + +class PolygonPathFinder : public Resource { + + OBJ_TYPE(PolygonPathFinder,Resource); + + struct Point { + Vector2 pos; + Set connections; + float distance; + int prev; + }; + + struct Edge { + + int points[2]; + + _FORCE_INLINE_ bool operator<(const Edge& p_edge) const { + + if (points[0]==p_edge.points[0]) + return points[1]b) { + SWAP(a,b); + } + } + }; + + Vector2 outside_point; + + Vector points; + Set edges; + + bool _is_point_inside(const Vector2& p_point); + + void _set_data(const Dictionary& p_data); + Dictionary _get_data() const; +protected: + + static void _bind_methods(); +public: + + + void setup(const Vector& p_points, const Vector& p_connections); + Vector find_path(const Vector2& p_from, const Vector2& p_to); + + PolygonPathFinder(); +}; + +#endif // POLYGON_PATH_FINDER_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0aa7fc2650d0..2e94f3fe9d15 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -167,6 +167,7 @@ public: }; + /* TEXTURE API */ virtual RID texture_create()=0; @@ -455,6 +456,7 @@ public: virtual int light_instance_get_shadow_passes(RID p_light_instance) const=0; virtual void light_instance_set_shadow_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0)=0; virtual int light_instance_get_shadow_size(RID p_light_instance, int p_index=0) const=0; + virtual bool light_instance_get_pssm_shadow_overlap(RID p_light_instance) const=0; /* SHADOWS */ diff --git a/servers/visual/rasterizer_dummy.cpp b/servers/visual/rasterizer_dummy.cpp index 1d55693bfbac..3a04ba7504f9 100644 --- a/servers/visual/rasterizer_dummy.cpp +++ b/servers/visual/rasterizer_dummy.cpp @@ -1371,6 +1371,12 @@ int RasterizerDummy::light_instance_get_shadow_passes(RID p_light_instance) cons return 0; } +bool RasterizerDummy::light_instance_get_pssm_shadow_overlap(RID p_light_instance) const { + + return false; +} + + void RasterizerDummy::light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near,float p_split_far) { LightInstance *lighti = light_instance_owner.get( p_light_instance ); diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h index b683a25bdcac..a837d54b9b67 100644 --- a/servers/visual/rasterizer_dummy.h +++ b/servers/visual/rasterizer_dummy.h @@ -345,7 +345,7 @@ class RasterizerDummy : public Rasterizer { fx_param[VS::ENV_FX_PARAM_BCS_BRIGHTNESS]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_CONTRAST]=1.0; fx_param[VS::ENV_FX_PARAM_BCS_SATURATION]=1.0; - fx_param[VS::ENV_FX_PARAM_GAMMA]=1.0; + } @@ -628,6 +628,7 @@ public: virtual bool light_instance_assign_shadow(RID p_light_instance); virtual ShadowType light_instance_get_shadow_type(RID p_light_instance) const; virtual int light_instance_get_shadow_passes(RID p_light_instance) const; + virtual bool light_instance_get_pssm_shadow_overlap(RID p_light_instance) const; virtual void light_instance_set_custom_transform(RID p_light_instance, int p_index, const CameraMatrix& p_camera, const Transform& p_transform, float p_split_near=0,float p_split_far=0); virtual int light_instance_get_shadow_size(RID p_light_instance, int p_index=0) const { return 1; } diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 519e697ab25b..8f1d444185d8 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -3970,6 +3970,8 @@ void VisualServerRaster::_light_instance_update_pssm_shadow(Instance *p_light,Sc //float cull_max=p_cull_range.max; + bool overlap = rasterizer->light_instance_get_pssm_shadow_overlap(p_light->light_info->instance); + float cull_min=p_camera->znear; float cull_max=p_camera->zfar; float max_dist = rasterizer->light_directional_get_shadow_param(p_light->base_rid,VS::LIGHT_DIRECTIONAL_SHADOW_PARAM_MAX_DISTANCE); @@ -3999,7 +4001,7 @@ void VisualServerRaster::_light_instance_update_pssm_shadow(Instance *p_light,Sc camera_matrix.set_orthogonal( p_camera->size, viewport_rect.width / (float)viewport_rect.height, - distances[i], + distances[(i==0 || !overlap )?i:i-1], distances[i+1], p_camera->vaspect @@ -4011,7 +4013,7 @@ void VisualServerRaster::_light_instance_update_pssm_shadow(Instance *p_light,Sc camera_matrix.set_perspective( p_camera->fov, viewport_rect.width / (float)viewport_rect.height, - distances[i], + distances[(i==0 || !overlap )?i:i-1], distances[i+1], p_camera->vaspect diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index 919656fe0415..62f18b9e812d 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -165,6 +165,7 @@ void VisualServerWrapMT::finish() { texture_free_cached_ids(); + mesh_free_cached_ids(); thread=NULL; } else { @@ -187,6 +188,7 @@ VisualServerWrapMT::VisualServerWrapMT(VisualServer* p_contained,bool p_create_t draw_thread_up=false; alloc_mutex=Mutex::create(); texture_pool_max_size=GLOBAL_DEF("render/thread_textures_prealloc",20); + mesh_pool_max_size=GLOBAL_DEF("render/thread_meshes_prealloc",20); if (!p_create_thread) { server_thread=Thread::get_caller_ID(); } else { diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 0b7721cf8b6f..f807a4b3a9ea 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -66,6 +66,16 @@ class VisualServerWrapMT : public VisualServer { int texture_pool_max_size; List texture_id_pool; + int mesh_pool_max_size; + List mesh_id_pool; + +//#define DEBUG_SYNC + +#ifdef DEBUG_SYNC +#define SYNC_DEBUG print_line("sync on: "+String(__FUNCTION__)); +#else +#define SYNC_DEBUG +#endif public: @@ -74,6 +84,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type();\ @@ -115,6 +126,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type();\ @@ -168,6 +180,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1);\ @@ -179,6 +192,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1);\ @@ -231,6 +245,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2);\ @@ -242,6 +257,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2);\ @@ -294,6 +310,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3);\ @@ -357,6 +374,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4);\ @@ -368,6 +386,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4);\ @@ -420,6 +439,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4, p5);\ @@ -431,6 +451,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4, p5);\ @@ -483,6 +504,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4, p5, p6);\ @@ -546,6 +568,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ @@ -557,6 +580,7 @@ public: if (Thread::get_caller_ID()!=server_thread) {\ m_r ret;\ command_queue.push_and_ret( visual_server, &VisualServer::m_type,p1, p2, p3, p4, p5, p6, p7,&ret);\ + SYNC_DEBUG\ return ret;\ } else {\ return visual_server->m_type(p1, p2, p3, p4, p5, p6, p7);\ @@ -691,7 +715,7 @@ public: FUNC1RC(float,fixed_material_get_point_size,RID); /* SURFACE API */ - FUNC0R(RID,mesh_create); + FUNCRID(mesh); FUNC2(mesh_set_morph_target_count,RID,int); FUNC1RC(int,mesh_get_morph_target_count,RID); @@ -1122,7 +1146,7 @@ public: /* RENDER INFO */ FUNC1R(int,get_render_info,RenderInfo ); - FUNC1RC(bool,has_feature,Features ); + virtual bool has_feature(Features p_feature) const { return visual_server->has_feature(p_feature); } FUNC2(set_boot_image,const Image& , const Color& ); FUNC1(set_default_clear_color,const Color& ); diff --git a/servers/visual_server.h b/servers/visual_server.h index f01685890f24..fa4090d39e50 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -481,6 +481,8 @@ public: LIGHT_PARAM_SHADOW_DARKENING, LIGHT_PARAM_SHADOW_Z_OFFSET, LIGHT_PARAM_SHADOW_Z_SLOPE_SCALE, + LIGHT_PARAM_SHADOW_ESM_MULTIPLIER, + LIGHT_PARAM_SHADOW_BLUR_PASSES, LIGHT_PARAM_MAX }; @@ -728,7 +730,7 @@ public: ENV_FX_HDR, ENV_FX_FOG, ENV_FX_BCS, - ENV_FX_GAMMA, + ENV_FX_SRGB, ENV_FX_MAX }; @@ -768,7 +770,6 @@ public: ENV_FX_PARAM_BCS_BRIGHTNESS, ENV_FX_PARAM_BCS_CONTRAST, ENV_FX_PARAM_BCS_SATURATION, - ENV_FX_PARAM_GAMMA, ENV_FX_PARAM_MAX }; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index ceb5b45a034c..27a5ddbeaf95 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -4067,7 +4067,7 @@ EditorNode::EditorNode() { import_menu->get_popup()->add_separator(); - import_menu->get_popup()->add_item("Import Settings",SETTINGS_IMPORT); + import_menu->get_popup()->add_item("Re-Import..",SETTINGS_IMPORT); editor_plugin_screen=NULL; editor_plugin_over=NULL; diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 5d455942465e..c7593625ffc3 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -45,6 +45,7 @@ static const char *flag_names[]={ "Repeat", "Filter (Magnifying)", "Premultiply Alpha", + "Convert SRGB->Linear", NULL }; @@ -57,6 +58,7 @@ static const char *flag_short_names[]={ "Repeat", "Filter", "PMAlpha", + "ToLinear", NULL }; @@ -927,6 +929,10 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref1) { @@ -985,6 +991,11 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Refmaterial) { - - //triangle->get_uv(r_point); - diffuse_at_point=triangle->material->diffuse.get_color(uv); - specular_at_point=triangle->material->specular.get_color(uv); - } float dist = p_begin.distance_to(r_point); @@ -963,6 +957,14 @@ float BakedLightBaker::_throw_ray(int p_light_index,const Vector3& p_begin, cons + if (triangle->material) { + + //triangle->get_uv(r_point); + + diffuse_at_point=triangle->material->diffuse.get_color(uv); + specular_at_point=triangle->material->specular.get_color(uv); + } + diffuse_at_point.r=res_light.r*diffuse_at_point.r; diffuse_at_point.g=res_light.g*diffuse_at_point.g; diff --git a/tools/editor/plugins/baked_light_editor_plugin.cpp b/tools/editor/plugins/baked_light_editor_plugin.cpp index 4d84b959005d..71f9671fd93d 100644 --- a/tools/editor/plugins/baked_light_editor_plugin.cpp +++ b/tools/editor/plugins/baked_light_editor_plugin.cpp @@ -111,7 +111,7 @@ void BakedLightEditor::_notification(int p_option) { ERR_FAIL_COND(node->get_baked_light().is_null()); baker->update_octree_image(octree_texture); -#if 0 +#if 1 //debug Image img(baker->baked_octree_texture_w,baker->baked_octree_texture_h,0,Image::FORMAT_RGBA,octree_texture); Ref it = memnew( ImageTexture );