#version 430
// vi: ft=glsl

layout(location = 0) in vec2 texture_coords;
layout(location = 0) out vec4 out_color;

layout(set = 1, binding = 0) uniform InfoBlock {
	uint format;
	uint width;
	uint height;
	uint stride_x;
	uint stride_y;
};

layout(set = 1, binding = 1) buffer Data {
	uint data[];
};

uint extract_u8(uint i) {
	uint word = data[i / 4];
	uint offset = (i % 4) * 8;
	return word >> offset & 0xFF;
}

float extract_unorm8(uint i) {
	return float(extract_u8(i)) / 255.0;
}

vec4 get_pixel(uint x, uint y) {
	uint i = x * stride_x + y * stride_y;

	// Mono8
	if (format == 0) {
		float mono = extract_unorm8(i);
		return vec4(mono, mono, mono, 1.0);

	// MonoAlpha8(Unpremultiplied)
	} else if (format == 1) {
		float mono = extract_unorm8(i);
		float a    = extract_unorm8(i + 1);
		return vec4(mono, mono, mono, a);

	// MonoAlpha8(Premultiplied)
	} else if (format == 2) {
		float a    = float(extract_u8(i + 1));
		float mono = float(extract_u8(i)) / a;
		return vec4(mono, mono, mono, a);

	// Bgr8
	} else if (format == 3) {
		float b = extract_unorm8(i + 0);
		float g = extract_unorm8(i + 1);
		float r = extract_unorm8(i + 2);
		return vec4(r, g, b, 1.0);

	// Bgra8(Unpremultiplied)
	} else if (format == 4) {
		float b = extract_unorm8(i + 0);
		float g = extract_unorm8(i + 1);
		float r = extract_unorm8(i + 2);
		float a = extract_unorm8(i + 3);
		return vec4(r, g, b, a);

	// Bgra8(Premultiplied)
	} else if (format == 5) {
		float a = float(extract_u8(i + 3));
		float b = float(extract_u8(i + 0)) / a;
		float g = float(extract_u8(i + 1)) / a;
		float r = float(extract_u8(i + 2)) / a;
		return vec4(r, g, b, a / 255.0);

	// Rgb8
	} else if (format == 6) {
		float r = extract_unorm8(i + 0);
		float g = extract_unorm8(i + 1);
		float b = extract_unorm8(i + 2);
		return vec4(r, g, b, 1.0);

	// Rgba8(Unpremultiplied)
	} else if (format == 7) {
		float r = extract_unorm8(i + 0);
		float g = extract_unorm8(i + 1);
		float b = extract_unorm8(i + 2);
		float a = extract_unorm8(i + 3);
		return vec4(r, g, b, a);

	// Rgba8(Premultiplied)
	} else if (format == 8) {
		float a = float(extract_u8(i + 3));
		float r = float(extract_u8(i + 0)) / a;
		float g = float(extract_u8(i + 1)) / a;
		float b = float(extract_u8(i + 2)) / a;
		return vec4(r, g, b, a / 255.0);

	} else {
		return vec4(1.0, 0.0, 1.0, 1.0);
	}
}

void main() {
	uint x = uint(round(texture_coords.x));
	uint y = uint(round(texture_coords.y));
	if (x >= width || y >= height) {
		out_color = vec4(0.0, 0.0, 0.0, 0.0);
	} else {
		out_color = get_pixel(x, y);
	}
}
