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.turbulencenoise 17 18 import android.graphics.RuntimeShader 19 import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary 20 import java.lang.Float.max 21 22 /** Shader that renders turbulence simplex noise, with no octave. */ 23 class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) { 24 // language=AGSL 25 companion object { 26 private const val UNIFORMS = 27 """ 28 uniform float in_gridNum; 29 uniform vec3 in_noiseMove; 30 uniform vec2 in_size; 31 uniform float in_aspectRatio; 32 uniform float in_opacity; 33 uniform float in_pixelDensity; 34 layout(color) uniform vec4 in_color; 35 layout(color) uniform vec4 in_backgroundColor; 36 """ 37 38 private const val SHADER_LIB = 39 """ 40 float getLuminosity(vec3 c) { 41 return 0.3*c.r + 0.59*c.g + 0.11*c.b; 42 } 43 44 vec3 maskLuminosity(vec3 dest, float lum) { 45 dest.rgb *= vec3(lum); 46 // Clip back into the legal range 47 dest = clamp(dest, vec3(0.), vec3(1.0)); 48 return dest; 49 } 50 """ 51 52 private const val MAIN_SHADER = 53 """ 54 vec4 main(vec2 p) { 55 vec2 uv = p / in_size.xy; 56 uv.x *= in_aspectRatio; 57 58 vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum; 59 float luma = simplex3d(noiseP) * in_opacity; 60 vec3 mask = maskLuminosity(in_color.rgb, luma); 61 vec3 color = in_backgroundColor.rgb + mask * 0.6; 62 63 // Add dither with triangle distribution to avoid color banding. Ok to dither in the 64 // shader here as we are in gamma space. 65 float dither = triangleNoise(p * in_pixelDensity) / 255.; 66 67 // The result color should be pre-multiplied, i.e. [R*A, G*A, B*A, A], thus need to 68 // multiply rgb with a to get the correct result. 69 color = (color + dither.rrr) * in_color.a; 70 return vec4(color, in_color.a); 71 } 72 """ 73 74 private const val TURBULENCE_NOISE_SHADER = 75 ShaderUtilLibrary.SHADER_LIB + UNIFORMS + SHADER_LIB + MAIN_SHADER 76 } 77 78 /** Sets the number of grid for generating noise. */ setGridCountnull79 fun setGridCount(gridNumber: Float = 1.0f) { 80 setFloatUniform("in_gridNum", gridNumber) 81 } 82 83 /** 84 * Sets the pixel density of the screen. 85 * 86 * Used it for noise dithering. 87 */ setPixelDensitynull88 fun setPixelDensity(pixelDensity: Float) { 89 setFloatUniform("in_pixelDensity", pixelDensity) 90 } 91 92 /** Sets the noise color of the effect. */ setColornull93 fun setColor(color: Int) { 94 setColorUniform("in_color", color) 95 } 96 97 /** Sets the background color of the effect. */ setBackgroundColornull98 fun setBackgroundColor(color: Int) { 99 setColorUniform("in_backgroundColor", color) 100 } 101 102 /** 103 * Sets the opacity to achieve fade in/ out of the animation. 104 * 105 * Expected value range is [1, 0]. 106 */ setOpacitynull107 fun setOpacity(opacity: Float) { 108 setFloatUniform("in_opacity", opacity) 109 } 110 111 /** Sets the size of the shader. */ setSizenull112 fun setSize(width: Float, height: Float) { 113 setFloatUniform("in_size", width, height) 114 setFloatUniform("in_aspectRatio", width / max(height, 0.001f)) 115 } 116 117 /** Current noise movements in x, y, and z axes. */ 118 var noiseOffsetX: Float = 0f 119 private set 120 var noiseOffsetY: Float = 0f 121 private set 122 var noiseOffsetZ: Float = 0f 123 private set 124 125 /** Sets noise move offset in x, y, and z direction. */ setNoiseMovenull126 fun setNoiseMove(x: Float, y: Float, z: Float) { 127 noiseOffsetX = x 128 noiseOffsetY = y 129 noiseOffsetZ = z 130 setFloatUniform("in_noiseMove", noiseOffsetX, noiseOffsetY, noiseOffsetZ) 131 } 132 } 133