// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
// This code in no way belongs to BrainFailProductions. I have just made a small change to make
// it work with texture arrays


#ifndef UNITY_STANDARD_INPUT_INCLUDED
#define UNITY_STANDARD_INPUT_INCLUDED

#include "UnityCG.cginc"
#include "Includes/BatchFewStandardConfig.cginc"
#include "UnityPBSLighting.cginc" // TBD: remove
#include "Includes/BatchFewStandardUtils.cginc"

//---------------------------------------
// Directional lightmaps & Parallax require tangent space too
#if (_NORMALMAP || DIRLIGHTMAP_COMBINED || defined(_PARALLAXMAP) || defined(_POM))
    #define _TANGENT_TO_WORLD 1
#endif

#if (_DETAIL_MULX2 || _DETAIL_MUL || _DETAIL_ADD || _DETAIL_LERP)
    #define _DETAIL 1
#endif

//---------------------------------------
half        _Cutoff;

UNITY_DECLARE_TEX2DARRAY(_MainTex);
float4      _MainTex_ST;

sampler2D _AttrImg;
float4    _AttrImg_TexelSize;

UNITY_DECLARE_TEX2DARRAY(_DetailAlbedoMap);
float4      _DetailAlbedoMap_ST;

UNITY_DECLARE_TEX2DARRAY(_BumpMap);

UNITY_DECLARE_TEX2DARRAY(_DetailMask);
UNITY_DECLARE_TEX2DARRAY(_DetailNormalMap);

UNITY_DECLARE_TEX2DARRAY(_SpecGlossMap);
UNITY_DECLARE_TEX2DARRAY(_MetallicGlossMap);

UNITY_DECLARE_TEX2DARRAY(_OcclusionMap);

UNITY_DECLARE_TEX2DARRAY(_ParallaxMap);
half        _Parallax;
half        _UVSec;

UNITY_DECLARE_TEX2DARRAY(_EmissionMap);

sampler2D _DetailAlbedoSingle;
sampler2D _DetailNormalSingle;

//-------------------------------------------------------------------------------------
// Input functions

struct VertexInput
{
    float4 vertex   : POSITION;
    half4 color     : COLOR;
    half3 normal    : NORMAL;
    float4 uv0      : TEXCOORD0;
    float2 uv1      : TEXCOORD1;
#if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META)
    float2 uv2      : TEXCOORD2;
#endif
#ifdef _TANGENT_TO_WORLD
    half4 tangent   : TANGENT;
#endif
    UNITY_VERTEX_INPUT_INSTANCE_ID

};

float4 SampleAttrImg(float prop, float index)
{
   return tex2Dlod(_AttrImg, float4((prop + 0.5) * _AttrImg_TexelSize.x, (index + 0.5) * _AttrImg_TexelSize.y, 0, 0));
}

float4 TexCoords(VertexInput v)
{
    
    float4 uvScaleOffset = SampleAttrImg(0, v.color.r * 255);

    float4 texcoord;
    texcoord.z = v.color.a * 255;
    texcoord.w = v.color.r * 255;
    texcoord.xy = v.uv0.xy * (uvScaleOffset.xy+1) + uvScaleOffset.zw;

    return texcoord;
}

half DetailMask(float3 uv)
{
    return UNITY_SAMPLE_TEX2DARRAY(_DetailMask, uv).a;
}


half3 Albedo(float4 texcoords, half4 attribs)
{
    half3 albedo = UNITY_SAMPLE_TEX2DARRAY (_MainTex, texcoords.xyz).rgb * SampleAttrImg(2, texcoords.w).rgb;
#if _DETAIL
    #if (SHADER_TARGET < 30)
        // SM20: instruction count limitation
        // SM20: no detail mask
        half mask = 1;
    #else
        half mask = DetailMask(texcoords);
    #endif
    //float4 uvmod = SampleAttrImg(5, texcoords.w);
    texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
    half3 detailAlbedo = UNITY_SAMPLE_TEX2DARRAY (_DetailAlbedoMap, texcoords.xyz).rgb;
    #if _DETAIL_MULX2
        albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask);
    #elif _DETAIL_MUL
        albedo *= LerpWhiteTo (detailAlbedo, mask);
    #elif _DETAIL_ADD
        albedo += detailAlbedo * mask;
    #elif _DETAIL_LERP
        albedo = lerp (albedo, detailAlbedo, mask);
    #endif
#elif _DETAIL_SINGLE
   #if (SHADER_TARGET < 30)
        // SM20: instruction count limitation
        // SM20: no detail mask
        half mask = 1;
    #else
        half mask = DetailMask(texcoords);
    #endif

    //float4 uvmod = SampleAttrImg(5, texcoords.w);
    
    texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
    half3 detailAlbedo = tex2D (_DetailAlbedoSingle, texcoords.xy).rgb;
    albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask);

#endif
    return albedo;
}

half Alpha(float4 uv)
{
    return UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a;
}

