#include "common.sh"


#define MAX_RK 8
#define FADE_RANGE 4

#define MAX_RK2 (MAX_RK*MAX_RK)
#define FADE_RANGE2 (FADE_RANGE*FADE_RANGE)


struct VsInput
{
  float2 dp  : POSITION0;
  float2 org : POSITION1;
  float4 data[NUMVEC] : TEXCOORD0;
};


struct VsOutput
{
  float4 pos  : POSITION;
  float4 data[NUMVEC] : TEXCOORD0;
  float2 tc           : TEXCOORD9;
  float3 wvec         : TEXCOORD10;
};


float4 postm : register(c15);
float4 texsz : register(c16);
float4 viewx : register(c17);
float4 viewy : register(c18);
float4 viewz : register(c19);


VsOutput vsh(VsInput I)
{
  VsOutput O;
  float2 pos=(I.org+I.dp)*postm.xy+postm.zw;
  O.pos=float4(pos, 1, 1);
  O.tc=pos.xy*texsz.xy+texsz.zw;
  O.wvec=pos.x*viewx.xyz+pos.y*viewy.xyz+viewz.xyz;
  O.data=I.data;
  return O;
}


float3 viewPos : register(c16);


float4 psh(VsOutput I) : COLOR
{
  float depth=unpack_from_8x3(tex2D(gbuf0_tex, I.tc.xy).xyz);
  float3 norm=normalize(tex2D(gbuf1_tex, I.tc.xy).xyz*2-1);

  float3 eyeVec=I.wvec*depth;
  float3 pos=eyeVec+viewPos;

  float2 shadow=1;

  [unroll]
  for (int i=0; i<NUMVEC; i++)
  {
    float4 ball=I.data[i];

    float3 bpos=ball.xyz;
    float r=ball.w;
    float r2=r*r;

    float3 dp=bpos-pos;
    float d2=dot(dp, dp);

    float3 dpn=dp*rsqrt(d2);

    float dn=saturate(dot(dpn, norm));

    // sky / ambient
    float sin2=r2/d2;
    float sky=sin2*dn;

    // sun
    float c=dot(dpn, sun_dir.xyz);
    float ca=sqrt(saturate(1-sin2)), cb=sun_dir.w;

    // enlarge source to smooth thin shadows in the distance
    const float blurFactor=8;
    float vn=dot(normalize(-I.wvec), norm);
    float bk=smoothstep(0, smoothstep(0.01, 0.075, depth)*0.3, vn);
    cb=1-(1-cb)*(blurFactor-bk*(blurFactor-1));

    float cc=ca*cb, ss=sqrt((1-ca*ca)*(1-cb*cb));
    float sun=smoothstep(cc-ss, cc+ss, c)*(1-ca)/(1-cb);

    // fade with distance
    float fk=saturate((r2*MAX_RK2-d2)/(r2*FADE_RANGE2));

    shadow*=saturate(1-float2(sky, sun)*fk);
  }

  return float4(shadow, 0, 0);
}
