// 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 sand [Mode] [Threshold]
//
// xs_begin
// author : '@lmcdx.bsky.social'
// arg : { name = 'Mode'  var = 'm_mode'  range = '0 2'  value = '0'  step = '1'  precision = '0' }
// arg : { name = 'Threshold'  var = 'm_threshold'  range = '0 100'  value = '0'  step = '1'  precision = '0' }
// xs_end

int mode = int(m_mode);
float threshold = mix(0.125, 0.175, m_threshold / 100.0);

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

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

bool isSelectedPal(float p) {
	for (int i = 0; i < i_num_color_sels; i += 1) {
		if (p == color_sel(float(i))) {
			return true;
		}
	}
	return false;
}

float map(vec3 v) {
	float index = voxel(v);

	if (index == 0.0) {
		float color_beneath = voxel(vec3(v.x, v.y, v.z - 1.0));

		if (isSelectedPal(color_beneath)) {
			bool a = (floor(v.x) == 0.0);
			bool b = (floor(v.x) == i_volume_size.x - 1.0);
			bool c = (floor(v.y) == 0.0);
			bool d = (floor(v.y) == i_volume_size.y - 1.0);

			float z = float((a ? 0.0 : voxel(vec3(v.x - 1.0, v.y, v.z - 1.0))) > 0.0) +
					  float((b ? 0.0 : voxel(vec3(v.x + 1.0, v.y, v.z - 1.0))) > 0.0) +
					  float((c ? 0.0 : voxel(vec3(v.x, v.y - 1.0, v.z - 1.0))) > 0.0) +
					  float((d ? 0.0 : voxel(vec3(v.x, v.y + 1.0, v.z - 1.0))) > 0.0) +
					  float((a && c ? 0.0 : voxel(vec3(v.x - 1.0, v.y - 1.0, v.z - 1.0))) > 0.0) +
					  float((b && c ? 0.0 : voxel(vec3(v.x + 1.0, v.y - 1.0, v.z - 1.0))) > 0.0) +
					  float((a && d ? 0.0 : voxel(vec3(v.x - 1.0, v.y + 1.0, v.z - 1.0))) > 0.0) +
					  float((b && d ? 0.0 : voxel(vec3(v.x + 1.0, v.y + 1.0, v.z - 1.0))) > 0.0);

			float p = hash(v);

			if (p <= (threshold * z)) {
				if (mode == 0 ) {
					return pal(p);
				} else if (mode == 1) {
					return pal(z / 8.0);
				} else if (mode == 2) {
					return pal(1.0 - z / 8.0);
				}
			}
		}
	}

	return index;
}