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

group_uniforms Albedo; 
uniform bool enabled = true;
uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_linear_mipmap_anisotropic;
uniform vec3 hslOffset = vec3( 0, 0, 0 );
uniform sampler2D texture_blend : source_color,hint_default_white, filter_linear_mipmap_anisotropic; 
uniform float blendAmount:hint_range(0, 1) =1;
// uniform float grow:hint_range(-0.01, 0.01, 0.0001) = 00;

uniform float naturalColors: hint_range(0, 1) = 0.5;

uniform sampler2D texture_opacity:hint_default_white, filter_linear_mipmap_anisotropic; 
uniform float opacity: hint_range(0, 1) = 0.5;
uniform float opacityGamma = 1;

#ifdef USE_SHADOW
uniform float opacityFarScale: hint_range(0, 1) = 0.4;

uniform float opacityBlur : hint_range(0, 10) = 4;
uniform float opacityBlurFarScale : hint_range(0, 10) = 8;


uniform float opacityFarStart = 0.5;
uniform float opacityFarRange = 5;
uniform float opacityFarPower = 0.5;
uniform float extending = 0.001; 

#endif

#ifdef USE_ALPHA_SCISSOR
uniform float alphaScissorTreshold:hint_range(0,1) = 0.5;
#endif

#ifdef USE_ALPHA_DISCARD
uniform float alphaDiscardTreshold:hint_range(0,1) = 0.05;
#endif

group_uniforms;

group_uniforms HairMaps;
uniform sampler2D rootMap : filter_linear_mipmap_anisotropic;
uniform sampler2D flowMap : filter_linear_mipmap_anisotropic;
uniform sampler2D idMap : filter_linear_mipmap_anisotropic;
group_uniforms;

group_uniforms MainColors;
uniform float diffuseStrength:hint_range(0.0, 1.0) = 1;
uniform float vertexColorStrength:hint_range(0.0, 1.0) = 1;
uniform vec4 vertexGreyToColor:source_color;

uniform bool activateHairColor = true;

uniform float baseColorMapStrength:hint_range(0.0, 1.0) = 1;

uniform vec4 strandRootColor:source_color;
uniform float strandRootStrength:hint_range(0.0, 1.0) = 1;

uniform vec4 strandEndColor:source_color;
uniform float strandEndStrength:hint_range(0.0, 1.0) = 1;

uniform float strandGamma = 1.0;
group_uniforms;

group_uniforms Highlights;
uniform float maximumHighlightAmount = 0.25;
uniform float highlightFadeOutStart = 0.1;
uniform float highlightFadeOutEnd = 1;
uniform float highlightFadeOutPower = 0.5;
uniform float highlightFadeOutAmount = 0.2;

group_uniforms;

group_uniforms HighlightA;
uniform vec4 highlightAColor:source_color;
uniform float highlightAStrength:hint_range(0.0, 1.0) = 1.0;
uniform vec3 highlightARange = vec3( 0, 0.25, 0.5);
uniform float highlightAOverlapEnd: hint_range(0.0, 1.0) = 1.0;
uniform float highlightAInvert: hint_range(0.0, 1.0) = 0.0;


group_uniforms;

group_uniforms HighlightB;
uniform vec4 highlightBColor:source_color;
uniform float highlightBStrength:hint_range(0.0, 1.0) = 1.0;
uniform vec3 highlightBRange = vec3( 0, 0.25, 0.5);
uniform float highlightBOverlapEnd: hint_range(0.0, 1.0) = 1.0;
uniform float highlightBInvert: hint_range(0.0, 1.0) = 0.0;
group_uniforms;


// group_uniforms Normal;
// uniform sampler2D texture_normal : hint_roughness_normal, filter_linear_mipmap_anisotropic, repeat_enable;
// uniform float normal_scale : hint_range(-16.0, 16.0) = 1.0;

group_uniforms Roughness_Metallness;
uniform float roughness : hint_range(0.0, 1.0) = 1.0;
uniform float roughnessOffset: hint_range(-1.0, 1.0) = 0;
uniform sampler2D texture_roughness : hint_roughness_r, filter_linear_mipmap_anisotropic, repeat_enable;

uniform float metallic : hint_range(0.0, 1.0, 0.01) = 1.0;
uniform float metallicOffset: hint_range(-1.0, 1.0) = 0.25;
uniform sampler2D texture_metallic : hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;

