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

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


/*
uniform float windOcclusionAmount = 0;
uniform float windStrength = 0;
uniform vec2 windSpeed = vec2(1,1);
uniform float windScale = 0.1;
uniform sampler2D windNoise;
uniform vec2 windNoiseAngleOffset;
uniform vec2 windNoiseStrengthOffset;
uniform float windStart = 0;
uniform float windEnd = 1;
uniform float windWeightCurve:hint_range(0,1) = 0.5f;
uniform float windHeightCompensation :hint_range(0,1) = 0.5f;
uniform float windNormalBending :hint_range(0,1) = 0.1f;
varying float vertexWindAO;

applyWind( 
  TIME, 
  MODEL_MATRIX, 
  VERTEX, 
  NORMAL,
  vertexWindAO,
  windOcclusionAmount,
  windStrength,
  windSpeed,
  windScale,
  windNoise,
  windNoiseAngleOffset,
  windNoiseStrengthOffset,
  windStart,
  windEnd,
  windWeightCurve,
  windHeightCompensation,
  windNormalBending
);

*/
void applyWind( 
  float _TIME, 
  mat4 _MODEL_MATRIX, 
  inout vec3 _VERTEX, 
  inout vec3 _NORMAL,
  inout float _vertexWindAO,
  float _windOcclusionAmount,
  float _windStrength,
  vec2 _windSpeed,
  float _windScale,
  sampler2D _windNoise,
  vec2 _windNoiseAngleOffset,
  vec2 _windNoiseStrengthOffset,
  float _windStart,
  float _windEnd,
  float _windWeightCurve,
  float _windHeightCompensation,
  float _windNormalBending
 )
{
  float _windAmount = normalizeToRange01( _VERTEX.y, _windStart, _windEnd );
  float rawWindAmount = _windAmount;
  float originalHeight = _VERTEX.y;
  _windAmount = mix( _windAmount, _windAmount * _windAmount, _windWeightCurve );    
  vec3 worldVertex = localToWorld( _VERTEX, _MODEL_MATRIX );
  vec2 _windUV = _TIME * _windSpeed + worldVertex.xz * _windScale;
  float angle = texture( _windNoise, _windUV + _windNoiseAngleOffset).r * PI * 2.0;
  float generalStrength = texture( _windNoise, _windUV + _windNoiseStrengthOffset ).r;
  float strength = generalStrength * _windStrength;
  vec2 circle = onCircle( angle ) * strength;
  _VERTEX = worldToLocal( worldVertex + vec3( circle.x, 0, circle.y ) * _windAmount, _MODEL_MATRIX );
  float minY = min( _VERTEX.y, 0 ); 
  _VERTEX.y = mix( _VERTEX.y, max( minY, _VERTEX.y - strength * _windAmount), _windHeightCompensation * 4.0f );
  _NORMAL = normalize( mix( _NORMAL, vec3( circle.x, -1, circle.y ), generalStrength * _windNormalBending ) );
  _vertexWindAO = mix( 1, 0, generalStrength * _windOcclusionAmount);
}


/*

// [ WIND ]
group_uniforms wind;

// Texture for close wind: grass/foliage
global uniform sampler2D rj_GlobalWindNoiseTextureClose;

// Texture for far wind: trees
global uniform sampler2D rj_GlobalWindNoiseTextureFar;

// Windposition close
global uniform vec2 rj_GlobalWindPositionClose;

// Windposition far
global uniform vec2 rj_GlobalWindPositionFar;

// Wind direction for both
global uniform vec2 rj_GlobalWindDirection;

// Wind speed for both
global uniform float rj_GlobalWindSpeed;

// Weights for x: close and y: far
uniform vec2 windWeights = vec2( 0.5, 0.5 );

// Scales the world-vertex based variance
uniform float windSeedSize = 1.0;

// Max xz bending
uniform float windMaxStrength = 0.2;

// Max yaw rotation
uniform float windMaxRotation = 0.1;

// Linear/Inv-Quadratic mapping for the strength
uniform float windStrengthCurve:hint_range( 0.0, 1.0 );

// Influence start in local Y
uniform float windStart = 0.1;

// Influence max in local Y
uniform float windEnd = 2.0;

// Influence mapping over local Y
uniform float windWeightCurve:hint_range( 0.0,1.0 ) = 0.5;

// Ducking in y for amount, strong wind => vertices lower
uniform float windHeightCompensation;

// Normal incluence
uniform float windNormalBending;

// AO influence
uniform float windOcclusionAmount;
varying float vertexWindAO;

// 

----------
== vertex()
{

  // WIND

  float windAO = 0.0;
  applyGlobalWind( 
    MODEL_MATRIX, 
    VERTEX, 
    NORMAL,
    windAO,
    windOcclusionAmount,
    rj_GlobalWindNoiseTextureClose,
    rj_GlobalWindNoiseTextureFar,
    rj_GlobalWindPositionClose,
    rj_GlobalWindPositionFar,
    rj_GlobalWindDirection,
    rj_GlobalWindSpeed,
    windWeights,
    windSeedSize,
    windMaxStrength,
    windMaxRotation,
    windStrengthCurve,
    windStart,
    windEnd,
    windWeightCurve,
    windHeightCompensation,
    windNormalBending
  );

  vertexWindAO = windAO;

}

----------
== fragment()
{
  AO *= vertexWindAO;
}

*/

