feat: added expression value to every primitive
This commit is contained in:
parent
63c391593d
commit
2b04362ecc
6 changed files with 121 additions and 48 deletions
|
|
@ -21,7 +21,6 @@ void initialize_terrain_editor_module(ModuleInitializationLevel p_level) {
|
||||||
ClassDB::register_class<PlanePrimitive>();
|
ClassDB::register_class<PlanePrimitive>();
|
||||||
ClassDB::register_class<PointPrimitive>();
|
ClassDB::register_class<PointPrimitive>();
|
||||||
ClassDB::register_class<NoisePrimitive>();
|
ClassDB::register_class<NoisePrimitive>();
|
||||||
ClassDB::register_class<ExpressionPrimitive>();
|
|
||||||
ClassDB::register_class<PointPrimitiveNode>();
|
ClassDB::register_class<PointPrimitiveNode>();
|
||||||
ClassDB::register_class<TerrainMeshEditor>();
|
ClassDB::register_class<TerrainMeshEditor>();
|
||||||
ClassDB::register_class<SaveData>();
|
ClassDB::register_class<SaveData>();
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
void TerrainPrimitive::_bind_methods() {
|
void TerrainPrimitive::_bind_methods() {
|
||||||
BIND_HPROPERTY(Variant::INT, blend_mode, PROPERTY_HINT_ENUM, BlendMode_hint());
|
BIND_HPROPERTY(Variant::INT, blend_mode, PROPERTY_HINT_ENUM, BlendMode_hint());
|
||||||
BIND_PROPERTY(Variant::FLOAT, blend_range);
|
BIND_PROPERTY(Variant::FLOAT, blend_range);
|
||||||
|
BIND_HPROPERTY(Variant::STRING, expression, PROPERTY_HINT_EXPRESSION);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_expression_error"), &self_type::get_expression_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// by default does not modify height
|
// by default does not modify height
|
||||||
|
|
@ -54,12 +56,42 @@ float TerrainPrimitive::get_blend_range() const {
|
||||||
return this->blend_range;
|
return this->blend_range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerrainPrimitive::set_expression(String expression) {
|
||||||
|
this->expr_text = expression;
|
||||||
|
if (expression.is_empty()) {
|
||||||
|
this->expression_valid = false;
|
||||||
|
} else {
|
||||||
|
_parse_new_expression(expression);
|
||||||
|
}
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
String TerrainPrimitive::get_expression() const {
|
||||||
|
return this->expr_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
String TerrainPrimitive::get_expression_error() const {
|
||||||
|
if (this->expression_valid) {
|
||||||
|
return "Valid Expression";
|
||||||
|
} else {
|
||||||
|
return this->expression->get_error_text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PlanePrimitive::_bind_methods() {
|
void PlanePrimitive::_bind_methods() {
|
||||||
BIND_PROPERTY(Variant::FLOAT, baseline);
|
BIND_PROPERTY(Variant::FLOAT, baseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanePrimitive::evaluate(Vector2, float &io_height) const {
|
void PlanePrimitive::_parse_new_expression(String expression) {
|
||||||
io_height = blend(io_height, this->baseline);
|
this->expression_valid = this->expression->parse(expression, { "previous_height", "at", "baseline" }) == OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlanePrimitive::evaluate(Vector2 at, float &io_height) const {
|
||||||
|
float height{ this->baseline };
|
||||||
|
if (this->expression_valid) {
|
||||||
|
height = this->expression->execute({ io_height, at, this->baseline }, nullptr, false, true);
|
||||||
|
}
|
||||||
|
io_height = blend(io_height, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanePrimitive::set_baseline(float value) {
|
void PlanePrimitive::set_baseline(float value) {
|
||||||
|
|
@ -77,9 +109,17 @@ void PointPrimitive::_bind_methods() {
|
||||||
BIND_PROPERTY(Variant::FLOAT, height);
|
BIND_PROPERTY(Variant::FLOAT, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PointPrimitive::_parse_new_expression(String expression) {
|
||||||
|
this->expression_valid = this->expression->parse(expression, { "previous_height", "at", "center", "height", "sloped_height", "distance", "slope" }) == OK;
|
||||||
|
}
|
||||||
|
|
||||||
void PointPrimitive::evaluate(Vector2 at, float &io_height) const {
|
void PointPrimitive::evaluate(Vector2 at, float &io_height) const {
|
||||||
float distance{ at.distance_to(this->center) };
|
float distance{ at.distance_to(this->center) };
|
||||||
io_height = blend(io_height, this->height + distance * this->slope);
|
float height{ this->height + distance * this->slope };
|
||||||
|
if (this->expression_valid) {
|
||||||
|
height = this->expression->execute({ io_height, at, this->center, this->height, height, distance, this->slope }, nullptr, false, true);
|
||||||
|
}
|
||||||
|
io_height = blend(io_height, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointPrimitive::set_center(Vector2 center) {
|
void PointPrimitive::set_center(Vector2 center) {
|
||||||
|
|
@ -115,6 +155,10 @@ void NoisePrimitive::_bind_methods() {
|
||||||
BIND_PROPERTY(Variant::FLOAT, noise_amplitude);
|
BIND_PROPERTY(Variant::FLOAT, noise_amplitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoisePrimitive::_parse_new_expression(String expression) {
|
||||||
|
this->expression_valid = this->expression->parse(expression, { "previous_height", "at", "noise", "amplitude", "scale" }) == OK;
|
||||||
|
}
|
||||||
|
|
||||||
void NoisePrimitive::evaluate(Vector2 at, float &io_height) const {
|
void NoisePrimitive::evaluate(Vector2 at, float &io_height) const {
|
||||||
if (this->noise.is_valid()) {
|
if (this->noise.is_valid()) {
|
||||||
if (Math::is_nan(io_height) || Math::is_inf(io_height)) {
|
if (Math::is_nan(io_height) || Math::is_inf(io_height)) {
|
||||||
|
|
@ -122,7 +166,11 @@ void NoisePrimitive::evaluate(Vector2 at, float &io_height) const {
|
||||||
}
|
}
|
||||||
float noise_sample{ this->noise->get_noise_2dv(at / this->noise_scale) };
|
float noise_sample{ this->noise->get_noise_2dv(at / this->noise_scale) };
|
||||||
noise_sample *= this->noise_amplitude;
|
noise_sample *= this->noise_amplitude;
|
||||||
io_height = blend(io_height, io_height + noise_sample);
|
float height{ noise_sample + io_height };
|
||||||
|
if (this->expression_valid) {
|
||||||
|
height = this->expression->execute({ io_height, at, noise_sample, this->noise_amplitude, this->noise_scale }, nullptr, false, true);
|
||||||
|
}
|
||||||
|
io_height = blend(io_height, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,31 +206,3 @@ void NoisePrimitive::set_noise_amplitude(float value) {
|
||||||
float NoisePrimitive::get_noise_amplitude() const {
|
float NoisePrimitive::get_noise_amplitude() const {
|
||||||
return this->noise_amplitude;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float blend(float under, float over) const;
|
float blend(float under, float over) const;
|
||||||
|
virtual void _parse_new_expression(String expression) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// evaluate the height of this primitive at point, returns the weight of the effect, out_height will be set to the closest point on the primitive
|
// evaluate the height of this primitive at point, returns the weight of the effect, out_height will be set to the closest point on the primitive
|
||||||
|
|
@ -27,10 +28,18 @@ public:
|
||||||
BlendMode get_blend_mode() const;
|
BlendMode get_blend_mode() const;
|
||||||
void set_blend_range(float blend_range);
|
void set_blend_range(float blend_range);
|
||||||
float get_blend_range() const;
|
float get_blend_range() const;
|
||||||
|
void set_expression(String expression);
|
||||||
|
String get_expression() const;
|
||||||
|
String get_expression_error() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float blend_range{ 4.f };
|
float blend_range{ 4.f };
|
||||||
BlendMode blend_mode{ Peak };
|
BlendMode blend_mode{ Peak };
|
||||||
|
String expr_text{};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool expression_valid{};
|
||||||
|
Ref<Expression> expression{ memnew(Expression) };
|
||||||
};
|
};
|
||||||
|
|
||||||
MAKE_TYPE_INFO(TerrainPrimitive::BlendMode, Variant::INT);
|
MAKE_TYPE_INFO(TerrainPrimitive::BlendMode, Variant::INT);
|
||||||
|
|
@ -39,6 +48,9 @@ class PlanePrimitive : public TerrainPrimitive {
|
||||||
GDCLASS(PlanePrimitive, TerrainPrimitive);
|
GDCLASS(PlanePrimitive, TerrainPrimitive);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _parse_new_expression(String expression) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void evaluate(Vector2 at, float &io_height) const override;
|
void evaluate(Vector2 at, float &io_height) const override;
|
||||||
void set_baseline(float value);
|
void set_baseline(float value);
|
||||||
|
|
@ -52,6 +64,9 @@ class PointPrimitive : public TerrainPrimitive {
|
||||||
GDCLASS(PointPrimitive, TerrainPrimitive);
|
GDCLASS(PointPrimitive, TerrainPrimitive);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _parse_new_expression(String expression) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void evaluate(Vector2 at, float &io_height) const override;
|
void evaluate(Vector2 at, float &io_height) const override;
|
||||||
void set_center(Vector2 center);
|
void set_center(Vector2 center);
|
||||||
|
|
@ -71,6 +86,9 @@ class NoisePrimitive : public TerrainPrimitive {
|
||||||
GDCLASS(NoisePrimitive, TerrainPrimitive);
|
GDCLASS(NoisePrimitive, TerrainPrimitive);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _parse_new_expression(String expression) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void evaluate(Vector2 at, float &io_height) const override;
|
void evaluate(Vector2 at, float &io_height) const override;
|
||||||
void set_noise(Ref<Noise> noise);
|
void set_noise(Ref<Noise> noise);
|
||||||
|
|
@ -85,18 +103,3 @@ private:
|
||||||
float noise_scale{ 1.f };
|
float noise_scale{ 1.f };
|
||||||
float noise_amplitude{ 1.f };
|
float noise_amplitude{ 1.f };
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpressionPrimitive : public TerrainPrimitive {
|
|
||||||
GDCLASS(ExpressionPrimitive, TerrainPrimitive);
|
|
||||||
static void _bind_methods();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void evaluate(Vector2 at, float &io_height) const override;
|
|
||||||
void set_expression(String expression);
|
|
||||||
String get_expression() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Ref<Expression> expression{ memnew(Expression) };
|
|
||||||
String expression_string{ "height" };
|
|
||||||
bool valid{ false };
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -95,8 +95,10 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||||
load_path = "res://.godot/imported/point.svg-e68fd7c1e788d2c48d769cc58eba6e98.ctex"
|
load_path = "res://.godot/imported/point.svg-e68fd7c1e788d2c48d769cc58eba6e98.ctex"
|
||||||
|
|
||||||
[sub_resource type="PointPrimitive" id="PointPrimitive_5lcyj"]
|
[sub_resource type="PointPrimitive" id="PointPrimitive_5lcyj"]
|
||||||
|
expression = "sloped_height"
|
||||||
|
|
||||||
[sub_resource type="PlanePrimitive" id="PlanePrimitive_5lcyj"]
|
[sub_resource type="PlanePrimitive" id="PlanePrimitive_5lcyj"]
|
||||||
|
expression = "baseline"
|
||||||
|
|
||||||
[sub_resource type="FastNoiseLite" id="FastNoiseLite_3vi5u"]
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_3vi5u"]
|
||||||
frequency = 0.0336
|
frequency = 0.0336
|
||||||
|
|
@ -107,6 +109,7 @@ domain_warp_fractal_lacunarity = 5.512
|
||||||
domain_warp_fractal_gain = 0.662
|
domain_warp_fractal_gain = 0.662
|
||||||
|
|
||||||
[sub_resource type="NoisePrimitive" id="NoisePrimitive_5lcyj"]
|
[sub_resource type="NoisePrimitive" id="NoisePrimitive_5lcyj"]
|
||||||
|
expression = "previous_height + noise_sample"
|
||||||
noise = SubResource("FastNoiseLite_3vi5u")
|
noise = SubResource("FastNoiseLite_3vi5u")
|
||||||
|
|
||||||
[sub_resource type="GDScript" id="GDScript_74j0u"]
|
[sub_resource type="GDScript" id="GDScript_74j0u"]
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,36 @@ func _pressed() -> void:
|
||||||
terrain.current_selected = null
|
terrain.current_selected = null
|
||||||
"
|
"
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id="GDScript_2i6ni"]
|
||||||
|
resource_name = "ExpressionEditor"
|
||||||
|
script/source = "extends TextEdit
|
||||||
|
|
||||||
|
@onready var terrain : TerrainMeshEditor = $\"../../..\".terrain
|
||||||
|
@onready var primitive : TerrainPrimitive = terrain.current_selected
|
||||||
|
|
||||||
|
var pushing_change : bool = false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
primitive.changed.connect(_primitive_changed)
|
||||||
|
text_changed.connect(_text_changed)
|
||||||
|
$ExpressionTimerBuffer.timeout.connect(_timeout)
|
||||||
|
_primitive_changed()
|
||||||
|
|
||||||
|
func _primitive_changed():
|
||||||
|
if not pushing_change and not has_focus():
|
||||||
|
pushing_change = true
|
||||||
|
self.text = primitive.expression
|
||||||
|
pushing_change = false
|
||||||
|
$\"../ExpressionError\".text = primitive.get_expression_error()
|
||||||
|
|
||||||
|
func _text_changed():
|
||||||
|
if not pushing_change:
|
||||||
|
$ExpressionTimerBuffer.start(2)
|
||||||
|
|
||||||
|
func _timeout():
|
||||||
|
primitive.expression = text
|
||||||
|
"
|
||||||
|
|
||||||
[node name="Primitive" type="MarginContainer" unique_id=905749607]
|
[node name="Primitive" type="MarginContainer" unique_id=905749607]
|
||||||
offset_right = 302.0
|
offset_right = 302.0
|
||||||
offset_bottom = 230.0
|
offset_bottom = 230.0
|
||||||
|
|
@ -91,6 +121,24 @@ icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
script = SubResource("GDScript_ivj30")
|
script = SubResource("GDScript_ivj30")
|
||||||
|
|
||||||
|
[node name="Expression" type="TextEdit" parent="VBoxContainer" unique_id=1154146381]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
placeholder_text = "expression"
|
||||||
|
backspace_deletes_composite_character_enabled = true
|
||||||
|
caret_blink = true
|
||||||
|
caret_move_on_right_click = false
|
||||||
|
draw_tabs = true
|
||||||
|
draw_spaces = true
|
||||||
|
script = SubResource("GDScript_2i6ni")
|
||||||
|
|
||||||
|
[node name="ExpressionTimerBuffer" type="Timer" parent="VBoxContainer/Expression" unique_id=1376932514]
|
||||||
|
wait_time = 2.0
|
||||||
|
|
||||||
|
[node name="ExpressionError" type="Label" parent="VBoxContainer" unique_id=1840569033]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Error Text"
|
||||||
|
|
||||||
[connection signal="item_selected" from="VBoxContainer/BlendModeSelector" to="VBoxContainer/BlendModeSelector" method="_on_item_selected"]
|
[connection signal="item_selected" from="VBoxContainer/BlendModeSelector" to="VBoxContainer/BlendModeSelector" method="_on_item_selected"]
|
||||||
|
|
||||||
[editable path="VBoxContainer/FloatEditor3"]
|
[editable path="VBoxContainer/FloatEditor3"]
|
||||||
|
|
|
||||||
BIN
test-terrains/hills.terrain.res
Normal file
BIN
test-terrains/hills.terrain.res
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue