Namespaced Interval
This commit is contained in:
parent
570d870b0a
commit
a9476227cb
@ -782,7 +782,7 @@ void VoxelGraphEditor::update_range_analysis_previews() {
|
|||||||
if (!_graph->try_get_output_port_address(loc, address)) {
|
if (!_graph->try_get_output_port_address(loc, address)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const Interval range = state.get_range(address);
|
const math::Interval range = state.get_range(address);
|
||||||
Control *label = node_view->output_labels[port_index];
|
Control *label = node_view->output_labels[port_index];
|
||||||
label->set_tooltip(String("Min: {0}\nMax: {1}").format(varray(range.min, range.max)));
|
label->set_tooltip(String("Min: {0}\nMax: {1}").format(varray(range.min, range.max)));
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
namespace zylann {
|
namespace zylann {
|
||||||
|
|
||||||
|
using namespace math;
|
||||||
|
|
||||||
ImageRangeGrid::~ImageRangeGrid() {
|
ImageRangeGrid::~ImageRangeGrid() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@ -125,8 +127,8 @@ static void interval_to_pixels(Interval i, int &out_min, int &out_max, int len)
|
|||||||
// Images are finite, intervals are not.
|
// Images are finite, intervals are not.
|
||||||
// It's useless to let the range span a potentially infinite area.
|
// It's useless to let the range span a potentially infinite area.
|
||||||
// The image can repeat, so we clamp to one repetition.
|
// The image can repeat, so we clamp to one repetition.
|
||||||
out_min = clamp(imin, -len, len);
|
out_min = ::clamp(imin, -len, len);
|
||||||
out_max = clamp(imax, -len, len);
|
out_max = ::clamp(imax, -len, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
Interval ImageRangeGrid::get_range(Interval xr, Interval yr) const {
|
Interval ImageRangeGrid::get_range(Interval xr, Interval yr) const {
|
||||||
|
@ -15,16 +15,16 @@ public:
|
|||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void generate(Image &im);
|
void generate(Image &im);
|
||||||
inline Interval get_range() const {
|
inline math::Interval get_range() const {
|
||||||
return _total_range;
|
return _total_range;
|
||||||
}
|
}
|
||||||
Interval get_range(Interval xr, Interval yr) const;
|
math::Interval get_range(math::Interval xr, math::Interval yr) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_LODS = 16;
|
static const int MAX_LODS = 16;
|
||||||
|
|
||||||
struct Lod {
|
struct Lod {
|
||||||
Interval *data = nullptr;
|
math::Interval *data = nullptr;
|
||||||
int size_x = 0;
|
int size_x = 0;
|
||||||
int size_y = 0;
|
int size_y = 0;
|
||||||
};
|
};
|
||||||
@ -36,7 +36,7 @@ private:
|
|||||||
int _lod_base = 0;
|
int _lod_base = 0;
|
||||||
int _lod_count = 0;
|
int _lod_count = 0;
|
||||||
|
|
||||||
Interval _total_range;
|
math::Interval _total_range;
|
||||||
|
|
||||||
FixedArray<Lod, MAX_LODS> _lods;
|
FixedArray<Lod, MAX_LODS> _lods;
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
namespace zylann {
|
namespace zylann {
|
||||||
|
|
||||||
|
using namespace math;
|
||||||
|
|
||||||
// TODO We could skew max derivative estimation if the anchor is on a bump or a dip
|
// TODO We could skew max derivative estimation if the anchor is on a bump or a dip
|
||||||
// because in these cases, it becomes impossible for noise to go further up or further down
|
// because in these cases, it becomes impossible for noise to go further up or further down
|
||||||
|
|
||||||
@ -21,7 +23,7 @@ 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_y = 0.5 * (y.min + y.max);
|
||||||
const float mid_value = noise_func(mid_x, mid_y);
|
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( //
|
return Interval( //
|
||||||
::max(mid_value - max_derivative_half_diagonal * diag, -1.f),
|
::max(mid_value - max_derivative_half_diagonal * diag, -1.f),
|
||||||
@ -38,7 +40,7 @@ inline Interval get_noise_range_3d(
|
|||||||
const float mid_z = 0.5 * (z.min + z.max);
|
const float mid_z = 0.5 * (z.min + z.max);
|
||||||
const float mid_value = noise_func(mid_x, mid_y, mid_z);
|
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( //
|
return Interval( //
|
||||||
::max(mid_value - max_derivative_half_diagonal * diag, -1.f),
|
::max(mid_value - max_derivative_half_diagonal * diag, -1.f),
|
||||||
|
@ -13,8 +13,8 @@ class FastNoiseLiteGradient;
|
|||||||
|
|
||||||
namespace zylann {
|
namespace zylann {
|
||||||
|
|
||||||
Interval get_osn_range_2d(OpenSimplexNoise *noise, Interval x, Interval y);
|
math::Interval get_osn_range_2d(OpenSimplexNoise *noise, math::Interval x, math::Interval y);
|
||||||
Interval get_osn_range_3d(OpenSimplexNoise *noise, Interval x, Interval y, Interval z);
|
math::Interval get_osn_range_3d(OpenSimplexNoise *noise, math::Interval x, math::Interval y, math::Interval z);
|
||||||
|
|
||||||
struct CurveMonotonicSection {
|
struct CurveMonotonicSection {
|
||||||
float x_min;
|
float x_min;
|
||||||
@ -39,13 +39,13 @@ static const float CURVE_RANGE_MARGIN = CMP_EPSILON;
|
|||||||
// we can quickly calculate an accurate range of output values by sampling the curve only at the two points.
|
// we can quickly calculate an accurate range of output values by sampling the curve only at the two points.
|
||||||
void get_curve_monotonic_sections(Curve &curve, std::vector<CurveMonotonicSection> §ions);
|
void get_curve_monotonic_sections(Curve &curve, std::vector<CurveMonotonicSection> §ions);
|
||||||
// Gets the range of Y values for a range of X values on a curve, using precalculated monotonic segments
|
// Gets the range of Y values for a range of X values on a curve, using precalculated monotonic segments
|
||||||
Interval get_curve_range(Curve &curve, const std::vector<CurveMonotonicSection> §ions, Interval x);
|
math::Interval get_curve_range(Curve &curve, const std::vector<CurveMonotonicSection> §ions, math::Interval x);
|
||||||
|
|
||||||
// Legacy
|
// Legacy
|
||||||
Interval get_curve_range(Curve &curve, bool &is_monotonic_increasing);
|
math::Interval get_curve_range(Curve &curve, bool &is_monotonic_increasing);
|
||||||
|
|
||||||
Interval get_heightmap_range(Image &im);
|
math::Interval get_heightmap_range(Image &im);
|
||||||
Interval get_heightmap_range(Image &im, Rect2i rect);
|
math::Interval get_heightmap_range(Image &im, Rect2i rect);
|
||||||
|
|
||||||
namespace math {
|
namespace math {
|
||||||
|
|
||||||
@ -91,10 +91,11 @@ struct Interval3 {
|
|||||||
|
|
||||||
} // namespace math
|
} // namespace math
|
||||||
|
|
||||||
Interval get_fnl_range_2d(const FastNoiseLite *noise, Interval x, Interval y);
|
math::Interval get_fnl_range_2d(const FastNoiseLite *noise, math::Interval x, math::Interval y);
|
||||||
Interval get_fnl_range_3d(const FastNoiseLite *noise, Interval x, Interval y, Interval z);
|
math::Interval get_fnl_range_3d(const FastNoiseLite *noise, math::Interval x, math::Interval y, math::Interval z);
|
||||||
math::Interval2 get_fnl_gradient_range_2d(const FastNoiseLiteGradient *noise, Interval x, Interval y);
|
math::Interval2 get_fnl_gradient_range_2d(const FastNoiseLiteGradient *noise, math::Interval x, math::Interval y);
|
||||||
math::Interval3 get_fnl_gradient_range_3d(const FastNoiseLiteGradient *noise, Interval x, Interval y, Interval z);
|
math::Interval3 get_fnl_gradient_range_3d(
|
||||||
|
const FastNoiseLiteGradient *noise, math::Interval x, math::Interval y, math::Interval z);
|
||||||
|
|
||||||
} // namespace zylann
|
} // namespace zylann
|
||||||
|
|
||||||
|
@ -532,7 +532,7 @@ VoxelGenerator::Result VoxelGeneratorGraph::generate_block(VoxelBlockRequest &in
|
|||||||
const Vector3i gmax = origin + (rmax << input.lod);
|
const Vector3i gmax = origin + (rmax << input.lod);
|
||||||
|
|
||||||
runtime.analyze_range(cache.state, gmin, gmax);
|
runtime.analyze_range(cache.state, gmin, gmax);
|
||||||
const Interval sdf_range = cache.state.get_range(sdf_output_buffer_index) * sdf_scale;
|
const math::Interval sdf_range = cache.state.get_range(sdf_output_buffer_index) * sdf_scale;
|
||||||
bool sdf_is_uniform = false;
|
bool sdf_is_uniform = false;
|
||||||
if (sdf_range.min > clip_threshold && sdf_range.max > clip_threshold) {
|
if (sdf_range.min > clip_threshold && sdf_range.max > clip_threshold) {
|
||||||
out_buffer.fill_area_f(air_sdf, rmin, rmax, channel);
|
out_buffer.fill_area_f(air_sdf, rmin, rmax, channel);
|
||||||
@ -1123,14 +1123,14 @@ VoxelSingleValue VoxelGeneratorGraph::generate_single(Vector3i position, unsigne
|
|||||||
|
|
||||||
// Note, this wrapper may not be used for main generation tasks.
|
// Note, this wrapper may not be used for main generation tasks.
|
||||||
// It is mostly used as a debug tool.
|
// It is mostly used as a debug tool.
|
||||||
Interval VoxelGeneratorGraph::debug_analyze_range(
|
math::Interval VoxelGeneratorGraph::debug_analyze_range(
|
||||||
Vector3i min_pos, Vector3i max_pos, bool optimize_execution_map) const {
|
Vector3i min_pos, Vector3i max_pos, bool optimize_execution_map) const {
|
||||||
std::shared_ptr<const Runtime> runtime_ptr;
|
std::shared_ptr<const Runtime> runtime_ptr;
|
||||||
{
|
{
|
||||||
RWLockRead rlock(_runtime_lock);
|
RWLockRead rlock(_runtime_lock);
|
||||||
runtime_ptr = _runtime;
|
runtime_ptr = _runtime;
|
||||||
}
|
}
|
||||||
ERR_FAIL_COND_V(runtime_ptr == nullptr, Interval::from_single_value(0.f));
|
ERR_FAIL_COND_V(runtime_ptr == nullptr, math::Interval::from_single_value(0.f));
|
||||||
Cache &cache = _cache;
|
Cache &cache = _cache;
|
||||||
const VoxelGraphRuntime &runtime = runtime_ptr->runtime;
|
const VoxelGraphRuntime &runtime = runtime_ptr->runtime;
|
||||||
// Note, buffer size is irrelevant here, because range analysis doesn't use buffers
|
// Note, buffer size is irrelevant here, because range analysis doesn't use buffers
|
||||||
@ -1505,7 +1505,7 @@ Vector2 VoxelGeneratorGraph::_b_debug_analyze_range(Vector3 min_pos, Vector3 max
|
|||||||
ERR_FAIL_COND_V(min_pos.x > max_pos.x, Vector2());
|
ERR_FAIL_COND_V(min_pos.x > max_pos.x, Vector2());
|
||||||
ERR_FAIL_COND_V(min_pos.y > max_pos.y, Vector2());
|
ERR_FAIL_COND_V(min_pos.y > max_pos.y, Vector2());
|
||||||
ERR_FAIL_COND_V(min_pos.z > max_pos.z, Vector2());
|
ERR_FAIL_COND_V(min_pos.z > max_pos.z, Vector2());
|
||||||
const Interval r =
|
const math::Interval r =
|
||||||
debug_analyze_range(Vector3iUtil::from_floored(min_pos), Vector3iUtil::from_floored(max_pos), false);
|
debug_analyze_range(Vector3iUtil::from_floored(min_pos), Vector3iUtil::from_floored(max_pos), false);
|
||||||
return Vector2(r.min, r.max);
|
return Vector2(r.min, r.max);
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ public:
|
|||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
||||||
Interval debug_analyze_range(Vector3i min_pos, Vector3i max_pos, bool optimize_execution_map) const;
|
zylann::math::Interval debug_analyze_range(Vector3i min_pos, Vector3i max_pos, bool optimize_execution_map) const;
|
||||||
float debug_measure_microseconds_per_voxel(bool singular);
|
float debug_measure_microseconds_per_voxel(bool singular);
|
||||||
void debug_load_waves_preset();
|
void debug_load_waves_preset();
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ namespace {
|
|||||||
VoxelGraphNodeDB *g_node_type_db = nullptr;
|
VoxelGraphNodeDB *g_node_type_db = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace math;
|
||||||
|
|
||||||
template <typename F> inline void do_monop(VoxelGraphRuntime::ProcessBufferContext &ctx, F f) {
|
template <typename F> inline void do_monop(VoxelGraphRuntime::ProcessBufferContext &ctx, F f) {
|
||||||
const VoxelGraphRuntime::Buffer &a = ctx.get_input(0);
|
const VoxelGraphRuntime::Buffer &a = ctx.get_input(0);
|
||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
@ -312,7 +314,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
const VoxelGraphRuntime::Buffer &input = ctx.get_input(0);
|
const VoxelGraphRuntime::Buffer &input = ctx.get_input(0);
|
||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
for (unsigned int i = 0; i < out.size; ++i) {
|
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) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
@ -476,7 +478,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
t.inputs.push_back(Port("length"));
|
t.inputs.push_back(Port("length"));
|
||||||
t.outputs.push_back(Port("out"));
|
t.outputs.push_back(Port("out"));
|
||||||
t.process_buffer_func = [](ProcessBufferContext &ctx) {
|
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) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
const Interval a = ctx.get_input(0);
|
const Interval a = ctx.get_input(0);
|
||||||
@ -532,7 +534,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
const VoxelGraphRuntime::Buffer &y1 = ctx.get_input(3);
|
const VoxelGraphRuntime::Buffer &y1 = ctx.get_input(3);
|
||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
for (uint32_t i = 0; i < out.size; ++i) {
|
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) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
@ -566,8 +568,8 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
const VoxelGraphRuntime::Buffer &z1 = ctx.get_input(5);
|
const VoxelGraphRuntime::Buffer &z1 = ctx.get_input(5);
|
||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
for (uint32_t i = 0; i < out.size; ++i) {
|
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]) +
|
||||||
squared(z1.data[i] - z0.data[i]));
|
::squared(z1.data[i] - z0.data[i]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
@ -607,7 +609,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
const Params p = ctx.get_params<Params>();
|
const Params p = ctx.get_params<Params>();
|
||||||
for (uint32_t i = 0; i < out.size; ++i) {
|
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) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
@ -771,7 +773,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
const Params p = ctx.get_params<Params>();
|
const Params p = ctx.get_params<Params>();
|
||||||
for (uint32_t i = 0; i < out.size; ++i) {
|
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) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
@ -1030,7 +1032,8 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
const VoxelGraphRuntime::Buffer &r = ctx.get_input(3);
|
const VoxelGraphRuntime::Buffer &r = ctx.get_input(3);
|
||||||
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
VoxelGraphRuntime::Buffer &out = ctx.get_output(0);
|
||||||
for (uint32_t i = 0; i < out.size; ++i) {
|
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) {
|
t.range_analysis_func = [](RangeAnalysisContext &ctx) {
|
||||||
@ -1386,7 +1389,7 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
|
|||||||
const float x = xb.data[i];
|
const float x = xb.data[i];
|
||||||
const float y = yb.data[i];
|
const float y = yb.data[i];
|
||||||
const float z = zb.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_nx.data[i] = x / len;
|
||||||
out_ny.data[i] = y / len;
|
out_ny.data[i] = y / len;
|
||||||
out_nz.data[i] = z / len;
|
out_nz.data[i] = z / len;
|
||||||
|
@ -536,7 +536,7 @@ void VoxelGraphRuntime::generate_optimized_execution_map(
|
|||||||
// The node is considered skippable, which means its outputs are either locally constant or unused.
|
// The node is considered skippable, which means its outputs are either locally constant or unused.
|
||||||
// Unused buffers can be left as-is, but local constants must be filled in.
|
// Unused buffers can be left as-is, but local constants must be filled in.
|
||||||
if (buffer.local_users_count > 0) {
|
if (buffer.local_users_count > 0) {
|
||||||
const Interval range = state.ranges[output_address];
|
const math::Interval range = state.ranges[output_address];
|
||||||
// If this interval is not a single value then the node should not have been skippable
|
// If this interval is not a single value then the node should not have been skippable
|
||||||
CRASH_COND(!range.is_single_value());
|
CRASH_COND(!range.is_single_value());
|
||||||
const float v = range.min;
|
const float v = range.min;
|
||||||
@ -651,7 +651,7 @@ void VoxelGraphRuntime::prepare_state(State &state, unsigned int buffer_size) co
|
|||||||
buffer.data[j] = bs.constant_value;
|
buffer.data[j] = bs.constant_value;
|
||||||
}
|
}
|
||||||
CRASH_COND(bs.address >= state.ranges.size());
|
CRASH_COND(bs.address >= state.ranges.size());
|
||||||
state.ranges[bs.address] = Interval::from_single_value(bs.constant_value);
|
state.ranges[bs.address] = math::Interval::from_single_value(bs.constant_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -806,7 +806,7 @@ void VoxelGraphRuntime::analyze_range(State &state, Vector3i min_pos, Vector3i m
|
|||||||
ERR_FAIL_COND(state.ranges.size() != _program.buffer_count);
|
ERR_FAIL_COND(state.ranges.size() != _program.buffer_count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Span<Interval> ranges(state.ranges, 0, state.ranges.size());
|
Span<math::Interval> ranges(state.ranges, 0, state.ranges.size());
|
||||||
Span<Buffer> buffers(state.buffers, 0, state.buffers.size());
|
Span<Buffer> buffers(state.buffers, 0, state.buffers.size());
|
||||||
|
|
||||||
// Reset users count, as they might be decreased during the analysis
|
// Reset users count, as they might be decreased during the analysis
|
||||||
@ -816,9 +816,9 @@ void VoxelGraphRuntime::analyze_range(State &state, Vector3i min_pos, Vector3i m
|
|||||||
b.local_users_count = bs.users_count;
|
b.local_users_count = bs.users_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
ranges[_program.x_input_address] = Interval(min_pos.x, max_pos.x);
|
ranges[_program.x_input_address] = math::Interval(min_pos.x, max_pos.x);
|
||||||
ranges[_program.y_input_address] = Interval(min_pos.y, max_pos.y);
|
ranges[_program.y_input_address] = math::Interval(min_pos.y, max_pos.y);
|
||||||
ranges[_program.z_input_address] = Interval(min_pos.z, max_pos.z);
|
ranges[_program.z_input_address] = math::Interval(min_pos.z, max_pos.z);
|
||||||
|
|
||||||
const Span<const uint16_t> operations(_program.operations.data(), 0, _program.operations.size());
|
const Span<const uint16_t> operations(_program.operations.data(), 0, _program.operations.size());
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public:
|
|||||||
return buffers[address];
|
return buffers[address];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const Interval get_range(uint16_t address) const {
|
inline const math::Interval get_range(uint16_t address) const {
|
||||||
// TODO Just for convenience because STL bound checks aren't working in Godot 3
|
// TODO Just for convenience because STL bound checks aren't working in Godot 3
|
||||||
CRASH_COND(address >= buffers.size());
|
CRASH_COND(address >= buffers.size());
|
||||||
return ranges[address];
|
return ranges[address];
|
||||||
@ -98,7 +98,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
friend class VoxelGraphRuntime;
|
friend class VoxelGraphRuntime;
|
||||||
|
|
||||||
std::vector<Interval> ranges;
|
std::vector<math::Interval> ranges;
|
||||||
std::vector<Buffer> buffers;
|
std::vector<Buffer> buffers;
|
||||||
|
|
||||||
unsigned int buffer_size = 0;
|
unsigned int buffer_size = 0;
|
||||||
@ -316,15 +316,15 @@ public:
|
|||||||
class RangeAnalysisContext : public _ProcessContext {
|
class RangeAnalysisContext : public _ProcessContext {
|
||||||
public:
|
public:
|
||||||
inline RangeAnalysisContext(const Span<const uint16_t> inputs, const Span<const uint16_t> outputs,
|
inline RangeAnalysisContext(const Span<const uint16_t> inputs, const Span<const uint16_t> outputs,
|
||||||
const Span<const uint8_t> params, Span<Interval> ranges, Span<Buffer> buffers) :
|
const Span<const uint8_t> params, Span<math::Interval> ranges, Span<Buffer> buffers) :
|
||||||
_ProcessContext(inputs, outputs, params), _ranges(ranges), _buffers(buffers) {}
|
_ProcessContext(inputs, outputs, params), _ranges(ranges), _buffers(buffers) {}
|
||||||
|
|
||||||
inline const Interval get_input(uint32_t i) const {
|
inline const math::Interval get_input(uint32_t i) const {
|
||||||
const uint32_t address = get_input_address(i);
|
const uint32_t address = get_input_address(i);
|
||||||
return _ranges[address];
|
return _ranges[address];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set_output(uint32_t i, const Interval r) {
|
inline void set_output(uint32_t i, const math::Interval r) {
|
||||||
const uint32_t address = get_output_address(i);
|
const uint32_t address = get_output_address(i);
|
||||||
_ranges[address] = r;
|
_ranges[address] = r;
|
||||||
}
|
}
|
||||||
@ -336,7 +336,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Span<Interval> _ranges;
|
Span<math::Interval> _ranges;
|
||||||
Span<Buffer> _buffers;
|
Span<Buffer> _buffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -906,19 +906,19 @@ void test_get_curve_monotonic_sections() {
|
|||||||
ERR_FAIL_COND(sections[0].y_min != 0.f);
|
ERR_FAIL_COND(sections[0].y_min != 0.f);
|
||||||
ERR_FAIL_COND(sections[0].y_max != 1.f);
|
ERR_FAIL_COND(sections[0].y_max != 1.f);
|
||||||
{
|
{
|
||||||
Interval yi = get_curve_range(**curve, sections, Interval(0.f, 1.f));
|
math::Interval yi = get_curve_range(**curve, sections, math::Interval(0.f, 1.f));
|
||||||
ERR_FAIL_COND(!L::is_equal_approx(yi.min, 0.f));
|
ERR_FAIL_COND(!L::is_equal_approx(yi.min, 0.f));
|
||||||
ERR_FAIL_COND(!L::is_equal_approx(yi.max, 1.f));
|
ERR_FAIL_COND(!L::is_equal_approx(yi.max, 1.f));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Interval yi = get_curve_range(**curve, sections, Interval(-2.f, 2.f));
|
math::Interval yi = get_curve_range(**curve, sections, math::Interval(-2.f, 2.f));
|
||||||
ERR_FAIL_COND(!L::is_equal_approx(yi.min, 0.f));
|
ERR_FAIL_COND(!L::is_equal_approx(yi.min, 0.f));
|
||||||
ERR_FAIL_COND(!L::is_equal_approx(yi.max, 1.f));
|
ERR_FAIL_COND(!L::is_equal_approx(yi.max, 1.f));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Interval xi(0.2f, 0.8f);
|
math::Interval xi(0.2f, 0.8f);
|
||||||
Interval yi = get_curve_range(**curve, sections, xi);
|
math::Interval yi = get_curve_range(**curve, sections, xi);
|
||||||
Interval yi_expected(curve->interpolate_baked(xi.min), curve->interpolate_baked(xi.max));
|
math::Interval yi_expected(curve->interpolate_baked(xi.min), curve->interpolate_baked(xi.max));
|
||||||
ERR_FAIL_COND(!L::is_equal_approx(yi.min, yi_expected.min));
|
ERR_FAIL_COND(!L::is_equal_approx(yi.min, yi_expected.min));
|
||||||
ERR_FAIL_COND(!L::is_equal_approx(yi.max, yi_expected.max));
|
ERR_FAIL_COND(!L::is_equal_approx(yi.max, yi_expected.max));
|
||||||
}
|
}
|
||||||
|
@ -4,27 +4,23 @@
|
|||||||
#include "funcs.h"
|
#include "funcs.h"
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
namespace zylann::math {
|
||||||
|
|
||||||
// For interval arithmetic
|
// For interval arithmetic
|
||||||
struct Interval {
|
struct Interval {
|
||||||
// Both inclusive
|
// Both inclusive
|
||||||
float min;
|
float min;
|
||||||
float max;
|
float max;
|
||||||
|
|
||||||
inline Interval() :
|
inline Interval() : min(0), max(0) {}
|
||||||
min(0),
|
|
||||||
max(0) {}
|
|
||||||
|
|
||||||
inline Interval(float p_min, float p_max) :
|
inline Interval(float p_min, float p_max) : min(p_min), max(p_max) {
|
||||||
min(p_min),
|
|
||||||
max(p_max) {
|
|
||||||
#if DEBUG_ENABLED
|
#if DEBUG_ENABLED
|
||||||
CRASH_COND(p_min > p_max);
|
CRASH_COND(p_min > p_max);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Interval(const Interval &other) :
|
inline Interval(const Interval &other) : min(other.min), max(other.max) {}
|
||||||
min(other.min),
|
|
||||||
max(other.max) {}
|
|
||||||
|
|
||||||
inline static Interval from_single_value(float p_val) {
|
inline static Interval from_single_value(float p_val) {
|
||||||
return Interval(p_val, p_val);
|
return Interval(p_val, p_val);
|
||||||
@ -35,9 +31,7 @@ struct Interval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline static Interval from_infinity() {
|
inline static Interval from_infinity() {
|
||||||
return Interval(
|
return Interval(-std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity());
|
||||||
-std::numeric_limits<float>::infinity(),
|
|
||||||
std::numeric_limits<float>::infinity());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool contains(float v) const {
|
inline bool contains(float v) const {
|
||||||
@ -178,25 +172,17 @@ inline Interval max_interval(const Interval &a, const float b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline Interval sqrt(const Interval &i) {
|
inline Interval sqrt(const Interval &i) {
|
||||||
return Interval{
|
return Interval{ Math::sqrt(::max(0.f, i.min)), Math::sqrt(::max(0.f, i.max)) };
|
||||||
Math::sqrt(::max(0.f, i.min)),
|
|
||||||
Math::sqrt(::max(0.f, i.max))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Interval abs(const Interval &i) {
|
inline Interval abs(const Interval &i) {
|
||||||
return Interval{
|
return Interval{ i.contains(0) ? 0 : ::min(Math::abs(i.min), Math::abs(i.max)),
|
||||||
i.contains(0) ? 0 : ::min(Math::abs(i.min), Math::abs(i.max)),
|
::max(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) {
|
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()) {
|
if (p_min.is_single_value() && p_max.is_single_value()) {
|
||||||
return {
|
return { ::clamp(i.min, p_min.min, p_max.min), ::clamp(i.max, p_min.min, p_max.min) };
|
||||||
::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) {
|
if (i.min >= p_min.max && i.max <= p_max.min) {
|
||||||
return i;
|
return i;
|
||||||
@ -224,9 +210,7 @@ inline Interval lerp(const Interval &a, const Interval &b, const Interval &t) {
|
|||||||
const float v6 = a.min + t.max * (b.max - a.min);
|
const float v6 = a.min + t.max * (b.max - a.min);
|
||||||
const float v7 = a.max + t.max * (b.max - a.max);
|
const float v7 = a.max + t.max * (b.max - a.max);
|
||||||
|
|
||||||
return Interval(
|
return Interval(min(v0, v1, v2, v3, v4, v5, v6, v7), max(v0, v1, v2, v3, v4, v5, v6, v7));
|
||||||
min(v0, v1, v2, v3, v4, v5, v6, v7),
|
|
||||||
max(v0, v1, v2, v3, v4, v5, v6, v7));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Interval sin(const Interval &i) {
|
inline Interval sin(const Interval &i) {
|
||||||
@ -354,8 +338,8 @@ inline Interval smoothstep(float p_from, float p_to, Interval p_weight) {
|
|||||||
return Interval::from_single_value(p_from);
|
return Interval::from_single_value(p_from);
|
||||||
}
|
}
|
||||||
// Smoothstep is monotonic
|
// Smoothstep is monotonic
|
||||||
float v0 = smoothstep(p_from, p_to, p_weight.min);
|
float v0 = ::smoothstep(p_from, p_to, p_weight.min);
|
||||||
float v1 = smoothstep(p_from, p_to, p_weight.max);
|
float v1 = ::smoothstep(p_from, p_to, p_weight.max);
|
||||||
if (v0 <= v1) {
|
if (v0 <= v1) {
|
||||||
return Interval(v0, v1);
|
return Interval(v0, v1);
|
||||||
} else {
|
} else {
|
||||||
@ -431,4 +415,6 @@ inline Interval get_length(const Interval &x, const Interval &y, const Interval
|
|||||||
return sqrt(squared(x) + squared(y) + squared(z));
|
return sqrt(squared(x) + squared(y) + squared(z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} //namespace zylann::math
|
||||||
|
|
||||||
#endif // INTERVAL_H
|
#endif // INTERVAL_H
|
||||||
|
@ -48,13 +48,13 @@ inline float sdf_subtract(float a, float b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline float sdf_smooth_union(float a, float b, float s) {
|
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);
|
return Math::lerp(b, a, h) - s * h * (1.0f - h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inverted a and b because it subtracts SDF a from SDF b
|
// Inverted a and b because it subtracts SDF a from SDF b
|
||||||
inline float sdf_smooth_subtract(float b, float a, float s) {
|
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);
|
return Math::lerp(b, -a, h) + s * h * (1.0f - h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,14 +465,14 @@ void FastNoise2::update_generator() {
|
|||||||
_generator = generator_node;
|
_generator = generator_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interval FastNoise2::get_estimated_output_range() const {
|
zylann::math::Interval FastNoise2::get_estimated_output_range() const {
|
||||||
// TODO Optimize: better range analysis on FastNoise2
|
// TODO Optimize: better range analysis on FastNoise2
|
||||||
// Most noises should have known bounds like FastNoiseLite, but the node-graph nature of this library
|
// Most noises should have known bounds like FastNoiseLite, but the node-graph nature of this library
|
||||||
// can make it difficult to calculate. Would be nice if the library could provide that out of the box.
|
// can make it difficult to calculate. Would be nice if the library could provide that out of the box.
|
||||||
if (is_remap_enabled()) {
|
if (is_remap_enabled()) {
|
||||||
return Interval(get_remap_output_min(), get_remap_output_max());
|
return zylann::math::Interval(get_remap_output_min(), get_remap_output_max());
|
||||||
} else {
|
} else {
|
||||||
return Interval(-1.f, 1.f);
|
return zylann::math::Interval(-1.f, 1.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ public:
|
|||||||
|
|
||||||
void generate_image(Ref<Image> image, bool tileable) const;
|
void generate_image(Ref<Image> image, bool tileable) const;
|
||||||
|
|
||||||
Interval get_estimated_output_range() const;
|
zylann::math::Interval get_estimated_output_range() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Non-static method for scripts because Godot4 does not support binding static methods (it's only implemented for
|
// Non-static method for scripts because Godot4 does not support binding static methods (it's only implemented for
|
||||||
|
Loading…
x
Reference in New Issue
Block a user