﻿// license: may not be redistributed, except for in your own avatars or worlds
// made by: luka[#]8375, zoey "luka" moon, luka.moe lukasong.booth.pm lukasong.gumroad.com github.com/lukasong lukazoeysong[@]gmail.com
Shader "luka/safespace/SS_Dome"
{
    Properties
    {
        // texture settings
        [Header(Main Texture Stuffs)]
        _MainTex ("Texture", 2D) = "white" {}
        [HideInInspector] _BlackIsAlpha ("Black is Alpha", Range(0,1)) = 0
    	[HideInInspector] _Clip ("Clip", Range(0, 1)) = 0
        _TexScale ("Texture Scale", Range(0, 100)) = 10
        _TexRotate ("Texture Rotation", Range(-360, 360)) = 0
        _TexRotateSpeed ("Texture Rotation Speed", Range(-10, 10)) = 0
        // [Enum(Yes, 0, No, 1)] _TexFixOnHemisphere ("Texture Fix on Hemisphere", Range(0, 1)) = 0
        _TexShiftX ("Texture Shift X", Range(-1, 1)) = 0
        _TexShiftY ("Texture Shift Y", Range(-1, 1)) = 0
        [Enum(No, 0, Yes, 1)] _FlipRows ("Flip based on rows?", Range(0, 1)) = 0
        // spritesheet settings
        [Header(Spritesheet Stuffs)]
        [Enum(No, 0, Yes, 1)] _UseSpritesheet ("Use Spritesheet", Range(0,1)) = 0
        _Columns ("Columns", Range(0, 32)) = 8
        _Rows ("Rows", Range(0, 32)) = 1
        _Frames ("Frames", Range(0, 128)) = 8
        _UpdateRate ("Update Rate", Range(0, 10)) = 0.15
        // bubble settings
        [Header(Bubble Settings)]
        [Enum(No, 0, Yes, 1)] _Bubbles ("Bubbles", Range(0,1)) = 0
        _BubbleOpacity ("Bubble Opacity", Range(0, 1)) = 0.5
        _BubblesThreshold ("Bubbles Threshold", Range(0, 1)) = 0.2
        _BubbleColor ("Bubble Color", Color) = (0, 0.85, 0.81, 1)
        // color settings
        [Header(Color Stuffs)]
        _Color ("Color", Color) = (1, 1, 1, 0)
        _Rainbow ("Use rainbows?", Range(0,1)) = 0
        _RainbowSpeed ("Rainbow speed", Float) = 0.01
        [Enum(No, 0, Yes, 1)] _UseLowColor ("Use Low Color", Range(0,1)) = 0
        _LowColor ("Low Color", Color) = (0, 0, 0, 1)
        // movement settings
        [Header(Movement Stuffs)]
        [Enum(Disabled, 0, ScrollTex, 1, ScrollAlpha, 2, ScrollBoth, 3)] _Scroll ("Scroll", Float) = 0
        _ScrollSpeed ("Scroll Speed", Vector) = (0,0,0,0)
        _ScrollScale ("Scroll Scale", Float) = 3
        _ScrollAmount ("Scroll Amount", Range(0, 1)) = 0.3
        // distance settings
        [Header(Distance Stuffs)]
        _DistanceCutoff ("Distance Cutoff", Float) = 20
        // actual distance settings
        [Header(Actual Distance Stuffs)]
        [Enum(No, 0, Yes, 1)] _UseRealDistance ("Use Real Distance", Range(0,1)) = 0
        _Distance ("Distance", Float) = 0.5
        [Enum(No, 0, Yes, 1)] _ReverseDistance ("Reverse Distance", Range(0,1)) = 0
        // advanced settings
        [Header(Advanced Stuffs)]
        [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Int) = 2
        _StencilRef ("Stencil Ref", Int) = 34
        _NoPatternMode ("No Pattern Mode", Range(0, 1)) = 0
        // vrchat fallback so hidden shaders dont see ugly sphere
		[HideInInspector] _Alpha ("Alpha", Range(0, 1)) = 0
		[HideInInspector] _Transparency ("Transparency", Range(0, 1)) = 0
    }
    SubShader
    {

        Tags { "RenderType"="Transparent" "Queue"="Transparent+1000" "VRCFallback" = "Hidden" "ForceNoShadowCasting" = "True" }
        Blend SrcAlpha OneMinusSrcAlpha
        Cull [_CullMode]

        // catch the rewrite before it hits the skybox
        Stencil { Ref [_StencilRef] Comp NotEqual Pass Keep Fail Keep ZFail Keep }

        Pass
        {
            CGPROGRAM
            #pragma vertex phys
            #pragma fragment pixel
            #include "UnityCG.cginc"

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

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float2 og : TEXCOORD1;
                float dist : TEXCOORD2;
                float dist2 : TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _TexScale, _TexRotate, _TexRotateSpeed;
            float _UseRealDistance, _Distance, _ReverseDistance;
            float _TexFixOnHemisphere;
            float _FlipRows;

            float2 rotuvs(float2 UV, float2 Center, float Rotation)
            {
                // attribution: unity
                Rotation = Rotation * (3.1415926f/180.0f);
                UV -= Center;
                float s = sin(Rotation);
                float c = cos(Rotation);
                float2x2 rMatrix = float2x2(c, -s, s, c);
                rMatrix *= 0.5;
                rMatrix += 0.5;
                rMatrix = rMatrix * 2 - 1;
                UV.xy = mul(UV.xy, rMatrix);
                UV += Center;
                return UV;
            }

            float _TexShiftX, _TexShiftY;

            float3 getCamera() {
	            #if UNITY_SINGLE_PASS_STEREO
                    return (unity_StereoWorldSpaceCameraPos[0] + unity_StereoWorldSpaceCameraPos[1]) * 0.5;
                #else
                    return _WorldSpaceCameraPos;
                #endif
            }

            float getDistance() {
                // getting a basic distance away from the center of the object 
                return float(distance(getCamera(), mul(unity_ObjectToWorld, float4(0, 0, 0, 1))));
            }

            v2f phys (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.uv.x += _TexShiftX;
                o.uv.y += _TexShiftY;
                [branch] if (_TexRotateSpeed != 0) _TexRotate += (_Time.y * _TexRotateSpeed);
                [branch] if (_TexRotate != 0) o.uv.xy = rotuvs(o.uv.xy, 0.5, _TexRotate);
                o.og = o.uv;
                o.uv.xy *= _TexScale;
                o.dist = getDistance();
                [branch] if (_UseRealDistance == 1) {
                    float3 viewDirW = _WorldSpaceCameraPos - mul((half4x4)unity_ObjectToWorld, v.vertex);
                    [branch] if (_ReverseDistance == 1) {
                        viewDirW = pow(viewDirW, 10);
                        o.dist2 = 1.0 - (1.0 - saturate(length(viewDirW) / _Distance));
                    }  else {
                        o.dist2 = (1.0 - saturate(length(viewDirW) / _Distance));
                    }
                } else {
                    o.dist2 = 1;
                }
                return o;
            }

            float _Scroll, _ScrollScale, _ScrollAmount;
            float _Bubbles, _BubbleOpacity, _BubblesThreshold;
            float _DistanceCutoff;
            float _Rainbow, _RainbowSpeed;
            float4 _ScrollSpeed;
            float4 _Color, _BubbleColor;
            float _UseSpritesheet, _Columns, _Rows, _Frames, _UpdateRate;


            inline float unity_noise_randomValue (float2 uv)
            {
                return frac(sin(dot(uv, float2(12.9898, 78.233)))*43758.5453);
            }

            inline float unity_noise_interpolate (float a, float b, float t)
            {
                return (1.0-t)*a + (t*b);
            }

            inline float unity_valueNoise (float2 uv)
            {
                float2 i = floor(uv);
                float2 f = frac(uv);
                f = f * f * (3.0 - 2.0 * f);

                uv = abs(frac(uv) - 0.5);
                float2 c0 = i + float2(0.0, 0.0);
                float2 c1 = i + float2(1.0, 0.0);
                float2 c2 = i + float2(0.0, 1.0);
                float2 c3 = i + float2(1.0, 1.0);
                float r0 = unity_noise_randomValue(c0);
                float r1 = unity_noise_randomValue(c1);
                float r2 = unity_noise_randomValue(c2);
                float r3 = unity_noise_randomValue(c3);

                float bottomOfGrid = unity_noise_interpolate(r0, r1, f.x);
                float topOfGrid = unity_noise_interpolate(r2, r3, f.x);
                float t = unity_noise_interpolate(bottomOfGrid, topOfGrid, f.y);
                return t;
            }

            float Unity_SimpleNoise_float(float2 UV, float Scale)
            {
                float t = 0.0;

                float freq = pow(2.0, float(0));
                float amp = pow(0.5, float(3-0));
                t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;

                freq = pow(2.0, float(1));
                amp = pow(0.5, float(3-1));
                t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;

                freq = pow(2.0, float(2));
                amp = pow(0.5, float(3-2));
                t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;

                return t;
            }

            float rand(float2 seed) {
                return frac(sin(dot(seed.xy, float2(12.9898, 78.233))) * 43758.5453);
            }

            void pix(inout float2 inputUVs,
                float inputPixelateX, float inputPixelateY) {
                float2 pixelateValues = ceil(abs(float2(inputPixelateX, inputPixelateY)));
                inputUVs = (floor((pixelateValues * inputUVs)) / pixelateValues);
            }

            float3 doCsSmoothHSVtoRGB(float3 c) {
                // smoothly converting from hsv color space to rgb color space
                // attribution: inigo quilez
                float3 rgb = clamp(abs(fmod(c.x * 6.0 + float3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
                rgb = rgb * rgb * (3.0 - 2.0 * rgb);
                return c.z * lerp(float3(1.0, 1.0, 1.0), rgb, c.y);
            }

            float3 makeRainbowFancy(float2 inputUVs, 
                float inputTime, float inputToggleY, 
                float inputToggleX, float inputHue, 
                float inputSat, float inputLight) {
                // faaaancy rainbow with hsv to rgb conversion
                float hueMod = _Time.y * inputTime;
                hueMod += (inputUVs.y * inputToggleY);
                hueMod += (inputUVs.x * inputToggleX);
                hueMod = (inputTime != 0) ? hueMod * inputHue : hueMod + inputHue;
                return float3(doCsSmoothHSVtoRGB(float3(hueMod, inputSat, inputLight)));
            }

            float2 makeSpritesheet(float inputColumns, 
                float inputRows, float inputTotal, 
                float inputSpeed, int inputCurrent, 
                float2 inputUVs) {
                // transforms the current uv into a frame of a spritesheet
                inputCurrent += (frac(inputSpeed * _Time.y) * inputTotal);
                inputCurrent = clamp(inputCurrent, 0, inputTotal);
                inputCurrent = fmod(inputCurrent, inputColumns * inputRows);
                float2 inputCurrentCount = float2(1.0, 1.0) / float2(inputColumns, inputRows);
                float inputCurrentY = abs(inputRows - (floor(inputCurrent * inputCurrentCount.x) + 1));
                float inputCurrentX = abs(0 * inputColumns - ((inputCurrent - inputColumns * floor(inputCurrent * inputCurrentCount.x))));
                return float2((inputUVs + float2(inputCurrentX, inputCurrentY)) * inputCurrentCount);
            }

            float _UseLowColor; float4 _LowColor;
            float _NoPatternMode;

            fixed4 pixel (v2f i) : SV_Target
            {
                [branch] if (_UseSpritesheet == 1) {
                    float randOffset = rand(floor(i.og.xy * _TexScale));
                    i.uv.xy = makeSpritesheet(_Columns, _Rows, _Frames, _UpdateRate, randOffset, i.uv.xy);
                }
                [branch] if (_FlipRows == 1) {
                    float flipVal = floor(i.og.x * _TexScale);
                    i.uv.y = (flipVal % 2 == 0) ? i.uv.y : 1 - i.uv.y;
                }
                fixed4 col = tex2D(_MainTex, i.uv);
                [forcecase] switch (_Scroll) {
                    case 1: // scroll image
                        float2 scrollUv = i.uv;
                        scrollUv = frac(scrollUv + (_ScrollSpeed.xy * _Time.y));
                        col.rgba = tex2D(_MainTex, scrollUv).rgba;
                        break;
                    case 2: // scroll alpha
                        float2 noiseGrid = i.og.xy;
                        pix(noiseGrid, _TexScale, _TexScale);
                        noiseGrid.xy += (_ScrollSpeed.xy * _Time.y);
                        float noiseVal = Unity_SimpleNoise_float(noiseGrid, _ScrollScale);
                        noiseVal = (noiseVal * 2.0) * step(noiseVal, _ScrollAmount);
                        col.a *= noiseVal;
                        break;
                    case 3: // scroll both
                        float2 bothUVs[2];
                        bothUVs[0] = i.uv;
                        bothUVs[0] = frac(bothUVs[0] + (_ScrollSpeed.xy * _Time.y));
                        col.rgba = tex2D(_MainTex, bothUVs[0]).rgba;
                        bothUVs[1] = i.og.xy;
                        bothUVs[1].xy = frac(bothUVs[1] + (_ScrollSpeed.xy * _Time.y));
                        pix(bothUVs[1], _TexScale, _TexScale);
                        bothUVs[1].xy += (_ScrollSpeed.xy * _Time.y);
                        float noiseVal2 = Unity_SimpleNoise_float(bothUVs[1], _ScrollScale);
                        noiseVal2 = (noiseVal2 * 2.0) * step(noiseVal2, _ScrollAmount);
                        col.a *= noiseVal2; 
                        break;
                    default: // nothing
                        break;
                }
                col.rgb *= _Color.rgb;
                [branch] if (_Rainbow != 0) {
                    float2 rainbowUvs = floor(i.og.xy * _TexScale);
                    float3 rainbowColor = makeRainbowFancy(rainbowUvs, _RainbowSpeed, 0, 0, rand(rainbowUvs), 1, 1);
                    col.rgb = lerp(col.rgb, rainbowColor, _Rainbow);
                }
                [branch] if (_UseLowColor == 1) {
                    float2 noiseGrid = i.og.xy;
                    pix(noiseGrid, _TexScale, _TexScale);
                    noiseGrid.xy += (_ScrollSpeed.xy * _Time.y) * 0.5;
                    float noiseVal = Unity_SimpleNoise_float(noiseGrid, _ScrollScale);
                    col.rgb = lerp(col.rgb, _LowColor.rgb, (noiseVal));
                }
                [branch] if (_Bubbles == 1) {
                    if (col.a <= _BubblesThreshold) {
                        col.rgb = _BubbleColor.rgb;
                        col.a = _BubbleOpacity;
                    }
                }
                [branch] if (_DistanceCutoff != 0) {
                    if (i.dist >= _DistanceCutoff) col.a = 0;
                }
                col.a *= i.dist2;
                [branch] if (_NoPatternMode == 1) {
                    col.rgba = float4(0, 0, 0, 0);
                }
                return col;
            }
            ENDCG
        }
    }
	// UNITY_SHADER_NO_UPGRADE
	FallBack "Diffuse"
}

//
//       ...    
//     .::'     
//    :::            luka song
//    :::    zoey, princess of the moon
//    `::.     
//      `':..  
//