• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
17 package android.graphics.drawable;
18 
19 import android.annotation.ColorInt;
20 import android.graphics.Color;
21 import android.graphics.RuntimeShader;
22 import android.graphics.Shader;
23 
24 final class RippleShader extends RuntimeShader {
25     private static final String SHADER_UNIFORMS =  "uniform vec2 in_origin;\n"
26             + "uniform vec2 in_touch;\n"
27             + "uniform float in_progress;\n"
28             + "uniform float in_maxRadius;\n"
29             + "uniform vec2 in_resolutionScale;\n"
30             + "uniform vec2 in_noiseScale;\n"
31             + "uniform float in_hasMask;\n"
32             + "uniform float in_noisePhase;\n"
33             + "uniform float in_turbulencePhase;\n"
34             + "uniform vec2 in_tCircle1;\n"
35             + "uniform vec2 in_tCircle2;\n"
36             + "uniform vec2 in_tCircle3;\n"
37             + "uniform vec2 in_tRotation1;\n"
38             + "uniform vec2 in_tRotation2;\n"
39             + "uniform vec2 in_tRotation3;\n"
40             + "uniform vec4 in_color;\n"
41             + "uniform vec4 in_sparkleColor;\n"
42             + "uniform shader in_shader;\n";
43     private static final String SHADER_LIB =
44             "float triangleNoise(vec2 n) {\n"
45             + "  n  = fract(n * vec2(5.3987, 5.4421));\n"
46             + "  n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));\n"
47             + "  float xy = n.x * n.y;\n"
48             + "  return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n"
49             + "}"
50             + "const float PI = 3.1415926535897932384626;\n"
51             + "\n"
52             + "float threshold(float v, float l, float h) {\n"
53             + "    return step(l, v) * (1.0 - step(h, v));\n"
54             + "}\n"
55             + "float sparkles(vec2 uv, float t) {\n"
56             + "  float n = triangleNoise(uv);\n"
57             + "  float s = 0.0;\n"
58             + "  for (float i = 0; i < 4; i += 1) {\n"
59             + "    float l = i * 0.1;\n"
60             + "    float h = l + 0.05;\n"
61             + "    float o = sin(PI * (t + 0.35 * i));\n"
62             + "    s += threshold(n + o, l, h);\n"
63             + "  }\n"
64             + "  return saturate(s) * in_sparkleColor.a;\n"
65             + "}\n"
66             + "float softCircle(vec2 uv, vec2 xy, float radius, float blur) {\n"
67             + "  float blurHalf = blur * 0.5;\n"
68             + "  float d = distance(uv, xy);\n"
69             + "  return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
70             + "}\n"
71             + "float softRing(vec2 uv, vec2 xy, float radius, float progress, float blur) {\n"
72             + "  float thickness = 0.05 * radius;\n"
73             + "  float currentRadius = radius * progress;\n"
74             + "  float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n"
75             + "  float circle_inner = softCircle(uv, xy, max(currentRadius - thickness, 0.), "
76             + "    blur);\n"
77             + "  return saturate(circle_outer - circle_inner);\n"
78             + "}\n"
79             + "float subProgress(float start, float end, float progress) {\n"
80             + "    float sub = clamp(progress, start, end);\n"
81             + "    return (sub - start) / (end - start); \n"
82             + "}\n"
83             + "mat2 rotate2d(vec2 rad){\n"
84             + "  return mat2(rad.x, -rad.y, rad.y, rad.x);\n"
85             + "}\n"
86             + "float circle_grid(vec2 resolution, vec2 coord, float time, vec2 center,\n"
87             + "    vec2 rotation, float cell_diameter) {\n"
88             + "  coord = rotate2d(rotation) * (center - coord) + center;\n"
89             + "  coord = mod(coord, cell_diameter) / resolution;\n"
90             + "  float normal_radius = cell_diameter / resolution.y * 0.5;\n"
91             + "  float radius = 0.65 * normal_radius;\n"
92             + "  return softCircle(coord, vec2(normal_radius), radius, radius * 50.0);\n"
93             + "}\n"
94             + "float turbulence(vec2 uv, float t) {\n"
95             + "  const vec2 scale = vec2(0.8);\n"
96             + "  uv = uv * scale;\n"
97             + "  float g1 = circle_grid(scale, uv, t, in_tCircle1, in_tRotation1, 0.17);\n"
98             + "  float g2 = circle_grid(scale, uv, t, in_tCircle2, in_tRotation2, 0.2);\n"
99             + "  float g3 = circle_grid(scale, uv, t, in_tCircle3, in_tRotation3, 0.275);\n"
100             + "  float v = (g1 * g1 + g2 - g3) * 0.5;\n"
101             + "  return saturate(0.45 + 0.8 * v);\n"
102             + "}\n";
103     private static final String SHADER_MAIN = "vec4 main(vec2 p) {\n"
104             + "    float fadeIn = subProgress(0., 0.13, in_progress);\n"
105             + "    float scaleIn = subProgress(0., 1.0, in_progress);\n"
106             + "    float fadeOutNoise = subProgress(0.4, 0.5, in_progress);\n"
107             + "    float fadeOutRipple = subProgress(0.4, 1., in_progress);\n"
108             + "    vec2 center = mix(in_touch, in_origin, saturate(in_progress * 2.0));\n"
109             + "    float ring = softRing(p, center, in_maxRadius, scaleIn, 1.);\n"
110             + "    float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
111             + "    vec2 uv = p * in_resolutionScale;\n"
112             + "    vec2 densityUv = uv - mod(uv, in_noiseScale);\n"
113             + "    float turbulence = turbulence(uv, in_turbulencePhase);\n"
114             + "    float sparkleAlpha = sparkles(densityUv, in_noisePhase) * ring * alpha "
115             + "* turbulence;\n"
116             + "    float fade = min(fadeIn, 1. - fadeOutRipple);\n"
117             + "    float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 1.) * fade "
118             + "* in_color.a;\n"
119             + "    vec4 waveColor = vec4(in_color.rgb * waveAlpha, waveAlpha);\n"
120             + "    vec4 sparkleColor = vec4(in_sparkleColor.rgb * in_sparkleColor.a, "
121             + "in_sparkleColor.a);\n"
122             + "    float mask = in_hasMask == 1. ? sample(in_shader, p).a > 0. ? 1. : 0. : 1.;\n"
123             + "    return mix(waveColor, sparkleColor, sparkleAlpha) * mask;\n"
124             + "}";
125     private static final String SHADER = SHADER_UNIFORMS + SHADER_LIB + SHADER_MAIN;
126     private static final double PI_ROTATE_RIGHT = Math.PI * 0.0078125;
127     private static final double PI_ROTATE_LEFT = Math.PI * -0.0078125;
128 
RippleShader()129     RippleShader() {
130         super(SHADER, false);
131     }
132 
setShader(Shader shader)133     public void setShader(Shader shader) {
134         if (shader != null) {
135             setInputShader("in_shader", shader);
136         }
137         setUniform("in_hasMask", shader == null ? 0 : 1);
138     }
139 
setRadius(float radius)140     public void setRadius(float radius) {
141         setUniform("in_maxRadius", radius * 2.3f);
142     }
143 
setOrigin(float x, float y)144     public void setOrigin(float x, float y) {
145         setUniform("in_origin", new float[] {x, y});
146     }
147 
setTouch(float x, float y)148     public void setTouch(float x, float y) {
149         setUniform("in_touch", new float[] {x, y});
150     }
151 
setProgress(float progress)152     public void setProgress(float progress) {
153         setUniform("in_progress", progress);
154     }
155 
156     /**
157      * Continuous offset used as noise phase.
158      */
setNoisePhase(float phase)159     public void setNoisePhase(float phase) {
160         setUniform("in_noisePhase", phase * 0.001f);
161 
162         //
163         // Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h
164         //
165         final float turbulencePhase = phase;
166         setUniform("in_turbulencePhase", turbulencePhase);
167         final float scale = 1.5f;
168         setUniform("in_tCircle1", new float[]{
169                 (float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))),
170                 (float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.sin(scale * 0.55)))
171         });
172         setUniform("in_tCircle2", new float[]{
173                 (float) (scale * 0.2 + (turbulencePhase * -0.0066 * Math.cos(scale * 0.45))),
174                 (float) (scale * 0.2 + (turbulencePhase * -0.0066 * Math.sin(scale * 0.45)))
175         });
176         setUniform("in_tCircle3", new float[]{
177                 (float) (scale + (turbulencePhase * -0.0066 * Math.cos(scale * 0.35))),
178                 (float) (scale + (turbulencePhase * -0.0066 * Math.sin(scale * 0.35)))
179         });
180         final double rotation1 = turbulencePhase * PI_ROTATE_RIGHT + 1.7 * Math.PI;
181         setUniform("in_tRotation1", new float[]{
182                 (float) Math.cos(rotation1), (float) Math.sin(rotation1)
183         });
184         final double rotation2 = turbulencePhase * PI_ROTATE_LEFT + 2 * Math.PI;
185         setUniform("in_tRotation2", new float[]{
186                 (float) Math.cos(rotation2), (float) Math.sin(rotation2)
187         });
188         final double rotation3 = turbulencePhase * PI_ROTATE_RIGHT + 2.75 * Math.PI;
189         setUniform("in_tRotation3", new float[]{
190                 (float) Math.cos(rotation3), (float) Math.sin(rotation3)
191         });
192     }
193 
194     /**
195      * Color of the circle that's under the sparkles. Sparkles will always be white.
196      */
setColor(@olorInt int colorInt, @ColorInt int sparkleColorInt)197     public void setColor(@ColorInt int colorInt, @ColorInt int sparkleColorInt) {
198         Color color = Color.valueOf(colorInt);
199         Color sparkleColor = Color.valueOf(sparkleColorInt);
200         setUniform("in_color", new float[] {color.red(),
201                 color.green(), color.blue(), color.alpha()});
202         setUniform("in_sparkleColor", new float[] {sparkleColor.red(),
203                 sparkleColor.green(), sparkleColor.blue(), sparkleColor.alpha()});
204     }
205 
setResolution(float w, float h)206     public void setResolution(float w, float h) {
207         final float densityScale = 2.1f;
208         setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
209         setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
210     }
211 }
212