Created
February 23, 2023 06:14
-
-
Save jmadaminov/bc9b75c95eea084e569b646b4e45ff88 to your computer and use it in GitHub Desktop.
A modifier which can be used on a Box composable for fancy animated look - works only on Android 13
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.Color | |
import android.graphics.RuntimeShader | |
import android.os.Build | |
import androidx.compose.animation.core.withInfiniteAnimationFrameMillis | |
import androidx.compose.runtime.getValue | |
import androidx.compose.runtime.produceState | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.composed | |
import androidx.compose.ui.draw.drawWithCache | |
import androidx.compose.ui.graphics.Brush | |
import androidx.compose.ui.graphics.ShaderBrush | |
import org.intellij.lang.annotations.Language | |
fun Modifier.btnShaderBg(bgColor: androidx.compose.ui.graphics.Color): Modifier = this.composed { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | |
// produce updating time in seconds variable to pass into shader | |
val time by produceState(0f) { | |
while (true) { | |
withInfiniteAnimationFrameMillis { | |
value = it / 1000f | |
} | |
} | |
} | |
Modifier.drawWithCache { | |
val shader = RuntimeShader(SHADER) | |
val shaderBrush = ShaderBrush(shader) | |
shader.setFloatUniform("iResolution", size.width, size.height) | |
shader.setFloatUniform("iTime", time) | |
// Pass the color to support color space automatically | |
shader.setColorUniform( | |
"iColor", | |
Color.valueOf(bgColor.red, bgColor.green, bgColor.blue, bgColor.alpha) | |
) | |
onDrawBehind { | |
drawRect(shaderBrush) | |
} | |
} | |
} else { | |
Modifier.drawWithCache { | |
val gradientBrush = Brush.verticalGradient(listOf(bgColor, BtnMain2)) | |
onDrawBehind { | |
drawRect(gradientBrush) | |
} | |
} | |
} | |
} | |
@Language("AGSL") | |
private val SHADER = """ | |
uniform float2 iResolution; | |
uniform float iTime; | |
layout(color) uniform half4 iColor; | |
float calculateColorMultiplier(float yCoord, float factor) { | |
return step(yCoord, 1.0 + factor * 4.0) - step(yCoord, factor - 0.1); | |
} | |
float4 main(in float2 fragCoord) { | |
// Config values | |
const float speedMultiplier = 1.5; | |
const float waveDensity = 1.0; | |
const float loops = 50.0; | |
const float energy = 0.6; | |
// Calculated values | |
float2 uv = fragCoord / iResolution.xy; | |
float3 color = iColor.rgb; | |
float timeOffset = iTime * speedMultiplier; | |
float hAdjustment = uv.x * 4.3; | |
float3 loopColor = vec3(1.0 - color.r, 1.0 - color.g, 1.0 - color.b) * 2.5 / loops; | |
for (float i = 1.0; i <= loops; i += 1.0) { | |
float loopFactor = i * 0.1; | |
float sinInput = (timeOffset + hAdjustment) * energy; | |
float curve = sin(sinInput) * (2.0 - loopFactor) * 0.05; | |
float colorMultiplier = calculateColorMultiplier(uv.y, loopFactor); | |
color += loopColor * colorMultiplier * iColor.rgb * uv.y; | |
uv.y += curve; | |
} | |
return float4(color, 1.0); | |
} | |
""".trimIndent() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment