Shader "CrispyPin/QRCode" {
Properties {
	[HideInInspector]
	_("",2D)=""
	_Version("Version", Integer) = 1
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 100
CGPROGRAM
	#pragma surface s Standard
	struct Input{float2 uv_;};
	uint _Version;

	#define VERSION _Version
	#define WIDTH (17 + VERSION * 4)
	#define ALIGNERS ((VERSION / 7) + 2)
	#define ALIGNER_SPACING ((WIDTH - 13) / (ALIGNERS-1))
	#define MISALIGNMENT ((WIDTH - 13) % (ALIGNERS-1))

	#define EC_LEVEL_L 1
	#define EC_LEVEL_M 0
	#define EC_LEVEL_Q 3
	#define EC_LEVEL_H 2

	#define EC_LEVEL EC_LEVEL_L
	#define MASK_TYPE 1

	static const uint FORMAT_BIT_SETS[32] = {0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed};
	#define FORMAT_BITS_RAW ((EC_LEVEL << 3) | MASK_TYPE)
	#define FORMAT_BITS FORMAT_BIT_SETS[FORMAT_BITS_RAW]

	/*
	v = 15
	width = 77
	aligners = 4
	spacing = (77-13)/3
	*/

	#define WHITE 1
	#define BLACK 0
	#define PINK float4(1, .3, .5, 1)
	#define BLUE float4(0, .4, .7, 1)

	float4 finder_pattern(uint x, uint y) {
		if (x < 6 && x > 0 && y < 6 && y > 0) return !(x < 5 && x > 1 && y < 5 && y > 1);
		return (x > 6 || y > 6);
	}

	float4 main (float2 uv){
		const uint data[] = {0x68656c6c,0x6f20776f,0x726c6421};
		uv.y = 1 - uv.y;
		uv = uv * 1.5 - 0.25;
		// Quiet zone
		if (uv.x < 0 || uv.x > 1 || uv.y < 0 || uv.y > 1) return 1;

		uint px = uv.x * WIDTH;
		uint py = uv.y * WIDTH;


		// Finder patterns
		if (px < 8 && py < 8) return finder_pattern(px, py);
		if (px < 8 && py > WIDTH - 9) return finder_pattern(px, py - WIDTH + 7);
		if (px > WIDTH - 9 && py < 8) return finder_pattern(px - WIDTH + 7, py);

		// filler pixel
		if (px == 8 && py == WIDTH - 8) return 0;

		// Timing patterns
		if (px == 6) return py & 1;
		if (py == 6) return px & 1;

		// Aligners
		if (VERSION > 1
			&& (px > 8 || py > 8) // top left
			&& (px < WIDTH - 9 || py > 8) // top right
			&& (py < WIDTH - 9 || px > 8) // bottom left
			) {
			// if (MISALIGNMENT != 0) return PINK;

			uint x = px + ALIGNER_SPACING - 4;// - MISALIGNMENT;
			uint y = py + ALIGNER_SPACING - 4;// - MISALIGNMENT;
			// if (px > WIDTH-15) x -= MISALIGNMENT;
			// if (py > WIDTH-15) y -= MISALIGNMENT;
			// if (px < 10) {
			// 	x += MISALIGNMENT;
			// }
			// if (py < 10) {
			// 	y += MISALIGNMENT;
			// }
			uint ax = x % ALIGNER_SPACING;
			uint ay = y % ALIGNER_SPACING;
			if (ax < 5 && ay < 5) {
				return (ax < 4 && ax > 0 && ay < 4 && ay > 0 && !(ax == 2 && ay == 2));
			}
		}

		// Format bits
		// left
		if (px < 6 && py == 8) return (FORMAT_BITS & (1 << (14 - px))) == 0;
		if (px == 7 && py == 8) return (FORMAT_BITS & (1 << 8)) == 0;
		// right
		if (px > WIDTH - 9 && py == 8) return (FORMAT_BITS & (1 << (WIDTH - 1 - px))) == 0;
		// top
		if (px == 8 && py < 6) return (FORMAT_BITS & (1 << py)) == 0;
		if (px == 8 && py < 9) return (FORMAT_BITS & (1 << (py-1))) == 0;
		// bottom
		if (px == 8 && py > WIDTH - 8) return (FORMAT_BITS & (1 << py + 15 - WIDTH)) == 0;

		uint column = (WIDTH - px - (px > 6))/2;
		uint direction_up = column & 1;
		return lerp(BLUE, PINK, column / (WIDTH/2.));
		// return direction_up;
		return 0.5;
	}

	void s (Input IN, inout SurfaceOutputStandard o) { o.Albedo = main(IN.uv_); }
ENDCG
}}