Add handling of custom visual shader nodes from GDExtension
This commit is contained in:
parent
8c729f0f34
commit
998b48f722
4 changed files with 124 additions and 65 deletions
|
@ -1209,13 +1209,19 @@ 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, bool p_highend) {
|
void VisualShaderEditor::add_custom_type(const String &p_name, const String &p_type, 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_name.is_valid_identifier());
|
||||||
ERR_FAIL_COND(!p_script.is_valid());
|
ERR_FAIL_COND(p_type.is_empty() && !p_script.is_valid());
|
||||||
|
|
||||||
for (int i = 0; i < add_options.size(); i++) {
|
for (int i = 0; i < add_options.size(); i++) {
|
||||||
if (add_options[i].is_custom) {
|
const AddOption &op = add_options[i];
|
||||||
if (add_options[i].script == p_script) {
|
|
||||||
|
if (op.is_custom) {
|
||||||
|
if (!p_type.is_empty()) {
|
||||||
|
if (op.type == p_type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (op.script == p_script) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1223,12 +1229,14 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script>
|
||||||
|
|
||||||
AddOption ao;
|
AddOption ao;
|
||||||
ao.name = p_name;
|
ao.name = p_name;
|
||||||
|
ao.type = p_type;
|
||||||
ao.script = p_script;
|
ao.script = p_script;
|
||||||
ao.return_type = p_return_icon_type;
|
ao.return_type = p_return_icon_type;
|
||||||
ao.description = p_description;
|
ao.description = p_description;
|
||||||
ao.category = p_category;
|
ao.category = p_category;
|
||||||
ao.highend = p_highend;
|
ao.highend = p_highend;
|
||||||
ao.is_custom = true;
|
ao.is_custom = true;
|
||||||
|
ao.is_native = !p_type.is_empty();
|
||||||
|
|
||||||
bool begin = false;
|
bool begin = false;
|
||||||
String root = p_category.split("/")[0];
|
String root = p_category.split("/")[0];
|
||||||
|
@ -1253,50 +1261,23 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script>
|
||||||
Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) {
|
Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) {
|
||||||
Dictionary dict;
|
Dictionary dict;
|
||||||
dict["script"] = p_custom_node->get_script();
|
dict["script"] = p_custom_node->get_script();
|
||||||
|
dict["name"] = p_custom_node->_get_name();
|
||||||
|
dict["description"] = p_custom_node->_get_description();
|
||||||
|
dict["return_icon_type"] = p_custom_node->_get_return_icon_type();
|
||||||
|
dict["highend"] = p_custom_node->_is_highend();
|
||||||
|
|
||||||
String name;
|
String category = p_custom_node->_get_category();
|
||||||
if (p_custom_node->has_method("_get_name")) {
|
|
||||||
name = (String)p_custom_node->call("_get_name");
|
|
||||||
} else {
|
|
||||||
name = "Unnamed";
|
|
||||||
}
|
|
||||||
dict["name"] = name;
|
|
||||||
|
|
||||||
String description = "";
|
|
||||||
if (p_custom_node->has_method("_get_description")) {
|
|
||||||
description = (String)p_custom_node->call("_get_description");
|
|
||||||
}
|
|
||||||
dict["description"] = description;
|
|
||||||
|
|
||||||
int return_icon_type = -1;
|
|
||||||
if (p_custom_node->has_method("_get_return_icon_type")) {
|
|
||||||
return_icon_type = (int)p_custom_node->call("_get_return_icon_type");
|
|
||||||
}
|
|
||||||
dict["return_icon_type"] = return_icon_type;
|
|
||||||
|
|
||||||
String category = "";
|
|
||||||
if (p_custom_node->has_method("_get_category")) {
|
|
||||||
category = (String)p_custom_node->call("_get_category");
|
|
||||||
}
|
|
||||||
category = category.rstrip("/");
|
category = category.rstrip("/");
|
||||||
category = category.lstrip("/");
|
category = category.lstrip("/");
|
||||||
category = "Addons/" + category;
|
category = "Addons/" + category;
|
||||||
|
|
||||||
String subcategory = "";
|
|
||||||
if (p_custom_node->has_method("_get_subcategory")) {
|
if (p_custom_node->has_method("_get_subcategory")) {
|
||||||
subcategory = (String)p_custom_node->call("_get_subcategory");
|
String subcategory = (String)p_custom_node->call("_get_subcategory");
|
||||||
}
|
if (!subcategory.is_empty()) {
|
||||||
if (!subcategory.is_empty()) {
|
category += "/" + subcategory;
|
||||||
category += "/" + subcategory;
|
}
|
||||||
}
|
}
|
||||||
dict["category"] = category;
|
dict["category"] = category;
|
||||||
|
|
||||||
bool highend = false;
|
|
||||||
if (p_custom_node->has_method("_is_highend")) {
|
|
||||||
highend = (bool)p_custom_node->call("_is_highend");
|
|
||||||
}
|
|
||||||
dict["highend"] = highend;
|
|
||||||
|
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1333,7 +1314,7 @@ void VisualShaderEditor::_script_created(const Ref<Script> &p_script) {
|
||||||
ref->set_script(p_script);
|
ref->set_script(p_script);
|
||||||
|
|
||||||
Dictionary dict = get_custom_node_data(ref);
|
Dictionary dict = get_custom_node_data(ref);
|
||||||
add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
|
add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
|
||||||
|
|
||||||
_update_options_menu();
|
_update_options_menu();
|
||||||
}
|
}
|
||||||
|
@ -1456,7 +1437,7 @@ void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_type) {
|
if (!found_type) {
|
||||||
add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
|
add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// To prevent updating options multiple times when multiple scripts are saved.
|
// To prevent updating options multiple times when multiple scripts are saved.
|
||||||
|
@ -1595,29 +1576,60 @@ bool VisualShaderEditor::_is_available(int p_mode) {
|
||||||
|
|
||||||
void VisualShaderEditor::_update_nodes() {
|
void VisualShaderEditor::_update_nodes() {
|
||||||
clear_custom_types();
|
clear_custom_types();
|
||||||
List<StringName> class_list;
|
|
||||||
ScriptServer::get_global_class_list(&class_list);
|
|
||||||
Dictionary added;
|
Dictionary added;
|
||||||
for (int i = 0; i < class_list.size(); i++) {
|
|
||||||
if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") {
|
|
||||||
String script_path = ScriptServer::get_global_class_path(class_list[i]);
|
|
||||||
Ref<Resource> res = ResourceLoader::load(script_path);
|
|
||||||
ERR_FAIL_COND(res.is_null());
|
|
||||||
ERR_FAIL_COND(!res->is_class("Script"));
|
|
||||||
Ref<Script> scr = Ref<Script>(res);
|
|
||||||
|
|
||||||
Ref<VisualShaderNodeCustom> ref;
|
// Add GDScript classes.
|
||||||
ref.instantiate();
|
{
|
||||||
ref->set_script(scr);
|
List<StringName> class_list;
|
||||||
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
|
ScriptServer::get_global_class_list(&class_list);
|
||||||
continue;
|
|
||||||
|
for (int i = 0; i < class_list.size(); i++) {
|
||||||
|
if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") {
|
||||||
|
String script_path = ScriptServer::get_global_class_path(class_list[i]);
|
||||||
|
Ref<Resource> res = ResourceLoader::load(script_path);
|
||||||
|
ERR_CONTINUE(res.is_null());
|
||||||
|
ERR_CONTINUE(!res->is_class("Script"));
|
||||||
|
Ref<Script> scr = Ref<Script>(res);
|
||||||
|
|
||||||
|
Ref<VisualShaderNodeCustom> ref;
|
||||||
|
ref.instantiate();
|
||||||
|
ref->set_script(scr);
|
||||||
|
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Dictionary dict = get_custom_node_data(ref);
|
||||||
|
dict["type"] = String();
|
||||||
|
|
||||||
|
String key;
|
||||||
|
key = String(dict["category"]) + "/" + String(dict["name"]);
|
||||||
|
|
||||||
|
added[key] = dict;
|
||||||
}
|
}
|
||||||
Dictionary dict = get_custom_node_data(ref);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String key;
|
// Add GDExtension classes.
|
||||||
key = String(dict["category"]) + "/" + String(dict["name"]);
|
{
|
||||||
|
List<StringName> class_list;
|
||||||
|
ClassDB::get_class_list(&class_list);
|
||||||
|
|
||||||
added[key] = dict;
|
for (int i = 0; i < class_list.size(); i++) {
|
||||||
|
if (ClassDB::get_parent_class(class_list[i]) == "VisualShaderNodeCustom") {
|
||||||
|
Object *instance = ClassDB::instantiate(class_list[i]);
|
||||||
|
Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance);
|
||||||
|
ERR_CONTINUE(ref.is_null());
|
||||||
|
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Dictionary dict = get_custom_node_data(ref);
|
||||||
|
dict["type"] = class_list[i];
|
||||||
|
dict["script"] = Ref<Script>();
|
||||||
|
|
||||||
|
String key;
|
||||||
|
key = String(dict["category"]) + "/" + String(dict["name"]);
|
||||||
|
|
||||||
|
added[key] = dict;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1655,7 +1667,7 @@ void VisualShaderEditor::_update_nodes() {
|
||||||
|
|
||||||
const Dictionary &value = (Dictionary)added[key];
|
const Dictionary &value = (Dictionary)added[key];
|
||||||
|
|
||||||
add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);
|
add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_update_options_menu();
|
_update_options_menu();
|
||||||
|
@ -3062,12 +3074,21 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
|
||||||
|
|
||||||
vsnode = Ref<VisualShaderNode>(vsn);
|
vsnode = Ref<VisualShaderNode>(vsn);
|
||||||
} else {
|
} else {
|
||||||
ERR_FAIL_COND(add_options[p_idx].script.is_null());
|
StringName base_type;
|
||||||
StringName base_type = add_options[p_idx].script->get_instance_base_type();
|
bool is_native = add_options[p_idx].is_native;
|
||||||
|
|
||||||
|
if (is_native) {
|
||||||
|
base_type = add_options[p_idx].type;
|
||||||
|
} else {
|
||||||
|
ERR_FAIL_COND(add_options[p_idx].script.is_null());
|
||||||
|
base_type = add_options[p_idx].script->get_instance_base_type();
|
||||||
|
}
|
||||||
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
|
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
|
||||||
ERR_FAIL_COND(!vsn);
|
ERR_FAIL_COND(!vsn);
|
||||||
vsnode = Ref<VisualShaderNode>(vsn);
|
vsnode = Ref<VisualShaderNode>(vsn);
|
||||||
vsnode->set_script(add_options[p_idx].script);
|
if (!is_native) {
|
||||||
|
vsnode->set_script(add_options[p_idx].script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);
|
bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr);
|
||||||
|
|
|
@ -310,6 +310,7 @@ class VisualShaderEditor : public VBoxContainer {
|
||||||
int func = 0;
|
int func = 0;
|
||||||
bool highend = false;
|
bool highend = false;
|
||||||
bool is_custom = false;
|
bool is_custom = false;
|
||||||
|
bool is_native = false;
|
||||||
int temp_idx = 0;
|
int temp_idx = 0;
|
||||||
|
|
||||||
AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_type = String(), const String &p_description = String(), const Vector<Variant> &p_ops = Vector<Variant>(), int p_return_type = -1, int p_mode = -1, int p_func = -1, bool p_highend = false) {
|
AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_type = String(), const String &p_description = String(), const Vector<Variant> &p_ops = Vector<Variant>(), int p_return_type = -1, int p_mode = -1, int p_func = -1, bool p_highend = false) {
|
||||||
|
@ -527,9 +528,10 @@ public:
|
||||||
VisualShaderGraphPlugin *get_graph_plugin() { return graph_plugin.ptr(); }
|
VisualShaderGraphPlugin *get_graph_plugin() { return graph_plugin.ptr(); }
|
||||||
|
|
||||||
void clear_custom_types();
|
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, bool p_highend);
|
void add_custom_type(const String &p_name, const String &p_type, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend);
|
||||||
|
|
||||||
Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node);
|
Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node);
|
||||||
|
void update_custom_type(const Ref<Resource> &p_resource);
|
||||||
|
|
||||||
virtual Size2 get_minimum_size() const override;
|
virtual Size2 get_minimum_size() const override;
|
||||||
void edit(VisualShader *p_visual_shader);
|
void edit(VisualShader *p_visual_shader);
|
||||||
|
|
|
@ -611,6 +611,36 @@ void VisualShaderNodeCustom::_set_initialized(bool p_enabled) {
|
||||||
is_initialized = p_enabled;
|
is_initialized = p_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::_get_name() const {
|
||||||
|
String ret;
|
||||||
|
GDVIRTUAL_CALL(_get_name, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::_get_description() const {
|
||||||
|
String ret;
|
||||||
|
GDVIRTUAL_CALL(_get_description, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::_get_category() const {
|
||||||
|
String ret;
|
||||||
|
GDVIRTUAL_CALL(_get_category, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::_get_return_icon_type() const {
|
||||||
|
PortType ret = PORT_TYPE_SCALAR;
|
||||||
|
GDVIRTUAL_CALL(_get_return_icon_type, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VisualShaderNodeCustom::_is_highend() const {
|
||||||
|
bool ret = false;
|
||||||
|
GDVIRTUAL_CALL(_is_highend, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void VisualShaderNodeCustom::_bind_methods() {
|
void VisualShaderNodeCustom::_bind_methods() {
|
||||||
GDVIRTUAL_BIND(_get_name);
|
GDVIRTUAL_BIND(_get_name);
|
||||||
GDVIRTUAL_BIND(_get_description);
|
GDVIRTUAL_BIND(_get_description);
|
||||||
|
|
|
@ -411,6 +411,12 @@ public:
|
||||||
|
|
||||||
bool _is_initialized();
|
bool _is_initialized();
|
||||||
void _set_initialized(bool p_enabled);
|
void _set_initialized(bool p_enabled);
|
||||||
|
|
||||||
|
String _get_name() const;
|
||||||
|
String _get_description() const;
|
||||||
|
String _get_category() const;
|
||||||
|
PortType _get_return_icon_type() const;
|
||||||
|
bool _is_highend() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
Loading…
Add table
Reference in a new issue