Shader "MPUI/Basic Procedural Image"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" { }
        _Color ("Tint", Color) = (1,1,1,1)
        
        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255
        _ColorMask ("Color Mask", Float) = 15
        
        
              /* //SOFTMASK_HANDLE_START
         [PerRendererData] _SoftMask ("Mask", 2D) = "white" {}
              */ //SOFTMASK_HANDLE_END
        
        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    }
    
    SubShader
    {
        Tags { "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "PreviewType" = "Plane" "CanUseSpriteAtlas" = "True" }
        
        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }
        
        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha
        ColorMask [_ColorMask]
        
        Pass
        {
            Name "Default"
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            #include "UnityUI.cginc"
            #include "2D_SDF.cginc"
                  /* //SOFTMASK_HANDLE_START
			#include "Assets/SoftMask/Shaders/SoftMask.cginc" //SOFTMASK_INCLUDE_HANDLE
                  */ //SOFTMASK_HANDLE_END
            
            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
            
            #pragma multi_compile_local _ CIRCLE TRIANGLE RECTANGLE NSTAR_POLYGON
            #pragma multi_compile_local _ STROKE OUTLINED OUTLINED_STROKE
            
                  /* //SOFTMASK_HANDLE_START
            #pragma multi_compile _ SOFTMASK_SIMPLE
                  */ //SOFTMASK_HANDLE_END
            
            
            struct appdata_t
            {
                float4 vertex: POSITION;
                float4 color: COLOR;
                float2 uv0: TEXCOORD0;
                float2 uv1: TEXCOORD1;
                float2 uv2: TEXCOORD2;
                float2 uv3: TEXCOORD3;
                float3 normal: NORMAL;
                float4 tangent: TANGENT;
                
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
            
            struct v2f
            {
                float4 vertex: SV_POSITION;
                fixed4 color: COLOR;
                float2 uv0: TEXCOORD0;
                float4 sizeData: TEXCOORD1;
                float4 strokeOutlineCornerData: TEXCOORD2;
                fixed4 outlineColor: COLOR1;
                float4 shapeData: TEXCOORD3;
                float4 worldPosition: TEXCOORD4;

                
                      /* //SOFTMASK_HANDLE_START
                SOFTMASK_COORDS(5)
                      */ //SOFTMASK_HANDLE_END
                
                UNITY_VERTEX_OUTPUT_STEREO
            };
            
            sampler2D _MainTex;
            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _ClipRect;
            float4 _MainTex_ST;

            #if RECTANGLE
                half rectangleScene(float4 _sizeData, float4 _shapeData, float _cornerStyle)
                {
                    float2 _texcoord = _sizeData.xy;
                    float2 _size = float2(_sizeData.z, _sizeData.w);
                    float4 radius = _shapeData;
                    half4 c  = half4(_texcoord, _size - _texcoord);
                    half rect = min(min(min(c.x, c.y), c.z), c.w);

                    bool4 cornerRects;
                    cornerRects.x = _texcoord.x < radius.x && _texcoord.y < radius.x;
                    cornerRects.y = _texcoord.x > _size.x - radius.y && _texcoord.y < radius.y;
                    cornerRects.z = _texcoord.x > _size.x - radius.z && _texcoord.y > _size.y - radius.z;
                    cornerRects.w = _texcoord.x < radius.w && _texcoord.y > _size.y - radius.w;

                    half cornerMask = any(cornerRects);

                    half4 cornerCircles;
                    cornerCircles.x = radius.x - length(_texcoord - radius.xx);//circle(_texcoord - radius.xx, radius.x);
                    cornerCircles.y = radius.y - length(_texcoord - half2(_size.x - radius.y, radius.y));//circle(_texcoord - half2(_size.x - radius.y, radius.y), radius.y);
                    cornerCircles.z = radius.z - length(_texcoord - (half2(_size.x, _size.y) - radius.zz));//circle(_texcoord - (half2(_size.x, _size.y) - radius.zz), radius.z);
                    cornerCircles.w = radius.w - length(_texcoord - half2(radius.w, _size.y - radius.w)); //circle(_texcoord - half2(radius.w, _size.y - radius.w), radius.w);

                    cornerCircles = min(max(cornerCircles, 0) * cornerRects, rect);
                    //cornerCircles = max(cornerCircles, 0) * cornerRects;
                    half corners = max(max(max(cornerCircles.x, cornerCircles.y), cornerCircles.z), cornerCircles.w);
                    corners = max(corners, 0.0) * cornerMask;

                    //return rect;
                    return rect*(cornerMask-1) - corners;

                    /*
                    half rect = rectanlge(_texcoord - half2(_size.x / 2.0, _size.y / 2.0), _size.x, _size.y);
                    half cornerCircle = circle(_texcoord - radius.xx, radius.x);
                    rect = _texcoord.x < radius.x && _texcoord.y < radius.x ? cornerCircle: rect;
                    cornerCircle = circle(_texcoord - half2(_size.x - radius.y, radius.y), radius.y);
                    rect = _texcoord.x > _size.x - radius.y && _texcoord.y < radius.y ? cornerCircle: rect;
                    cornerCircle = circle(_texcoord - (half2(_size.x, _size.y) - radius.zz), radius.z);
                    rect = _texcoord.x > _size.x - radius.z && _texcoord.y > _size.y - radius.z ? cornerCircle: rect;
                    cornerCircle = circle(_texcoord - half2(radius.w, _size.y - radius.w), radius.w);
                    rect = _texcoord.x < radius.w && _texcoord.y > _size.y - radius.w ? cornerCircle: rect;
                    */
                    
                    //max(max(max(cornerCircles.x, cornerCircles.y), cornerCircles.z), cornerCircles.w);
                }
            #endif
            
            #if CIRCLE
                float circleScene(float4 _sizeData, float4 _shapeData)
                {
                    float2 _texcoord = _sizeData.xy;
                    float2 _size = _sizeData.zw;
                    float width = _size.x;
                    float height = _size.y;
                    float radius = lerp(_shapeData.x, min(width, height) / 2.0, _shapeData.y);
                    float sdf = circle(_texcoord - float2(width / 2.0, height / 2.0), radius);
                    return sdf;
                }
            #endif
            
            #if TRIANGLE
                half triangleScene(float4 _sizeData, float4 _shapeData)
                {
                    float2 _texcoord = _sizeData.xy;
                    float2 _size = _sizeData.zw;
                    float width = _size.x;//_additionalData.z;
                    float height = _size.y;//_additionalData.w;
                    
                    half sdf = sdTriangleIsosceles(_texcoord - half2(width / 2.0, height), half2(width / 2.0, -height));

                    //return sdf;
                    
                    float3 _TriangleCornerRadius = max(_shapeData.xyz, float3(0.001, 0.001, 0.001));
                    // Left Corner
                    half halfWidth = width / 2.0;
                    half m = height / halfWidth;
                    half d = sqrt(1.0 + m * m);
                    half c = 0.0;
                    half k = -_TriangleCornerRadius.x * d + c;
                    half x = (_TriangleCornerRadius.x - k) / m;
                    half2 circlePivot = half2(x, _TriangleCornerRadius.x);
                    half cornerCircle = circle(_texcoord - circlePivot, _TriangleCornerRadius.x);
                    //sdf = sdfDifference(sdf, cornerCircle);
                    //return sdf;
                    x = (circlePivot.y + circlePivot.x / m - c) / (m + 1.0 / m);
                    half y = m * x + c;
                    half fy = map(_texcoord.x, x, circlePivot.x, y, circlePivot.y);
                    sdf = _texcoord.y < fy && _texcoord.x < circlePivot.x ? cornerCircle: sdf;
                    //return sdf;
                    // Right Corner
                    m = -m; c = 2.0 * height;
                    k = -_TriangleCornerRadius.y * d + c;
                    x = (_TriangleCornerRadius.y - k) / m;
                    circlePivot = half2(x, _TriangleCornerRadius.y);
                    cornerCircle = circle(_texcoord - circlePivot, _TriangleCornerRadius.y);
                    x = (circlePivot.y + circlePivot.x / m - c) / (m + 1.0 / m); y = m * x + c;
                    fy = map(_texcoord.x, circlePivot.x, x, circlePivot.y, y);
                    sdf = _texcoord.x > circlePivot.x && _texcoord.y < fy ? cornerCircle: sdf;
                    
                    //Top Corner
                    k = -_TriangleCornerRadius.z * sqrt(1.0 + m * m) + c;
                    y = m * (width / 2.0) + k;
                    circlePivot = half2(halfWidth, y);
                    cornerCircle = circle(_texcoord - circlePivot, _TriangleCornerRadius.z);
                    x = (circlePivot.y + circlePivot.x / m - c) / (m + 1.0 / m); y = m * x + c;
                    fy = map(_texcoord.x, width - x, x, -1.0, 1.0);
                    fy = lerp(circlePivot.y, y, abs(fy));
                    sdf = _texcoord.y > fy ? cornerCircle: sdf;
                    
                    return sdf;
                }
            #endif
            
            #if NSTAR_POLYGON
                half nStarPolygonScene(float4 _sizeData, float4 _shapeData)
                {
                    float2 _texcoord = _sizeData.xy;
                    float width = _sizeData.z;
                    float height = _sizeData.w;
                    float size = height / 2 - _shapeData.y;
                    half str = sdNStarPolygon(_texcoord - half2(width / 2, height / 2), size, _shapeData.x, _shapeData.z) - _shapeData.y;
                    return str;
                }
            #endif
            
            float2 rotateUV(float2 uv, float rotation, float2 mid)
            {
                return float2(
                  cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
                  cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
                );
            }
            
			
			float4 decode_0_1_16(float2 input){
			    float m = 65535.0;
			    float e = 256.0 / 255.0;
			    float n = 1.0 / m;
			    
			    float4 c = float4(input.x, input.x, input.y, input.y);
			    c.yw *= m;
			    c = frac(c);
			    c -= float4(c.y, 0.0, c.w, 0.0) * n;
			    return clamp(c * e, 0.0, 1.0);
			}
			
            
            v2f vert(appdata_t v)
            {
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
                
                OUT.vertex = UnityObjectToClipPos(v.vertex);
                OUT.worldPosition = v.vertex;
                OUT.color = v.color * _Color;
                OUT.uv0 = v.uv0;
    
                
                float2 size = v.uv1;
                half strokeWidth = v.normal.y;
                half falloff = v.normal.z;
                
                float rotationData = v.uv3.x;
                half cornerStyle = v.uv3.y;
                
                half outlineWidth = v.normal.x;
                half4 outlineColor = v.tangent;

                float4 shapeData;
                #if CIRCLE
                    shapeData.xy = v.uv2.xy;
                #else
                    shapeData = decode_0_1_16(v.uv2) * min(size.x, size.y);
                #endif
                
               
                OUT.strokeOutlineCornerData = float4(strokeWidth, falloff, outlineWidth, cornerStyle);
                OUT.outlineColor = outlineColor;
                OUT.shapeData = shapeData;
                
                // Rotation Values
                half sign = rotationData > 0.0 ? 1 : -1;
                float f = abs(rotationData);
                float shapeRotation = frac(f) * 360.0 * sign;
                
                // r.xyz -> constrainRotation, flipHorizontal, flipVertical
                
                f = floor(f);
                float p = f / 100.0;
                float z = round(p); 
                p = frac(p) * 10.0;
                float y = round(p);
                p = frac(p) * 10.0;
                float x = round(p);
                
                half constrainRotation = x;
                half flipHorizontal = y;
                half flipVertical = z;
                
                
                shapeRotation = radians(shapeRotation);
                size = constrainRotation > 0.0 && frac(abs(shapeRotation) / 3.14159) > 0.1? float2(size.y, size.x) : size;
                
                float2 shapeUv = constrainRotation > 0 ? v.uv0 : v.uv0 * size;
                shapeUv = rotateUV(shapeUv, shapeRotation, constrainRotation > 0? float2(0.5, 0.5) : size * 0.5);
                shapeUv*= constrainRotation > 0.0? size : 1.0;
                
                shapeUv.x = lerp(shapeUv.x, abs(size.x - shapeUv.x), flipHorizontal);
                shapeUv.y = lerp(shapeUv.y, abs(size.y - shapeUv.y), flipVertical);
                
                OUT.sizeData = float4(shapeUv.x, shapeUv.y, size.x, size.y);
                
                #ifdef UNITY_HALF_TEXEL_OFFSET
                    OUT.vertex.xy += (_ScreenParams.zw - 1.0) * float2(-1.0, 1.0);
                #endif
                
                      /* //SOFTMASK_HANDLE_START
                SOFTMASK_CALCULATE_COORDS(OUT, v.vertex);
                      */ //SOFTMASK_HANDLE_END
                return OUT;
            }
            
            fixed4 frag(v2f IN): SV_Target
            {
                half4 color = IN.color;
                half2 texcoord = IN.uv0;
                color = (tex2D(_MainTex, texcoord) + _TextureSampleAdd) * color;
                
                float4 sizeData = IN.sizeData;
                float strokeWidth = IN.strokeOutlineCornerData.x;
                float falloff = IN.strokeOutlineCornerData.y;
                float outlineWidth = IN.strokeOutlineCornerData.z;
                half4 outlineColor = IN.outlineColor;
                float cornerStyle = IN.strokeOutlineCornerData.w;
                
                float4 shapeData = IN.shapeData;
                half pixelScale = clamp(1.0/falloff, 1.0/2048.0, 2048.0);
                
                float sdfData = 0;
                #if RECTANGLE
                    sdfData = rectangleScene(sizeData, shapeData, cornerStyle);
                #endif
                
                #if CIRCLE
                    sdfData = circleScene(sizeData, shapeData);
                #endif
                
                #if TRIANGLE
                    sdfData = triangleScene(sizeData, shapeData);
                #endif
                
                #if NSTAR_POLYGON
                    sdfData = nStarPolygonScene(sizeData, shapeData);
                #endif
                
                
                #if !OUTLINED && !STROKE && !OUTLINED_STROKE
                    half shape = sampleSdf(sdfData, pixelScale);
                    color.a *= shape;
                    //color.a = sdfData;
                #endif
                #if STROKE
                    half shape = sampleSdfStrip(sdfData, strokeWidth, pixelScale);
                    color.a *= shape;
                #endif
                
                #if OUTLINED
                    float alpha = sampleSdf(sdfData, pixelScale);
                    float lerpFac = sampleSdf(sdfData + outlineWidth, pixelScale);
                    color = half4(lerp(outlineColor.rgb, color.rgb, lerpFac), lerp(outlineColor.a * color.a, color.a, lerpFac));
                    color.a *= alpha;
                #endif
                
                #if OUTLINED_STROKE
                    float alpha = sampleSdfStrip(sdfData, outlineWidth + strokeWidth, pixelScale);
                    float lerpFac = sampleSdfStrip(sdfData + outlineWidth, strokeWidth + falloff, pixelScale);
                    lerpFac = clamp(lerpFac, 0, 1);
                    color = half4(lerp(outlineColor.rgb, color.rgb, lerpFac), lerp(outlineColor.a * color.a, color.a, lerpFac));
                    color.a *= alpha;
                #endif


                      /* //SOFTMASK_HANDLE_START
                color.a *= SOFTMASK_GET_MASK(IN);
                      */ //SOFTMASK_HANDLE_END
                
                #ifdef UNITY_UI_CLIP_RECT
                    color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif
                
                #ifdef UNITY_UI_ALPHACLIP
                    clip(color.a - 0.001);
                #endif
                
                return fixed4(color);
            }
            ENDCG
            
        }
    }
    CustomEditor "MPUIKIT.Editor.MPImageShaderGUI"
}
