// 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/bricks_vert [Mode] [Direction] [Height] [Depth] [Width] [Grout Size] [Grout Color] [Offset] [Noise] [Threshold]
//
// xs_begin
// author : '@lmcdx.bsky.social'
// arg : { name = 'Mode'  var = 'm_mode'  range = '0 2'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Direction'  var = 'm_direction'  range = '0 3'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Height'  var = 'm_height'  range = '1 256'  value = '5'  step = '1'  precision = '0' }
// arg : { name = 'Depth'  var = 'm_depth'  range = '1 256'  value = '2'  step = '1'  precision = '0' }
// arg : { name = 'Width'  var = 'm_width'  range = '1 256'  value = '3'  step = '1'  precision = '0' }
// arg : { name = 'Grout Size'  var = 'm_grout_size'  range = '0 256'  value = '1'  step = '1'  precision = '0' }
// arg : { name = 'Grout Color'  var = 'm_grout_color'  range = '0 255'  value = '1'  step = '1'  precision = '0' }
// arg : { name = 'Offset'  var = 'm_offset'  range = '0 256'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Noise'  var = 'm_noise'  range = '0 100'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Threshold'  var = 'm_threshold'  range = '0 100'  value = '100'  step = '1'  precision = '0' }
// xs_end

int mode = int(m_mode);
int direction = int(m_direction);
float height = m_height;
float depth = m_depth;
float width = m_width;
float grout = m_grout_size;
float grout_color = m_grout_color;
float row_offset = m_offset;
float noise = m_noise / 100.0;
float threshold = m_threshold / 100.0;

float hash(vec2 p, float seed) {
	p += 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(vec3 co, float seed) {
	float a = hash(co.xy, seed);
	return hash(vec2(a, co.z), seed);
}

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

vec3 mod3(vec3 a, vec3 b) {
	return vec3(mod(a.x, b.x), mod(a.y, b.y), mod(a.z, b.z));
}

vec3 brick(vec3 p, vec3 dim, float offset) {
	vec3 bk = floor(p / dim);
	bk.x = floor((p.x + bk.z * (offset * (bk.y + 1.0))) / dim.x);
	return bk;
}

float map(vec3 v) {
	vec3 dim = vec3(width, depth, height) + grout;
	float d;

	if (direction == 0) {
		v = v.xyz;
		d = dim.x;
	} else if (direction == 1) {
		v = v.yxz;
		d = dim.y;
	} else if (direction == 2) {
		v = v.yzx;
		d = dim.y;
	} else if (direction == 3) {
		v = v.xzy;
		d = dim.y;
	}

	float offset = (row_offset == 0.0) ? floor(d / 2.0) : row_offset;

	vec3 bk = brick(v, dim, offset);
	vec3 iv = vec3(v.x + bk.z * (offset * (bk.y + 1.0)), v.yz);
	vec3 ic = mod3(iv, dim);

	float bk_randomness = hash(bk, bk.x * bk.y);

	if (bk_randomness < threshold) {
		if (any(greaterThanEqual(ic, floor(dim - grout)))) {
			return grout_color;
		} else {
			float bk_color;

			if (mode == 0) {
				float r = hash(bk, 0.0);
				bk_color = r;
			} else if (mode == 1) {
				float m = ceil(i_volume_size.z / dim.z);

				if (direction == 0) {
					bk_color = (bk.z / m);
				} else if (direction == 1) {
					bk_color = (bk.y / m);
				} else if (direction == 2) {
					bk_color = (bk.y / m);
				} else if (direction == 3) {
					bk_color = (bk.z / m);
				}
			} else if (mode == 2) {
				float m = ceil(i_volume_size.z / dim.z);

				if (direction == 0) {
					bk_color = (1.0 - bk.z / m);
				} else if (direction == 1) {
					bk_color = (1.0 - bk.y / m);
				} else if (direction == 2) {
					bk_color = (1.0 - bk.y / m);
				} else if (direction == 3) {
					bk_color = (1.0 - bk.z / m);
				}
			}

			if (hash(v, 0.0) < noise) {
				return pal(hash(v, 64.0));
			} else {
				return pal(bk_color);
			}
		}
	} else {
		return 0.0;
	}
}