﻿Shader "LyumaShader/AvatarCam"
{
    Properties
    {
        _Color ("Multiply color", Color) = (1,1,1,1)
        _VRColor ("VR Multiply color", Color) = (1,1,1,1)
        _MainTex ("Texture (to flip: tilingX=-1 offsetX=1)", 2D) = "black" {}
        [NoScaleOffset] _RightEyeMainTex ("Right Eye Texture (Optional)", 2D) = "black" {}
        _CamOffsetX ("Camera Offset X", Range (-2, 2)) = 1
        _CamOffsetY ("Camera Offset Y", Range (-2, 2)) = -1
        _CamScale ("Camera Size", Range (0.01, 1)) = .25
        _VRCenterFactor ("VR View Centering", Range(1.0, 5.0)) = 2.0
        _VRAspect ("VR OBS Aspect (16:9 -> 1.77)", Float) = 1.77
        [PowerSlider(2.0)] _VRScale ("VR Scale", Range(0.1, 5.0)) = 2.0
        [PowerSlider(10.0)] _VRDistCM ("VR Converge (cm)", Range(37, 10000)) = 1.0
        [ToggleUI]_ShowOnlyInHead("Show only inside head (head scale < 0.01)", Float) = 0
        [Enum(Always,0,VROnly,1,VROnlyLeftEye,2,VROnlyRightEye,3,DesktopOrLeftEyeVR,4,DesktopOrRightEyeVR,5,DesktopOnly,6)] _ShowOnlyVRType("Additional show condition", Float) = 6
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Overlay" "PreviewType"="Plane" }
        LOD 100
        ZTest Always
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float3 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _MainTex_TexelSize;
            sampler2D _RightEyeMainTex;
            float4 _RightEyeMainTex_TexelSize;

            float4 _Color;
            float4 _VRColor;

            float _CamOffsetX;
            float _CamOffsetY;
            float _CamScale;
            float _VRCenterFactor;
            float _VRAspect;
            float _VRDistCM;
            float _VRScale;
            static float2 camOffsetDesk = .5 + .5 * float2(_CamOffsetX, -_CamOffsetY);
#ifdef UNITY_SINGLE_PASS_STEREO
            static bool isInMirror = 0;
            static bool isDesktop = (distance(unity_StereoWorldSpaceCameraPos[0], unity_StereoWorldSpaceCameraPos[1]) == 0.0);
            static float2 camOffset = isDesktop ? camOffsetDesk : .5 + .5 * float2(_CamOffsetX, -_CamOffsetY) / _VRCenterFactor;
            //static float3 centerCameraPos = lerp(unity_StereoWorldSpaceCameraPos[0], unity_StereoWorldSpaceCameraPos[1], 0.5)
            //static float4x4 centerMatrix = lerp(unity_StereoCameraToWorld[0], unity_StereoCameraToWorld[1], 0.5);
#else
            static bool isInMirror = (unity_CameraProjection[2][0] != 0.f || unity_CameraProjection[2][1] != 0.f);
            static bool isDesktop = true;
            static float2 camOffset = camOffsetDesk;
            //static float4x4 mixedMatrix = (float4x4)0.0;
#endif
            static float2 camScale = float2(1,1) * _CamScale * (isDesktop ? 2.0 : _VRScale / sqrt(_VRCenterFactor));
            static float aspectAdjustVR = (isDesktop ? 1.0 : _VRAspect);

            static float2 relativeAspect = abs(_MainTex_ST.xy) * _MainTex_TexelSize.zw / _ScreenParams.xy;
            static float2 relativeAspectRatio = min(1.0, relativeAspect.xy / relativeAspect.yx);
            static float2 correctedScale = camScale * min(1.0, relativeAspectRatio);
            float _ShowOnlyInHead;
            float _ShowOnlyVRType;
            
            v2f vert (appdata v)
            {
                float2 screenEdge = float2(min(1,aspectAdjustVR),min(1,1/aspectAdjustVR)) - .5 * correctedScale;
                screenEdge = float2(
                    lerp(-screenEdge.x, screenEdge.x, camOffset.x),
                    lerp(-screenEdge.y, screenEdge.y, camOffset.y));
                float3x3 camera_offset = float3x3(correctedScale.x,0,screenEdge.x,0,correctedScale.y,screenEdge.y,0,0,1);

                v2f o;
                // float2 thisvertex = float2(v.vertex.x, -v.vertex.y);
                float2 thisvertex = float2(v.uv.x, 1.0 - v.uv.y) - 0.5;
                o.vertex = float4(mul(camera_offset, float3(thisvertex.xy, 1)), 0).xywz;
                if ((_ShowOnlyVRType == 0 || _ShowOnlyVRType == 1) && !isDesktop) {
#if defined(UNITY_SINGLE_PASS_STEREO)
                    float distanceMeters = _VRDistCM / 100.0;
                    // Bug: Vertices jump from the center of one eye to the center of the other eye. Not sure what causes that.

                    float4 projSpaceVert0 = mul(unity_StereoCameraProjection[0], float4(o.vertex.xyw, distanceMeters).xywz);
                    projSpaceVert0 = float4(o.vertex.xyw, projSpaceVert0.z * o.vertex.w / projSpaceVert0.w).xywz;
                    float4 viewSpaceVert0 = mul(unity_StereoCameraInvProjection[0], projSpaceVert0);
                    viewSpaceVert0 = float4(sign(o.vertex.xy) * float2(1,-1) * abs(viewSpaceVert0.xy/viewSpaceVert0.w), distanceMeters, 1.0);
                    float3 worldSpaceInVertex0 = mul(unity_StereoCameraToWorld[0], viewSpaceVert0).xyz;

                    float4 projSpaceVert1 = mul(unity_StereoCameraProjection[1], float4(o.vertex.xyw, distanceMeters).xywz);
                    projSpaceVert1 = float4(o.vertex.xyw, projSpaceVert1.z * o.vertex.w / projSpaceVert1.w).xywz;
                    float4 viewSpaceVert1 = mul(unity_StereoCameraInvProjection[1], projSpaceVert1);
                    viewSpaceVert1 = float4(sign(o.vertex.xy) * float2(1,-1) * abs(viewSpaceVert1.xy/viewSpaceVert1.w), distanceMeters, 1.0);
                    float3 worldSpaceInVertex1 = mul(unity_StereoCameraToWorld[1], viewSpaceVert1).xyz;

                    float3 worldSpaceVert = lerp(worldSpaceInVertex0, worldSpaceInVertex1, 0.5);
                    o.vertex = UnityWorldToClipPos(float4(worldSpaceVert, 1.0));
                    o.vertex.z = clamp(o.vertex.z, sign(o.vertex.z) > 0 ? -abs(o.vertex.w) : 0, sign(o.vertex.z) > 0 ? 0 : abs(o.vertex.w));
#endif
                }
                float4 hasData = tex2Dlod(_MainTex, float4(.5,.5,0,0)) +
                        tex2Dlod(_MainTex, float4(.51,.4,0,0)) + tex2Dlod(_MainTex, float4(.4,.51,0,0)) +
                        tex2Dlod(_MainTex, float4(.61,.61,0,0)) + tex2Dlod(_MainTex, float4(.3,.71,0,0));
                if (_ShowOnlyInHead > 0 && length(mul((float3x3)unity_ObjectToWorld, float3(0,0,1)).xyz) > 0.01) {
                    o.vertex = float4(1,1,1,1);
                }
                if (any(_MainTex_TexelSize.zw == _ScreenParams.xy)) {
                    o.vertex = float4(1,1,1,1);
                }
                if (all(hasData == 0) || any(_MainTex_TexelSize.zw < float2(64,64))) {
                    o.vertex = float4(1,1,1,1);
                }
                if (isInMirror) {
                    o.vertex = float4(1,1,1,1);
                }
#if defined(UNITY_SINGLE_PASS_STEREO)
                if ((_ShowOnlyVRType == 6 && !isDesktop) ||
                    ((_ShowOnlyVRType == 1|| _ShowOnlyVRType == 2 || _ShowOnlyVRType == 3) && isDesktop) ||
                    (_CamScale * _VRScale) > 1.5 ||
                    ((_ShowOnlyVRType == 2 || _ShowOnlyVRType == 4) && !isDesktop && unity_StereoEyeIndex != 0) ||
                    ((_ShowOnlyVRType == 3 || _ShowOnlyVRType == 5) && !isDesktop && unity_StereoEyeIndex != 1))
#else
                if (_ShowOnlyVRType == 1 || _ShowOnlyVRType == 2 || _ShowOnlyVRType == 3)
#endif
                {
                    o.vertex = float4(1,1,1,1);
                }
                o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv.z = 0.0;
                if (!isDesktop && !any(_RightEyeMainTex_TexelSize.zw < float2(64,64))) {
#if defined(UNITY_SINGLE_PASS_STEREO)
                    float4 hasRightEyeData = tex2Dlod(_RightEyeMainTex, float4(.5,.5,0,0)) +
                            tex2Dlod(_RightEyeMainTex, float4(.51,.4,0,0)) + tex2Dlod(_RightEyeMainTex, float4(.4,.51,0,0)) +
                            tex2Dlod(_RightEyeMainTex, float4(.61,.61,0,0)) + tex2Dlod(_RightEyeMainTex, float4(.3,.71,0,0));
                    if (!all(hasRightEyeData == 0) && unity_StereoEyeIndex == 1) {
                        o.uv.z = 1.0;
                    }
#endif
                }
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv.xy);
                if (i.uv.z > 0.5) {
                    col = tex2D(_RightEyeMainTex, i.uv.xy);
                }
                col *= (isDesktop ? _Color : _VRColor);
                return col;
            }
            ENDCG
        }
    }
}