Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ac6ce93 authored by Yein Jo's avatar Yein Jo Committed by Android (Google) Code Review
Browse files

Merge "Add ellipse shape to the ripple." into tm-qpr-dev

parents b9e77447 436b6628
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.systemui.ripple.RippleView
 */
class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleView(context, attrs) {
    init {
        // TODO: use RippleShape#ELLIPSE when calling setupShader.
        setupShader()
        setRippleFill(true)
        duration = 3000L
+36 −12
Original line number Diff line number Diff line
@@ -36,7 +36,8 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C
    /** Shapes that the [RippleShader] supports. */
    enum class RippleShape {
        CIRCLE,
        ROUNDED_BOX
        ROUNDED_BOX,
        ELLIPSE
    }

    companion object {
@@ -57,12 +58,10 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C
                uniform float in_sparkle_strength;"""

        private const val SHADER_CIRCLE_MAIN = """vec4 main(vec2 p) {
                // distortion only applies to circle
                vec2 p_distorted = distort(p, in_time, in_distort_radial, in_distort_xy);
                float radius = in_size.x * 0.5;

                float sparkleRing = softRing(p_distorted, in_center, radius, in_blur);
                float inside = softCircle(p_distorted, in_center, radius * 1.2, in_blur);
                float sparkleRing = soften(circleRing(p_distorted-in_center, radius), in_blur);
                float inside = soften(sdCircle(p_distorted-in_center, radius * 1.2), in_blur);
                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
                    * (1.-sparkleRing) * in_fadeSparkle;

@@ -75,9 +74,26 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C
        """

        private const val SHADER_ROUNDED_BOX_MAIN = """vec4 main(vec2 p) {
                float sparkleRing = softRoundedBoxRing(p, in_center, in_size, in_cornerRadius,
                    in_thickness, in_blur);
                float inside = softRoundedBox(p, in_center, in_size * 1.2, in_cornerRadius, in_blur);
                float sparkleRing = soften(roundedBoxRing(p-in_center, in_size, in_cornerRadius,
                    in_thickness), in_blur);
                float inside = soften(sdRoundedBox(p-in_center, in_size * 1.2, in_cornerRadius),
                    in_blur);
                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
                    * (1.-sparkleRing) * in_fadeSparkle;

                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * 0.45;
                vec4 ripple = in_color * rippleAlpha;
                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
            }
        """

        private const val SHADER_ELLIPSE_MAIN = """vec4 main(vec2 p) {
                vec2 p_distorted = distort(p, in_time, in_distort_radial, in_distort_xy);

                float sparkleRing = soften(ellipseRing(p_distorted-in_center, in_size), in_blur);
                float inside = soften(sdEllipse(p_distorted-in_center, in_size * 1.2), in_blur);
                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
                    * (1.-sparkleRing) * in_fadeSparkle;

@@ -90,13 +106,21 @@ class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.C
        """

        private const val CIRCLE_SHADER = SHADER_UNIFORMS + RippleShaderUtilLibrary.SHADER_LIB +
                SdfShaderLibrary.CIRCLE_SDF + SHADER_CIRCLE_MAIN
                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB + SdfShaderLibrary.CIRCLE_SDF +
                SHADER_CIRCLE_MAIN
        private const val ROUNDED_BOX_SHADER = SHADER_UNIFORMS +
                RippleShaderUtilLibrary.SHADER_LIB + SdfShaderLibrary.ROUNDED_BOX_SDF +
                SHADER_ROUNDED_BOX_MAIN
                RippleShaderUtilLibrary.SHADER_LIB + SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
                SdfShaderLibrary.ROUNDED_BOX_SDF + SHADER_ROUNDED_BOX_MAIN
        private const val ELLIPSE_SHADER = SHADER_UNIFORMS + RippleShaderUtilLibrary.SHADER_LIB +
                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB + SdfShaderLibrary.ELLIPSE_SDF +
                SHADER_ELLIPSE_MAIN

        private fun buildShader(rippleShape: RippleShape): String =
                if (rippleShape == RippleShape.CIRCLE) CIRCLE_SHADER else ROUNDED_BOX_SHADER
                when (rippleShape) {
                    RippleShape.CIRCLE -> CIRCLE_SHADER
                    RippleShape.ROUNDED_BOX -> ROUNDED_BOX_SHADER
                    RippleShape.ELLIPSE -> ELLIPSE_SHADER
                }

        private fun subProgress(start: Float, end: Float, progress: Float): Float {
            val min = Math.min(start, end)
+16 −15
Original line number Diff line number Diff line
@@ -18,7 +18,8 @@ package com.android.systemui.ripple
/** A common utility functions that are used for computing [RippleShader]. */
class RippleShaderUtilLibrary {
    companion object {
        const val SHADER_LIB = """float triangleNoise(vec2 n) {
        const val SHADER_LIB = """
            float triangleNoise(vec2 n) {
                    n  = fract(n * vec2(5.3987, 5.4421));
                    n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
                    float xy = n.x * n.y;
+58 −24
Original line number Diff line number Diff line
@@ -23,22 +23,13 @@ class SdfShaderLibrary {
                return (length(p)-r) / r;
            }

            float softCircle(vec2 p, vec2 origin, float radius, float blur) {
                float d = sdCircle(p-origin, radius);
                float blurHalf = blur * 0.5;
                return smoothstep(-blurHalf, blurHalf, d);
            }

            float softRing(vec2 p, vec2 origin, float radius, float blur) {
            float circleRing(vec2 p, float radius) {
                float thicknessHalf = radius * 0.25;

                float outerCircle = sdCircle(p-origin, radius + thicknessHalf);
                float innerCircle = sdCircle(p-origin, radius);
                float outerCircle = sdCircle(p, radius + thicknessHalf);
                float innerCircle = sdCircle(p, radius);

                float d = max(outerCircle, -innerCircle);
                float blurHalf = blur * 0.5;

                return smoothstep(-blurHalf, blurHalf, d);
                return subtract(outerCircle, innerCircle);
            }
        """

@@ -54,24 +45,67 @@ class SdfShaderLibrary {
                return (outside+inside-cornerRadius)/size.y;
            }

            float softRoundedBox(vec2 p, vec2 origin, vec2 size, float cornerRadius, float blur) {
                float d = sdRoundedBox(p-origin, size, cornerRadius);
                float blurHalf = blur * 0.5;
                return smoothstep(-blurHalf, blurHalf, d);
            float roundedBoxRing(vec2 p, vec2 size, float cornerRadius,
                float borderThickness) {
                float outerRoundBox = sdRoundedBox(p, size, cornerRadius);
                float innerRoundBox = sdRoundedBox(p, size - vec2(borderThickness),
                    cornerRadius - borderThickness);
                return subtract(outerRoundBox, innerRoundBox);
            }
        """

            float softRoundedBoxRing(vec2 p, vec2 origin, vec2 size, float cornerRadius,
                float borderThickness, float blur) {
        // Used non-trigonometry parametrization and Halley's method (iterative) for root finding.
        // This is more expensive than the regular circle SDF, recommend to use the circle SDF if
        // possible.
        const val ELLIPSE_SDF = """float sdEllipse(vec2 p, vec2 wh) {
            wh *= 0.5;

                float outerRoundBox = sdRoundedBox(p-origin, size, cornerRadius);
                float innerRoundBox = sdRoundedBox(p-origin, size - vec2(borderThickness),
                    cornerRadius - borderThickness);
            // symmetry
            (wh.x > wh.y) ? wh = wh.yx, p = abs(p.yx) : p = abs(p);

                float d = max(outerRoundBox, -innerRoundBox);
                float blurHalf = blur * 0.5;
            vec2 u = wh*p, v = wh*wh;

            float U1 = u.y/2.0;  float U5 = 4.0*U1;
            float U2 = v.y-v.x;  float U6 = 6.0*U1;
            float U3 = u.x-U2;   float U7 = 3.0*U3;
            float U4 = u.x+U2;

            float t = 0.5;
            for (int i = 0; i < 3; i ++) {
                float F1 = t*(t*t*(U1*t+U3)+U4)-U1;
                float F2 = t*t*(U5*t+U7)+U4;
                float F3 = t*(U6*t+U7);

                t += (F1*F2)/(F1*F3-F2*F2);
            }

            t = clamp(t, 0.0, 1.0);

            float d = distance(p, wh*vec2(1.0-t*t,2.0*t)/(t*t+1.0));
            d /= wh.y;

            return (dot(p/wh,p/wh)>1.0) ? d : -d;
        }

        float ellipseRing(vec2 p, vec2 wh) {
            vec2 thicknessHalf = wh * 0.25;

            float outerEllipse = sdEllipse(p, wh + thicknessHalf);
            float innerEllipse = sdEllipse(p, wh);

            return subtract(outerEllipse, innerEllipse);
        }
        """

        const val SHADER_SDF_OPERATION_LIB = """
            float soften(float d, float blur) {
                float blurHalf = blur * 0.5;
                return smoothstep(-blurHalf, blurHalf, d);
            }

            float subtract(float outer, float inner) {
                return max(outer, -inner);
            }
        """
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -43,4 +43,9 @@ class RippleViewTest : SysuiTestCase() {
    fun testSetupShader_compilesRoundedBox() {
        rippleView.setupShader(RippleShader.RippleShape.ROUNDED_BOX)
    }

    @Test
    fun testSetupShader_compilesEllipse() {
        rippleView.setupShader(RippleShader.RippleShape.ELLIPSE)
    }
}