uniform float specular : hint_range(0.0, 1.0, 0.01) = 0.2;
uniform float specularOpacityAmount: hint_range(0.0, 1.0) = 1;
uniform float specularOpacityGamma: hint_range(0.0, 3) = 2;

uniform float anisotropy_ratio: hint_range(0.0, 1.0) = 1;

group_uniforms;

group_uniforms emission;
uniform sampler2D texture_emission : source_color, hint_default_black, filter_linear_mipmap_anisotropic, repeat_enable;
uniform vec4 emission : source_color;
uniform float emission_energy : hint_range(0.0, 100.0, 0.01);

uniform vec4 backlight : source_color;
uniform float albedoToBacklightAmount : hint_range(0.0, 1.0) = 0.25;
uniform sampler2D texture_backlight : hint_default_black, filter_linear_mipmap_anisotropic, repeat_enable;

uniform float subsurface_scattering_strength : hint_range(0.0, 1.0) = 1.0;
group_uniforms;


// uniform float rim : hint_range(0.0, 1.0, 0.01);
// uniform float rim_tint : hint_range(0.0, 1.0, 0.01);
// uniform sampler2D texture_rim : hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;

// uniform float clearcoat : hint_range(0.0, 1.0, 0.01);
// uniform float clearcoat_roughness : hint_range(0.0, 1.0, 0.01);
// uniform sampler2D texture_clearcoat : hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;

group_uniforms Occlusion;
uniform sampler2D texture_ambient_occlusion : hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;
uniform float ao_light_affect : hint_range(0.0, 1.0 ) = 1.0;
uniform float ambientOcclusion:hint_range(0.0, 2.0) = 1.0;
uniform float aoGamma: hint_range(0.1, 10) = 1.0;

uniform float rootOcclusionAmount: hint_range(0.0, 1.0 ) = 0.1;
uniform float rootOcclusionRange: hint_range(0.0, 1.0 ) = 0.3; 

uniform float endOcclusionAmount: hint_range(0.0, 1.0 ) = 0.1;
uniform float endOcclusionRange: hint_range(0.0, 1.0 ) = 0.3; 

uniform float rootBasedOcclusion:hint_range(0.0, 1.0) = 0.5;

group_uniforms;
// uniform float subsurface_scattering_strength : hint_range(0.0, 1.0, 0.01);
// uniform sampler2D texture_subsurface_scattering : hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;

// uniform vec4 transmittance_color : source_color;
// uniform float transmittance_depth : hint_range(0.001, 8.0, 0.001);
// uniform sampler2D texture_subsurface_transmittance : hint_default_white, filter_linear_mipmap_anisotropic, repeat_enable;
// uniform float transmittance_boost : hint_range(0.0, 1.0, 0.01);



// uniform sampler2D texture_heightmap : hint_default_black, filter_linear_mipmap_anisotropic, repeat_enable;
// uniform float heightmap_scale : hint_range(-16.0, 16.0, 0.001);
// uniform int heightmap_min_layers : hint_range(1, 64);
// uniform int heightmap_max_layers : hint_range(1, 64);
// uniform vec2 heightmap_flip;

// uniform vec3 uv1_scale;
// uniform vec3 uv1_offset;
// uniform vec3 uv2_scale;
// uniform vec3 uv2_offset;

float computeCameraFadeout( float cameraDistance, float close, float range, float power, float closeValue, float farValue )
{
  float far = close + range;
  float mapped = mapClamped( cameraDistance, close, far, 0, 1 );

  float powered = pow( mapped, power );

  return mix( closeValue, farValue, powered ); 
}


float computeHighlightCameraFadeout( float cameraDistance, float fadeStart, float fadeEnd, float power, float fadeOut )
{
  float mapped = mapClamped( cameraDistance, fadeStart, fadeEnd, 0, 1 );

  float powered = pow( mapped, power );

  return mix( 1, fadeOut, powered ); 
}

varying float fadeAmount;

#ifdef USE_SHADOW
varying float shadowBlur;
varying float shadowOpacity;
#endif

