diff --git a/backdrop/src/main/java/com/kyant/backdrop/Shaders.kt b/backdrop/src/main/java/com/kyant/backdrop/Shaders.kt index 7eac99a..856c1e9 100644 --- a/backdrop/src/main/java/com/kyant/backdrop/Shaders.kt +++ b/backdrop/src/main/java/com/kyant/backdrop/Shaders.kt @@ -210,3 +210,17 @@ half4 main(float2 coord) { } return half4(0.0) * intensity * alpha; }""" + +@Language("AGSL") +internal const val GammaAdjustmentShaderString = """ +uniform shader image; + +uniform float power; + +half4 main(float2 coord) { + half4 color = image.eval(coord); + color.r = pow(color.r, power); + color.g = pow(color.g, power); + color.b = pow(color.b, power); + return color; +}""" diff --git a/backdrop/src/main/java/com/kyant/backdrop/effects/ColorFilter.kt b/backdrop/src/main/java/com/kyant/backdrop/effects/ColorFilter.kt index 81c77c8..b43573f 100644 --- a/backdrop/src/main/java/com/kyant/backdrop/effects/ColorFilter.kt +++ b/backdrop/src/main/java/com/kyant/backdrop/effects/ColorFilter.kt @@ -7,6 +7,28 @@ import android.graphics.RenderEffect import android.os.Build import androidx.compose.ui.graphics.asAndroidColorFilter import com.kyant.backdrop.BackdropEffectScope +import com.kyant.backdrop.GammaAdjustmentShaderString +import kotlin.math.pow + +@Deprecated( + "Use colorControls() instead", + replaceWith = ReplaceWith("colorControls(brightness, contrast, saturation)") +) +fun BackdropEffectScope.colorFilter( + brightness: Float = 0f, + contrast: Float = 1f, + saturation: Float = 1f +) { + colorControls(brightness, contrast, saturation) +} + +@Deprecated( + "Use vibrancy() instead", + replaceWith = ReplaceWith("vibrancy()") +) +fun BackdropEffectScope.saturation() { + vibrancy() +} fun BackdropEffectScope.colorFilter(colorFilter: ColorFilter) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return @@ -21,18 +43,10 @@ fun BackdropEffectScope.colorFilter(colorFilter: ColorFilter) { } fun BackdropEffectScope.colorFilter(colorFilter: androidx.compose.ui.graphics.ColorFilter) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return - - val currentEffect = renderEffect - renderEffect = - if (currentEffect != null) { - RenderEffect.createColorFilterEffect(colorFilter.asAndroidColorFilter(), currentEffect) - } else { - RenderEffect.createColorFilterEffect(colorFilter.asAndroidColorFilter()) - } + colorFilter(colorFilter.asAndroidColorFilter()) } -fun BackdropEffectScope.colorFilter( +fun BackdropEffectScope.colorControls( brightness: Float = 0f, contrast: Float = 1f, saturation: Float = 1f @@ -41,25 +55,38 @@ fun BackdropEffectScope.colorFilter( return } - val colorFilter = colorAdjustmentColorFilter(brightness, contrast, saturation) - colorFilter(colorFilter) + colorFilter(colorControlsColorFilter(brightness, contrast, saturation)) } fun BackdropEffectScope.vibrancy() { colorFilter(VibrantColorFilter) } -@Deprecated( - "Use vibrancy() instead", - replaceWith = ReplaceWith("vibrancy()") -) -fun BackdropEffectScope.saturation() { - vibrancy() +private val VibrantColorFilter = colorControlsColorFilter(saturation = 1.5f) + +fun BackdropEffectScope.exposureAdjustment(ev: Float) { + val scale = 2f.pow(ev / 2.2f) + val colorMatrix = ColorMatrix( + floatArrayOf( + scale, 0f, 0f, 0f, 0f, + 0f, scale, 0f, 0f, 0f, + 0f, 0f, scale, 0f, 0f, + 0f, 0f, 0f, 1f, 0f + ) + ) + colorFilter(ColorMatrixColorFilter(colorMatrix)) } -private val VibrantColorFilter = colorAdjustmentColorFilter(saturation = 1.5f) +fun BackdropEffectScope.gammaAdjustment(power: Float) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return -private fun colorAdjustmentColorFilter( + val shader = obtainRuntimeShader("GammaAdjustment", GammaAdjustmentShaderString).apply { + setFloatUniform("power", power) + } + effect(RenderEffect.createRuntimeShaderEffect(shader, "image")) +} + +private fun colorControlsColorFilter( brightness: Float = 0f, contrast: Float = 1f, saturation: Float = 1f diff --git a/backdrop/src/main/java/com/kyant/backdrop/effects/RenderEffect.kt b/backdrop/src/main/java/com/kyant/backdrop/effects/RenderEffect.kt index a86c3bb..bccbb90 100644 --- a/backdrop/src/main/java/com/kyant/backdrop/effects/RenderEffect.kt +++ b/backdrop/src/main/java/com/kyant/backdrop/effects/RenderEffect.kt @@ -19,11 +19,5 @@ fun BackdropEffectScope.effect(effect: RenderEffect) { fun BackdropEffectScope.effect(effect: androidx.compose.ui.graphics.RenderEffect) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return - val currentEffect = renderEffect - renderEffect = - if (currentEffect != null) { - RenderEffect.createChainEffect(effect.asAndroidRenderEffect(), currentEffect) - } else { - effect.asAndroidRenderEffect() - } + effect(effect.asAndroidRenderEffect()) } diff --git a/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/AdaptiveLuminanceGlassContent.kt b/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/AdaptiveLuminanceGlassContent.kt index cd74293..0160241 100644 --- a/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/AdaptiveLuminanceGlassContent.kt +++ b/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/AdaptiveLuminanceGlassContent.kt @@ -32,7 +32,7 @@ import com.kyant.backdrop.catalog.BackdropDemoScaffold import com.kyant.backdrop.catalog.Block import com.kyant.backdrop.drawBackdrop import com.kyant.backdrop.effects.blur -import com.kyant.backdrop.effects.colorFilter +import com.kyant.backdrop.effects.colorControls import com.kyant.backdrop.effects.refraction import com.kyant.capsule.ContinuousRoundedRectangle import kotlinx.coroutines.Dispatchers @@ -115,7 +115,7 @@ fun AdaptiveLuminanceGlassContent() { } ) { val l = (luminanceAnimation.value * 2f - 1f).let { sign(it) * it * it } - colorFilter( + colorControls( brightness = if (l > 0f) lerp(0.1f, 0.5f, l) else lerp(0.1f, -0.2f, -l), diff --git a/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/DialogContent.kt b/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/DialogContent.kt index 4ad8142..40b277a 100644 --- a/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/DialogContent.kt +++ b/catalog/src/main/java/com/kyant/backdrop/catalog/destinations/DialogContent.kt @@ -27,7 +27,7 @@ import com.kyant.backdrop.catalog.BackdropDemoScaffold import com.kyant.backdrop.catalog.R import com.kyant.backdrop.drawBackdrop import com.kyant.backdrop.effects.blur -import com.kyant.backdrop.effects.colorFilter +import com.kyant.backdrop.effects.colorControls import com.kyant.backdrop.effects.refraction import com.kyant.backdrop.highlight.Highlight import com.kyant.backdrop.highlight.HighlightStyle @@ -66,7 +66,7 @@ fun DialogContent() { highlight = { Highlight { HighlightStyle.Solid } }, onDrawSurface = { drawRect(containerColor) } ) { - colorFilter( + colorControls( brightness = if (isLightTheme) 0.2f else 0f, saturation = 1.5f )