@@ -19,58 +19,79 @@ package com.example.jetlagged
19
19
import android.graphics.Color
20
20
import android.graphics.RuntimeShader
21
21
import android.os.Build
22
+ import androidx.annotation.RequiresApi
22
23
import androidx.compose.animation.core.withInfiniteAnimationFrameMillis
23
- import androidx.compose.runtime.getValue
24
- import androidx.compose.runtime.produceState
24
+ import androidx.compose.runtime.mutableFloatStateOf
25
25
import androidx.compose.ui.Modifier
26
- import androidx.compose.ui.composed
27
26
import androidx.compose.ui.draw.drawWithCache
28
27
import androidx.compose.ui.graphics.Brush
29
28
import androidx.compose.ui.graphics.ShaderBrush
29
+ import androidx.compose.ui.graphics.drawscope.ContentDrawScope
30
+ import androidx.compose.ui.node.DrawModifierNode
31
+ import androidx.compose.ui.node.ModifierNodeElement
30
32
import com.example.jetlagged.ui.theme.White
31
33
import com.example.jetlagged.ui.theme.Yellow
32
34
import com.example.jetlagged.ui.theme.YellowVariant
35
+ import kotlinx.coroutines.launch
33
36
import org.intellij.lang.annotations.Language
34
37
35
- fun Modifier.yellowBackground (): Modifier = this .composed {
36
- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
37
- // produce updating time in seconds variable to pass into shader
38
- val time by produceState(0f ) {
38
+ private data object YellowBackgroundElement : ModifierNodeElement <YellowBackgroundNode >() {
39
+ @RequiresApi(Build .VERSION_CODES .TIRAMISU )
40
+ override fun create () = YellowBackgroundNode ()
41
+ override fun update (node : YellowBackgroundNode ) {
42
+ }
43
+ }
44
+
45
+ @RequiresApi(Build .VERSION_CODES .TIRAMISU )
46
+ private class YellowBackgroundNode : DrawModifierNode , Modifier .Node () {
47
+
48
+ private val shader = RuntimeShader (SHADER )
49
+ private val shaderBrush = ShaderBrush (shader)
50
+ private val time = mutableFloatStateOf(0f )
51
+
52
+ init {
53
+ shader.setColorUniform(
54
+ " color" ,
55
+ Color .valueOf(Yellow .red, Yellow .green, Yellow .blue, Yellow .alpha)
56
+ )
57
+ }
58
+
59
+ override fun ContentDrawScope.draw () {
60
+ shader.setFloatUniform(" resolution" , size.width, size.height)
61
+ shader.setFloatUniform(" time" , time.floatValue)
62
+ drawRect(shaderBrush)
63
+ drawContent()
64
+ }
65
+
66
+ override fun onAttach () {
67
+ coroutineScope.launch {
39
68
while (true ) {
40
69
withInfiniteAnimationFrameMillis {
41
- value = it / 1000f
70
+ time.floatValue = it / 1000f
42
71
}
43
72
}
44
73
}
45
- Modifier .drawWithCache {
46
- val shader = RuntimeShader (SHADER )
47
- val shaderBrush = ShaderBrush (shader)
48
- shader.setFloatUniform(" iResolution" , size.width, size.height)
49
- // Pass the color to support color space automatically
50
- shader.setColorUniform(
51
- " iColor" ,
52
- Color .valueOf(Yellow .red, Yellow .green, Yellow .blue, Yellow .alpha)
53
- )
54
- onDrawBehind {
55
- shader.setFloatUniform(" iTime" , time)
56
- drawRect(shaderBrush)
57
- }
58
- }
74
+ }
75
+ }
76
+
77
+ fun Modifier.yellowBackground (): Modifier =
78
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
79
+ this .then(YellowBackgroundElement )
59
80
} else {
60
- Modifier .drawWithCache {
81
+ drawWithCache {
82
+
61
83
val gradientBrush = Brush .verticalGradient(listOf (Yellow , YellowVariant , White ))
62
84
onDrawBehind {
63
85
drawRect(gradientBrush)
64
86
}
65
87
}
66
88
}
67
- }
68
89
69
90
@Language(" AGSL" )
70
91
val SHADER = """
71
- uniform float2 iResolution ;
72
- uniform float iTime ;
73
- layout(color) uniform half4 iColor ;
92
+ uniform float2 resolution ;
93
+ uniform float time ;
94
+ layout(color) uniform half4 color ;
74
95
75
96
float calculateColorMultiplier(float yCoord, float factor) {
76
97
return step(yCoord, 1.0 + factor * 2.0) - step(yCoord, factor - 0.1);
@@ -84,23 +105,23 @@ val SHADER = """
84
105
const float energy = 0.6;
85
106
86
107
// Calculated values
87
- float2 uv = fragCoord / iResolution .xy;
88
- float3 color = iColor .rgb;
89
- float timeOffset = iTime * speedMultiplier;
108
+ float2 uv = fragCoord / resolution .xy;
109
+ float3 rgbColor = color .rgb;
110
+ float timeOffset = time * speedMultiplier;
90
111
float hAdjustment = uv.x * 4.3;
91
- float3 loopColor = vec3(1.0 - color .r, 1.0 - color .g, 1.0 - color .b) / loops;
112
+ float3 loopColor = vec3(1.0 - rgbColor .r, 1.0 - rgbColor .g, 1.0 - rgbColor .b) / loops;
92
113
93
114
for (float i = 1.0; i <= loops; i += 1.0) {
94
115
float loopFactor = i * 0.1;
95
116
float sinInput = (timeOffset + hAdjustment) * energy;
96
117
float curve = sin(sinInput) * (1.0 - loopFactor) * 0.05;
97
118
float colorMultiplier = calculateColorMultiplier(uv.y, loopFactor);
98
- color += loopColor * colorMultiplier;
119
+ rgbColor += loopColor * colorMultiplier;
99
120
100
121
// Offset for next loop
101
122
uv.y += curve;
102
123
}
103
124
104
- return float4(color , 1.0);
125
+ return float4(rgbColor , 1.0);
105
126
}
106
127
""" .trimIndent()
0 commit comments