Skip to content

Commit

Permalink
Merge pull request #36421 from Chaosus/vs_sort_custom_nods
Browse files Browse the repository at this point in the history
Refactor node processing in visual shader member dialog
  • Loading branch information
Chaosus authored Feb 21, 2020
2 parents a77c862 + b78b37e commit 7c1415b
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 131 deletions.
12 changes: 2 additions & 10 deletions doc/classes/VisualShaderNodeCustom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
<return type="String">
</return>
<description>
Override this method to define the category of the associated custom node in the Visual Shader Editor's members dialog.
Defining this method is [b]optional[/b]. If not overridden, the node will be filed under the "Custom" category.
Override this method to define the path to the associated custom node in the Visual Shader Editor's members dialog. The path may looks like [code]"MyGame/MyFunctions/Noise"[/code].
Defining this method is [b]optional[/b]. If not overridden, the node will be filed under the "Addons" category.
</description>
</method>
<method name="_get_code" qualifiers="virtual">
Expand Down Expand Up @@ -135,14 +135,6 @@
Defining this method is [b]optional[/b]. If not overridden, no return icon is shown.
</description>
</method>
<method name="_get_subcategory" qualifiers="virtual">
<return type="String">
</return>
<description>
Override this method to define the subcategory of the associated custom node in the Visual Shader Editor's members dialog.
Defining this method is [b]optional[/b]. If not overridden, the node will be filed under the root of the main category (see [method _get_category]).
</description>
</method>
<method name="_is_highend" qualifiers="virtual">
<return type="bool">
</return>
Expand Down
197 changes: 83 additions & 114 deletions editor/plugins/visual_shader_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ void VisualShaderEditor::clear_custom_types() {
}
}

