diff --git a/JetLagged/app/src/main/java/com/example/jetlagged/Background.kt b/JetLagged/app/src/main/java/com/example/jetlagged/Background.kt index 0f4fc3ecda..fd6c42c320 100644 --- a/JetLagged/app/src/main/java/com/example/jetlagged/Background.kt +++ b/JetLagged/app/src/main/java/com/example/jetlagged/Background.kt @@ -19,58 +19,79 @@ package com.example.jetlagged import android.graphics.Color import android.graphics.RuntimeShader import android.os.Build +import androidx.annotation.RequiresApi import androidx.compose.animation.core.withInfiniteAnimationFrameMillis -import androidx.compose.runtime.getValue -import androidx.compose.runtime.produceState +import androidx.compose.runtime.mutableFloatStateOf 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 androidx.compose.ui.graphics.drawscope.ContentDrawScope +import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.ModifierNodeElement import com.example.jetlagged.ui.theme.White import com.example.jetlagged.ui.theme.Yellow import com.example.jetlagged.ui.theme.YellowVariant +import kotlinx.coroutines.launch import org.intellij.lang.annotations.Language -fun Modifier.yellowBackground(): 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) { +private data object YellowBackgroundElement : ModifierNodeElement() { + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + override fun create() = YellowBackgroundNode() + override fun update(node: YellowBackgroundNode) { + } +} + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +private class YellowBackgroundNode : DrawModifierNode, Modifier.Node() { + + private val shader = RuntimeShader(SHADER) + private val shaderBrush = ShaderBrush(shader) + private val time = mutableFloatStateOf(0f) + + init { + shader.setColorUniform( + "color", + Color.valueOf(Yellow.red, Yellow.green, Yellow.blue, Yellow.alpha) + ) + } + + override fun ContentDrawScope.draw() { + shader.setFloatUniform("resolution", size.width, size.height) + shader.setFloatUniform("time", time.floatValue) + drawRect(shaderBrush) + drawContent() + } + + override fun onAttach() { + coroutineScope.launch { while (true) { withInfiniteAnimationFrameMillis { - value = it / 1000f + time.floatValue = it / 1000f } } } - Modifier.drawWithCache { - val shader = RuntimeShader(SHADER) - val shaderBrush = ShaderBrush(shader) - shader.setFloatUniform("iResolution", size.width, size.height) - // Pass the color to support color space automatically - shader.setColorUniform( - "iColor", - Color.valueOf(Yellow.red, Yellow.green, Yellow.blue, Yellow.alpha) - ) - onDrawBehind { - shader.setFloatUniform("iTime", time) - drawRect(shaderBrush) - } - } + } +} + +fun Modifier.yellowBackground(): Modifier = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.then(YellowBackgroundElement) } else { - Modifier.drawWithCache { + drawWithCache { + val gradientBrush = Brush.verticalGradient(listOf(Yellow, YellowVariant, White)) onDrawBehind { drawRect(gradientBrush) } } } -} @Language("AGSL") val SHADER = """ - uniform float2 iResolution; - uniform float iTime; - layout(color) uniform half4 iColor; + uniform float2 resolution; + uniform float time; + layout(color) uniform half4 color; float calculateColorMultiplier(float yCoord, float factor) { return step(yCoord, 1.0 + factor * 2.0) - step(yCoord, factor - 0.1); @@ -84,23 +105,23 @@ val SHADER = """ const float energy = 0.6; // Calculated values - float2 uv = fragCoord / iResolution.xy; - float3 color = iColor.rgb; - float timeOffset = iTime * speedMultiplier; + float2 uv = fragCoord / resolution.xy; + float3 rgbColor = color.rgb; + float timeOffset = time * speedMultiplier; float hAdjustment = uv.x * 4.3; - float3 loopColor = vec3(1.0 - color.r, 1.0 - color.g, 1.0 - color.b) / loops; + float3 loopColor = vec3(1.0 - rgbColor.r, 1.0 - rgbColor.g, 1.0 - rgbColor.b) / 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) * (1.0 - loopFactor) * 0.05; float colorMultiplier = calculateColorMultiplier(uv.y, loopFactor); - color += loopColor * colorMultiplier; + rgbColor += loopColor * colorMultiplier; // Offset for next loop uv.y += curve; } - return float4(color, 1.0); + return float4(rgbColor, 1.0); } """.trimIndent()