Implemented the isolevel brush in TerrainWorldEditor.

This commit is contained in:
Relintai 2025-02-04 18:27:35 +01:00
parent 9cd4da72c8
commit 4114c23649
2 changed files with 168 additions and 28 deletions

View File

@ -31,6 +31,9 @@
#include "terrain_world_editor.h"
#include "core/error/error_macros.h"
#include "core/math/plane.h"
#include "editor/editor_plugin.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@ -70,26 +73,65 @@ EditorPlugin::AfterGUIInput TerrainWorldEditor::forward_spatial_input_event(Came
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (!_mouse_down) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
switch (_tool_mode) {
case TOOL_MODE_ADD:
case TOOL_MODE_REMOVE: {
} break;
case TOOL_MODE_ISOLEVEL_BRUSH: {
Vector3 position;
Vector3 normal;
if (get_draw_world_coordinate(p_camera, Point2(mm->get_position().x, mm->get_position().y), position, normal)) {
isolevel_brush_draw(position);
}
} break;
case TOOL_MODE_PAINT_BRUSH: {
} break;
case TOOL_MODE_PAINT_PICKER: {
} break;
}
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
if (mb->is_pressed()) {
if (mb->get_button_index() == BUTTON_LEFT) {
_mouse_down = true;
switch (_tool_mode) {
case TOOL_MODE_ADD:
case TOOL_MODE_REMOVE:
return do_add_remove_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true);
case TOOL_MODE_ISOLEVEL_BRUSH:
break;
case TOOL_MODE_PAINT_BRUSH:
break;
case TOOL_MODE_PAINT_PICKER:
break;
case TOOL_MODE_ISOLEVEL_BRUSH: {
Vector3 position;
Vector3 normal;
if (get_draw_world_coordinate(p_camera, Point2(mb->get_position().x, mb->get_position().y), position, normal)) {
_mouse_down = true;
isolevel_brush_draw(position);
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
} break;
case TOOL_MODE_PAINT_BRUSH: {
} break;
case TOOL_MODE_PAINT_PICKER: {
} break;
}
return EditorPlugin::AFTER_GUI_INPUT_STOP;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
} else {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
@ -178,6 +220,100 @@ EditorPlugin::AfterGUIInput TerrainWorldEditor::do_add_remove_action(Camera *p_c
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
bool TerrainWorldEditor::get_draw_world_coordinate(Camera *p_camera, const Point2 &p_point, Vector3 &r_position, Vector3 &r_normal) {
Camera *camera = p_camera;
Vector3 from = camera->project_ray_origin(p_point);
Vector3 to = from + camera->project_ray_normal(p_point) * 10000;
Transform local_xform = _world->get_global_transform().affine_inverse();
from = local_xform.xform(from);
to = local_xform.xform(to);
PhysicsDirectSpaceState *ss = _world->get_world_3d()->get_direct_space_state();
PhysicsDirectSpaceState::RayResult res;
if (ss->intersect_ray(from, to, res)) {
r_position = res.position;
r_normal = res.normal;
return true;
}
Vector3 intersection;
Plane xz_plane(Vector3(), Vector3(0, 1, 0));
if (xz_plane.intersects_ray(from, to, &intersection)) {
r_normal = Vector3(0, 1, 0);
r_position = intersection;
return true;
}
return false;
}
void TerrainWorldEditor::isolevel_brush_draw(const Vector3 &p_world_position) {
if (_isolevel_brush_size == 0) {
return;
}
if (_isolevel_brush_channel == -1) {
return;
}
Vector2i wdp = _world->world_position_to_world_data_position(p_world_position);
int ilbh = _isolevel_brush_size / 2;
// Value will likely need more fine tuning.
float s = 10.0 * _isolevel_brush_strength;
_undo_redo->create_action("Isolevel Brush Draw");
// TODO use a proper circle drawing algorithm.
for (int x = -ilbh; x < ilbh; ++x) {
for (int y = -ilbh; y < ilbh; ++y) {
float l = Vector2(x, y).length();
if (l > ilbh) {
continue;
}
Vector2i vwp = wdp + Vector2i(x, y);
uint8_t orig_val = _world->get_voxel_at_world_data_position(vwp, _isolevel_brush_channel);
int pil = orig_val;
Vector2 tv = Vector2(ilbh - ABS(x), ilbh - ABS(y));
float t = tv.length() / (float)ilbh;
float sl = Math::lerp(0, s, t * _isolevel_brush_smoothness);
float npil = 0;
switch (_isolevel_brush_type) {
case ISOLEVEL_BRUSH_TYPE_ADD: {
npil = pil + sl;
} break;
case ISOLEVEL_BRUSH_TYPE_SUBSTRACT: {
npil = pil - sl;
} break;
case ISOLEVEL_BRUSH_TYPE_SET: {
npil = _isolevel_brush_strength * 255.0;
} break;
}
npil = CLAMP(npil, 0, 255);
uint8_t new_val = static_cast<uint8_t>(npil);
_undo_redo->add_do_method(_world, "set_voxel_at_world_data_position", vwp, new_val, true, _isolevel_brush_allow_create_chunks);
_undo_redo->add_undo_method(_world, "set_voxel_at_world_data_position", vwp, orig_val, true, _isolevel_brush_allow_create_chunks);
}
}
_undo_redo->commit_action();
}
void TerrainWorldEditor::edit(TerrainWorld *p_world) {
if (_world == p_world) {
return;
@ -268,8 +404,8 @@ TerrainWorldEditor::TerrainWorldEditor() {
_isolevel_brush_channel = -1;
_isolevel_brush_size = 10;
_isolevel_brush_strength = 25;
_isolevel_brush_smoothness = 10;
_isolevel_brush_strength = 0.25;
_isolevel_brush_smoothness = 0.5;
//_brush_type = BRUSH_TYPE_CIRCLE;
_isolevel_brush_type = ISOLEVEL_BRUSH_TYPE_ADD;
_isolevel_brush_allow_create_chunks = false;
@ -289,8 +425,8 @@ TerrainWorldEditor::TerrainWorldEditor(EditorNode *p_editor) {
_isolevel_brush_channel = -1;
_isolevel_brush_size = 10;
_isolevel_brush_strength = 25;
_isolevel_brush_smoothness = 10;
_isolevel_brush_strength = 0.25;
_isolevel_brush_smoothness = 0.5;
//_brush_type = BRUSH_TYPE_CIRCLE;
_isolevel_brush_type = ISOLEVEL_BRUSH_TYPE_ADD;
_isolevel_brush_allow_create_chunks = false;
@ -423,13 +559,13 @@ TerrainWorldEditor::TerrainWorldEditor(EditorNode *p_editor) {
_isolevel_brush_type_set_button->set_shortcut(ED_SHORTCUT("terrain_world_editor/isolevel_brush_type_set", "Isolevel Brush Type Set", KEY_J));
isolevel_brush_flow_container->add_child(_isolevel_brush_type_set_button);
_isolevel_brush_type_smooth_button = memnew(ToolButton);
_isolevel_brush_type_smooth_button->set_toggle_mode(true);
_isolevel_brush_type_smooth_button->set_button_group(_isolevel_brush_tool_button_group);
_isolevel_brush_type_smooth_button->set_meta("type", ISOLEVEL_BRUSH_TYPE_SMOOTH);
_isolevel_brush_type_smooth_button->connect("button_up", this, "_on_isolevel_brush_tool_button_pressed");
_isolevel_brush_type_smooth_button->set_shortcut(ED_SHORTCUT("terrain_world_editor/isolevel_brush_type_smooth", "Isolevel Brush Type Smooth", KEY_K));
isolevel_brush_flow_container->add_child(_isolevel_brush_type_smooth_button);
//_isolevel_brush_type_smooth_button = memnew(ToolButton);
//_isolevel_brush_type_smooth_button->set_toggle_mode(true);
//_isolevel_brush_type_smooth_button->set_button_group(_isolevel_brush_tool_button_group);
//_isolevel_brush_type_smooth_button->set_meta("type", ISOLEVEL_BRUSH_TYPE_SMOOTH);
//_isolevel_brush_type_smooth_button->connect("button_up", this, "_on_isolevel_brush_tool_button_pressed");
//_isolevel_brush_type_smooth_button->set_shortcut(ED_SHORTCUT("terrain_world_editor/isolevel_brush_type_smooth", "Isolevel Brush Type Smooth", KEY_K));
//isolevel_brush_flow_container->add_child(_isolevel_brush_type_smooth_button);
_isolevel_brush_allow_creating_chunks_button = memnew(ToolButton);
_isolevel_brush_allow_creating_chunks_button->set_toggle_mode(true);
@ -443,7 +579,7 @@ TerrainWorldEditor::TerrainWorldEditor(EditorNode *p_editor) {
_isolevel_brush_size_slider = memnew(HSlider);
_isolevel_brush_size_slider->set_min(1);
_isolevel_brush_size_slider->set_max(250);
_isolevel_brush_size_slider->set_max(100);
_isolevel_brush_size_slider->set_value(_isolevel_brush_size);
_isolevel_brush_size_slider->set_v_size_flags(SIZE_EXPAND_FILL);
_isolevel_brush_size_slider->set_tooltip(TTR("Brush Size"));
@ -455,8 +591,9 @@ TerrainWorldEditor::TerrainWorldEditor(EditorNode *p_editor) {
_isolevel_brush_tool_container->add_child(isolevel_brush_strength_label);
_isolevel_brush_strength_slider = memnew(HSlider);
_isolevel_brush_strength_slider->set_min(0);
_isolevel_brush_strength_slider->set_max(100);
_isolevel_brush_strength_slider->set_min(0.01);
_isolevel_brush_strength_slider->set_max(1);
_isolevel_brush_strength_slider->set_step(0);
_isolevel_brush_strength_slider->set_value(_isolevel_brush_strength);
_isolevel_brush_strength_slider->set_v_size_flags(SIZE_EXPAND_FILL);
_isolevel_brush_strength_slider->set_tooltip(TTR("Brush Strength"));
@ -468,8 +605,9 @@ TerrainWorldEditor::TerrainWorldEditor(EditorNode *p_editor) {
_isolevel_brush_tool_container->add_child(isolevel_brush_smoothness_label);
_isolevel_brush_smoothness_slider = memnew(HSlider);
_isolevel_brush_smoothness_slider->set_min(1);
_isolevel_brush_smoothness_slider->set_max(250);
_isolevel_brush_smoothness_slider->set_min(0.01);
_isolevel_brush_smoothness_slider->set_max(1);
_isolevel_brush_smoothness_slider->set_step(0);
_isolevel_brush_smoothness_slider->set_value(_isolevel_brush_smoothness);
_isolevel_brush_smoothness_slider->set_v_size_flags(SIZE_EXPAND_FILL);
_isolevel_brush_smoothness_slider->set_tooltip(TTR("Brush Smoothness"));
@ -524,7 +662,7 @@ void TerrainWorldEditor::_notification(int p_what) {
_isolevel_brush_type_add_button->set_icon(get_theme_icon("MoveUp", "EditorIcons"));
_isolevel_brush_type_substract_button->set_icon(get_theme_icon("MoveDown", "EditorIcons"));
_isolevel_brush_type_set_button->set_icon(get_theme_icon("CanvasLayer", "EditorIcons"));
_isolevel_brush_type_smooth_button->set_icon(get_theme_icon("Blend", "EditorIcons"));
//_isolevel_brush_type_smooth_button->set_icon(get_theme_icon("Blend", "EditorIcons"));
_isolevel_brush_allow_creating_chunks_button->set_icon(get_theme_icon("Add", "EditorIcons"));
} break;
}

View File

@ -63,6 +63,8 @@ public:
void edit(TerrainWorld *p_world);
EditorPlugin::AfterGUIInput do_add_remove_action(Camera *p_camera, const Point2 &p_point, bool p_click);
bool get_draw_world_coordinate(Camera *p_camera, const Point2 &p_point, Vector3 &r_position, Vector3 &r_normal);
void isolevel_brush_draw(const Vector3 &p_world_position);
TerrainWorldEditor();
TerrainWorldEditor(EditorNode *p_editor);
@ -98,7 +100,7 @@ private:
ISOLEVEL_BRUSH_TYPE_ADD = 0,
ISOLEVEL_BRUSH_TYPE_SUBSTRACT,
ISOLEVEL_BRUSH_TYPE_SET,
ISOLEVEL_BRUSH_TYPE_SMOOTH,
//ISOLEVEL_BRUSH_TYPE_SMOOTH,
};
bool _isolevel_picker_mode;
@ -145,7 +147,7 @@ private:
ToolButton *_isolevel_brush_type_add_button;
ToolButton *_isolevel_brush_type_substract_button;
ToolButton *_isolevel_brush_type_set_button;
ToolButton *_isolevel_brush_type_smooth_button;
//ToolButton *_isolevel_brush_type_smooth_button;
ToolButton *_isolevel_brush_allow_creating_chunks_button;
HSlider *_isolevel_brush_size_slider;
HSlider *_isolevel_brush_strength_slider;