void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory, bool p_highend) {
void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend) {

ERR_FAIL_COND(!p_name.is_valid_identifier());
ERR_FAIL_COND(!p_script.is_valid());
Expand All @@ -134,15 +134,15 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script>
ao.return_type = p_return_icon_type;
ao.description = p_description;
ao.category = p_category;
ao.sub_category = p_subcategory;
ao.highend = p_highend;
ao.is_custom = true;

bool begin = false;
String root = p_category.split("/")[0];

for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].is_custom) {
if (add_options[i].category == p_category) {
if (add_options[i].category == root) {
if (!begin) {
begin = true;
}
Expand Down Expand Up @@ -239,9 +239,6 @@ void VisualShaderEditor::update_custom_nodes() {
if (ref->has_method("_get_category")) {
category = (String)ref->call("_get_category");
}
if (category == "") {
category = "Custom";
}

String subcategory = "";
if (ref->has_method("_get_subcategory")) {
Expand All @@ -258,18 +255,19 @@ void VisualShaderEditor::update_custom_nodes() {
dict["script"] = script;
dict["description"] = description;
dict["return_icon_type"] = return_icon_type;

category = category.rstrip("/");
category = category.lstrip("/");
category = "Addons/" + category;
if (subcategory != "") {
category += "/" + subcategory;
}

dict["category"] = category;
dict["subcategory"] = subcategory;
dict["highend"] = highend;

String key;
key = category;
key += "/";
if (subcategory != "") {
key += subcategory;
key += "/";
}
key += name;
key = category + "/" + name;

added[key] = dict;
}
Expand All @@ -284,7 +282,7 @@ void VisualShaderEditor::update_custom_nodes() {

const Dictionary &value = (Dictionary)added[key];

add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["subcategory"], value["highend"]);
add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);
}

_update_options_menu();
Expand All @@ -299,134 +297,105 @@ void VisualShaderEditor::_update_options_menu() {
node_desc->set_text("");
members_dialog->get_ok()->set_disabled(true);

String prev_category;
String prev_sub_category;

members->clear();
TreeItem *root = members->create_item();
TreeItem *category = NULL;
TreeItem *sub_category = NULL;

String filter = node_filter->get_text().strip_edges();
bool use_filter = !filter.empty();

Vector<String> categories;
Vector<String> sub_categories;

int item_count = 0;
int item_count2 = 0;
bool is_first_item = true;

Color unsupported_color = get_color("error_color", "Editor");
Color supported_color = get_color("warning_color", "Editor");

static bool low_driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES2";

Map<String, TreeItem *> folders;

int current_func = -1;

if (!visual_shader.is_null()) {
current_func = visual_shader->get_mode();
}

for (int i = 0; i < add_options.size() + 1; i++) {
Vector<AddOption> custom_options;
Vector<AddOption> embedded_options;

if (i == add_options.size()) {
if (sub_category != NULL && item_count2 == 0) {
memdelete(sub_category);
--item_count;
for (int i = 0; i < add_options.size(); i++) {
if (!use_filter || add_options[i].name.findn(filter) != -1) {
if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode)) {
continue;
}
if (category != NULL && item_count == 0) {
memdelete(category);
const_cast<AddOption &>(add_options[i]).temp_idx = i; // save valid id
if (add_options[i].is_custom) {
custom_options.push_back(add_options[i]);
} else {
embedded_options.push_back(add_options[i]);
}
break;
}
}
Vector<AddOption> options;
SortArray<AddOption, _OptionComparator> sorter;
sorter.sort(custom_options.ptrw(), custom_options.size());

if (!use_filter || add_options[i].name.findn(filter) != -1) {

if ((add_options[i].func != current_func && add_options[i].func != -1) || !_is_available(add_options[i].mode))
continue;
options.append_array(custom_options);
options.append_array(embedded_options);

if (prev_category != add_options[i].category) {
if (category != NULL && item_count == 0) {
memdelete(category);
}
for (int i = 0; i < options.size(); i++) {
String path = options[i].category;
Vector<String> subfolders = path.split("/");
TreeItem *category = NULL;

item_count = 0;
prev_sub_category = "";
category = members->create_item(root);
category->set_text(0, add_options[i].category);
category->set_selectable(0, false);
if (!use_filter)
category->set_collapsed(true);
}

if (add_options[i].sub_category != "") {
if (prev_sub_category != add_options[i].sub_category) {
if (category != NULL) {
if (sub_category != NULL && item_count2 == 0) {
memdelete(sub_category);
--item_count;
}
++item_count;
item_count2 = 0;
sub_category = members->create_item(category);
sub_category->set_text(0, add_options[i].sub_category);
sub_category->set_selectable(0, false);
if (!use_filter)
sub_category->set_collapsed(true);
}
}
} else {
sub_category = NULL;
}

TreeItem *p_category = NULL;

if (sub_category != NULL) {
p_category = sub_category;
++item_count2;
} else if (category != NULL) {
p_category = category;
++item_count;
}

if (p_category != NULL) {
TreeItem *item = members->create_item(p_category);
if (add_options[i].highend && low_driver)
item->set_custom_color(0, unsupported_color);
else if (add_options[i].highend)
item->set_custom_color(0, supported_color);
item->set_text(0, add_options[i].name);
if (is_first_item && use_filter) {
item->select(0);
node_desc->set_text(_get_description(i));
is_first_item = false;
}
switch (add_options[i].return_type) {
case VisualShaderNode::PORT_TYPE_SCALAR:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_VECTOR:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_TRANSFORM:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_SAMPLER:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"));
break;
default:
break;
if (!folders.has(path)) {
category = root;
String path_temp = "";
for (int j = 0; j < subfolders.size(); j++) {
path_temp += subfolders[j];
if (!folders.has(path_temp)) {
category = members->create_item(category);
category->set_selectable(0, false);
category->set_collapsed(!use_filter);
category->set_text(0, subfolders[j]);
folders.insert(path_temp, category);
} else {
category = folders[path_temp];
}
item->set_meta("id", i);
}

prev_sub_category = add_options[i].sub_category;
prev_category = add_options[i].category;
} else {
category = folders[path];
}

TreeItem *item = members->create_item(category);
if (options[i].highend && low_driver)
item->set_custom_color(0, unsupported_color);
else if (options[i].highend)
item->set_custom_color(0, supported_color);
item->set_text(0, options[i].name);
if (is_first_item && use_filter) {
item->select(0);
node_desc->set_text(options[i].description);
is_first_item = false;
}
switch (options[i].return_type) {
case VisualShaderNode::PORT_TYPE_SCALAR:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("float", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_VECTOR:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Vector3", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("bool", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_TRANSFORM:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
break;
case VisualShaderNode::PORT_TYPE_SAMPLER:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("ImageTexture", "EditorIcons"));
break;
default:
break;
}
item->set_meta("id", options[i].temp_idx);
}
}

Expand Down
16 changes: 10 additions & 6 deletions editor/plugins/visual_shader_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ class VisualShaderEditor : public VBoxContainer {
struct AddOption {
String name;
String category;
String sub_category;
String type;
String description;
int sub_func;
Expand All @@ -116,12 +115,12 @@ class VisualShaderEditor : public VBoxContainer {
float value;
bool highend;
bool is_custom;
int temp_idx;

AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) {
name = p_name;
type = p_type;
category = p_category;
sub_category = p_sub_category;
category = p_category + "/" + p_sub_category;
description = p_description;
sub_func = p_sub_func;
return_type = p_return_type;
Expand All @@ -135,8 +134,7 @@ class VisualShaderEditor : public VBoxContainer {
AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) {
name = p_name;
type = p_type;
category = p_category;
sub_category = p_sub_category;
category = p_category + "/" + p_sub_category;
description = p_description;
sub_func = 0;
sub_func_str = p_sub_func;
Expand All @@ -148,6 +146,12 @@ class VisualShaderEditor : public VBoxContainer {
is_custom = false;
}
};
struct _OptionComparator {

_FORCE_INLINE_ bool operator()(const AddOption &a, const AddOption &b) const {
return a.category.count("/") > b.category.count("/") || (a.category + "/" + a.name).naturalnocasecmp_to(b.category + "/" + b.name) < 0;
}
};

Vector<AddOption> add_options;
int texture_node_option_idx;
Expand Down Expand Up @@ -265,7 +269,7 @@ class VisualShaderEditor : public VBoxContainer {
static VisualShaderEditor *get_singleton() { return singleton; }

void clear_custom_types();
void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_subcategory, bool p_highend);
void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend);

virtual Size2 get_minimum_size() const;
void edit(VisualShader *p_visual_shader);
Expand Down
1 change: 0 additions & 1 deletion scene/resources/visual_shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,6 @@ void VisualShaderNodeCustom::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_description"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_category"));
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_subcategory"));
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_return_icon_type"));
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_count"));
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_type", PropertyInfo(Variant::INT, "port")));
Expand Down

0 comments on commit 7c1415b

Please sign in to comment.