/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /// This shader repeats an image pattern. #include ps_quad varying highp vec2 v_uv; flat varying mediump vec4 v_uv_sample_bounds; flat varying mediump vec4 v_uv_bounds; flat varying highp vec4 v_repetitions_and_spacing_threshold; #define v_repetitions v_repetitions_and_spacing_threshold.xy #define v_spacing_threshold v_repetitions_and_spacing_threshold.zw #ifdef WR_VERTEX_SHADER struct RepeatedPattern { // In layout space. vec2 stretch_size; // In layout space. vec2 spacing; }; RepeatedPattern fetch_repated_pattern(int address) { vec4 payload = fetch_from_gpu_buffer_1f(address); return RepeatedPattern(payload.xy, payload.zw); } void pattern_vertex(PrimitiveInfo info) { RepeatedPattern pattern = fetch_repated_pattern(info.pattern_input.x); vec2 f = (info.local_pos - info.local_prim_rect.p0) / rect_size(info.local_prim_rect); // In layout coordinates. vec2 inv_repeated_size = vec2(1.0) / (pattern.stretch_size + pattern.spacing); // Number of repetitions on the x and y axis. vec2 repeat = rect_size(info.local_prim_rect) * inv_repeated_size; v_repetitions = repeat; // Normalized relative to the source uv bounds. v_spacing_threshold = pattern.stretch_size * inv_repeated_size; // In pixels. vec2 uv0 = info.segment.uv_rect.p0; vec2 uv1 = info.segment.uv_rect.p1; vec2 min_uv = min(uv0, uv1); vec2 max_uv = max(uv0, uv1); // In source texels. vec2 uv_px = (mix(uv0, uv1, f) - min_uv) * repeat.xy; // Normalized relative to the source uv bounds. v_uv = uv_px / (max_uv - min_uv); vec2 inv_texture_size = vec2(1.0) / vec2(TEX_SIZE(sColor0)); // In normalized texel coordinates. v_uv_sample_bounds = vec4( min_uv + vec2(0.5), max_uv - vec2(0.5) ) * inv_texture_size.xyxy; v_uv_bounds = vec4(min_uv, max_uv) * inv_texture_size.xyxy; } #endif #ifdef WR_FRAGMENT_SHADER vec4 pattern_fragment(vec4 color) { // In normalized pixel coordinates. vec2 uv_size = v_uv_bounds.zw - v_uv_bounds.xy; // This prevents the uv on the top and left parts of the primitive that was inflated // for anti-aliasing purposes from going beyound the range covered by the regular // (non-inflated) primitive. vec2 local_uv = max(v_uv, vec2(0.0)); // Normalized relative to the source uv bounds. vec2 repeated_uv = fract(local_uv); if (repeated_uv.x > v_spacing_threshold.x || repeated_uv.y > v_spacing_threshold.y) { // Make pixels transparent in the spacing area. color *= 0.0; } // At this point repeated_uv does a linear ramp over the whole span of each repetition, // which includes the spacing area. It is equal to zero at the beginning of the repetition // and one at the end of the spacing area just before the next repetition. // What we need is for the the ramp to be equal to one just before the spacing area. // This is what dividing by the spacing threshold achives. repeated_uv /= v_spacing_threshold; // Now express repeated_uv in pixels and clamp it to the source's sample bounds. repeated_uv = repeated_uv * uv_size + v_uv_bounds.xy; repeated_uv = max(repeated_uv, v_uv_sample_bounds.xy); repeated_uv = min(repeated_uv, v_uv_sample_bounds.zw); // This takes care of the bottom and right inflated parts. // We do it after the modulo because the latter wraps around the values exactly on // the right and bottom edges, which we do not want. if (local_uv.x >= v_repetitions.x) { repeated_uv.x = v_uv_bounds.z; } if (local_uv.y >= v_repetitions.y) { repeated_uv.y = v_uv_bounds.w; } vec4 texel = TEX_SAMPLE(sColor0, repeated_uv); return color * texel; } #if defined(SWGL_DRAW_SPAN) void swgl_drawSpanRGBA8() { if (!swgl_isTextureRGBA8(sColor0)) { return; } if (v_spacing_threshold.x < 1.0 || v_spacing_threshold.y < 1.0) { // TODO: SWGL's repeating span shaders don't support spacing. return; } if (v_color != vec4(1.0)) { swgl_commitTextureRepeatColorRGBA8(sColor0, v_uv, v_repetitions, v_uv_bounds, v_uv_sample_bounds, v_color); } else { swgl_commitTextureRepeatRGBA8(sColor0, v_uv, v_repetitions, v_uv_bounds, v_uv_sample_bounds); } } #endif #endif