half Occlusion(float4 uv, half4 attribs)
{
      return UNITY_SAMPLE_TEX2DARRAY(_OcclusionMap, uv.xyz).g * attribs.y;
}

half4 SpecularGloss(float4 uv, half4 attribs)
{
   half4 sg = attribs.wwzz;
   #ifdef _SPECGLOSSMAP
       #if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A)
           sg.rgb = UNITY_SAMPLE_TEX2DARRAY(_SpecGlossMap, uv.xyz).rgb;
           sg.a = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a * attribs.z;
       #else
           sg = UNITY_SAMPLE_TEX2DARRAY(_SpecGlossMap, uv.xyz);
       #endif
       sg.a *= SampleAttrImg(4, uv.w).a;
   #else
       sg.rgb = SampleAttrImg(4, uv.w).rgb;
       #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
          sg.a = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a * attribs.z;
       #else
          sg.a = SampleAttrImg(1, uv.w).b;
       #endif
   #endif

   return sg;
}


half2 MetallicGloss(float4 uv, half4 attribs)
{
    half2 mg = attribs.wz;

    #ifdef _METALLICGLOSSMAP
        #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
            mg.r = UNITY_SAMPLE_TEX2DARRAY(_MetallicGlossMap, uv.xyz).r;
            mg.g = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a * attribs.z;
        #else
            mg = UNITY_SAMPLE_TEX2DARRAY(_MetallicGlossMap, uv.xyz).ra;
            mg.g *= attribs.z;
        #endif
    #else
        mg.r = attribs.w;
        #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
            mg.g = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a;
        #else
            mg.g = attribs.z;
        #endif
    #endif

    return mg;
}

half3 Emission(float4 uv)
{
#if _EMISSION
    return UNITY_SAMPLE_TEX2DARRAY(_EmissionMap, uv.xyz).rgb;
#endif
#if _EMISSION_COLOR
    return SampleAttrImg(3, uv.w).xyz;
#endif
return half3(0,0,0);
}

#ifdef _NORMALMAP
half3 NormalInTangentSpace(float4 texcoords, half4 attribs)
{
    half3 normalTangent = UnpackScaleNormal(UNITY_SAMPLE_TEX2DARRAY (_BumpMap, texcoords.xyz), attribs.r);

#if _DETAIL && defined(UNITY_ENABLE_DETAIL_NORMALMAP)
    half mask = DetailMask(texcoords);
        
    texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
    half3 detailNormalTangent = UnpackScaleNormal(UNITY_SAMPLE_TEX2DARRAY (_DetailNormalMap, texcoords.xyz), SampleAttrImg(6, texcoords.w).r);
    #if _DETAIL_LERP
        normalTangent = lerp(
            normalTangent,
            detailNormalTangent,
            mask);
    #else
        normalTangent = lerp(
            normalTangent,
            BlendNormals(normalTangent, detailNormalTangent),
            mask);
    #endif
#endif

#if _DETAIL_SINGLE && defined(UNITY_ENABLE_DETAIL_NORMALMAP)
    half mask = DetailMask(texcoords);
    //float uvmod = SampleAttrImg(5, texcoords.w);
    texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
    half3 detailNormalTangent = UnpackScaleNormal(tex2D (_DetailNormalSingle, texcoords.xy), SampleAttrImg(6, texcoords.w).r);
    #if _DETAIL_LERP
        normalTangent = lerp(
            normalTangent,
            detailNormalTangent,
            mask);
    #else
        normalTangent = lerp(
            normalTangent,
            BlendNormals(normalTangent, detailNormalTangent),
            mask);
    #endif
#endif

    return normalTangent;
}
#endif


#if (UNITY_VERSION >= 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (SHADER_TARGET_SURFACE_ANALYSIS && !SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))) || (UNITY_VERSION < 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL))) 
  #define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) tex.SampleGrad (sampler##tex,coord,dx,dy)
#elif defined(SHADER_API_D3D9)
  #define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(0,1,0,0) 
#elif defined(UNITY_COMPILER_HLSL2GLSL) || defined(SHADER_TARGET_SURFACE_ANALYSIS)
  #define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) texCUBEgrad (tex,coord,float3(dx.x,dx.y,0),float3(dy.x,dy.y,0))
#elif defined(SHADER_API_GLES)
  #define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(1,1,0,0)
#elif defined(SHADER_API_D3D11_9X)
  #define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(0,1,1,0) 
#else
  #define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(0,0,1,0) 
#endif


#if (UNITY_VERSION >= 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (SHADER_TARGET_SURFACE_ANALYSIS && !SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))) || (UNITY_VERSION < 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL))) 
     #define BATCHFEW_SAMPLE_TEX2D_LOD(tex,coord, lod) tex.SampleLevel (sampler##tex,coord, lod)
     #define BATCHFEW_SAMPLE_TEX2D_SAMPLER_LOD(tex,samplertex,coord, lod) tex.SampleLevel (sampler##samplertex,coord, lod)
