#version 150
#extension GL_ARB_texture_gather : enable
/// BEGIN AUTOGENERATED HEADER
#define CONC(a,b) a##b

#define IF(c, t, e) CONC(IF_, c)(t, e)

#define IF_UNDEF(t, e) e
#define IF_0(t, e) t
#define IF_1(t, e) t
#define IF_2(t, e) t
#define IF_3(t, e) t
#define IF_4(t, e) t
#define IF_5(t, e) t
#define IF_6(t, e) t
#define IF_7(t, e) t
#define IF_8(t, e) t
#define IF_9(t, e) t
#define IF_10(t, e) t
#define IF_11(t, e) t
#define IF_12(t, e) t
#define IF_13(t, e) t
#define IF_14(t, e) t
#define IF_15(t, e) t
#define IF_16(t, e) t
// Workaround for intel HD:
#define IF_00(t, e) t
#ifdef UG_COMPILE_SPIRV
	#define gl_VertexID gl_VertexIndex

	#define LAYOUT_SAMPLER2(s, b) layout(set = s, binding = b)
	#define LAYOUT_SAMPLER(s, b) layout(set = s, binding = b)
	#define LAYOUT_UBO(s, b) layout(std140, set = s, binding = b)
	#define LAYOUT_PUSH_CONSTANT() layout(push_constant, std140)
	#define LAYOUT_STORAGE(s, b) layout(std140, set = s, binding = b) readonly restrict buffer

	#define VERTEX_INPUT(loc, type, name, defaultValue) IF(loc, layout (location = loc) in type name, const type name = defaultValue)
		
	#define INPUT_MOD(loc, mod, type, name, defaultValue) IF(loc, layout (location = loc) mod in type name, const type name = defaultValue)
		
	#define INPUT(loc, type, name, defaultValue) IF(loc, layout (location = loc) in type name, const type name = defaultValue)

	#define OUTPUT(loc, type, name) IF(loc, layout (location = loc) out type name, type name)
	
	#define OUTPUT_MOD(loc, mod, type, name) IF(loc, layout (location = loc) mod out type name, type name)
	
	#define WINDING ccw

	#define LOCATION(loc) layout(location = loc) 
#else
	#extension GL_ARB_separate_shader_objects : require
	#extension GL_ARB_explicit_attrib_location : require
	#extension GL_ARB_shading_language_420pack : require

#ifdef USE_SAMPLER2
	#define LAYOUT_SAMPLER2(s, b)
#else
	#define LAYOUT_SAMPLER2(s, b) layout(binding = b)
#endif

	#define LAYOUT_SAMPLER(s, b) layout(binding = b)
	#define LAYOUT_UBO(s, b) layout(std140, binding = b)
	#define LAYOUT_PUSH_CONSTANT() layout(std140, binding = 2)
	#define LAYOUT_STORAGE(s, b) layout(std140, binding = b) buffer

	#define VERTEX_INPUT(loc, type, name, defaultValue) IF(loc, layout (location = loc) in type name, const type name = defaultValue)
		
	#define INPUT_MOD(loc, mod, type, name, defaultValue) mod in type name
		
	#define INPUT(loc, type, name, defaultValue) in type name

	#define OUTPUT(loc, type, name) out type name
	
	#define OUTPUT_MOD(loc, mod, type, name) mod out type name
	
	#define WINDING ccw

	#define LOCATION(loc)
#endif
/// END AUTOGENERATED HEADER

LAYOUT_SAMPLER(1, 26) uniform sampler2DArray detailColorArrayTex;
LAYOUT_SAMPLER(1, 27) uniform sampler2DArray detailNrmlArrayTex;
LAYOUT_SAMPLER(1, 28) uniform sampler2DArray detailGlossArrayTex;
LAYOUT_SAMPLER(1, 29) uniform sampler2DArray overlayArrayTex;

const float texpixel = 1.0/4096.0;

LAYOUT_UBO(1, 15) uniform DataBlock {
	vec4 data[255];
} u_dataBlock;

const vec3 offset = vec3(0.3, 0.3, 0.57); // min = 0, max = 0.57
const float pw = 2.0; // min = 1, max = 14

vec3 overlay(vec4 col0, vec3 col1);

vec3 transformNormal(vec3 normal) {
	normal = pow(max(vec3(.0), abs(normal) - offset), vec3(pw));
	normal = normal / (normal.x + normal.y + normal.z);
	
	return normal;
}

