/** @file SchattenWeiter.shader
 * weitere Passes zur Schattenberechnung: mit exponentiell wachsenden Teststrahlen Schatten von der Lichtquelle weg verlängern
 */

struct Vertex
{
  float4 mPosition : POSITION0;
  float3 mVertexPos : TEXCOORD0; // Vertexposition in Weltkoords
  float4 mLichtPos : TEXCOORD1; // Lichtposition in Weltkoords, w > 0.0f -> Parallel-Licht Sinkgeschwindigkeit
  float3 mLichtParams : TEXCOORD2; // Lichtparameter: XY Strecken-Ausdehnung, Z radiale Ausdehnung
  float4 mWeltZuTex : TEXCOORD3; // Weltkoords zu Texkoords: XY Skalierung, ZW Basisaddition
  float4 mTexGrenzen : TEXCOORD4; // Texturkoord-Grenzen xy linksoben, zw rechtsunten
};

// Temp-Textur mit den Werten des letzten Passes: X Intensität 0..1, Y Höhe der Schattenkante, Z Sinktempo der Schattenkantenhöhe
sampler2D TexSchatten;

// Laenge des Schatten-Teststrahls in Tiles. Shader geht davon aus, dass der gegenüber dem vorherigen Pass
// jeweils vervierfacht wird.
float gTestStrahlLaenge;

// ein paar Offsets zum Streuen der Samples
static const float2 gSampleOffsets[] =
{
  { 0.00397408, -0.0311718 },
  { 0.0192963, -0.0191685 },
  { -0.00125793, 0.00531308 },
  { 0.0247476, -0.00935678 },
  { 0.0154128, 0.0201775 },
  { 0.022434, -0.0203682 },
  { 0.000845935, 0.0131563 },
  { -0.0303135, -0.0122503 },
  { -0.00847175, -0.0255373 },
  { -0.0208813, -0.0220429 },
  { -0.00339423, 0.0305328 },
  { -0.0309582, -0.0238073 },
  { -0.00763249, -0.030693 }
};

// ------------------------------------------------------------------------------------------------
// VertexShader 
Vertex VertexMain( const Vertex rein)
{
  return rein;
}

// ------------------------------------------------------------------------------------------------
// PixelShader 
float4 PixelMain( const Vertex rein) : COLOR0
{
  // den ersten Sample schreiben wir manuell aus, um den Texturwert an der Stelle dazuhaben
  float2 startTexkoords = rein.mVertexPos.xy * rein.mWeltZuTex.xy + rein.mWeltZuTex.zw;
  float4 startTexel = tex2D( TexSchatten, startTexkoords);
  
  float2 vekZumLicht = rein.mLichtPos.xy - rein.mVertexPos.xy;
  float2 querZumLicht = normalize( float2( -1.0f, 1.0f) * vekZumLicht.yx);

  float4 erg = float4( 0.0f, 0.0f, 0.0f, 0.0f);

  int minStrahl, maxStrahl;
  float schattenSkalierung;
  if( SCHATTENSTUFE > 1 )
  {  minStrahl = 0; maxStrahl = 5; schattenSkalierung = 0.2f; }
  else
  {  minStrahl = 2; maxStrahl = 3; schattenSkalierung = 1.0f; }

  [unroll] 
  for( int b = minStrahl; b < maxStrahl; ++b )
  {
    float fb = float( b) * 0.5f - 1.0f;
    float2 zielPos = rein.mLichtPos.xy + fb * rein.mLichtParams.xy;
    zielPos += fb * rein.mLichtParams.z * querZumLicht;

    float2 vertexZuLicht = zielPos - rein.mVertexPos.xy;
    float abstandZuLicht = length( vertexZuLicht); 
    float strecke = min( gTestStrahlLaenge, abstandZuLicht); 
    float2 richtung = normalize( vertexZuLicht);

    float2 wert = startTexel.xy;

    // jeweils 7 Samples entlang des Wegs zum Licht nehmen
    [unroll]
    for( int a = 1; a < 8; ++a )
    {
      float entf = strecke * (float( a) - 0.5f) / 8.0f;
      float2 texkoords = (rein.mVertexPos.xy + entf * richtung) * rein.mWeltZuTex.xy + rein.mWeltZuTex.zw;
      texkoords = clamp( texkoords, rein.mTexGrenzen.xy, rein.mTexGrenzen.zw);
      float4 t = tex2D( TexSchatten, texkoords);

      // Sinktempo berechnen, wenn die Schattenkante vom Licht bis zu diesem Texel verläuft
      // bei Parallellicht ist die Sinkgeschwindigkeit in mLichtPos.w gegeben
      float sinkTempo = rein.mLichtPos.w > 0.0f ? rein.mLichtPos.w : (rein.mLichtPos.z - t.x) / (abstandZuLicht - entf);
      // daraus Höhe der Schattenkante am Ausgangspunkt errechnen
      t.x -= sinkTempo * entf;
      t.y *= saturate( t.x * 10.0f);

      // Intensität dieser Schattenkante am Zielpunkt muss stärker sein als das bisher gefundene
      wert.xy = max( wert.xy, t.xy);
    }

    // Ergebnis anteilig aufrechnen
    erg.x = max( erg.x, wert.x);
    erg.y += schattenSkalierung * wert.y;
  }
  
  // so zurückgeben
  return erg;
}
