180 lines
4.7 KiB
C++
180 lines
4.7 KiB
C++
#include "terrain_primitive.h"
|
|
#include "core/error/error_list.h"
|
|
#include "core/math/expression.h"
|
|
#include "core/math/math_funcs.h"
|
|
#include "terrain_editor/macros.h"
|
|
|
|
void TerrainPrimitive::_bind_methods() {
|
|
BIND_HPROPERTY(Variant::INT, blend_mode, PROPERTY_HINT_ENUM, BlendMode_hint());
|
|
BIND_PROPERTY(Variant::FLOAT, blend_range);
|
|
}
|
|
|
|
// by default does not modify height
|
|
void TerrainPrimitive::evaluate(Vector2, float &) const {}
|
|
|
|
float TerrainPrimitive::blend(float under, float over) const {
|
|
float const difference{ under - over };
|
|
float const distance{ Math::abs(difference) };
|
|
// .25 because we need half of each half of the blend range to be used
|
|
float const center_distance{ this->blend_range == 0.f ? 0.f : this->blend_range * 0.25f - distance / this->blend_range };
|
|
if (center_distance < 0.f) {
|
|
if (this->blend_mode == Both) {
|
|
return over;
|
|
} else if (this->blend_mode == Peak) {
|
|
return under > over ? under : over;
|
|
} else {
|
|
return under > over ? over : under;
|
|
}
|
|
}
|
|
float const smooth_center_distance{ center_distance * center_distance };
|
|
if (this->blend_mode == Both) {
|
|
return over + smooth_center_distance;
|
|
} else {
|
|
return (this->blend_mode == Peak
|
|
? (under > over ? under : over) + smooth_center_distance
|
|
: (under > over ? over : under) - smooth_center_distance);
|
|
}
|
|
}
|
|
|
|
void TerrainPrimitive::set_blend_mode(BlendMode mode) {
|
|
this->blend_mode = mode;
|
|
emit_changed();
|
|
}
|
|
|
|
TerrainPrimitive::BlendMode TerrainPrimitive::get_blend_mode() const {
|
|
return this->blend_mode;
|
|
}
|
|
|
|
void TerrainPrimitive::set_blend_range(float value) {
|
|
this->blend_range = value;
|
|
emit_changed();
|
|
}
|
|
|
|
float TerrainPrimitive::get_blend_range() const {
|
|
return this->blend_range;
|
|
}
|
|
|
|
void PlanePrimitive::_bind_methods() {
|
|
BIND_PROPERTY(Variant::FLOAT, baseline);
|
|
}
|
|
|
|
void PlanePrimitive::evaluate(Vector2, float &io_height) const {
|
|
io_height = blend(io_height, this->baseline);
|
|
}
|
|
|
|
void PlanePrimitive::set_baseline(float value) {
|
|
this->baseline = value;
|
|
emit_changed();
|
|
}
|
|
|
|
float PlanePrimitive::get_baseline() const {
|
|
return this->baseline;
|
|
}
|
|
|
|
void PointPrimitive::_bind_methods() {
|
|
BIND_PROPERTY(Variant::VECTOR2, center);
|
|
BIND_PROPERTY(Variant::FLOAT, slope);
|
|
BIND_PROPERTY(Variant::FLOAT, height);
|
|
}
|
|
|
|
void PointPrimitive::evaluate(Vector2 at, float &io_height) const {
|
|
float distance{ at.distance_to(this->center) };
|
|
io_height = blend(io_height, this->height + distance * this->slope);
|
|
}
|
|
|
|
void PointPrimitive::set_center(Vector2 center) {
|
|
this->center = center;
|
|
emit_changed();
|
|
}
|
|
|
|
Vector2 PointPrimitive::get_center() const {
|
|
return this->center;
|
|
}
|
|
|
|
void PointPrimitive::set_slope(float radius) {
|
|
this->slope = radius;
|
|
emit_changed();
|
|
}
|
|
|
|
float PointPrimitive::get_slope() const {
|
|
return this->slope;
|
|
}
|
|
|
|
void PointPrimitive::set_height(float height) {
|
|
this->height = height;
|
|
emit_changed();
|
|
}
|
|
|
|
float PointPrimitive::get_height() const {
|
|
return this->height;
|
|
}
|
|
|
|
void NoisePrimitive::_bind_methods() {
|
|
BIND_HPROPERTY(Variant::OBJECT, noise, PROPERTY_HINT_RESOURCE_TYPE, "Noise");
|
|
BIND_PROPERTY(Variant::FLOAT, noise_scale);
|
|
BIND_PROPERTY(Variant::FLOAT, noise_amplitude);
|
|
}
|
|
|
|
void NoisePrimitive::evaluate(Vector2 at, float &io_height) const {
|
|
if (this->noise.is_valid()) {
|
|
float noise_sample{ this->noise->get_noise_2dv(at / this->noise_scale) };
|
|
noise_sample *= this->noise_amplitude;
|
|
io_height = blend(io_height, io_height + noise_sample);
|
|
}
|
|
}
|
|
|
|
void NoisePrimitive::set_noise(Ref<Noise> noise) {
|
|
this->noise = noise;
|
|
emit_changed();
|
|
}
|
|
|
|
Ref<Noise> NoisePrimitive::get_noise() const {
|
|
return this->noise;
|
|
}
|
|
|
|
void NoisePrimitive::set_noise_scale(float value) {
|
|
this->noise_scale = value;
|
|
emit_changed();
|
|
}
|
|
|
|
float NoisePrimitive::get_noise_scale() const {
|
|
return this->noise_scale;
|
|
}
|
|
|
|
void NoisePrimitive::set_noise_amplitude(float value) {
|
|
this->noise_amplitude = value;
|
|
emit_changed();
|
|
}
|
|
|
|
float NoisePrimitive::get_noise_amplitude() const {
|
|
return this->noise_amplitude;
|
|
}
|
|
|
|
void ExpressionPrimitive::_bind_methods() {
|
|
BIND_HPROPERTY(Variant::STRING, expression, PROPERTY_HINT_EXPRESSION);
|
|
}
|
|
|
|
void ExpressionPrimitive::evaluate(Vector2 at, float &io_height) const {
|
|
if (!this->valid) {
|
|
return;
|
|
}
|
|
Variant result{ this->expression->execute({ io_height, at }, nullptr, false, true) };
|
|
if (!this->expression->has_execute_failed()) {
|
|
io_height = blend(io_height, float(result.get(0)));
|
|
}
|
|
}
|
|
|
|
void ExpressionPrimitive::set_expression(String expression) {
|
|
this->expression_string = expression;
|
|
this->expression.unref();
|
|
this->expression = memnew(Expression);
|
|
Error error{ this->expression->parse(this->expression_string, { "height", "at" }) };
|
|
if ((this->valid = error == OK)) {
|
|
emit_changed();
|
|
}
|
|
}
|
|
|
|
String ExpressionPrimitive::get_expression() const {
|
|
return this->expression_string;
|
|
}
|