// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/Textures.gdshaderinc"

vec3 sampleRGB( sampler2D sampler, vec2 uv )
{
  return texture( sampler, uv ).rgb;
}

vec3 sampleRGB( sampler2D sampler, vec2 uv, vec4 tint )
{
  return texture( sampler, uv ).rgb * tint.rgb;
}

float sampleAlphaUnclamped( sampler2D opacitySampler, sampler2D albedoSampler, vec2 uv, vec4 albedo, float scale )
{
  float sampledOpacity = texture( opacitySampler, uv ).r;
  float sampledAlpha = texture( albedoSampler, uv ).a * albedo.a;

  return sampledOpacity * sampledAlpha * scale;
}

float sampleAlpha( sampler2D opacitySampler, sampler2D albedoSampler, vec2 uv, vec4 albedo, float scale )
{
  float alpha = sampleAlphaUnclamped( opacitySampler, albedoSampler, uv, albedo, scale );

  return clamp( alpha, 0, 1 );
}


float sampleRedUnclamped( sampler2D sampler, vec2 uv, float scale, float offset )
{
  float value = texture( sampler, uv ).r;

  return value * scale + offset;
}

float sampleRedBlurredUnclamped( sampler2D sampler, vec2 uv, float scale, float offset, float blur )
{
   float value = textureLod( sampler, uv, blur ).r;

  return value * scale + offset;
}

float sampleRed( sampler2D sampler, vec2 uv, float scale, float offset )
{
  float value = sampleRedUnclamped( sampler, uv, scale, offset );
  return clamp( value, 0, 1 );
}

vec3 sampleEmission( sampler2D sampler, vec2 uv, float emissionScale, vec4 emissionOffset )
{
  vec3 value = texture( sampler, uv ).rgb;

  return ( value + emissionOffset.rgb ) * emissionScale;
}

float sampleOcclusionUnclamped( sampler2D sampler, vec2 uv, float amount, float offset )
{
  float value = texture( sampler, uv ).r;
  return mix( 1, value, amount ) + offset;
}

float sampleOcclusion( sampler2D sampler, vec2 uv, float scale, float offset )
{
  float value = sampleOcclusionUnclamped( sampler, uv, scale, offset );
  return clamp( value, 0, 1 );
}



vec4 triplanarTexture( sampler2D sampler, vec3 weights, vec3 triplanerPosition )
{
  vec4 sample = vec4( 0.0 );

	sample += texture( sampler, triplanerPosition.xy ) * weights.z;
	sample += texture( sampler, triplanerPosition.xz ) * weights.y;
	sample += texture( sampler, triplanerPosition.zy * vec2( -1.0, 1.0 ) ) * weights.x;

	return sample;
}

vec2 heightMapUV( vec3 worldPosition, vec3 terrainSize, vec3 terrainOffset )
{
  vec3 inTerrain = worldPosition - terrainOffset;
  vec3 terrainUV = inTerrain / terrainSize;

  return vec2( terrainUV.x, terrainUV.z );
}

vec4 fromHeightMap( sampler2D sampler, vec3 worldPosition, vec3 terrainSize, vec3 terrainOffset )
{
  vec3 inTerrain = worldPosition - terrainOffset;
  vec3 terrainUV = inTerrain / terrainSize;

  return texture( sampler, vec2( terrainUV.x, terrainUV.z ) );
}

vec4 fromHeightMapSmoothed( sampler2D terrain, vec2 terrainUV, vec2 kernelSize, float weightSmoothing )
{
  vec4 output = vec4( 0, 0, 0, 0 );

  float sumW = 0.0;

  for ( int i = -1; i < 2; i++ ) 
  {
    for ( int j= -1; j < 2; j++ )
    { 
      vec2 offset = vec2( kernelSize.x * float(i), kernelSize.y * float(j) );
      float w = 1.0 / ( weightSmoothing + length( offset ) );
      output += texture( terrain, terrainUV + offset ) * w; 

      sumW += w;
    }
  }

  return output / sumW;
}


vec3 heightMapDirection( sampler2D terrain, vec2 terrainUV, vec2 kernelSize, float normalScale )
{
  float hL = texture( terrain, terrainUV - vec2( kernelSize.x, 0 ) ).r * normalScale;
  float hR = texture( terrain, terrainUV + vec2( kernelSize.x, 0 ) ).r * normalScale;
  float hD = texture( terrain, terrainUV - vec2( 0, kernelSize.y ) ).r * normalScale;
  float hU = texture( terrain, terrainUV + vec2( 0, kernelSize.y ) ).r * normalScale;

  return vec3( hL - hR, 2.0, hD - hU );
}

vec3 heightMapNormal( sampler2D terrain, vec2 terrainUV, vec2 kernelSize, float normalScale )
{
  return normalize( heightMapDirection( terrain, terrainUV, kernelSize, normalScale ) );
}

vec3 heightMapNormalSmoothed( sampler2D terrain, vec2 terrainUV, vec2 kernelSize, float normalScale, float kernelSpread )
{
  vec3 n0 = heightMapDirection( terrain, terrainUV, kernelSize, normalScale ); 
  vec3 n1 = heightMapDirection( terrain, terrainUV, kernelSize * kernelSpread, normalScale ) * 0.5;
  vec3 n2 = heightMapDirection( terrain, terrainUV, kernelSize * kernelSpread * kernelSpread, normalScale ) * 0.25;

  return normalize( n0 + n1 + n2 );
}

vec2 tilingOffset( vec2 uv, vec2 scale, vec2 offset )
{
  return uv * scale + offset;
}