#version 450

#ifdef USE_TX2
#define USE_TX1
#endif

#ifdef USE_CL2
#define USE_CL1
#endif

#if defined (USE_FOG) || defined (USE_ENT_COLOR)
layout(set = 0, binding = 0) uniform UBO {
	// light/env parameters:
	vec4 eyePos;				// vertex
#ifdef USE_ENT_COLOR
	vec4 ent_color0;			// fragment: ent.color[0]
	vec4 ent_color1;			// fragment: ent.color[1]
	vec4 ent_color2;			// fragment: ent.color[2]
#else
	vec4 lightPos;				// vertex: light origin
	vec4 lightColor;			// fragment: rgb + 1/(r*r)
	vec4 lightVector;			// fragment: linear dynamic light
#endif
//#ifdef USE_FOG
	// fog parameters:
	vec4 fogDistanceVector;		// vertex
	vec4 fogDepthVector;		// vertex
	vec4 fogEyeT;				// vertex
	vec4 fogColor;				// fragment
//#endif
};
#endif

layout(set = 1, binding = 0) uniform sampler2D texture0;
#ifdef USE_TX1
layout(set = 2, binding = 0) uniform sampler2D texture1;
#endif
#ifdef USE_TX2
layout(set = 3, binding = 0) uniform sampler2D texture2;
#endif
#ifdef USE_FOG
layout(set = 4, binding = 0) uniform sampler2D fog_texture;
#endif

#if defined (USE_CLX_IDENT)
// fixed identity (1.0) color for all textures
#else
#if defined (USE_FIXED_COLOR) || defined(USE_ENT_COLOR)
// use fixed color from spec.constant.8 or entColor[0..2]
#else
layout(location = 0) in vec4 frag_color0;
#endif

#ifdef USE_CL1
layout(location = 5) in vec4 frag_color1;
#endif
#ifdef USE_CL2
layout(location = 6) in vec4 frag_color2;
#endif
#endif

layout(location = 1) centroid in vec2 frag_tex_coord0;
#ifdef USE_TX1
layout(location = 2) centroid in vec2 frag_tex_coord1;
#endif
#ifdef USE_TX2
layout(location = 3) centroid in vec2 frag_tex_coord2;
#endif
#ifdef USE_FOG
layout(location = 4) in vec2 fog_tex_coord;
#endif

#ifdef USE_DF
layout(depth_less) out float gl_FragDepth;
#else
layout(location = 0) out vec4 out_color;
#endif

#ifdef USE_ATEST
layout (constant_id = 0) const int alpha_test_func = 0;
layout (constant_id = 1) const float alpha_test_value = 0.0;
#ifdef USE_DF
layout (constant_id = 2) const float depth_fragment = 0.85;
#endif
#endif

layout (constant_id = 3) const int alpha_to_coverage = 0;
//layout (constant_id = 4) const int color_mode = 0;
//layout (constant_id = 5) const int abs_light = 0;
#if defined (USE_TX1) || defined(USE_TX2)
layout (constant_id = 6) const int tex_mode = 0; // modulate, add (identity), add(non-identity) etc
#endif
layout (constant_id = 7) const int discard_mode = 0;

#ifdef USE_FIXED_COLOR
layout (constant_id = 8) const float identity_color = 1.0;
layout (constant_id = 9) const float identity_alpha = 1.0;
#endif

#ifdef USE_FOG
layout (constant_id = 10) const int acff = 0; // NONE, RGB, RGBA, ALPHA
#endif

#ifdef USE_ATEST
#if 0
float CorrectAlpha(float threshold, float alpha, vec2 tc)
{
	ivec2 ts = textureSize(texture0, 0);
	float dx = max(abs(dFdx(tc.x * float(ts.x))), 0.001);
	float dy = max(abs(dFdy(tc.y * float(ts.y))), 0.001);
	float dxy = max(dx, dy); // apply the smallest boost
	float scale = max(1.0 / dxy, 1.0);
	float ac = threshold + (alpha - threshold) * scale;
	return ac;
}
#endif
#endif

