//data texture
uniform sampler3D volume;

//size of the data bounding box
uniform vec3 size;

uniform mat4 modelview;
uniform mat4 projection;

uniform float zRatio;

uniform int mode;

uniform float zClipping;

//rendering
varying vec3 eye,ve,dir,light,lightPos;

float rand()
{
    return fract(sin(dot(gl_FragCoord.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float cube(in vec3 eye, in vec3 dir, in vec3 size, out float fr)
{
	float far;
	float near;
	float t1, t2, t3;
	int i;
	fr = 0.0;
	far = 9999.0;
	near = -9999.0;
	for (i = 0; i < 3; i++)
	{
		if (dir[i] == 0.0)
		{
			if (eye[i]<-0.0001 || eye[i]>0.0001)
			{
				return -1.0;
			}
		}
		else
		{
			t1 = (-size[i] - eye[i]) / dir[i];
			t2 = (size[i] - eye[i]) / dir[i];
			if (t2 > t1)
			{
				t3 = t1;
				t1 = t2;
				t2 = t3;
			}

			if (t2 > near)
				near=t2;
			if (t1 < far)
				far=t1;
			if (far < 0.0) //eye lies behind the cube and looks away
				return -1.0;
			if (near > far) //eye is drunk
				return -1.0;
		}
	}
	if (near < 0.0) //eye lies within the cube
	{
		fr = far;
		return 0.0;
	}
	else
	{
		fr = far;
		return near;
	}
}

float dataRead(in vec3 pos)
{
	vec4 value;
	value = texture3D(volume, pos);

	return value.a;
}

vec4 dataReadTransfer2D(in vec3 pos, in float gm)
{
	/*if (pos.y < 0.5 && pos.y > 0.4)
		return vec4(0.0);*/

	vec4 value;
	value = texture3D(volume, pos);

	//return value.a * gm;
	//return vec4(1.0, 0.0, 0.0, texture2D(Transfer2D, vec2(mix(0.0, 1.0, value.a) * 0.8, mix(0.0, 1.0, gm) * 5.0)).r * 5.2);
	//return texture1D(Transfer1D, mix(0.0, 1.0, value.a));

/*float level = 0.68;
float window = 0.5;

float a =        
       mix(
		step(level + window / 2.0, value.a),
		step(level - window / 2.0, value.a),
		(value.a - (level - window / 2.0)) / window
				);   


return a;*/

  if (value.a > 0.5)
  return 1.0;
  else
  return 0.0;
}

void main()
{
	vec4 color, background, mx; //sampled colors
	vec3 halfV,                 //half vector
		 isec0,                 //intersection
		 isec1,                 //transformed intersection
		 halfv,
		 n = vec3(0.0),         //normal
		 accumC = vec3(0.0),    //accumulated color (for DVR)
		 voxelSize = 1.0 / vec3(32.0);
	float accumA = 0.0, t, tmp, fr = 0.0, gm, nDotL;

	float firstHit = 0.0, lastHit = 0.0;

	//float mxa[50];
	int mxp = 0;

	int i, j = 0;

	color = vec4(0);
  
  size = vec3(1,1,1.0/zRatio);

	//get intersection with the bounding cube (in form of distance on the ray dir * t + eye)
	t = cube(eye, dir, size, fr);
	
	//if ray missed the cube, just return first color (at 0.0) of the transfer function (without alpha)
	if (t < 0.0)
	{
    discard;
	}

	//step size
	float stepSize = 1.0 / 512.0; //0.003

	//ray offset jittering
	t += rand() * stepSize;

	//rendering loop
	i = 0;
	while (float(i) < (fr - t) / stepSize)
	{
		i++;

		//calculate intersection along the ray
		tmp = float(i) * stepSize + t;
		isec0 = tmp * dir + eye;

		//transform it to match the bounding box centered on [0, 0, 0]
		isec1 = (isec0 / size) * 0.5 + 0.5;

    if (isec0.z < zClipping)
    {
      continue;
    }
  
		if (isec1.x < 0.0 || isec1.x > 1.0 ||
			isec1.y < 0.0 || isec1.y > 1.0 ||
			isec1.z < 0.0 || isec1.z > 1.0)
		{
			break;
		}

		if (accumA > 0.95)
		{
			break;
		}

		//n.x = dataReadTransfer2D(isec1 - vec3(voxelSize.x, 0.0, 0.0), 0.0).a - dataReadTransfer2D(isec1 + vec3(voxelSize.x, 0.0, 0.0), 0.05).a;
		//n.y = dataReadTransfer2D(isec1 - vec3(0.0, voxelSize.y, 0.0), 0.0).a - dataReadTransfer2D(isec1 + vec3(0.0, voxelSize.y, 0.0), 0.05).a;
		//n.z = dataReadTransfer2D(isec1 - vec3(0.0, 0.0, voxelSize.z), 0.0).a - dataReadTransfer2D(isec1 + vec3(0.0, 0.0, voxelSize.z), 0.05).a;
		
		n.x = dataRead(isec1 - vec3(voxelSize.x, 0.0, 0.0)) - dataRead(isec1 + vec3(voxelSize.x, 0.0, 0.0));
		n.y = dataRead(isec1 - vec3(0.0, voxelSize.y, 0.0)) - dataRead(isec1 + vec3(0.0, voxelSize.y, 0.0));
		n.z = dataRead(isec1 - vec3(0.0, 0.0, voxelSize.z)) - dataRead(isec1 + vec3(0.0, 0.0, voxelSize.z));
		
		gm = length(n);
		n = normalize(n);




		mx = dataReadTransfer2D(isec1, gm);
		mx.rgb = vec3(1.0);
		//mx.rgb = vec3(10.0 * gm, 12.0 * mx.a, 0.5) + vec3(0.3);
		//mx.rgb *= mx.a;

		//mx.a = (gm * 0.2) + (mx.a * 0.12);

		/*if (mx.a < 0.1)
			mx.a = 0.0;*/
		if (mx.a < 0.04)
			continue;


		//mx.a = mix(mx.a, mx.a * pow(gm, 1.2), 1.0);

		//mx.a *= 0.4;

		/*mxa[mxp] = mx.a;
		mxp++;
		if (mxp >= 50)
			mxp = 0;

		float sm = 0.0;
		for (j = 0; j < 50; j++)
		{
			sm += mxa[j] * 0.02;
		}

		mx.a = sm;*/




		/*if (dot(-dir, n) < 0.0)
			n = -n;*/


    vec3 position = -1.0 + 2.0 * isec1.xyz;
   

		//halfV = normalize(lightPos - isec1);
    halfV = normalize(lightPos - position);

		vec4 s = vec4(0);

		float t;
		/*for (t = 0.01; t < 0.25; t += 0.005)
		{
			s += dataReadTransfer2D(isec1 + halfV * t, gm) * (0.25 - t) * 3.5;
		}
		s /= 1.3;
		s = clamp(s, 0.0, 1.0);*/



		nDotL = max(dot(n, halfV), 0.0);



/*
		color = vec4(
vec3(
min(1.0, 0.2 + pow(0.95 * nDotL,3.0)),
min(1.0, 0.3 + pow(0.85 * nDotL,2.0)),
min(1.0, 0.4 + pow(0.65 * nDotL,2.3))
),

1.0);*/


   
   
    vec3 toFresnel = normalize(eye - position);

		float nDotL = max(dot(n, halfV), 0.0);
    
    float fresnel = pow(max(dot(n, toFresnel), 0.0), 0.5);
    
    fresnel = clamp(pow(1.0 - fresnel, 1.0), 0.0, 1.0);
    
    //fresnel = (fresnel + _depth.a)* 0.5;
    //piFresnel = fresnel;
   
    //color.rgb = vec3(0.2, 0.0, 0.0);
    color.rgb = vec3(0.8, 0.65, 0.65);

		//diffuse
    color.rgb = mix(vec3(0.0, 0.02, 0.15), color, max(0.1, nDotL));
		//specular
		color.rgb = mix(color.rgb, vec3(1.0, 1.0, 1.0), clamp(pow(nDotL, 160.0) * 1.7, 0.0, 1.0));

    //color.rgb += pow(1.0 - gm, 5.0);

    color.rgb += vec3(fresnel * 1.0);
    
    
    if (mode == 1)
    {
      color.rgb = vec3(1.0);
      color.b = fresnel;
    }





		//base color
		//color = vec4(0.9,0.9,0.9,1.0);
		//color = vec4(0.9,0.85,0.82,1.0); //skull

		/*if (mx.a < 0.4)
			color = vec4(0.7,0.1,0.1,1.0);
		else
			color = vec4(0.9,0.92,0.9,1.0);*/

		/*color = mix(vec4(0.7,0.2,0.2,1.0),
			vec4(0.9,0.92,0.9,1.0),
			smoothstep(0.3, 0.40, mx.a));*/

		//color = vec4(0.9, 0.9, 0.9, 1.0);

		//color = vec4(0.8,0.56,0.5,1.0);
		
		//ambient
		//color = mix(color, vec4(1.0), 0.1);


   //mx.a *= 0.1;
    
		//diffuse
		//color = mix(vec4(0.0, 0.02, 0.1, 1.0), color, max(0.6, nDotL));

		//specular
		//color = mix(color, vec4(1.0, 1.0, 1.0, 1.0), pow(nDotL, 30.0) * 1.5);
		
		//shadows
		//color = mix(color, vec4(0.15, 0.18, 0.22, 1.0), s.a * 1.2); //0.7);
    //color = mix(color, color * vec4(0.15, 0.18, 0.22, 1.0), s.a * 1.2);

		accumC += (1.0 - accumA) * color.rgb * mx.a;
		accumA += (1.0 - accumA) * mx.a;

		if (accumA > 0.9)
		{
			break;
		}
	}
  
	//gl_FragColor = vec4(background.rgb * (1.0 - accumA) + accumC, 1.0);
  
  gl_FragColor = vec4(accumC, accumA);
  
  
  
  vec4 veye = modelview * vec4(eye, 1.0);
  vec4 vve = modelview * vec4(ve, 1.0);
  vec3 vdir = vve.xyz - veye.xyz;
  
  
  


  vec3 posCorrected = -1.0 + 2.0 * isec1.xyz;
  posCorrected.z /= zRatio;
  
  vec4 post = projection * modelview * vec4(posCorrected.xyz, 1.0);
    
   float ndc_depth = post.z / post.w;
  
  float far = 1.0;
  float near = 0.0;
  float dddepth = (((far-near) * ndc_depth) + near + far) / 2.0;
  float newDepth = dddepth;
  
  newDepth = 0.5*(post.z / post.w)+0.5;
  
  gl_FragDepth = newDepth;
 
  if (accumA < 0.5)
  {
    gl_FragDepth = 1.0;
  }
  
  /*
  
  //vec4 pp = modelview * vec4((isec1 * 2.0 + 1.0) - eye, 1.0);

  vec4 pp = projection * modelview * vec4(isec0, 1.0);
  //pp /= pp.w; 
  
	float depth = pp.z;
  
  float depthCorrected = depth; 
	vec4 depthVec = projection * vec4(0,0,depthCorrected,1);	
	float ndcDepth = depthVec.z / depthVec.w;
	gl_FragDepth = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;
  
  float d = ((gl_DepthRange.diff * ndcDepth) + gl_DepthRange.near + gl_DepthRange.far) / 2.0;


  if (accumA < 0.5)
  {
    gl_FragDepth = 1.0;
  }
  
  gl_FragDepth = 0.5;  
  gl_FragColor = vec4(vec3(depth), 1.0);*/  
}
