struct VertexEingabe
{
  float2 vpos : POSITION0;   // Reckeck-Ecke xy (0 .. 1)
  float4 pos[2] : TEXCOORD0; // und TEXCOORD1: Position der Ecken
  float4 grafik : TEXCOORD2; // Grafikbereich in Texturpixeln, xy = linksoben, zw = BreiteHöhe
  float4 farbe[4] : TEXCOORD3; // bis einschl. TEXCOORD6: Farben der vier Ecken
};

struct VertexAusgabe
{
  float4 pos : POSITION0;
  float4 farbe : COLOR0;
  float2 tex : TEXCOORD0;
  float4 texGrenz : TEXCOORD1;
  float4 dxdy: TEXCOORD2; // Tangente für X und Y-Texturrichtung
};

sampler2D Textur;
float2 gQuellGroesse; // Größe der Quelltextur in 1/Pixel
float2 gZielGroesse; // Größe des Zielbereichs, in 1/Pixel, y bereits negiert

VertexAusgabe VertexMain( const VertexEingabe rein)
{
  VertexAusgabe raus;

  float pzeile = rein.vpos.y > 0.5f ? 1 : 0;
  float pspalte = rein.vpos.x > 0.5f ? 1 : 0;
  float2 pos = pspalte ? rein.pos[pzeile].zw : rein.pos[pzeile].xy;
  // mit halbem Pixel Offset nach links oben für DX9-Rasterizing Rules
  pos -= float2( 0.5f, 0.5f);  
  raus.pos = float4( pos.xy * gZielGroesse.xy * 2.0f + float2( -1.0f, 1.0f), 0.5f, 1.0f);
  
  float findex = rein.vpos.y * 2.0f + rein.vpos.x;
  raus.farbe = rein.farbe[findex];

  raus.tex = (rein.grafik.xy + rein.vpos.xy * rein.grafik.zw) * gQuellGroesse.xy;

  // Tangentenvektoren in X und Y berechnen. Daraus leiten wir Rotation und Texturrandweite ab
  float2 tangx[2];
  tangx[0] = rein.pos[0].zw - rein.pos[0].xy;
  tangx[1] = rein.pos[1].zw - rein.pos[1].xy;
  float2 tangy[2];
  tangy[0] = rein.pos[1].xy - rein.pos[0].xy;
  tangy[1] = rein.pos[1].zw - rein.pos[0].zw;

  // X-Tangente und Y-Tangente einfach mal normiert rausschreiben und gucken, wie es aussieht.
  // die Idee mit atan2() und dem interpolierten Winkel war nicht so gut, weil die Interpolation über +-PI springt
  raus.dxdy.xy = normalize( tangx[pzeile]);
  raus.dxdy.zw = normalize( tangy[pspalte]);

  // Größe des Tex-Randbereiches ermitteln. Standard ist ein halber Pixel, bei verkleinerter Darstellung 
  // und entsprechender MipMap-Nutzung muss der Grenzbereich entsprechend größer werden
  float grx = min( length( tangx[0]), length( tangx[1]));
  float gry = min( length( tangy[0]), length( tangy[1]));

  float randGrenze = min( grx / rein.grafik.z, gry / rein.grafik.w);
  randGrenze = 0.5f / clamp( randGrenze, 1.0f/16.0f, 1.0f);
  raus.texGrenz = (rein.grafik.xyxy + float4( 0, 0, 1, 1) * rein.grafik.zwzw + float4( 1, 1, -1, -1) * randGrenze) * gQuellGroesse.xyxy;
  
  return raus;
}

float4 PixelMainFarbe( const VertexAusgabe rein) : COLOR0
{
  float2 texk = clamp( rein.tex.xy, rein.texGrenz.xy, rein.texGrenz.zw);
  float4 farbe = tex2D( Textur, texk);
  farbe *= rein.farbe;
  farbe.rgb *= farbe.a; // für premultiplied alpha
  return farbe;
}

float4 PixelMainNormal( const VertexAusgabe rein) : COLOR0
{
  float2 texk = clamp( rein.tex.xy, rein.texGrenz.xy, rein.texGrenz.zw);
  float4 bump = tex2D( Textur, texk);

  // Normalenvektor drehen anhand des reingereichten Winkels
  float2 nx = rein.dxdy.xy;
  float2 ny = rein.dxdy.zw;
  bump.xy = bump.xy * 2.0f - float2( 1.0f, 1.0f);
  bump.xy = bump.x * nx + bump.y * ny;
  bump.xy = 0.5f * bump.xy + float2( 0.5f, 0.5f);

  bump.rgb *= bump.a; // für premultiplied alpha
  return bump;
}
