/*****************************************************************************
The Dark Mod GPL Source Code

This file is part of the The Dark Mod Source Code, originally based
on the Doom 3 GPL Source Code as published in 2011.

The Dark Mod Source Code is free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version. For details, see LICENSE.TXT.

Project: The Dark Mod (http://www.thedarkmod.com/)

******************************************************************************/
#version 140

// same as TiledCustomMipmapStage::MipmapMode
#pragma tdm_define "MIPMAP_MODE"
// set to 1 if we fill first level from user's source texture
#pragma tdm_define "MIPMAP_FIRST"
// set to number of first lod levels we want to skip
#pragma tdm_define "MIPMAP_SKIP"


// destination mipmap level we need to fill
uniform int u_level;
// for all fetches from source texture, clamp texcoords to this region
// specified as (x1, y1, x2, y2) in pixels (inclusive)
uniform ivec4 u_clampRegion;

ivec2 clampPixelCoords(ivec2 pixelCoords) {
	return clamp(pixelCoords, u_clampRegion.xy, u_clampRegion.zw);
}

// "sample" function returns contents of texture by given pixel coords
#if MIPMAP_FIRST
	#if MODE == 0   // MM_STENCIL_SHADOW
		uniform usampler2D u_sourceTexture;
	#else
		//TODO
		uniform sampler2D u_sourceTexture;
	#endif

	vec4 sample(ivec2 pixelCoords) {
		// fetch from base LOD level
		return vec4(texelFetch(u_sourceTexture, clampPixelCoords(pixelCoords), 0));
	}
#else
	uniform sampler2D u_mipmapTexture;

	vec4 sample(ivec2 pixelCoords) {
		// fetch from previous LOD level
		return texelFetch(u_mipmapTexture, clampPixelCoords(pixelCoords), u_level - 1 - MIPMAP_SKIP);
	}
#endif


// each mode defines behavior via 3 functions:
//   "convertInitial" --- given a raw source texel, computes cooked value for it (the one stored in mipmaps)
//   "combine" --- given cooked values of 4 texels, computes combined cooked value in next LOD level
//   "combineBilinear" --- given simple cooked value sampled from the center of 2x2 texel block, computes combined cooked value in next LOD level
//                         note: define CAN_COMBINE_BILINEAR if this function can be implmented
#if MODE == 0
	float detail_normalizeBoolean(float v) {
		return (v > 0.0 && v < 1.0 ? 0.5 : v);
	}

	vec4 convertInitial(vec4 data) {
		return vec4(data.r <= 128.1);     // 128 or less = lit
	}
	vec4 combine(vec4 a, vec4 b, vec4 c, vec4 d) {
		return vec4(detail_normalizeBoolean((a.r + b.r + c.r + d.r) * 0.25));
	}
#else
	//TODO
#endif


out vec4 FragColor;

void main() {
	ivec2 pixelCoords = ivec2(gl_FragCoord.xy);

	#if MIPMAP_FIRST
		#if MIPMAP_SKIP == 0
			// take raw pixel from source
			FragColor = convertInitial(sample(pixelCoords));
		#elif MIPMAP_SKIP == 1
			// don't rely on filtering (especially for stencil texture)
			// just fetch 4 raw pixels individually, and combine their values
			FragColor = combine(
				convertInitial(sample(2 * pixelCoords + ivec2(0, 0))),
				convertInitial(sample(2 * pixelCoords + ivec2(1, 0))),
				convertInitial(sample(2 * pixelCoords + ivec2(0, 1))),
				convertInitial(sample(2 * pixelCoords + ivec2(1, 1)))
			);
		#elif MIPMAP_SKIP == 2
			// don't rely on filtering (especially for stencil texture)
			// just fetch 16 raw pixels individually, and combine their values
			vec4 p0 = combine(
				convertInitial(sample(4 * pixelCoords + ivec2(0, 0))),
				convertInitial(sample(4 * pixelCoords + ivec2(1, 0))),
				convertInitial(sample(4 * pixelCoords + ivec2(0, 1))),
				convertInitial(sample(4 * pixelCoords + ivec2(1, 1)))
			);
			vec4 p1 = combine(
				convertInitial(sample(4 * pixelCoords + ivec2(2, 0))),
				convertInitial(sample(4 * pixelCoords + ivec2(3, 0))),
				convertInitial(sample(4 * pixelCoords + ivec2(2, 1))),
				convertInitial(sample(4 * pixelCoords + ivec2(3, 1)))
			);
			vec4 p2 = combine(
				convertInitial(sample(4 * pixelCoords + ivec2(0, 2))),
				convertInitial(sample(4 * pixelCoords + ivec2(1, 2))),
				convertInitial(sample(4 * pixelCoords + ivec2(0, 3))),
				convertInitial(sample(4 * pixelCoords + ivec2(1, 3)))
			);
			vec4 p3 = combine(
				convertInitial(sample(4 * pixelCoords + ivec2(2, 2))),
				convertInitial(sample(4 * pixelCoords + ivec2(3, 2))),
				convertInitial(sample(4 * pixelCoords + ivec2(2, 3))),
				convertInitial(sample(4 * pixelCoords + ivec2(3, 3)))
			);
			FragColor = combine(p0, p1, p2, p3);
		#else
			TODO: not implemented yet
		#endif
	#else
		// fetch 4 cooked pixels individually, and combine their values
		FragColor = combine(
			sample(2 * pixelCoords + ivec2(0, 0)),
			sample(2 * pixelCoords + ivec2(1, 0)),
			sample(2 * pixelCoords + ivec2(0, 1)),
			sample(2 * pixelCoords + ivec2(1, 1))
		);
	#endif
}