vec3 getLevelColor(vec3 pos, int iLevel, vec3 normal, 
		out vec2 nrml, out vec3 glossAoH, vec3 dposdx, vec3 dposdy) {
	vec3 doSizeoStrength = u_dataBlock.data[iLevel].xyz;

	pos = pos * doSizeoStrength.x;
	dposdx = dposdx * doSizeoStrength.x;
	dposdy = dposdy * doSizeoStrength.x;
	
	vec3 color = vec3(.0);
	glossAoH = vec3(.0);
	nrml = vec2(.0);
	vec3 col;
	vec4 col0;
	
	if (doSizeoStrength.z > 1000) {
		float scale = doSizeoStrength.x;
		vec2 tiles = doSizeoStrength.yz;
		tiles.y -= 1001;
		pos.xy = pos.xy * scale * texpixel + 0.5*tiles.xy;
		dposdx = dposdx * scale * texpixel;
		dposdy = dposdy * scale * texpixel;
		nrml = vec2(0.5, 0.5);
		glossAoH = vec3 (0.0, 0.2, 0.0);
		int mapx = int(floor(pos.x));
		int mapy = int(floor(pos.y));
		int idx = mapx + int(tiles.x)*mapy + iLevel;
		vec2 subp = fract(pos.xy);
		vec4 col0 = textureGrad(detailColorArrayTex, vec3(subp.xy, idx),
		dposdx.xy, dposdy.xy);
		return col0.rgb;
	}
	else
	{
		if (normal.y > 0.0) { // Sample projecting onto y-coord
			nrml += normal.y * textureGrad(detailNrmlArrayTex, vec3(pos.xz, iLevel), dposdx.xz, dposdy.xz).rg;
			col = textureGrad(overlayArrayTex, vec3(pos.xz * doSizeoStrength.y, iLevel), dposdx.xz * u_dataBlock.data[iLevel].y, dposdy.xz * u_dataBlock.data[iLevel].y).rgb;
			col0 = textureGrad(detailColorArrayTex, vec3(pos.xz, iLevel), dposdx.xz, dposdy.xz);
			col0.a = u_dataBlock.data[iLevel].z;
			color += normal.y * overlay(col0, col.rgb);
			glossAoH += normal.y * textureGrad(detailGlossArrayTex, vec3(pos.xz, iLevel), dposdx.xz, dposdy.xz).gba;
		}
		if (normal.x > 0.0) { // Sample projecting onto x-coord
			nrml += normal.x * textureGrad(detailNrmlArrayTex, vec3(pos.yz, iLevel), dposdx.yz, dposdy.yz).rg;
			col = textureGrad(overlayArrayTex, vec3(pos.yz * doSizeoStrength.y, iLevel), dposdx.yz * u_dataBlock.data[iLevel].y, dposdy.yz * u_dataBlock.data[iLevel].y).rgb;
			col0 = textureGrad(detailColorArrayTex, vec3(pos.yz, iLevel), dposdx.yz, dposdy.yz);
			col0.a = u_dataBlock.data[iLevel].z;
			color += normal.x * overlay(col0, col.rgb);
			glossAoH += normal.x * textureGrad(detailGlossArrayTex, vec3(pos.yz, iLevel), dposdx.yz, dposdy.yz).gba;
		}
		if (normal.z > 0.0) { // Sample projecting onto z-coord (vertical proj)
			nrml += normal.z * textureGrad(detailNrmlArrayTex, vec3(pos.xy, iLevel), dposdx.xy, dposdy.xy).rg;
			col = textureGrad(overlayArrayTex, vec3(pos.xy * doSizeoStrength.y, iLevel), dposdx.xy * u_dataBlock.data[iLevel].y, dposdy.xy * u_dataBlock.data[iLevel].y).rgb;
			col0 = textureGrad(detailColorArrayTex, vec3(pos.xy, iLevel), dposdx.xy, dposdy.xy);
			col0.a = u_dataBlock.data[iLevel].z;
			color += normal.z * overlay(col0, col.rgb);
			glossAoH += normal.z * textureGrad(detailGlossArrayTex, vec3(pos.xy, iLevel), dposdx.xy, dposdy.xy).gba;
		}
		glossAoH.z += u_dataBlock.data[iLevel].w;
		
		//return normal;
		return color;
	}
}
