Add convert options between constants and uniforms in visual shaders

This commit is contained in:
Yuri Roubinsky 2020-12-30 11:45:31 +03:00
parent 59b30e1d23
commit c98c6eadbe
15 changed files with 341 additions and 19 deletions

View file

@ -169,6 +169,19 @@
Removes the specified node from the shader.
</description>
</method>
<method name="replace_node">
<return type="void">
</return>
<argument index="0" name="type" type="int" enum="VisualShader.Type">
</argument>
<argument index="1" name="id" type="int">
</argument>
<argument index="2" name="new_class" type="StringName">
</argument>
<description>
Replaces the specified node with a node of new class type.
</description>
</method>
<method name="set_mode">
<return type="void">
</return>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeBooleanConstant" inherits="VisualShaderNode" version="4.0">
<class name="VisualShaderNodeBooleanConstant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
A boolean constant to be used within the visual shader graph.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeColorConstant" inherits="VisualShaderNode" version="4.0">
<class name="VisualShaderNodeColorConstant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
A [Color] constant to be used within the visual shader graph.
</brief_description>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeConstant" inherits="VisualShaderNode" version="4.0">
<brief_description>
A base type for the constants within the visual shader graph.
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<constants>
</constants>
</class>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeFloatConstant" inherits="VisualShaderNode" version="4.0">
<class name="VisualShaderNodeFloatConstant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
A scalar floating-point constant to be used within the visual shader graph.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeIntConstant" inherits="VisualShaderNode" version="4.0">
<class name="VisualShaderNodeIntConstant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
A scalar integer constant to be used within the visual shader graph.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNode" version="4.0">
<class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
A [Transform] constant for use within the visual shader graph.
</brief_description>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeVec3Constant" inherits="VisualShaderNode" version="4.0">
<class name="VisualShaderNodeVec3Constant" inherits="VisualShaderNodeConstant" version="4.0">
<brief_description>
A [Vector3] constant to be used within the visual shader graph.
</brief_description>

View file

