diff options
Diffstat (limited to 'drivers')
23 files changed, 303 insertions, 458 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index 9c8b16d3e5..e77b96cc87 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -14,6 +14,8 @@ SConscript("coreaudio/SCsub") SConscript("pulseaudio/SCsub") if env["platform"] == "windows": SConscript("wasapi/SCsub") + if not env.msvc: + SConscript("backtrace/SCsub") if env["xaudio2"]: SConscript("xaudio2/SCsub") diff --git a/drivers/backtrace/SCsub b/drivers/backtrace/SCsub new file mode 100644 index 0000000000..f61fb21581 --- /dev/null +++ b/drivers/backtrace/SCsub @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +Import("env") + +env_backtrace = env.Clone() + +# Thirdparty source files + +thirdparty_obj = [] + +thirdparty_dir = "#thirdparty/libbacktrace/" +thirdparty_sources = [ + "atomic.c", + "dwarf.c", + "fileline.c", + "posix.c", + "print.c", + "sort.c", + "state.c", + "backtrace.c", + "simple.c", + "pecoff.c", + "read.c", + "alloc.c", +] +thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + +env_backtrace.Prepend(CPPPATH=[thirdparty_dir]) + +env_thirdparty = env_backtrace.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) + +env.drivers_sources += thirdparty_obj + +# Godot source files + +driver_obj = [] + +env_backtrace.add_source_files(driver_obj, "*.cpp") +env.drivers_sources += driver_obj + +# Needed to force rebuilding the driver files when the thirdparty library is updated. +env.Depends(driver_obj, thirdparty_obj) diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp index 6e64652982..47ca832bd7 100644 --- a/drivers/gles3/effects/copy_effects.cpp +++ b/drivers/gles3/effects/copy_effects.cpp @@ -198,8 +198,7 @@ void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, con for (int i = 1; i < p_mipmap_count; i++) { dest_region.position.x >>= 1; dest_region.position.y >>= 1; - dest_region.size.x = MAX(1, dest_region.size.x >> 1); - dest_region.size.y = MAX(1, dest_region.size.y >> 1); + dest_region.size = Size2i(dest_region.size.x >> 1, dest_region.size.y >> 1).maxi(1); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[i % 2]); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_source_texture, i); glBlitFramebuffer(source_region.position.x, source_region.position.y, source_region.position.x + source_region.size.x, source_region.position.y + source_region.size.y, @@ -238,8 +237,7 @@ void CopyEffects::gaussian_blur(GLuint p_source_texture, int p_mipmap_count, con for (int i = 1; i < p_mipmap_count; i++) { dest_region.position.x >>= 1; dest_region.position.y >>= 1; - dest_region.size.x = MAX(1, dest_region.size.x >> 1); - dest_region.size.y = MAX(1, dest_region.size.y >> 1); + dest_region.size = Size2i(dest_region.size.x >> 1, dest_region.size.y >> 1).maxi(1); base_size.x >>= 1; base_size.y >>= 1; diff --git a/drivers/gles3/effects/post_effects.cpp b/drivers/gles3/effects/post_effects.cpp index 8ad872f319..105c8f6b71 100644 --- a/drivers/gles3/effects/post_effects.cpp +++ b/drivers/gles3/effects/post_effects.cpp @@ -87,7 +87,7 @@ void PostEffects::_draw_screen_triangle() { glBindVertexArray(0); } -void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view, bool p_use_multiview) { +void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view, bool p_use_multiview, uint64_t p_spec_constants) { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glDisable(GL_BLEND); @@ -96,7 +96,7 @@ void PostEffects::post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuin glViewport(0, 0, p_dest_size.x, p_dest_size.y); PostShaderGLES3::ShaderVariant mode = PostShaderGLES3::MODE_DEFAULT; - uint64_t flags = 0; + uint64_t flags = p_spec_constants; if (p_use_multiview) { flags |= PostShaderGLES3::USE_MULTIVIEW; } diff --git a/drivers/gles3/effects/post_effects.h b/drivers/gles3/effects/post_effects.h index b90c77d6c7..916d29a052 100644 --- a/drivers/gles3/effects/post_effects.h +++ b/drivers/gles3/effects/post_effects.h @@ -59,7 +59,7 @@ public: PostEffects(); ~PostEffects(); - void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view = 0, bool p_use_multiview = false); + void post_copy(GLuint p_dest_framebuffer, Size2i p_dest_size, GLuint p_source_color, Size2i p_source_size, float p_luminance_multiplier, const Glow::GLOWLEVEL *p_glow_buffers, float p_glow_intensity, uint32_t p_view = 0, bool p_use_multiview = false, uint64_t p_spec_constants = 0); }; } //namespace GLES3 diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index bc1af86938..ee770be3da 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -788,7 +788,6 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, } if (!p_apply_color_adjustments_in_post) { spec_constants |= SkyShaderGLES3::APPLY_TONEMAPPING; - // TODO add BCS and color corrections once supported. } RS::EnvironmentBG background = environment_get_background(p_env); @@ -2336,9 +2335,18 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ SceneState::TonemapUBO tonemap_ubo; if (render_data.environment.is_valid()) { + bool use_bcs = environment_get_adjustments_enabled(render_data.environment); + if (use_bcs) { + apply_color_adjustments_in_post = true; + } + tonemap_ubo.exposure = environment_get_exposure(render_data.environment); tonemap_ubo.white = environment_get_white(render_data.environment); tonemap_ubo.tonemapper = int32_t(environment_get_tone_mapper(render_data.environment)); + + tonemap_ubo.brightness = environment_get_adjustments_brightness(render_data.environment); + tonemap_ubo.contrast = environment_get_adjustments_contrast(render_data.environment); + tonemap_ubo.saturation = environment_get_adjustments_saturation(render_data.environment); } if (scene_state.tonemap_buffer == 0) { @@ -2558,8 +2566,6 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ if (!apply_color_adjustments_in_post) { spec_constant_base_flags |= SceneShaderGLES3::APPLY_TONEMAPPING; - - // TODO add BCS and Color corrections here once supported. } } // Render Opaque Objects. @@ -2700,6 +2706,29 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend rb->check_glow_buffers(); } + bool use_bcs = environment_get_adjustments_enabled(p_render_data->environment); + uint64_t bcs_spec_constants = 0; + RID color_correction_texture = environment_get_color_correction(p_render_data->environment); + if (use_bcs && color_correction_texture.is_valid()) { + bcs_spec_constants |= PostShaderGLES3::USE_BCS; + bcs_spec_constants |= PostShaderGLES3::USE_COLOR_CORRECTION; + + bool use_1d_lut = environment_get_use_1d_color_correction(p_render_data->environment); + GLenum texture_target = GL_TEXTURE_3D; + if (use_1d_lut) { + bcs_spec_constants |= PostShaderGLES3::USE_1D_LUT; + texture_target = GL_TEXTURE_2D; + } + + glActiveTexture(GL_TEXTURE2); + glBindTexture(texture_target, texture_storage->texture_get_texid(color_correction_texture)); + glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + if (view_count == 1) { // Resolve if needed. if (fbo_msaa_3d != 0 && msaa3d_needs_resolve) { @@ -2735,7 +2764,7 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend } // Copy color buffer - post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity); + post_effects->post_copy(fbo_rt, target_size, color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, 0, false, bcs_spec_constants); // Copy depth buffer glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_int); @@ -2803,7 +2832,7 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend glBindFramebuffer(GL_FRAMEBUFFER, fbos[2]); glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, write_color, 0, v); - post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, v, true); + post_effects->post_copy(fbos[2], target_size, source_color, internal_size, p_render_data->luminance_multiplier, glow_buffers, glow_intensity, v, true, bcs_spec_constants); } // Copy depth @@ -2824,6 +2853,9 @@ void RasterizerSceneGLES3::_render_post_processing(const RenderDataGLES3 *p_rend glBindFramebuffer(GL_FRAMEBUFFER, fbo_rt); glDeleteFramebuffers(3, fbos); } + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, 0); } template <PassMode p_pass_mode> @@ -3009,6 +3041,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } } break; + case GLES3::SceneShaderData::BLEND_MODE_PREMULT_ALPHA: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + } break; case GLES3::SceneShaderData::BLEND_MODE_ALPHA_TO_COVERAGE: { // Do nothing for now. } break; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index cc479bd4e9..c656ee3cc7 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -434,6 +434,11 @@ private: float white = 1.0; int32_t tonemapper = 0; int32_t pad = 0; + + int32_t pad2 = 0; + float brightness = 1.0; + float contrast = 1.0; + float saturation = 1.0; }; static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes"); diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index efddbe9ad2..65332c06be 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -776,6 +776,12 @@ void main() { vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array[light_base].texture_matrix[0], light_array[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. vec2 tex_uv_atlas = tex_uv * light_array[light_base].atlas_rect.zw + light_array[light_base].atlas_rect.xy; + + if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { + //if outside the light texture, light color is zero + continue; + } + vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0); vec4 light_base_color = light_array[light_base].color; @@ -800,10 +806,6 @@ void main() { light_color.rgb *= base_color.rgb; } #endif - if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) { - //if outside the light texture, light color is zero - light_color.a = 0.0; - } if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations. diff --git a/drivers/gles3/shaders/effects/post.glsl b/drivers/gles3/shaders/effects/post.glsl index e61171c92a..1d17510c52 100644 --- a/drivers/gles3/shaders/effects/post.glsl +++ b/drivers/gles3/shaders/effects/post.glsl @@ -1,13 +1,15 @@ /* clang-format off */ #[modes] -mode_default = #define MODE_DEFAULT -// mode_glow = #define MODE_GLOW +mode_default = #[specializations] USE_MULTIVIEW = false USE_GLOW = false USE_LUMINANCE_MULTIPLIER = false +USE_BCS = false +USE_COLOR_CORRECTION = false +USE_1D_LUT = false #[vertex] layout(location = 0) in vec2 vertex_attrib; @@ -25,6 +27,9 @@ void main() { #[fragment] /* clang-format on */ +// If we reach this code, we always tonemap. +#define APPLY_TONEMAPPING + #include "../tonemap_inc.glsl" #ifdef USE_MULTIVIEW @@ -57,6 +62,35 @@ vec4 get_glow_color(vec2 uv) { } #endif // USE_GLOW +#ifdef USE_COLOR_CORRECTION +#ifdef USE_1D_LUT +uniform sampler2D source_color_correction; //texunit:2 + +vec3 apply_color_correction(vec3 color) { + color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; + color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; + color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; + return color; +} +#else +uniform sampler3D source_color_correction; //texunit:2 + +vec3 apply_color_correction(vec3 color) { + return textureLod(source_color_correction, color, 0.0).rgb; +} +#endif // USE_1D_LUT +#endif // USE_COLOR_CORRECTION + +#ifdef USE_BCS +vec3 apply_bcs(vec3 color) { + color = mix(vec3(0.0), color, brightness); + color = mix(vec3(0.5), color, contrast); + color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, saturation); + + return color; +} +#endif + in vec2 uv_interp; layout(location = 0) out vec4 frag_color; @@ -85,11 +119,11 @@ void main() { color.rgb = linear_to_srgb(color.rgb); #ifdef USE_BCS - color.rgb = apply_bcs(color.rgb, bcs); + color.rgb = apply_bcs(color.rgb); #endif #ifdef USE_COLOR_CORRECTION - color.rgb = apply_color_correction(color.rgb, color_correction); + color.rgb = apply_color_correction(color.rgb); #endif frag_color = color; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 1973eb56c2..2b372cb88d 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1442,6 +1442,9 @@ void main() { float clearcoat_roughness = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); +#ifdef PREMUL_ALPHA_USED + float premul_alpha = 1.0; +#endif // PREMUL_ALPHA_USED #ifndef FOG_DISABLED vec4 fog = vec4(0.0); #endif // !FOG_DISABLED @@ -1535,6 +1538,7 @@ void main() { if (alpha < alpha_scissor_threshold) { discard; } + alpha = 1.0; #else #ifdef MODE_RENDER_DEPTH #ifdef USE_OPAQUE_PREPASS @@ -1858,23 +1862,16 @@ void main() { #endif // !MODE_RENDER_DEPTH #if defined(USE_SHADOW_TO_OPACITY) +#ifndef MODE_RENDER_DEPTH alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } -#else -#ifdef MODE_RENDER_DEPTH -#ifdef USE_OPAQUE_PREPASS - - if (alpha < opaque_prepass_threshold) { - discard; - } -#endif // USE_OPAQUE_PREPASS -#endif // MODE_RENDER_DEPTH #endif // !ALPHA_SCISSOR_USED +#endif // !MODE_RENDER_DEPTH #endif // USE_SHADOW_TO_OPACITY #ifdef MODE_RENDER_DEPTH @@ -1934,13 +1931,6 @@ void main() { #endif frag_color.rgb = linear_to_srgb(frag_color.rgb); -#ifdef USE_BCS - frag_color.rgb = apply_bcs(frag_color.rgb, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction); -#endif #else // !BASE_PASS frag_color = vec4(0.0, 0.0, 0.0, alpha); #endif // !BASE_PASS @@ -2152,19 +2142,14 @@ void main() { #endif additive_light_color = linear_to_srgb(additive_light_color); -#ifdef USE_BCS - additive_light_color = apply_bcs(additive_light_color, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - additive_light_color = apply_color_correction(additive_light_color, color_correction); -#endif - frag_color.rgb += additive_light_color; #endif // USE_ADDITIVE_LIGHTING - frag_color.rgb *= scene_data.luminance_multiplier; #endif // !RENDER_MATERIAL #endif // !MODE_RENDER_DEPTH + +#ifdef PREMUL_ALPHA_USED + frag_color.rgb *= premul_alpha; +#endif // PREMUL_ALPHA_USED } diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl index 6c33bf7123..26549901a6 100644 --- a/drivers/gles3/shaders/sky.glsl +++ b/drivers/gles3/shaders/sky.glsl @@ -209,14 +209,6 @@ void main() { #endif color = linear_to_srgb(color); -#ifdef USE_BCS - color = apply_bcs(color, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - color = apply_color_correction(color, color_correction); -#endif - frag_color.rgb = color * luminance_multiplier; frag_color.a = alpha; diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl deleted file mode 100644 index 0b769e77f2..0000000000 --- a/drivers/gles3/shaders/tonemap.glsl +++ /dev/null @@ -1,333 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -layout(location = 0) in vec2 vertex_attrib; -/* clang-format on */ -layout(location = 4) in vec2 uv_in; - -out vec2 uv_interp; - -void main() { - gl_Position = vec4(vertex_attrib, 0.0, 1.0); - - uv_interp = uv_in; -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -in vec2 uv_interp; -/* clang-format on */ - -layout(location = 0) out vec4 frag_color; - -#ifdef USE_MULTIVIEW -uniform highp sampler2DArray source; //texunit:0 -#else -uniform highp sampler2D source; //texunit:0 -#endif - -#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) -#define USING_GLOW // only use glow when at least one glow level is selected - -#ifdef USE_MULTI_TEXTURE_GLOW -uniform highp sampler2D source_glow1; //texunit:2 -uniform highp sampler2D source_glow2; //texunit:3 -uniform highp sampler2D source_glow3; //texunit:4 -uniform highp sampler2D source_glow4; //texunit:5 -uniform highp sampler2D source_glow5; //texunit:6 -uniform highp sampler2D source_glow6; //texunit:7 -#ifdef USE_GLOW_LEVEL7 -uniform highp sampler2D source_glow7; //texunit:8 -#endif -#else -uniform highp sampler2D source_glow; //texunit:2 -#endif -uniform highp float glow_intensity; -#endif - -#ifdef USE_BCS -uniform vec3 bcs; -#endif - -#ifdef USE_FXAA -uniform vec2 pixel_size; -#endif - -#ifdef USE_COLOR_CORRECTION -uniform sampler2D color_correction; //texunit:1 -#endif - -#ifdef USE_GLOW_FILTER_BICUBIC -// w0, w1, w2, and w3 are the four cubic B-spline basis functions -float w0(float a) { - return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0); -} - -float w1(float a) { - return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0); -} - -float w2(float a) { - return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0); -} - -float w3(float a) { - return (1.0 / 6.0) * (a * a * a); -} - -// g0 and g1 are the two amplitude functions -float g0(float a) { - return w0(a) + w1(a); -} - -float g1(float a) { - return w2(a) + w3(a); -} - -// h0 and h1 are the two offset functions -float h0(float a) { - return -1.0 + w1(a) / (w0(a) + w1(a)); -} - -float h1(float a) { - return 1.0 + w3(a) / (w2(a) + w3(a)); -} - -uniform ivec2 glow_texture_size; - -vec4 texture_bicubic(sampler2D tex, vec2 uv, int p_lod) { - float lod = float(p_lod); - vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 texel_size = vec2(1.0) / tex_size; - - uv = uv * tex_size + vec2(0.5); - - vec2 iuv = floor(uv); - vec2 fuv = fract(uv); - - float g0x = g0(fuv.x); - float g1x = g1(fuv.x); - float h0x = h0(fuv.x); - float h1x = h1(fuv.x); - float h0y = h0(fuv.y); - float h1y = h1(fuv.y); - - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size; - - return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); -} - -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture_bicubic(m_tex, m_uv, m_lod) -#else //!USE_GLOW_FILTER_BICUBIC -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) -#endif //USE_GLOW_FILTER_BICUBIC - -vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode -#ifdef USE_GLOW_REPLACE - color = glow; -#endif - -#ifdef USE_GLOW_SCREEN - color = max((color + glow) - (color * glow), vec3(0.0)); -#endif - -#ifdef USE_GLOW_SOFTLIGHT - glow = glow * vec3(0.5) + vec3(0.5); - - color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); -#endif - -#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive - color += glow; -#endif - - return color; -} - -vec3 apply_bcs(vec3 color, vec3 bcs) { - color = mix(vec3(0.0), color, bcs.x); - color = mix(vec3(0.5), color, bcs.y); - color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); - - return color; -} - -vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { - color.r = texture(correction_tex, vec2(color.r, 0.0)).r; - color.g = texture(correction_tex, vec2(color.g, 0.0)).g; - color.b = texture(correction_tex, vec2(color.b, 0.0)).b; - - return color; -} - -vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { - const float FXAA_REDUCE_MIN = (1.0 / 128.0); - const float FXAA_REDUCE_MUL = (1.0 / 8.0); - const float FXAA_SPAN_MAX = 8.0; - -#ifdef USE_MULTIVIEW - vec3 rgbNW = textureLod(source, vec3(uv_interp + vec2(-1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz; - vec3 rgbNE = textureLod(source, vec3(uv_interp + vec2(1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz; - vec3 rgbSW = textureLod(source, vec3(uv_interp + vec2(-1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz; - vec3 rgbSE = textureLod(source, vec3(uv_interp + vec2(1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz; -#else - vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz; - vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz; - vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz; - vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz; -#endif - vec3 rgbM = color; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), - FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * - pixel_size; - -#ifdef USE_MULTIVIEW - vec3 rgbA = 0.5 * (textureLod(source, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz); -#else - vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz); -#endif - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) { - return rgbA; - } else { - return rgbB; - } -} - -void main() { -#ifdef USE_MULTIVIEW - vec4 color = textureLod(source, vec3(uv_interp, ViewIndex), 0.0); -#else - vec4 color = textureLod(source, uv_interp, 0.0); -#endif - -#ifdef USE_FXAA - color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size); -#endif - - // Glow - -#ifdef USING_GLOW - vec3 glow = vec3(0.0); -#ifdef USE_MULTI_TEXTURE_GLOW -#ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(source_glow1, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL2 - glow += GLOW_TEXTURE_SAMPLE(source_glow2, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL3 - glow += GLOW_TEXTURE_SAMPLE(source_glow3, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL4 - glow += GLOW_TEXTURE_SAMPLE(source_glow4, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL5 - glow += GLOW_TEXTURE_SAMPLE(source_glow5, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL6 - glow += GLOW_TEXTURE_SAMPLE(source_glow6, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(source_glow7, uv_interp, 0).rgb; -#endif -#endif -#endif -#endif -#endif -#endif -#endif - -#else - -#ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 1).rgb; -#endif - -#ifdef USE_GLOW_LEVEL2 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 2).rgb; -#endif - -#ifdef USE_GLOW_LEVEL3 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 3).rgb; -#endif - -#ifdef USE_GLOW_LEVEL4 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 4).rgb; -#endif - -#ifdef USE_GLOW_LEVEL5 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 5).rgb; -#endif - -#ifdef USE_GLOW_LEVEL6 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 6).rgb; -#endif - -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 7).rgb; -#endif -#endif //USE_MULTI_TEXTURE_GLOW - - glow *= glow_intensity; - color.rgb = apply_glow(color.rgb, glow); -#endif - - // Additional effects - -#ifdef USE_BCS - color.rgb = apply_bcs(color.rgb, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - color.rgb = apply_color_correction(color.rgb, color_correction); -#endif - - frag_color = color; -} diff --git a/drivers/gles3/shaders/tonemap_inc.glsl b/drivers/gles3/shaders/tonemap_inc.glsl index f8f12760ec..fb915aeb38 100644 --- a/drivers/gles3/shaders/tonemap_inc.glsl +++ b/drivers/gles3/shaders/tonemap_inc.glsl @@ -1,43 +1,31 @@ -#ifdef USE_BCS -uniform vec3 bcs; -#endif - -#ifdef USE_COLOR_CORRECTION -#ifdef USE_1D_LUT -uniform sampler2D source_color_correction; //texunit:-1 -#else -uniform sampler3D source_color_correction; //texunit:-1 -#endif -#endif - layout(std140) uniform TonemapData { //ubo:0 float exposure; float white; int tonemapper; int pad; -}; -vec3 apply_bcs(vec3 color, vec3 bcs) { - color = mix(vec3(0.0), color, bcs.x); - color = mix(vec3(0.5), color, bcs.y); - color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); + int pad2; + float brightness; + float contrast; + float saturation; +}; - return color; -} -#ifdef USE_COLOR_CORRECTION -#ifdef USE_1D_LUT -vec3 apply_color_correction(vec3 color) { - color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r; - color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g; - color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b; - return color; +// This expects 0-1 range input. +vec3 linear_to_srgb(vec3 color) { + //color = clamp(color, vec3(0.0), vec3(1.0)); + //const vec3 a = vec3(0.055f); + //return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); + // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html + return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0)); } -#else -vec3 apply_color_correction(vec3 color) { - return textureLod(source_color_correction, color, 0.0).rgb; + +// This expects 0-1 range input, outside that range it behaves poorly. +vec3 srgb_to_linear(vec3 color) { + // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html + return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878); } -#endif -#endif + +#ifdef APPLY_TONEMAPPING vec3 tonemap_filmic(vec3 color, float p_white) { // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers @@ -92,21 +80,6 @@ vec3 tonemap_reinhard(vec3 color, float p_white) { return (p_white * color + color) / (color * p_white + p_white); } -// This expects 0-1 range input. -vec3 linear_to_srgb(vec3 color) { - //color = clamp(color, vec3(0.0), vec3(1.0)); - //const vec3 a = vec3(0.055f); - //return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); - // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html - return max(vec3(1.055) * pow(color, vec3(0.416666667)) - vec3(0.055), vec3(0.0)); -} - -// This expects 0-1 range input, outside that range it behaves poorly. -vec3 srgb_to_linear(vec3 color) { - // Approximation from http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html - return color * (color * (color * 0.305306011 + 0.682171111) + 0.012522878); -} - #define TONEMAPPER_LINEAR 0 #define TONEMAPPER_REINHARD 1 #define TONEMAPPER_FILMIC 2 @@ -125,3 +98,5 @@ vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always return tonemap_aces(max(vec3(0.0f), color), p_white); } } + +#endif // APPLY_TONEMAPPING diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 62d22dac4d..996c205042 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1243,6 +1243,7 @@ MaterialStorage::MaterialStorage() { actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth"; actions.renames["ALBEDO"] = "albedo"; actions.renames["ALPHA"] = "alpha"; + actions.renames["PREMUL_ALPHA_FACTOR"] = "premul_alpha"; actions.renames["METALLIC"] = "metallic"; actions.renames["SPECULAR"] = "specular"; actions.renames["ROUGHNESS"] = "roughness"; @@ -1327,6 +1328,7 @@ MaterialStorage::MaterialStorage() { actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n"; actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n"; actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE"; + actions.usage_defines["PREMULT_ALPHA_FACTOR"] = "#define PREMULT_ALPHA_USED"; actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n"; @@ -1964,13 +1966,9 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture Variant value = d["value"]; if (gvtype >= RS::GLOBAL_VAR_TYPE_SAMPLER2D) { - //textire - if (!p_load_textures) { - continue; - } - String path = value; - if (path.is_empty()) { + // Don't load the textures, but still add the parameter so shaders compile correctly while loading. + if (!p_load_textures || path.is_empty()) { value = RID(); } else { Ref<Resource> resource = ResourceLoader::load(path); @@ -2908,6 +2906,7 @@ void SceneShaderData::set_code(const String &p_code) { actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX); actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB); actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL); + actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PREMULT_ALPHA); actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_modei, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE); actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_modei, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE); diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 02aecf33d6..392ebcc570 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -248,6 +248,7 @@ struct SceneShaderData : public ShaderData { BLEND_MODE_ADD, BLEND_MODE_SUB, BLEND_MODE_MUL, + BLEND_MODE_PREMULT_ALPHA, BLEND_MODE_ALPHA_TO_COVERAGE }; diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp index 6803c92dc9..cb194933ed 100644 --- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp +++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp @@ -577,8 +577,7 @@ void RenderSceneBuffersGLES3::check_glow_buffers() { GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton(); Size2i level_size = internal_size; for (int i = 0; i < 4; i++) { - level_size.x = MAX(level_size.x >> 1, 4); - level_size.y = MAX(level_size.y >> 1, 4); + level_size = Size2i(level_size.x >> 1, level_size.y >> 1).maxi(4); glow.levels[i].size = level_size; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 6f32e4d49d..373df8d8de 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -2812,7 +2812,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { } rt->process_size = size * scale / 100; - rt->process_size = rt->process_size.max(Size2i(1, 1)); + rt->process_size = rt->process_size.maxi(1); glGenTextures(2, rt->sdf_texture_process); glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[0]); diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp index 7e2e3dfa2b..356dc06733 100644 --- a/drivers/gles3/storage/utilities.cpp +++ b/drivers/gles3/storage/utilities.cpp @@ -299,7 +299,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de ERR_FAIL_NULL(vn); if (p_enter) { - if (!vn->enter_callback.is_null()) { + if (vn->enter_callback.is_valid()) { if (p_deferred) { vn->enter_callback.call_deferred(); } else { @@ -307,7 +307,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de } } } else { - if (!vn->exit_callback.is_null()) { + if (vn->exit_callback.is_valid()) { if (p_deferred) { vn->exit_callback.call_deferred(); } else { diff --git a/drivers/png/SCsub b/drivers/png/SCsub index dd4777a19b..e38f3c4760 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -39,7 +39,7 @@ if env["builtin_libpng"]: if env["arch"].startswith("arm"): if env.msvc: # Can't compile assembly files with MSVC. - env_thirdparty.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT"), 0]) + env_thirdparty.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT", 0)]) else: env_neon = env_thirdparty.Clone() if "S_compiler" in env: diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 1906d168fe..803555cb07 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -1008,7 +1008,7 @@ VkResult RenderingDeviceDriverVulkan::_create_render_pass(VkDevice p_device, con const uint32_t depth_attachment_index = vector_base_index + 3; _convert_subpass_attachments(p_create_info->pSubpasses[i].pInputAttachments, p_create_info->pSubpasses[i].inputAttachmentCount, subpasses_attachments[input_attachments_index]); _convert_subpass_attachments(p_create_info->pSubpasses[i].pColorAttachments, p_create_info->pSubpasses[i].colorAttachmentCount, subpasses_attachments[color_attachments_index]); - _convert_subpass_attachments(p_create_info->pSubpasses[i].pResolveAttachments, p_create_info->pSubpasses[i].colorAttachmentCount, subpasses_attachments[resolve_attachments_index]); + _convert_subpass_attachments(p_create_info->pSubpasses[i].pResolveAttachments, (p_create_info->pSubpasses[i].pResolveAttachments != nullptr) ? p_create_info->pSubpasses[i].colorAttachmentCount : 0, subpasses_attachments[resolve_attachments_index]); _convert_subpass_attachments(p_create_info->pSubpasses[i].pDepthStencilAttachment, (p_create_info->pSubpasses[i].pDepthStencilAttachment != nullptr) ? 1 : 0, subpasses_attachments[depth_attachment_index]); // Ignores sType and pNext from the subpass. diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 43dd62cdf6..63ba6a6c96 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -396,6 +396,66 @@ bool DirAccessWindows::is_case_sensitive(const String &p_path) const { } } +bool DirAccessWindows::is_link(String p_file) { + String f = p_file; + + if (!f.is_absolute_path()) { + f = get_current_dir().path_join(f); + } + f = fix_path(f); + + DWORD attr = GetFileAttributesW((LPCWSTR)(f.utf16().get_data())); + if (attr == INVALID_FILE_ATTRIBUTES) { + return false; + } + + return (attr & FILE_ATTRIBUTE_REPARSE_POINT); +} + +String DirAccessWindows::read_link(String p_file) { + String f = p_file; + + if (!f.is_absolute_path()) { + f = get_current_dir().path_join(f); + } + f = fix_path(f); + + HANDLE hfile = CreateFileW((LPCWSTR)(f.utf16().get_data()), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (hfile == INVALID_HANDLE_VALUE) { + return f; + } + + DWORD ret = GetFinalPathNameByHandleW(hfile, nullptr, 0, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED); + if (ret == 0) { + return f; + } + Char16String cs; + cs.resize(ret + 1); + GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED); + CloseHandle(hfile); + + return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)"); +} + +Error DirAccessWindows::create_link(String p_source, String p_target) { + if (p_target.is_relative_path()) { + p_target = get_current_dir().path_join(p_target); + } + + p_source = fix_path(p_source); + p_target = fix_path(p_target); + + DWORD file_attr = GetFileAttributesW((LPCWSTR)(p_source.utf16().get_data())); + bool is_dir = (file_attr & FILE_ATTRIBUTE_DIRECTORY); + + DWORD flags = ((is_dir) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + if (CreateSymbolicLinkW((LPCWSTR)p_target.utf16().get_data(), (LPCWSTR)p_source.utf16().get_data(), flags) != 0) { + return OK; + } else { + return FAILED; + } +} + DirAccessWindows::DirAccessWindows() { p = memnew(DirAccessWindowsPrivate); p->h = INVALID_HANDLE_VALUE; diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index 576ba18d9a..46755cbf33 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.h @@ -77,9 +77,9 @@ public: virtual Error rename(String p_path, String p_new_path) override; virtual Error remove(String p_path) override; - virtual bool is_link(String p_file) override { return false; }; - virtual String read_link(String p_file) override { return p_file; }; - virtual Error create_link(String p_source, String p_target) override { return FAILED; }; + virtual bool is_link(String p_file) override; + virtual String read_link(String p_file) override; + virtual Error create_link(String p_source, String p_target) override; uint64_t get_space_left() override; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 726e0fdc5a..9885d9d7ee 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -32,6 +32,7 @@ #include "file_access_windows.h" +#include "core/config/project_settings.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -121,19 +122,63 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) { // Windows is case insensitive, but all other platforms are sensitive to it // To ease cross-platform development, we issue a warning if users try to access // a file using the wrong case (which *works* on Windows, but won't on other - // platforms). - if (p_mode_flags == READ) { - WIN32_FIND_DATAW d; - HANDLE fnd = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d); - if (fnd != INVALID_HANDLE_VALUE) { - String fname = String::utf16((const char16_t *)(d.cFileName)); - if (!fname.is_empty()) { - String base_file = path.get_file(); - if (base_file != fname && base_file.findn(fname) == 0) { - WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); + // platforms), we only check for relative paths, or paths in res:// or user://, + // other paths aren't likely to be portable anyway. + if (p_mode_flags == READ && (p_path.is_relative_path() || get_access_type() != ACCESS_FILESYSTEM)) { + String base_path = path; + String working_path; + String proper_path; + + if (get_access_type() == ACCESS_RESOURCES) { + if (ProjectSettings::get_singleton()) { + working_path = ProjectSettings::get_singleton()->get_resource_path(); + if (!working_path.is_empty()) { + base_path = working_path.path_to_file(base_path); } } + proper_path = "res://"; + } else if (get_access_type() == ACCESS_USERDATA) { + working_path = OS::get_singleton()->get_user_data_dir(); + if (!working_path.is_empty()) { + base_path = working_path.path_to_file(base_path); + } + proper_path = "user://"; + } + + WIN32_FIND_DATAW d; + Vector<String> parts = base_path.split("/"); + + bool mismatch = false; + + for (const String &part : parts) { + working_path = working_path.path_join(part); + + // Skip if relative. + if (part == "." || part == "..") { + proper_path = proper_path.path_join(part); + continue; + } + + HANDLE fnd = FindFirstFileW((LPCWSTR)(working_path.utf16().get_data()), &d); + + if (fnd == INVALID_HANDLE_VALUE) { + mismatch = false; + break; + } + + const String fname = String::utf16((const char16_t *)(d.cFileName)); + FindClose(fnd); + + if (!mismatch) { + mismatch = (part != fname && part.findn(fname) == 0); + } + + proper_path = proper_path.path_join(fname); + } + + if (mismatch) { + WARN_PRINT("Case mismatch opening requested file '" + p_path + "', stored as '" + proper_path + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); } } #endif |
