mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 03:35:33 +00:00
7f1e850080
MozReview-Commit-ID: 88ia1A1Dyhq --HG-- extra : rebase_source : db4fc1e00eed8bdb20f0316e47d79d27bc28e322
94 lines
3.5 KiB
GLSL
94 lines
3.5 KiB
GLSL
/* 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/. */
|
|
|
|
#ifdef WR_FRAGMENT_SHADER
|
|
|
|
// One iteration of Newton's method on the 2D equation of an ellipse:
|
|
//
|
|
// E(x, y) = x^2/a^2 + y^2/b^2 - 1
|
|
//
|
|
// The Jacobian of this equation is:
|
|
//
|
|
// J(E(x, y)) = [ 2*x/a^2 2*y/b^2 ]
|
|
//
|
|
// We approximate the distance with:
|
|
//
|
|
// E(x, y) / ||J(E(x, y))||
|
|
//
|
|
// See G. Taubin, "Distance Approximations for Rasterizing Implicit
|
|
// Curves", section 3.
|
|
float distance_to_ellipse(vec2 p, vec2 radii, float aa_range) {
|
|
float dist;
|
|
if (any(lessThanEqual(radii, vec2(0.0)))) {
|
|
dist = length(p);
|
|
} else {
|
|
vec2 invRadiiSq = 1.0 / (radii * radii);
|
|
float g = dot(p * p * invRadiiSq, vec2(1.0)) - 1.0;
|
|
vec2 dG = 2.0 * p * invRadiiSq;
|
|
dist = g * inversesqrt(dot(dG, dG));
|
|
}
|
|
return clamp(dist, -aa_range, aa_range);
|
|
}
|
|
|
|
float clip_against_ellipse_if_needed(
|
|
vec2 pos,
|
|
float current_distance,
|
|
vec4 ellipse_center_radius,
|
|
vec2 sign_modifier,
|
|
float aa_range
|
|
) {
|
|
if (!all(lessThan(sign_modifier * pos, sign_modifier * ellipse_center_radius.xy))) {
|
|
return current_distance;
|
|
}
|
|
|
|
float distance = distance_to_ellipse(pos - ellipse_center_radius.xy,
|
|
ellipse_center_radius.zw,
|
|
aa_range);
|
|
|
|
return max(distance, current_distance);
|
|
}
|
|
|
|
float rounded_rect(vec2 pos,
|
|
vec4 clip_center_radius_tl,
|
|
vec4 clip_center_radius_tr,
|
|
vec4 clip_center_radius_br,
|
|
vec4 clip_center_radius_bl,
|
|
float aa_range) {
|
|
// Start with a negative value (means "inside") for all fragments that are not
|
|
// in a corner. If the fragment is in a corner, one of the clip_against_ellipse_if_needed
|
|
// calls below will update it.
|
|
float current_distance = -aa_range;
|
|
|
|
// Clip against each ellipse.
|
|
current_distance = clip_against_ellipse_if_needed(pos,
|
|
current_distance,
|
|
clip_center_radius_tl,
|
|
vec2(1.0),
|
|
aa_range);
|
|
|
|
current_distance = clip_against_ellipse_if_needed(pos,
|
|
current_distance,
|
|
clip_center_radius_tr,
|
|
vec2(-1.0, 1.0),
|
|
aa_range);
|
|
|
|
current_distance = clip_against_ellipse_if_needed(pos,
|
|
current_distance,
|
|
clip_center_radius_br,
|
|
vec2(-1.0),
|
|
aa_range);
|
|
|
|
current_distance = clip_against_ellipse_if_needed(pos,
|
|
current_distance,
|
|
clip_center_radius_bl,
|
|
vec2(1.0, -1.0),
|
|
aa_range);
|
|
|
|
// Apply AA
|
|
// See comment in ps_border_corner about the choice of constants.
|
|
|
|
return distance_aa(aa_range, current_distance);
|
|
}
|
|
#endif
|