@ -2087,6 +2087,197 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
}
}
void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) {
undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to);
undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from);
}
void VisualShaderEditor::_update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
Ref<VisualShaderNode> node = visual_shader->get_node(p_type_id, p_node_id);
ERR_FAIL_COND(!node.is_valid());
ERR_FAIL_COND(!node->has_method("set_constant"));
node->call("set_constant", p_var);
if (p_preview_port != -1) {
node->set_output_port_for_preview(p_preview_port);
}
}
void VisualShaderEditor::_update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port) {
Ref<VisualShaderNodeUniform> uniform = visual_shader->get_node(p_type_id, p_node_id);
ERR_FAIL_COND(!uniform.is_valid());
String valid_name = visual_shader->validate_uniform_name(uniform->get_uniform_name(), uniform);
uniform->set_uniform_name(valid_name);
graph_plugin->set_uniform_name(p_type_id, p_node_id, valid_name);
if (uniform->has_method("set_default_value_enabled")) {
uniform->call("set_default_value_enabled", true);
uniform->call("set_default_value", p_var);
}
if (p_preview_port != -1) {
uniform->set_output_port_for_preview(p_preview_port);
}
}
void VisualShaderEditor::_convert_constants_to_uniforms(bool p_vice_versa) {
VisualShader::Type type_id = get_current_shader_type();
if (!p_vice_versa) {
undo_redo->create_action(TTR("Convert Constant Node(s) To Uniform(s)"));
} else {
undo_redo->create_action(TTR("Convert Uniform Node(s) To Constant(s)"));
}
const Set<int> &current_set = p_vice_versa ? selected_uniforms : selected_constants;
Set<String> deleted_names;
for (Set<int>::Element *E = current_set.front(); E; E = E->next()) {
int node_id = E->get();
Ref<VisualShaderNode> node = visual_shader->get_node(type_id, node_id);
bool catched = false;
Variant var;
// float
if (!p_vice_versa) {
Ref<VisualShaderNodeFloatConstant> float_const = Object::cast_to<VisualShaderNodeFloatConstant>(node.ptr());
if (float_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeFloatConstant", "VisualShaderNodeFloatUniform");
var = float_const->get_constant();
catched = true;
}
} else {
Ref<VisualShaderNodeFloatUniform> float_uniform = Object::cast_to<VisualShaderNodeFloatUniform>(node.ptr());
if (float_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeFloatUniform", "VisualShaderNodeFloatConstant");
var = float_uniform->get_default_value();
catched = true;
}
}
// int
if (!catched) {
if (!p_vice_versa) {
Ref<VisualShaderNodeIntConstant> int_const = Object::cast_to<VisualShaderNodeIntConstant>(node.ptr());
if (int_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeIntConstant", "VisualShaderNodeIntUniform");
var = int_const->get_constant();
catched = true;
}
} else {
Ref<VisualShaderNodeIntUniform> int_uniform = Object::cast_to<VisualShaderNodeIntUniform>(node.ptr());
if (int_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeIntUniform", "VisualShaderNodeIntConstant");
var = int_uniform->get_default_value();
catched = true;
}
}
}
// boolean
if (!catched) {
if (!p_vice_versa) {
Ref<VisualShaderNodeBooleanConstant> boolean_const = Object::cast_to<VisualShaderNodeBooleanConstant>(node.ptr());
if (boolean_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeBooleanConstant", "VisualShaderNodeBooleanUniform");
var = boolean_const->get_constant();
catched = true;
}
} else {
Ref<VisualShaderNodeBooleanUniform> boolean_uniform = Object::cast_to<VisualShaderNodeBooleanUniform>(node.ptr());
if (boolean_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanConstant");
var = boolean_uniform->get_default_value();
catched = true;
}
}
}
// vec3
if (!catched) {
if (!p_vice_versa) {
Ref<VisualShaderNodeVec3Constant> vec3_const = Object::cast_to<VisualShaderNodeVec3Constant>(node.ptr());
if (vec3_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeVec3Constant", "VisualShaderNodeVec3Uniform");
var = vec3_const->get_constant();
catched = true;
}
} else {
Ref<VisualShaderNodeVec3Uniform> vec3_uniform = Object::cast_to<VisualShaderNodeVec3Uniform>(node.ptr());
if (vec3_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Constant");
var = vec3_uniform->get_default_value();
catched = true;
}
}
}
// color
if (!catched) {
if (!p_vice_versa) {
Ref<VisualShaderNodeColorConstant> color_const = Object::cast_to<VisualShaderNodeColorConstant>(node.ptr());
if (color_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeColorConstant", "VisualShaderNodeColorUniform");
var = color_const->get_constant();
catched = true;
}
} else {
Ref<VisualShaderNodeColorUniform> color_uniform = Object::cast_to<VisualShaderNodeColorUniform>(node.ptr());
if (color_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeColorUniform", "VisualShaderNodeColorConstant");
var = color_uniform->get_default_value();
catched = true;
}
}
}
// transform
if (!catched) {
if (!p_vice_versa) {
Ref<VisualShaderNodeTransformConstant> transform_const = Object::cast_to<VisualShaderNodeTransformConstant>(node.ptr());
if (transform_const.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeTransformConstant", "VisualShaderNodeTransformUniform");
var = transform_const->get_constant();
catched = true;
}
} else {
Ref<VisualShaderNodeTransformUniform> transform_uniform = Object::cast_to<VisualShaderNodeTransformUniform>(node.ptr());
if (transform_uniform.is_valid()) {
_replace_node(type_id, node_id, "VisualShaderNodeTransformUniform", "VisualShaderNodeTransformConstant");
var = transform_uniform->get_default_value();
catched = true;
}
}
}
ERR_CONTINUE(!catched);
int preview_port = node->get_output_port_for_preview();
if (!p_vice_versa) {
undo_redo->add_do_method(this, "_update_uniform", type_id, node_id, var, preview_port);
undo_redo->add_undo_method(this, "_update_constant", type_id, node_id, var, preview_port);
} else {
undo_redo->add_do_method(this, "_update_constant", type_id, node_id, var, preview_port);
undo_redo->add_undo_method(this, "_update_uniform", type_id, node_id, var, preview_port);
Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
ERR_CONTINUE(!uniform.is_valid());
deleted_names.insert(uniform->get_uniform_name());
}
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, node_id);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, node_id);
}
undo_redo->add_do_method(this, "_update_uniforms", true);
undo_redo->add_undo_method(this, "_update_uniforms", true);
if (deleted_names.size() > 0) {
_update_uniform_refs(deleted_names);
}
undo_redo->commit_action();
}
void VisualShaderEditor::_delete_node_request(int p_type, int p_node) {
List<int> to_erase;
to_erase.push_back(p_node);
@ -2134,14 +2325,29 @@ void VisualShaderEditor::_node_selected(Object *p_node) {
void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
VisualShader::Type type = get_current_shader_type();
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
selected_constants.clear();
selected_uniforms.clear();
List<int> to_change;
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
if (gn) {
if (gn->is_selected() && gn->is_close_button_visible()) {
to_change.push_back(gn->get_name().operator String().to_int());
int id = gn->get_name().operator String().to_int();
to_change.push_back(id);
Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
VisualShaderNodeConstant *cnode = Object::cast_to<VisualShaderNodeConstant>(node.ptr());
if (cnode != nullptr) {
selected_constants.insert(id);
}
VisualShaderNodeUniform *unode = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
if (unode != nullptr) {
selected_uniforms.insert(id);
}
}
}
}
@ -2152,6 +2358,32 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
popup_menu->set_item_disabled(NodeMenuOptions::PASTE, copy_nodes_buffer.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::DELETE, to_change.is_empty());
popup_menu->set_item_disabled(NodeMenuOptions::DUPLICATE, to_change.is_empty());
int temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR2);
if (temp != -1) {
popup_menu->remove_item(temp);
}
temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
temp = popup_menu->get_item_index(NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
if (temp != -1) {
popup_menu->remove_item(temp);
}
if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
if (selected_constants.size() > 0) {
popup_menu->add_item(TTR("Convert Constant(s) to Uniform(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
}
if (selected_uniforms.size() > 0) {
popup_menu->add_item(TTR("Convert Uniforms(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
}
}
menu_point = graph->get_local_mouse_position();
Point2 gpos = Input::get_singleton()->get_mouse_position();
popup_menu->set_position(gpos);
@ -2695,6 +2927,14 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::DUPLICATE:
_duplicate_nodes();
break;
case NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS:
_convert_constants_to_uniforms(false);
break;
case NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS:
_convert_constants_to_uniforms(true);
break;
default:
break;
}
}
@ -2856,6 +3096,8 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_set_mode", &VisualShaderEditor::_set_mode);
ClassDB::bind_method("_nodes_dragged", &VisualShaderEditor::_nodes_dragged);
ClassDB::bind_method("_float_constant_selected", &VisualShaderEditor::_float_constant_selected);
ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant);
ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform);
ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);

