Use Shader instead of RenderEffect for highlight
This commit is contained in:
1 parent
e2571c1d67
commit
781ff16df8
3 files changed
+34
-61
No files matched your search
@@ -166,8 +166,6 @@ half4 main(float2 coord) {
|
|||||||
|
|
||||||
@Language("AGSL")
|
@Language("AGSL")
|
||||||
internal const val DefaultHighlightShaderString = """
|
internal const val DefaultHighlightShaderString = """
|
||||||
uniform shader content;
|
|
||||||
|
|
||||||
uniform float2 size;
|
uniform float2 size;
|
||||||
uniform float4 cornerRadii;
|
uniform float4 cornerRadii;
|
||||||
uniform float angle;
|
uniform float angle;
|
||||||
@@ -184,13 +182,11 @@ half4 main(float2 coord) {
|
|||||||
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, gradRadius);
|
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, gradRadius);
|
||||||
float2 normal = float2(-cos(angle), -sin(angle));
|
float2 normal = float2(-cos(angle), -sin(angle));
|
||||||
float intensity = pow(abs(dot(normal, grad)), falloff);
|
float intensity = pow(abs(dot(normal, grad)), falloff);
|
||||||
return content.eval(coord) * intensity;
|
return half4(intensity);
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
@Language("AGSL")
|
@Language("AGSL")
|
||||||
internal const val AmbientHighlightShaderString = """
|
internal const val AmbientHighlightShaderString = """
|
||||||
uniform shader content;
|
|
||||||
|
|
||||||
uniform float2 size;
|
uniform float2 size;
|
||||||
uniform float4 cornerRadii;
|
uniform float4 cornerRadii;
|
||||||
uniform float angle;
|
uniform float angle;
|
||||||
@@ -207,16 +203,13 @@ half4 main(float2 coord) {
|
|||||||
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, gradRadius);
|
float2 grad = gradSdRoundedRectangle(centeredCoord, halfSize, gradRadius);
|
||||||
float2 normal = float2(-cos(angle), -sin(angle));
|
float2 normal = float2(-cos(angle), -sin(angle));
|
||||||
float d = dot(normal, grad);
|
float d = dot(normal, grad);
|
||||||
float alpha = content.eval(coord).a;
|
|
||||||
float intensity = pow(abs(d), falloff);
|
float intensity = pow(abs(d), falloff);
|
||||||
|
|
||||||
if (d > 0.0) {
|
if (d > 0.0) {
|
||||||
return half4(0.0, 0.0, 0.0, 1.0) * intensity * alpha;
|
return half4(0.0, 0.0, 0.0, 1.0) * intensity;
|
||||||
|
} else {
|
||||||
|
return half4(1.0) * intensity;
|
||||||
}
|
}
|
||||||
if (d < 0.0) {
|
|
||||||
return half4(1.0) * intensity * alpha;
|
|
||||||
}
|
|
||||||
return half4(0.0);
|
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
@Language("AGSL")
|
@Language("AGSL")
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import androidx.compose.ui.graphics.drawOutline
|
|||||||
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
||||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||||
import androidx.compose.ui.graphics.drawscope.translate
|
import androidx.compose.ui.graphics.drawscope.translate
|
||||||
import androidx.compose.ui.graphics.layer.CompositingStrategy
|
|
||||||
import androidx.compose.ui.graphics.layer.GraphicsLayer
|
import androidx.compose.ui.graphics.layer.GraphicsLayer
|
||||||
import androidx.compose.ui.graphics.layer.drawLayer
|
import androidx.compose.ui.graphics.layer.drawLayer
|
||||||
import androidx.compose.ui.node.DrawModifierNode
|
import androidx.compose.ui.node.DrawModifierNode
|
||||||
@@ -73,7 +72,6 @@ internal class HighlightNode(
|
|||||||
override val shouldAutoInvalidate: Boolean = false
|
override val shouldAutoInvalidate: Boolean = false
|
||||||
|
|
||||||
private var highlightLayer: GraphicsLayer? = null
|
private var highlightLayer: GraphicsLayer? = null
|
||||||
private var maskLayer: GraphicsLayer? = null
|
|
||||||
|
|
||||||
private val paint =
|
private val paint =
|
||||||
Paint().apply {
|
Paint().apply {
|
||||||
@@ -94,8 +92,7 @@ internal class HighlightNode(
|
|||||||
drawContent()
|
drawContent()
|
||||||
|
|
||||||
val highlightLayer = highlightLayer
|
val highlightLayer = highlightLayer
|
||||||
val maskLayer = maskLayer
|
if (highlightLayer != null) {
|
||||||
if (highlightLayer != null && maskLayer != null) {
|
|
||||||
val size = size
|
val size = size
|
||||||
val density: Density = this
|
val density: Density = this
|
||||||
val layoutDirection = layoutDirection
|
val layoutDirection = layoutDirection
|
||||||
@@ -116,18 +113,8 @@ internal class HighlightNode(
|
|||||||
|
|
||||||
configurePaint(highlight)
|
configurePaint(highlight)
|
||||||
|
|
||||||
val style = highlight.style
|
highlightLayer.alpha = highlight.alpha
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
highlightLayer.blendMode = highlight.style.blendMode
|
||||||
if (prevStyle != style) {
|
|
||||||
highlightLayer.renderEffect = with(style) {
|
|
||||||
createRenderEffect(
|
|
||||||
shape = shapeProvider.shape,
|
|
||||||
runtimeShaderCache = runtimeShaderCache
|
|
||||||
)
|
|
||||||
}
|
|
||||||
prevStyle = style
|
|
||||||
}
|
|
||||||
}
|
|
||||||
highlightLayer.record(safeSize) {
|
highlightLayer.record(safeSize) {
|
||||||
translate(1f, 1f) {
|
translate(1f, 1f) {
|
||||||
val canvas = drawContext.canvas
|
val canvas = drawContext.canvas
|
||||||
@@ -138,14 +125,8 @@ internal class HighlightNode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maskLayer.alpha = highlight.alpha
|
|
||||||
maskLayer.blendMode = style.blendMode
|
|
||||||
maskLayer.record(safeSize) {
|
|
||||||
drawLayer(highlightLayer)
|
|
||||||
}
|
|
||||||
|
|
||||||
translate(-1f, -1f) {
|
translate(-1f, -1f) {
|
||||||
drawLayer(maskLayer)
|
drawLayer(highlightLayer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,10 +134,6 @@ internal class HighlightNode(
|
|||||||
override fun onAttach() {
|
override fun onAttach() {
|
||||||
val graphicsContext = requireGraphicsContext()
|
val graphicsContext = requireGraphicsContext()
|
||||||
highlightLayer = graphicsContext.createGraphicsLayer()
|
highlightLayer = graphicsContext.createGraphicsLayer()
|
||||||
maskLayer =
|
|
||||||
graphicsContext.createGraphicsLayer().apply {
|
|
||||||
compositingStrategy = CompositingStrategy.Offscreen
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetach() {
|
override fun onDetach() {
|
||||||
@@ -165,10 +142,6 @@ internal class HighlightNode(
|
|||||||
graphicsContext.releaseGraphicsLayer(layer)
|
graphicsContext.releaseGraphicsLayer(layer)
|
||||||
highlightLayer = null
|
highlightLayer = null
|
||||||
}
|
}
|
||||||
maskLayer?.let { layer ->
|
|
||||||
graphicsContext.releaseGraphicsLayer(layer)
|
|
||||||
maskLayer = null
|
|
||||||
}
|
|
||||||
clipPath = null
|
clipPath = null
|
||||||
runtimeShaderCache.clear()
|
runtimeShaderCache.clear()
|
||||||
prevStyle = null
|
prevStyle = null
|
||||||
@@ -185,5 +158,13 @@ internal class HighlightNode(
|
|||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
|
paint.shader = with(highlight.style) {
|
||||||
|
createShader(
|
||||||
|
shape = shapeProvider.shape,
|
||||||
|
runtimeShaderCache = runtimeShaderCache
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,9 +8,8 @@ import androidx.compose.runtime.Immutable
|
|||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.ui.graphics.BlendMode
|
import androidx.compose.ui.graphics.BlendMode
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RenderEffect
|
import androidx.compose.ui.graphics.Shader
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.graphics.asComposeRenderEffect
|
|
||||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.util.fastCoerceAtMost
|
import androidx.compose.ui.util.fastCoerceAtMost
|
||||||
@@ -27,10 +26,10 @@ interface HighlightStyle {
|
|||||||
val blendMode: BlendMode
|
val blendMode: BlendMode
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.S)
|
@RequiresApi(Build.VERSION_CODES.S)
|
||||||
fun DrawScope.createRenderEffect(
|
fun DrawScope.createShader(
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
runtimeShaderCache: RuntimeShaderCache
|
runtimeShaderCache: RuntimeShaderCache
|
||||||
): RenderEffect?
|
): Shader?
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class Plain(
|
data class Plain(
|
||||||
@@ -39,10 +38,10 @@ interface HighlightStyle {
|
|||||||
) : HighlightStyle {
|
) : HighlightStyle {
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.S)
|
@RequiresApi(Build.VERSION_CODES.S)
|
||||||
override fun DrawScope.createRenderEffect(
|
override fun DrawScope.createShader(
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
runtimeShaderCache: RuntimeShaderCache
|
runtimeShaderCache: RuntimeShaderCache
|
||||||
): RenderEffect? = null
|
): Shader? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
@@ -57,20 +56,20 @@ interface HighlightStyle {
|
|||||||
override val blendMode: BlendMode = BlendMode.Plus
|
override val blendMode: BlendMode = BlendMode.Plus
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.S)
|
@RequiresApi(Build.VERSION_CODES.S)
|
||||||
override fun DrawScope.createRenderEffect(
|
override fun DrawScope.createShader(
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
runtimeShaderCache: RuntimeShaderCache
|
runtimeShaderCache: RuntimeShaderCache
|
||||||
): RenderEffect? {
|
): Shader? {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
val shader = runtimeShaderCache.obtainRuntimeShader("Default", DefaultHighlightShaderString)
|
runtimeShaderCache.obtainRuntimeShader(
|
||||||
shader.apply {
|
"Default",
|
||||||
|
DefaultHighlightShaderString
|
||||||
|
).apply {
|
||||||
setFloatUniform("size", size.width, size.height)
|
setFloatUniform("size", size.width, size.height)
|
||||||
setFloatUniform("cornerRadii", getCornerRadii(shape))
|
setFloatUniform("cornerRadii", getCornerRadii(shape))
|
||||||
setFloatUniform("angle", angle * (PI / 180f).toFloat())
|
setFloatUniform("angle", angle * (PI / 180f).toFloat())
|
||||||
setFloatUniform("falloff", falloff)
|
setFloatUniform("falloff", falloff)
|
||||||
}
|
}
|
||||||
android.graphics.RenderEffect.createRuntimeShaderEffect(shader, "content")
|
|
||||||
.asComposeRenderEffect()
|
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -87,20 +86,20 @@ interface HighlightStyle {
|
|||||||
override val blendMode: BlendMode = DrawScope.DefaultBlendMode
|
override val blendMode: BlendMode = DrawScope.DefaultBlendMode
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.S)
|
@RequiresApi(Build.VERSION_CODES.S)
|
||||||
override fun DrawScope.createRenderEffect(
|
override fun DrawScope.createShader(
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
runtimeShaderCache: RuntimeShaderCache
|
runtimeShaderCache: RuntimeShaderCache
|
||||||
): RenderEffect? {
|
): Shader? {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
val shader = runtimeShaderCache.obtainRuntimeShader("Ambient", AmbientHighlightShaderString)
|
runtimeShaderCache.obtainRuntimeShader(
|
||||||
shader.apply {
|
"Ambient",
|
||||||
|
AmbientHighlightShaderString
|
||||||
|
).apply {
|
||||||
setFloatUniform("size", size.width, size.height)
|
setFloatUniform("size", size.width, size.height)
|
||||||
setFloatUniform("cornerRadii", getCornerRadii(shape))
|
setFloatUniform("cornerRadii", getCornerRadii(shape))
|
||||||
setFloatUniform("angle", 45f * (PI / 180f).toFloat())
|
setFloatUniform("angle", 45f * (PI / 180f).toFloat())
|
||||||
setFloatUniform("falloff", 1f)
|
setFloatUniform("falloff", 1f)
|
||||||
}
|
}
|
||||||
android.graphics.RenderEffect.createRuntimeShaderEffect(shader, "content")
|
|
||||||
.asComposeRenderEffect()
|
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -121,9 +120,9 @@ interface HighlightStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun DrawScope.getCornerRadii(shape: Shape): FloatArray {
|
private fun DrawScope.getCornerRadii(shape: Shape): FloatArray {
|
||||||
val shape = shape as? CornerBasedShape ?: return FloatArray(4) { size.minDimension / 2f }
|
|
||||||
val size = size
|
val size = size
|
||||||
val maxRadius = size.minDimension / 2f
|
val maxRadius = size.minDimension / 2f
|
||||||
|
val shape = shape as? CornerBasedShape ?: return FloatArray(4) { maxRadius }
|
||||||
val isLtr = layoutDirection == LayoutDirection.Ltr
|
val isLtr = layoutDirection == LayoutDirection.Ltr
|
||||||
val topLeft =
|
val topLeft =
|
||||||
if (isLtr) shape.topStart.toPx(size, this)
|
if (isLtr) shape.topStart.toPx(size, this)
|
||||||
|
|||||||
Reference in new issue
Block a user