diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt new file mode 100644 index 0000000000000..c94fad7246fae --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SolidColorShader.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.surfaceeffects.shaders + +import android.graphics.RuntimeShader + +/** Simply renders a solid color. */ +class SolidColorShader(color: Int) : RuntimeShader(SHADER) { + // language=AGSL + private companion object { + private const val SHADER = + """ + layout(color) uniform vec4 in_color; + vec4 main(vec2 p) { + return in_color; + } + """ + } + + init { + setColorUniform("in_color", color) + } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt new file mode 100644 index 0000000000000..df07856e325e3 --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaders/SparkleShader.kt @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.surfaceeffects.shaders + +import android.graphics.Color +import android.graphics.RuntimeShader +import android.graphics.Shader +import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary + +/** + * Renders sparkles based on the luma matte. + * + * For example, you can pass in simplex noise as the luma matte and have a cloud looking sparkles. + * + * You may want to utilize this shader by: (Preferred) 1. Create a RuntimeShaderEffect and set the + * [RenderEffect] to the target [View]. + * 2. Create a custom [View], set the shader to the [Paint] and use [Canvas.drawPaint] in [onDraw]. + */ +class SparkleShader : RuntimeShader(SPARKLE_SHADER) { + // language=AGSL + companion object { + private const val UNIFORMS = + """ + // Used it for RenderEffect. For example: + // myView.setRenderEffect( + // RenderEffect.createRuntimeShaderEffect(SparkleShader(), "in_src") + // ) + uniform shader in_src; + uniform half in_time; + uniform half in_pixelate; + uniform shader in_lumaMatte; + layout(color) uniform vec4 in_color; + """ + private const val MAIN_SHADER = + """vec4 main(vec2 p) { + half3 src = in_src.eval(p).rgb; + half luma = getLuminosity(in_lumaMatte.eval(p).rgb); + half sparkle = sparkles(p - mod(p, in_pixelate), in_time); + half3 mask = maskLuminosity(in_color.rgb * sparkle, luma); + + return vec4(src * mask * in_color.a, in_color.a); + } + """ + private const val SPARKLE_SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER + + /** Highly recommended to use this value unless specified by design spec. */ + const val DEFAULT_SPARKLE_PIXELATE_AMOUNT = 0.8f + } + + init { + // Initializes the src and luma matte to be white. + setInputShader("in_src", SolidColorShader(Color.WHITE)) + setLumaMatteColor(Color.WHITE) + } + + /** + * Sets the time of the sparkle animation. + * + * This is used for animating sparkles. Note that this only makes the sparkles sparkle in place. + * In order to move the sparkles in x, y directions, move the luma matte input instead. + */ + fun setTime(time: Float) { + setFloatUniform("in_time", time) + } + + /** + * Sets pixelated amount of the sparkle. + * + * This value *must* be based on [resources.displayMetrics.density]. Otherwise, this will result + * in having different sparkle sizes on different screens. + * + * Expected to be used as follows: + *
+ * {@code
+ * val pixelDensity = context.resources.displayMetrics.density
+ * // Sparkles will be 0.8 of the pixel size.
+ * val sparkleShader = SparkleShader().apply { setPixelateAmount(pixelDensity * 0.8f) }
+ * }
+ *
+ */
+ fun setPixelateAmount(pixelateAmount: Float) {
+ setFloatUniform("in_pixelate", pixelateAmount)
+ }
+
+ /**
+ * Sets the luma matte for the sparkles. The luminosity determines the sparkle's visibility.
+ * Useful for setting a complex mask (e.g. simplex noise, texture, etc.)
+ */
+ fun setLumaMatte(lumaMatte: Shader) {
+ setInputShader("in_lumaMatte", lumaMatte)
+ }
+
+ /** Sets the luma matte for the sparkles. Useful for setting a solid color. */
+ fun setLumaMatteColor(color: Int) {
+ setInputShader("in_lumaMatte", SolidColorShader(color))
+ }
+
+ /** Sets the color of the sparkles. Expect to have the alpha value encoded. */
+ fun setColor(color: Int) {
+ setColorUniform("in_color", color)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
new file mode 100644
index 0000000000000..f1fadf6f1a4af
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SolidColorShaderTest.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.surfaceeffects.shaders
+
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SolidColorShaderTest : SysuiTestCase() {
+
+ @Test
+ fun compilesShader() {
+ SolidColorShader(Color.RED)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
new file mode 100644
index 0000000000000..64ea6a68a5185
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/shaders/SparkleShaderTest.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.surfaceeffects.shaders
+
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SparkleShaderTest : SysuiTestCase() {
+
+ private lateinit var sparkleShader: SparkleShader
+
+ @Test
+ fun compilesSparkleShader() {
+ sparkleShader =
+ SparkleShader().apply {
+ setPixelateAmount(
+ context.resources.displayMetrics.density *
+ SparkleShader.DEFAULT_SPARKLE_PIXELATE_AMOUNT
+ )
+ setColor(Color.RED)
+ setTime(0.01f)
+ setLumaMatteColor(Color.WHITE)
+ }
+ }
+}