View file

@ -188,6 +188,9 @@ class VisualShaderEditor : public VBoxContainer {
PASTE,
DELETE,
DUPLICATE,
SEPARATOR2, // ignore
CONVERT_CONSTANTS_TO_UNIFORMS,
CONVERT_UNIFORMS_TO_CONSTANTS,
};
Tree *members;
@ -316,6 +319,14 @@ class VisualShaderEditor : public VBoxContainer {
int from_node;
int from_slot;
Set<int> selected_constants;
Set<int> selected_uniforms;
void _convert_constants_to_uniforms(bool p_vice_versa);
void _replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to);
void _update_constant(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
void _update_uniform(VisualShader::Type p_type_id, int p_node_id, Variant p_var, int p_preview_port);
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);

View file

@ -533,6 +533,7 @@ void register_scene_types() {
ClassDB::register_virtual_class<VisualShaderNodeOutput>();
ClassDB::register_virtual_class<VisualShaderNodeResizableBase>();
ClassDB::register_virtual_class<VisualShaderNodeGroupBase>();
ClassDB::register_virtual_class<VisualShaderNodeConstant>();
ClassDB::register_class<VisualShaderNodeFloatConstant>();
ClassDB::register_class<VisualShaderNodeIntConstant>();
ClassDB::register_class<VisualShaderNodeBooleanConstant>();

View file

@ -486,6 +486,21 @@ void VisualShader::remove_node(Type p_type, int p_id) {
_queue_update();
}
void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_class) {
ERR_FAIL_INDEX(p_type, TYPE_MAX);
ERR_FAIL_COND(p_id < 2);
Graph *g = &graph[p_type];
ERR_FAIL_COND(!g->nodes.has(p_id));
if (g->nodes[p_id].node->get_class_name() == p_new_class) {
return;
}
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(p_new_class));
g->nodes[p_id].node = Ref<VisualShaderNode>(vsn);
_queue_update();
}
bool VisualShader::is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false);
const Graph *g = &graph[p_type];
@ -1605,6 +1620,7 @@ void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id);
ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node);
ClassDB::bind_method(D_METHOD("replace_node", "type", "id", "new_class"), &VisualShader::replace_node);
ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::can_connect_nodes);

