[VisualShader] Fix and improve editor state persistence

This commit is contained in:
Hendrik Brucker 2024-11-16 15:05:54 +01:00
parent 1218a16de5
commit 666d7c030b
7 changed files with 139 additions and 106 deletions

View file

@ -186,11 +186,6 @@
</description> </description>
</method> </method>
</methods> </methods>
<members>
<member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2(0, 0)">
The offset vector of the whole graph.
</member>
</members>
<constants> <constants>
<constant name="TYPE_VERTEX" value="0" enum="Type"> <constant name="TYPE_VERTEX" value="0" enum="Type">
A vertex shader, operating on vertices. A vertex shader, operating on vertices.

View file

@ -454,6 +454,7 @@ void ShaderEditorPlugin::_close_shader(int p_index) {
Control *c = shader_tabs->get_tab_control(p_index); Control *c = shader_tabs->get_tab_control(p_index);
VisualShaderEditor *vs_editor = Object::cast_to<VisualShaderEditor>(c); VisualShaderEditor *vs_editor = Object::cast_to<VisualShaderEditor>(c);
if (vs_editor) { if (vs_editor) {
vs_editor->save_editor_layout();
file_menu->get_parent()->remove_child(file_menu); file_menu->get_parent()->remove_child(file_menu);
menu_hb->add_child(file_menu); menu_hb->add_child(file_menu);
menu_hb->move_child(file_menu, 0); menu_hb->move_child(file_menu, 0);

View file

@ -36,6 +36,7 @@
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "core/version_generated.gen.h" #include "core/version_generated.gen.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_properties.h" #include "editor/editor_properties.h"
#include "editor/editor_properties_vector.h" #include "editor/editor_properties_vector.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
@ -224,7 +225,7 @@ void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connectio
} }
void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) { void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id, bool p_is_valid) {
if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) { if (editor->get_current_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {
Link &link = links[p_node_id]; Link &link = links[p_node_id];
for (const KeyValue<int, Port> &E : link.output_ports) { for (const KeyValue<int, Port> &E : link.output_ports) {
@ -261,7 +262,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
vbox->add_child(offset); vbox->add_child(offset);
VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview); VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);
port_preview->setup(visual_shader, editor->preview_material, visual_shader->get_shader_type(), links[p_node_id].output_ports[p_port_id].type == VisualShaderNode::PORT_TYPE_VECTOR_4D, p_node_id, p_port_id, p_is_valid); port_preview->setup(visual_shader, editor->preview_material, editor->get_current_shader_type(), links[p_node_id].output_ports[p_port_id].type == VisualShaderNode::PORT_TYPE_VECTOR_4D, p_node_id, p_port_id, p_is_valid);
port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER); port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
vbox->add_child(port_preview); vbox->add_child(port_preview);
link.preview_visible = true; link.preview_visible = true;
@ -276,7 +277,7 @@ void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, in
} }
void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) { void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) {
if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) { if (p_type != editor->get_current_shader_type() || !links.has(p_node_id)) {
return; return;
} }
remove_node(p_type, p_node_id, true); remove_node(p_type, p_node_id, true);
@ -286,7 +287,7 @@ void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_
} }
void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value) { void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value) {
if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) { if (p_type != editor->get_current_shader_type() || !links.has(p_node_id)) {
return; return;
} }
@ -326,7 +327,7 @@ void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_
} }
void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) { void VisualShaderGraphPlugin::set_parameter_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) { if (editor->get_current_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].parameter_name != nullptr) {
links[p_node_id].parameter_name->set_text(p_name); links[p_node_id].parameter_name->set_text(p_name);
} }
} }
@ -367,14 +368,14 @@ int VisualShaderGraphPlugin::get_constant_index(float p_constant) const {
} }
void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression) { void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression) {
if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id) || !links[p_node_id].expression_edit) { if (p_type != editor->get_current_shader_type() || !links.has(p_node_id) || !links[p_node_id].expression_edit) {
return; return;
} }
links[p_node_id].expression_edit->set_text(p_expression); links[p_node_id].expression_edit->set_text(p_expression);
} }
void VisualShaderGraphPlugin::attach_node_to_frame(VisualShader::Type p_type, int p_node_id, int p_frame_id) { void VisualShaderGraphPlugin::attach_node_to_frame(VisualShader::Type p_type, int p_node_id, int p_frame_id) {
if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id) || !links.has(p_frame_id)) { if (p_type != editor->get_current_shader_type() || !links.has(p_node_id) || !links.has(p_frame_id)) {
return; return;
} }
@ -463,7 +464,7 @@ void VisualShaderGraphPlugin::update_reroute_nodes() {
for (const KeyValue<int, Link> &E : links) { for (const KeyValue<int, Link> &E : links) {
Ref<VisualShaderNodeReroute> reroute_node = Object::cast_to<VisualShaderNodeReroute>(E.value.visual_node); Ref<VisualShaderNodeReroute> reroute_node = Object::cast_to<VisualShaderNodeReroute>(E.value.visual_node);
if (reroute_node.is_valid()) { if (reroute_node.is_valid()) {
update_node(visual_shader->get_shader_type(), E.key); update_node(editor->get_current_shader_type(), E.key);
} }
} }
} }
@ -503,10 +504,6 @@ void VisualShaderGraphPlugin::update_parameter_refs() {
} }
} }
VisualShader::Type VisualShaderGraphPlugin::get_shader_type() const {
return visual_shader->get_shader_type();
}
// Only updates the linked frames of the given node, not the node itself (in case it's a frame node). // Only updates the linked frames of the given node, not the node itself (in case it's a frame node).
void VisualShaderGraphPlugin::update_frames(VisualShader::Type p_type, int p_node) { void VisualShaderGraphPlugin::update_frames(VisualShader::Type p_type, int p_node) {
GraphEdit *graph = editor->graph; GraphEdit *graph = editor->graph;
@ -540,7 +537,7 @@ void VisualShaderGraphPlugin::update_frames(VisualShader::Type p_type, int p_nod
} }
void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) { void VisualShaderGraphPlugin::set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position) {
if (visual_shader->get_shader_type() == p_type && links.has(p_id)) { if (editor->get_current_shader_type() == p_type && links.has(p_id)) {
links[p_id].graph_element->set_position_offset(p_position); links[p_id].graph_element->set_position_offset(p_position);
} }
} }
@ -606,7 +603,7 @@ bool VisualShaderGraphPlugin::is_node_has_parameter_instances_relatively(VisualS
} }
void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update, bool p_update_frames) { void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool p_just_update, bool p_update_frames) {
if (visual_shader.is_null() || p_type != visual_shader->get_shader_type()) { if (visual_shader.is_null() || p_type != editor->get_current_shader_type()) {
return; return;
} }
GraphEdit *graph = editor->graph; GraphEdit *graph = editor->graph;
@ -1441,7 +1438,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
} }
void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id, bool p_just_update) { void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id, bool p_just_update) {
if (visual_shader->get_shader_type() == p_type && links.has(p_id)) { if (editor->get_current_shader_type() == p_type && links.has(p_id)) {
GraphEdit *graph_edit = editor->graph; GraphEdit *graph_edit = editor->graph;
if (!graph_edit) { if (!graph_edit) {
return; return;
@ -1461,7 +1458,7 @@ void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_fro
return; return;
} }
if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) { if (visual_shader.is_valid() && editor->get_current_shader_type() == p_type) {
// Update reroute nodes since their port type might have changed. // Update reroute nodes since their port type might have changed.
Ref<VisualShaderNodeReroute> reroute_to = visual_shader->get_node(p_type, p_to_node); Ref<VisualShaderNodeReroute> reroute_to = visual_shader->get_node(p_type, p_to_node);
Ref<VisualShaderNodeReroute> reroute_from = visual_shader->get_node(p_type, p_from_node); Ref<VisualShaderNodeReroute> reroute_from = visual_shader->get_node(p_type, p_from_node);
@ -1484,7 +1481,7 @@ void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_
return; return;
} }
if (visual_shader.is_valid() && visual_shader->get_shader_type() == p_type) { if (visual_shader.is_valid() && editor->get_current_shader_type() == p_type) {
graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port);
for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) {
@ -1524,6 +1521,7 @@ List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer;
List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer; List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer;
void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) { void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) {
shader_fully_loaded = false;
bool changed = false; bool changed = false;
VisualShader *visual_shader_ptr = Object::cast_to<VisualShader>(p_shader.ptr()); VisualShader *visual_shader_ptr = Object::cast_to<VisualShader>(p_shader.ptr());
if (visual_shader_ptr) { if (visual_shader_ptr) {
@ -1538,7 +1536,6 @@ void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) {
graph_plugin->register_shader(visual_shader.ptr()); graph_plugin->register_shader(visual_shader.ptr());
visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview)); visual_shader->connect_changed(callable_mp(this, &VisualShaderEditor::_update_preview));
visual_shader->set_graph_offset(graph->get_scroll_offset() / EDSCALE);
_set_mode(visual_shader->get_mode()); _set_mode(visual_shader->get_mode());
preview_material->set_shader(visual_shader); preview_material->set_shader(visual_shader);
@ -1558,6 +1555,7 @@ void VisualShaderEditor::edit_shader(const Ref<Shader> &p_shader) {
_update_options_menu(); _update_options_menu();
_update_preview(); _update_preview();
_update_graph(); _update_graph();
callable_mp(this, &VisualShaderEditor::_restore_editor_state).call_deferred();
} }
} }
} }
@ -1581,6 +1579,37 @@ void VisualShaderEditor::validate_script() {
} }
} }
void VisualShaderEditor::save_editor_layout() {
const String id_string = _get_cache_id_string();
const String offset_cache_key = _get_cache_key("offset");
const String zoom_cache_key = _get_cache_key("zoom");
vs_editor_cache->set_value(id_string, offset_cache_key, graph->get_scroll_offset() / EDSCALE);
vs_editor_cache->set_value(id_string, zoom_cache_key, graph->get_zoom());
vs_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));
}
void VisualShaderEditor::set_current_shader_type(VisualShader::Type p_type) {
current_type = p_type;
const String id_string = _get_cache_id_string();
vs_editor_cache->set_value(id_string, "edited_type", p_type);
vs_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));
const String offset_cache_key = _get_cache_key("offset");
const String zoom_cache_key = _get_cache_key("zoom");
const Vector2 saved_scroll_offset = vs_editor_cache->get_value(id_string, offset_cache_key, Vector2());
const real_t saved_zoom = vs_editor_cache->get_value(id_string, zoom_cache_key, 1.0);
graph->set_scroll_offset(saved_scroll_offset);
graph->set_zoom(saved_zoom);
}
VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
return current_type;
}
Control *VisualShaderEditor::get_top_bar() { Control *VisualShaderEditor::get_top_bar() {
return toolbar; return toolbar;
} }
@ -1723,7 +1752,7 @@ void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {
Ref<VisualShaderNodeCustom> ref; Ref<VisualShaderNodeCustom> ref;
ref.instantiate(); ref.instantiate();
ref->set_script(p_script); ref->set_script(p_script);
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {
for (int i = 0; i < add_options.size(); i++) { for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].is_custom && add_options[i].script == p_script) { if (add_options[i].is_custom && add_options[i].script == p_script) {
add_options.remove_at(i); add_options.remove_at(i);
@ -2140,7 +2169,7 @@ void VisualShaderEditor::_update_nodes() {
Ref<VisualShaderNodeCustom> ref; Ref<VisualShaderNodeCustom> ref;
ref.instantiate(); ref.instantiate();
ref->set_script(scr); ref->set_script(scr);
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {
continue; continue;
} }
Dictionary dict = get_custom_node_data(ref); Dictionary dict = get_custom_node_data(ref);
@ -2164,7 +2193,7 @@ void VisualShaderEditor::_update_nodes() {
Object *instance = ClassDB::instantiate(E); Object *instance = ClassDB::instantiate(E);
Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance); Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance);
ERR_CONTINUE(ref.is_null()); ERR_CONTINUE(ref.is_null());
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { if (!ref->is_available(visual_shader->get_mode(), get_current_shader_type())) {
continue; continue;
} }
Dictionary dict = get_custom_node_data(ref); Dictionary dict = get_custom_node_data(ref);
@ -2185,7 +2214,7 @@ void VisualShaderEditor::_update_nodes() {
Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(item.node.ptr()); Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(item.node.ptr());
if (custom.is_valid()) { if (custom.is_valid()) {
if (!custom->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { if (!custom->is_available(visual_shader->get_mode(), get_current_shader_type())) {
item.disabled = true; item.disabled = true;
} else { } else {
item.disabled = false; item.disabled = false;
@ -2276,7 +2305,7 @@ void VisualShaderEditor::_update_options_menu() {
Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(vsn.ptr()); Ref<VisualShaderNodeInput> input = Object::cast_to<VisualShaderNodeInput>(vsn.ptr());
if (input.is_valid()) { if (input.is_valid()) {
input->set_shader_mode(visual_shader->get_mode()); input->set_shader_mode(visual_shader->get_mode());
input->set_shader_type(visual_shader->get_shader_type()); input->set_shader_type(get_current_shader_type());
if (!add_options[i].ops.is_empty() && add_options[i].ops[0].is_string()) { if (!add_options[i].ops.is_empty() && add_options[i].ops[0].is_string()) {
input->set_input_name((String)add_options[i].ops[0]); input->set_input_name((String)add_options[i].ops[0]);
} }
@ -2468,7 +2497,12 @@ void VisualShaderEditor::_set_mode(int p_which) {
varying_button->show(); varying_button->show();
mode = MODE_FLAGS_SPATIAL_CANVASITEM; mode = MODE_FLAGS_SPATIAL_CANVASITEM;
} }
visual_shader->set_shader_type(get_current_shader_type());
const String id_string = _get_cache_id_string();
int saved_type = vs_editor_cache->get_value(id_string, "edited_type", 0);
edit_type->select(saved_type);
set_current_shader_type((VisualShader::Type)saved_type);
} }
Size2 VisualShaderEditor::get_minimum_size() const { Size2 VisualShaderEditor::get_minimum_size() const {
@ -2566,16 +2600,10 @@ void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names
} }
void VisualShaderEditor::_update_graph() { void VisualShaderEditor::_update_graph() {
if (updating) {
return;
}
if (visual_shader.is_null()) { if (visual_shader.is_null()) {
return; return;
} }
graph->set_scroll_offset(visual_shader->get_graph_offset() * EDSCALE);
VisualShader::Type type = get_current_shader_type(); VisualShader::Type type = get_current_shader_type();
graph->clear_connections(); graph->clear_connections();
@ -2632,18 +2660,33 @@ void VisualShaderEditor::_update_graph() {
graph->set_connection_lines_curvature(graph_lines_curvature); graph->set_connection_lines_curvature(graph_lines_curvature);
} }
VisualShader::Type VisualShaderEditor::get_current_shader_type() const { void VisualShaderEditor::_restore_editor_state() {
VisualShader::Type type; const String id_string = _get_cache_id_string();
if (mode & MODE_FLAGS_PARTICLES) {
type = VisualShader::Type(edit_type->get_selected() + 3 + (custom_mode_enabled ? 3 : 0)); const String offset_cache_key = _get_cache_key("offset");
} else if (mode & MODE_FLAGS_SKY) { const String zoom_cache_key = _get_cache_key("zoom");
type = VisualShader::Type(edit_type->get_selected() + 8); const Vector2 saved_scroll_offset = vs_editor_cache->get_value(id_string, offset_cache_key, Vector2());
} else if (mode & MODE_FLAGS_FOG) { const real_t saved_zoom = vs_editor_cache->get_value(id_string, zoom_cache_key, 1.0);
type = VisualShader::Type(edit_type->get_selected() + 9);
} else { // Setting the scroll offset needs to be further deferred because it requires min/max scroll offset to be final (as it gets clamped).
type = VisualShader::Type(edit_type->get_selected()); callable_mp(graph, &GraphEdit::set_zoom).call_deferred(saved_zoom);
callable_mp(graph, &GraphEdit::set_scroll_offset).call_deferred(saved_scroll_offset);
shader_fully_loaded = true;
}
String VisualShaderEditor::_get_cache_id_string() const {
String id_string = visual_shader->get_path();
const ResourceUID::ID uid = EditorFileSystem::get_singleton()->get_file_uid(id_string);
if (uid != ResourceUID::INVALID_ID) {
id_string = ResourceUID::get_singleton()->id_to_text(uid);
} }
return type; return id_string;
}
String VisualShaderEditor::_get_cache_key(const String &p_prop_name) const {
const int type = get_current_shader_type();
return "type" + itos(type) + ":" + p_prop_name;
} }
void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) { void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) {
@ -3922,7 +3965,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, cons
VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr()); VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr());
if (input) { if (input) {
input->set_shader_mode(visual_shader->get_mode()); input->set_shader_mode(visual_shader->get_mode());
input->set_shader_type(visual_shader->get_shader_type()); input->set_shader_type(get_current_shader_type());
} }
// Attempting to connect to the first correct port. // Attempting to connect to the first correct port.
@ -4123,7 +4166,7 @@ void VisualShaderEditor::_nodes_dragged() {
} }
for (const int node_id : nodes_link_to_frame_buffer) { for (const int node_id : nodes_link_to_frame_buffer) {
VisualShader::Type type = visual_shader->get_shader_type(); VisualShader::Type type = get_current_shader_type();
Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, node_id); Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, node_id);
undo_redo->add_do_method(visual_shader.ptr(), "attach_node_to_frame", type, node_id, frame_node_id_to_link_to); undo_redo->add_do_method(visual_shader.ptr(), "attach_node_to_frame", type, node_id, frame_node_id_to_link_to);
@ -5295,20 +5338,15 @@ void VisualShaderEditor::_notification(int p_what) {
} }
} }
void VisualShaderEditor::_scroll_changed(const Vector2 &p_scroll) { void VisualShaderEditor::_scroll_offset_changed(const Vector2 &p_scroll) {
if (updating) { if (!shader_fully_loaded) {
return; return;
} }
updating = true;
visual_shader->set_graph_offset(p_scroll / EDSCALE); panning_debounce_timer->start();
updating = false;
} }
void VisualShaderEditor::_node_changed(int p_id) { void VisualShaderEditor::_node_changed(int p_id) {
if (updating) {
return;
}
if (is_visible_in_tree()) { if (is_visible_in_tree()) {
_update_graph(); _update_graph();
} }
@ -5329,7 +5367,7 @@ void VisualShaderEditor::_frame_rect_changed(const GraphFrame *p_frame, const Re
} }
int node_id = String(p_frame->get_name()).to_int(); int node_id = String(p_frame->get_name()).to_int();
Ref<VisualShaderNodeResizableBase> vsnode = visual_shader->get_node(visual_shader->get_shader_type(), node_id); Ref<VisualShaderNodeResizableBase> vsnode = visual_shader->get_node(get_current_shader_type(), node_id);
if (vsnode.is_null()) { if (vsnode.is_null()) {
return; return;
} }
@ -5573,7 +5611,7 @@ void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2
_dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_offset() / scale + mpos / scale - selection_center, false); _dup_paste_nodes(type, copy_items_buffer, copy_connections_buffer, graph->get_scroll_offset() / scale + mpos / scale - selection_center, false);
} }
void VisualShaderEditor::_mode_selected(int p_id) { void VisualShaderEditor::_type_selected(int p_id) {
int offset = 0; int offset = 0;
if (mode & MODE_FLAGS_PARTICLES) { if (mode & MODE_FLAGS_PARTICLES) {
offset = 3; offset = 3;
@ -5593,7 +5631,7 @@ void VisualShaderEditor::_mode_selected(int p_id) {
offset = 9; offset = 9;
} }
visual_shader->set_shader_type(VisualShader::Type(p_id + offset)); set_current_shader_type(VisualShader::Type(p_id + offset));
_update_nodes(); _update_nodes();
_update_graph(); _update_graph();
@ -5607,9 +5645,9 @@ void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) {
custom_mode_enabled = p_enabled; custom_mode_enabled = p_enabled;
int id = edit_type->get_selected() + 3; int id = edit_type->get_selected() + 3;
if (p_enabled) { if (p_enabled) {
visual_shader->set_shader_type(VisualShader::Type(id + 3)); set_current_shader_type(VisualShader::Type(id + 3));
} else { } else {
visual_shader->set_shader_type(VisualShader::Type(id)); set_current_shader_type(VisualShader::Type(id));
} }
_update_options_menu(); _update_options_menu();
_update_graph(); _update_graph();
@ -6242,7 +6280,7 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
saved_node_pos_dirty = true; saved_node_pos_dirty = true;
_add_node(cubemap_node_option_idx, {}, arr[i], i); _add_node(cubemap_node_option_idx, {}, arr[i], i);
} else if (type == "Mesh" && visual_shader->get_mode() == Shader::MODE_PARTICLES && } else if (type == "Mesh" && visual_shader->get_mode() == Shader::MODE_PARTICLES &&
(visual_shader->get_shader_type() == VisualShader::TYPE_START || visual_shader->get_shader_type() == VisualShader::TYPE_START_CUSTOM)) { (get_current_shader_type() == VisualShader::TYPE_START || get_current_shader_type() == VisualShader::TYPE_START_CUSTOM)) {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true; saved_node_pos_dirty = true;
_add_node(mesh_emitter_option_idx, {}, arr[i], i); _add_node(mesh_emitter_option_idx, {}, arr[i], i);
@ -6425,6 +6463,9 @@ void VisualShaderEditor::_bind_methods() {
} }
VisualShaderEditor::VisualShaderEditor() { VisualShaderEditor::VisualShaderEditor() {
vs_editor_cache.instantiate();
vs_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("vs_editor_cache.cfg"));
ShaderLanguage::get_keyword_list(&keyword_list); ShaderLanguage::get_keyword_list(&keyword_list);
EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved)); EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::_resource_saved));
FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created)); FileSystemDock::get_singleton()->get_script_create_dialog()->connect("script_created", callable_mp(this, &VisualShaderEditor::_script_created));
@ -6462,7 +6503,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect("connection_request", callable_mp(this, &VisualShaderEditor::_connection_request), CONNECT_DEFERRED); graph->connect("connection_request", callable_mp(this, &VisualShaderEditor::_connection_request), CONNECT_DEFERRED);
graph->connect("disconnection_request", callable_mp(this, &VisualShaderEditor::_disconnection_request), CONNECT_DEFERRED); graph->connect("disconnection_request", callable_mp(this, &VisualShaderEditor::_disconnection_request), CONNECT_DEFERRED);
graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected)); graph->connect("node_selected", callable_mp(this, &VisualShaderEditor::_node_selected));
graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_changed)); graph->connect("scroll_offset_changed", callable_mp(this, &VisualShaderEditor::_scroll_offset_changed));
graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes)); graph->connect("duplicate_nodes_request", callable_mp(this, &VisualShaderEditor::_duplicate_nodes));
graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(false)); graph->connect("copy_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(false));
graph->connect("cut_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(true)); graph->connect("cut_nodes_request", callable_mp(this, &VisualShaderEditor::_copy_nodes).bind(true));
@ -6576,24 +6617,24 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type_standard->add_item(TTR("Fragment")); edit_type_standard->add_item(TTR("Fragment"));
edit_type_standard->add_item(TTR("Light")); edit_type_standard->add_item(TTR("Light"));
edit_type_standard->select(1); edit_type_standard->select(1);
edit_type_standard->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_mode_selected)); edit_type_standard->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));
edit_type_particles = memnew(OptionButton); edit_type_particles = memnew(OptionButton);
edit_type_particles->add_item(TTR("Start")); edit_type_particles->add_item(TTR("Start"));
edit_type_particles->add_item(TTR("Process")); edit_type_particles->add_item(TTR("Process"));
edit_type_particles->add_item(TTR("Collide")); edit_type_particles->add_item(TTR("Collide"));
edit_type_particles->select(0); edit_type_particles->select(0);
edit_type_particles->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_mode_selected)); edit_type_particles->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));
edit_type_sky = memnew(OptionButton); edit_type_sky = memnew(OptionButton);
edit_type_sky->add_item(TTR("Sky")); edit_type_sky->add_item(TTR("Sky"));
edit_type_sky->select(0); edit_type_sky->select(0);
edit_type_sky->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_mode_selected)); edit_type_sky->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));
edit_type_fog = memnew(OptionButton); edit_type_fog = memnew(OptionButton);
edit_type_fog->add_item(TTR("Fog")); edit_type_fog->add_item(TTR("Fog"));
edit_type_fog->select(0); edit_type_fog->select(0);
edit_type_fog->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_mode_selected)); edit_type_fog->connect(SceneStringName(item_selected), callable_mp(this, &VisualShaderEditor::_type_selected));
edit_type = edit_type_standard; edit_type = edit_type_standard;
@ -7691,6 +7732,12 @@ VisualShaderEditor::VisualShaderEditor() {
add_child(property_editor_popup); add_child(property_editor_popup);
edited_property_holder.instantiate(); edited_property_holder.instantiate();
panning_debounce_timer = memnew(Timer);
panning_debounce_timer->set_one_shot(true);
panning_debounce_timer->set_wait_time(1.0);
panning_debounce_timer->connect("timeout", callable_mp(this, &VisualShaderEditor::save_editor_layout));
add_child(panning_debounce_timer);
} }
class VisualShaderNodePluginInputEditor : public OptionButton { class VisualShaderNodePluginInputEditor : public OptionButton {
@ -8052,7 +8099,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
if (p_shader.is_valid() && (p_node->is_class("VisualShaderNodeVaryingGetter") || p_node->is_class("VisualShaderNodeVaryingSetter"))) { if (p_shader.is_valid() && (p_node->is_class("VisualShaderNodeVaryingGetter") || p_node->is_class("VisualShaderNodeVaryingSetter"))) {
VisualShaderNodePluginVaryingEditor *editor = memnew(VisualShaderNodePluginVaryingEditor); VisualShaderNodePluginVaryingEditor *editor = memnew(VisualShaderNodePluginVaryingEditor);
editor->setup(vseditor, p_node, p_shader->get_shader_type()); editor->setup(vseditor, p_node, vseditor->get_current_shader_type());
return editor; return editor;
} }

View file

@ -175,7 +175,6 @@ public:
Ref<Script> get_node_script(int p_node_id) const; Ref<Script> get_node_script(int p_node_id) const;
void update_theme(); void update_theme();
bool is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const; bool is_node_has_parameter_instances_relatively(VisualShader::Type p_type, int p_node) const;
VisualShader::Type get_shader_type() const;
VisualShaderGraphPlugin(); VisualShaderGraphPlugin();
}; };
@ -198,6 +197,8 @@ class VisualShaderEditor : public ShaderEditor {
GDCLASS(VisualShaderEditor, ShaderEditor); GDCLASS(VisualShaderEditor, ShaderEditor);
friend class VisualShaderGraphPlugin; friend class VisualShaderGraphPlugin;
Ref<ConfigFile> vs_editor_cache; // Keeps the graph offsets and zoom levels for each VisualShader that has been edited.
PopupPanel *property_editor_popup = nullptr; PopupPanel *property_editor_popup = nullptr;
EditorProperty *property_editor = nullptr; EditorProperty *property_editor = nullptr;
int editing_node = -1; int editing_node = -1;
@ -295,6 +296,7 @@ class VisualShaderEditor : public ShaderEditor {
}; };
int mode = MODE_FLAGS_SPATIAL_CANVASITEM; int mode = MODE_FLAGS_SPATIAL_CANVASITEM;
VisualShader::Type current_type = VisualShader::Type::TYPE_VERTEX; // The type of the currently edited VisualShader.
enum TypeFlags { enum TypeFlags {
TYPE_FLAGS_VERTEX = 1, TYPE_FLAGS_VERTEX = 1,
@ -381,6 +383,11 @@ class VisualShaderEditor : public ShaderEditor {
void _update_nodes(); void _update_nodes();
void _update_graph(); void _update_graph();
void _restore_editor_state();
String _get_cache_id_string() const;
String _get_cache_key(const String &p_prop_name) const;
struct AddOption { struct AddOption {
String name; String name;
String category; String category;
@ -459,15 +466,17 @@ class VisualShaderEditor : public ShaderEditor {
}; };
List<DragOp> drag_buffer; List<DragOp> drag_buffer;
Timer *panning_debounce_timer = nullptr;
bool shader_fully_loaded = false;
bool drag_dirty = false; bool drag_dirty = false;
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node); void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node);
void _nodes_dragged(); void _nodes_dragged();
bool updating = false;
void _connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index); void _connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
void _disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index); void _disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
void _scroll_changed(const Vector2 &p_scroll); void _scroll_offset_changed(const Vector2 &p_scroll);
void _node_selected(Object *p_node); void _node_selected(Object *p_node);
void _delete_nodes(int p_type, const List<int> &p_nodes); void _delete_nodes(int p_type, const List<int> &p_nodes);
@ -556,7 +565,7 @@ class VisualShaderEditor : public ShaderEditor {
Vector<Ref<VisualShaderNodePlugin>> plugins; Vector<Ref<VisualShaderNodePlugin>> plugins;
Ref<VisualShaderGraphPlugin> graph_plugin; Ref<VisualShaderGraphPlugin> graph_plugin;
void _mode_selected(int p_id); void _type_selected(int p_id);
void _custom_mode_toggled(bool p_enabled); void _custom_mode_toggled(bool p_enabled);
void _input_select_item(Ref<VisualShaderNodeInput> p_input, const String &p_name); void _input_select_item(Ref<VisualShaderNodeInput> p_input, const String &p_name);
@ -565,8 +574,6 @@ class VisualShaderEditor : public ShaderEditor {
void _float_constant_selected(int p_which); void _float_constant_selected(int p_which);
VisualShader::Type get_current_shader_type() const;
void _add_input_port(int p_node, int p_port, int p_port_type, const String &p_name); void _add_input_port(int p_node, int p_port, int p_port_type, const String &p_name);
void _remove_input_port(int p_node, int p_port); void _remove_input_port(int p_node, int p_port);
void _change_input_port_type(int p_type, int p_node, int p_port); void _change_input_port_type(int p_type, int p_node, int p_port);
@ -647,6 +654,12 @@ public:
virtual bool is_unsaved() const override; virtual bool is_unsaved() const override;
virtual void save_external_data(const String &p_str = "") override; virtual void save_external_data(const String &p_str = "") override;
virtual void validate_script() override; virtual void validate_script() override;
void save_editor_layout();
void set_current_shader_type(VisualShader::Type p_type);
VisualShader::Type get_current_shader_type() const;
virtual Control *get_top_bar() override; virtual Control *get_top_bar() override;
void add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin); void add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin);

