From b570d1b5b61d0448e983d588134e4de3b57525e5 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Thu, 28 Jul 2022 18:38:33 -0500 Subject: [PATCH 01/12] Rename translated to translated_local --- edition/voxel_tool_lod_terrain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edition/voxel_tool_lod_terrain.cpp b/edition/voxel_tool_lod_terrain.cpp index 1b3503ba..6970a085 100644 --- a/edition/voxel_tool_lod_terrain.cpp +++ b/edition/voxel_tool_lod_terrain.cpp @@ -651,7 +651,7 @@ Array separate_floating_chunks(VoxelTool &voxel_tool, Box3i world_box, Node *par collision_shape->set_position(offset); RigidDynamicBody3D *rigid_body = memnew(RigidDynamicBody3D); - rigid_body->set_transform(transform * local_transform.translated(-offset)); + rigid_body->set_transform(transform * local_transform.translated_local(-offset)); rigid_body->add_child(collision_shape); rigid_body->set_freeze_mode(RigidDynamicBody3D::FREEZE_MODE_KINEMATIC); rigid_body->set_freeze_enabled(true); From bf6dc622b5d5ca8ade8eded22194bfeec8bc916d Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Sun, 31 Jul 2022 23:20:27 +0100 Subject: [PATCH 02/12] Comment --- edition/funcs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/edition/funcs.h b/edition/funcs.h index 3f94ddd2..7475c87a 100644 --- a/edition/funcs.h +++ b/edition/funcs.h @@ -257,6 +257,8 @@ struct SdfBufferShape { // Outside the buffer return 100; } + // TODO Trilinear looks bad when the shape is scaled up. + // Use Hermite in 3D https://www.researchgate.net/publication/360206102_Hermite_interpolation_of_heightmaps return interpolate_trilinear(buffer, buffer_size, lpos) * sdf_scale - isolevel; } From 5330c946a5574a5e77eed7296425fe70626edbc4 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Sun, 31 Jul 2022 23:24:33 +0100 Subject: [PATCH 03/12] Fix crash when modifying a VoxelGeneratorGraph with "live update" while no terrain node is selected --- editor/graph/voxel_graph_editor.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/editor/graph/voxel_graph_editor.cpp b/editor/graph/voxel_graph_editor.cpp index e25dcec1..e9f49ab6 100644 --- a/editor/graph/voxel_graph_editor.cpp +++ b/editor/graph/voxel_graph_editor.cpp @@ -659,9 +659,13 @@ void VoxelGraphEditor::update_previews(bool with_live_update) { if (hash != _last_output_graph_hash) { _last_output_graph_hash = hash; - // Re-generate the terrain. - // Only do that if the graph is valid. - _voxel_node->restart_stream(); + + // We could be editing the graph standalone with no terrain loaded + if (_voxel_node != nullptr) { + // Re-generate the terrain. + // Only do that if the graph is valid. + _voxel_node->restart_stream(); + } } } } From ed21e3bdeb39070e8b58da0f9af3cbb31a24f431 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Mon, 1 Aug 2022 00:07:20 +0100 Subject: [PATCH 04/12] Binds arguments were removed from connect() --- edition/voxel_tool_lod_terrain.cpp | 2 +- editor/graph/voxel_graph_editor.cpp | 2 +- .../voxel_instance_library_editor_plugin.cpp | 8 ++++---- editor/terrain/editor_property_aabb_min_max.cpp | 2 +- editor/terrain/voxel_terrain_editor_plugin.cpp | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/edition/voxel_tool_lod_terrain.cpp b/edition/voxel_tool_lod_terrain.cpp index 402ae1ab..ddde04ea 100644 --- a/edition/voxel_tool_lod_terrain.cpp +++ b/edition/voxel_tool_lod_terrain.cpp @@ -670,7 +670,7 @@ Array separate_floating_chunks(VoxelTool &voxel_tool, Box3i world_box, Node *par Timer *timer = memnew(Timer); timer->set_wait_time(0.2); timer->set_one_shot(true); - timer->connect("timeout", callable_mp(rigid_body, &RigidDynamicBody3D::set_freeze_enabled), varray(false)); + timer->connect("timeout", callable_mp(rigid_body, &RigidDynamicBody3D::set_freeze_enabled).bind(false)); // Cannot use start() here because it requires to be inside the SceneTree, // and we don't know if it will be after we add to the parent. timer->set_autostart(true); diff --git a/editor/graph/voxel_graph_editor.cpp b/editor/graph/voxel_graph_editor.cpp index e9f49ab6..955c9e81 100644 --- a/editor/graph/voxel_graph_editor.cpp +++ b/editor/graph/voxel_graph_editor.cpp @@ -282,7 +282,7 @@ void VoxelGraphEditor::create_node_gui(uint32_t node_id) { VoxelGraphEditorNode *node_view = VoxelGraphEditorNode::create(**_graph, node_id); node_view->set_name(ui_node_name); - node_view->connect("dragged", callable_mp(this, &VoxelGraphEditor::_on_graph_node_dragged), varray(node_id)); + node_view->connect("dragged", callable_mp(this, &VoxelGraphEditor::_on_graph_node_dragged).bind(node_id)); _graph_edit->add_child(node_view); } diff --git a/editor/instance_library/voxel_instance_library_editor_plugin.cpp b/editor/instance_library/voxel_instance_library_editor_plugin.cpp index d0063c83..e5ffd1d6 100644 --- a/editor/instance_library/voxel_instance_library_editor_plugin.cpp +++ b/editor/instance_library/voxel_instance_library_editor_plugin.cpp @@ -50,8 +50,8 @@ void VoxelInstanceLibraryEditorInspectorPlugin::add_buttons() { button_remove->set_icon(icon_provider->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); button_remove->set_flat(true); button_remove->connect("pressed", - callable_mp(button_listener, &VoxelInstanceLibraryEditorPlugin::_on_button_pressed), - varray(BUTTON_REMOVE_ITEM)); + callable_mp(button_listener, &VoxelInstanceLibraryEditorPlugin::_on_button_pressed) + .bind(BUTTON_REMOVE_ITEM)); hb->add_child(button_remove); Control *spacer = memnew(Control); @@ -61,8 +61,8 @@ void VoxelInstanceLibraryEditorInspectorPlugin::add_buttons() { Button *button_update = memnew(Button); button_update->set_text(TTR("Update From Scene...")); button_update->connect("pressed", - callable_mp(button_listener, &VoxelInstanceLibraryEditorPlugin::_on_button_pressed), - varray(BUTTON_UPDATE_MULTIMESH_ITEM_FROM_SCENE)); + callable_mp(button_listener, &VoxelInstanceLibraryEditorPlugin::_on_button_pressed) + .bind(BUTTON_UPDATE_MULTIMESH_ITEM_FROM_SCENE)); hb->add_child(button_update); add_custom_control(hb); diff --git a/editor/terrain/editor_property_aabb_min_max.cpp b/editor/terrain/editor_property_aabb_min_max.cpp index e77aec36..a64d5ea0 100644 --- a/editor/terrain/editor_property_aabb_min_max.cpp +++ b/editor/terrain/editor_property_aabb_min_max.cpp @@ -23,7 +23,7 @@ EditorPropertyAABBMinMax::EditorPropertyAABBMinMax() { EditorSpinSlider *sb = memnew(EditorSpinSlider); sb->set_flat(true); sb->set_h_size_flags(SIZE_EXPAND_FILL); - sb->connect("value_changed", callable_mp(this, &EditorPropertyAABBMinMax::_value_changed), varray(i)); + sb->connect("value_changed", callable_mp(this, &EditorPropertyAABBMinMax::_value_changed).bind(i)); _spinboxes[i] = sb; add_focusable(sb); diff --git a/editor/terrain/voxel_terrain_editor_plugin.cpp b/editor/terrain/voxel_terrain_editor_plugin.cpp index 630f3e3a..88e72c1b 100644 --- a/editor/terrain/voxel_terrain_editor_plugin.cpp +++ b/editor/terrain/voxel_terrain_editor_plugin.cpp @@ -156,9 +156,9 @@ void VoxelTerrainEditorPlugin::set_node(VoxelNode *node) { if (_node != nullptr) { _node->connect( - "tree_entered", callable_mp(this, &VoxelTerrainEditorPlugin::_on_terrain_tree_entered), varray(_node)); + "tree_entered", callable_mp(this, &VoxelTerrainEditorPlugin::_on_terrain_tree_entered).bind(_node)); _node->connect( - "tree_exited", callable_mp(this, &VoxelTerrainEditorPlugin::_on_terrain_tree_exited), varray(_node)); + "tree_exited", callable_mp(this, &VoxelTerrainEditorPlugin::_on_terrain_tree_exited).bind(_node)); VoxelLodTerrain *vlt = Object::cast_to(_node); From f160891b5d6581cd74b0342aef23d2eff9b74a13 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Mon, 1 Aug 2022 00:07:51 +0100 Subject: [PATCH 05/12] Callable::call was renamed callp --- edition/voxel_tool_terrain.cpp | 4 ++-- storage/voxel_buffer_gd.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/edition/voxel_tool_terrain.cpp b/edition/voxel_tool_terrain.cpp index ddd96604..7a5786ce 100644 --- a/edition/voxel_tool_terrain.cpp +++ b/edition/voxel_tool_terrain.cpp @@ -411,7 +411,7 @@ void VoxelToolTerrain::run_blocky_random_tick( Callable::CallError error; Variant retval; // We don't care about the return value, Callable API requires it const CallbackData *cd = (const CallbackData *)self; - cd->callable.call(args, 2, retval, error); + cd->callable.callp(args, 2, retval, error); // TODO I would really like to know what's the correct way to report such errors... // Examples I found in the engine are inconsistent ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, false); @@ -450,7 +450,7 @@ void VoxelToolTerrain::for_each_voxel_metadata_in_area(AABB voxel_area, const Ca const Variant *args[2] = { &key, &v }; Callable::CallError err; Variant retval; // We don't care about the return value, Callable API requires it - callback.call(args, 2, retval, err); + callback.callp(args, 2, retval, err); ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, String("Callable failed at {0}").format(varray(key))); diff --git a/storage/voxel_buffer_gd.cpp b/storage/voxel_buffer_gd.cpp index 4de6fd7e..f32e6db4 100644 --- a/storage/voxel_buffer_gd.cpp +++ b/storage/voxel_buffer_gd.cpp @@ -152,7 +152,7 @@ void VoxelBuffer::for_each_voxel_metadata(const Callable &callback) const { const Variant *args[2] = { &key, &v }; Callable::CallError err; Variant retval; // We don't care about the return value, Callable API requires it - callback.call(args, 2, retval, err); + callback.callp(args, 2, retval, err); ERR_FAIL_COND_MSG( err.error != Callable::CallError::CALL_OK, String("Callable failed at {0}").format(varray(key))); @@ -174,7 +174,7 @@ void VoxelBuffer::for_each_voxel_metadata_in_area(const Callable &callback, Vect const Variant *args[2] = { &key, &v }; Callable::CallError err; Variant retval; // We don't care about the return value, Callable API requires it - callback.call(args, 2, retval, err); + callback.callp(args, 2, retval, err); ERR_FAIL_COND_MSG( err.error != Callable::CallError::CALL_OK, String("Callable failed at {0}").format(varray(key))); From b1f4aee78b7397c94a4a0b4b117ac0b85f7064ce Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Mon, 1 Aug 2022 00:08:21 +0100 Subject: [PATCH 06/12] ResourceSaver::save arguments were swapped --- editor/vox/vox_mesh_importer.cpp | 2 +- editor/vox/vox_scene_importer.cpp | 4 ++-- terrain/instancing/voxel_instancer.cpp | 2 +- terrain/variable_lod/voxel_lod_terrain.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/editor/vox/vox_mesh_importer.cpp b/editor/vox/vox_mesh_importer.cpp index 2ed8a9e5..5ffabdff 100644 --- a/editor/vox/vox_mesh_importer.cpp +++ b/editor/vox/vox_mesh_importer.cpp @@ -357,7 +357,7 @@ Error VoxelVoxMeshImporter::import(const String &p_source_file, const String &p_ { ZN_PROFILE_SCOPE(); String mesh_save_path = String("{0}.mesh").format(varray(p_save_path)); - const Error mesh_save_err = ResourceSaver::save(mesh_save_path, mesh); + const Error mesh_save_err = ResourceSaver::save(mesh, mesh_save_path); ERR_FAIL_COND_V_MSG( mesh_save_err != OK, mesh_save_err, String("Failed to save {0}").format(varray(mesh_save_path))); } diff --git a/editor/vox/vox_scene_importer.cpp b/editor/vox/vox_scene_importer.cpp index 9687a400..552b0a63 100644 --- a/editor/vox/vox_scene_importer.cpp +++ b/editor/vox/vox_scene_importer.cpp @@ -373,7 +373,7 @@ Error VoxelVoxSceneImporter::import(const String &p_source_file, const String &p String res_save_path = String("{0}.model{1}.mesh").format(varray(p_save_path, model_index)); // `FLAG_CHANGE_PATH` did not do what I thought it did. mesh->set_path(res_save_path); - const Error mesh_save_err = ResourceSaver::save(res_save_path, mesh); + const Error mesh_save_err = ResourceSaver::save(mesh, res_save_path); ERR_FAIL_COND_V_MSG( mesh_save_err != OK, mesh_save_err, String("Failed to save {0}").format(varray(res_save_path))); } @@ -387,7 +387,7 @@ Error VoxelVoxSceneImporter::import(const String &p_source_file, const String &p scene.instantiate(); scene->pack(root_node); String scene_save_path = p_save_path + ".tscn"; - const Error save_err = ResourceSaver::save(scene_save_path, scene); + const Error save_err = ResourceSaver::save(scene, scene_save_path); memdelete(root_node); ERR_FAIL_COND_V_MSG(save_err != OK, save_err, "Cannot save scene to file '" + scene_save_path); } diff --git a/terrain/instancing/voxel_instancer.cpp b/terrain/instancing/voxel_instancer.cpp index 4e371d52..79c439d7 100644 --- a/terrain/instancing/voxel_instancer.cpp +++ b/terrain/instancing/voxel_instancer.cpp @@ -1642,7 +1642,7 @@ void VoxelInstancer::debug_dump_as_scene(String fpath) const { memdelete(root); ERR_FAIL_COND(pack_result != OK); - const Error save_result = ResourceSaver::save(fpath, packed_scene, ResourceSaver::FLAG_BUNDLE_RESOURCES); + const Error save_result = ResourceSaver::save(packed_scene, fpath, ResourceSaver::FLAG_BUNDLE_RESOURCES); ERR_FAIL_COND(save_result != OK); } diff --git a/terrain/variable_lod/voxel_lod_terrain.cpp b/terrain/variable_lod/voxel_lod_terrain.cpp index ce93b7f2..fe6e6bc0 100644 --- a/terrain/variable_lod/voxel_lod_terrain.cpp +++ b/terrain/variable_lod/voxel_lod_terrain.cpp @@ -2609,7 +2609,7 @@ Error VoxelLodTerrain::_b_debug_dump_as_scene(String fpath, bool include_instanc return pack_result; } - const Error save_result = ResourceSaver::save(fpath, scene, ResourceSaver::FLAG_BUNDLE_RESOURCES); + const Error save_result = ResourceSaver::save(scene, fpath, ResourceSaver::FLAG_BUNDLE_RESOURCES); return save_result; } From b53df948d0f007dd582418f8857ab15002e93846 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Mon, 1 Aug 2022 00:55:21 +0100 Subject: [PATCH 07/12] Fix ambiguous call with float=64 --- edition/funcs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edition/funcs.h b/edition/funcs.h index 7475c87a..47a7f669 100644 --- a/edition/funcs.h +++ b/edition/funcs.h @@ -168,7 +168,7 @@ struct SdfSubtract { }; struct SdfSet { - float strength; + real_t strength; inline real_t operator()(real_t a, real_t b) const { return Math::lerp(a, b, strength); } From 181601e0118080edfaab2d65277bba0d58da1beb Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Mon, 1 Aug 2022 01:03:28 +0100 Subject: [PATCH 08/12] Fix macro --- generators/graph/voxel_graph_compiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/graph/voxel_graph_compiler.cpp b/generators/graph/voxel_graph_compiler.cpp index 389be7f2..58b1c07c 100644 --- a/generators/graph/voxel_graph_compiler.cpp +++ b/generators/graph/voxel_graph_compiler.cpp @@ -338,7 +338,7 @@ static bool is_node_equivalent(const ProgramGraph &graph, const ProgramGraph::No return false; } ZN_ASSERT_RETURN_V_MSG( - node1_input.connections.size() <= 1, "Multiple input connections isn't supported", false); + node1_input.connections.size() <= 1, false, "Multiple input connections isn't supported"); // TODO Some nodes like `*` and `+` have unordered inputs, we need to handle that if (node1_input.connections.size() == 0) { // No ancestor, check default inputs (autoconnect is ignored, it must have been applied earlier) From fd54901700f7173b486b6b246743b4b910e8fd22 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Mon, 1 Aug 2022 01:24:55 +0100 Subject: [PATCH 09/12] Unused variable --- editor/graph/voxel_graph_node_inspector_wrapper.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/editor/graph/voxel_graph_node_inspector_wrapper.cpp b/editor/graph/voxel_graph_node_inspector_wrapper.cpp index 2112191b..bb2420a9 100644 --- a/editor/graph/voxel_graph_node_inspector_wrapper.cpp +++ b/editor/graph/voxel_graph_node_inspector_wrapper.cpp @@ -196,7 +196,6 @@ bool VoxelGraphNodeInspectorWrapper::_set(const StringName &p_name, const Varian const uint32_t node_type_id = graph->get_node_type_id(_node_id); const VoxelGraphNodeDB &db = VoxelGraphNodeDB::get_singleton(); - const bool autoconnect = graph->get_node_default_inputs_autoconnect(_node_id); uint32_t index; if (db.try_get_param_index_from_name(node_type_id, p_name, index)) { From cff51fbe89ca45d6df6225fe14d221ed0905ab78 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Tue, 2 Aug 2022 00:35:13 +0100 Subject: [PATCH 10/12] Unnecessary signal arguments --- editor/graph/voxel_graph_editor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/graph/voxel_graph_editor.cpp b/editor/graph/voxel_graph_editor.cpp index 955c9e81..e19ac061 100644 --- a/editor/graph/voxel_graph_editor.cpp +++ b/editor/graph/voxel_graph_editor.cpp @@ -981,8 +981,8 @@ void VoxelGraphEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("update_node_layout", "node_id"), &VoxelGraphEditor::update_node_layout); ADD_SIGNAL(MethodInfo(SIGNAL_NODE_SELECTED, PropertyInfo(Variant::INT, "node_id"))); - ADD_SIGNAL(MethodInfo(SIGNAL_NOTHING_SELECTED, PropertyInfo(Variant::INT, "nothing_selected"))); - ADD_SIGNAL(MethodInfo(SIGNAL_NODES_DELETED, PropertyInfo(Variant::INT, "nodes_deleted"))); + ADD_SIGNAL(MethodInfo(SIGNAL_NOTHING_SELECTED)); + ADD_SIGNAL(MethodInfo(SIGNAL_NODES_DELETED)); } } // namespace zylann::voxel From f81e64dd14f31eca6c31720f5ce4e656babd8964 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Tue, 2 Aug 2022 00:38:21 +0100 Subject: [PATCH 11/12] Added pinning to voxel graph editor --- doc/source/changelog.md | 1 + editor/graph/voxel_graph_editor.cpp | 32 +++++++++++--- editor/graph/voxel_graph_editor.h | 5 +++ editor/graph/voxel_graph_editor_plugin.cpp | 49 +++++++++++++++++++--- editor/graph/voxel_graph_editor_plugin.h | 3 ++ 5 files changed, 79 insertions(+), 11 deletions(-) diff --git a/doc/source/changelog.md b/doc/source/changelog.md index cf94a63e..91f6af56 100644 --- a/doc/source/changelog.md +++ b/doc/source/changelog.md @@ -28,6 +28,7 @@ Godot 4 is required from this version. - `VoxelGeneratorGraph`: editor: allow to change the axes on preview nodes 3D slices - `VoxelGeneratorGraph`: editor: replace existing connection if dragging from/to an input port having one already - `VoxelGeneratorGraph`: editor: creating noise and curve nodes now auto-create their resource instead of coming up null + - `VoxelGeneratorGraph`: editor: added pin button to keep the graph editor shown even after deselecting the terrain. - `VoxelGeneratorGraph`: added `OutputSingleTexture` node for outputting a single texture index per voxel, as an alternative to weights. This is specific to smooth voxels. - `VoxelGeneratorGraph`: added math expression node - `VoxelGeneratorGraph`: added Pow and Powi nodes diff --git a/editor/graph/voxel_graph_editor.cpp b/editor/graph/voxel_graph_editor.cpp index e19ac061..2350b794 100644 --- a/editor/graph/voxel_graph_editor.cpp +++ b/editor/graph/voxel_graph_editor.cpp @@ -28,6 +28,7 @@ namespace zylann::voxel { const char *VoxelGraphEditor::SIGNAL_NODE_SELECTED = "node_selected"; const char *VoxelGraphEditor::SIGNAL_NOTHING_SELECTED = "nothing_selected"; const char *VoxelGraphEditor::SIGNAL_NODES_DELETED = "nodes_deleted"; +const char *VoxelGraphEditor::SIGNAL_REGENERATE_REQUESTED = "regenerate_requested"; static NodePath to_node_path(StringName sn) { Vector path; @@ -88,6 +89,17 @@ VoxelGraphEditor::VoxelGraphEditor() { live_update_checkbox->connect("toggled", callable_mp(this, &VoxelGraphEditor::_on_live_update_toggled)); toolbar->add_child(live_update_checkbox); + Control *spacer = memnew(Control); + spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); + toolbar->add_child(spacer); + + _pin_button = memnew(Button); + _pin_button->set_flat(true); + _pin_button->set_toggle_mode(true); + _pin_button->set_tooltip(TTR("Pin AnimationPlayer")); + toolbar->add_child(_pin_button); + //_pin_button->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed)); + vbox_container->add_child(toolbar); } @@ -195,6 +207,10 @@ void VoxelGraphEditor::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: set_process_internal(is_visible()); break; + + case NOTIFICATION_THEME_CHANGED: + _pin_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"))); + break; } } @@ -371,6 +387,10 @@ void VoxelGraphEditor::update_node_layout(uint32_t node_id) { } } +bool VoxelGraphEditor::is_pinned_hint() const { + return _pin_button->is_pressed(); +} + static bool is_nothing_selected(GraphEdit *graph_edit) { for (int i = 0; i < graph_edit->get_child_count(); ++i) { GraphNode *node = Object::cast_to(graph_edit->get_child(i)); @@ -660,12 +680,11 @@ void VoxelGraphEditor::update_previews(bool with_live_update) { if (hash != _last_output_graph_hash) { _last_output_graph_hash = hash; - // We could be editing the graph standalone with no terrain loaded - if (_voxel_node != nullptr) { - // Re-generate the terrain. - // Only do that if the graph is valid. - _voxel_node->restart_stream(); - } + // Not calling into `_voxel_node` directly because the editor could be pinned and the terrain not actually + // selected. In this situation the plugin may reset the node to null. But it is desirable for terrains + // using the current graph to update if they are in the edited scene, so this may be delegated to the editor + // plugin. There isn't enough context from here to do this cleanly. + emit_signal(SIGNAL_REGENERATE_REQUESTED); } } } @@ -983,6 +1002,7 @@ void VoxelGraphEditor::_bind_methods() { ADD_SIGNAL(MethodInfo(SIGNAL_NODE_SELECTED, PropertyInfo(Variant::INT, "node_id"))); ADD_SIGNAL(MethodInfo(SIGNAL_NOTHING_SELECTED)); ADD_SIGNAL(MethodInfo(SIGNAL_NODES_DELETED)); + ADD_SIGNAL(MethodInfo(SIGNAL_REGENERATE_REQUESTED)); } } // namespace zylann::voxel diff --git a/editor/graph/voxel_graph_editor.h b/editor/graph/voxel_graph_editor.h index 4812eb26..f9e1c6e4 100644 --- a/editor/graph/voxel_graph_editor.h +++ b/editor/graph/voxel_graph_editor.h @@ -8,6 +8,7 @@ class GraphEdit; class PopupMenu; class AcceptDialog; class UndoRedo; +class Button; namespace zylann::voxel { @@ -23,6 +24,7 @@ public: static const char *SIGNAL_NODE_SELECTED; static const char *SIGNAL_NOTHING_SELECTED; static const char *SIGNAL_NODES_DELETED; + static const char *SIGNAL_REGENERATE_REQUESTED; VoxelGraphEditor(); @@ -38,6 +40,8 @@ public: // Rebuilds the node's internal controls, and updates GUI connections going to it from the graph. void update_node_layout(uint32_t node_id); + bool is_pinned_hint() const; + private: void _notification(int p_what); void _process(float delta); @@ -95,6 +99,7 @@ private: VoxelGraphEditorShaderDialog *_shader_dialog = nullptr; bool _live_update_enabled = false; uint64_t _last_output_graph_hash = 0; + Button *_pin_button = nullptr; enum PreviewAxes { // PREVIEW_XY = 0, diff --git a/editor/graph/voxel_graph_editor_plugin.cpp b/editor/graph/voxel_graph_editor_plugin.cpp index e5ad274e..0e936aa1 100644 --- a/editor/graph/voxel_graph_editor_plugin.cpp +++ b/editor/graph/voxel_graph_editor_plugin.cpp @@ -41,6 +41,8 @@ VoxelGraphEditorPlugin::VoxelGraphEditorPlugin() { callable_mp(this, &VoxelGraphEditorPlugin::_on_graph_editor_nothing_selected)); _graph_editor->connect(VoxelGraphEditor::SIGNAL_NODES_DELETED, callable_mp(this, &VoxelGraphEditorPlugin::_on_graph_editor_nodes_deleted)); + _graph_editor->connect(VoxelGraphEditor::SIGNAL_REGENERATE_REQUESTED, + callable_mp(this, &VoxelGraphEditorPlugin::_on_graph_editor_regenerate_requested)); _bottom_panel_button = add_control_to_bottom_panel(_graph_editor, TTR("Voxel Graph")); _bottom_panel_button->hide(); @@ -87,6 +89,7 @@ void VoxelGraphEditorPlugin::edit(Object *p_object) { break; } } + _voxel_node = voxel_node; _graph_editor->set_voxel_node(voxel_node); } @@ -96,13 +99,17 @@ void VoxelGraphEditorPlugin::make_visible(bool visible) { make_bottom_panel_item_visible(_graph_editor); } else { - _bottom_panel_button->hide(); + _voxel_node = nullptr; _graph_editor->set_voxel_node(nullptr); - // TODO Awful hack to handle the nonsense happening in `_on_graph_editor_node_selected` - if (!_deferred_visibility_scheduled) { - _deferred_visibility_scheduled = true; - call_deferred("_hide_deferred"); + if (!_graph_editor->is_pinned_hint()) { + _bottom_panel_button->hide(); + + // TODO Awful hack to handle the nonsense happening in `_on_graph_editor_node_selected` + if (!_deferred_visibility_scheduled) { + _deferred_visibility_scheduled = true; + call_deferred("_hide_deferred"); + } } } } @@ -152,6 +159,38 @@ void VoxelGraphEditorPlugin::_on_graph_editor_nodes_deleted() { get_editor_interface()->inspect_object(*graph); } +template +void for_each_node(Node *parent, F action) { + action(parent); + for (int i = 0; i < parent->get_child_count(); ++i) { + for_each_node(parent->get_child(i), action); + } +} + +void VoxelGraphEditorPlugin::_on_graph_editor_regenerate_requested() { + // We could be editing the graph standalone with no terrain loaded + if (_voxel_node != nullptr) { + // Re-generate the selected terrain. + _voxel_node->restart_stream(); + + } else { + // The node is not selected, but it might be in the tree + Node *root = get_editor_interface()->get_edited_scene_root(); + + if (root != nullptr) { + Ref generator = _graph_editor->get_graph(); + ERR_FAIL_COND(generator.is_null()); + + for_each_node(root, [&generator](Node *node) { + VoxelNode *vnode = Object::cast_to(node); + if (vnode != nullptr && vnode->get_generator() == generator) { + vnode->restart_stream(); + } + }); + } + } +} + void VoxelGraphEditorPlugin::_bind_methods() { // ClassDB::bind_method(D_METHOD("_on_graph_editor_node_selected", "node_id"), // &VoxelGraphEditorPlugin::_on_graph_editor_node_selected); diff --git a/editor/graph/voxel_graph_editor_plugin.h b/editor/graph/voxel_graph_editor_plugin.h index 2a12c017..d859d38c 100644 --- a/editor/graph/voxel_graph_editor_plugin.h +++ b/editor/graph/voxel_graph_editor_plugin.h @@ -6,6 +6,7 @@ namespace zylann::voxel { class VoxelGraphEditor; +class VoxelNode; class VoxelGraphEditorPlugin : public EditorPlugin { GDCLASS(VoxelGraphEditorPlugin, EditorPlugin) @@ -20,6 +21,7 @@ private: void _on_graph_editor_node_selected(uint32_t node_id); void _on_graph_editor_nothing_selected(); void _on_graph_editor_nodes_deleted(); + void _on_graph_editor_regenerate_requested(); void _hide_deferred(); static void _bind_methods(); @@ -27,6 +29,7 @@ private: VoxelGraphEditor *_graph_editor = nullptr; Button *_bottom_panel_button = nullptr; bool _deferred_visibility_scheduled = false; + VoxelNode *_voxel_node = nullptr; }; } // namespace zylann::voxel From f171628ad2a2a19d3ddd994163b84b20ffe927bb Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Tue, 2 Aug 2022 22:14:33 +0100 Subject: [PATCH 12/12] Added popout button to the graph editor to open it on a separate window --- doc/source/changelog.md | 1 + editor/graph/voxel_graph_editor.cpp | 17 ++++ editor/graph/voxel_graph_editor.h | 4 + editor/graph/voxel_graph_editor_plugin.cpp | 96 +++++++++++++++++++++- editor/graph/voxel_graph_editor_plugin.h | 7 ++ 5 files changed, 124 insertions(+), 1 deletion(-) diff --git a/doc/source/changelog.md b/doc/source/changelog.md index 91f6af56..2c71bfdc 100644 --- a/doc/source/changelog.md +++ b/doc/source/changelog.md @@ -29,6 +29,7 @@ Godot 4 is required from this version. - `VoxelGeneratorGraph`: editor: replace existing connection if dragging from/to an input port having one already - `VoxelGeneratorGraph`: editor: creating noise and curve nodes now auto-create their resource instead of coming up null - `VoxelGeneratorGraph`: editor: added pin button to keep the graph editor shown even after deselecting the terrain. + - `VoxelGeneratorGraph`: editor: added popout button to open the graph editor in a separate window - `VoxelGeneratorGraph`: added `OutputSingleTexture` node for outputting a single texture index per voxel, as an alternative to weights. This is specific to smooth voxels. - `VoxelGeneratorGraph`: added math expression node - `VoxelGeneratorGraph`: added Pow and Powi nodes diff --git a/editor/graph/voxel_graph_editor.cpp b/editor/graph/voxel_graph_editor.cpp index 2350b794..bd44bfb9 100644 --- a/editor/graph/voxel_graph_editor.cpp +++ b/editor/graph/voxel_graph_editor.cpp @@ -29,6 +29,7 @@ const char *VoxelGraphEditor::SIGNAL_NODE_SELECTED = "node_selected"; const char *VoxelGraphEditor::SIGNAL_NOTHING_SELECTED = "nothing_selected"; const char *VoxelGraphEditor::SIGNAL_NODES_DELETED = "nodes_deleted"; const char *VoxelGraphEditor::SIGNAL_REGENERATE_REQUESTED = "regenerate_requested"; +const char *VoxelGraphEditor::SIGNAL_POPOUT_REQUESTED = "popout_requested"; static NodePath to_node_path(StringName sn) { Vector path; @@ -100,6 +101,12 @@ VoxelGraphEditor::VoxelGraphEditor() { toolbar->add_child(_pin_button); //_pin_button->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed)); + _popout_button = memnew(Button); + _popout_button->set_flat(true); + _popout_button->set_tooltip(TTR("Pop-out as separate window")); + _popout_button->connect("pressed", callable_mp(this, &VoxelGraphEditor::_on_popout_button_pressed)); + toolbar->add_child(_popout_button); + vbox_container->add_child(toolbar); } @@ -210,6 +217,7 @@ void VoxelGraphEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: _pin_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"))); + _popout_button->set_icon(get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); break; } } @@ -991,6 +999,14 @@ void VoxelGraphEditor::_on_live_update_toggled(bool enabled) { _live_update_enabled = enabled; } +void VoxelGraphEditor::_on_popout_button_pressed() { + emit_signal(SIGNAL_POPOUT_REQUESTED); +} + +void VoxelGraphEditor::set_popout_button_enabled(bool enable) { + _popout_button->set_visible(enable); +} + void VoxelGraphEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_check_nothing_selected"), &VoxelGraphEditor::_check_nothing_selected); @@ -1003,6 +1019,7 @@ void VoxelGraphEditor::_bind_methods() { ADD_SIGNAL(MethodInfo(SIGNAL_NOTHING_SELECTED)); ADD_SIGNAL(MethodInfo(SIGNAL_NODES_DELETED)); ADD_SIGNAL(MethodInfo(SIGNAL_REGENERATE_REQUESTED)); + ADD_SIGNAL(MethodInfo(SIGNAL_POPOUT_REQUESTED)); } } // namespace zylann::voxel diff --git a/editor/graph/voxel_graph_editor.h b/editor/graph/voxel_graph_editor.h index f9e1c6e4..86fb6579 100644 --- a/editor/graph/voxel_graph_editor.h +++ b/editor/graph/voxel_graph_editor.h @@ -25,6 +25,7 @@ public: static const char *SIGNAL_NOTHING_SELECTED; static const char *SIGNAL_NODES_DELETED; static const char *SIGNAL_REGENERATE_REQUESTED; + static const char *SIGNAL_POPOUT_REQUESTED; VoxelGraphEditor(); @@ -41,6 +42,7 @@ public: void update_node_layout(uint32_t node_id); bool is_pinned_hint() const; + void set_popout_button_enabled(bool enable); private: void _notification(int p_what); @@ -78,6 +80,7 @@ private: void _on_preview_axes_menu_id_pressed(int id); void _on_generate_shader_button_pressed(); void _on_live_update_toggled(bool enabled); + void _on_popout_button_pressed(); void _check_nothing_selected(); @@ -100,6 +103,7 @@ private: bool _live_update_enabled = false; uint64_t _last_output_graph_hash = 0; Button *_pin_button = nullptr; + Button *_popout_button = nullptr; enum PreviewAxes { // PREVIEW_XY = 0, diff --git a/editor/graph/voxel_graph_editor_plugin.cpp b/editor/graph/voxel_graph_editor_plugin.cpp index 0e936aa1..842130cc 100644 --- a/editor/graph/voxel_graph_editor_plugin.cpp +++ b/editor/graph/voxel_graph_editor_plugin.cpp @@ -10,6 +10,35 @@ namespace zylann::voxel { +// TODO It would be really nice if we were not forced to use an AcceptDialog for making a window. +// AcceptDialog adds stuff I don't need, but Window is too low level. +class VoxelGraphEditorWindow : public AcceptDialog { + GDCLASS(VoxelGraphEditorWindow, AcceptDialog) +public: + VoxelGraphEditorWindow() { + set_exclusive(false); + set_close_on_escape(false); + get_ok_button()->hide(); + set_min_size(Vector2(600, 300) * EDSCALE); + // I want the window to remain on top of the editor if the editor is given focus. `always_on_top` is the only + // property allowing that, but it requires `transient` to be `false`. Without `transient`, the window is no + // longer considered a child and won't give back focus to the editor when closed. + // So for now, the window will get hidden behind the editor if you click on the editor. + // you'll have to suffer moving popped out windows out of the editor area if you want to see them both... + //set_flag(Window::FLAG_ALWAYS_ON_TOP, true); + } + + // void _notification(int p_what) { + // switch (p_what) { + // case NOTIFICATION_WM_CLOSE_REQUEST: + // call_deferred(SNAME("hide")); + // break; + // } + // } + + static void _bind_methods() {} +}; + // Changes string editors of the inspector to call setters only when enter key is pressed, similar to Unreal. // Because the default behavior of `EditorPropertyText` is to call the setter on every character typed, which is a // nightmare when editing an Expression node: inputs change constantly as the code is written which has much higher @@ -43,6 +72,8 @@ VoxelGraphEditorPlugin::VoxelGraphEditorPlugin() { callable_mp(this, &VoxelGraphEditorPlugin::_on_graph_editor_nodes_deleted)); _graph_editor->connect(VoxelGraphEditor::SIGNAL_REGENERATE_REQUESTED, callable_mp(this, &VoxelGraphEditorPlugin::_on_graph_editor_regenerate_requested)); + _graph_editor->connect(VoxelGraphEditor::SIGNAL_POPOUT_REQUESTED, + callable_mp(this, &VoxelGraphEditorPlugin::_on_graph_editor_popout_requested)); _bottom_panel_button = add_control_to_bottom_panel(_graph_editor, TTR("Voxel Graph")); _bottom_panel_button->hide(); @@ -91,9 +122,17 @@ void VoxelGraphEditorPlugin::edit(Object *p_object) { } _voxel_node = voxel_node; _graph_editor->set_voxel_node(voxel_node); + + if (_graph_editor_window != nullptr) { + update_graph_editor_window_title(); + } } void VoxelGraphEditorPlugin::make_visible(bool visible) { + if (_graph_editor_window != nullptr) { + return; + } + if (visible) { _bottom_panel_button->show(); make_bottom_panel_item_visible(_graph_editor); @@ -102,7 +141,8 @@ void VoxelGraphEditorPlugin::make_visible(bool visible) { _voxel_node = nullptr; _graph_editor->set_voxel_node(nullptr); - if (!_graph_editor->is_pinned_hint()) { + const bool pinned = _graph_editor_window != nullptr || _graph_editor->is_pinned_hint(); + if (!pinned) { _bottom_panel_button->hide(); // TODO Awful hack to handle the nonsense happening in `_on_graph_editor_node_selected` @@ -191,6 +231,60 @@ void VoxelGraphEditorPlugin::_on_graph_editor_regenerate_requested() { } } +void VoxelGraphEditorPlugin::_on_graph_editor_popout_requested() { + undock_graph_editor(); +} + +void VoxelGraphEditorPlugin::undock_graph_editor() { + ERR_FAIL_COND(_graph_editor_window != nullptr); + ZN_PRINT_VERBOSE("Undock voxel graph editor"); + + remove_control_from_bottom_panel(_graph_editor); + _bottom_panel_button = nullptr; + + _graph_editor->set_popout_button_enabled(false); + _graph_editor->set_anchors_preset(Control::PRESET_FULL_RECT); + // I don't know what hides it but I needed to make it visible again + _graph_editor->show(); + + _graph_editor_window = memnew(VoxelGraphEditorWindow); + update_graph_editor_window_title(); + _graph_editor_window->add_child(_graph_editor); + _graph_editor_window->connect("close_requested", callable_mp(this, &VoxelGraphEditorPlugin::dock_graph_editor)); + + Node *base_control = get_editor_interface()->get_base_control(); + base_control->add_child(_graph_editor_window); + + _graph_editor_window->popup_centered_ratio(0.6); +} + +void VoxelGraphEditorPlugin::dock_graph_editor() { + ERR_FAIL_COND(_graph_editor_window == nullptr); + ZN_PRINT_VERBOSE("Dock voxel graph editor"); + + _graph_editor->get_parent()->remove_child(_graph_editor); + _graph_editor_window->queue_delete(); + _graph_editor_window = nullptr; + + _graph_editor->set_popout_button_enabled(true); + + _bottom_panel_button = add_control_to_bottom_panel(_graph_editor, TTR("Voxel Graph")); + + _bottom_panel_button->show(); + make_bottom_panel_item_visible(_graph_editor); +} + +void VoxelGraphEditorPlugin::update_graph_editor_window_title() { + ERR_FAIL_COND(_graph_editor_window == nullptr); + String title; + if (_graph_editor->get_graph().is_valid()) { + title = _graph_editor->get_graph()->get_path(); + title += " - "; + } + title += VoxelGeneratorGraph::get_class_static(); + _graph_editor_window->set_title(title); +} + void VoxelGraphEditorPlugin::_bind_methods() { // ClassDB::bind_method(D_METHOD("_on_graph_editor_node_selected", "node_id"), // &VoxelGraphEditorPlugin::_on_graph_editor_node_selected); diff --git a/editor/graph/voxel_graph_editor_plugin.h b/editor/graph/voxel_graph_editor_plugin.h index d859d38c..8af2fc0a 100644 --- a/editor/graph/voxel_graph_editor_plugin.h +++ b/editor/graph/voxel_graph_editor_plugin.h @@ -7,6 +7,7 @@ namespace zylann::voxel { class VoxelGraphEditor; class VoxelNode; +class VoxelGraphEditorWindow; class VoxelGraphEditorPlugin : public EditorPlugin { GDCLASS(VoxelGraphEditorPlugin, EditorPlugin) @@ -18,15 +19,21 @@ public: void make_visible(bool visible) override; private: + void undock_graph_editor(); + void dock_graph_editor(); + void update_graph_editor_window_title(); + void _on_graph_editor_node_selected(uint32_t node_id); void _on_graph_editor_nothing_selected(); void _on_graph_editor_nodes_deleted(); void _on_graph_editor_regenerate_requested(); + void _on_graph_editor_popout_requested(); void _hide_deferred(); static void _bind_methods(); VoxelGraphEditor *_graph_editor = nullptr; + VoxelGraphEditorWindow *_graph_editor_window = nullptr; Button *_bottom_panel_button = nullptr; bool _deferred_visibility_scheduled = false; VoxelNode *_voxel_node = nullptr;