terrain-editor/modules/terrain_editor/terrain_mesh_editor.cpp

157 lines
5.7 KiB
C++

#include "terrain_mesh_editor.h"
#include "core/input/input_event.h"
#include "core/io/file_access.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/os/keyboard.h"
#include "scene/3d/node_3d.h"
#include "scene/gui/file_dialog.h"
#include "scene/resources/packed_scene.h"
#include "terrain_editor/edit_history.h"
#include "terrain_editor/macros.h"
#include "terrain_editor/point_primitive_node.h"
#include "terrain_editor/terrain_primitive.h"
void SaveData::_bind_methods() {
BIND_HPROPERTY(Variant::ARRAY, primitives, PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:TerrainPrimitive", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE));
}
void SaveData::write_to_file() {
ResourceSaver::save(this, this->save_file_path, ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES | ResourceSaver::FLAG_BUNDLE_RESOURCES);
}
void SaveData::set_save_path(String value) {
this->save_file_path = value;
}
String SaveData::get_save_path() const {
return this->save_file_path;
}
void SaveData::set_primitives(Array array) {
this->primitives = array.duplicate(true); // do a full deep copy of the data, to avoid modification before saving
}
Array SaveData::get_primitives() const {
return this->primitives;
}
void TerrainMeshEditor::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, point_primitive_object, PROPERTY_HINT_RESOURCE_TYPE, "PackedScene");
ClassDB::bind_method(D_METHOD("save_data"), &self_type::save_data);
}
void TerrainMeshEditor::ready() {
connect(sig_primitive_list_changed, callable_mp(this, &self_type::on_primitive_list_changed));
on_primitive_list_changed(get_primitives());
if (FileDialog * dialog{ memnew(FileDialog) }) {
this->file_dialog = dialog;
add_child(dialog);
dialog->set_filters({ "*.terrain.tres;World Resource Files;", "*.terrain.res;Binary World Resource Files;" });
dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
dialog->connect("file_selected", callable_mp(this, &self_type::on_save_file_selected));
}
}
void TerrainMeshEditor::on_primitive_list_changed(Array primitives) {
this->out_of_date = true;
for (Node3D *existing : this->primitive_nodes) {
existing->queue_free();
}
this->primitive_nodes.clear();
for (Variant var : primitives) {
if (this->point_primitive_object.is_valid() && this->point_primitive_object->get_state()->get_node_type(0) == PointPrimitiveNode::get_class_static()) {
Ref<PointPrimitive> point{ var };
if (point.is_valid()) {
PointPrimitiveNode *primitive_node{ cast_to<PointPrimitiveNode>(this->point_primitive_object->instantiate()) };
primitive_node->set_primitive(point);
this->add_child(primitive_node);
this->primitive_nodes.push_back(primitive_node);
}
}
}
}
void TerrainMeshEditor::on_save_file_selected(String path) {
switch (this->file_dialog->get_file_mode()) {
default:
print_error("Attempt to open or save with invalid file dialog mode");
break;
case FileDialog::FILE_MODE_SAVE_FILE:
this->data->set_save_path(path);
this->data->set_primitives(get_primitives());
this->data->write_to_file();
break;
case FileDialog::FILE_MODE_OPEN_FILE:
Ref<Resource> resource{ ResourceLoader::load(path, "SaveData", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP) };
Ref<SaveData> loaded_data{ resource };
if (loaded_data.is_valid()) {
this->data = loaded_data;
this->set_primitives(this->data->get_primitives().duplicate(true));
this->data->set_save_path(path);
}
break;
}
}
void TerrainMeshEditor::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_READY:
set_process_unhandled_input(true);
ready();
return;
}
}
void TerrainMeshEditor::unhandled_input(Ref<InputEvent> const &event) {
Ref<InputEventKey> key{ event };
if (key.is_valid() && key->get_key_label() == Key::S && key->get_modifiers_mask() == (KeyModifierMask::SHIFT | KeyModifierMask::CTRL)) {
get_viewport()->set_input_as_handled();
this->file_dialog->set_file_mode(FileDialog::FILE_MODE_SAVE_FILE);
this->file_dialog->set_ok_button_text("Save");
this->file_dialog->popup_file_dialog();
} else if (key.is_valid() && key->get_key_label() == Key::S && key->get_modifiers_mask() == KeyModifierMask::CTRL) {
get_viewport()->set_input_as_handled();
save_data();
} else if (key.is_valid() && key->get_key_label() == Key::O && key->get_modifiers_mask() == KeyModifierMask::CTRL) {
get_viewport()->set_input_as_handled();
this->file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
this->file_dialog->set_ok_button_text("Open");
this->file_dialog->popup_file_dialog();
} else if (key.is_valid() && key->get_key_label() == Key::Z && key->get_modifiers_mask() == KeyModifierMask::CTRL) {
get_viewport()->set_input_as_handled();
EditHistory::get_singleton()->undo();
} else if (key.is_valid() && key->get_key_label() == Key::Z && key->get_modifiers_mask() == (KeyModifierMask::CTRL | KeyModifierMask::SHIFT)) {
get_viewport()->set_input_as_handled();
EditHistory::get_singleton()->redo();
}
}
void TerrainMeshEditor::save_data() {
// TODO: figure out if this is the correct way to see if the popup is popped up
if (this->file_dialog->is_visible()) {
return;
}
if (this->data->get_save_path().is_empty()) {
this->file_dialog->set_file_mode(FileDialog::FILE_MODE_SAVE_FILE);
this->file_dialog->set_ok_button_text("Save");
this->file_dialog->popup_file_dialog();
} else {
this->data->set_primitives(get_primitives());
this->data->write_to_file();
}
}
void TerrainMeshEditor::set_point_primitive_object(Ref<PackedScene> scene) {
this->point_primitive_object = scene;
}
Ref<PackedScene> TerrainMeshEditor::get_point_primitive_object() const {
return this->point_primitive_object;
}