1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.systemui.surfaceeffects.shaderutil
17 
18 /** Library class that contains 2D signed distance functions. */
19 class SdfShaderLibrary {
20     // language=AGSL
21     companion object {
22         const val CIRCLE_SDF =
23             """
24             float sdCircle(vec2 p, float r) {
25                 return (length(p)-r) / r;
26             }
27 
28             float circleRing(vec2 p, float radius) {
29                 float thicknessHalf = radius * 0.25;
30 
31                 float outerCircle = sdCircle(p, radius + thicknessHalf);
32                 float innerCircle = sdCircle(p, radius);
33 
34                 return subtract(outerCircle, innerCircle);
35             }
36         """
37 
38         const val ROUNDED_BOX_SDF =
39             """
40             float sdRoundedBox(vec2 p, vec2 size, float cornerRadius) {
41                 size *= 0.5;
42                 cornerRadius *= 0.5;
43                 vec2 d = abs(p)-size+cornerRadius;
44 
45                 float outside = length(max(d, 0.0));
46                 float inside = min(max(d.x, d.y), 0.0);
47 
48                 return (outside+inside-cornerRadius)/size.y;
49             }
50 
51             float roundedBoxRing(vec2 p, vec2 size, float cornerRadius,
52                 float borderThickness) {
53                 float outerRoundBox = sdRoundedBox(p, size + vec2(borderThickness),
54                     cornerRadius + borderThickness);
55                 float innerRoundBox = sdRoundedBox(p, size, cornerRadius);
56                 return subtract(outerRoundBox, innerRoundBox);
57             }
58         """
59 
60         // Used non-trigonometry parametrization and Halley's method (iterative) for root finding.
61         // This is more expensive than the regular circle SDF, recommend to use the circle SDF if
62         // possible.
63         const val ELLIPSE_SDF =
64             """float sdEllipse(vec2 p, vec2 wh) {
65             wh *= 0.5;
66 
67             // symmetry
68             (wh.x > wh.y) ? wh = wh.yx, p = abs(p.yx) : p = abs(p);
69 
70             vec2 u = wh*p, v = wh*wh;
71 
72             float U1 = u.y/2.0;
73             float U2 = v.y-v.x;
74             float U3 = u.x-U2;
75             float U4 = u.x+U2;
76             float U5 = 4.0*U1;
77             float U6 = 6.0*U1;
78             float U7 = 3.0*U3;
79 
80             float t = 0.5;
81             for (int i = 0; i < 3; i ++) {
82                 float F1 = t*(t*t*(U1*t+U3)+U4)-U1;
83                 float F2 = t*t*(U5*t+U7)+U4;
84                 float F3 = t*(U6*t+U7);
85 
86                 t += (F1*F2)/(F1*F3-F2*F2);
87             }
88 
89             t = clamp(t, 0.0, 1.0);
90 
91             float d = distance(p, wh*vec2(1.0-t*t,2.0*t)/(t*t+1.0));
92             d /= wh.y;
93 
94             return (dot(p/wh,p/wh)>1.0) ? d : -d;
95         }
96 
97         float ellipseRing(vec2 p, vec2 wh) {
98             vec2 thicknessHalf = wh * 0.25;
99 
100             float outerEllipse = sdEllipse(p, wh + thicknessHalf);
101             float innerEllipse = sdEllipse(p, wh);
102 
103             return subtract(outerEllipse, innerEllipse);
104         }
105         """
106 
107         const val SHADER_SDF_OPERATION_LIB =
108             """
109             float soften(float d, float blur) {
110                 float blurHalf = blur * 0.5;
111                 return smoothstep(-blurHalf, blurHalf, d);
112             }
113 
114             float subtract(float outer, float inner) {
115                 return max(outer, -inner);
116             }
117         """
118     }
119 }
120