void applyGlobalWind( 
  mat4 _MODEL_MATRIX, 
  inout vec3 _VERTEX, 
  inout vec3 _NORMAL,
  inout float _vertexWindAO,
  float _windOcclusionAmount,
  sampler2D _globalWindNoiseTextureClose,
  sampler2D _globalWindNoiseTextureFar,
  vec2 _globalWindPositionClose,
  vec2 _globalWindPositionFar,
  vec2 _globalWindDirection,
  float _globalWindSpeed,
  vec2 _windWeights,
  float _windSeedSize,
  float _windMaxStrength,  
  float _windMaxRotation,
  float _windStrengthCurve,
  float _windStart,
  float _windEnd,
  float _windWeightCurve,
  float _windHeightCompensation,
  float _windNormalBending
 )
{
  float _windForceState = ( _globalWindSpeed / 100.0 );

  if ( _windForceState !=  0.0 )
  {
    _windForceState = mix( _windForceState, _windForceState / _windForceState, _windStrengthCurve *_windForceState );
  }

  float _windStrength = _windMaxStrength * _windForceState;
  float _windAmount = normalizeToRange01( _VERTEX.y, _windStart, _windEnd );
  float rawWindAmount = _windAmount;
  float originalHeight = _VERTEX.y;
  _windAmount = mix( _windAmount, _windAmount * _windAmount, _windWeightCurve );    
  vec3 worldVertex = localToWorld( _VERTEX, _MODEL_MATRIX );

  vec2 seedSizeClose = vec2( textureSize( _globalWindNoiseTextureClose, 0 ) ) * _windSeedSize;
  vec2 seedSizeFar = vec2( textureSize( _globalWindNoiseTextureFar, 0 ) ) * _windSeedSize;
  vec4 windRGBClose = texture( _globalWindNoiseTextureClose, fract( _globalWindPositionClose + worldVertex.xz / seedSizeClose ) );
  vec4 windRGBFar = texture( _globalWindNoiseTextureFar, fract( _globalWindPositionFar + worldVertex.xz / seedSizeFar ) );
  float generalStrength = windRGBClose.r * _windWeights.x + windRGBFar.r * _windWeights.y;

  float angleAmount = windRGBClose.g * _windWeights.x + windRGBFar.g * _windWeights.y;

  float strength = generalStrength * _windStrength;
  float angle = ( angleAmount * 2.0 - 1.0 ) * PI * _windMaxRotation * _windForceState;
  vec2 direction = normalize( _globalWindDirection );
  direction =  normalize( rotate_v2( direction, angle ) );
  direction *= strength;

  _VERTEX = worldToLocal( worldVertex + vec3( direction.x, 0, direction.y ) * _windAmount, _MODEL_MATRIX );
  float minY = min( _VERTEX.y, 0 ); 
  _VERTEX.y = mix( _VERTEX.y, max( minY, _VERTEX.y - strength * _windAmount), _windHeightCompensation * 4.0f );
  _NORMAL = normalize( mix( _NORMAL, vec3( direction.x, -1, direction.y ), generalStrength * _windNormalBending ) );
  _vertexWindAO = mix( 1, 0, generalStrength * _windOcclusionAmount);
}