Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cs_clip_box_shadow.glsl   Sprache: unbekannt

 
/* 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/. */

#include shared,clip_shared

varying highp vec4 vLocalPos;
varying highp vec2 vUv;
flat varying highp vec4 vUvBounds;
flat varying mediump vec4 vEdge;
flat varying highp vec4 vUvBounds_NoClamp;
// Clip mode. Packed in to a vector to avoid bug 1630356.
flat varying mediump vec2 vClipMode;

#define MODE_STRETCH        0
#define MODE_SIMPLE         1

#ifdef WR_VERTEX_SHADER

PER_INSTANCE in ivec2 aClipDataResourceAddress;
PER_INSTANCE in vec2 aClipSrcRectSize;
PER_INSTANCE in int aClipMode;
PER_INSTANCE in ivec2 aStretchMode;
PER_INSTANCE in vec4 aClipDestRect;

struct ClipMaskInstanceBoxShadow {
    ClipMaskInstanceCommon base;
    ivec2 resource_address;
};

ClipMaskInstanceBoxShadow fetch_clip_item() {
    ClipMaskInstanceBoxShadow cmi;

    cmi.base = fetch_clip_item_common();
    cmi.resource_address = aClipDataResourceAddress;

    return cmi;
}

struct BoxShadowData {
    vec2 src_rect_size;
    int clip_mode;
    int stretch_mode_x;
    int stretch_mode_y;
    RectWithEndpoint dest_rect;
};

BoxShadowData fetch_data() {
    BoxShadowData bs_data = BoxShadowData(
        aClipSrcRectSize,
        aClipMode,
        aStretchMode.x,
        aStretchMode.y,
        RectWithEndpoint(aClipDestRect.xy, aClipDestRect.zw)
    );
    return bs_data;
}

void main(void) {
    ClipMaskInstanceBoxShadow cmi = fetch_clip_item();
    Transform clip_transform = fetch_transform(cmi.base.clip_transform_id);
    Transform prim_transform = fetch_transform(cmi.base.prim_transform_id);
    BoxShadowData bs_data = fetch_data();
    ImageSource res = fetch_image_source_direct(cmi.resource_address);

    RectWithEndpoint dest_rect = bs_data.dest_rect;

    ClipVertexInfo vi = write_clip_tile_vertex(
        dest_rect,
        prim_transform,
        clip_transform,
        cmi.base.sub_rect,
        cmi.base.task_origin,
        cmi.base.screen_origin,
        cmi.base.device_pixel_scale
    );
    vClipMode.x = float(bs_data.clip_mode);

    vec2 texture_size = vec2(TEX_SIZE(sColor0));
    vec2 local_pos = vi.local_pos.xy / vi.local_pos.w;
    vLocalPos = vi.local_pos;
    vec2 dest_rect_size = rect_size(dest_rect);

    switch (bs_data.stretch_mode_x) {
        case MODE_STRETCH: {
            vEdge.x = 0.5;
            vEdge.z = (dest_rect_size.x / bs_data.src_rect_size.x) - 0.5;
            vUv.x = (local_pos.x - dest_rect.p0.x) / bs_data.src_rect_size.x;
            break;
        }
        case MODE_SIMPLE:
        default: {
            vEdge.xz = vec2(1.0);
            vUv.x = (local_pos.x - dest_rect.p0.x) / dest_rect_size.x;
            break;
        }
    }

    switch (bs_data.stretch_mode_y) {
        case MODE_STRETCH: {
            vEdge.y = 0.5;
            vEdge.w = (dest_rect_size.y / bs_data.src_rect_size.y) - 0.5;
            vUv.y = (local_pos.y - dest_rect.p0.y) / bs_data.src_rect_size.y;
            break;
        }
        case MODE_SIMPLE:
        default: {
            vEdge.yw = vec2(1.0);
            vUv.y = (local_pos.y - dest_rect.p0.y) / dest_rect_size.y;
            break;
        }
    }

    vUv *= vi.local_pos.w;
    vec2 uv0 = res.uv_rect.p0;
    vec2 uv1 = res.uv_rect.p1;
    vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
    vUvBounds_NoClamp = vec4(uv0, uv1) / texture_size.xyxy;
}
#endif

#ifdef WR_FRAGMENT_SHADER
void main(void) {
    vec2 uv_linear = vUv / vLocalPos.w;
    vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy);
    uv += max(vec2(0.0), uv_linear - vEdge.zw);
    uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
    uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);

    float in_shadow_rect = rectangle_aa_rough_fragment(vLocalPos.xy / vLocalPos.w);

    float texel = TEX_SAMPLE(sColor0, uv).r;

    float alpha = mix(texel, 1.0 - texel, vClipMode.x);
    float result = vLocalPos.w > 0.0 ? mix(vClipMode.x, alpha, in_shadow_rect) : 0.0;

    oFragColor = vec4(result);
}

