tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ellipse.glsl (3519B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2  * License, v. 2.0. If a copy of the MPL was not distributed with this
      3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 // Preprocess the radii for computing the distance approximation. This should
      6 // be used in the vertex shader if possible to avoid doing expensive division
      7 // in the fragment shader. When dealing with a point (zero radii), approximate
      8 // it as an ellipse with very small radii so that we don't need to branch.
      9 vec2 inverse_radii_squared(vec2 radii) {
     10     return 1.0 / max(radii * radii, 1.0e-6);
     11 }
     12 
     13 #ifdef WR_FRAGMENT_SHADER
     14 
     15 // One iteration of Newton's method on the 2D equation of an ellipse:
     16 //
     17 //     E(x, y) = x^2/a^2 + y^2/b^2 - 1
     18 //
     19 // The Jacobian of this equation is:
     20 //
     21 //     J(E(x, y)) = [ 2*x/a^2 2*y/b^2 ]
     22 //
     23 // We approximate the distance with:
     24 //
     25 //     E(x, y) / ||J(E(x, y))||
     26 //
     27 // See G. Taubin, "Distance Approximations for Rasterizing Implicit
     28 // Curves", section 3.
     29 //
     30 // A scale relative to the unit scale of the ellipse may be passed in to cause
     31 // the math to degenerate to length(p) when scale is 0, or otherwise give the
     32 // normal distance approximation if scale is 1.
     33 float distance_to_ellipse_approx(vec2 p, vec2 inv_radii_sq, float scale) {
     34     vec2 p_r = p * inv_radii_sq;
     35     float g = dot(p, p_r) - scale;
     36     vec2 dG = (1.0 + scale) * p_r;
     37     return g * inversesqrt(dot(dG, dG));
     38 }
     39 
     40 // Slower but more accurate version that uses the exact distance when dealing
     41 // with a 0-radius point distance and otherwise uses the faster approximation
     42 // when dealing with non-zero radii.
     43 float distance_to_ellipse(vec2 p, vec2 radii) {
     44     return distance_to_ellipse_approx(p, inverse_radii_squared(radii),
     45                                       float(all(greaterThan(radii, vec2(0.0)))));
     46 }
     47 
     48 float distance_to_rounded_rect(
     49     vec2 pos,
     50     vec3 plane_tl,
     51     vec4 center_radius_tl,
     52     vec3 plane_tr,
     53     vec4 center_radius_tr,
     54     vec3 plane_br,
     55     vec4 center_radius_br,
     56     vec3 plane_bl,
     57     vec4 center_radius_bl,
     58     vec4 rect_bounds
     59 ) {
     60     // Clip against each ellipse. If the fragment is in a corner, one of the
     61     // branches below will select it as the corner to calculate the distance
     62     // to. We use half-space planes to detect which corner's ellipse the
     63     // fragment is inside, where the plane is defined by a normal and offset.
     64     // If outside any ellipse, default to a small offset so a negative distance
     65     // is returned for it.
     66     vec4 corner = vec4(vec2(1.0e-6), vec2(1.0));
     67 
     68     // Calculate the ellipse parameters for each corner.
     69     center_radius_tl.xy = center_radius_tl.xy - pos;
     70     center_radius_tr.xy = (center_radius_tr.xy - pos) * vec2(-1.0, 1.0);
     71     center_radius_br.xy = pos - center_radius_br.xy;
     72     center_radius_bl.xy = (center_radius_bl.xy - pos) * vec2(1.0, -1.0);
     73 
     74     // Evaluate each half-space plane in turn to select a corner.
     75     if (dot(pos, plane_tl.xy) > plane_tl.z) {
     76       corner = center_radius_tl;
     77     }
     78     if (dot(pos, plane_tr.xy) > plane_tr.z) {
     79       corner = center_radius_tr;
     80     }
     81     if (dot(pos, plane_br.xy) > plane_br.z) {
     82       corner = center_radius_br;
     83     }
     84     if (dot(pos, plane_bl.xy) > plane_bl.z) {
     85       corner = center_radius_bl;
     86     }
     87 
     88     // Calculate the distance of the selected corner and the rectangle bounds,
     89     // whichever is greater.
     90     return max(distance_to_ellipse_approx(corner.xy, corner.zw, 1.0),
     91                signed_distance_rect(pos, rect_bounds.xy, rect_bounds.zw));
     92 }
     93 #endif