#version 330

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aTex;
layout (location = 2) in vec2 aTexY;
layout (location = 3) in vec3 aOffset;
layout (location = 4) in vec2 aAnimate;
layout (location = 5) in vec3 aFlags;

out float pCameraDepth;
out vec3 pSunDepth;
out vec3 pLightMapPos;
out vec3 pTexture;
out vec2 pVertex;
out vec3 pPos;

flat out int pFlags;
flat out float pFade;
flat out int pRGB;

uniform mat4 camera;
uniform mat4 projection_sun;
uniform mat4 billboard;
uniform mat4 projection;
uniform mat4 model;
uniform mat4 rotated;
uniform float mist;
uniform int time;
uniform int mode;

float map(float x, float in_min, float in_max, float out_min, float out_max) {
	return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

mat4 translate(vec3 vec)
{
	mat4 result = mat4(1);
	
	result[0][3] = vec.x;
	result[1][3] = vec.y;
	result[2][3] = vec.z;
	
	return result;
}

float getTexY()
{
	float animate_count = aAnimate.x;
	float animate_speed = aAnimate.y;
	float animate_index = mod(time / int(animate_speed), animate_count);
	
	float tex_y_size = (aTexY.y - aTexY.x) / animate_count;
	
	float tex_y = map(
		aTex.y, aTexY.x, aTexY.y,
		aTexY.x + tex_y_size * animate_index,
		aTexY.x + tex_y_size * (animate_index + 1));

	return tex_y;
}

void main()
{
	int type = int(aFlags.z);
	
	vec4 pos = vec4(aPos, 1) * (mod(type >> 3, 2) == 1 ? billboard : (mod(type, 2) == 1 ? rotated : mat4(1))) *
		translate(aOffset) * model;
	
	gl_Position = pos * projection;
	pVertex = pos.xy / pos.w;
	
	if(mode == 0) {
		pCameraDepth = mod(type >> 4, 2) == 1 ? 0 : min(1, mist * (-(pos * camera).z * 0.5 + 0.5));
		pSunDepth = (pos * projection_sun).xyz;
		pLightMapPos = pos.xyz;
		pRGB = int(aFlags.y);
		pFade = aFlags.x;
	}
	
	pTexture = vec3(aTex.x, getTexY(), aTex.z);
	pFlags = type;
	pPos = aPos;
}