#ifdef SWGL_DRAW_SPAN
// As with cs_clip_rectangle, this shader spends a lot of time doing clipping and
// combining for every fragment, even if outside of the primitive to initialize
// the clip tile, or inside the inner bounds of the primitive, where the shadow
// is unnecessary. To alleviate this, the span shader attempts to first intersect
// the the local clip bounds, outside of which we can just use a solid fill
// to initialize those clip tile fragments. Once inside the primitive bounds,
// we further intersect with the inner region where no shadow is necessary either
// so that we can commit entire spans of texture within this nine-patch region
// instead of having to do the work of mapping per fragment.
void swgl_drawSpanR8() {
    // Perspective is not supported.
    if (swgl_interpStep(vLocalPos).w != 0.0) {
        return;
    }

    // If the span is completely outside the Z-range and clipped out, just
    // output clear so we don't need to consider invalid W in the rest of the
    // shader.
    float w = swgl_forceScalar(vLocalPos.w);
    if (w <= 0.0) {
        swgl_commitSolidR8(0.0);
        return;
    }

    // To start, we evaluate the box shadow in both UV and local space relative
    // to the local-space position. This will be interpolated across the span to
    // track whether we intersect the nine-patch.
    w = 1.0 / w;
    vec2 uv_linear = vUv * w;
    vec2 uv_linear0 = swgl_forceScalar(uv_linear);
    vec2 uv_linear_step = swgl_interpStep(vUv).xy * w;
    vec2 local_pos = vLocalPos.xy * w;
    vec2 local_pos0 = swgl_forceScalar(local_pos);
    vec2 local_step = swgl_interpStep(vLocalPos).xy * w;

    // We need to compute the local-space distance to the bounding box and then
    // figure out how many processing steps that maps to. If we are stepping in
    // a negative direction on an axis, we need to swap the sides of the box
    // which we consider as the start or end. If there is no local-space step
    // on an axis (i.e. constant Y), we need to take care to force the steps to
    // either the start or end of the span depending on if we are inside or
    // outside of the bounding box.
    vec4 clip_dist =
        mix(vTransformBounds, vTransformBounds.zwxy, lessThan(local_step, vec2(0.0)).xyxy)
            - local_pos0.xyxy;
    clip_dist =
        mix(1.0e6 * step(0.0, clip_dist),
            clip_dist * recip(local_step).xyxy,
            notEqual(local_step, vec2(0.0)).xyxy);

    // Find the start and end of the shadowed region on this span.
    float shadow_start = max(clip_dist.x, clip_dist.y);
    float shadow_end = min(clip_dist.z, clip_dist.w);

    // Flip the offsets from the start of the span so we can compare against the
    // remaining span length which automatically deducts as we commit fragments.
    ivec2 shadow_steps = ivec2(clamp(
        swgl_SpanLength - swgl_StepSize * vec2(floor(shadow_start), ceil(shadow_end)),
        0.0, swgl_SpanLength));
    int shadow_start_len = shadow_steps.x;
    int shadow_end_len = shadow_steps.y;

    // Likewise, once inside the primitive bounds, we also need to track which
    // sector of the nine-patch we are in which requires intersecting against
    // the inner box instead of the outer box.
    vec4 opaque_dist =
        mix(vEdge, vEdge.zwxy, lessThan(uv_linear_step, vec2(0.0)).xyxy)
            - uv_linear0.xyxy;
    opaque_dist =
        mix(1.0e6 * step(0.0, opaque_dist),
            opaque_dist * recip(uv_linear_step).xyxy,
            notEqual(uv_linear_step, vec2(0.0)).xyxy);

    // Unlike for the shadow clipping bounds, here we need to rather find the floor of all
    // the offsets so that we don't accidentally process any chunks in the transitional areas
    // between sectors of the nine-patch.
    ivec4 opaque_steps = ivec4(clamp(
        swgl_SpanLength -
            swgl_StepSize *
                vec4(floor(opaque_dist.x), floor(opaque_dist.y), floor(opaque_dist.z), floor(opaque_dist.w)),
        shadow_end_len, swgl_SpanLength));

    // Fill any initial sections of the span that are clipped out based on clip mode.
    if (swgl_SpanLength > shadow_start_len) {
        int num_before = swgl_SpanLength - shadow_start_len;
        swgl_commitPartialSolidR8(num_before, vClipMode.x);
        float steps_before = float(num_before / swgl_StepSize);
        uv_linear += steps_before * uv_linear_step;
        local_pos += steps_before * local_step;
    }

    // This loop tries to repeatedly process entire spans of the nine-patch that map
    // to a contiguous spans of texture in the source box shadow. First, we process
    // a chunk with per-fragment clipping and mapping in case we're starting on a
    // transitional region between sectors of the nine-patch which may need to map
    // to different spans of texture per-fragment. After, we find the largest span
    // within the current sector before we hit the next transitional region, and
    // attempt to commit an entire span of texture therein.
    while (swgl_SpanLength > 0) {
        // Here we might be in a transitional chunk, so do everything per-fragment.
        {
            vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy);
            uv += max(vec2(0.0), uv_linear - vEdge.zw);
            uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
            uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);

            float in_shadow_rect = rectangle_aa_rough_fragment(local_pos);

            float texel = TEX_SAMPLE(sColor0, uv).r;

            float alpha = mix(texel, 1.0 - texel, vClipMode.x);
            float result = mix(vClipMode.x, alpha, in_shadow_rect);
            swgl_commitColorR8(result);

            uv_linear += uv_linear_step;
            local_pos += local_step;
        }
        // If we now hit the end of the clip bounds, just bail out since there is
        // no more shadow to map.
        if (swgl_SpanLength <= shadow_end_len) {
            break;
        }
        // By here we've determined to be still inside the nine-patch. We need to
        // compare against the inner rectangle thresholds to see which sector of
        // the nine-patch to use and thus how to map the box shadow texture. Stop
        // at least one step before the end of the shadow region to properly clip
        // on the boundary.
        int num_inside = swgl_SpanLength - swgl_StepSize - shadow_end_len;
        vec4 uv_bounds = vUvBounds;
        if (swgl_SpanLength >= opaque_steps.y) {
            // We're in the top Y band of the nine-patch.
            num_inside = min(num_inside, swgl_SpanLength - opaque_steps.y);
        } else if (swgl_SpanLength >= opaque_steps.w) {
            // We're in the middle Y band of the nine-patch. Set the UV clamp bounds
            // to the vertical center texel of the box shadow.
            num_inside = min(num_inside, swgl_SpanLength - opaque_steps.w);
            uv_bounds.yw = vec2(clamp(mix(vUvBounds_NoClamp.y, vUvBounds_NoClamp.w, vEdge.y),
                                      vUvBounds.y, vUvBounds.w));
        }
        if (swgl_SpanLength >= opaque_steps.x) {
            // We're in the left X column of the nine-patch.
            num_inside = min(num_inside, swgl_SpanLength - opaque_steps.x);
        } else if (swgl_SpanLength >= opaque_steps.z) {
            // We're in the middle X band of the nine-patch. Set the UV clamp bounds
            // to the horizontal center texel of the box shadow.
            num_inside = min(num_inside, swgl_SpanLength - opaque_steps.z);
            uv_bounds.xz = vec2(clamp(mix(vUvBounds_NoClamp.x, vUvBounds_NoClamp.z, vEdge.x),
                                      vUvBounds.x, vUvBounds.z));
        }
        if (num_inside > 0) {
            // We have a non-zero span of fragments within the sector. Map to the UV
            // start offset of the sector and the UV offset within the sector.
            vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy);
            uv += max(vec2(0.0), uv_linear - vEdge.zw);
            uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
            // If we're in the center sector of the nine-patch, then we only need to
            // sample from a single texel of the box shadow. Just sample that single
            // texel once and output it for the entire span. Otherwise, we just need
            // to commit an actual span of texture from the box shadow. Depending on
            // if we are in clip-out mode, we may need to invert the source texture.
            if (uv_bounds.xy == uv_bounds.zw) {
                uv = clamp(uv, uv_bounds.xy, uv_bounds.zw);
                float texel = TEX_SAMPLE(sColor0, uv).r;
                float alpha = mix(texel, 1.0 - texel, vClipMode.x);
                swgl_commitPartialSolidR8(num_inside, alpha);
            } else if (vClipMode.x != 0.0) {
                swgl_commitPartialTextureLinearInvertR8(num_inside, sColor0, uv, uv_bounds);
            } else {
                swgl_commitPartialTextureLinearR8(num_inside, sColor0, uv, uv_bounds);
            }
            float steps_inside = float(num_inside / swgl_StepSize);
            uv_linear += steps_inside * uv_linear_step;
            local_pos += steps_inside * local_step;
        }
        // By here we're probably in a transitional chunk of the nine-patch that
        // requires per-fragment processing, so loop around again to the handler
        // for that case.
    }

    // Fill any remaining sections of the span that are clipped out.
    if (swgl_SpanLength > 0) {
        swgl_commitPartialSolidR8(swgl_SpanLength, vClipMode.x);
    }
}
#endif

#endif

[ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge