@@ -30,6 +30,9 @@ const vgerGlyph = 8;
3030/// Path fills.
3131const vgerPathFill = 9 ;
3232
33+ /// Rounded blurred rectangle.
34+ const vgerBlurredRect = 10 ;
35+
3336struct Prim {
3437
3538 /// Min and max coordinates of the quad we're rendering.
@@ -343,6 +346,10 @@ fn sdPrimBounds(prim: Prim) -> BBox {
343346 b = expand (b , cvs . cvs [i32 (prim . start )+ i ]);
344347 }
345348 }
349+ case 10u : { // vgerBlurredRect
350+ b . min = prim . cv0 ;
351+ b . max = prim . cv1 ;
352+ }
346353 default : {}
347354 }
348355 return b ;
@@ -463,6 +470,26 @@ fn sdPrim(prim: Prim, p: vec2<f32>, filterWidth: f32) -> f32 {
463470 d = d * s ;
464471 break ;
465472 }
473+ case 10u : { // vgerBlurredRect
474+ let blur_radius = prim . cv2 . x ;
475+ let center = 0 .5 * (prim . cv1 + prim . cv0 );
476+ let half_size = 0 .5 * (prim . cv1 - prim . cv0 );
477+ let point = p - center ;
478+
479+ let low = point . y - half_size . y ;
480+ let high = point . y + half_size . y ;
481+ let start = clamp (- 3 .0 * blur_radius , low , high );
482+ let end = clamp (3 .0 * blur_radius , low , high );
483+
484+ let step = (end - start ) / 4 .0 ;
485+ var y = start + step * 0 .5 ;
486+ var value = 0 .0 ;
487+ for (var i : i32 = 0 ; i < 4 ; i ++ ) {
488+ value += roundedBoxShadowX (point . x , point . y - y , blur_radius , prim . radius , half_size ) * gaussian (y , blur_radius ) * step ;
489+ y += step ;
490+ }
491+ d = 1 .0 - value * 4 .0 ;
492+ }
466493 default : { }
467494 }
468495 return d ;
@@ -619,6 +646,27 @@ fn toLinear(s: f32) -> f32
619646 return pow ((s + 0 .055 )/ 1 .055 , 2 .4 );
620647}
621648
649+ // This approximates the error function, needed for the gaussian integral
650+ fn erf (x : vec2 <f32 >) -> vec2 <f32 > {
651+ let s = sign (x );
652+ let a = abs (x );
653+ var y = 1 .0 + (0 .278393 + (0 .230389 + 0 .078108 * (a * a )) * a ) * a ;
654+ y *= y ;
655+ return s - s / (y * y );
656+ }
657+
658+ fn gaussian (x : f32 , sigma : f32 ) -> f32 {
659+ let pi : f32 = 3 .141592653589793 ;
660+ return exp (- (x * x ) / (2 .0 * sigma * sigma )) / (sqrt (2 .0 * pi ) * sigma );
661+ }
662+
663+ fn roundedBoxShadowX (x : f32 , y : f32 , sigma : f32 , corner : f32 , halfSize : vec2 <f32 >) -> f32 {
664+ let delta = min (halfSize . y - corner - abs (y ), 0 .0 );
665+ let curved = halfSize . x - corner + sqrt (max (0 .0 , corner * corner - delta * delta ));
666+ let integral = 0 .5 + 0 .5 * erf ((x + vec2 (- curved , curved )) * (sqrt (0 .5 ) / sigma ));
667+ return integral . y - integral . x ;
668+ }
669+
622670@fragment
623671fn fs_main (
624672 in : VertexOutput ,
0 commit comments