diff options
Diffstat (limited to 'drivers/gles3/shaders')
-rw-r--r-- | drivers/gles3/shaders/SCsub | 9 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas.glsl | 1056 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_shadow.glsl | 2 | ||||
-rw-r--r-- | drivers/gles3/shaders/canvas_uniforms_inc.glsl | 120 | ||||
-rw-r--r-- | drivers/gles3/shaders/copy.glsl | 41 | ||||
-rw-r--r-- | drivers/gles3/shaders/cube_to_dp.glsl | 4 | ||||
-rw-r--r-- | drivers/gles3/shaders/cubemap_filter.glsl | 4 | ||||
-rw-r--r-- | drivers/gles3/shaders/effect_blur.glsl | 4 | ||||
-rw-r--r-- | drivers/gles3/shaders/lens_distorted.glsl | 2 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 34 | ||||
-rw-r--r-- | drivers/gles3/shaders/stdlib_inc.glsl | 58 | ||||
-rw-r--r-- | drivers/gles3/shaders/tonemap.glsl | 4 |
12 files changed, 804 insertions, 534 deletions
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index 47d56b9947..2f56b77bdc 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -3,12 +3,5 @@ Import("env") if "GLES3_GLSL" in env["BUILDERS"]: - env.GLES3_GLSL("copy.glsl") env.GLES3_GLSL("canvas.glsl") - env.GLES3_GLSL("canvas_shadow.glsl") - env.GLES3_GLSL("scene.glsl") - env.GLES3_GLSL("cubemap_filter.glsl") - env.GLES3_GLSL("cube_to_dp.glsl") - env.GLES3_GLSL("effect_blur.glsl") - env.GLES3_GLSL("tonemap.glsl") - env.GLES3_GLSL("lens_distorted.glsl") + env.GLES3_GLSL("copy.glsl") diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index f2b141252a..a18c451858 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -1,665 +1,753 @@ /* clang-format off */ -[vertex] +#[modes] -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif +mode_quad = +mode_ninepatch = #define USE_NINEPATCH +mode_primitive = #define USE_PRIMITIVE +mode_attributes = #define USE_ATTRIBUTES -uniform highp mat4 projection_matrix; -/* clang-format on */ +#[specializations] -uniform highp mat4 modelview_matrix; -uniform highp mat4 extra_matrix; -layout(location = 0) in highp vec2 vertex; +DISABLE_LIGHTING = false -#ifdef USE_ATTRIB_LIGHT_ANGLE -// shared with tangent, not used in canvas shader -layout(location = 2) in highp float light_angle; -#endif +#[vertex] +#ifdef USE_ATTRIBUTES +layout(location = 0) in vec2 vertex_attrib; layout(location = 3) in vec4 color_attrib; layout(location = 4) in vec2 uv_attrib; -#ifdef USE_ATTRIB_MODULATE -layout(location = 5) in highp vec4 modulate_attrib; -#endif +layout(location = 10) in uvec4 bone_attrib; +layout(location = 11) in vec4 weight_attrib; -#ifdef USE_ATTRIB_LARGE_VERTEX -// shared with skeleton attributes, not used in batched shader -layout(location = 6) in highp vec2 translate_attrib; -layout(location = 7) in highp vec4 basis_attrib; #endif +/* clang-format on */ +#include "canvas_uniforms_inc.glsl" +#include "stdlib_inc.glsl" -#ifdef USE_SKELETON -layout(location = 6) in highp vec4 bone_indices; -layout(location = 7) in highp vec4 bone_weights; -#endif +uniform sampler2D transforms_texture; //texunit:-1 -#ifdef USE_INSTANCING +out vec2 uv_interp; +out vec4 color_interp; +out vec2 vertex_interp; +flat out int draw_data_instance; -layout(location = 8) in highp vec4 instance_xform0; -layout(location = 9) in highp vec4 instance_xform1; -layout(location = 10) in highp vec4 instance_xform2; -layout(location = 11) in highp vec4 instance_color; +#ifdef USE_NINEPATCH -#ifdef USE_INSTANCE_CUSTOM -layout(location = 12) in highp vec4 instance_custom_data; -#endif +out vec2 pixel_size_interp; #endif -#ifdef USE_SKELETON -uniform highp sampler2D skeleton_texture; // texunit:-3 -uniform highp ivec2 skeleton_texture_size; -uniform highp mat4 skeleton_transform; -uniform highp mat4 skeleton_transform_inverse; -#endif +#ifdef MATERIAL_UNIFORMS_USED +layout(std140) uniform MaterialUniforms{ +//ubo:4 -out vec2 uv_interp; -out vec4 color_interp; +#MATERIAL_UNIFORMS -#ifdef USE_ATTRIB_MODULATE -// modulate doesn't need interpolating but we need to send it to the fragment shader -flat out vec4 modulate_interp; +}; #endif -#ifdef MODULATE_USED -uniform vec4 final_modulate; -#endif - -uniform highp vec2 color_texpixel_size; +#GLOBALS -#ifdef USE_TEXTURE_RECT +void main() { + vec4 instance_custom = vec4(0.0); + draw_data_instance = gl_InstanceID; +#ifdef USE_PRIMITIVE -uniform vec4 dst_rect; -uniform vec4 src_rect; + //weird bug, + //this works + vec2 vertex; + vec2 uv; + vec4 color; + + if (gl_VertexID == 0) { + vertex = draw_data[draw_data_instance].point_a; + uv = draw_data[draw_data_instance].uv_a; + color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_a_rg), unpackHalf2x16(draw_data[draw_data_instance].color_a_ba)); + } else if (gl_VertexID == 1) { + vertex = draw_data[draw_data_instance].point_b; + uv = draw_data[draw_data_instance].uv_b; + color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_b_rg), unpackHalf2x16(draw_data[draw_data_instance].color_b_ba)); + } else { + vertex = draw_data[draw_data_instance].point_c; + uv = draw_data[draw_data_instance].uv_c; + color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_c_rg), unpackHalf2x16(draw_data[draw_data_instance].color_c_ba)); + } + uvec4 bones = uvec4(0, 0, 0, 0); + vec4 bone_weights = vec4(0.0); -#endif +#elif defined(USE_ATTRIBUTES) -uniform highp float time; - -#ifdef USE_LIGHTING - -// light matrices -uniform highp mat4 light_matrix; -uniform highp mat4 light_matrix_inverse; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; - -out vec4 light_uv_interp; -out vec2 transformed_light_uv; -out vec4 local_rot; - -#ifdef USE_SHADOWS -out highp vec2 pos; -#endif + vec2 vertex = vertex_attrib; + vec4 color = color_attrib * draw_data[draw_data_instance].modulation; + vec2 uv = uv_attrib; -const bool at_light_pass = true; + uvec4 bones = bone_attrib; + vec4 bone_weights = weight_attrib; #else -const bool at_light_pass = false; -#endif -/* clang-format off */ + vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); + vec2 vertex_base = vertex_base_arr[gl_VertexID]; -VERTEX_SHADER_GLOBALS + vec2 uv = draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw) * ((draw_data[draw_data_instance].flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy); + vec4 color = draw_data[draw_data_instance].modulation; + vec2 vertex = draw_data[draw_data_instance].dst_rect.xy + abs(draw_data[draw_data_instance].dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data[draw_data_instance].src_rect.zw, vec2(0.0, 0.0))); + uvec4 bones = uvec4(0, 0, 0, 0); -/* clang-format on */ +#endif -vec2 select(vec2 a, vec2 b, bvec2 c) { - vec2 ret; + mat4 world_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0)); - ret.x = c.x ? b.x : a.x; - ret.y = c.y ? b.y : a.y; + // MultiMeshes don't batch, so always read from draw_data[0] + uint instancing = draw_data[0].flags & FLAGS_INSTANCING_MASK; - return ret; -} +#ifdef USE_ATTRIBUTES +/* + if (instancing > 1) { + // trails -void main() { - vec4 color = color_attrib; - vec2 uv; + uint stride = 2 + 1 + 1; //particles always uses this format -#ifdef USE_INSTANCING - mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); - color *= instance_color; + uint trail_size = instancing; -#ifdef USE_INSTANCE_CUSTOM - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); -#endif + uint offset = trail_size * stride * gl_InstanceID; -#else - mat4 extra_matrix_instance = extra_matrix; - vec4 instance_custom = vec4(0.0); -#endif + vec4 pcolor; + vec2 new_vertex; + { + uint boffset = offset + bone_attrib.x * stride; + new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x; + pcolor = transforms.data[boffset + 2] * weight_attrib.x; + } + if (weight_attrib.y > 0.001) { + uint boffset = offset + bone_attrib.y * stride; + new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y; + pcolor += transforms.data[boffset + 2] * weight_attrib.y; + } + if (weight_attrib.z > 0.001) { + uint boffset = offset + bone_attrib.z * stride; + new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z; + pcolor += transforms.data[boffset + 2] * weight_attrib.z; + } + if (weight_attrib.w > 0.001) { + uint boffset = offset + bone_attrib.w * stride; + new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w; + pcolor += transforms.data[boffset + 2] * weight_attrib.w; + } -#ifdef USE_TEXTURE_RECT + instance_custom = transforms.data[offset + 3]; - if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; - } else { - uv = src_rect.xy + abs(src_rect.zw) * vertex; + vertex = new_vertex; + color *= pcolor; + } else*/ +#endif // USE_ATTRIBUTES +/* + { + if (instancing == 1) { + uint stride = 2; + { + if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) { + stride += 1; + } + if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { + stride += 1; + } + } + + uint offset = stride * gl_InstanceID; + + mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + offset += 2; + + if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) { + color *= transforms.data[offset]; + offset += 1; + } + + if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { + instance_custom = transforms.data[offset]; + } + + matrix = transpose(matrix); + world_matrix = world_matrix * matrix; + } + } +*/ +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) + if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) { + //scale by texture size + vertex /= draw_data[draw_data_instance].color_texture_pixel_size; } - - vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); - - // This is what is done in the GLES 3 bindings and should - // take care of flipped rects. - // - // But it doesn't. - // I don't know why, will need to investigate further. - - outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); - - // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; -#else - vec4 outvec = vec4(vertex.xy, 0.0, 1.0); - - uv = uv_attrib; #endif +#ifdef USE_POINT_SIZE float point_size = 1.0; - +#endif { - vec2 src_vtx = outvec.xy; - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ +#CODE : VERTEX } - gl_PointSize = point_size; +#ifdef USE_NINEPATCH + pixel_size_interp = abs(draw_data[draw_data_instance].dst_rect.zw) * vertex_base; +#endif -#ifdef USE_ATTRIB_MODULATE - // modulate doesn't need interpolating but we need to send it to the fragment shader - modulate_interp = modulate_attrib; +#if !defined(SKIP_TRANSFORM_USED) + vertex = (world_matrix * vec4(vertex, 0.0, 1.0)).xy; #endif -#ifdef USE_ATTRIB_LARGE_VERTEX - // transform is in attributes - vec2 temp; + color_interp = color; - temp = outvec.xy; - temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z); - temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w); + if (use_pixel_snap) { + vertex = floor(vertex + 0.5); + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv += 1e-5; + } - temp += translate_attrib; - outvec.xy = temp; +#ifdef USE_ATTRIBUTES +#if 0 + if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_SKELETON) && bone_weights != vec4(0.0)) { //must be a valid bone + //skeleton transform + ivec4 bone_indicesi = ivec4(bone_indices); -#else + uvec2 tex_ofs = bone_indicesi.x * 2; - // transform is in uniforms -#if !defined(SKIP_TRANSFORM_USED) - outvec = extra_matrix_instance * outvec; - outvec = modelview_matrix * outvec; -#endif + mat2x4 m; + m = mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.x; -#endif // not large integer + tex_ofs = bone_indicesi.y * 2; - color_interp = color; + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.y; -#ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; - // precision issue on some hardware creates artifacts within texture - // offset uv by a small amount to avoid - uv += 1e-5; -#endif + tex_ofs = bone_indicesi.z * 2; -#ifdef USE_SKELETON + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.z; - // look up transform from the "pose texture" - if (bone_weights != vec4(0.0)) { - highp mat4 bone_transform = mat4(0.0); + tex_ofs = bone_indicesi.w * 2; - for (int i = 0; i < 4; i++) { - ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0); + m += mat2x4( + texelFetch(skeleton_buffer, tex_ofs + 0), + texelFetch(skeleton_buffer, tex_ofs + 1)) * + bone_weights.w; - highp mat4 b = mat4( - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)), - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); + mat4 bone_matrix = skeleton_data.skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_data.skeleton_transform_inverse; - bone_transform += b * bone_weights[i]; - } - - mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse; - - outvec = bone_matrix * outvec; + //outvec = bone_matrix * outvec; } - #endif +#endif + + vertex = (canvas_transform * vec4(vertex, 0.0, 1.0)).xy; + vertex_interp = vertex; uv_interp = uv; - gl_Position = projection_matrix * outvec; -#ifdef USE_LIGHTING + gl_Position = screen_transform * vec4(vertex, 0.0, 1.0); - light_uv_interp.xy = (light_matrix * outvec).xy; - light_uv_interp.zw = (light_local_matrix * outvec).xy; +#ifdef USE_POINT_SIZE + gl_PointSize = point_size; +#endif +} - transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping +#[fragment] -#ifdef USE_SHADOWS - pos = outvec.xy; -#endif +#include "canvas_uniforms_inc.glsl" +#include "stdlib_inc.glsl" -#ifdef USE_ATTRIB_LIGHT_ANGLE - // we add a fixed offset because we are using the sign later, - // and don't want floating point error around 0.0 - float la = abs(light_angle) - 1.0; - - // vector light angle - vec4 vla; - vla.xy = vec2(cos(la), sin(la)); - vla.zw = vec2(-vla.y, vla.x); - - // vertical flip encoded in the sign - vla.zw *= sign(light_angle); - - // apply the transform matrix. - // The rotate will be encoded in the transform matrix for single rects, - // and just the flips in the light angle. - // For batching we will encode the rotation and the flips - // in the light angle, and can use the same shader. - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.xy, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.zw, 0.0, 0.0))).xy); -#else - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); -#ifdef USE_TEXTURE_RECT - local_rot.xy *= sign(src_rect.z); - local_rot.zw *= sign(src_rect.w); -#endif -#endif // not using light angle +uniform sampler2D atlas_texture; //texunit:-2 +uniform sampler2D shadow_atlas_texture; //texunit:-3 +uniform sampler2D screen_texture; //texunit:-4 +uniform sampler2D sdf_texture; //texunit:-5 +uniform sampler2D normal_texture; //texunit:-6 +uniform sampler2D specular_texture; //texunit:-7 -#endif -} +uniform sampler2D color_texture; //texunit:0 -/* clang-format off */ -[fragment] +in vec2 uv_interp; +in vec4 color_interp; +in vec2 vertex_interp; +flat in int draw_data_instance; + +#ifdef USE_NINEPATCH + +in vec2 pixel_size_interp; -#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 -uniform sampler2D color_texture; // texunit:-1 -/* clang-format on */ -uniform highp vec2 color_texpixel_size; -uniform mediump sampler2D normal_texture; // texunit:-2 +layout(location = 0) out vec4 frag_color; + +#ifdef MATERIAL_UNIFORMS_USED +uniform MaterialUniforms{ +//ubo:4 -in mediump vec2 uv_interp; -in mediump vec4 color_interp; +#MATERIAL_UNIFORMS -#ifdef USE_ATTRIB_MODULATE -in mediump vec4 modulate_interp; +}; #endif -uniform highp float time; +vec2 screen_uv_to_sdf(vec2 p_uv) { + return screen_to_sdf * p_uv; +} -uniform vec4 final_modulate; +float texture_sdf(vec2 p_sdf) { + vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw; + float d = texture(sdf_texture, uv).r; + d *= SDF_MAX_LENGTH; + return d * tex_to_sdf; +} -#ifdef SCREEN_TEXTURE_USED +vec2 texture_sdf_normal(vec2 p_sdf) { + vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw; -uniform sampler2D screen_texture; // texunit:-4 + const float EPSILON = 0.001; + return normalize(vec2( + texture(sdf_texture, uv + vec2(EPSILON, 0.0)).r - texture(sdf_texture, uv - vec2(EPSILON, 0.0)).r, + texture(sdf_texture, uv + vec2(0.0, EPSILON)).r - texture(sdf_texture, uv - vec2(0.0, EPSILON)).r)); +} -#endif +vec2 sdf_to_screen_uv(vec2 p_sdf) { + return p_sdf * sdf_to_screen; +} -#ifdef SCREEN_UV_USED +#GLOBALS -uniform vec2 screen_pixel_size; +#ifdef LIGHT_CODE_USED -#endif +vec4 light_compute( + vec3 light_vertex, + vec3 light_position, + vec3 normal, + vec4 light_color, + float light_energy, + vec4 specular_shininess, + inout vec4 shadow_modulate, + vec2 screen_uv, + vec2 uv, + vec4 color, bool is_directional) { + vec4 light = vec4(0.0); -#ifdef USE_LIGHTING +#CODE : LIGHT -uniform highp mat4 light_matrix; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; + return light; +} -uniform lowp sampler2D light_texture; // texunit:-6 -in vec4 light_uv_interp; -in vec2 transformed_light_uv; +#endif -in vec4 local_rot; +#ifdef USE_NINEPATCH -#ifdef USE_SHADOWS +float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) { + float tex_size = 1.0 / tex_pixel_size; -uniform highp sampler2D shadow_texture; // texunit:-5 -in highp vec2 pos; + if (pixel < margin_begin) { + return pixel * tex_pixel_size; + } else if (pixel >= draw_size - margin_end) { + return (tex_size - (draw_size - pixel)) * tex_pixel_size; + } else { + if (!bool(draw_data[draw_data_instance].flags & FLAGS_NINEPACH_DRAW_CENTER)) { + draw_center--; + } -#endif + // np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum. + if (np_repeat == 0) { // Stretch. + // Convert to ratio. + float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end); + // Scale to source texture. + return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size; + } else if (np_repeat == 1) { // Tile. + // Convert to offset. + float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end); + // Scale to source texture. + return (margin_begin + ofs) * tex_pixel_size; + } else if (np_repeat == 2) { // Tile Fit. + // Calculate scale. + float src_area = draw_size - margin_begin - margin_end; + float dst_area = tex_size - margin_begin - margin_end; + float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5)); + // Convert to ratio. + float ratio = (pixel - margin_begin) / src_area; + ratio = mod(ratio * scale, 1.0); + // Scale to source texture. + return (margin_begin + ratio * dst_area) * tex_pixel_size; + } else { // Shouldn't happen, but silences compiler warning. + return 0.0; + } + } +} -const bool at_light_pass = true; -#else -const bool at_light_pass = false; #endif -uniform bool use_default_normal; +vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) { + float cNdotL = max(0.0, dot(normal, light_vec)); -layout(location = 0) out mediump vec4 frag_color; + if (specular_shininess_used) { + //blinn + vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough + vec3 half_vec = normalize(view + light_vec); -/* clang-format off */ + float cNdotV = max(dot(normal, view), 0.0); + float cNdotH = max(dot(normal, half_vec), 0.0); + float cVdotH = max(dot(view, half_vec), 0.0); + float cLdotH = max(dot(light_vec, half_vec), 0.0); + float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); -FRAGMENT_SHADER_GLOBALS + return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL; + } else { + return light_color * base_color * cNdotL; + } +} -/* clang-format on */ +//float distance = length(shadow_pos); +vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv +#ifdef LIGHT_CODE_USED + , + vec3 shadow_modulate +#endif +) { + float shadow; + uint shadow_mode = light_data[light_base].flags & LIGHT_FLAGS_FILTER_MASK; + + if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) { + shadow = textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x; + } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) { + vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow /= 5.0; + } else { //PCF13 + vec4 shadow_pixel_size = vec4(light_data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0); + shadow = 0.0; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 6.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv - shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 2.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 3.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 4.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 5.0, 0.0).x; + shadow += textureProjLod(shadow_atlas_texture, shadow_uv + shadow_pixel_size * 6.0, 0.0).x; + shadow /= 13.0; + } -void light_compute( - inout vec4 light, - inout vec2 light_vec, - inout float light_height, - inout vec4 light_color, - vec2 light_uv, - inout vec4 shadow_color, - inout vec2 shadow_vec, - vec3 normal, - vec2 uv, -#if defined(SCREEN_UV_USED) - vec2 screen_uv, + vec4 shadow_color = unpackUnorm4x8(light_data[light_base].shadow_color); +#ifdef LIGHT_CODE_USED + shadow_color.rgb *= shadow_modulate; #endif - vec4 color) { -#if defined(USE_LIGHT_SHADER_CODE) + shadow_color.a *= light_color.a; //respect light alpha - /* clang-format off */ + return mix(light_color, shadow_color, shadow); +} -LIGHT_SHADER_CODE +void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) { + uint blend_mode = light_data[light_base].flags & LIGHT_FLAGS_BLEND_MASK; + + switch (blend_mode) { + case LIGHT_FLAGS_BLEND_MODE_ADD: { + color.rgb += light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_SUB: { + color.rgb -= light_color.rgb * light_color.a; + } break; + case LIGHT_FLAGS_BLEND_MODE_MIX: { + color.rgb = mix(color.rgb, light_color.rgb, light_color.a); + } break; + } +} - /* clang-format on */ +float msdf_median(float r, float g, float b, float a) { + return min(max(min(r, g), min(max(r, g), b)), a); +} -#endif +vec2 msdf_map(vec2 value, vec2 in_min, vec2 in_max, vec2 out_min, vec2 out_max) { + return out_min + (out_max - out_min) * (value - in_min) / (in_max - in_min); } void main() { vec4 color = color_interp; vec2 uv = uv_interp; -#ifdef USE_FORCE_REPEAT - //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it - uv = mod(uv, vec2(1.0, 1.0)); + vec2 vertex = vertex_interp; + +#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) + +#ifdef USE_NINEPATCH + + int draw_center = 2; + uv = vec2( + map_ninepatch_axis(pixel_size_interp.x, abs(draw_data[draw_data_instance].dst_rect.z), draw_data[draw_data_instance].color_texture_pixel_size.x, draw_data[draw_data_instance].ninepatch_margins.x, draw_data[draw_data_instance].ninepatch_margins.z, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center), + map_ninepatch_axis(pixel_size_interp.y, abs(draw_data[draw_data_instance].dst_rect.w), draw_data[draw_data_instance].color_texture_pixel_size.y, draw_data[draw_data_instance].ninepatch_margins.y, draw_data[draw_data_instance].ninepatch_margins.w, int(draw_data[draw_data_instance].flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center)); + + if (draw_center == 0) { + color.a = 0.0; + } + + uv = uv * draw_data[draw_data_instance].src_rect.zw + draw_data[draw_data_instance].src_rect.xy; //apply region if needed + #endif + if (bool(draw_data[draw_data_instance].flags & FLAGS_CLIP_RECT_UV)) { + uv = clamp(uv, draw_data[draw_data_instance].src_rect.xy, draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw)); + } -#if !defined(COLOR_USED) - //default behavior, texture by color - color *= texture(color_texture, uv); #endif -#ifdef SCREEN_UV_USED - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#ifndef USE_PRIMITIVE + if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_MSDF)) { + float px_range = draw_data[draw_data_instance].ninepatch_margins.x; + float outline_thickness = draw_data[draw_data_instance].ninepatch_margins.y; + //float reserved1 = draw_data[draw_data_instance].ninepatch_margins.z; + //float reserved2 = draw_data[draw_data_instance].ninepatch_margins.w; + + vec4 msdf_sample = texture(color_texture, uv); + vec2 msdf_size = vec2(textureSize(color_texture, 0)); + vec2 dest_size = vec2(1.0) / fwidth(uv); + float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0); + float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5; + + if (outline_thickness > 0) { + float cr = clamp(outline_thickness, 0.0, px_range / 2) / px_range; + float a = clamp((d + cr) * px_size, 0.0, 1.0); + color.a = a * color.a; + } else { + float a = clamp(d * px_size + 0.5, 0.0, 1.0); + color.a = a * color.a; + } + + } else { +#else + { #endif + color *= texture(color_texture, uv); + } + + uint light_count = (draw_data[draw_data_instance].flags >> FLAGS_LIGHT_COUNT_SHIFT) & uint(0xF); //max 16 lights + bool using_light = light_count > uint(0) || directional_light_count > uint(0); vec3 normal; #if defined(NORMAL_USED) - bool normal_used = true; #else bool normal_used = false; #endif - if (use_default_normal) { - normal.xy = texture(normal_texture, uv).xy * 2.0 - 1.0; + if (normal_used || (using_light && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { + normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); normal_used = true; } else { normal = vec3(0.0, 0.0, 1.0); } - { - float normal_depth = 1.0; - -#if defined(NORMALMAP_USED) - vec3 normal_map = vec3(0.0, 0.0, 1.0); - normal_used = true; -#endif - - /* clang-format off */ + vec4 specular_shininess; -FRAGMENT_SHADER_CODE +#if defined(SPECULAR_SHININESS_USED) - /* clang-format on */ - -#if defined(NORMALMAP_USED) - normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); -#endif - } - -#ifdef USE_ATTRIB_MODULATE - color *= modulate_interp; + bool specular_shininess_used = true; #else -#if !defined(MODULATE_USED) - color *= final_modulate; -#endif + bool specular_shininess_used = false; #endif -#ifdef USE_LIGHTING - - vec2 light_vec = transformed_light_uv; - vec2 shadow_vec = transformed_light_uv; - - if (normal_used) { - normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; + if (specular_shininess_used || (using_light && normal_used && bool(draw_data[draw_data_instance].flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) { + specular_shininess = texture(specular_texture, uv); + specular_shininess *= unpackUnorm4x8(draw_data[draw_data_instance].specular_shininess); + specular_shininess_used = true; + } else { + specular_shininess = vec4(1.0); } - float att = 1.0; - - vec2 light_uv = light_uv_interp.xy; - vec4 light = texture(light_texture, light_uv); - - if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) { - color.a *= light_outside_alpha; //invisible - - } else { - float real_light_height = light_height; - vec4 real_light_color = light_color; - vec4 real_light_shadow_color = light_shadow_color; - -#if defined(USE_LIGHT_SHADER_CODE) - //light is written by the light shader - light_compute( - light, - light_vec, - real_light_height, - real_light_color, - light_uv, - real_light_shadow_color, - shadow_vec, - normal, - uv, #if defined(SCREEN_UV_USED) - screen_uv, -#endif - color); + vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#else + vec2 screen_uv = vec2(0.0); #endif - light *= real_light_color; - - if (normal_used) { - vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); - light *= max(dot(-light_normal, normal), 0.0); - } + vec3 light_vertex = vec3(vertex, 0.0); + vec2 shadow_vertex = vertex; - color *= light; - -#ifdef USE_SHADOWS + { + float normal_map_depth = 1.0; -#ifdef SHADOW_VEC_USED - mat3 inverse_light_matrix = mat3(light_matrix); - inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); - inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); - inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); - shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy; -#else - shadow_vec = light_uv_interp.zw; +#if defined(NORMAL_MAP_USED) + vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; #endif - float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); - float PI = 3.14159265358979323846264; - /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays - float ang*/ - - float su, sz; - - float abs_angle = abs(angle_to_light); - vec2 point; - float sh; - if (abs_angle < 45.0 * PI / 180.0) { - point = shadow_vec; - sh = 0.0 + (1.0 / 8.0); - } else if (abs_angle > 135.0 * PI / 180.0) { - point = -shadow_vec; - sh = 0.5 + (1.0 / 8.0); - } else if (angle_to_light > 0.0) { - point = vec2(shadow_vec.y, -shadow_vec.x); - sh = 0.25 + (1.0 / 8.0); - } else { - point = vec2(-shadow_vec.y, shadow_vec.x); - sh = 0.75 + (1.0 / 8.0); - } +#CODE : FRAGMENT - highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); - s.xyz /= s.w; - su = s.x * 0.5 + 0.5; - sz = s.z * 0.5 + 0.5; - //sz=lightlength(light_vec); +#if defined(NORMAL_MAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth); +#endif + } - highp float shadow_attenuation = 0.0; + if (normal_used) { + //convert by item transform + normal.xy = mat2(normalize(draw_data[draw_data_instance].world_x), normalize(draw_data[draw_data_instance].world_y)) * normal.xy; + //convert by canvas transform + normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz); + } -#ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) + vec3 base_color = color.rgb; + if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_LIGHT_MASK)) { + color = vec4(0.0); //invisible by default due to using light mask + } +#ifdef MODE_LIGHT_ONLY + color = vec4(0.0); #else + color *= canvas_modulation; +#endif -#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r) +#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED) -#endif + for (uint i = uint(0); i < directional_light_count; i++) { + uint light_base = i; -#ifdef SHADOW_USE_GRADIENT + vec2 direction = light_data[light_base].position; + vec4 light_color = light_data[light_base].color; - /* clang-format off */ - /* GLSL es 100 doesn't support line continuation characters(backslashes) */ -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); } +#ifdef LIGHT_CODE_USED + vec4 shadow_modulate = vec4(1.0); + light_color = light_compute(light_vertex, vec3(direction, light_data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true); #else -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); } - /* clang-format on */ - + if (normal_used) { + vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_data[light_base].height)); + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); + } #endif -#ifdef SHADOW_FILTER_NEAREST + if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { + vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[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. - SHADOW_TEST(su); + vec4 shadow_uv = vec4(shadow_pos.x, light_data[light_base].shadow_y_ofs, shadow_pos.y * light_data[light_base].shadow_zfar_inv, 1.0); + light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_CODE_USED + , + shadow_modulate.rgb #endif + ); + } -#ifdef SHADOW_FILTER_PCF3 - - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - shadow_attenuation /= 3.0; + light_blend_compute(light_base, light_color, color.rgb); + } -#endif + // Positional Lights -#ifdef SHADOW_FILTER_PCF5 + for (uint i = uint(0); i < MAX_LIGHTS_PER_ITEM; i++) { + if (i >= light_count) { + break; + } + uint light_base; + if (i < uint(8)) { + if (i < uint(4)) { + light_base = draw_data[draw_data_instance].lights.x; + } else { + light_base = draw_data[draw_data_instance].lights.y; + } + } else { + if (i < uint(12)) { + light_base = draw_data[draw_data_instance].lights.z; + } else { + light_base = draw_data[draw_data_instance].lights.w; + } + } + light_base >>= (i & uint(3)) * uint(8); + light_base &= uint(0xFF); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - shadow_attenuation /= 5.0; + vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_data[light_base].texture_matrix[0], light_data[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_data[light_base].atlas_rect.zw + light_data[light_base].atlas_rect.xy; + vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0); + vec4 light_base_color = light_data[light_base].color; -#endif +#ifdef LIGHT_CODE_USED -#ifdef SHADOW_FILTER_PCF7 + vec4 shadow_modulate = vec4(1.0); + vec3 light_position = vec3(light_data[light_base].position, light_data[light_base].height); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - shadow_attenuation /= 7.0; - -#endif + light_color.rgb *= light_base_color.rgb; + light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false); +#else -#ifdef SHADOW_FILTER_PCF9 + light_color.rgb *= light_base_color.rgb * light_base_color.a; - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - shadow_attenuation /= 9.0; + if (normal_used) { + vec3 light_pos = vec3(light_data[light_base].position, light_data[light_base].height); + vec3 pos = light_vertex; + vec3 light_vec = normalize(light_pos - pos); + float cNdotL = max(0.0, dot(normal, light_vec)); + light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used); + } #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; + } -#ifdef SHADOW_FILTER_PCF13 - - SHADOW_TEST(su + shadowpixel_size * 6.0); - SHADOW_TEST(su + shadowpixel_size * 5.0); - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - SHADOW_TEST(su - shadowpixel_size * 5.0); - SHADOW_TEST(su - shadowpixel_size * 6.0); - shadow_attenuation /= 13.0; - -#endif + if (bool(light_data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) { + vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_data[light_base].shadow_matrix[0], light_data[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. + + vec2 pos_norm = normalize(shadow_pos); + vec2 pos_abs = abs(pos_norm); + vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y); + vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot? + float tex_ofs; + float distance; + if (pos_rot.y > 0) { + if (pos_rot.x > 0) { + tex_ofs = pos_box.y * 0.125 + 0.125; + distance = shadow_pos.x; + } else { + tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125); + distance = shadow_pos.y; + } + } else { + if (pos_rot.x < 0) { + tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125); + distance = -shadow_pos.x; + } else { + tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125); + distance = -shadow_pos.y; + } + } + + distance *= light_data[light_base].shadow_zfar_inv; + + //float distance = length(shadow_pos); + vec4 shadow_uv = vec4(tex_ofs, light_data[light_base].shadow_y_ofs, distance, 1.0); + + light_color = light_shadow_compute(light_base, light_color, shadow_uv +#ifdef LIGHT_CODE_USED + , + shadow_modulate.rgb +#endif + ); + } - //color *= shadow_attenuation; - color = mix(real_light_shadow_color, color, shadow_attenuation); -//use shadows -#endif + light_blend_compute(light_base, light_color, color.rgb); } - -//use lighting -#endif +#endif // UNSHADED frag_color = color; } diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl index 2b3be43f6e..65389c211a 100644 --- a/drivers/gles3/shaders/canvas_shadow.glsl +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -10,7 +10,7 @@ precision highp float; precision highp int; #endif -layout(location = 0) highp vec3 vertex; +layout(location = 0) in highp vec3 vertex; uniform highp mat4 projection_matrix; /* clang-format on */ diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl new file mode 100644 index 0000000000..e08a15e59d --- /dev/null +++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl @@ -0,0 +1,120 @@ + +#define MAX_LIGHTS_PER_ITEM uint(16) + +#define M_PI 3.14159265359 + +#define SDF_MAX_LENGTH 16384.0 + +//1 means enabled, 2+ means trails in use +#define FLAGS_INSTANCING_MASK uint(0x7F) +#define FLAGS_INSTANCING_HAS_COLORS uint(1 << 7) +#define FLAGS_INSTANCING_HAS_CUSTOM_DATA uint(1 << 8) + +#define FLAGS_CLIP_RECT_UV uint(1 << 9) +#define FLAGS_TRANSPOSE_RECT uint(1 << 10) +#define FLAGS_USING_LIGHT_MASK uint(1 << 11) +#define FLAGS_NINEPACH_DRAW_CENTER uint(1 << 12) +#define FLAGS_USING_PARTICLES uint(1 << 13) + +#define FLAGS_NINEPATCH_H_MODE_SHIFT 16 +#define FLAGS_NINEPATCH_V_MODE_SHIFT 18 + +#define FLAGS_LIGHT_COUNT_SHIFT 20 + +#define FLAGS_DEFAULT_NORMAL_MAP_USED uint(1 << 26) +#define FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 27) + +#define FLAGS_USE_MSDF uint(1 << 28) + +// must be always 128 bytes long +struct DrawData { + vec2 world_x; + vec2 world_y; + vec2 world_ofs; + vec2 color_texture_pixel_size; +#ifdef USE_PRIMITIVE + vec2 point_a; + vec2 point_b; + vec2 point_c; + vec2 uv_a; + vec2 uv_b; + vec2 uv_c; + uint color_a_rg; + uint color_a_ba; + uint color_b_rg; + uint color_b_ba; + uint color_c_rg; + uint color_c_ba; +#else + vec4 modulation; + vec4 ninepatch_margins; + vec4 dst_rect; //for built-in rect and UV + vec4 src_rect; + uint pad; + uint pad2; +#endif + uint flags; + uint specular_shininess; + uvec4 lights; +}; + +layout(std140) uniform GlobalVariableData { //ubo:1 + vec4 global_variables[MAX_GLOBAL_VARIABLES]; +}; + +layout(std140) uniform CanvasData { //ubo:0 + mat4 canvas_transform; + mat4 screen_transform; + mat4 canvas_normal_transform; + vec4 canvas_modulation; + vec2 screen_pixel_size; + float time; + bool use_pixel_snap; + + vec4 sdf_to_tex; + vec2 screen_to_sdf; + vec2 sdf_to_screen; + + uint directional_light_count; + float tex_to_sdf; + uint pad1; + uint pad2; +}; + +#define LIGHT_FLAGS_BLEND_MASK uint(3 << 16) +#define LIGHT_FLAGS_BLEND_MODE_ADD uint(0 << 16) +#define LIGHT_FLAGS_BLEND_MODE_SUB uint(1 << 16) +#define LIGHT_FLAGS_BLEND_MODE_MIX uint(2 << 16) +#define LIGHT_FLAGS_BLEND_MODE_MASK uint(3 << 16) +#define LIGHT_FLAGS_HAS_SHADOW uint(1 << 20) +#define LIGHT_FLAGS_FILTER_SHIFT 22 +#define LIGHT_FLAGS_FILTER_MASK uint(3 << 22) +#define LIGHT_FLAGS_SHADOW_NEAREST uint(0 << 22) +#define LIGHT_FLAGS_SHADOW_PCF5 uint(1 << 22) +#define LIGHT_FLAGS_SHADOW_PCF13 uint(2 << 22) + +struct Light { + mat2x4 texture_matrix; //light to texture coordinate matrix (transposed) + mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed) + vec4 color; + + uint shadow_color; // packed + uint flags; //index to light texture + float shadow_pixel_size; + float height; + + vec2 position; + float shadow_zfar_inv; + float shadow_y_ofs; + + vec4 atlas_rect; +}; + +layout(std140) uniform LightData { //ubo:2 + Light light_data[MAX_LIGHTS]; +}; + +layout(std140) uniform DrawDataInstances { //ubo:3 + + DrawData draw_data[MAX_DRAW_DATA_INSTANCES]; +}; diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index 598c6fd614..62332a15a7 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -1,5 +1,21 @@ /* clang-format off */ -[vertex] +#[modes] + +mode_default = +mode_cubemap = #define USE_CUBEMAP +mode_panorama = #define USE_PANORAMA +mode_copy_section = #define USE_COPY_SECTION +mode_asym_pano = #define USE_ASYM_PANO +mode_no_alpha = #define USE_NO_ALPHA +mode_custom_alpha = #define USE_CUSTOM_ALPHA +mode_multiplier = #define USE_MULTIPLIER +mode_sep_cbcr_texture = #define USE_SEP_CBCR_TEXTURE +mode_ycbcr_to_rgb = #define USE_YCBCR_TO_RGB + +#[specializations] + + +#[vertex] #ifdef USE_GLES_OVER_GL #define lowp @@ -10,16 +26,16 @@ precision highp float; precision highp int; #endif -layout(location = 0) highp vec4 vertex_attrib; +layout(location = 0) in highp vec4 vertex_attrib; /* clang-format on */ #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -layout(location = 4) vec3 cube_in; +layout(location = 4) in vec3 cube_in; #else -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; #endif -layout(location = 5) vec2 uv2_in; +layout(location = 5) in vec2 uv2_in; #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) out vec3 cube_interp; @@ -28,11 +44,6 @@ out vec2 uv_interp; #endif out vec2 uv2_interp; -// These definitions are here because the shader-wrapper builder does -// not understand `#elif defined()` -#ifdef USE_DISPLAY_TRANSFORM -#endif - #ifdef USE_COPY_SECTION uniform highp vec4 copy_section; #elif defined(USE_DISPLAY_TRANSFORM) @@ -60,7 +71,7 @@ void main() { } /* clang-format off */ -[fragment] +#[fragment] #define M_PI 3.14159265359 @@ -96,7 +107,7 @@ uniform samplerCube source_cube; // texunit:0 uniform sampler2D source; // texunit:0 #endif -#ifdef SEP_CBCR_TEXTURE +#ifdef USE_SEP_CBCR_TEXTURE uniform sampler2D CbCr; //texunit:1 #endif @@ -156,8 +167,8 @@ void main() { vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); #elif defined(USE_CUBEMAP) - vec4 color = textureCube(source_cube, normalize(cube_interp)); -#elif defined(SEP_CBCR_TEXTURE) + vec4 color = texture(source_cube, normalize(cube_interp)); +#elif defined(USE_SEP_CBCR_TEXTURE) vec4 color; color.r = texture(source, uv_interp).r; color.gb = texture(CbCr, uv_interp).rg - vec2(0.5, 0.5); @@ -166,7 +177,7 @@ void main() { vec4 color = texture(source, uv_interp); #endif -#ifdef YCBCR_TO_RGB +#ifdef USE_YCBCR_TO_RGB // YCbCr -> RGB conversion // Using BT.601, which is the standard for SDTV is provided as a reference diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl index ea4df79d4e..2384529a89 100644 --- a/drivers/gles3/shaders/cube_to_dp.glsl +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -10,9 +10,9 @@ precision mediump float; precision mediump int; #endif -layout(location = 0) highp vec4 vertex_attrib; +layout(location = 0) in highp vec4 vertex_attrib; /* clang-format on */ -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; out vec2 uv_interp; diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index 04bf3ebf02..2081abfef6 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -10,9 +10,9 @@ precision highp float; precision highp int; #endif -layout(location = 0) highp vec2 vertex; +layout(location = 0) in highp vec2 vertex; /* clang-format on */ -layout(location = 4) highp vec2 uv; +layout(location = 4) in highp vec2 uv; out highp vec2 uv_interp; diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 80063a7175..c9184cca77 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -10,9 +10,9 @@ precision highp float; precision highp int; #endif -layout(location = 0) vec2 vertex_attrib; +layout(location = 0) in vec2 vertex_attrib; /* clang-format on */ -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; out vec2 uv_interp; diff --git a/drivers/gles3/shaders/lens_distorted.glsl b/drivers/gles3/shaders/lens_distorted.glsl index 64c2d70cc8..3aaf1050e5 100644 --- a/drivers/gles3/shaders/lens_distorted.glsl +++ b/drivers/gles3/shaders/lens_distorted.glsl @@ -10,7 +10,7 @@ precision highp float; precision highp int; #endif -layout(location = 0) highp vec2 vertex; +layout(location = 0) in highp vec2 vertex; /* clang-format on */ uniform vec2 offset; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index de2aa0fc48..98c92a1d99 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -18,38 +18,38 @@ precision highp int; // attributes // -layout(location = 0) highp vec4 vertex_attrib; +layout(location = 0) in highp vec4 vertex_attrib; /* clang-format on */ -layout(location = 1) vec3 normal_attrib; +layout(location = 1) in vec3 normal_attrib; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -layout(location = 2) vec4 tangent_attrib; +layout(location = 2) in vec4 tangent_attrib; #endif #if defined(ENABLE_COLOR_INTERP) -layout(location = 3) vec4 color_attrib; +layout(location = 3) in vec4 color_attrib; #endif #if defined(ENABLE_UV_INTERP) -layout(location = 4) vec2 uv_attrib; +layout(location = 4) in vec2 uv_attrib; #endif #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -layout(location = 5) vec2 uv2_attrib; +layout(location = 5) in vec2 uv2_attrib; #endif #ifdef USE_SKELETON #ifdef USE_SKELETON_SOFTWARE -layout(location = 13) highp vec4 bone_transform_row_0; -layout(location = 14) highp vec4 bone_transform_row_1; -layout(location = 15) highp vec4 bone_transform_row_2; +layout(location = 13) in highp vec4 bone_transform_row_0; +layout(location = 14) in highp vec4 bone_transform_row_1; +layout(location = 15) in highp vec4 bone_transform_row_2; #else -layout(location = 6) vec4 bone_ids; -layout(location = 7) highp vec4 bone_weights; +layout(location = 6) in vec4 bone_ids; +layout(location = 7) in highp vec4 bone_weights; uniform highp sampler2D bone_transforms; // texunit:-1 uniform ivec2 skeleton_texture_size; @@ -60,12 +60,12 @@ uniform ivec2 skeleton_texture_size; #ifdef USE_INSTANCING -layout(location = 8) highp vec4 instance_xform_row_0; -layout(location = 9) highp vec4 instance_xform_row_1; -layout(location = 10) highp vec4 instance_xform_row_2; +layout(location = 8) in highp vec4 instance_xform_row_0; +layout(location = 9) in highp vec4 instance_xform_row_1; +layout(location = 10) in highp vec4 instance_xform_row_2; -layout(location = 11) highp vec4 instance_color; -layout(location = 12) highp vec4 instance_custom_data; +layout(location = 11) in highp vec4 instance_color; +layout(location = 12) in highp vec4 instance_custom_data; #endif @@ -1610,7 +1610,7 @@ FRAGMENT_SHADER_CODE specular_light *= specular * metallic * albedo * 2.0; #else - // scales the specular reflections, needs to be be computed before lighting happens, + // scales the specular reflections, needs to be computed before lighting happens, // but after environment and reflection probes are added //TODO: this curve is not really designed for gammaspace, should be adjusted const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl new file mode 100644 index 0000000000..2eddf9d479 --- /dev/null +++ b/drivers/gles3/shaders/stdlib_inc.glsl @@ -0,0 +1,58 @@ +//TODO: only needed by GLES_OVER_GL + +uint float2half(uint f) { + return ((f >> uint(16)) & uint(0x8000)) | + ((((f & uint(0x7f800000)) - uint(0x38000000)) >> uint(13)) & uint(0x7c00)) | + ((f >> uint(13)) & uint(0x03ff)); +} + +uint half2float(uint h) { + return ((h & uint(0x8000)) << uint(16)) | (((h & uint(0x7c00)) + uint(0x1c000)) << uint(13)) | ((h & uint(0x03ff)) << uint(13)); +} + +uint packHalf2x16(vec2 v) { + return float2half(floatBitsToUint(v.x)) | float2half(floatBitsToUint(v.y)) << uint(16); +} + +vec2 unpackHalf2x16(uint v) { + return vec2(uintBitsToFloat(half2float(v & uint(0xffff))), + uintBitsToFloat(half2float(v >> uint(16)))); +} + +uint packUnorm2x16(vec2 v) { + uvec2 uv = uvec2(round(clamp(v, vec2(0.0), vec2(1.0)) * 65535.0)); + return uv.x | uv.y << uint(16); +} + +vec2 unpackUnorm2x16(uint p) { + return vec2(float(p & uint(0xffff)), float(p >> uint(16))) * 0.000015259021; // 1.0 / 65535.0 optimization +} + +uint packSnorm2x16(vec2 v) { + uvec2 uv = uvec2(round(clamp(v, vec2(-1.0), vec2(1.0)) * 32767.0) + 32767.0); + return uv.x | uv.y << uint(16); +} + +vec2 unpackSnorm2x16(uint p) { + vec2 v = vec2(float(p & uint(0xffff)), float(p >> uint(16))); + return clamp((v - 32767.0) * vec2(0.00003051851), vec2(-1.0), vec2(1.0)); +} + +uint packUnorm4x8(vec4 v) { + uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0)); + return uv.x | uv.y << uint(8) | uv.z << uint(16) | uv.w << uint(24); +} + +vec4 unpackUnorm4x8(uint p) { + return vec4(float(p & uint(0xffff)), float((p >> uint(8)) & uint(0xffff)), float((p >> uint(16)) & uint(0xffff)), float(p >> uint(24))) * 0.00392156862; // 1.0 / 255.0 +} + +uint packSnorm4x8(vec4 v) { + uvec4 uv = uvec4(round(clamp(v, vec4(-1.0), vec4(1.0)) * 127.0) + 127.0); + return uv.x | uv.y << uint(8) | uv.z << uint(16) | uv.w << uint(24); +} + +vec4 unpackSnorm4x8(uint p) { + vec4 v = vec4(float(p & uint(0xffff)), float((p >> uint(8)) & uint(0xffff)), float((p >> uint(16)) & uint(0xffff)), float(p >> uint(24))); + return clamp((v - vec4(127.0)) * vec4(0.00787401574), vec4(-1.0), vec4(1.0)); +} diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 8b3aa4d309..4f962626a3 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -10,9 +10,9 @@ precision highp float; precision highp int; #endif -layout(location = 0) vec2 vertex_attrib; +layout(location = 0) in vec2 vertex_attrib; /* clang-format on */ -layout(location = 4) vec2 uv_in; +layout(location = 4) in vec2 uv_in; out vec2 uv_interp; |