void main() {
#ifdef USE_FOG
	vec4 fog = texture(fog_texture, fog_tex_coord);
#endif

#if defined (USE_CLX_IDENT)
	vec4 color0 = texture(texture0, frag_tex_coord0);
#elif defined (USE_FIXED_COLOR)
	const vec4 frag_color = vec4(identity_color, identity_color,identity_color, identity_alpha);
	vec4 color0 = texture(texture0, frag_tex_coord0) * frag_color;
#elif defined (USE_ENT_COLOR)
	vec4 color0 = texture(texture0, frag_tex_coord0) * ent_color0;
#else
	vec4 color0 = texture(texture0, frag_tex_coord0) * frag_color0;
#endif
	vec4 base;

	// triple-texture with non-identity colors in color1 and color2
#if defined (USE_TX2)
#ifdef USE_CL2
	// special blend modes for non-identity colors
	if ( tex_mode == 1 || tex_mode == 2 )
	{
		// add
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif

		base = vec4( color0.rgb + color1.rgb + color2.rgb, color0.a * color1.a * color2.a );
	}
	else if ( tex_mode == 3 )
	{
		// modulate by alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif
		color0 *= color0.a;
		color1 *= color1.a;
		color2 *= color2.a;
		base = vec4( color0.rgb + color1.rgb + color2.rgb, color0.a * color1.a * color2.a );
	}
	else if ( tex_mode == 4 )
	{
		// modulate by 1.0-alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif
		color0 *= 1.0-color0.a;
		color1 *= 1.0-color1.a;
		color2 *= 1.0-color2.a;
		base = vec4( color0.rgb + color1.rgb + color2.rgb, color0.a * color1.a * color2.a );
	}
	else if ( tex_mode == 5 )
	{
		// mix by src alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif
		//base = mix( color0, color1, color1.a );
		//base = mix( base, color2, color2.a );
		base = mix( mix( color0, color1, color1.a ), color2, color2.a );
	}
	else if ( tex_mode == 6 )
	{
		// mix by 1-src alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif
		//base = mix( color1, color0, color1.a );
		//base = mix( color2, base, color2.a );
		base = mix( color2, mix( color1, color0, color1.a ), color2.a );
	}
	else if ( tex_mode == 7 ) // 0 + 2x GLS_DSTBLEND_SRC_ALPHA | GLS_SRCBLEND_DST_COLOR
	{
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif
		base = (color2 + color2.a) * (color1 + color1.a) * color0;
	}
	else
	{
		// default case, modulate
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color2;
#endif
		base = color0 * color1 * color2;
	}
#else // !USE_CL2
	// triple-texture with identity colors (1.0) in color1 and color2
	if ( tex_mode == 1 )
	{
		// add (identity color0 == 1.0)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
		base = vec4(color0.rgb + color1.rgb + color2.rgb, color0.a * color1.a * color2.a);
	}
	else if ( tex_mode == 2 )
	{
		// add (color0 != 1.0)
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
		vec4 color2 = texture(texture2, frag_tex_coord2) * ent_color2;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color0;
		vec4 color2 = texture(texture2, frag_tex_coord2) * frag_color0;
#endif
		base = vec4(color0.rgb + color1.rgb + color2.rgb, color0.a * color1.a * color2.a);
	}
	else 
	{
		// default case, modulate
		vec4 color1 = texture(texture1, frag_tex_coord1);
		vec4 color2 = texture(texture2, frag_tex_coord2);
		base = color0 * color1 * color2;
	}
#endif // !USE_TX2
#elif defined(USE_TX1)
	// double-texture with non-identity colors in color1
#ifdef USE_CL1
	// special blend modes for non-identity colors
	if ( tex_mode == 1 || tex_mode == 2 )
	{
		// add
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		base = vec4( color0.rgb + color1.rgb, color0.a * color1.a );
	}
	else if ( tex_mode == 3 ) // 2x GLS_DSTBLEND_ONE | GLS_SRCBLEND_SRC_ALPHA
	{
		// modulate by alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		color0 *= color0.a;
		color1 *= color1.a;
		base = vec4( color0.rgb + color1.rgb, color0.a * color1.a );
	}
	else if ( tex_mode == 4 ) // 2x GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA
	{
		// modulate by 1.0-alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		color0 *= 1.0-color0.a;
		color1 *= 1.0-color1.a;
		base = vec4( color0.rgb + color1.rgb, color0.a * color1.a );
	}
	else if ( tex_mode == 5 ) // 0 + GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA
	{
		// mix by src alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		base = mix( color0, color1, color1.a );
	}
	else if ( tex_mode == 6 ) // 0 + GLS_DSTBLEND_SRC_ALPHA | GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA
	{
		// mix by 1-src alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		base = mix( color1, color0, color1.a );
	}
	else if ( tex_mode == 7 ) // 0 + GLS_DSTBLEND_SRC_ALPHA | GLS_SRCBLEND_DST_COLOR
	{
		// modulate color1 by color0
		// moduleta color0 by color1.alpha
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		base = (color1 + color1.a) * color0;
	}
	else
	{
		// default case, modulate
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color1;
#endif
		base = color0 * color1;
	}
#else
	// double-texture with identity colors (1.0) in color1
	if ( tex_mode == 1 )
	{
		// add (identity)
		vec4 color1 = texture(texture1, frag_tex_coord1);
		base = vec4(color0.rgb + color1.rgb, color0.a * color1.a);
	}
	else if ( tex_mode == 2 )
	{
		// add
#if defined (USE_CLX_IDENT)
		vec4 color1 = texture(texture1, frag_tex_coord1);
#elif defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color0;
#endif
		base = vec4(color0.rgb + color1.rgb, color0.a * color1.a);
	}
	else // default case
	{
		// modulate
#if defined (USE_FIXED_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * frag_color;
#elif defined (USE_ENT_COLOR)
		vec4 color1 = texture(texture1, frag_tex_coord1) * ent_color1;
#else
		vec4 color1 = texture(texture1, frag_tex_coord1);
#endif
		base = color0 * color1;
	}
#endif // !USE_CL1
#endif // !USE_TX1

#ifdef USE_ATEST
#if 0
	if (alpha_to_coverage != 0) {
		if (alpha_test_func == 1) {
			base.a =  base.a > 0.0 ? 1.0 : 0.0;
		} else if (alpha_test_func == 2) {
			base.a = CorrectAlpha(alpha_test_value, 1.0 - base.a, frag_tex_coord0);
		} else if (alpha_test_func == 3) {
			base.a = CorrectAlpha(alpha_test_value, base.a, frag_tex_coord0);
		}
	} else
#endif
	// specialization: alpha-test function
	if (alpha_test_func == 1) {
		if (color0.a == alpha_test_value) discard;
	} else if (alpha_test_func == 2) {
		if (color0.a >= alpha_test_value) discard;
	} else if (alpha_test_func == 3) {
		if (color0.a < alpha_test_value) discard;
	}
#endif

#if !defined(USE_TX1) && !defined(USE_TX2)
	base = color0;
#endif

#ifdef USE_FOG
	if ( acff == 1 ) {
		// ACFF_RGB
		base.rgb = base.rgb * (1.0 - fog.w);
	} else if ( acff == 2 ) {
		// ACFF_RGBA
		base = base * (1.0 - fog.w);
	} else if ( acff == 3 ) {
		// ACFF_ALPHA
		base.a = base.a * (1.0 - fog.w);
	} else {
		// default: ACFF_NONE
		base = mix( base, fog * fogColor, fog.a );
	}
#endif

	if ( discard_mode == 1 ) {
		if ( base.a == 0.0 ) {
			discard;
		}
	} else if ( discard_mode == 2 ) {
		if ( dot( base.rgb, base.rgb ) == 0.0 ) {
			discard;
		}
	}

#ifdef USE_DF
	if ( base.a < depth_fragment )
		discard;

	gl_FragDepth = gl_FragCoord.z;
#else
	out_color = base;
#endif
}