View file

@ -321,3 +321,11 @@ Validate extension JSON: Error: Field 'classes/RichTextLabel/methods/add_image/a
Validate extension JSON: Error: Field 'classes/RichTextLabel/methods/update_image/arguments': size changed value in new API, from 11 to 12. Validate extension JSON: Error: Field 'classes/RichTextLabel/methods/update_image/arguments': size changed value in new API, from 11 to 12.
Optional argument added. Compatibility methods registered. Optional argument added. Compatibility methods registered.
GH-98566
--------
Validate extension JSON: API was removed: classes/VisualShader/methods/set_graph_offset
Validate extension JSON: API was removed: classes/VisualShader/methods/get_graph_offset
The graph_offset property was removed from the resource. This information is now stored in `vs_editor_cache.cfg`.

View file

@ -822,14 +822,6 @@ VisualShaderNodeCustom::VisualShaderNodeCustom() {
///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////
void VisualShader::set_shader_type(Type p_type) {
current_type = p_type;
}
VisualShader::Type VisualShader::get_shader_type() const {
return current_type;
}
void VisualShader::add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type) { void VisualShader::add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type) {
ERR_FAIL_COND(!p_name.is_valid_ascii_identifier()); ERR_FAIL_COND(!p_name.is_valid_ascii_identifier());
ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX); ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX);
@ -1466,14 +1458,6 @@ void VisualShader::set_mode(Mode p_mode) {
notify_property_list_changed(); notify_property_list_changed();
} }
void VisualShader::set_graph_offset(const Vector2 &p_offset) {
graph_offset = p_offset;
}
Vector2 VisualShader::get_graph_offset() const {
return graph_offset;
}
Shader::Mode VisualShader::get_mode() const { Shader::Mode VisualShader::get_mode() const {
return shader_mode; return shader_mode;
} }
@ -3157,9 +3141,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections); ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset);
ClassDB::bind_method(D_METHOD("attach_node_to_frame", "type", "id", "frame"), &VisualShader::attach_node_to_frame); ClassDB::bind_method(D_METHOD("attach_node_to_frame", "type", "id", "frame"), &VisualShader::attach_node_to_frame);
ClassDB::bind_method(D_METHOD("detach_node_from_frame", "type", "id"), &VisualShader::detach_node_from_frame); ClassDB::bind_method(D_METHOD("detach_node_from_frame", "type", "id"), &VisualShader::detach_node_from_frame);
@ -3173,8 +3154,6 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader); ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset");
ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs. ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs.
BIND_ENUM_CONSTANT(TYPE_VERTEX); BIND_ENUM_CONSTANT(TYPE_VERTEX);

View file

@ -114,8 +114,6 @@ public:
}; };
private: private:
Type current_type;
struct Node { struct Node {
Ref<VisualShaderNode> node; Ref<VisualShaderNode> node;
Vector2 position; Vector2 position;
@ -133,8 +131,6 @@ private:
TypedArray<Dictionary> _get_node_connections(Type p_type) const; TypedArray<Dictionary> _get_node_connections(Type p_type) const;
Vector2 graph_offset;
HashMap<String, int> modes; HashMap<String, int> modes;
HashSet<StringName> flags; HashSet<StringName> flags;
@ -180,9 +176,6 @@ protected:
virtual void reset_state() override; virtual void reset_state() override;
public: // internal methods public: // internal methods
void set_shader_type(Type p_type);
Type get_shader_type() const;
enum { enum {
NODE_ID_INVALID = -1, NODE_ID_INVALID = -1,
NODE_ID_OUTPUT = 0, NODE_ID_OUTPUT = 0,
@ -249,9 +242,6 @@ public: // internal methods
virtual bool is_text_shader() const override; virtual bool is_text_shader() const override;
void set_graph_offset(const Vector2 &p_offset);
Vector2 get_graph_offset() const;
String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const; String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const;
String validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const; String validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const;