// Copyright (c) 2023 Lachlan McDonald
// This work is licensed under the MIT License (MIT)
// https://github.com/lachlanmcdonald/magicavoxel-shaders
//
// This script utilises or modifies code from other projects or publications.
// Please see the attributions below for more information:
//
// 1. Copyright (c) 2020 ValgoBoi <https://github.com/ValgoBoi/clover-noise>
//    MIT License (MIT)
//    https://github.com/ValgoBoi/clover-noise/blob/master/LICENSE
//
// xs brush/tiles_puzzle [Mode] [Size X] [Size Y] [Line Color] [Line Width] [Noise] [Seed]
//
// xs_begin
// author : '@lmcdx.bsky.social'
// arg : { name = 'Mode'  var = 'm_mode'  range = '0 4'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Size X'  var = 'm_size_x'  range = '1 256'  value = '4'  step = '1'  precision = '0' }
// arg : { name = 'Size Y'  var = 'm_size_y'  range = '1 256'  value = '4'  step = '1'  precision = '0' }
// arg : { name = 'Line Color'  var = 'm_line_color'  range = '0 255'  value = '16'  step = '1'  precision = '0' }
// arg : { name = 'Line Width'  var = 'm_line_width'  range = '0 256'  value = '1'  step = '1'  precision = '0' }
// arg : { name = 'Noise'  var = 'm_noise'  range = '0 100'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Seed'  var = 'global_seed'  range = '1 100'  value = '1'  step = '1'  precision = '0' }
// xs_end

int mode = int(m_mode);
float line_color = m_line_color;
float line_width = m_line_width;
float noise = m_noise / 100.0;

vec3 shape = vec3(m_size_x + line_width,
				  m_size_y + line_width,
				  1.0);

float hash(vec2 p, float seed) {
	p += seed + global_seed;
	return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x))));
}

float hash(vec2 co) {
	return hash(co, 0.0);
}

float pal(float p) {
	float f = floor(mix(0.0, float(i_num_color_sels), p));
	return color_sel(f);
}

float pal_noise(float p, vec3 v) {
	if (noise > 0.0) {
		float d = hash(v.xy, global_seed * 2.0);
		return d <= noise ? pal(d) : pal(p);
	} else {
		return pal(p);
	}
}

float map(vec3 v) {
	vec3 j = floor(v / shape);
	vec3 m = mod(v, shape);
	float tile = hash(j.xy);
	float next = tile;
	int i;

	if (tile > 0.5) {
		for (i = 0; i < 5; i += 1) {
			float b = hash(j.xy + vec2(float(i), 0.0));

			if (b > 0.5) {
				next = b;
			} else {
				break;
			}
		}

		if (i == 1) {
			if (any(greaterThan(m.xy, shape.xy - vec2(line_width)))) {
				return line_color;
			}
		} else if (m.y > (shape.y - line_width)) {
			return line_color;
		}

		if (mode != 4) {
			next = (next - 0.5) * 2.0;
		}
	} else {
		for (i = 0; i < 5; i += 1) {
			float b = hash(j.xy + vec2(0.0, float(i)));

			if (b <= 0.5) {
				next = b;
			} else {
				break;
			}
		}

		if (i == 1) {
			if (any(greaterThan(m.xy, shape.xy - vec2(line_width)))) {
				return line_color;
			}
		} else if (m.x > (shape.x - line_width)) {
			return line_color;
		}

		if (mode != 4) {
			next *= 2.0;
		}
	}

	if (mode == 1) {
		return tile > 0.5 ? pal_noise(0.0, v) : pal_noise(1.0, v);
	} else if (mode == 2) {
		return tile > 0.5 ? line_color : pal_noise(next, v);
	} else if (mode == 3) {
		return tile <= 0.5 ? line_color : pal_noise(next, v);
	} else {
		return pal_noise(next, v);
	}
}