#else
     #define BATCHFEW_SAMPLE_TEX2D_LOD(tex,coord,lod) tex2D (tex,coord,0,lod)
     #define BATCHFEW_SAMPLE_TEX2D_SAMPLER_LOD(tex,samplertex,coord,lod) tex2D (tex,coord,0,lod)
#endif


float ComputeMipLevel(float2 uv, float2 textureSize)
{
   uv *= textureSize;
   float2  dx_vtc        = ddx(uv);
   float2  dy_vtc        = ddy(uv);
   float delta_max_sqr   = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
   return 0.5 * log2(delta_max_sqr);
}

int _ParallaxSteps;

float4 _ParallaxMap_TexelSize;

inline float2 POM( float2 uvs,
                   float3 normalWorld, float3 viewWorld, float3 viewDirTan, 
                   float parallax, float texIndex)
{
   float curvFix = 1.0;

   float2 curv = float2(0, 0);
   float refPlane = 0;

   float3 result = 0;
   int stepIndex = 0;
   //int numSteps = ( int )lerp( maxSamples, minSamples, dot( normalWorld, viewWorld ) );
   int numSteps = _ParallaxSteps; // artifacts when using variable step slope above
   float layerHeight = 1.0 / numSteps;
   float2 plane = parallax * ( viewDirTan.xy / viewDirTan.z );
   uvs += refPlane * plane;
   float2 deltaTex = -plane * layerHeight;
   float2 prevTexOffset = 0;
   float prevRayZ = 1.0f;
   float prevHeight = 0.0f;
   float2 currTexOffset = deltaTex;
   float currRayZ = 1.0f - layerHeight;
   float currHeight = 0.0f;
   float intersection = 0;
   float2 finalTexOffset = 0;
   float mipLevel = ComputeMipLevel(uvs, _ParallaxMap_TexelSize.zw);


   while ( stepIndex < numSteps + 1 )
   {
      result.z = dot( curv, currTexOffset * currTexOffset );

      currHeight = BATCHFEW_SAMPLE_TEX2D_LOD(_ParallaxMap, float3(uvs + currTexOffset, texIndex), mipLevel ).r * ( 1 - result.z );

      if ( currHeight > currRayZ )
      {
         stepIndex = numSteps + 1;
      }
      else
      {
         stepIndex++;
         prevTexOffset = currTexOffset;
         prevRayZ = currRayZ;
         prevHeight = currHeight;
         currTexOffset += deltaTex;
         currRayZ -= layerHeight * ( 1 - result.z ) * (1+curvFix);
      }
   }
   int sectionSteps = 10;
   int sectionIndex = 0;
   float newZ = 0;
   float newHeight = 0;
   while ( sectionIndex < sectionSteps )
   {
      intersection = ( prevHeight - prevRayZ ) / ( prevHeight - currHeight + currRayZ - prevRayZ );
      finalTexOffset = prevTexOffset + intersection * deltaTex;
      newZ = prevRayZ - intersection * layerHeight;

      newHeight = BATCHFEW_SAMPLE_TEX2D_LOD(_ParallaxMap, float3(uvs + finalTexOffset, texIndex), mipLevel ).r * ( 1 - result.z );
      

      if ( newHeight > newZ )
      {
         currTexOffset = finalTexOffset;
         currHeight = newHeight;
         currRayZ = newZ;
         deltaTex = intersection * deltaTex;
         layerHeight = intersection * layerHeight;
      }
      else
      {
         prevTexOffset = finalTexOffset;
         prevHeight = newHeight;
         prevRayZ = newZ;
         deltaTex = ( 1 - intersection ) * deltaTex;
         layerHeight = ( 1 - intersection ) * layerHeight;
      }
      sectionIndex++;
   }
   #ifdef UNITY_PASS_SHADOWCASTER
   if ( unity_LightShadowBias.z == 0.0 )
   {
   #endif
      if ( result.z > 1 )
         clip( -1 );
   #ifdef UNITY_PASS_SHADOWCASTER
   }
   #endif
   return uvs + finalTexOffset;
}


float4 Parallax (float4 texcoords, half3 i_viewDirForParallax, float3 i_eyeVec, float4 tangentToWorld[3])
{
#if defined(_PARALLAXMAP)

    half h = UNITY_SAMPLE_TEX2DARRAY (_ParallaxMap, texcoords.xyz).g;
    
    float2 offset = ParallaxOffset1Step (h, SampleAttrImg(6, texcoords.w).b, i_viewDirForParallax);
    return float4(texcoords.xy + offset, texcoords.zw);
#endif
#if defined(_POM)
    float parallax = SampleAttrImg(6, texcoords.w).b;
    half3 normal = (0,0,1);


    half3 worldNormal = half3(dot(tangentToWorld[0], normal), dot(tangentToWorld[1],normal), dot(tangentToWorld[2],normal));

    float2 offset = POM(texcoords.xy, worldNormal, i_eyeVec, i_viewDirForParallax, parallax, texcoords.z); 
    return float4(offset, texcoords.zw);
#endif
return texcoords;
}


#endif // UNITY_STANDARD_INPUT_INCLUDED