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 BOX_SDF = 39 """ 40 float sdBox(vec2 p, vec2 size) { 41 size = size * 0.5; 42 vec2 d = abs(p) - size; 43 return length(max(d, 0.)) + min(max(d.x, d.y), 0.) / size.y; 44 } 45 """ 46 47 const val ROUNDED_BOX_SDF = 48 """ 49 float sdRoundedBox(vec2 p, vec2 size, float cornerRadius) { 50 size *= 0.5; 51 cornerRadius *= 0.5; 52 vec2 d = abs(p) - size + cornerRadius; 53 54 float outside = length(max(d, 0.0)); 55 float inside = min(max(d.x, d.y), 0.0); 56 57 return (outside + inside - cornerRadius) / size.y; 58 } 59 60 float roundedBoxRing(vec2 p, vec2 size, float cornerRadius, 61 float borderThickness) { 62 float outerRoundBox = sdRoundedBox(p, size + vec2(borderThickness), 63 cornerRadius + borderThickness); 64 float innerRoundBox = sdRoundedBox(p, size, cornerRadius); 65 return subtract(outerRoundBox, innerRoundBox); 66 } 67 """ 68 69 // Used non-trigonometry parametrization and Halley's method (iterative) for root finding. 70 // This is more expensive than the regular circle SDF, recommend to use the circle SDF if 71 // possible. 72 const val ELLIPSE_SDF = 73 """float sdEllipse(vec2 p, vec2 wh) { 74 wh *= 0.5; 75 76 // symmetry 77 (wh.x > wh.y) ? wh = wh.yx, p = abs(p.yx) : p = abs(p); 78 79 vec2 u = wh*p, v = wh*wh; 80 81 float U1 = u.y/2.0; 82 float U2 = v.y-v.x; 83 float U3 = u.x-U2; 84 float U4 = u.x+U2; 85 float U5 = 4.0*U1; 86 float U6 = 6.0*U1; 87 float U7 = 3.0*U3; 88 89 float t = 0.5; 90 for (int i = 0; i < 3; i ++) { 91 float F1 = t*(t*t*(U1*t+U3)+U4)-U1; 92 float F2 = t*t*(U5*t+U7)+U4; 93 float F3 = t*(U6*t+U7); 94 95 t += (F1*F2)/(F1*F3-F2*F2); 96 } 97 98 t = clamp(t, 0.0, 1.0); 99 100 float d = distance(p, wh*vec2(1.0-t*t,2.0*t)/(t*t+1.0)); 101 d /= wh.y; 102 103 return (dot(p/wh,p/wh)>1.0) ? d : -d; 104 } 105 106 float ellipseRing(vec2 p, vec2 wh) { 107 vec2 thicknessHalf = wh * 0.25; 108 109 float outerEllipse = sdEllipse(p, wh + thicknessHalf); 110 float innerEllipse = sdEllipse(p, wh); 111 112 return subtract(outerEllipse, innerEllipse); 113 } 114 """ 115 116 const val SHADER_SDF_OPERATION_LIB = 117 """ 118 float soften(float d, float blur) { 119 float blurHalf = blur * 0.5; 120 return smoothstep(-blurHalf, blurHalf, d); 121 } 122 123 float subtract(float outer, float inner) { 124 return max(outer, -inner); 125 } 126 """ 127 } 128 } 129