void vertex() 
{
  

	// UV = UV * uv1_scale.xy + uv1_offset.xy;

  float cameraDistance = cameraDistanceLocal( VERTEX, CAMERA_POSITION_WORLD, MODEL_MATRIX );

  fadeAmount = computeHighlightCameraFadeout( 
    cameraDistance, highlightFadeOutStart, highlightFadeOutEnd, highlightFadeOutPower, highlightFadeOutAmount
  ) * maximumHighlightAmount;

  // VERTEX += NORMAL * grow;

  #ifdef USE_SHADOW
  
    float farAmount = computeCameraFadeout( 
      cameraDistance, opacityFarStart, opacityFarRange, opacityFarPower, 0, 1 
    );
    
    shadowBlur = mix( opacityBlur, opacityBlurFarScale, farAmount );
    shadowOpacity = mix( opacity, opacityFarScale, farAmount );


    vec2 uv = UV - 0.5;
    float angle = atan( uv.y, uv.x );
    vec3 viewPosition = normalize( localToView( VERTEX, MODELVIEW_MATRIX ) );
    vec2 uvE = vec2( cos( angle ), sin( angle ) );
    uvE = viewPosition.xy; 
    
    vec3 localX = viewToLocalDirection( vec3( 1, 0, 0 ), INV_VIEW_MATRIX, MODEL_MATRIX );
    vec3 localY = viewToLocalDirection( vec3( 0, 1, 0 ), INV_VIEW_MATRIX, MODEL_MATRIX );  

    VERTEX +=  extending * NORMAL;  
  #endif




  // fadeAmountA = max( 1, clamp01( fadeAmountA ) );
  // fadeAmountB = max( 1, clamp01( fadeAmountB ) );
}

