Namespaced math funcs

This commit is contained in:
Marc Gilleron 2022-01-03 23:14:18 +00:00
parent a9476227cb
commit e20684ce69
39 changed files with 199 additions and 153 deletions

@ -51,8 +51,8 @@ inline void normalize_weights_preserving(FixedArray<float, 4> &weights, unsigned
}
}*/
inline void blend_texture_packed_u16(int texture_index, float target_weight,
uint16_t &encoded_indices, uint16_t &encoded_weights) {
inline void blend_texture_packed_u16(
int texture_index, float target_weight, uint16_t &encoded_indices, uint16_t &encoded_weights) {
#ifdef DEBUG_ENABLED
ERR_FAIL_COND(target_weight < 0.f || target_weight > 1.f);
#endif
@ -98,7 +98,7 @@ inline void blend_texture_packed_u16(int texture_index, float target_weight,
normalize_weights_preserving(weights_f, component_index);
for (unsigned int i = 0; i < weights_f.size(); ++i) {
weights[i] = clamp(weights_f[i] * 255.f, 0.f, 255.f);
weights[i] = zylann::math::clamp(weights_f[i] * 255.f, 0.f, 255.f);
}
encoded_indices = encode_indices_to_packed_u16(indices[0], indices[1], indices[2], indices[3]);

@ -3,6 +3,8 @@
#include "../util/macros.h"
#include "../util/profiling.h"
using namespace zylann;
VoxelTool::VoxelTool() {
_sdf_scale = VoxelBufferInternal::get_sdf_quantization_scale(VoxelBufferInternal::DEFAULT_SDF_CHANNEL_DEPTH);
}
@ -45,7 +47,7 @@ float VoxelTool::get_sdf_scale() const {
}
void VoxelTool::set_sdf_scale(float s) {
_sdf_scale = max(s, 0.00001f);
_sdf_scale = math::max(s, 0.00001f);
}
void VoxelTool::set_texture_index(int ti) {
@ -58,7 +60,7 @@ int VoxelTool::get_texture_index() const {
}
void VoxelTool::set_texture_opacity(float opacity) {
_texture_params.opacity = clamp(opacity, 0.f, 1.f);
_texture_params.opacity = math::clamp(opacity, 0.f, 1.f);
}
float VoxelTool::get_texture_opacity() const {
@ -66,7 +68,7 @@ float VoxelTool::get_texture_opacity() const {
}
void VoxelTool::set_texture_falloff(float falloff) {
_texture_params.sharpness = 1.f / clamp(falloff, 0.001f, 1.f);
_texture_params.sharpness = 1.f / math::clamp(falloff, 0.001f, 1.f);
}
float VoxelTool::get_texture_falloff() const {

@ -9,6 +9,8 @@
class VoxelBuffer;
using namespace zylann;
namespace VoxelToolOps {
template <typename Op, typename Shape> struct SdfOperation16bit {
@ -70,7 +72,8 @@ struct TextureBlendSphereOp {
const float distance_squared = Vector3(pos).distance_squared_to(center);
if (distance_squared < radius_squared) {
const float distance_from_radius = radius - Math::sqrt(distance_squared);
const float target_weight = tp.opacity * clamp(tp.sharpness * (distance_from_radius / radius), 0.f, 1.f);
const float target_weight =
tp.opacity * math::clamp(tp.sharpness * (distance_from_radius / radius), 0.f, 1.f);
blend_texture_packed_u16(tp.index, target_weight, indices, weights);
}
}

@ -14,6 +14,9 @@
#include <scene/3d/physics_body_3d.h>
#include <scene/main/timer.h>
using namespace zylann;
using namespace voxel;
VoxelToolLodTerrain::VoxelToolLodTerrain(VoxelLodTerrain *terrain) : _terrain(terrain) {
ERR_FAIL_COND(terrain == nullptr);
// At the moment, only LOD0 is supported.
@ -37,7 +40,7 @@ template <typename Volume_F> float get_sdf_interpolated(const Volume_F &f, Vecto
const float s011 = f(Vector3i(c.x, c.y + 1, c.z + 1));
const float s111 = f(Vector3i(c.x + 1, c.y + 1, c.z + 1));
return interpolate(s000, s100, s101, s001, s010, s110, s111, s011, fract(pos));
return math::interpolate(s000, s100, s101, s001, s010, s110, s111, s011, math::fract(pos));
}
// Binary search can be more accurate than linear regression because the SDF can be inaccurate in the first place.
@ -378,7 +381,7 @@ int VoxelToolLodTerrain::get_raycast_binary_search_iterations() const {
}
void VoxelToolLodTerrain::set_raycast_binary_search_iterations(int iterations) {
_raycast_binary_search_iterations = clamp(iterations, 0, 16);
_raycast_binary_search_iterations = math::clamp(iterations, 0, 16);
}
namespace zylann::voxel {
@ -714,7 +717,7 @@ Array separate_floating_chunks(VoxelTool &voxel_tool, Box3i world_box, Node *par
Array VoxelToolLodTerrain::separate_floating_chunks(AABB world_box, Node *parent_node) {
ERR_FAIL_COND_V(_terrain == nullptr, Array());
ERR_FAIL_COND_V(!is_valid_size(world_box.size), Array());
ERR_FAIL_COND_V(!math::is_valid_size(world_box.size), Array());
Ref<VoxelMesher> mesher = _terrain->get_mesher();
Array materials;
materials.append(_terrain->get_material());

@ -5,6 +5,8 @@
#include "../util/godot/funcs.h"
#include "../util/voxel_raycast.h"
using namespace zylann;
VoxelToolTerrain::VoxelToolTerrain() {}
VoxelToolTerrain::VoxelToolTerrain(VoxelTerrain *terrain) {
@ -232,7 +234,7 @@ void VoxelToolTerrain::run_blocky_random_tick(
ERR_FAIL_COND(callback.is_null());
ERR_FAIL_COND(batch_count <= 0);
ERR_FAIL_COND(voxel_count < 0);
ERR_FAIL_COND(!is_valid_size(voxel_area.size));
ERR_FAIL_COND(!math::is_valid_size(voxel_area.size));
if (voxel_count == 0) {
return;
@ -328,7 +330,7 @@ void VoxelToolTerrain::run_blocky_random_tick(
void VoxelToolTerrain::for_each_voxel_metadata_in_area(AABB voxel_area, const Callable &callback) {
ERR_FAIL_COND(_terrain == nullptr);
ERR_FAIL_COND(callback.is_null());
ERR_FAIL_COND(!is_valid_size(voxel_area.size));
ERR_FAIL_COND(!math::is_valid_size(voxel_area.size));
const Box3i voxel_box =
Box3i(Vector3iUtil::from_floored(voxel_area.position), Vector3iUtil::from_floored(voxel_area.size));

@ -398,7 +398,7 @@ void VoxelGraphEditor::create_node_gui(uint32_t node_id) {
// These nodes have an output for implementation reasons, some outputs can process the data like any other node.
const bool hide_outputs = node_type.category == VoxelGraphNodeDB::CATEGORY_OUTPUT;
const unsigned int row_count = max(node_type.inputs.size(), hide_outputs ? 0 : node_type.outputs.size());
const unsigned int row_count = math::max(node_type.inputs.size(), hide_outputs ? 0 : node_type.outputs.size());
const Color port_color(0.4, 0.4, 1.0);
// TODO Insert a summary so the graph would be readable without having to inspect nodes
@ -898,7 +898,7 @@ void VoxelGraphEditor::update_slice_previews() {
for (int y = 0; y < im.get_height(); ++y) {
for (int x = 0; x < im.get_width(); ++x) {
const float v = buffer.data[i];
const float g = clamp((v - info.min_value) * info.value_scale, 0.f, 1.f);
const float g = math::clamp((v - info.min_value) * info.value_scale, 0.f, 1.f);
im.set_pixel(x, im.get_height() - y - 1, Color(g, g, g));
++i;
}

@ -127,8 +127,8 @@ static void interval_to_pixels(Interval i, int &out_min, int &out_max, int len)
// Images are finite, intervals are not.
// It's useless to let the range span a potentially infinite area.
// The image can repeat, so we clamp to one repetition.
out_min = ::clamp(imin, -len, len);
out_max = ::clamp(imax, -len, len);
out_min = clamp(imin, -len, len);
out_max = clamp(imax, -len, len);
}
Interval ImageRangeGrid::get_range(Interval xr, Interval yr) const {

@ -23,11 +23,11 @@ inline Interval get_noise_range_2d(Noise_F noise_func, const Interval &x, const
const float mid_y = 0.5 * (y.min + y.max);
const float mid_value = noise_func(mid_x, mid_y);
const float diag = Math::sqrt(::squared(x.length()) + ::squared(y.length()));
const float diag = Math::sqrt(squared(x.length()) + squared(y.length()));
return Interval( //
::max(mid_value - max_derivative_half_diagonal * diag, -1.f),
::min(mid_value + max_derivative_half_diagonal * diag, 1.f));
max(mid_value - max_derivative_half_diagonal * diag, -1.f),
min(mid_value + max_derivative_half_diagonal * diag, 1.f));
}
template <typename Noise_F>
@ -40,11 +40,11 @@ inline Interval get_noise_range_3d(
const float mid_z = 0.5 * (z.min + z.max);
const float mid_value = noise_func(mid_x, mid_y, mid_z);
const float diag = Math::sqrt(::squared(x.length()) + ::squared(y.length()) + ::squared(z.length()));
const float diag = Math::sqrt(squared(x.length()) + squared(y.length()) + squared(z.length()));
return Interval( //
::max(mid_value - max_derivative_half_diagonal * diag, -1.f),
::min(mid_value + max_derivative_half_diagonal * diag, 1.f));
max(mid_value - max_derivative_half_diagonal * diag, -1.f),
min(mid_value + max_derivative_half_diagonal * diag, 1.f));
}
Interval get_osn_octave_range_2d(OpenSimplexNoise *noise, const Interval &p_x, const Interval &p_y, int octave) {

@ -243,7 +243,7 @@ float VoxelGeneratorGraph::get_sdf_clip_threshold() const {
}
void VoxelGeneratorGraph::set_sdf_clip_threshold(float t) {
_sdf_clip_threshold = max(t, 0.f);
_sdf_clip_threshold = math::max(t, 0.f);
}
int VoxelGeneratorGraph::get_used_channels_mask() const {
@ -314,7 +314,7 @@ void VoxelGeneratorGraph::gather_indices_and_weights(Span<const WeightOutput> we
const float weight = buffers[oi][value_index];
// TODO Optimization: weight output nodes could already multiply by 255 and clamp afterward
// so we would not need to do it here
weights[oi] = clamp(weight * 255.f, 0.f, 255.f);
weights[oi] = math::clamp(weight * 255.f, 0.f, 255.f);
indices[oi] = weight_outputs[oi].layer_index;
}
debug_check_texture_indices(indices);
@ -338,7 +338,7 @@ void VoxelGeneratorGraph::gather_indices_and_weights(Span<const WeightOutput> we
FixedArray<uint8_t, 4> indices;
for (unsigned int oi = 0; oi < buffers_count; ++oi) {
const float weight = buffers[oi][value_index];
weights[oi] = clamp(weight * 255.f, 0.f, 255.f);
weights[oi] = math::clamp(weight * 255.f, 0.f, 255.f);
indices[oi] = weight_outputs[oi].layer_index;
}
const uint16_t encoded_indices =
@ -372,7 +372,7 @@ void VoxelGeneratorGraph::gather_indices_and_weights(Span<const WeightOutput> we
for (unsigned int oi = 0; oi < buffers_count && recorded_weights < indices.size(); ++oi) {
const float weight = buffers[oi][value_index];
if (weight > pivot) {
weights[recorded_weights] = clamp(weight * 255.f, 0.f, 255.f);
weights[recorded_weights] = math::clamp(weight * 255.f, 0.f, 255.f);
indices[recorded_weights] = weight_outputs[oi].layer_index;
++recorded_weights;
} else {

@ -314,7 +314,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
const VoxelGraphRuntime::Buffer &input = ctx.get_input(0);
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
for (unsigned int i = 0; i < out.size; ++i) {
out.data[i] = ::clamp(input.data[i], 0.f, 1.f);
out.data[i] = clamp(input.data[i], 0.f, 1.f);
}
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
@ -478,7 +478,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
t.inputs.push_back(Port("length"));
t.outputs.push_back(Port("out"));
t.process_buffer_func = [](ProcessBufferContext &ctx) {
do_binop(ctx, [](float a, float b) { return ::wrapf(a, b); });
do_binop(ctx, [](float a, float b) { return wrapf(a, b); });
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
const Interval a = ctx.get_input(0);
@ -534,7 +534,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
const VoxelGraphRuntime::Buffer &y1 = ctx.get_input(3);
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
for (uint32_t i = 0; i < out.size; ++i) {
out.data[i] = Math::sqrt(::squared(x1.data[i] - x0.data[i]) + ::squared(y1.data[i] - y0.data[i]));
out.data[i] = Math::sqrt(squared(x1.data[i] - x0.data[i]) + squared(y1.data[i] - y0.data[i]));
}
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
@ -568,8 +568,8 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
const VoxelGraphRuntime::Buffer &z1 = ctx.get_input(5);
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
for (uint32_t i = 0; i < out.size; ++i) {
out.data[i] = Math::sqrt(::squared(x1.data[i] - x0.data[i]) + ::squared(y1.data[i] - y0.data[i]) +
::squared(z1.data[i] - z0.data[i]));
out.data[i] = Math::sqrt(squared(x1.data[i] - x0.data[i]) + squared(y1.data[i] - y0.data[i]) +
squared(z1.data[i] - z0.data[i]));
}
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
@ -609,7 +609,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
const Params p = ctx.get_params<Params>();
for (uint32_t i = 0; i < out.size; ++i) {
out.data[i] = ::clamp(a.data[i], p.min, p.max);
out.data[i] = clamp(a.data[i], p.min, p.max);
}
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
@ -773,7 +773,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
const Params p = ctx.get_params<Params>();
for (uint32_t i = 0; i < out.size; ++i) {
out.data[i] = ::smoothstep(p.edge0, p.edge1, a.data[i]);
out.data[i] = smoothstep(p.edge0, p.edge1, a.data[i]);
}
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
@ -1032,8 +1032,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
const VoxelGraphRuntime::Buffer &r = ctx.get_input(3);
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
for (uint32_t i = 0; i < out.size; ++i) {
out.data[i] =
Math::sqrt(::squared(x.data[i]) + ::squared(y.data[i]) + ::squared(z.data[i])) - r.data[i];
out.data[i] = Math::sqrt(squared(x.data[i]) + squared(y.data[i]) + squared(z.data[i])) - r.data[i];
}
};
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
@ -1389,7 +1388,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
const float x = xb.data[i];
const float y = yb.data[i];
const float z = zb.data[i];
const float len = Math::sqrt(::squared(x) + ::squared(y) + ::squared(z));
const float len = Math::sqrt(squared(x) + squared(y) + squared(z));
out_nx.data[i] = x / len;
out_ny.data[i] = y / len;
out_nz.data[i] = z / len;

@ -609,7 +609,7 @@ void VoxelGraphRuntime::prepare_state(State &state, unsigned int buffer_size) co
CRASH_COND(buffer.data != nullptr);
// TODO Use pool?
// New buffers get an up-to-date size, but must also comply with common capacity
const unsigned int bs = max(state.buffer_capacity, buffer_size);
const unsigned int bs = math::max(state.buffer_capacity, buffer_size);
buffer.data = reinterpret_cast<float *>(memalloc(bs * sizeof(float)));
buffer.capacity = bs;
}

@ -2,10 +2,12 @@
#include "../../util/fixed_array.h"
#include "../../util/span.h"
using namespace zylann;
namespace {
inline float get_height_repeat(const Image &im, int x, int y) {
return im.get_pixel(wrap(x, im.get_width()), wrap(y, im.get_height())).r;
return im.get_pixel(math::wrap(x, im.get_width()), math::wrap(y, im.get_height())).r;
}
inline float get_height_blurred(const Image &im, int x, int y) {

@ -1,6 +1,8 @@
#include "voxel_generator_waves.h"
#include <cmath>
using namespace zylann;
VoxelGeneratorWaves::VoxelGeneratorWaves() {
_parameters.pattern_size = Vector2(30, 30);
// This might be a different default value than the base class,
@ -8,8 +10,7 @@ VoxelGeneratorWaves::VoxelGeneratorWaves() {
set_height_range(30);
}
VoxelGeneratorWaves::~VoxelGeneratorWaves() {
}
VoxelGeneratorWaves::~VoxelGeneratorWaves() {}
VoxelGenerator::Result VoxelGeneratorWaves::generate_block(VoxelBlockRequest &input) {
Parameters params;
@ -20,8 +21,7 @@ VoxelGenerator::Result VoxelGeneratorWaves::generate_block(VoxelBlockRequest &in
VoxelBufferInternal &out_buffer = input.voxel_buffer;
const Vector2 freq(
Math_PI / static_cast<float>(params.pattern_size.x),
Math_PI / static_cast<float>(params.pattern_size.y));
Math_PI / static_cast<float>(params.pattern_size.x), Math_PI / static_cast<float>(params.pattern_size.y));
const Vector2 offset = params.pattern_offset;
return VoxelGeneratorHeightmap::generate(
@ -39,8 +39,8 @@ Vector2 VoxelGeneratorWaves::get_pattern_size() const {
void VoxelGeneratorWaves::set_pattern_size(Vector2 size) {
RWLockWrite wlock(_parameters_lock);
size.x = max(size.x, 0.1f);
size.y = max(size.y, 0.1f);
size.x = math::max(size.x, 0.1f);
size.y = math::max(size.y, 0.1f);
_parameters.pattern_size = size;
}

@ -5,6 +5,8 @@
#define STRLEN(x) (sizeof(x) / sizeof(x[0]))
using namespace zylann;
Voxel::Voxel() :
_id(-1), _material_id(0), _transparency_index(0), _color(1.f, 1.f, 1.f), _geometry_type(GEOMETRY_NONE) {}
@ -105,7 +107,7 @@ void Voxel::set_transparent(bool t) {
}
void Voxel::set_transparency_index(int i) {
_transparency_index = clamp(i, 0, 255);
_transparency_index = math::clamp(i, 0, 255);
}
void Voxel::set_geometry_type(GeometryType type) {

@ -6,6 +6,8 @@
#include <bitset>
using namespace zylann;
VoxelLibrary::VoxelLibrary() {}
VoxelLibrary::~VoxelLibrary() {}
@ -139,6 +141,8 @@ template <typename F> static void rasterize_triangle_barycentric(Vector2 a, Vect
b += 0.001 * (b - m);
c += 0.001 * (c - m);
using namespace math;
const int min_x = (int)Math::floor(min(min(a.x, b.x), c.x));
const int min_y = (int)Math::floor(min(min(a.y, b.y), c.y));
const int max_x = (int)Math::ceil(max(max(a.x, b.x), c.x));

@ -5,6 +5,8 @@
#include "../../util/span.h"
#include <core/os/os.h>
using namespace zylann;
// Utility functions
namespace {
@ -349,7 +351,7 @@ Ref<VoxelLibrary> VoxelMesherBlocky::get_library() const {
void VoxelMesherBlocky::set_occlusion_darkness(float darkness) {
RWLockWrite wlock(_parameters_lock);
_parameters.baked_occlusion_darkness = clamp(darkness, 0.0f, 1.0f);
_parameters.baked_occlusion_darkness = math::clamp(darkness, 0.0f, 1.0f);
}
float VoxelMesherBlocky::get_occlusion_darkness() const {

@ -11,9 +11,7 @@ struct HermiteValue {
float sdf; // Signed "distance" to surface
Vector3 gradient; // Derivation of the density
HermiteValue() :
sdf(1.0) {
}
HermiteValue() : sdf(1.0) {}
};
inline float get_isolevel_clamped(const VoxelBufferInternal &voxels, unsigned int x, unsigned int y, unsigned int z) {
@ -23,8 +21,8 @@ inline float get_isolevel_clamped(const VoxelBufferInternal &voxels, unsigned in
return voxels.get_voxel_f(x, y, z, VoxelBufferInternal::CHANNEL_SDF);
}
inline HermiteValue get_hermite_value(const VoxelBufferInternal &voxels,
unsigned int x, unsigned int y, unsigned int z) {
inline HermiteValue get_hermite_value(
const VoxelBufferInternal &voxels, unsigned int x, unsigned int y, unsigned int z) {
HermiteValue v;
v.sdf = voxels.get_voxel_f(x, y, z, VoxelBufferInternal::CHANNEL_SDF);
@ -69,10 +67,9 @@ inline HermiteValue get_interpolated_hermite_value(const VoxelBufferInternal &vo
Vector3 rpos = pos - Vector3(x0, y0, z0);
HermiteValue v;
v.sdf = ::interpolate(v0.sdf, v1.sdf, v2.sdf, v3.sdf, v4.sdf, v5.sdf, v6.sdf, v7.sdf, rpos);
v.gradient = ::interpolate(
v0.gradient, v1.gradient, v2.gradient, v3.gradient,
v4.gradient, v5.gradient, v6.gradient, v7.gradient, rpos);
v.sdf = zylann::math::interpolate(v0.sdf, v1.sdf, v2.sdf, v3.sdf, v4.sdf, v5.sdf, v6.sdf, v7.sdf, rpos);
v.gradient = zylann::math::interpolate(v0.gradient, v1.gradient, v2.gradient, v3.gradient, v4.gradient, v5.gradient,
v6.gradient, v7.gradient, rpos);
return v;
}

@ -5,6 +5,8 @@
#include "mesh_builder.h"
#include <core/os/time.h>
using namespace zylann;
// Dual marching cubes
// Algorithm taken from https://www.volume-gfx.com/volume-rendering/dual-marching-cubes/
// Partially based on Ogre's implementation, adapted for requirements of this module with a few extras
@ -123,7 +125,7 @@ bool can_split(Vector3i node_origin, int node_size, const VoxelAccess &voxels, f
HermiteValue value = get_hermite_value(voxels.buffer, pos.x, pos.y, pos.z);
float interpolated_value = ::interpolate(v0, v1, v2, v3, v4, v5, v6, v7, positions_ratio[i]);
float interpolated_value = math::interpolate(v0, v1, v2, v3, v4, v5, v6, v7, positions_ratio[i]);
float gradient_magnitude = value.gradient.length();
if (gradient_magnitude < FLT_EPSILON) {

@ -4,6 +4,8 @@
#include "../../util/profiling.h"
#include "transvoxel_tables.cpp"
using namespace zylann;
namespace Transvoxel {
static const float TRANSITION_CELL_SCALE = 0.25;
@ -542,7 +544,7 @@ void build_regular_mesh(Span<const Sdf_T> sdf_data, TextureIndicesData texture_i
FixedArray<uint8_t, MAX_TEXTURE_BLENDS> weights;
for (unsigned int i = 0; i < MAX_TEXTURE_BLENDS; ++i) {
weights[i] = static_cast<uint8_t>(
clamp(Math::lerp(weights0[i], weights1[i], t1), 0.f, 255.f));
math::clamp(Math::lerp(weights0[i], weights1[i], t1), 0.f, 255.f));
}
add_texture_data(output.texturing_data, cell_textures.packed_indices, weights);
}
@ -1037,7 +1039,7 @@ void build_transition_mesh(Span<const Sdf_T> sdf_data, TextureIndicesData textur
FixedArray<uint8_t, MAX_TEXTURE_BLENDS> weights;
for (unsigned int i = 0; i < cell_textures.indices.size(); ++i) {
weights[i] = static_cast<uint8_t>(
clamp(Math::lerp(weights0[i], weights1[i], t1), 0.f, 255.f));
math::clamp(Math::lerp(weights0[i], weights1[i], t1), 0.f, 255.f));
}
add_texture_data(output.texturing_data, cell_textures.packed_indices, weights);
}

@ -5,6 +5,8 @@
#include "../../util/profiling.h"
#include "transvoxel_tables.cpp"
using namespace zylann;
VoxelMesherTransvoxel::VoxelMesherTransvoxel() {
set_padding(Transvoxel::MIN_PADDING, Transvoxel::MAX_PADDING);
}
@ -250,7 +252,7 @@ bool VoxelMesherTransvoxel::is_mesh_optimization_enabled() const {
}
void VoxelMesherTransvoxel::set_mesh_optimization_error_threshold(float threshold) {
_mesh_optimization_params.error_threshold = clamp(threshold, 0.f, 1.f);
_mesh_optimization_params.error_threshold = math::clamp(threshold, 0.f, 1.f);
}
float VoxelMesherTransvoxel::get_mesh_optimization_error_threshold() const {
@ -258,7 +260,7 @@ float VoxelMesherTransvoxel::get_mesh_optimization_error_threshold() const {
}
void VoxelMesherTransvoxel::set_mesh_optimization_target_ratio(float ratio) {
_mesh_optimization_params.target_ratio = clamp(ratio, 0.f, 1.f);
_mesh_optimization_params.target_ratio = math::clamp(ratio, 0.f, 1.f);
}
float VoxelMesherTransvoxel::get_mesh_optimization_target_ratio() const {

@ -11,6 +11,8 @@
#include <scene/main/window.h> // Needed for doing `Node *root = SceneTree::get_root()`, Window* is forward-declared
#include <thread>
using namespace zylann;
namespace {
VoxelServer *g_voxel_server = nullptr;
// Could be atomics, but it's for debugging so I don't bother for now
@ -72,20 +74,21 @@ VoxelServer::VoxelServer() {
_main_thread_time_budget_usec =
1000 * int(ProjectSettings::get_singleton()->get("voxel/threads/main/time_budget_ms"));
const int minimum_thread_count = max(1, int(ProjectSettings::get_singleton()->get("voxel/threads/count/minimum")));
const int minimum_thread_count =
math::max(1, int(ProjectSettings::get_singleton()->get("voxel/threads/count/minimum")));
// How many threads below available count on the CPU should we set as limit
const int thread_count_margin =
max(1, int(ProjectSettings::get_singleton()->get("voxel/threads/count/margin_below_max")));
math::max(1, int(ProjectSettings::get_singleton()->get("voxel/threads/count/margin_below_max")));
// Portion of available CPU threads to attempt using
const float threads_ratio =
clamp(float(ProjectSettings::get_singleton()->get("voxel/threads/count/ratio_over_max")), 0.f, 1.f);
math::clamp(float(ProjectSettings::get_singleton()->get("voxel/threads/count/ratio_over_max")), 0.f, 1.f);
const int maximum_thread_count = max(hw_threads_hint - thread_count_margin, minimum_thread_count);
const int maximum_thread_count = math::max(hw_threads_hint - thread_count_margin, minimum_thread_count);
// `-1` is for the stream thread
const int thread_count_by_ratio = int(Math::round(float(threads_ratio) * hw_threads_hint)) - 1;
const int thread_count = clamp(thread_count_by_ratio, minimum_thread_count, maximum_thread_count);
const int thread_count = math::clamp(thread_count_by_ratio, minimum_thread_count, maximum_thread_count);
PRINT_VERBOSE(String("Voxel: automatic thread count set to {0}").format(varray(thread_count)));
if (thread_count > hw_threads_hint) {
@ -286,14 +289,14 @@ void VoxelServer::init_priority_dependency(VoxelServer::PriorityDependency &dep,
// Distance beyond which no field of view can overlap the block.
// Doubling block radius to account for an extra margin of blocks,
// since they are used to provide neighbors when meshing
dep.drop_distance_squared =
squared(_world.shared_priority_dependency->highest_view_distance + 2.f * transformed_block_radius);
dep.drop_distance_squared = math::squared(
_world.shared_priority_dependency->highest_view_distance + 2.f * transformed_block_radius);
break;
case VOLUME_SPARSE_OCTREE:
// Distance beyond which it is safe to drop a block without risking to block LOD subdivision.
// This does not depend on viewer's view distance, but on LOD precision instead.
dep.drop_distance_squared = squared(2.f * transformed_block_radius *
dep.drop_distance_squared = math::squared(2.f * transformed_block_radius *
get_octree_lod_block_region_extent(volume.octree_lod_distance, block_size));
break;

@ -101,11 +101,11 @@ inline float u16_to_norm(uint16_t v) {
}
inline uint8_t norm_to_u8(float v) {
return clamp(static_cast<int>(128.f * v + 128.f), 0, 0xff);
return zylann::math::clamp(static_cast<int>(128.f * v + 128.f), 0, 0xff);
}
inline uint16_t norm_to_u16(float v) {
return clamp(static_cast<int>(0x8000 * v + 0x8000), 0, 0xffff);
return zylann::math::clamp(static_cast<int>(0x8000 * v + 0x8000), 0, 0xffff);
}
/*static inline float quantized_u8_to_real(uint8_t v) {

@ -78,7 +78,7 @@ private:
// `get_next_power_of_two_32` takes unsigned int
CRASH_COND(size > std::numeric_limits<unsigned int>::max());
#endif
return get_shift_from_power_of_two_32(get_next_power_of_two_32(size));
return zylann::math::get_shift_from_power_of_two_32(zylann::math::get_next_power_of_two_32(size));
}
inline size_t get_size_from_pool_index(unsigned int i) const {

@ -4,6 +4,8 @@
#include "../util/serialization.h"
#include <core/variant/variant.h>
using namespace zylann;
namespace {
const uint32_t TRAILING_MAGIC = 0x900df00d;
}
@ -15,7 +17,7 @@ const float VoxelInstanceBlockData::SIMPLE_11B_V1_SCALE_RANGE_MINIMUM = 0.01f;
// TODO Unify with functions from VoxelBuffer?
inline uint8_t norm_to_u8(float x) {
return clamp(static_cast<int>(128.f * x + 128.f), 0, 0xff);
return math::clamp(static_cast<int>(128.f * x + 128.f), 0, 0xff);
}
inline float u8_to_norm(uint8_t v) {
@ -57,7 +59,7 @@ bool serialize_instance_block_data(const VoxelInstanceBlockData &src, std::vecto
zylann::MemoryWriter w(dst, zylann::ENDIANESS_BIG_ENDIAN);
ERR_FAIL_COND_V(src.position_range < 0.f, false);
const float position_range = max(src.position_range, VoxelInstanceBlockData::POSITION_RANGE_MINIMUM);
const float position_range = math::max(src.position_range, VoxelInstanceBlockData::POSITION_RANGE_MINIMUM);
w.store_8(version);
w.store_8(src.layers.size());

@ -8,6 +8,8 @@
#include <core/os/time.h>
#include <algorithm>
using namespace zylann;
namespace {
const uint8_t FORMAT_VERSION = 3;
@ -547,7 +549,7 @@ void VoxelStreamRegionFiles::close_oldest_region() {
}
static inline int convert_block_coordinate(int p_x, int old_size, int new_size) {
return ::floordiv(p_x * old_size, new_size);
return math::floordiv(p_x * old_size, new_size);
}
static Vector3i convert_block_coordinates(Vector3i pos, Vector3i old_size, Vector3i new_size) {

@ -5,6 +5,8 @@
#include <core/core_string_names.h>
#include <scene/resources/mesh.h>
using namespace zylann;
namespace {
const float MAX_DENSITY = 1.f;
const char *DENSITY_HINT_STRING = "0.0, 1.0, 0.01";
@ -96,7 +98,8 @@ void VoxelInstanceGenerator::generate_transforms(std::vector<Transform3D> &out_t
// so it's possible a different emit mode will produce different amounts of instances.
// I had to use `uint64` and clamp it because floats can't contain `0xffffffff` accurately. Instead
// it results in `0x100000000`, one unit above.
const uint32_t density_u32 = min(uint64_t(0xffffffff * (_density / MAX_DENSITY)), uint64_t(0xffffffff));
const uint32_t density_u32 =
math::min(uint64_t(0xffffffff * (_density / MAX_DENSITY)), uint64_t(0xffffffff));
const int size = vertices.size();
for (int i = 0; i < size; ++i) {
// TODO We could actually generate indexes and pick those,
@ -418,7 +421,7 @@ void VoxelInstanceGenerator::generate_transforms(std::vector<Transform3D> &out_t
CRASH_COND(vertex_index >= noise_cache.size());
#endif
// Multiplied noise because it gives more pronounced results
const float n = clamp(noise_cache[vertex_index] * 2.f, 0.f, 1.f);
const float n = math::clamp(noise_cache[vertex_index] * 2.f, 0.f, 1.f);
r *= Math::lerp(1.f, n, _noise_on_scale);
}
@ -444,7 +447,7 @@ void VoxelInstanceGenerator::generate_transforms(std::vector<Transform3D> &out_t
}
void VoxelInstanceGenerator::set_density(float density) {
density = max(density, 0.f);
density = math::max(density, 0.f);
if (density == _density) {
return;
}
@ -507,7 +510,7 @@ VoxelInstanceGenerator::Distribution VoxelInstanceGenerator::get_scale_distribut
}
void VoxelInstanceGenerator::set_vertical_alignment(float amount) {
amount = clamp(amount, 0.f, 1.f);
amount = math::clamp(amount, 0.f, 1.f);
if (_vertical_alignment == amount) {
return;
}
@ -532,8 +535,8 @@ float VoxelInstanceGenerator::get_offset_along_normal() const {
}
void VoxelInstanceGenerator::set_min_slope_degrees(float degrees) {
_min_slope_degrees = clamp(degrees, 0.f, 180.f);
const float max_surface_normal_y = min(1.f, Math::cos(Math::deg2rad(_min_slope_degrees)));
_min_slope_degrees = math::clamp(degrees, 0.f, 180.f);
const float max_surface_normal_y = math::min(1.f, Math::cos(Math::deg2rad(_min_slope_degrees)));
if (max_surface_normal_y == _max_surface_normal_y) {
return;
}
@ -546,8 +549,8 @@ float VoxelInstanceGenerator::get_min_slope_degrees() const {
}
void VoxelInstanceGenerator::set_max_slope_degrees(float degrees) {
_max_slope_degrees = clamp(degrees, 0.f, 180.f);
const float min_surface_normal_y = max(-1.f, Math::cos(Math::deg2rad(_max_slope_degrees)));
_max_slope_degrees = math::clamp(degrees, 0.f, 180.f);
const float min_surface_normal_y = math::max(-1.f, Math::cos(Math::deg2rad(_max_slope_degrees)));
if (min_surface_normal_y == _min_surface_normal_y) {
return;
}
@ -640,7 +643,7 @@ VoxelInstanceGenerator::Dimension VoxelInstanceGenerator::get_noise_dimension()
}
void VoxelInstanceGenerator::set_noise_on_scale(float amount) {
amount = clamp(amount, 0.f, 1.f);
amount = math::clamp(amount, 0.f, 1.f);
if (amount == _noise_on_scale) {
return;
}

@ -78,8 +78,8 @@ public:
void set_lod_distance(float p_lod_distance) {
// Distance must be greater than a threshold,
// otherwise lods will decimate too fast and it will look messy
_lod_distance =
clamp(p_lod_distance, VoxelConstants::MINIMUM_LOD_DISTANCE, VoxelConstants::MAXIMUM_LOD_DISTANCE);
_lod_distance = zylann::math::clamp(
p_lod_distance, VoxelConstants::MINIMUM_LOD_DISTANCE, VoxelConstants::MAXIMUM_LOD_DISTANCE);
}
float get_lod_distance() const {
@ -266,7 +266,7 @@ private:
const int lod_factor = get_lod_factor(lod);
const int chunk_size = _base_size * lod_factor;
const Vector3 world_center = static_cast<real_t>(chunk_size) * (Vector3(node_pos) + Vector3(0.5, 0.5, 0.5));
const float split_distance_sq = squared(_lod_distance * lod_factor);
const float split_distance_sq = zylann::math::squared(_lod_distance * lod_factor);
Node *node = get_node(node_index);
if (!node->has_children()) {

@ -16,6 +16,9 @@
#include <scene/3d/mesh_instance_3d.h>
#include <scene/resources/packed_scene.h>
using namespace zylann;
//using namespace voxel;
namespace {
Ref<ArrayMesh> build_mesh(
@ -382,7 +385,7 @@ void VoxelLodTerrain::_on_stream_params_changed() {
void VoxelLodTerrain::set_mesh_block_size(unsigned int mesh_block_size) {
// Mesh block size cannot be smaller than data block size, for now
mesh_block_size = clamp(mesh_block_size, get_data_block_size(), VoxelConstants::MAX_BLOCK_SIZE);
mesh_block_size = math::clamp(mesh_block_size, get_data_block_size(), VoxelConstants::MAX_BLOCK_SIZE);
// Only these sizes are allowed at the moment. This stuff is still not supported in a generic way yet,
// some code still exploits the fact it's a multiple of data block size, for performance
@ -814,7 +817,8 @@ void VoxelLodTerrain::set_lod_distance(float p_lod_distance) {
return;
}
_lod_distance = clamp(p_lod_distance, VoxelConstants::MINIMUM_LOD_DISTANCE, VoxelConstants::MAXIMUM_LOD_DISTANCE);
_lod_distance =
math::clamp(p_lod_distance, VoxelConstants::MINIMUM_LOD_DISTANCE, VoxelConstants::MAXIMUM_LOD_DISTANCE);
for (Map<Vector3i, OctreeItem>::Element *E = _lod_octrees.front(); E; E = E->next()) {
OctreeItem &item = E->value();
@ -907,7 +911,7 @@ void VoxelLodTerrain::set_generate_collisions(bool enabled) {
void VoxelLodTerrain::set_collision_lod_count(int lod_count) {
ERR_FAIL_COND(lod_count < 0);
_collision_lod_count = static_cast<unsigned int>(min(lod_count, get_lod_count()));
_collision_lod_count = static_cast<unsigned int>(math::min(lod_count, get_lod_count()));
}
int VoxelLodTerrain::get_collision_lod_count() const {
@ -1097,12 +1101,12 @@ void VoxelLodTerrain::try_schedule_loading_with_neighbors_no_lock(
const int bound_max_y = (_bounds_in_voxels.pos.y + _bounds_in_voxels.size.y) >> p;
const int bound_max_z = (_bounds_in_voxels.pos.z + _bounds_in_voxels.size.z) >> p;
const int min_x = max(p_data_block_pos.x - 1, bound_min_x);
const int min_y = max(p_data_block_pos.y - 1, bound_min_y);
const int min_z = max(p_data_block_pos.z - 1, bound_min_z);
const int max_x = min(p_data_block_pos.x + 2, bound_max_x);
const int max_y = min(p_data_block_pos.y + 2, bound_max_y);
const int max_z = min(p_data_block_pos.z + 2, bound_max_z);
const int min_x = math::max(p_data_block_pos.x - 1, bound_min_x);
const int min_y = math::max(p_data_block_pos.y - 1, bound_min_y);
const int min_z = math::max(p_data_block_pos.z - 1, bound_min_z);
const int max_x = math::min(p_data_block_pos.x + 2, bound_max_x);
const int max_y = math::min(p_data_block_pos.y + 2, bound_max_y);
const int max_z = math::min(p_data_block_pos.z + 2, bound_max_z);
// Not locking here, we assume it's done by the caller
//RWLockRead rlock(data_lod.map_lock);
@ -2562,7 +2566,7 @@ void VoxelLodTerrain::set_voxel_bounds(Box3i p_box) {
}
void VoxelLodTerrain::set_collision_update_delay(int delay_msec) {
_collision_update_delay = clamp(delay_msec, 0, 4000);
_collision_update_delay = math::clamp(delay_msec, 0, 4000);
}
int VoxelLodTerrain::get_collision_update_delay() const {
@ -2570,7 +2574,7 @@ int VoxelLodTerrain::get_collision_update_delay() const {
}
void VoxelLodTerrain::set_lod_fade_duration(float seconds) {
_lod_fade_duration = clamp(seconds, 0.f, 1.f);
_lod_fade_duration = math::clamp(seconds, 0.f, 1.f);
}
float VoxelLodTerrain::get_lod_fade_duration() const {
@ -2594,7 +2598,7 @@ void VoxelLodTerrain::_b_save_modified_blocks() {
}
void VoxelLodTerrain::_b_set_voxel_bounds(AABB aabb) {
ERR_FAIL_COND(!is_valid_size(aabb.size));
ERR_FAIL_COND(!math::is_valid_size(aabb.size));
set_voxel_bounds(Box3i(Vector3iUtil::from_rounded(aabb.position), Vector3iUtil::from_rounded(aabb.size)));
}
@ -2824,7 +2828,7 @@ void VoxelLodTerrain::update_gizmos() {
const Transform3D t = parent_transform * local_transform;
// Squaring because lower lod indexes are more interesting to see, so we give them more contrast.
// Also this might be better with sRGB?
const float g = squared(max(1.f - float(lod_index) / lod_count_f, 0.f));
const float g = math::squared(math::max(1.f - float(lod_index) / lod_count_f, 0.f));
dr.draw_box_mm(t, Color8(255, uint8_t(g * 254.f), 0, 255));
});
}
@ -2861,7 +2865,7 @@ void VoxelLodTerrain::set_show_gizmos(bool enable) {
// This copies at multiple LOD levels to debug mips
Array VoxelLodTerrain::_b_debug_print_sdf_top_down(Vector3i center, Vector3i extents) {
ERR_FAIL_COND_V(!is_valid_size(extents), Array());
ERR_FAIL_COND_V(!math::is_valid_size(extents), Array());
Array image_array;
image_array.resize(get_lod_count());

@ -13,6 +13,8 @@
#include <core/core_string_names.h>
#include <scene/3d/mesh_instance_3d.h>
using namespace zylann;
VoxelTerrain::VoxelTerrain() {
// Note: don't do anything heavy in the constructor.
// Godot may create and destroy dozens of instances of all node types on startup,
@ -190,7 +192,7 @@ unsigned int VoxelTerrain::get_mesh_block_size_pow2() const {
}
void VoxelTerrain::set_mesh_block_size(unsigned int mesh_block_size) {
mesh_block_size = clamp(mesh_block_size, get_data_block_size(), VoxelConstants::MAX_BLOCK_SIZE);
mesh_block_size = math::clamp(mesh_block_size, get_data_block_size(), VoxelConstants::MAX_BLOCK_SIZE);
unsigned int po2;
switch (mesh_block_size) {
@ -885,7 +887,7 @@ void VoxelTerrain::process_viewers() {
static_cast<unsigned int>(static_cast<float>(viewer.view_distance) * view_distance_scale);
const Vector3 local_position = world_to_local_transform.xform(viewer.world_position);
state.view_distance_voxels = min(view_distance_voxels, self._max_view_distance_voxels);
state.view_distance_voxels = math::min(view_distance_voxels, self._max_view_distance_voxels);
state.local_position_voxels = Vector3iUtil::from_floored(local_position);
state.requires_collisions = VoxelServer::get_singleton()->is_viewer_requiring_collisions(viewer_id);
state.requires_meshes = VoxelServer::get_singleton()->is_viewer_requiring_visuals(viewer_id);
@ -899,7 +901,7 @@ void VoxelTerrain::process_viewers() {
Vector3i data_block_pos;
if (state.requires_meshes || state.requires_collisions) {
const int view_distance_mesh_blocks = ceildiv(state.view_distance_voxels, mesh_block_size);
const int view_distance_mesh_blocks = math::ceildiv(state.view_distance_voxels, mesh_block_size);
const int render_to_data_factor = (mesh_block_size / data_block_size);
const Vector3i mesh_block_pos =
Vector3iUtil::floordiv(state.local_position_voxels, mesh_block_size);
@ -913,7 +915,7 @@ void VoxelTerrain::process_viewers() {
.clipped(bounds_in_mesh_blocks);
} else {
view_distance_data_blocks = ceildiv(state.view_distance_voxels, data_block_size);
view_distance_data_blocks = math::ceildiv(state.view_distance_voxels, data_block_size);
data_block_pos = Vector3iUtil::floordiv(state.local_position_voxels, data_block_size);
state.mesh_box = Box3i();
@ -1298,11 +1300,12 @@ void VoxelTerrain::set_bounds(Box3i box) {
// Round to block size
_bounds_in_voxels = _bounds_in_voxels.snapped(get_data_block_size());
const unsigned int largest_dimension = static_cast<unsigned int>(max(max(box.size.x, box.size.y), box.size.z));
const unsigned int largest_dimension =
static_cast<unsigned int>(math::max(math::max(box.size.x, box.size.y), box.size.z));
if (largest_dimension > MAX_VIEW_DISTANCE_FOR_LARGE_VOLUME) {
// Cap view distance to make sure you don't accidentally blow up memory when changing parameters
if (_max_view_distance_voxels > MAX_VIEW_DISTANCE_FOR_LARGE_VOLUME) {
_max_view_distance_voxels = min(_max_view_distance_voxels, MAX_VIEW_DISTANCE_FOR_LARGE_VOLUME);
_max_view_distance_voxels = math::min(_max_view_distance_voxels, MAX_VIEW_DISTANCE_FOR_LARGE_VOLUME);
notify_property_list_changed();
}
}
@ -1340,7 +1343,7 @@ void VoxelTerrain::_b_save_block(Vector3i p_block_pos) {
}
void VoxelTerrain::_b_set_bounds(AABB aabb) {
ERR_FAIL_COND(!is_valid_size(aabb.size));
ERR_FAIL_COND(!math::is_valid_size(aabb.size));
set_bounds(Box3i(Vector3iUtil::from_rounded(aabb.position), Vector3iUtil::from_rounded(aabb.size)));
}

@ -82,13 +82,13 @@ template <typename F2, typename F3, typename FloatT> void test_min_max(F2 noise_
FloatT n = noise_func_2d(x, y);
min_value_2d = min(n, min_value_2d);
max_value_2d = max(n, max_value_2d);
min_value_2d = math::min(n, min_value_2d);
max_value_2d = math::max(n, max_value_2d);
n = noise_func_3d(x, y, z);
min_value_3d = min(n, min_value_3d);
max_value_3d = max(n, max_value_3d);
min_value_3d = math::min(n, min_value_3d);
max_value_3d = math::max(n, max_value_3d);
}
print_line(String("2D | Min: {0}, Max: {1}").format(varray(min_value_2d, max_value_2d)));

@ -739,7 +739,7 @@ void test_instance_data_serialization() {
ERR_FAIL_COND(dst_data.position_range < 0.f);
ERR_FAIL_COND(dst_data.position_range != src_data.position_range);
const float distance_error = max(src_data.position_range, VoxelInstanceBlockData::POSITION_RANGE_MINIMUM) /
const float distance_error = math::max(src_data.position_range, VoxelInstanceBlockData::POSITION_RANGE_MINIMUM) /
float(VoxelInstanceBlockData::POSITION_RESOLUTION);
// Compare layers
@ -756,7 +756,7 @@ void test_instance_data_serialization() {
}
ERR_FAIL_COND(src_layer.instances.size() != dst_layer.instances.size());
const float scale_error = max(src_layer.scale_max - src_layer.scale_min,
const float scale_error = math::max(src_layer.scale_max - src_layer.scale_min,
VoxelInstanceBlockData::SIMPLE_11B_V1_SCALE_RANGE_MINIMUM) /
float(VoxelInstanceBlockData::SIMPLE_11B_V1_SCALE_RESOLUTION);

@ -33,16 +33,16 @@ public:
static inline Box3i get_bounding_box(Box3i a, Box3i b) {
Box3i box;
box.pos.x = min(a.pos.x, b.pos.x);
box.pos.y = min(a.pos.y, b.pos.y);
box.pos.z = min(a.pos.z, b.pos.z);
box.pos.x = zylann::math::min(a.pos.x, b.pos.x);
box.pos.y = zylann::math::min(a.pos.y, b.pos.y);
box.pos.z = zylann::math::min(a.pos.z, b.pos.z);
Vector3i max_a = a.pos + a.size;
Vector3i max_b = b.pos + b.size;
box.size.x = max(max_a.x, max_b.x) - box.pos.x;
box.size.y = max(max_a.y, max_b.y) - box.pos.y;
box.size.z = max(max_a.z, max_b.z) - box.pos.z;
box.size.x = zylann::math::max(max_a.x, max_b.x) - box.pos.x;
box.size.y = zylann::math::max(max_a.y, max_b.y) - box.pos.y;
box.size.z = zylann::math::max(max_a.z, max_b.z) - box.pos.z;
return box;
}
@ -288,8 +288,8 @@ public:
int max_pos = pos + size;
int lim_max_pos = lim_pos + lim_size;
pos = clamp(pos, lim_pos, lim_max_pos);
max_pos = clamp(max_pos, lim_pos, lim_max_pos);
pos = zylann::math::clamp(pos, lim_pos, lim_max_pos);
max_pos = zylann::math::clamp(max_pos, lim_pos, lim_max_pos);
size = max_pos - pos;
if (size < 0) {
@ -329,13 +329,13 @@ public:
void merge_with(const Box3i &other) {
const Vector3i min_pos( //
min(pos.x, other.pos.x), //
min(pos.y, other.pos.y), //
min(pos.z, other.pos.z));
zylann::math::min(pos.x, other.pos.x), //
zylann::math::min(pos.y, other.pos.y), //
zylann::math::min(pos.z, other.pos.z));
const Vector3i max_pos( //
max(pos.x + size.x, other.pos.x + other.size.x), //
max(pos.y + size.y, other.pos.y + other.size.y), //
max(pos.z + size.z, other.pos.z + other.size.z));
zylann::math::max(pos.x + size.x, other.pos.x + other.size.x), //
zylann::math::max(pos.y + size.y, other.pos.y + other.size.y), //
zylann::math::max(pos.z + size.z, other.pos.z + other.size.z));
pos = min_pos;
size = max_pos - min_pos;
}

@ -3,6 +3,8 @@
#include <core/math/vector3.h>
namespace zylann::math {
// Trilinear interpolation between corner values of a cube.
//
// 6---------------7
@ -200,4 +202,6 @@ inline size_t alignup(size_t a, size_t align) {
// return i & (i - 1);
// }
} // namespace zylann::math
#endif // VOXEL_MATH_FUNCS_H

@ -27,7 +27,7 @@ struct Interval {
}
inline static Interval from_unordered_values(float a, float b) {
return Interval(::min(a, b), ::max(a, b));
return Interval(math::min(a, b), math::max(a, b));
}
inline static Interval from_infinity() {
@ -112,7 +112,7 @@ struct Interval {
const float b = min * other.max;
const float c = max * other.min;
const float d = max * other.max;
return Interval{ ::min(a, b, c, d), ::max(a, b, c, d) };
return Interval{ math::min(a, b, c, d), math::max(a, b, c, d) };
}
inline void operator*=(float x) {
@ -136,7 +136,7 @@ struct Interval {
const float b = min / other.max;
const float c = max / other.min;
const float d = max / other.max;
return Interval{ ::min(a, b, c, d), ::max(a, b, c, d) };
return Interval{ math::min(a, b, c, d), math::max(a, b, c, d) };
}
inline Interval operator/(float x) const {
@ -156,33 +156,33 @@ inline Interval operator*(float b, const Interval &a) {
// Functions declared outside, so using intervals or numbers can be the same code (templatable)
inline Interval min_interval(const Interval &a, const Interval &b) {
return Interval(::min(a.min, b.min), ::min(a.max, b.max));
return Interval(min(a.min, b.min), min(a.max, b.max));
}
inline Interval max_interval(const Interval &a, const Interval &b) {
return Interval(::max(a.min, b.min), ::max(a.max, b.max));
return Interval(max(a.min, b.min), max(a.max, b.max));
}
inline Interval min_interval(const Interval &a, const float b) {
return Interval(::min(a.min, b), ::min(a.max, b));
return Interval(min(a.min, b), min(a.max, b));
}
inline Interval max_interval(const Interval &a, const float b) {
return Interval(::max(a.min, b), ::max(a.max, b));
return Interval(max(a.min, b), max(a.max, b));
}
inline Interval sqrt(const Interval &i) {
return Interval{ Math::sqrt(::max(0.f, i.min)), Math::sqrt(::max(0.f, i.max)) };
return Interval{ Math::sqrt(max(0.f, i.min)), Math::sqrt(max(0.f, i.max)) };
}
inline Interval abs(const Interval &i) {
return Interval{ i.contains(0) ? 0 : ::min(Math::abs(i.min), Math::abs(i.max)),
::max(Math::abs(i.min), Math::abs(i.max)) };
return Interval{ i.contains(0) ? 0 : min(Math::abs(i.min), Math::abs(i.max)),
max(Math::abs(i.min), Math::abs(i.max)) };
}
inline Interval clamp(const Interval &i, const Interval &p_min, const Interval &p_max) {
if (p_min.is_single_value() && p_max.is_single_value()) {
return { ::clamp(i.min, p_min.min, p_max.min), ::clamp(i.max, p_min.min, p_max.min) };
return { clamp(i.min, p_min.min, p_max.min), clamp(i.max, p_min.min, p_max.min) };
}
if (i.min >= p_min.max && i.max <= p_max.min) {
return i;
@ -338,8 +338,8 @@ inline Interval smoothstep(float p_from, float p_to, Interval p_weight) {
return Interval::from_single_value(p_from);
}
// Smoothstep is monotonic
float v0 = ::smoothstep(p_from, p_to, p_weight.min);
float v1 = ::smoothstep(p_from, p_to, p_weight.max);
float v0 = smoothstep(p_from, p_to, p_weight.min);
float v1 = smoothstep(p_from, p_to, p_weight.max);
if (v0 <= v1) {
return Interval(v0, v1);
} else {

@ -48,13 +48,13 @@ inline float sdf_subtract(float a, float b) {
}
inline float sdf_smooth_union(float a, float b, float s) {
float h = ::clamp(0.5f + 0.5f * (b - a) / s, 0.0f, 1.0f);
float h = clamp(0.5f + 0.5f * (b - a) / s, 0.0f, 1.0f);
return Math::lerp(b, a, h) - s * h * (1.0f - h);
}
// Inverted a and b because it subtracts SDF a from SDF b
inline float sdf_smooth_subtract(float b, float a, float s) {
float h = ::clamp(0.5f - 0.5f * (b + a) / s, 0.0f, 1.0f);
float h = clamp(0.5f - 0.5f * (b + a) / s, 0.0f, 1.0f);
return Math::lerp(b, -a, h) + s * h * (1.0f - h);
}

@ -324,19 +324,20 @@ inline Vector3i from_zxy_index(unsigned int i, const Vector3i area_size) {
}
inline Vector3i floordiv(const Vector3i v, const Vector3i d) {
return Vector3i(::floordiv(v.x, d.x), ::floordiv(v.y, d.y), ::floordiv(v.z, d.z));
return Vector3i(
zylann::math::floordiv(v.x, d.x), zylann::math::floordiv(v.y, d.y), zylann::math::floordiv(v.z, d.z));
}
inline Vector3i floordiv(const Vector3i v, const int d) {
return Vector3i(::floordiv(v.x, d), ::floordiv(v.y, d), ::floordiv(v.z, d));
return Vector3i(zylann::math::floordiv(v.x, d), zylann::math::floordiv(v.y, d), zylann::math::floordiv(v.z, d));
}
inline Vector3i ceildiv(const Vector3i v, const int d) {
return Vector3i(::ceildiv(v.x, d), ::ceildiv(v.y, d), ::ceildiv(v.z, d));
return Vector3i(zylann::math::ceildiv(v.x, d), zylann::math::ceildiv(v.y, d), zylann::math::ceildiv(v.z, d));
}
inline Vector3i wrap(const Vector3i v, const Vector3i d) {
return Vector3i(::wrap(v.x, d.x), ::wrap(v.y, d.y), ::wrap(v.z, d.z));
return Vector3i(zylann::math::wrap(v.x, d.x), zylann::math::wrap(v.y, d.y), zylann::math::wrap(v.z, d.z));
}
inline bool all_members_equal(const Vector3i v) {

@ -2,6 +2,8 @@
#include "../math/funcs.h"
#include <core/io/image.h>
using namespace zylann;
FastNoise2::FastNoise2() {
// Setup default
update_generator();
@ -174,7 +176,7 @@ bool FastNoise2::is_terrace_enabled() const {
}
void FastNoise2::set_terrace_multiplier(float m) {
const float clamped_multiplier = max(m, 0.f);
const float clamped_multiplier = math::max(m, 0.f);
if (clamped_multiplier == _terrace_multiplier) {
return;
}
@ -187,7 +189,7 @@ float FastNoise2::get_terrace_multiplier() const {
}
void FastNoise2::set_terrace_smoothness(float s) {
const float clamped_smoothness = max(s, 0.f);
const float clamped_smoothness = math::max(s, 0.f);
if (_terrace_smoothness == clamped_smoothness) {
return;
}
@ -279,7 +281,7 @@ FastNoise2::CellularReturnType FastNoise2::get_cellular_return_type() const {
}
void FastNoise2::set_cellular_jitter(float jitter) {
jitter = clamp(jitter, 0.f, 1.f);
jitter = math::clamp(jitter, 0.f, 1.f);
if (_cellular_jitter == jitter) {
return;
}
@ -323,7 +325,7 @@ void FastNoise2::get_noise_2d_grid(Vector2 origin, Vector2i size, Span<float> ds
void FastNoise2::get_noise_3d_grid(Vector3 origin, Vector3i size, Span<float> dst) const {
ERR_FAIL_COND(!is_valid());
ERR_FAIL_COND(!is_valid_size(size));
ERR_FAIL_COND(!math::is_valid_size(size));
ERR_FAIL_COND(dst.size() != size.x * size.y * size.z);
_generator->GenUniformGrid3D(dst.data(), origin.x, origin.y, origin.z, size.x, size.y, size.z, 1.f, _seed);
}

@ -196,7 +196,7 @@ FastNoiseLite::CellularReturnType FastNoiseLite::get_cellular_return_type() cons
}
void FastNoiseLite::set_cellular_jitter(float jitter) {
jitter = clamp(jitter, 0.f, 1.f);
jitter = zylann::math::clamp(jitter, 0.f, 1.f);
if (_cellular_jitter == jitter) {
return;
}

@ -25,8 +25,8 @@ void ProgressiveTaskRunner::process() {
// As the number of pending tasks decreases, we want to keep running the highest amount we calculated.
// we reset when we are done.
_dequeue_count = max(int64_t(_dequeue_count), (int64_t(_tasks.size()) * delta_msec) / COMPLETION_TIME_MSEC);
_dequeue_count = min(_dequeue_count, max(MIN_COUNT, unsigned int(_tasks.size())));
_dequeue_count = math::max(int64_t(_dequeue_count), (int64_t(_tasks.size()) * delta_msec) / COMPLETION_TIME_MSEC);
_dequeue_count = math::min(_dequeue_count, math::max(MIN_COUNT, unsigned int(_tasks.size())));
unsigned int count = _dequeue_count;
while (_tasks.size() > 0 && count > 0) {