Plugin support for visual shaders
This commit is contained in:
parent
1dae4c9e7f
commit
33e9fce1bb
|
@ -39,5 +39,20 @@
|
||||||
</signal>
|
</signal>
|
||||||
</signals>
|
</signals>
|
||||||
<constants>
|
<constants>
|
||||||
|
<constant name="PORT_TYPE_SCALAR" value="0" enum="PortType">
|
||||||
|
Floating-point scalar. Translated to [code]float[/code] type in shader code.
|
||||||
|
</constant>
|
||||||
|
<constant name="PORT_TYPE_VECTOR" value="1" enum="PortType">
|
||||||
|
3D vector of floating-point values. Translated to [code]vec3[/code] type in shader code.
|
||||||
|
</constant>
|
||||||
|
<constant name="PORT_TYPE_BOOLEAN" value="2" enum="PortType">
|
||||||
|
Boolean type. Translated to [code]bool[/code] type in shader code.
|
||||||
|
</constant>
|
||||||
|
<constant name="PORT_TYPE_TRANSFORM" value="3" enum="PortType">
|
||||||
|
Transform type. Translated to [code]mat4[/code] type in shader code.
|
||||||
|
</constant>
|
||||||
|
<constant name="PORT_TYPE_ICON_COLOR" value="4" enum="PortType">
|
||||||
|
Color type. Can be used for return icon type in members dialog (see [method VisualShaderNodeCustom._get_return_icon_type]) - do not use it in other cases!
|
||||||
|
</constant>
|
||||||
</constants>
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<class name="VisualShaderNodeCustom" inherits="VisualShaderNode" category="Core" version="3.2">
|
||||||
|
<brief_description>
|
||||||
|
Virtual class to define custom [VisualShaderNode]s for use in the Visual Shader Editor.
|
||||||
|
</brief_description>
|
||||||
|
<description>
|
||||||
|
By inheriting this class you can create a custom [VisualShader] script addon which will be automatically added to the Visual Shader Editor. The [VisualShaderNode]'s behavior is defined by overriding the provided virtual methods.
|
||||||
|
In order for the node to be registered as an editor addon, you must use the [code]tool[/code] keyword and provide a [code]class_name[/code] for your custom script. For example:
|
||||||
|
[codeblock]
|
||||||
|
tool
|
||||||
|
extends VisualShaderNodeCustom
|
||||||
|
class_name VisualShaderNodeNoise
|
||||||
|
[/codeblock]
|
||||||
|
</description>
|
||||||
|
<tutorials>
|
||||||
|
</tutorials>
|
||||||
|
<methods>
|
||||||
|
<method name="_get_category" qualifiers="virtual">
|
||||||
|
<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.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_description" qualifiers="virtual">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
Override this method to define the description of the associated custom node in the Visual Shader Editor's members dialog.
|
||||||
|
Defining this method is [b]optional[/b].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_code" qualifiers="virtual">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="input_vars" type="Array">
|
||||||
|
</argument>
|
||||||
|
<argument index="1" name="output_vars" type="Array">
|
||||||
|
</argument>
|
||||||
|
<argument index="2" name="mode" type="int" enum="Shader.Mode">
|
||||||
|
</argument>
|
||||||
|
<argument index="3" name="type" type="int" enum="VisualShader.Type">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Override this method to define the actual shader code of the associated custom node. The shader code should be returned as a string, which can have multiple lines (the [code]"""[/code] multiline string construct can be used for convenience).
|
||||||
|
The [code]input_vars[/code] and [code]output_vars[/code] arrays contain the string names of the various input and output variables, as defined by [code]_get_input_*[/code] and [code]_get_output_*[/code] virtual methods in this class.
|
||||||
|
The output ports can be assigned values in the shader code. For example, [code]return output_vars[0] + " = " + input_vars[0] + ";"[/code].
|
||||||
|
You can customize the generated code based on the shader [code]mode[/code] (see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader.Type]).
|
||||||
|
Defining this method is [b]required[/b].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_global_code" qualifiers="virtual">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="mode" type="int" enum="Shader.Mode">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Override this method to add shader code on top of the global shader, to define your own standard library of reusable methods, varyings, constants, uniforms, etc. The shader code should be returned as a string, which can have multiple lines (the [code]"""[/code] multiline string construct can be used for convenience).
|
||||||
|
Be careful with this functionality as it can cause name conflicts with other custom nodes, so be sure to give the defined entities unique names.
|
||||||
|
You can customize the generated code based on the shader [code]mode[/code] (see [enum Shader.Mode]).
|
||||||
|
Defining this method is [b]optional[/b].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_input_port_count" qualifiers="virtual">
|
||||||
|
<return type="int">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
Override this method to define the amount of input ports of the associated custom node.
|
||||||
|
Defining this method is [b]required[/b]. If not overridden, the node has no input ports.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_input_port_name" qualifiers="virtual">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="port" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Override this method to define the names of input ports of the associated custom node. The names are used both for the input slots in the editor and as identifiers in the shader code, and are passed in the [code]input_vars[/code] array in [method _get_code].
|
||||||
|
Defining this method is [b]optional[/b], but recommended. If not overridden, input ports are named as [code]"in" + str(port)[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_input_port_type" qualifiers="virtual">
|
||||||
|
<return type="int" enum="VisualShaderNode.PortType">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="port" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Override this method to define the returned type of each input port of the associated custom node (see [enum VisualShaderNode.PortType] for possible types).
|
||||||
|
Defining this method is [b]optional[/b], but recommended. If not overridden, input ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] type.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_name" qualifiers="virtual">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
Override this method to define the name of the associated custom node in the Visual Shader Editor's members dialog and graph.
|
||||||
|
Defining this method is [b]optional[/b], but recommended. If not overridden, the node will be named as "Unnamed".
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_output_port_count" qualifiers="virtual">
|
||||||
|
<return type="int">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
Override this method to define the amount of output ports of the associated custom node.
|
||||||
|
Defining this method is [b]required[/b]. If not overridden, the node has no output ports.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_output_port_name" qualifiers="virtual">
|
||||||
|
<return type="String">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="port" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Override this method to define the names of output ports of the associated custom node. The names are used both for the output slots in the editor and as identifiers in the shader code, and are passed in the [code]output_vars[/code] array in [method _get_code].
|
||||||
|
Defining this method is [b]optional[/b], but recommended. If not overridden, output ports are named as [code]"out" + str(port)[/code].
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_output_port_type" qualifiers="virtual">
|
||||||
|
<return type="int" enum="VisualShaderNode.PortType">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="port" type="int">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Override this method to define the returned type of each output port of the associated custom node (see [enum VisualShaderNode.PortType] for possible types).
|
||||||
|
Defining this method is [b]optional[/b], but recommended. If not overridden, output ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] type.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_get_return_icon_type" qualifiers="virtual">
|
||||||
|
<return type="int" enum="VisualShaderNode.PortType">
|
||||||
|
</return>
|
||||||
|
<description>
|
||||||
|
Override this method to define the return icon of the associated custom node in the Visual Shader Editor's members dialog.
|
||||||
|
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>
|
||||||
|
</methods>
|
||||||
|
<constants>
|
||||||
|
</constants>
|
||||||
|
</class>
|
|
@ -79,6 +79,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) {
|
||||||
} else {
|
} else {
|
||||||
if (changed) { // to avoid tree collapse
|
if (changed) { // to avoid tree collapse
|
||||||
_clear_buffer();
|
_clear_buffer();
|
||||||
|
_update_custom_nodes();
|
||||||
_update_options_menu();
|
_update_options_menu();
|
||||||
}
|
}
|
||||||
_update_graph();
|
_update_graph();
|
||||||
|
@ -95,31 +96,36 @@ void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plug
|
||||||
plugins.erase(p_plugin);
|
plugins.erase(p_plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualShaderEditor::add_custom_type(const String &p_name, const String &p_category, const Ref<Script> &p_script) {
|
void VisualShaderEditor::clear_custom_types() {
|
||||||
|
for (int i = 0; i < add_options.size(); i++) {
|
||||||
|
if (add_options[i].is_custom) {
|
||||||
|
add_options.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_sub_category) {
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!p_name.is_valid_identifier());
|
||||||
|
ERR_FAIL_COND(!p_script.is_valid());
|
||||||
|
|
||||||
for (int i = 0; i < add_options.size(); i++) {
|
for (int i = 0; i < add_options.size(); i++) {
|
||||||
ERR_FAIL_COND(add_options[i].script == p_script);
|
if (add_options[i].is_custom) {
|
||||||
|
if (add_options[i].script == p_script)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddOption ao;
|
AddOption ao;
|
||||||
ao.name = p_name;
|
ao.name = p_name;
|
||||||
ao.script = p_script;
|
ao.script = p_script;
|
||||||
|
ao.return_type = p_return_icon_type;
|
||||||
|
ao.description = p_description;
|
||||||
ao.category = p_category;
|
ao.category = p_category;
|
||||||
|
ao.sub_category = p_sub_category;
|
||||||
|
ao.is_custom = true;
|
||||||
|
|
||||||
add_options.push_back(ao);
|
add_options.push_back(ao);
|
||||||
|
|
||||||
_update_options_menu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisualShaderEditor::remove_custom_type(const Ref<Script> &p_script) {
|
|
||||||
|
|
||||||
for (int i = 0; i < add_options.size(); i++) {
|
|
||||||
if (add_options[i].script == p_script) {
|
|
||||||
add_options.remove(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_update_options_menu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VisualShaderEditor::_is_available(int p_mode) {
|
bool VisualShaderEditor::_is_available(int p_mode) {
|
||||||
|
@ -162,6 +168,58 @@ bool VisualShaderEditor::_is_available(int p_mode) {
|
||||||
return (p_mode == -1 || (p_mode & current_mode) != 0);
|
return (p_mode == -1 || (p_mode & current_mode) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VisualShaderEditor::_update_custom_nodes() {
|
||||||
|
clear_custom_types();
|
||||||
|
List<StringName> class_list;
|
||||||
|
ScriptServer::get_global_class_list(&class_list);
|
||||||
|
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> script = Ref<Script>(res);
|
||||||
|
|
||||||
|
Ref<VisualShaderNodeCustom> ref;
|
||||||
|
ref.instance();
|
||||||
|
ref->set_script(script.get_ref_ptr());
|
||||||
|
|
||||||
|
String name;
|
||||||
|
if (ref->has_method("_get_name")) {
|
||||||
|
name = (String)ref->call("_get_name");
|
||||||
|
} else {
|
||||||
|
name = "Unnamed";
|
||||||
|
}
|
||||||
|
|
||||||
|
String description = "";
|
||||||
|
if (ref->has_method("_get_description")) {
|
||||||
|
description = (String)ref->call("_get_description");
|
||||||
|
}
|
||||||
|
|
||||||
|
int return_icon_type = -1;
|
||||||
|
if (ref->has_method("_get_return_icon_type")) {
|
||||||
|
return_icon_type = (int)ref->call("_get_return_icon_type");
|
||||||
|
}
|
||||||
|
|
||||||
|
String category = "";
|
||||||
|
if (ref->has_method("_get_category")) {
|
||||||
|
category = (String)ref->call("_get_category");
|
||||||
|
}
|
||||||
|
if (category == "") {
|
||||||
|
category = "Custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
String sub_category = "";
|
||||||
|
if (ref->has_method("_get_subcategory")) {
|
||||||
|
sub_category = (String)ref->call("_get_subcategory");
|
||||||
|
}
|
||||||
|
|
||||||
|
add_custom_type(name, script, description, return_icon_type, category, sub_category);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VisualShaderEditor::_update_options_menu() {
|
void VisualShaderEditor::_update_options_menu() {
|
||||||
|
|
||||||
node_desc->set_text("");
|
node_desc->set_text("");
|
||||||
|
@ -284,7 +342,7 @@ void VisualShaderEditor::_update_options_menu() {
|
||||||
case VisualShaderNode::PORT_TYPE_TRANSFORM:
|
case VisualShaderNode::PORT_TYPE_TRANSFORM:
|
||||||
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
|
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons"));
|
||||||
break;
|
break;
|
||||||
case VisualShaderNode::PORT_TYPE_COLOR:
|
case VisualShaderNode::PORT_TYPE_ICON_COLOR:
|
||||||
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons"));
|
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -942,8 +1000,10 @@ void VisualShaderEditor::_expression_focus_out(Object *text_edit, int p_node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualShaderEditor::_rebuild() {
|
void VisualShaderEditor::_rebuild() {
|
||||||
EditorNode::get_singleton()->get_log()->clear();
|
if (visual_shader != NULL) {
|
||||||
visual_shader->rebuild();
|
EditorNode::get_singleton()->get_log()->clear();
|
||||||
|
visual_shader->rebuild();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) {
|
void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) {
|
||||||
|
@ -1139,7 +1199,9 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
|
||||||
|
|
||||||
Ref<VisualShaderNode> vsnode;
|
Ref<VisualShaderNode> vsnode;
|
||||||
|
|
||||||
if (add_options[p_idx].type != String()) {
|
bool is_custom = add_options[p_idx].is_custom;
|
||||||
|
|
||||||
|
if (!is_custom && add_options[p_idx].type != String()) {
|
||||||
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type));
|
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type));
|
||||||
ERR_FAIL_COND(!vsn);
|
ERR_FAIL_COND(!vsn);
|
||||||
|
|
||||||
|
@ -2164,8 +2226,8 @@ VisualShaderEditor::VisualShaderEditor() {
|
||||||
add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR));
|
add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR));
|
||||||
add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), VisualShaderNodeColorOp::OP_SOFT_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
|
add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), VisualShaderNodeColorOp::OP_SOFT_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR));
|
||||||
|
|
||||||
add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, VisualShaderNode::PORT_TYPE_COLOR));
|
add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR));
|
||||||
add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
|
add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR));
|
||||||
|
|
||||||
// CONDITIONAL
|
// CONDITIONAL
|
||||||
|
|
||||||
|
@ -2368,12 +2430,12 @@ VisualShaderEditor::VisualShaderEditor() {
|
||||||
|
|
||||||
// TEXTURES
|
// TEXTURES
|
||||||
|
|
||||||
add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
|
add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR));
|
||||||
add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
|
add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR));
|
||||||
|
|
||||||
add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
|
add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR));
|
||||||
add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
|
add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR));
|
||||||
add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, VisualShaderNode::PORT_TYPE_COLOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
|
add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
|
||||||
|
|
||||||
// TRANSFORM
|
// TRANSFORM
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,7 @@ class VisualShaderEditor : public VBoxContainer {
|
||||||
int func;
|
int func;
|
||||||
float value;
|
float value;
|
||||||
bool highend;
|
bool highend;
|
||||||
|
bool is_custom;
|
||||||
|
|
||||||
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) {
|
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;
|
name = p_name;
|
||||||
|
@ -117,6 +118,7 @@ class VisualShaderEditor : public VBoxContainer {
|
||||||
func = p_func;
|
func = p_func;
|
||||||
value = p_value;
|
value = p_value;
|
||||||
highend = p_highend;
|
highend = p_highend;
|
||||||
|
is_custom = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
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) {
|
||||||
|
@ -131,6 +133,7 @@ class VisualShaderEditor : public VBoxContainer {
|
||||||
func = p_func;
|
func = p_func;
|
||||||
value = p_value;
|
value = p_value;
|
||||||
highend = p_highend;
|
highend = p_highend;
|
||||||
|
is_custom = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,6 +143,7 @@ class VisualShaderEditor : public VBoxContainer {
|
||||||
void _draw_color_over_button(Object *obj, Color p_color);
|
void _draw_color_over_button(Object *obj, Color p_color);
|
||||||
|
|
||||||
void _add_node(int p_idx, int p_op_idx = -1);
|
void _add_node(int p_idx, int p_op_idx = -1);
|
||||||
|
void _update_custom_nodes();
|
||||||
void _update_options_menu();
|
void _update_options_menu();
|
||||||
|
|
||||||
static VisualShaderEditor *singleton;
|
static VisualShaderEditor *singleton;
|
||||||
|
@ -240,8 +244,8 @@ public:
|
||||||
|
|
||||||
static VisualShaderEditor *get_singleton() { return singleton; }
|
static VisualShaderEditor *get_singleton() { return singleton; }
|
||||||
|
|
||||||
void add_custom_type(const String &p_name, const String &p_category, const Ref<Script> &p_script);
|
void clear_custom_types();
|
||||||
void remove_custom_type(const Ref<Script> &p_script);
|
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_sub_category);
|
||||||
|
|
||||||
virtual Size2 get_minimum_size() const;
|
virtual Size2 get_minimum_size() const;
|
||||||
void edit(VisualShader *p_visual_shader);
|
void edit(VisualShader *p_visual_shader);
|
||||||
|
|
|
@ -2530,7 +2530,7 @@ String VisualScriptCustomNode::get_category() const {
|
||||||
if (get_script_instance() && get_script_instance()->has_method("_get_category")) {
|
if (get_script_instance() && get_script_instance()->has_method("_get_category")) {
|
||||||
return get_script_instance()->call("_get_category");
|
return get_script_instance()->call("_get_category");
|
||||||
}
|
}
|
||||||
return "custom";
|
return "Custom";
|
||||||
}
|
}
|
||||||
|
|
||||||
class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
|
class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
|
||||||
|
|
|
@ -475,6 +475,7 @@ void register_scene_types() {
|
||||||
ClassDB::register_class<Shader>();
|
ClassDB::register_class<Shader>();
|
||||||
ClassDB::register_class<VisualShader>();
|
ClassDB::register_class<VisualShader>();
|
||||||
ClassDB::register_virtual_class<VisualShaderNode>();
|
ClassDB::register_virtual_class<VisualShaderNode>();
|
||||||
|
ClassDB::register_class<VisualShaderNodeCustom>();
|
||||||
ClassDB::register_class<VisualShaderNodeInput>();
|
ClassDB::register_class<VisualShaderNodeInput>();
|
||||||
ClassDB::register_virtual_class<VisualShaderNodeOutput>();
|
ClassDB::register_virtual_class<VisualShaderNodeOutput>();
|
||||||
ClassDB::register_class<VisualShaderNodeGroupBase>();
|
ClassDB::register_class<VisualShaderNodeGroupBase>();
|
||||||
|
|
|
@ -117,6 +117,12 @@ void VisualShaderNode::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values");
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_default_input_values", "_get_default_input_values");
|
||||||
ADD_SIGNAL(MethodInfo("editor_refresh_request"));
|
ADD_SIGNAL(MethodInfo("editor_refresh_request"));
|
||||||
|
|
||||||
|
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR);
|
||||||
|
BIND_ENUM_CONSTANT(PORT_TYPE_VECTOR);
|
||||||
|
BIND_ENUM_CONSTANT(PORT_TYPE_BOOLEAN);
|
||||||
|
BIND_ENUM_CONSTANT(PORT_TYPE_TRANSFORM);
|
||||||
|
BIND_ENUM_CONSTANT(PORT_TYPE_ICON_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
VisualShaderNode::VisualShaderNode() {
|
VisualShaderNode::VisualShaderNode() {
|
||||||
|
@ -125,6 +131,147 @@ VisualShaderNode::VisualShaderNode() {
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void VisualShaderNodeCustom::update_ports() {
|
||||||
|
ERR_FAIL_COND(!get_script_instance());
|
||||||
|
|
||||||
|
input_ports.clear();
|
||||||
|
if (get_script_instance()->has_method("_get_input_port_count")) {
|
||||||
|
int input_port_count = (int)get_script_instance()->call("_get_input_port_count");
|
||||||
|
bool has_name = get_script_instance()->has_method("_get_input_port_name");
|
||||||
|
bool has_type = get_script_instance()->has_method("_get_input_port_type");
|
||||||
|
for (int i = 0; i < input_port_count; i++) {
|
||||||
|
Port port;
|
||||||
|
if (has_name) {
|
||||||
|
port.name = (String)get_script_instance()->call("_get_input_port_name", i);
|
||||||
|
} else {
|
||||||
|
port.name = "in" + itos(i);
|
||||||
|
}
|
||||||
|
if (has_type) {
|
||||||
|
port.type = (int)get_script_instance()->call("_get_input_port_type", i);
|
||||||
|
} else {
|
||||||
|
port.type = (int)PortType::PORT_TYPE_SCALAR;
|
||||||
|
}
|
||||||
|
input_ports.push_back(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output_ports.clear();
|
||||||
|
if (get_script_instance()->has_method("_get_output_port_count")) {
|
||||||
|
int output_port_count = (int)get_script_instance()->call("_get_output_port_count");
|
||||||
|
bool has_name = get_script_instance()->has_method("_get_output_port_name");
|
||||||
|
bool has_type = get_script_instance()->has_method("_get_output_port_type");
|
||||||
|
for (int i = 0; i < output_port_count; i++) {
|
||||||
|
Port port;
|
||||||
|
if (has_name) {
|
||||||
|
port.name = (String)get_script_instance()->call("_get_output_port_name", i);
|
||||||
|
} else {
|
||||||
|
port.name = "out" + itos(i);
|
||||||
|
}
|
||||||
|
if (has_type) {
|
||||||
|
port.type = (int)get_script_instance()->call("_get_output_port_type", i);
|
||||||
|
} else {
|
||||||
|
port.type = (int)PortType::PORT_TYPE_SCALAR;
|
||||||
|
}
|
||||||
|
output_ports.push_back(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::get_caption() const {
|
||||||
|
ERR_FAIL_COND_V(!get_script_instance(), "");
|
||||||
|
if (get_script_instance()->has_method("_get_name")) {
|
||||||
|
return (String)get_script_instance()->call("_get_name");
|
||||||
|
}
|
||||||
|
return "Unnamed";
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisualShaderNodeCustom::get_input_port_count() const {
|
||||||
|
return input_ports.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_input_port_type(int p_port) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_port, input_ports.size(), PORT_TYPE_SCALAR);
|
||||||
|
return (PortType)input_ports[p_port].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::get_input_port_name(int p_port) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_port, input_ports.size(), "");
|
||||||
|
return input_ports[p_port].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisualShaderNodeCustom::get_output_port_count() const {
|
||||||
|
return output_ports.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualShaderNodeCustom::PortType VisualShaderNodeCustom::get_output_port_type(int p_port) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_port, output_ports.size(), PORT_TYPE_SCALAR);
|
||||||
|
return (PortType)output_ports[p_port].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::get_output_port_name(int p_port) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_port, output_ports.size(), "");
|
||||||
|
return output_ports[p_port].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(!get_script_instance(), "");
|
||||||
|
ERR_FAIL_COND_V(!get_script_instance()->has_method("_get_code"), "");
|
||||||
|
Array input_vars;
|
||||||
|
for (int i = 0; i < get_input_port_count(); i++) {
|
||||||
|
input_vars.push_back(p_input_vars[i]);
|
||||||
|
}
|
||||||
|
Array output_vars;
|
||||||
|
for (int i = 0; i < get_output_port_count(); i++) {
|
||||||
|
output_vars.push_back(p_output_vars[i]);
|
||||||
|
}
|
||||||
|
String code = "\t{\n";
|
||||||
|
String _code = (String)get_script_instance()->call("_get_code", input_vars, output_vars, (int)p_mode, (int)p_type);
|
||||||
|
bool nend = _code.ends_with("\n");
|
||||||
|
_code = _code.insert(0, "\t\t");
|
||||||
|
_code = _code.replace("\n", "\n\t\t");
|
||||||
|
code += _code;
|
||||||
|
if (!nend) {
|
||||||
|
code += "\n\t}";
|
||||||
|
} else {
|
||||||
|
code.remove(code.size() - 1);
|
||||||
|
code += "}";
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
|
||||||
|
ERR_FAIL_COND_V(!get_script_instance(), "");
|
||||||
|
if (get_script_instance()->has_method("_get_global_code")) {
|
||||||
|
String code = "// " + get_caption() + "\n";
|
||||||
|
code += (String)get_script_instance()->call("_get_global_code", (int)p_mode);
|
||||||
|
code += "\n";
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
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")));
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_input_port_name", PropertyInfo(Variant::INT, "port")));
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_count"));
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_type", PropertyInfo(Variant::INT, "port")));
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_output_port_name", PropertyInfo(Variant::INT, "port")));
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_code", PropertyInfo(Variant::ARRAY, "input_vars"), PropertyInfo(Variant::ARRAY, "output_vars"), PropertyInfo(Variant::INT, "mode"), PropertyInfo(Variant::INT, "type")));
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_global_code", PropertyInfo(Variant::INT, "mode")));
|
||||||
|
}
|
||||||
|
|
||||||
|
VisualShaderNodeCustom::VisualShaderNodeCustom() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
|
void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id) {
|
||||||
ERR_FAIL_COND(p_node.is_null());
|
ERR_FAIL_COND(p_node.is_null());
|
||||||
ERR_FAIL_COND(p_id < 2);
|
ERR_FAIL_COND(p_id < 2);
|
||||||
|
@ -150,6 +297,11 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co
|
||||||
|
|
||||||
n.node->connect("changed", this, "_queue_update");
|
n.node->connect("changed", this, "_queue_update");
|
||||||
|
|
||||||
|
Ref<VisualShaderNodeCustom> custom = n.node;
|
||||||
|
if (custom.is_valid()) {
|
||||||
|
custom->update_ports();
|
||||||
|
}
|
||||||
|
|
||||||
g->nodes[p_id] = n;
|
g->nodes[p_id] = n;
|
||||||
|
|
||||||
_queue_update();
|
_queue_update();
|
||||||
|
@ -965,6 +1117,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
|
||||||
bool skip_global = input.is_valid() && for_preview;
|
bool skip_global = input.is_valid() && for_preview;
|
||||||
|
|
||||||
if (!skip_global) {
|
if (!skip_global) {
|
||||||
|
|
||||||
global_code += vsnode->generate_global(get_mode(), type, node);
|
global_code += vsnode->generate_global(get_mode(), type, node);
|
||||||
|
|
||||||
if (!r_classes.has(vsnode->get_class_name())) {
|
if (!r_classes.has(vsnode->get_class_name())) {
|
||||||
|
@ -976,7 +1129,6 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle normally
|
|
||||||
code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
|
code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
|
||||||
|
|
||||||
code += "\n"; //
|
code += "\n"; //
|
||||||
|
|
|
@ -183,7 +183,7 @@ public:
|
||||||
PORT_TYPE_VECTOR,
|
PORT_TYPE_VECTOR,
|
||||||
PORT_TYPE_BOOLEAN,
|
PORT_TYPE_BOOLEAN,
|
||||||
PORT_TYPE_TRANSFORM,
|
PORT_TYPE_TRANSFORM,
|
||||||
PORT_TYPE_COLOR // just a hint for node tree icons, do not use it as actual port type !
|
PORT_TYPE_ICON_COLOR // just a hint for node tree icons, do not use it as actual port type !
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual String get_caption() const = 0;
|
virtual String get_caption() const = 0;
|
||||||
|
@ -216,6 +216,44 @@ public:
|
||||||
|
|
||||||
VisualShaderNode();
|
VisualShaderNode();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(VisualShaderNode::PortType)
|
||||||
|
|
||||||
|
class VisualShaderNodeCustom : public VisualShaderNode {
|
||||||
|
GDCLASS(VisualShaderNodeCustom, VisualShaderNode);
|
||||||
|
|
||||||
|
struct Port {
|
||||||
|
String name;
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
List<Port> input_ports;
|
||||||
|
List<Port> output_ports;
|
||||||
|
|
||||||
|
friend class VisualShaderEditor;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual String get_caption() const;
|
||||||
|
|
||||||
|
virtual int get_input_port_count() const;
|
||||||
|
virtual PortType get_input_port_type(int p_port) const;
|
||||||
|
virtual String get_input_port_name(int p_port) const;
|
||||||
|
|
||||||
|
virtual int get_output_port_count() const;
|
||||||
|
virtual PortType get_output_port_type(int p_port) const;
|
||||||
|
virtual String get_output_port_name(int p_port) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const;
|
||||||
|
virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
|
||||||
|
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
VisualShaderNodeCustom();
|
||||||
|
void update_ports();
|
||||||
|
};
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
class VisualShaderNodeInput : public VisualShaderNode {
|
class VisualShaderNodeInput : public VisualShaderNode {
|
||||||
|
|
Loading…
Reference in New Issue