uniform samplerCube cubemap;
uniform samplerCube reflmap;
uniform vec3 campos;            // camera position in object space
uniform vec3 lightintense;      // intensity of light
uniform vec3 lightcolor;        // intensity of light
uniform float refraction;       // attenuation for refracted reflections

const vec3 bias= vec3(0.004, -0.005,-0.003);

const vec3 lightposition= vec3(0.0, -0.3, 0.0); // position of the light-source in object-space; (0,0,0) is object-center.
const vec3 materialcolour= vec3(6.0, 5.4, 5.4) / 1.5;
const float index= 1.0 / 1.5; // index of refraction air -> glass
const float indexRcp= 1.0 / index; // index of refraction glass -> air

varying vec3 normal;
varying vec3 hit;

vec3 hitnormal;

vec3 intersectCube(vec3 pos, vec3 dir)
{
   const float EPS= 0.0001;
   const vec3 side= vec3(1.0, 1.0, 1.0);
   float hit= 1000.0;
   
   vec3 r1= (side-pos) / dir;
   vec3 r2= (-side-pos) / dir;

   if (r1.x>EPS && r1.x<hit) { hitnormal= vec3(-1,0,0); hit=r1.x; }
   if (r1.y>EPS && r1.y<hit) { hitnormal= vec3(0,-1,0); hit=r1.y; }
   if (r1.z>EPS && r1.z<hit) { hitnormal= vec3(0,0,-1); hit=r1.z; }

   if (r2.x>EPS && r2.x<hit) { hitnormal= vec3(1,0,0); hit=r2.x; }
   if (r2.y>EPS && r2.y<hit) { hitnormal= vec3(0,1,0); hit=r2.y; }
   if (r2.z>EPS && r2.z<hit) { hitnormal= vec3(0,0,1); hit=r2.z; }

   return pos + dir * hit * 0.9999; // make sure ray keeps inside
}

float length(vec3 v)
{
   return sqrt( dot(v,v) );
}

vec3 reflect(vec3 dir, vec3 nrm)
{
	return dir - nrm * 2.0 * (dir * nrm);
}

float hitlight(vec3 pos, vec3 dir, vec3 p)
{
  vec3 a= cross(dir, pos-p);
  float b= 1.05 - sqrt( dot(a,a) ) * lightintense.x;
  if (b<0.0) b=0.0;
  return pow(b, 80.0) * lightintense.z;
}

void main()
{
   vec3 dir= normalize(hit - campos);  // vector camera -> vertex
	vec3 n= normalize(normal);          // normal vector

   // reflect view-vector at surface normal
   float c1= -dot(n, dir); // angle between view (inward) and surface-normal (outward)
	vec3 refl= dir + n * 2.0 * c1; 

   // refraction air -> glas
   float c2 = sqrt( 1.0 - index*index * (1.0 - c1*c1) );
   vec3 refr = (dir * index) + n * (index * c1 - c2); // refract view-vector at surface normal

   // how much of the incoming ray reflects at the surface
   float ri= pow(1.0-c1, 3.0);

   // rest enters the object
   float factor= (1.0-ri);

   vec3 col1= vec3(0.01,0.01,0.01); // ambient light; makes less contrast
   vec3 col2= vec3(0,0,0);
   vec3 col3= textureCube(reflmap, refl).rgb * ri;

   dir= normalize( refr );
    

   float dist= 1.1; // smaller values raise border lightness

   vec3 curhit= hit + dir * 0.0001; // make sure ray starts inside
   for (int i=0;i<3;i++)
   {
	   vec3 intersect= intersectCube(curhit, dir);

      vec3 ray= intersect-curhit;
      dist+= dot(ray, ray);

	   // refraction glas -> air
      float c1= -dot(hitnormal, dir);
      float c2= sqrt( 1.0 - (index*index) * (1.0 - c1*c1) );

      vec3 refr = (dir * indexRcp) + hitnormal * (indexRcp * c1 - c2);

      float da= 1.0 / dist; // distance attenuation factor
      col1+= factor * textureCube(cubemap, intersect).aaa * da;
	   col2+= hitlight(curhit, dir, lightposition) * da;
      col3+= c1*refraction* textureCube(reflmap, refr).rgb * da;

//         ( textureCube(reflmap, refr+ vec3( 0.002, -0.003,-0.001) ).rgb 
//         + textureCube(reflmap, refr+ vec3(-0.001,  0.002, 0.003) ).rgb
//         + textureCube(reflmap, refr+ vec3( 0.003, -0.001, 0.002) ).rgb
//         + textureCube(reflmap, refr+ vec3(-0.002,  0.001,-0.003) ).rgb )

   	dir+= hitnormal * 2.0 * c1; // reflection vector
	   factor*= (1.0 - c1); 
      curhit= intersect;
   }

//   col1*= 1.0+textureCube(cubemap, hit).a;

   col1*= materialcolour;
//   col1+= dist*0.01;     // length of ray used for attenuation (not perfectly transparent)

   vec3 col= (col1 * (1.25-lightintense.x*0.5)
            + col2 * lightintense.y * 0.5) *lightcolor
            + col3 * 5.0;

   col*= textureCube(cubemap, hit).a*2.0+0.5;

   gl_FragColor = vec4(col, 1);
}
