//? #version 150
#extension GL_ARB_gpu_shader5: enable

#include "shadows.sdr"

#conditional_include +"LARGE_SHADER" "main_large.sdr"
#conditional_include -"LARGE_SHADER" "main_small.sdr"

in vec4 vertPosition;
in vec4 vertTexCoord;
in vec3 vertNormal;
in vec4 vertTangent;
in float vertModelID;

#define MAX_LIGHTS 8

struct model_light {
	vec4 position;

	vec3 diffuse_color;
	int light_type;

	vec3 direction;
	float attenuation;

	float ml_sourceRadius;
};

layout (std140) uniform modelData {
	mat4 modelViewMatrix;
	mat4 modelMatrix;
	mat4 viewMatrix;
	mat4 projMatrix;
	mat4 textureMatrix;
	mat4 shadow_mv_matrix;
	mat4 shadow_proj_matrix[4];

	vec4 color;

	model_light lights[MAX_LIGHTS];

	float outlineWidth;
	float fogNear;
	float fogDensity;
	int buffer_matrix_offset;

	vec4 clip_equation;

	float thruster_scale;
	bool use_clip_plane;
	int n_lights;
	float defaultGloss;

	vec3 ambientFactor;
	int desaturate;

	vec3 diffuseFactor;
	int blend_alpha;

	vec3 emissionFactor;

	bool alphaGloss;

	bool gammaSpec;
	bool envGloss;
	int effect_num;
	int sBasemapIndex;

	vec4 fogColor;

	vec3 base_color;
	float anim_timer;

	vec3 stripe_color;
	float vpwidth;

	float vpheight;
	bool team_glow_enabled;
	float znear;
	float zfar;

	float veryneardist;
	float neardist;
	float middist;
	float fardist;

	int sGlowmapIndex;

	int sSpecmapIndex;
	int sNormalmapIndex;
	int sAmbientmapIndex;
	int sMiscmapIndex;

	float alphaMult;

	int flags;
};

#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
uniform samplerBuffer transform_tex;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM

out VertexOutput {
	mat3 tangentMatrix;

#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_FOG
	float fogDist;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_FOG

#ifdef MODEL_SDR_FLAG_SHADOW_MAP
 #if !defined(GL_ARB_gpu_shader5)
	float instance;
 #endif
	// This flag is needed to let the geometry shader know that it doesn't need to apply the
	// shadow projection to gl_Position
	float clipModel;
#else
	vec4 position;
#endif
	vec3 normal;
	vec4 texCoord;

#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
	vec4 shadowUV[4];
	vec4 shadowPos;
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_SHADOWS
} vertOut;

#define TEXELS_PER_MATRIX 4
#prereplace IF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM
void getModelTransform(inout mat4 transform, out bool invisible, int id, int matrix_offset)
{
	transform[0] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX);
	transform[1] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 1);
	transform[2] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 2);
	transform[3] = texelFetch(transform_tex, (matrix_offset + id) * TEXELS_PER_MATRIX + 3);
	invisible = transform[3].w >= 0.9;
	transform[3].w = 1.0;
}
#prereplace ENDIF_FLAG_COMPILED MODEL_SDR_FLAG_TRANSFORM

void main()
{
	vec4 position;
	vec3 normal;
	vec4 texCoord;
	mat4 orient = mat4(1.0);
	mat4 scale = mat4(1.0);
	bool clipModel = false;
	
	#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
		getModelTransform(orient, clipModel, int(vertModelID), buffer_matrix_offset);
	#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM

	texCoord = textureMatrix * vertTexCoord;
	vec4 vertex = vertPosition;
	#prereplace IF_FLAG MODEL_SDR_FLAG_THRUSTER
		if(vertex.z < -1.5) {
			vertex.z *= thruster_scale;
		}
	#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_THRUSTER
	// Transform the normal into eye space and normalize the result.
	normal = normalize(mat3(modelViewMatrix) * mat3(orient) * vertNormal);
	position = modelViewMatrix * orient * vertex;
	#ifdef MODEL_SDR_FLAG_SHADOW_MAP
		gl_Position = position;
		#if !defined(GL_ARB_gpu_shader5)
			#ifdef APPLE
				vertOut.instance = float(gl_InstanceIDARB);
			#else
				vertOut.instance = float(gl_InstanceID);
			#endif
		#endif
	#else
		gl_Position = projMatrix * position;
	#endif
	#prereplace IF_FLAG MODEL_SDR_FLAG_SHADOWS
		vec4 shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
		vertOut.shadowPos = shadow_mv_matrix * modelMatrix * orient * vertPosition;
		vertOut.shadowUV[0] = transformToShadowMap(shadow_proj_matrix[0], 0, shadowPos);
		vertOut.shadowUV[1] = transformToShadowMap(shadow_proj_matrix[1], 1, shadowPos);
		vertOut.shadowUV[2] = transformToShadowMap(shadow_proj_matrix[2], 2, shadowPos);
		vertOut.shadowUV[3] = transformToShadowMap(shadow_proj_matrix[3], 3, shadowPos);
	#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_SHADOWS

	// Setup stuff for normal maps and envmaps
	vec3 t = normalize(mat3(modelViewMatrix) * mat3(orient) * vertTangent.xyz);
	vec3 b = cross(normal, t) * vertTangent.w;
	vertOut.tangentMatrix = mat3(t, b, normal);

	#prereplace IF_FLAG MODEL_SDR_FLAG_FOG
		vertOut.fogDist = gl_Position.z - fogNear;
	#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_FOG

	#prereplace IF_FLAG MODEL_SDR_FLAG_TRANSFORM
		if (clipModel) {
			// Clip this model by moving all vertices outside the clip volume
			gl_Position = vec4(vec3(-2.0), 1.0);
		}
		#ifdef MODEL_SDR_FLAG_SHADOW_MAP
			vertOut.clipModel = clipModel ? 1.0 : 0.0;
		#endif
	#prereplace ENDIF_FLAG //MODEL_SDR_FLAG_TRANSFORM

	if(use_clip_plane) {
		gl_ClipDistance[0] = dot(clip_equation, modelMatrix * orient * vertex);
	} else {
		gl_ClipDistance[0] = 1.0;
	}

	#ifndef MODEL_SDR_FLAG_SHADOW_MAP
		vertOut.position = position;
		vertOut.normal = normal;
		vertOut.texCoord = texCoord;
	#else
		vertOut.normal = normal;
		vertOut.texCoord = texCoord;
	#endif
}
