﻿Shader "Ikeiwa/HUD/HUDs/SciFi"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color("Color",Color) = (0,1,1,1)
        _SecondaryColor("Active Color",Color) = (1,0,0,1)
        _ShadowColor("Shadow Color",Color) = (0,0,0,0.5)
        
        [Header(Hidden Modules)]
        [Toggle(HIDE_COMPASS)] _HideCompass("Hide Compass", Float) = 0
        [Toggle(HIDE_CLOCK)] _HideClock("Hide Clock", Float) = 0
        [Toggle(HIDE_FPS)] _HideFPS("Hide FPS", Float) = 0
        [Toggle(HIDE_MINIMAP)] _HideMiniMap("Hide Minimap", Float) = 0
        [Toggle(HIDE_MIC)] _HideMic("Hide Microphone", Float) = 0
        [Toggle(HIDE_COORDS)] _HideCoordinates("Hide Coordinates", Float) = 0
        [Toggle(HIDE_OVERLAYS)] _HideOverlays("Hide Overlays Status", Float) = 0

        [Header(Shape)]
        _Curvature("Curvature", Float) = 0.25
        _HUDOffset("Offset", Vector) = (0,0,-1,0)
        _RatioTweak("UI Ratio Tweak",Float) = 0
        _ScaleRatio("UI Scale Ratio",Float) = 1
        _Scale("UI Scale",Float) = 1
        _VRHUDOffset("VR Offset", Vector) = (0,0,-1,0)
        _VRRatioTweak("VR UI Ratio Tweak",Float) = 0
        _VRScaleRatio("VR UI Scale Ratio",Float) = 1
        _VRScale("VR UI Scale",Float) = 1
        _VRStereoSeparation("VR Stereo Separation", Float) = 0

        [Header(Radar)]
        _MapDepthTex ("Map Depth Texture", 2D) = "white" {}
        _MapDepthHighTex ("Map Depth High Texture", 2D) = "white" {}
        _PlayersTex ("Players Texture", 2D) = "white" {}
        _ZHeight( "Height", Float ) = 12
        _ZHeightHigh( "Height High", Float ) = 20
        _ZOffset("Offset", Float) = 2
        _ZOffsetHigh("Offset High", Float) = 10
        _MapSize("Map Size", Float) = 20

        [Header(Runtime Values)]
        _HUDActive("HUD Active", Range(0,1)) = 1
        _MicEnabled("Mic Enabled",Range(0,1)) = 0
        _MicLevel("Mic Level",Range(0,1)) = 0
        _OverlayActive("Overlay Is Active",Float) = 0
        _Overlay("Current Overlay",Float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Overlay+1" }
        LOD 100
        ZTest Off
        ZWrite Off
        Cull Off
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #pragma shader_feature HIDE_COMPASS
            #pragma shader_feature HIDE_CLOCK
            #pragma shader_feature HIDE_FPS
            #pragma shader_feature HIDE_MINIMAP
            #pragma shader_feature HIDE_MIC
            #pragma shader_feature HIDE_COORDS
            #pragma shader_feature HIDE_OVERLAYS

            #include "UnityCG.cginc"
            #include "../../Shaders/Overlays.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float2 ID : TEXCOORD1;
                float2 Anchor : TEXCOORD2;
                float2 ExtraData : TEXCOORD3;
                float2 Module : TEXCOORD4;
                float4 color : COLOR;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                int2 ID : TEXCOORD1;
                float2 ExtraData : TEXCOORD2;
                float4 vertex : SV_POSITION;
                float4 color : COLOR;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            float4 _Color;
            float4 _SecondaryColor;
            float4 _ShadowColor;
            float _Curvature;
            float3 _HUDOffset;
            float3 _VRHUDOffset;
            float _RatioTweak;
            float _VRRatioTweak;
            float _ScaleRatio;
            float _VRScaleRatio;
            float _Scale;
            float _VRScale;
            float _VRStereoSeparation;

            //Runtime Values
            float _HUDActive;
            float _MicEnabled;
            float _MicLevel;
            float _OverlayActive;
            float _Overlay;

            //Radar
            float _ZHeight;
            float _ZHeightHigh;
            float _ZOffset;
            float _ZOffsetHigh;
            sampler2D _MapDepthTex;
            sampler2D _MapDepthHighTex;
            float4 _MapDepthHighTex_TexelSize;
            sampler2D _PlayersTex;
            float _MapSize;

            v2f vert (appdata v)
            {
                v2f o;

                UNITY_SETUP_INSTANCE_ID( v );
	            UNITY_INITIALIZE_OUTPUT( v2f, o );
	            UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o );

                bool hidden = CheckModules(isHudHidden(), v.Module);

                if(hidden)
                {
                    o.vertex = 0;
                    o.uv = 0;
                    o.ID = 0;
                    o.ExtraData = 0;
                    o.color = 0;
                    return o;
                }

                float dist = length(v.vertex.xy)*_Curvature;

                v.Anchor.y = -v.Anchor.y;

                bool isvr = isVR();

                float ratioTweak = isvr ? _VRRatioTweak : _RatioTweak;
                float ratio = (_ScreenParams.x / _ScreenParams.y - 1) / 2 + ratioTweak;

                v.vertex.xy += v.Anchor.xy/2;
                v.vertex.xyz *= isvr ? _VRScaleRatio : _ScaleRatio;
                v.vertex.xy -= v.Anchor.xy/2;

                v.vertex.x -= v.Anchor.x * ratio;

                v.vertex.xyz *= isvr ? _VRScale : _Scale;


                float3 hudOffset = _HUDOffset;

                if(isvr){
                    hudOffset = _VRHUDOffset;
                    float stereoOffset = isRightEye() ? -_VRStereoSeparation : _VRStereoSeparation;
                    hudOffset.x += stereoOffset;
                }
                hudOffset.xy *= abs(_VRHUDOffset.z);

                v.vertex.z += dist - _Curvature/2;
                v.vertex.xyz += hudOffset;
                v.vertex.xz *= -1;

                float3 scale = float3(smoothstep(0,0.5,_HUDActive),smoothstep(0.45,1,_HUDActive)+0.05f,1);

                v.vertex.xyz *= scale;

                unity_ObjectToWorld = cameraCenterToWorld();

                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.ID = v.ID;
                o.ExtraData = v.ExtraData;

                o.color = lerp(_Color,_SecondaryColor,v.color.g);
                o.color = lerp(o.color,_ShadowColor,v.color.b);
                o.color.a *= v.color.a;

                float3 camForward = cameraCenterForward();

                float3 viewForward = normalize(float3(camForward.xz,0));
                float viewDir = atan2(dot(cross(viewForward,float3(0,1,0)), float3(0,0,1)),dot(viewForward,float3(0,1,0)));

                int ID = o.ID.x;
                int subID = o.ID.y;

                if(ID == ID_COMPASS)
                {
                    o.uv.x += (viewDir/TwoPI);
                }
                else if(ID == ID_TIME)
                {
                    uint minutes = _Time.y / 60;
                    uint hours = _Time.y / 3600;

				    uint m1 = minutes % 10;
				    uint m10 = minutes / 10 % 6;
				    uint h1 = hours % 10;
				    uint h10 = hours / 10 % 10;

                    float offset = m1;
                    if(subID == 1) offset = m10;
                    else if(subID == 2) offset = h1;
                    else if(subID == 3) offset = h10;

                    o.uv.x += 0.1 * offset;
                }
                else if(ID == ID_FPS)
                {
                    float fpsPower = pow(10,subID);
                    int fpsDigit = (abs(unity_DeltaTime.w) / fpsPower) % 10;
                    o.uv.x += fpsDigit * 0.1f;
                }
                else if(ID == ID_MINIMAP)
                {
                    o.ExtraData = o.uv;
                    o.uv = rotateUV(o.uv,viewDir);
                }
                else if(ID >= ID_COORDX && ID <= ID_COORDZ) 
                { 
                    int coord = ObjectWorldPivot().x;

                    if(ID == ID_COORDY)
                        coord = ObjectWorldPivot().y;
                    else if(ID == ID_COORDZ)
                        coord = ObjectWorldPivot().z;

                    if(subID == SUBID_COORD_NEG && coord > 0)
                    {
                        o.color.a = 0;
                    }
                    else
                    {
                        float coordPower = pow(10,subID);
                        int coordDigit = (abs(coord) / coordPower) % 10;
                        o.uv.x += coordDigit * 0.1f;
                    }
                    
                }

                return o;
            }

            float FitHeight(float depth, float camFar, float offset)
            {
                return depth * camFar - offset;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX( i );

                float2 uv = i.uv;
                float2 ExtraData = i.ExtraData;

                int ID = i.ID.x;
                int subID = i.ID.y;

                fixed4 masks = tex2Dlod(_MainTex, float4(uv,0,0));

                float4 color = i.color;
                float alpha = masks.r;

                //Components
                float radarMask = saturate(i.color.r + i.color.g + i.color.b - 2);

                if(ID == ID_MIC)
                {
                    if(subID == SUBID_MIC_VOL)
                    {
                        alpha = step(ExtraData.y+0.005f,_MicLevel);
                    }
                    else
                    {
                        alpha = masks.r * lerp(1-_MicEnabled,_MicEnabled,ExtraData.y);
                    }
                }
                else if (ID == ID_OVERLAY) 
                { 
                    float overlayMask = subID == _Overlay;

                    alpha = masks.r * lerp(1-overlayMask,overlayMask,ExtraData.x);
                }
                else if (ID == ID_MINIMAP)
                {
                    // Sample Height maps
                    float z = FitHeight(tex2D(_MapDepthTex,ExtraData), _ZHeight, _ZOffsetHigh);
		            float zHigh = FitHeight(tex2D(_MapDepthHighTex,ExtraData), _ZHeightHigh, _ZOffsetHigh);
		            float zPlayers = tex2D(_PlayersTex,ExtraData);

                    float height = zHigh;

                    // Ceilling Check
                    float2 hiddenOffset = _MapDepthHighTex_TexelSize.xy * 5;

                    float isHidden = tex2Dlod(_MapDepthHighTex, float4(float2(0.5,0.5),0,0)).r;
                    isHidden += tex2Dlod(_MapDepthHighTex, float4(float2(0.5,0.5)+float2(hiddenOffset.x,0),0,0)).r;
                    isHidden += tex2Dlod(_MapDepthHighTex, float4(float2(0.5,0.5)-float2(hiddenOffset.x,0),0,0)).r;
                    isHidden += tex2Dlod(_MapDepthHighTex, float4(float2(0.5,0.5)+float2(0,hiddenOffset.y),0,0)).r;
                    isHidden += tex2Dlod(_MapDepthHighTex, float4(float2(0.5,0.5)-float2(0,hiddenOffset.y),0,0)).r;

                    if((isHidden / 5) > 0.6f)
                    {
                        height = z;
                    }

                    // Masks
                    float heightGradient = remap(-_ZOffsetHigh,_ZOffsetHigh,0.3,0.75,height);
                    float heightWorld = height + ObjectWorldPivot().y;
                    bool playerMask = ceil(zPlayers);
                    float radarDistance = distance(uv,float2(0.5f,0.5f))*4;
                    float radarFade = smoothstep(2,1,radarDistance)*0.75f;

                    float pulseRing = glsl_mod(radarDistance/5-_Time.y/5,1); 
                    float radarRing = smoothstep(0.9,1,pulseRing) * radarFade;
                    float playerRing = smoothstep(0.15,1,pulseRing) * radarFade * playerMask;

                    float mapForeground = tex2Dlod(_MainTex,float4(uv,0,0)).b * IsWithinUnitSquare(uv);

                    // Grid
                    float2 gridUV = uv + ObjectWorldPivot().xz/_MapSize;
                    float grid = tex2Dlod(_MainTex,float4(gridUV*3,0,4)).g;

                    // Height Lines
                    float heightLines = heightWorld + 0.7;

                    float smallLineDst = abs(glsl_mod(heightLines,1)*2-1);
                    float smallLines = smoothstep(0.98 - fwidth(smallLineDst), 0.98, smallLineDst);

                    float bigLineDst = abs(glsl_mod(heightLines/5,1)*2-1);
                    float bigLines = smoothstep(0.99 - fwidth(bigLineDst), 0.99, bigLineDst);

                    float lines = saturate(smallLines*0.25f + bigLines * 0.5f) * (1-playerMask);

                    // Player Arrow
                    float playerArrow = tex2Dlod(_MainTex,float4(i.ExtraData,0,2)).a;

                    // Final Layering
                    float mapAlpha = heightGradient + lines + grid + radarRing + playerMask + mapForeground + playerArrow;

                    alpha = saturate(pow(mapAlpha,2));

                    color = lerp(_Color,_SecondaryColor, saturate(playerRing + mapForeground + playerArrow));
                    color.rgb *= alpha;

                    return color;
                }

                color.a *= alpha;

                return color;
            }
            ENDCG
        }
    }
}
