/*#ifdef SKINNING

	#version 120
	#extension EXT_gpu_shader4 : enable          

#endif*/

#ifdef _VERSION_CHECK_
	#ifndef MSET

		#ifndef _NOT_INSTANCED_
		
			#version 120
			#extension GL_EXT_gpu_shader4 : enable          
			
		#endif
		
	#endif
#endif

#ifdef ALPHATEST

	varying float		distance;
	uniform vec2		cull;

#endif

#ifdef _HEIGHTMAP_
	
	uniform sampler2D	heightmap;
	uniform vec2		invHeightmapSize;
	uniform vec2		tileDim;
	//uniform vec3		tilePos;	// tilepos
	uniform vec3		terrainDim; // width, depth and height of the terrain
 	
	uniform samplerBuffer		WorldPoses;

	varying vec3		eye0,
						eye1,
						eye2;
#else

	#ifdef SKINNING

	/*	uniform mat3 	boneMatrices[100],
						prevBoneMatrices[100];
		*/				
		uniform samplerBuffer 	boneMatrices;
		uniform samplerBuffer 	prevBoneMatrices;
		attribute vec4 		 	weights;
		attribute vec4  		matrixIndices;

		varying vec3	eye0,
						eye1,
						eye2;
						
	#else
	
		#ifdef PSYSTEM

			uniform	vec4 	pparams[100]; 
			uniform vec4	prevPParams[100];
			
			vec4			tpos;
			uniform vec4	data;

			attribute vec4	index;
			varying float 	life;

			uniform vec2	tofs;			// cambiare in uniform
			uniform vec2	tscale;
			//varying vec4	pnormal;
			varying float	cosa,
							sina;
	
		#else

			#ifdef BSET

				//uniform	mat4 	pparams[100];
				
				//uniform float pparams[1000];
				uniform 		samplerBuffer 	pparams;
				//uniform vec4 pparams[300];
				vec4			tpos;
				uniform vec4	data;
				attribute vec4	index;
				varying vec4	pnormal;
				varying vec3 	pcolor;
				
				uniform vec3	campos;
				uniform vec3 	prevcampos;
				
			#else
	
				#ifdef MSET

					uniform	mat4 	pparams[64];
					
					vec4			tpos;
					attribute vec3 	index;
					//varying vec3 	pcolor;
				
				#else
				
					#ifndef _NOT_INSTANCED_
					
						uniform samplerBuffer 		WorldPoses;
						uniform samplerBuffer 		prevWorldPoses;
					
					#endif
					
				#endif
		
				varying vec3	eye0,
								eye1,
								eye2;

			#endif

		#endif
						
	#endif
	
#endif

varying vec2 			texcoord;

attribute vec3 			normal,
						tangent,
						binormal; 

vec4 					outNormal,
						outTangent,
						outBinormal; 

varying vec4 	curpos,
				pos, 
				prev;
uniform mat4	prevMVM,
				WTM;
uniform vec2	NF;
	
vec2 ComputeFrame(float dt, vec2 nf)
{
	vec2 ofs=vec2(1.0,1.0)/nf;
	float frame=floor(dt*nf.x*nf.y);
	float row=floor(frame/nf.x);
	float col=floor(frame-nf.x*row);
	
	return vec2(ofs.x*col, 1.0-(ofs.y*row)-ofs.y);
}

void main()
{

#ifdef _HEIGHTMAP_

	// compute position basing on heightmap
	vec4 	position00 = gl_Vertex,
			position10 = gl_Vertex,
			position01 = gl_Vertex;
		
	mat4 MTX;
	int index=gl_InstanceID*4;
	MTX[0]=texelFetchBuffer(WorldPoses,index);
	MTX[1]=texelFetchBuffer(WorldPoses,index+1);
	MTX[2]=texelFetchBuffer(WorldPoses,index+2);
	MTX[3]=texelFetchBuffer(WorldPoses,index+3);
	vec3 tilepos=MTX[3].xyz;
	texcoord = ((gl_Vertex.xz + tilepos.xz)/terrainDim.xz)+vec2(0.5,0.5)+(invHeightmapSize*0.5);
	
	position00.y=(texture2D(heightmap,texcoord.st).x-0.5)*terrainDim.y;
	position00.xz=gl_Vertex.xz;
	position10.y=(texture2D(heightmap,texcoord.st + vec2(invHeightmapSize.x,0.0)).x-0.5)*terrainDim.y;
	position10.xz=gl_Vertex.xz + vec2(tileDim.x,0.0);
	position01.y=(texture2D(heightmap,texcoord.st + vec2(0.0,invHeightmapSize.y)).x-0.5)*terrainDim.y;
	position01.xz=gl_Vertex.xz + vec2(0.0,tileDim.y);
	
	vec4 position;
	position.xyz=tilepos+position00.xyz;
	position.w=1.0;
	
	// transform position in projection and eye space
	//vec3 position=MTX*position00;
	gl_Position = gl_ModelViewProjectionMatrix * position;
	pos=gl_ModelViewMatrix*position;
	
	// compute previous position for motion blur
	mat4 MVP=gl_ProjectionMatrix*prevMVM;//*WTM;	
	prev=MVP*position;
	
	// compute normals (convert heightmap into normalmap
	binormal4.xyz=normalize(position00.xyz-position10.xyz);
	tangent4.xyz=normalize(position00.xyz-position01.xyz);
	normal4.xyz=cross(tangent4.xyz,binormal4.xyz);
	binormal4.xyz=cross(normal4.xyz,vec3(1.0,0.0,0.0));
	tangent4.xyz=cross(binormal4.xyz,normal4.xyz);
	
	outNormal=gl_ModelViewMatrix*normal4;
	outTangent=gl_ModelViewMatrix*tangent4;
	outBinormal=gl_ModelViewMatrix*binormal4; 

	eye0=vec3(outTangent.x,outBinormal.x,outNormal.x);
	eye1=vec3(outTangent.y,outBinormal.y,outNormal.y);
	eye2=vec3(outTangent.z,outBinormal.z,outNormal.z);
	
	curpos=gl_Position;

#else

	vec4 normal4      	= vec4( normal.xyz, 0.0 );
	vec4 binormal4      = vec4( binormal.xyz, 0.0 );
	vec4 tangent4   = vec4(cross(binormal4.xyz,normal4.xyz),0.0);
	binormal4.xyz*=binormal.w;
  
	#ifdef SKINNING

		vec4 index  		= matrixIndices;
		vec4 weight 		= weights;
		vec4 position   	= vec4( 0.0, 0.0, 0.0, 0.0 );
		vec4 tempNormal  	= vec4( 0.0, 0.0, 0.0, 0.0 );
		vec4 tempTangent  	= vec4( 0.0, 0.0, 0.0, 0.0 );
		vec4 tempBinormal  	= vec4( 0.0, 0.0, 0.0, 0.0 );
		vec4 prevpos 		= vec4( 0.0, 0.0, 0.0, 0.0 );
		
		mat4 TM=mat4(	0.0,0.0,0.0,0.0,
						0.0,0.0,0.0,0.0,
						0.0,0.0,0.0,0.0,
						0.0,0.0,0.0,1.0);
		mat4 pTM=mat4(	0.0,0.0,0.0,0.0,
						0.0,0.0,0.0,0.0,
						0.0,0.0,0.0,0.0,
						0.0,0.0,0.0,1.0);

		int j;
		for( int i = 0; i < 4; i++ )
		{
				// Apply influence of bone i
				j=int(index[i]*4);
				TM[0].xyz=texelFetchBuffer(boneMatrices,j).xyz;
				TM[1].xyz=texelFetchBuffer(boneMatrices,j+1).xyz;
				TM[2].xyz=texelFetchBuffer(boneMatrices,j+2).xyz;
				TM[3].xyz=texelFetchBuffer(boneMatrices,j+3).xyz;
				
				pTM[0].xyz=texelFetchBuffer(prevBoneMatrices,j).xyz;
				pTM[1].xyz=texelFetchBuffer(prevBoneMatrices,j+1).xyz;
				pTM[2].xyz=texelFetchBuffer(prevBoneMatrices,j+2).xyz;
				pTM[3].xyz=texelFetchBuffer(prevBoneMatrices,j+3).xyz;
				
				//j+=4;
				
				position = position + (TM * gl_Vertex) *weight[i];
				prevpos = prevpos + ( (pTM*gl_Vertex) * weights[i] );
			
					
		//	TM=boneMatrices[int(index[i])];
			//	position = position + (TM * gl_Vertex) *weight[i];
		//	prevpos = prevpos + ((prevBoneMatrices[int(index[i])] * gl_Vertex) * weights[i]);
		
			// Transform normals by bone i
			TM[3]=vec4(0,0,0,1);
			tempNormal = tempNormal + (TM * normal4)*weight[i];
			tempBinormal = tempBinormal + (TM * binormal4)*weight[i];
			tempTangent = tempTangent + (TM * tangent4)*weight[i];
		}
		gl_Position = gl_ModelViewProjectionMatrix * position;
		prev = gl_ProjectionMatrix*prevMVM*prevpos;	
		pos = (gl_ModelViewMatrix * position);

		normal4=tempNormal;
		tangent4=tempTangent;
		binormal4=tempBinormal;
		
		texcoord = gl_MultiTexCoord0.st;
		curpos=gl_Position;	
		
		outNormal=gl_ModelViewMatrix*normal4;
		outTangent=gl_ModelViewMatrix*tangent4;
		outBinormal=gl_ModelViewMatrix*binormal4; 

		normalize(outNormal);
		normalize(outTangent);
		normalize(outBinormal);

		eye0=vec3(outTangent.x,outBinormal.x,outNormal.x);
		eye1=vec3(outTangent.y,outBinormal.y,outNormal.y);
		eye2=vec3(outTangent.z,outBinormal.z,outNormal.z);
		
	#else

		#ifdef PSYSTEM

			vec4 ppos=pparams[int(index.x)];
			life=clamp(ppos.w,0.0,1.0);
			float scale=data.x + (data.y*(1.0-life));
			scale=clamp(scale,0.0,abs(scale))*0.5;
			scale+=scale*index.y;	
			ppos.w=1.0;

			float angle=(index.y*6.28)+(data.z*(1.0-life)*6.28);

			cosa=cos(angle);
			sina=sin(angle);

			tpos=gl_ModelViewMatrix * ppos;	
			
			vec3 tv=gl_Vertex.xyz;
			tv.x=(gl_Vertex.x*cosa)-(gl_Vertex.y*sina);
			tv.y=(gl_Vertex.x*sina)+(gl_Vertex.y*cosa);
			tpos.xyz=(tv.xyz*scale + tpos.xyz);

			gl_Position=gl_ProjectionMatrix*tpos;
			
			//tofs=vec2(0.0,0.0);//ComputeFrame(1.0-life, NF);
			texcoord = gl_MultiTexCoord0.st*tscale;// + tofs;	

			curpos=gl_Position;		
			pos=tpos;
			
			ppos=prevPParams[int(index.x)];
			scale=data.x + (data.y*(1.0-life));
			scale=clamp(scale,0.0,abs(scale))*0.5;
			scale+=scale*index.y;	
			ppos.w=1.0;

			tpos=prevMVM*ppos;	
			tpos.xyz=(tv.xyz*scale + tpos.xyz);
			prev=gl_ProjectionMatrix*tpos;
			
		#else

			#ifdef BSET

			/*	mat4 PTM=gl_ModelViewMatrix;
				PTM[3]=vec4(0,0,0,1);

				vec4 ppos=pparams[index.x][0];
				ppos.w=1.0;
				
				mat3 rTM;
				vec3 up=vec3(0,1,0);
				campos.y=ppos.y;
				rTM[2]=normalize(campos-ppos.xyz);
				rTM[0]=cross(up,rTM[2]);
				rTM[1]=up;
				
				float scale=clamp(pparams[index.x][3].x,0.0,abs(pparams[index.x][3].x))*0.5*index.y;
				vec4 rpos=gl_Vertex*scale;
				rpos.xyz=(rTM*rpos.xyz) + ppos.xyz;
				rpos.w=1.0;
				tpos=gl_ModelViewMatrix*rpos;
				gl_Position=gl_ProjectionMatrix*tpos;	
				curpos=gl_Position;	
				pos=tpos;
				
				// compute prev pos
				prev=prevMVM*rpos;
				
				pnormal=PTM * pparams[index.x][2];
				texcoord = gl_MultiTexCoord0.st;	
				pcolor=pparams[index.x][1].xyz;
				*/
				
				/*mat4 PTM=gl_ModelViewMatrix;
				PTM[3]=vec4(0,0,0,1);

				int i=int(index.x)*10;
				vec4 ppos;
				ppos.x=pparams[i];
				ppos.y=pparams[i+1];
				ppos.z=pparams[i+2];
				ppos.w=1.0;
				
				float scale=clamp(pparams[i+9],0.0,abs(pparams[i+9]))*0.5*index.y;
				tpos=gl_ModelViewMatrix * ppos;	
				tpos.xyz=(gl_Vertex.xyz*scale + tpos.xyz);
				gl_Position=gl_ProjectionMatrix*tpos;	
				curpos=gl_Position;	
				pos=tpos;
				
				// compute prev pos
				tpos=prevMVM * ppos;	
				tpos.xyz=(gl_Vertex.xyz*scale + tpos.xyz);
				prev=gl_ProjectionMatrix*tpos;
				
				pnormal.x=pparams[i+6];
				pnormal.y=pparams[i+7];
				pnormal.z=pparams[i+8];
				pnormal.w=1.0;
				pnormal=PTM * pnormal;
				texcoord = gl_MultiTexCoord0.st;	
				pcolor.r=pparams[i+3];
				pcolor.g=pparams[i+4];
				pcolor.b=pparams[i+5];*/
				
				mat4 PTM=gl_ModelViewMatrix;
				PTM[3]=vec4(0,0,0,1);

				int i=int(index.x)*3;
				vec4 ppos;
				ppos.xyz=texelFetchBuffer(pparams,i).xyz;
				ppos.w=1.0;
				pcolor=texelFetchBuffer(pparams,i+1).xyz;	
				
				normal4=texelFetchBuffer(pparams,i+2);
				float scale=clamp( normal4.w,0.0,abs(normal4.w) )*0.5*index.y;
				
				tpos=gl_ModelViewMatrix * ppos;	
				tpos.xyz=(gl_Vertex.xyz*scale + tpos.xyz);
				gl_Position=gl_ProjectionMatrix*tpos;	
				curpos=gl_Position;	
				pos=tpos;
				
				// compute prev pos
				tpos=prevMVM * ppos;	
				tpos.xyz=(gl_Vertex.xyz*scale + tpos.xyz);
				prev=gl_ProjectionMatrix*tpos;
				
				pnormal.xyz=normal4.xyz;
				pnormal.w=1.0;
				pnormal=PTM * pnormal;
				texcoord = gl_MultiTexCoord0.st;	
				
			#else
			
				#ifdef MSET

					mat4 mtx=pparams[index.x];
					
					tpos=(gl_ModelViewMatrix * mtx) * gl_Vertex;	
					gl_Position=gl_ProjectionMatrix*tpos;	
					curpos=gl_Position;	
					pos=tpos;
					
					// compute prev pos
					tpos=(prevMVM * mtx) * gl_Vertex;	
					prev=gl_ProjectionMatrix*tpos;
					
					texcoord = gl_MultiTexCoord0.st;	
					//pcolor=pparams[index.x][1].xyz;

					tangent4.xyz=cross(normal4.xyz,binormal4.xyz);
					
					outNormal=gl_ModelViewMatrix*normal4;
					outTangent=gl_ModelViewMatrix*tangent4;
					outBinormal=gl_ModelViewMatrix*binormal4; 

					normalize(outNormal);
					normalize(outTangent);
					normalize(outBinormal);

					eye0=vec3(outTangent.x,outBinormal.x,outNormal.x);
					eye1=vec3(outTangent.y,outBinormal.y,outNormal.y);
					eye2=vec3(outTangent.z,outBinormal.z,outNormal.z);
					
				#else
			
					#ifndef _NOT_INSTANCED_
					
						mat4 MTX;
						int index=gl_InstanceID*4;
						MTX[0]=texelFetchBuffer(WorldPoses,index);
						MTX[1]=texelFetchBuffer(WorldPoses,index+1);
						MTX[2]=texelFetchBuffer(WorldPoses,index+2);
						MTX[3]=texelFetchBuffer(WorldPoses,index+3);
						
						mat4 prevMTX;
						prevMTX[0]=texelFetchBuffer(prevWorldPoses,index);
						prevMTX[1]=texelFetchBuffer(prevWorldPoses,index+1);
						prevMTX[2]=texelFetchBuffer(prevWorldPoses,index+2);
						prevMTX[3]=texelFetchBuffer(prevWorldPoses,index+3);
					
						gl_Position = (gl_ModelViewProjectionMatrix*MTX)*gl_Vertex;//ftransform();
						
						MTX=gl_ModelViewMatrix*MTX;
						pos=(MTX*gl_Vertex);
						
						mat4 MVP=gl_ProjectionMatrix*prevMVM*prevMTX;
						prev=MVP*gl_Vertex;
						texcoord = gl_MultiTexCoord0.st;		
						curpos=gl_Position;
						
						
						outNormal=MTX*normal4;
						outTangent=MTX*tangent4;
						outBinormal=MTX*binormal4; 
					
					#else
					
						gl_Position = ftransform();
						pos=(gl_ModelViewMatrix * gl_Vertex);
						mat4 MVP=gl_ProjectionMatrix*prevMVM*WTM;
						prev=MVP*gl_Vertex;
						texcoord = gl_MultiTexCoord0.st;		
						curpos=gl_Position;
						
						outNormal=gl_ModelViewMatrix*normal4;
						outTangent=gl_ModelViewMatrix*tangent4;
						outBinormal=gl_ModelViewMatrix*binormal4; 

					#endif

					eye0=vec3(outTangent.x,outBinormal.x,outNormal.x);
					eye1=vec3(outTangent.y,outBinormal.y,outNormal.y);
					eye2=vec3(outTangent.z,outBinormal.z,outNormal.z);
					
				#endif
			
			#endif
			
		#endif
		
	#endif
	
#endif

#ifdef ALPHATEST
	//float dist=(gl_Position.z-100.0)*0.0003;
	float dist=(/*gl_Position.z*/length(pos)-cull.x)/(cull.y-cull.x);
	distance=1.0 - (clamp(dist,0.0,1.0));
#endif
			
			
}