View file

@ -152,6 +152,7 @@ public:
int find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const;
void remove_node(Type p_type, int p_id);
void replace_node(Type p_type, int p_id, const StringName &p_new_class);
bool is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;

View file

@ -30,6 +30,11 @@
#include "visual_shader_nodes.h"
////////////// Constants Base
VisualShaderNodeConstant::VisualShaderNodeConstant() {
}
////////////// Scalar(Float)
String VisualShaderNodeFloatConstant::get_caption() const {

View file

@ -37,8 +37,27 @@
/// CONSTANTS
///////////////////////////////////////
class VisualShaderNodeFloatConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNode);
class VisualShaderNodeConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeConstant, VisualShaderNode);
public:
virtual String get_caption() const override = 0;
virtual int get_input_port_count() const override = 0;
virtual PortType get_input_port_type(int p_port) const override = 0;
virtual String get_input_port_name(int p_port) const override = 0;
virtual int get_output_port_count() const override = 0;
virtual PortType get_output_port_type(int p_port) const override = 0;
virtual String get_output_port_name(int p_port) const override = 0;
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 override = 0;
VisualShaderNodeConstant();
};
class VisualShaderNodeFloatConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNodeConstant);
float constant = 0.0f;
protected:
@ -67,8 +86,8 @@ public:
///////////////////////////////////////
class VisualShaderNodeIntConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeIntConstant, VisualShaderNode);
class VisualShaderNodeIntConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeIntConstant, VisualShaderNodeConstant);
int constant = 0;
protected:
@ -97,8 +116,8 @@ public:
///////////////////////////////////////
class VisualShaderNodeBooleanConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode);
class VisualShaderNodeBooleanConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNodeConstant);
bool constant = false;
protected:
@ -127,8 +146,8 @@ public:
///////////////////////////////////////
class VisualShaderNodeColorConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode);
class VisualShaderNodeColorConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeColorConstant, VisualShaderNodeConstant);
Color constant = Color(1, 1, 1, 1);
protected:
@ -157,8 +176,8 @@ public:
///////////////////////////////////////
class VisualShaderNodeVec3Constant : public VisualShaderNode {
GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode);
class VisualShaderNodeVec3Constant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNodeConstant);
Vector3 constant;
protected:
@ -187,8 +206,8 @@ public:
///////////////////////////////////////
class VisualShaderNodeTransformConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode);
class VisualShaderNodeTransformConstant : public VisualShaderNodeConstant {
GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNodeConstant);
Transform constant;
protected: