// NOTE: Shader automatically converted from Godot Engine 4.4.stable.mono's StandardMaterial3D.

shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx;

#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Math.gdshaderinc"
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Transform.gdshaderinc"
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Noise.gdshaderinc"
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Light.gdshaderinc"
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Textures.gdshaderinc"

uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_linear_mipmap, repeat_enable;
uniform ivec2 albedo_texture_size;
uniform float point_size : hint_range(0.1, 128.0, 0.1);

uniform sampler2D terrain : filter_linear_mipmap, repeat_enable;
uniform sampler2D terrainNormal : filter_linear_mipmap, repeat_enable;
uniform float terrainNormalScaling: hint_range(0.5,10);
uniform vec3 terrainSize;
uniform vec3 terrainOffset;
uniform float terrainMaxHeight = 500;
varying vec2 terrainUV;
uniform float texel = 1;
uniform float texelSpread = 2;
uniform float texelVertexSpread = 2;
uniform float texelVertexSpreadCamDistance = 2000;
uniform float texelVertexSpreadCamPower = 1;
uniform float texelVertexSpreadCamAmount = 1;
uniform float texelVertexSpreadWeight = 1;
uniform float texelNormalScale = 100;

uniform float roughness : hint_range(0.0, 1.0);
uniform sampler2D texture_metallic : hint_default_white, filter_linear_mipmap, repeat_enable;
uniform vec4 metallic_texture_channel;
uniform sampler2D texture_roughness : hint_roughness_r, filter_linear_mipmap, repeat_enable;

uniform float specular : hint_range(0.0, 1.0, 0.01);
uniform float metallic : hint_range(0.0, 1.0, 0.01);

uniform sampler2D texture_normal : hint_roughness_normal, filter_linear_mipmap, repeat_enable;
uniform float normal_scale : hint_range(-16.0, 16.0);
uniform float normalMinDistance = 5;
uniform float normalMaxDistance = 100;
uniform float normalMinValue = 0.5;
uniform float normalMaxValue = 1;

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, repeat_enable;

uniform sampler2D texture_detail_albedo : source_color, filter_linear_mipmap, repeat_enable;
uniform sampler2D texture_detail_normal : hint_normal, filter_linear_mipmap, repeat_enable;
uniform sampler2D texture_detail_mask : hint_default_white, filter_linear_mipmap, repeat_enable;

uniform sampler2D texture_heightmap : hint_default_black, filter_linear_mipmap, 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;
varying vec3 uv1_triplanar_pos;
varying vec3 uv2_triplanar_pos;

uniform float uv1_blend_sharpness : hint_range(0.0, 150.0, 0.001);
varying vec3 uv1_power_normal;
uniform float uv2_blend_sharpness : hint_range(0.0, 150.0, 0.001);
varying vec3 uv2_power_normal;

uniform vec3 uv1_scale;
uniform vec3 uv1_offset;
uniform vec3 uv2_scale;
uniform vec3 uv2_offset;
varying float cameraDistanceFactor;

uniform float terrainUVScale = 1;

void vertex() 
{
	vec3 normal = NORMAL;

	TANGENT = vec3(0.0, 0.0, -1.0) * abs(normal.x);
	TANGENT += vec3(1.0, 0.0, 0.0) * abs(normal.y);
	TANGENT += vec3(1.0, 0.0, 0.0) * abs(normal.z);
	TANGENT = normalize(TANGENT);

	BINORMAL = vec3(0.0, 1.0, 0.0) * abs(normal.x);
	BINORMAL += vec3(0.0, 0.0, -1.0) * abs(normal.y);
	BINORMAL += vec3(0.0, 1.0, 0.0) * abs(normal.z);
	BINORMAL = normalize(BINORMAL);

	// UV1 Triplanar: Enabled
	uv1_power_normal = pow(abs(NORMAL), vec3(uv1_blend_sharpness));
	uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;
	uv1_power_normal /= dot(uv1_power_normal, vec3(1.0));
	uv1_triplanar_pos *= vec3(1.0, -1.0, 1.0);

	// UV2 Triplanar: Enabled (with World Triplanar)
	uv2_power_normal = pow(abs(mat3(MODEL_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));
	uv2_triplanar_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz * uv2_scale + uv2_offset;
	uv2_power_normal /= dot(uv2_power_normal, vec3(1.0));
	uv2_triplanar_pos *= vec3(1.0, -1.0, 1.0);
  
  vec3 worldPosition = localToWorld( VERTEX, MODEL_MATRIX );
  terrainUV = heightMapUV( worldPosition, terrainSize, terrainOffset );
  //vec4 heightMapData = texture( terrain, terrainUV );
  float tx = texelVertexSpread / 2048.0;
  
  vec3 camPosWorld = ( vec4( 0, 0, 0, 1 ) * INV_VIEW_MATRIX ).xyz;
  float cameraDistance = length( worldPosition - CAMERA_POSITION_WORLD );
  float txCam = texelVertexSpreadCamAmount * pow( cameraDistance / texelVertexSpreadCamDistance, texelVertexSpreadCamPower );
  txCam /= 2048.0;
  txCam = min( txCam, 1.0/100.0 );
  vec4 heightMapData = fromHeightMapSmoothed( terrain, terrainUV, vec2( tx + txCam ), texelVertexSpreadWeight );
  UV = terrainUV * terrainUVScale;
  
  worldPosition.y += heightMapData.r * terrainMaxHeight;
  
  
  cameraDistanceFactor = mapClamped( cameraDistance, normalMinDistance, normalMaxDistance, normalMinValue, normalMaxValue );
   // (dx, dy, dz)
    
  VERTEX.y += heightMapData.r * terrainMaxHeight;
}

vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {
	vec4 samp = vec4(0.0);
	samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;
	samp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;
	samp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;
	return samp;
}

void fragment() {
	vec2 base_uv2 = UV2;

	vec4 albedo_tex = triplanar_texture(texture_albedo, uv1_power_normal, uv1_triplanar_pos);
	ALBEDO = albedo.rgb * albedo_tex.rgb;

	float metallic_tex = dot(triplanar_texture(texture_metallic, uv1_power_normal, uv1_triplanar_pos), metallic_texture_channel);
	METALLIC = metallic_tex * metallic;
	SPECULAR = specular;

	vec4 roughness_texture_channel = vec4(1.0, 0.0, 0.0, 0.0);
	float roughness_tex = dot(triplanar_texture(texture_roughness, uv1_power_normal, uv1_triplanar_pos), roughness_texture_channel);
	ROUGHNESS = roughness_tex * roughness;

  float tx = texel / 2048.0;

  // Sample heights at neighboring pixels
  float hL = texture(terrain, terrainUV - vec2(tx, 0)).r * texelNormalScale;
  float hR = texture(terrain, terrainUV + vec2(tx, 0)).r * texelNormalScale;
  float hD = texture(terrain, terrainUV - vec2(0, tx)).r * texelNormalScale;
  float hU = texture(terrain, terrainUV + vec2(0, tx)).r * texelNormalScale;

  // Compute gradient
  //NORMAL = normalize( texture( terrainNormal, terrainUV ).rgb - vec3( 0.5, 0.5, 0.5 ) );
  //NORMAL = normalize(vec3(hL - hR, hD - hU, 2.0));
  vec3 worldNormal = heightMapNormalSmoothed( terrain, terrainUV, vec2(tx,tx), texelNormalScale, texelSpread );
  NORMAL = worldToViewDirection( worldNormal, VIEW_MATRIX );
  NORMAL_MAP = texture( texture_normal, UV ).rgb;
	// Normal Map: Enabled
	//NORMAL_MAP = normalize( texture( terrainNormal, terrainUV ).rgb * vec3( 1, terrainNormalScaling, 1 ) );
	NORMAL_MAP_DEPTH = normal_scale * cameraDistanceFactor;

	// Rim: Enabled
	/*
  vec2 rim_tex = triplanar_texture(texture_rim, uv1_power_normal, uv1_triplanar_pos).xy;
	RIM = rim * rim_tex.x;
	RIM_TINT = rim_tint * rim_tex.y;
  */

	// Detail: Enabled
	vec4 detail_tex = triplanar_texture(texture_detail_albedo, uv2_power_normal, uv2_triplanar_pos);
	vec4 detail_norm_tex = triplanar_texture(texture_detail_normal, uv2_power_normal, uv2_triplanar_pos);
	vec4 detail_mask_tex = triplanar_texture(texture_detail_mask, uv1_power_normal, uv1_triplanar_pos);

	// Detail Blend Mode: Mix
	vec3 detail = mix(ALBEDO.rgb, detail_tex.rgb, detail_tex.a);
	vec3 detail_norm = mix(NORMAL_MAP, detail_norm_tex.rgb, detail_tex.a);
	//NORMAL_MAP = mix(NORMAL_MAP, detail_norm, detail_mask_tex.r);
	ALBEDO.rgb = mix(ALBEDO.rgb, detail, detail_mask_tex.r);
}