void fragment() 
{
  if ( ! enabled ) 
  {
   discard;
  } 

  // if ( ! FRONT_FACING )
  // {
  //   NORMAL = -NORMAL;
  // } 

	vec2 base_uv = UV;

  
	vec4 albedo_tex = albedo * texture( texture_albedo, base_uv );
  albedo_tex.rgb = adjustHSL( albedo_tex.rgb, hslOffset );
  albedo_tex.rgb = albedo_tex.rgb * diffuseStrength;

  #ifdef USE_SHADOW

    albedo_tex.rgb = vec3( 0, 0, 0 );

    float sampledAlpha = sampleRedBlurredUnclamped( texture_opacity, base_uv, shadowOpacity, 0, shadowBlur );
    ALPHA = clamp01( sampledAlpha );
    

  #else 
    ALPHA = pow( sampleRed( texture_opacity, base_uv, opacity, 0 ), opacityGamma );
  #endif


  
  #ifdef USE_ALPHA_SCISSOR
  ALPHA_SCISSOR_THRESHOLD = alphaScissorTreshold;
  #endif

  #ifdef USE_ALPHA_DISCARD
  
  if ( ALPHA < alphaDiscardTreshold )
  {
    discard;
  }

  #endif



  float root = clamp01( 1.0 - texture( rootMap, UV ).r );
  float id   = texture( idMap, UV ).r;
  
  if ( activateHairColor )
  {
    
    albedo_tex = mix( vec4( 1, 1, 1, 1 ), albedo_tex, baseColorMapStrength );

   
    albedo_tex.rgb = mix( albedo_tex.rgb, vertexGreyToColor.rgb, ( 1.0 - COLOR.r ) * vertexColorStrength );

    float strandAmount = mix( strandEndStrength, strandRootStrength, root );
    vec4 strandColor = mix( strandEndColor, strandRootColor, root );
    strandColor = gamma( strandColor, strandGamma );

    // albedo_tex.rgb = blendMode_colorHSL( albedo_tex, strandColor, strandAmount ).rgb;
    // albedo_tex.rgb = mix( albedo_tex.rgb, strandColor.rgb, strandAmount );
    albedo_tex.rgb = mix( albedo_tex, strandColor, strandAmount ).rgb;

    
    float highlightABlend = rangeAmount( id, highlightARange ) * highlightAStrength;
    float rootBlendAmountA = mix( 1.0, mix( root, 1.0 - root, highlightAInvert ), highlightAOverlapEnd );
    vec3 rootBlendedA = mix( albedo_tex.rgb, highlightAColor.rgb, clamp01( rootBlendAmountA )  );

    albedo_tex.rgb = mix( albedo_tex.rgb, rootBlendedA, highlightABlend * fadeAmount );


    float highlightBBlend = rangeAmount( id, highlightBRange ) * highlightBStrength;
    float rootBlendAmountB = mix( 1.0, mix( root, 1.0 - root, highlightBInvert ), highlightBOverlapEnd );
    vec3 rootBlendedB = mix( albedo_tex.rgb, highlightBColor.rgb, clamp01( rootBlendAmountB ) );

    albedo_tex.rgb = mix( albedo_tex.rgb, rootBlendedB, highlightBBlend * fadeAmount );


  }
  else
  {
    albedo_tex.rgb = mix( albedo_tex.rgb, vertexGreyToColor.rgb, ( 1.0 - COLOR.r ) * vertexColorStrength );
  }
	
  
  ALBEDO = albedo_tex.rgb;


  if ( naturalColors > 0.0 )
  {
    // ALBEDO = ALBEDO * 0.95;
    vec3 hsl = RGBtoHSL( ALBEDO );

    hsl.z = pow( hsl.z, 0.95 ) * 0.95 + hsl.y * 0.05;
    hsl.y = pow( hsl.y, 2 );

    hsl = clamp( hsl, 0, 1 );
    
    ALBEDO = mix( ALBEDO, HSLtoRGB( hsl ), naturalColors );
  }

  vec4 blendTexture = texture( texture_blend, UV );
  ALBEDO = mix( ALBEDO, ALBEDO * blendTexture.rgb, blendAmount );

  
  

  // ALBEDO = clamp( COLOR.rgb, 0, 1 );

	float metallic_tex = texture(texture_metallic, base_uv).r;
	METALLIC = clamp( metallic_tex * metallic + metallicOffset, 0, 1 );
	SPECULAR = specular * mix( 1.0, pow( ALPHA, specularOpacityGamma ), specularOpacityAmount );

	float roughness_tex =texture(texture_roughness, base_uv).r;
	ROUGHNESS = clamp( roughness_tex * roughness + roughnessOffset, 0, 1 );

	// // Normal Map: Enabled
	// NORMAL_MAP = texture(texture_normal, base_uv).rgb;
	// NORMAL_MAP_DEPTH = normal_scale;

	// Emission: Enabled
	vec3 emission_tex = texture(texture_emission, base_uv).rgb;
	// Emission Operator: Add
	EMISSION = (emission.rgb + emission_tex) * emission_energy;
  
  
  
	// // Rim: Enabled
	// vec2 rim_tex = texture(texture_rim, base_uv).xy;
	// RIM = rim * rim_tex.x;
	// RIM_TINT = rim_tint * rim_tex.y;

	// // Clearcoat: Enabled
	// vec2 clearcoat_tex = texture(texture_clearcoat, base_uv).xy;
	// CLEARCOAT = clearcoat * clearcoat_tex.x;
	// CLEARCOAT_ROUGHNESS = clearcoat_roughness * clearcoat_tex.y;

	// Ambient Occlusion: Enabled
  float sampledAO = texture(texture_ambient_occlusion, base_uv).a;
  float rootAO = mapClamped( root, 0.0, rootOcclusionRange, 1.0 - rootOcclusionAmount, 1 );
  float endAO  = mapClamped( root, 1.0, 1.0 - endOcclusionRange, 1.0 - endOcclusionAmount, 1 );
  
  sampledAO *= mix( 1, ( rootAO * endAO ), rootBasedOcclusion );

	AO = mix( 1, pow( sampledAO, aoGamma ), ambientOcclusion );
	AO_LIGHT_AFFECT = ao_light_affect;

	// // Subsurface Scattering: Enabled
	// float sss_tex = texture(texture_subsurface_scattering, base_uv).r;
	SSS_STRENGTH = subsurface_scattering_strength * ALPHA;

	// // Backlight: Enabled
	// vec3 backlight_tex = texture(texture_backlight, base_uv).rgb;
	// BACKLIGHT = (backlight.rgb + backlight_tex);
  BACKLIGHT = albedo_tex.rgb * albedoToBacklightAmount;

  vec3 anisotropy_tex = texture(flowMap, base_uv).rga;
	ANISOTROPY = anisotropy_ratio * anisotropy_tex.b;
	ANISOTROPY_FLOW = anisotropy_tex.rg * 2.0 - 1.0;

  #ifdef USE_SHADOW

    ALBEDO = vec3( 0, 0, 0 );
    BACKLIGHT = vec3( 0, 0, 0 );
    AO_LIGHT_AFFECT = 1.0;
    AO = 0.0;
    EMISSION = vec3( 0, 0, 0 );
    ROUGHNESS = 1.0;
    METALLIC = 0.0;
    SPECULAR = 0.0;

    
  #endif
}
