Update the shader layer.
This commit is contained in:
parent
223ae9f02b
commit
a0be0274f1
8 changed files with 399 additions and 83 deletions
|
|
@ -0,0 +1,148 @@
|
||||||
|
package com.pixelized.rplexicon.ui.agsl
|
||||||
|
|
||||||
|
import android.graphics.RenderEffect
|
||||||
|
import android.graphics.RuntimeShader
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Slider
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pixelized.rplexicon.R
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
|
||||||
|
@Language("AGSL")
|
||||||
|
val CHROMATIC_ABERRATION: String = """
|
||||||
|
uniform shader composable;
|
||||||
|
uniform float displacement;
|
||||||
|
uniform float2 size;
|
||||||
|
|
||||||
|
half4 main(float2 coord) {
|
||||||
|
half4 texture = composable.eval(coord);
|
||||||
|
|
||||||
|
float2 distance = (coord - size * 0.5) * 2.0 / size;
|
||||||
|
distance = distance * abs(distance);
|
||||||
|
|
||||||
|
half4 red = composable.eval(float2(
|
||||||
|
coord.x - displacement * distance.x,
|
||||||
|
coord.y - displacement * distance.y
|
||||||
|
));
|
||||||
|
half4 blue = composable.eval(float2(
|
||||||
|
coord.x + displacement * distance.x,
|
||||||
|
coord.y + displacement * distance.y
|
||||||
|
));
|
||||||
|
|
||||||
|
texture.r = red.r;
|
||||||
|
texture.b = blue.b;
|
||||||
|
texture.a = max(texture.a, (red.a + blue.a) / 3.0);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun ChromaticAberrationD20() {
|
||||||
|
val shader = remember { RuntimeShader(CHROMATIC_ABERRATION) }
|
||||||
|
val displacement = remember { mutableFloatStateOf(25f) }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.graphicsLayer {
|
||||||
|
shader.setFloatUniform("displacement", displacement.floatValue)
|
||||||
|
shader.setFloatUniform("size", size.width, size.height)
|
||||||
|
|
||||||
|
renderEffect = RenderEffect
|
||||||
|
.createRuntimeShaderEffect(shader, "composable")
|
||||||
|
.asComposeRenderEffect()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 16.dp),
|
||||||
|
painter = painterResource(id = R.drawable.ic_d20_24),
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
value = displacement.floatValue,
|
||||||
|
valueRange = remember { 0f..100f },
|
||||||
|
onValueChange = { displacement.floatValue = it },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
private fun ChromaticAberrationImage() {
|
||||||
|
val shader = remember { RuntimeShader(CHROMATIC_ABERRATION) }
|
||||||
|
val displacement = remember { mutableFloatStateOf(25f) }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(all = 16.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.graphicsLayer {
|
||||||
|
shader.setFloatUniform("displacement", displacement.floatValue)
|
||||||
|
shader.setFloatUniform("size", size.width, size.height)
|
||||||
|
clip = true
|
||||||
|
renderEffect = RenderEffect
|
||||||
|
.createRuntimeShaderEffect(shader, "composable")
|
||||||
|
.asComposeRenderEffect()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
painter = painterResource(id = R.drawable.im_naderius_background),
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
painter = painterResource(id = R.drawable.im_naderius_foreground),
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
Image(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.offset(y = (-16).dp),
|
||||||
|
painter = painterResource(id = R.drawable.im_naderius_dice),
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
value = displacement.floatValue,
|
||||||
|
valueRange = remember { 0f..100f },
|
||||||
|
onValueChange = { displacement.floatValue = it },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
package com.pixelized.rplexicon.ui.agsl
|
||||||
|
|
||||||
|
import android.graphics.RuntimeShader
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithCache
|
||||||
|
import androidx.compose.ui.graphics.BlendMode
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.CompositingStrategy
|
||||||
|
import androidx.compose.ui.graphics.ShaderBrush
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.pixelized.rplexicon.R
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
@Language("AGSL")
|
||||||
|
val DANCING_COLOR = """
|
||||||
|
uniform float2 size;
|
||||||
|
uniform float time;
|
||||||
|
uniform float transition;
|
||||||
|
layout(color) uniform half4 tint;
|
||||||
|
|
||||||
|
half4 main(float2 coord) {
|
||||||
|
// Normalized pixel coordinates (from 0 to 1)
|
||||||
|
half2 uv = coord.xy / size;
|
||||||
|
// Time varying pixel color
|
||||||
|
half2 wave = 0.5 + 0.5 * cos(time + uv.xy * 2.0 + half2(0, 3.14));
|
||||||
|
half4 color = half4(wave, 1.0, 1.0);
|
||||||
|
// Output to screen
|
||||||
|
return mix(tint, color, transition);
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
fun Modifier.dancingColor(
|
||||||
|
transition: State<Float>,
|
||||||
|
time: State<Float>,
|
||||||
|
default: Color,
|
||||||
|
): Modifier = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
this
|
||||||
|
.graphicsLayer {
|
||||||
|
compositingStrategy = CompositingStrategy.Offscreen
|
||||||
|
}
|
||||||
|
.drawWithCache {
|
||||||
|
val shader = RuntimeShader(DANCING_COLOR)
|
||||||
|
val brush = ShaderBrush(shader)
|
||||||
|
val color = android.graphics.Color.valueOf(default.red, default.green, default.blue)
|
||||||
|
shader.setColorUniform("tint", color)
|
||||||
|
shader.setFloatUniform("size", size.width, size.height)
|
||||||
|
shader.setFloatUniform("transition", transition.value)
|
||||||
|
|
||||||
|
onDrawWithContent {
|
||||||
|
drawContent()
|
||||||
|
shader.setFloatUniform("time", time.value)
|
||||||
|
drawRect(brush = brush, blendMode = BlendMode.SrcAtop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
@Composable
|
||||||
|
@Preview
|
||||||
|
private fun DancingColor() {
|
||||||
|
Image(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.dancingColor(
|
||||||
|
transition = remember { mutableFloatStateOf(1.0f) },
|
||||||
|
time = rememberTimeState(),
|
||||||
|
default = Color.White,
|
||||||
|
),
|
||||||
|
painter = painterResource(id = R.drawable.ic_d20_24),
|
||||||
|
contentScale = ContentScale.FillWidth,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package com.pixelized.rplexicon.ui.agsl
|
||||||
|
|
||||||
|
import android.graphics.RenderEffect
|
||||||
|
import android.graphics.RuntimeShader
|
||||||
|
import android.graphics.Shader
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.pixelized.rplexicon.R
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
// https://medium.com/androiddevelopers/agsl-made-in-the-shade-r-7d06d14fe02a
|
||||||
|
|
||||||
|
@Language("AGSL")
|
||||||
|
val FROSTED_GLASS_SHADER = """
|
||||||
|
uniform shader inputShader;
|
||||||
|
uniform float height;
|
||||||
|
uniform float width;
|
||||||
|
|
||||||
|
vec4 main(vec2 coords) {
|
||||||
|
vec4 currValue = inputShader.eval(coords);
|
||||||
|
float top = height - 100;
|
||||||
|
if (coords.y < top) {
|
||||||
|
return currValue;
|
||||||
|
} else {
|
||||||
|
// Avoid blurring edges
|
||||||
|
if (coords.x > 1 && coords.y > 1 &&
|
||||||
|
coords.x < (width - 1) &&
|
||||||
|
coords.y < (height - 1)) {
|
||||||
|
// simple box blur - average 5x5 grid around pixel
|
||||||
|
vec4 boxSum =
|
||||||
|
inputShader.eval(coords + vec2(-2, -2)) +
|
||||||
|
// ...
|
||||||
|
currValue +
|
||||||
|
// ...
|
||||||
|
inputShader.eval(coords + vec2(2, 2));
|
||||||
|
currValue = boxSum / 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vec4 white = vec4(1);
|
||||||
|
// top-left corner of label area
|
||||||
|
vec2 lefttop = vec2(0.0, top);
|
||||||
|
float lightenFactor = min(1.0, .6 *
|
||||||
|
length(coords - lefttop) /
|
||||||
|
(0.85 * length(vec2(width, 100))));
|
||||||
|
// White in upper-left, blended increasingly
|
||||||
|
// toward lower-right
|
||||||
|
return mix(currValue, white, 1 - lightenFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
@Composable
|
||||||
|
@Preview
|
||||||
|
private fun FrostedGlass() {
|
||||||
|
val shader = remember { RuntimeShader(FROSTED_GLASS_SHADER) }
|
||||||
|
|
||||||
|
Image(
|
||||||
|
modifier = Modifier.graphicsLayer {
|
||||||
|
shader.setFloatUniform("width", size.width)
|
||||||
|
shader.setFloatUniform("height", size.height)
|
||||||
|
clip = true
|
||||||
|
val glass = RenderEffect.createRuntimeShaderEffect(shader, "inputShader")
|
||||||
|
val blur = RenderEffect.createBlurEffect(30f, 30f, Shader.TileMode.CLAMP)
|
||||||
|
renderEffect = RenderEffect.createChainEffect(blur, glass).asComposeRenderEffect()
|
||||||
|
},
|
||||||
|
painter = painterResource(id = R.drawable.im_brulkhai),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.pixelized.rplexicon.ui.agsl
|
||||||
|
|
||||||
|
import android.graphics.RenderEffect
|
||||||
|
import android.graphics.RuntimeShader
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import com.pixelized.rplexicon.R
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
|
|
||||||
|
@Language("AGSL")
|
||||||
|
val RANDOM_NOISE = """
|
||||||
|
uniform shader composable;
|
||||||
|
uniform float2 size;
|
||||||
|
|
||||||
|
float random(float2 uv) {
|
||||||
|
return fract(sin(dot(uv.xy, float2(12.9898, 78.233))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
half4 main(float2 coord) {
|
||||||
|
float2 uv = coord / size;
|
||||||
|
float noise = random(uv);
|
||||||
|
return half4(uv.x * noise, 0.0, uv.y * noise, 1.0);
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
@Composable
|
||||||
|
@Preview
|
||||||
|
private fun RandomNoise() {
|
||||||
|
val shader = remember { RuntimeShader(RANDOM_NOISE) }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.graphicsLayer {
|
||||||
|
shader.setFloatUniform("size", size.width, size.height)
|
||||||
|
clip = true
|
||||||
|
val noise = RenderEffect
|
||||||
|
.createRuntimeShaderEffect(shader, "composable")
|
||||||
|
renderEffect = noise.asComposeRenderEffect()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Image(painter = painterResource(id = R.drawable.im_brulkhai), contentDescription = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.pixelized.rplexicon.ui.agsl
|
||||||
|
|
||||||
|
import androidx.compose.animation.core.withInfiniteAnimationFrameMillis
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Stable
|
||||||
|
fun rememberTimeState(speed: Float = 1f): State<Float> {
|
||||||
|
return produceState(0f) {
|
||||||
|
while (true) {
|
||||||
|
withInfiniteAnimationFrameMillis {
|
||||||
|
value = it / 1000f * speed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -119,6 +119,7 @@ private fun LandingContent(
|
||||||
.aspectRatio(1f)
|
.aspectRatio(1f)
|
||||||
.clip(RectangleShape),
|
.clip(RectangleShape),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
Image(
|
Image(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.matchParentSize()
|
.matchParentSize()
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.shrinkOut
|
import androidx.compose.animation.shrinkOut
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
|
@ -21,7 +22,6 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
|
@ -35,6 +35,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
|
@ -44,10 +45,10 @@ import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.rplexicon.R
|
import com.pixelized.rplexicon.R
|
||||||
|
import com.pixelized.rplexicon.ui.agsl.dancingColor
|
||||||
|
import com.pixelized.rplexicon.ui.agsl.rememberTimeState
|
||||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.criticalShader
|
|
||||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.rememberITimeState
|
|
||||||
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -120,25 +121,26 @@ private fun Dice(
|
||||||
dice: State<RollDiceUio?>,
|
dice: State<RollDiceUio?>,
|
||||||
) {
|
) {
|
||||||
dice.value?.let {
|
dice.value?.let {
|
||||||
|
val time = rememberTimeState()
|
||||||
val animatedRotation = animateFloatAsState(
|
val animatedRotation = animateFloatAsState(
|
||||||
targetValue = it.rotation * 360,
|
targetValue = it.rotation * 360,
|
||||||
animationSpec = it.animationSpec,
|
animationSpec = it.animationSpec,
|
||||||
label = "AnimatedRotation"
|
label = "AnimatedRotation"
|
||||||
)
|
)
|
||||||
val isCritical = animateFloatAsState(
|
val transition = animateFloatAsState(
|
||||||
targetValue = if (it.isCriticalSuccess) 1.0f else 0f,
|
targetValue = if (it.isCriticalSuccess) 1.0f else 0f,
|
||||||
label = "animatedCritical",
|
label = "animatedCritical",
|
||||||
animationSpec = tween(1500),
|
animationSpec = tween(1500),
|
||||||
)
|
)
|
||||||
Icon(
|
Image(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.rotate(degrees = animatedRotation.value % 360)
|
.rotate(degrees = animatedRotation.value % 360)
|
||||||
.criticalShader(
|
.dancingColor(
|
||||||
iDefault = MaterialTheme.colorScheme.primary,
|
time = time,
|
||||||
isCritical = isCritical.value,
|
transition = transition,
|
||||||
iTime = rememberITimeState().value,
|
default = MaterialTheme.colorScheme.primary,
|
||||||
),
|
),
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
colorFilter = ColorFilter.tint(color = MaterialTheme.colorScheme.primary),
|
||||||
painter = painterResource(id = it.icon),
|
painter = painterResource(id = it.icon),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
package com.pixelized.rplexicon.utilitary.extentions.modifier
|
|
||||||
|
|
||||||
import android.graphics.Color.valueOf
|
|
||||||
import android.graphics.RuntimeShader
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.compose.animation.core.withInfiniteAnimationFrameMillis
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import androidx.compose.runtime.State
|
|
||||||
import androidx.compose.runtime.produceState
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.drawWithCache
|
|
||||||
import androidx.compose.ui.graphics.BlendMode
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.CompositingStrategy
|
|
||||||
import androidx.compose.ui.graphics.ShaderBrush
|
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
|
||||||
import org.intellij.lang.annotations.Language
|
|
||||||
|
|
||||||
fun Modifier.criticalShader(
|
|
||||||
isCritical: Float,
|
|
||||||
iTime: Float,
|
|
||||||
iDefault: Color,
|
|
||||||
): Modifier = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
this
|
|
||||||
.graphicsLayer {
|
|
||||||
compositingStrategy = CompositingStrategy.Offscreen
|
|
||||||
}
|
|
||||||
.drawWithCache {
|
|
||||||
val shader = RuntimeShader(CRITICAL_SHADER)
|
|
||||||
val shaderBrush = ShaderBrush(shader)
|
|
||||||
shader.setFloatUniform("iResolution", size.width, size.height)
|
|
||||||
shader.setFloatUniform("isCritical", isCritical)
|
|
||||||
shader.setColorUniform("iDefault", valueOf(iDefault.red, iDefault.green, iDefault.blue))
|
|
||||||
|
|
||||||
onDrawWithContent {
|
|
||||||
drawContent()
|
|
||||||
shader.setFloatUniform("iTime", iTime)
|
|
||||||
drawRect(brush = shaderBrush, blendMode = BlendMode.SrcAtop)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Stable
|
|
||||||
fun rememberITimeState(speed: Float = 1f): State<Float> {
|
|
||||||
return produceState(0f) {
|
|
||||||
while (true) {
|
|
||||||
withInfiniteAnimationFrameMillis {
|
|
||||||
value = it / 1000f * speed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Language("AGSL")
|
|
||||||
val CRITICAL_SHADER = """
|
|
||||||
uniform float2 iResolution;
|
|
||||||
uniform float iTime;
|
|
||||||
uniform float isCritical;
|
|
||||||
layout(color) uniform half4 iDefault;
|
|
||||||
|
|
||||||
half4 main(float2 fragCoord) {
|
|
||||||
// Normalized pixel coordinates (from 0 to 1)
|
|
||||||
float2 uv = fragCoord.xy / iResolution;
|
|
||||||
// Time varying pixel color
|
|
||||||
float2 color = 0.5 + 0.5 * cos(iTime + uv.xy * 2.0 + float2(0, 3.14));
|
|
||||||
// Output to screen
|
|
||||||
return mix(iDefault, float4(color, 1.0, 1.0), isCritical);
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue