#ifndef POI_MSDF
    #define POI_MSDF
    
    sampler2D _TextGlyphs; 
    float4 _TextGlyphs_ST; 
    float4 _TextGlyphs_TexelSize;
    float _TextFPSUV;
    float _TextTimeUV;
    float _TextPositionUV;
    float _TextPixelRange;
    
    float _TextFPSEnabled;
    float _TextPositionEnabled;
    float _TextTimeEnabled;
    
    
    float4 _TextFPSColor;
    half _TextFPSEmissionStrength;
    fixed4 _TextFPSPadding;
    half2 _TextFPSOffset;
    half2 _TextFPSScale;
    half _TextFPSRotation;
    
    fixed _TextPositionVertical;
    float4 _TextPositionColor;
    half _TextPositionEmissionStrength;
    fixed4 _TextPositionPadding;
    half2 _TextPositionOffset;
    half2 _TextPositionScale;
    half _TextPositionRotation;
    
    float4 _TextTimeColor;
    half _TextTimeEmissionStrength;
    fixed4 _TextTimePadding;
    half2 _TextTimeOffset;
    half2 _TextTimeScale;
    half _TextTimeRotation;
    
    #define glyphWidth 0.0625
    
    #define ASCII_LEFT_PARENTHESIS 40
    #define ASCII_RIGHT_PARENTHESIS 41
    #define ASCII_POSITIVE 43
    #define ASCII_PERIOD 46
    #define ASCII_NEGATIVE 45
    #define ASCII_COMMA 44
    #define ASCII_E 69
    #define ASCII_F 70
    #define ASCII_I 73
    #define ASCII_M 77
    #define ASCII_O 79
    #define ASCII_P 80
    #define ASCII_S 83
    #define ASCII_T 54
    #define ASCII_SEMICOLON 58
    
    float3 globalTextEmission;
    
    half2 getAsciiCoordinate(float index)
    {
        return half2((index - 1) / 16, 1 - ((floor(index / 16 - glyphWidth)) / 16));
    }
    
    float median(float r, float g, float b)
    {
        return max(min(r, g), min(max(r, g), b));
    }
    
    void ApplyPositionText(inout float4 albedo, float2 uv)
    {
        float3 cameraPos = clamp(getCameraPosition(), -999, 999);
        float3 absCameraPos = abs(cameraPos);
        float totalCharacters = 20;
        float positionArray[20];
        positionArray[0] = cameraPos.x >= 0 ? ASCII_NEGATIVE: ASCII_POSITIVE;
        positionArray[1] = floor((absCameraPos.x * .01) % 10) + 48;
        positionArray[2] = floor((absCameraPos.x * .1) % 10) + 48;
        positionArray[3] = floor(absCameraPos.x % 10) + 48;
        positionArray[4] = ASCII_PERIOD;
        positionArray[5] = floor((absCameraPos.x * 10) % 10) + 48;
        positionArray[6] = ASCII_COMMA;
        positionArray[7] = cameraPos.y >= 0 ? ASCII_NEGATIVE: ASCII_POSITIVE;
        positionArray[8] = floor((absCameraPos.y * .01) % 10) + 48;
        positionArray[9] = floor((absCameraPos.y * .1) % 10) + 48;
        positionArray[10] = floor(absCameraPos.y % 10) + 48;
        positionArray[11] = ASCII_PERIOD;
        positionArray[12] = floor((absCameraPos.y * 10) % 10) + 48;
        positionArray[13] = ASCII_COMMA;
        positionArray[14] = cameraPos.z >= 0 ? ASCII_NEGATIVE: ASCII_POSITIVE;
        positionArray[15] = floor((absCameraPos.z * .01) % 10) + 48;
        positionArray[16] = floor((absCameraPos.z * .1) % 10) + 48;
        positionArray[17] = floor(absCameraPos.z % 10) + 48;
        positionArray[18] = ASCII_PERIOD;
        positionArray[19] = floor((absCameraPos.z * 10) % 10) + 48;
        
        uv = TransformUV(_TextPositionOffset, _TextPositionRotation, _TextPositionScale, uv);
        
        if (uv.x > 1 || uv.x < 0 || uv.y > 1 || uv.y < 0)
        {
            return;
        }
        
        float currentCharacter = floor(uv.x * totalCharacters);
        half2 glyphPos = getAsciiCoordinate(positionArray[currentCharacter]);
        
        float2 startUV = float2(1 / totalCharacters * currentCharacter, 0);
        float2 endUV = float2(1 / totalCharacters * (currentCharacter + 1), 1);
        
        fixed4 textPositionPadding = _TextPositionPadding;
        textPositionPadding *= 1 / totalCharacters;
        uv = remapClamped(uv, startUV, endUV, float2(glyphPos.x + textPositionPadding.x, glyphPos.y - glyphWidth + textPositionPadding.y), float2(glyphPos.x + glyphWidth - textPositionPadding.z, glyphPos.y - textPositionPadding.w));
                
        if (uv.x > glyphPos.x + glyphWidth - textPositionPadding.z - .001 || uv.x < glyphPos.x + textPositionPadding.x + .001 || uv.y > glyphPos.y - textPositionPadding.w - .001 || uv.y < glyphPos.y - glyphWidth + textPositionPadding.y + .001)
        {
            return;
        }
        
        float3 samp = tex2D(_TextGlyphs, TRANSFORM_TEX(uv, _TextGlyphs)).rgb;
        float2 msdfUnit = _TextPixelRange / _TextGlyphs_TexelSize.zw;
        float sigDist = median(samp.r, samp.g, samp.b) - 0.5;
        sigDist *= max(dot(msdfUnit, 0.5 / fwidth(uv)), 1);
        float opacity = clamp(sigDist + 0.5, 0, 1);
        albedo.rgb = lerp(albedo.rgb, _TextPositionColor.rgb, opacity * _TextPositionColor.a);
        globalTextEmission += _TextPositionColor.rgb * opacity * _TextPositionEmissionStrength;
    }
    
    void ApplyTimeText(inout float4 albedo, float2 uv)
    {
        float instanceTime = _Time.y;
        float hours = instanceTime / 3600;
        float minutes = (instanceTime / 60) % 60;
        float seconds = instanceTime % 60;
        float totalCharacters = 8;
        float timeArray[8];
        timeArray[0] = floor((hours * .1) % 10) + 48;
        timeArray[1] = floor(hours % 10) + 48;
        timeArray[2] = ASCII_SEMICOLON;
        timeArray[3] = floor((minutes * .1) % 10) + 48;
        timeArray[4] = floor(minutes % 10) + 48;
        timeArray[5] = ASCII_SEMICOLON;
        timeArray[6] = floor((seconds * .1) % 10) + 48;
        timeArray[7] = floor(seconds % 10) + 48;
        
        uv = TransformUV(_TextTimeOffset, _TextTimeRotation, _TextTimeScale, uv);
        
        if(uv.x > 1 || uv.x < 0 || uv.y > 1 || uv.y < 0)
        {
            return;
        }
        
        float currentCharacter = floor(uv.x * totalCharacters);
        half2 glyphPos = getAsciiCoordinate(timeArray[currentCharacter]);
        // 0.1428571 = 1/7 = 1 / totalCharacters
        float startUV = 1 / totalCharacters * currentCharacter;
        float endUV = 1 / totalCharacters * (currentCharacter + 1);
        fixed4 textTimePadding = _TextTimePadding;
        textTimePadding *= 1 / totalCharacters;
        uv = remapClamped(uv, float2(startUV, 0), float2(endUV, 1), float2(glyphPos.x + textTimePadding.x, glyphPos.y - glyphWidth + textTimePadding.y), float2(glyphPos.x + glyphWidth - textTimePadding.z, glyphPos.y - textTimePadding.w));
        
        if (uv.x > glyphPos.x + glyphWidth - textTimePadding.z - .001 || uv.x < glyphPos.x + textTimePadding.x + .001 || uv.y > glyphPos.y - textTimePadding.w - .001 || uv.y < glyphPos.y - glyphWidth + textTimePadding.y + .001)
        {
            return;
        }

        float3 samp = tex2D(_TextGlyphs, TRANSFORM_TEX(uv, _TextGlyphs)).rgb;
        float2 msdfUnit = _TextPixelRange / _TextGlyphs_TexelSize.zw;
        float sigDist = median(samp.r, samp.g, samp.b) - 0.5;
        sigDist *= max(dot(msdfUnit, 0.5 / fwidth(uv)), 1);
        float opacity = clamp(sigDist + 0.5, 0, 1);
        albedo.rgb = lerp(albedo.rgb, _TextTimeColor.rgb, opacity * _TextTimeColor.a);
        globalTextEmission += _TextTimeColor.rgb * opacity * _TextTimeEmissionStrength;
    }
    
    void ApplyFPSText(inout float4 albedo, float2 uv)
    {
        float smoothDeltaTime = clamp(unity_DeltaTime.w, 0, 999);
        float totalCharacters = 7;
        float fpsArray[7];
        fpsArray[0] = ASCII_F;
        fpsArray[1] = ASCII_P;
        fpsArray[2] = ASCII_S;
        fpsArray[3] = ASCII_SEMICOLON;
        fpsArray[4] = floor((smoothDeltaTime * .01) % 10) + 48;
        fpsArray[5] = floor((smoothDeltaTime * .1) % 10) + 48;
        fpsArray[6] = floor(smoothDeltaTime % 10) + 48;
        
        uv = TransformUV(_TextFPSOffset, _TextFPSRotation, _TextFPSScale, uv);
        
        if(uv.x > 1 || uv.x < 0 || uv.y > 1 || uv.y < 0)
        {
            return;
        }
        
        float currentCharacter = floor(uv.x * totalCharacters);
        half2 glyphPos = getAsciiCoordinate(fpsArray[currentCharacter]);
        // 0.1428571 = 1/7 = 1 / totalCharacters
        float startUV = 1 / totalCharacters * currentCharacter;
        float endUV = 1 / totalCharacters * (currentCharacter + 1);

        fixed4 textFPSPadding = _TextFPSPadding;
        textFPSPadding *= 1 / totalCharacters;
        uv = remapClamped(uv, float2(startUV, 0), float2(endUV, 1), float2(glyphPos.x + textFPSPadding.x, glyphPos.y - glyphWidth + textFPSPadding.y), float2(glyphPos.x + glyphWidth - textFPSPadding.z, glyphPos.y - textFPSPadding.w));
        
        if (uv.x > glyphPos.x + glyphWidth - textFPSPadding.z - .001 || uv.x < glyphPos.x + textFPSPadding.x + .001 || uv.y > glyphPos.y - textFPSPadding.w - .001 || uv.y < glyphPos.y - glyphWidth + textFPSPadding.y + .001)
        {
            return;
        }
        
        float3 samp = tex2D(_TextGlyphs, TRANSFORM_TEX(uv, _TextGlyphs)).rgb;
        float2 msdfUnit = _TextPixelRange / _TextGlyphs_TexelSize.zw;
        float sigDist = median(samp.r, samp.g, samp.b) - 0.5;
        sigDist *= max(dot(msdfUnit, 0.5 / fwidth(uv)), 1);
        float opacity = clamp(sigDist + 0.5, 0, 1);
        albedo.rgb = lerp(albedo.rgb, _TextFPSColor.rgb, opacity * _TextFPSColor.a);
        globalTextEmission += _TextFPSColor.rgb * opacity * _TextFPSEmissionStrength;
    }
    
    void ApplyTextOverlayColor(inout float4 albedo, inout float3 textOverlayEmission)
    {
        globalTextEmission = 0;
        half positionalOpacity = 0;
        #ifdef EFFECT_BUMP
            UNITY_BRANCH
            if(_TextFPSEnabled)
            {
                ApplyFPSText(albedo, poiMesh.uv[_TextFPSUV]);
            }
            UNITY_BRANCH
            if(_TextPositionEnabled)
            {
                ApplyPositionText(albedo, poiMesh.uv[_TextPositionUV]);
            }
            UNITY_BRANCH
            if(_TextTimeEnabled)
            {
                ApplyTimeText(albedo, poiMesh.uv[_TextTimeUV]);
            }

            textOverlayEmission = globalTextEmission;
        #endif
    }
    
#endif