Expression node for visual shaders
This commit is contained in:
parent
d111d59640
commit
5648924eef
6 changed files with 1341 additions and 16 deletions
|
@ -239,6 +239,9 @@ void editor_register_fonts(Ref<Theme> p_theme) {
|
|||
MAKE_SOURCE_FONT(df_code, int(EditorSettings::get_singleton()->get("interface/editor/code_font_size")) * EDSCALE);
|
||||
p_theme->set_font("source", "EditorFonts", df_code);
|
||||
|
||||
MAKE_SOURCE_FONT(df_expression, (int(EditorSettings::get_singleton()->get("interface/editor/code_font_size")) - 1) * EDSCALE);
|
||||
p_theme->set_font("expression", "EditorFonts", df_expression);
|
||||
|
||||
MAKE_SOURCE_FONT(df_output_code, int(EDITOR_DEF("run/output/font_size", 13)) * EDSCALE);
|
||||
p_theme->set_font("output_source", "EditorFonts", df_output_code);
|
||||
|
||||
|
|
|
@ -358,7 +358,9 @@ void VisualShaderEditor::_update_graph() {
|
|||
for (int i = 0; i < graph->get_child_count(); i++) {
|
||||
|
||||
if (Object::cast_to<GraphNode>(graph->get_child(i))) {
|
||||
memdelete(graph->get_child(i));
|
||||
Node *node = graph->get_child(i);
|
||||
graph->remove_child(node);
|
||||
memdelete(node);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
@ -377,13 +379,33 @@ void VisualShaderEditor::_update_graph() {
|
|||
|
||||
Vector<int> nodes = visual_shader->get_node_list(type);
|
||||
|
||||
Control *offset;
|
||||
|
||||
for (int n_i = 0; n_i < nodes.size(); n_i++) {
|
||||
|
||||
Vector2 position = visual_shader->get_node_position(type, nodes[n_i]);
|
||||
Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, nodes[n_i]);
|
||||
|
||||
Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(vsnode.ptr());
|
||||
bool is_group = !group_node.is_null();
|
||||
Size2 size = Size2(0, 0);
|
||||
|
||||
Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(group_node.ptr());
|
||||
bool is_expression = !expression_node.is_null();
|
||||
String expression = "";
|
||||
|
||||
GraphNode *node = memnew(GraphNode);
|
||||
|
||||
if (is_group) {
|
||||
size = group_node->get_size();
|
||||
|
||||
node->set_resizable(true);
|
||||
node->connect("resize_request", this, "_node_resized", varray((int)type, nodes[n_i]));
|
||||
}
|
||||
if (is_expression) {
|
||||
expression = expression_node->get_expression();
|
||||
}
|
||||
|
||||
/*if (!vsnode->is_connected("changed", this, "_node_changed")) {
|
||||
vsnode->connect("changed", this, "_node_changed", varray(vsnode->get_instance_id()), CONNECT_DEFERRED);
|
||||
}*/
|
||||
|
@ -403,6 +425,10 @@ void VisualShaderEditor::_update_graph() {
|
|||
Control *custom_editor = NULL;
|
||||
int port_offset = 0;
|
||||
|
||||
if (is_group) {
|
||||
port_offset++;
|
||||
}
|
||||
|
||||
Ref<VisualShaderNodeUniform> uniform = vsnode;
|
||||
if (uniform.is_valid()) {
|
||||
graph->add_child(node);
|
||||
|
@ -438,6 +464,24 @@ void VisualShaderEditor::_update_graph() {
|
|||
custom_editor = NULL;
|
||||
}
|
||||
|
||||
if (is_group) {
|
||||
HBoxContainer *hb2 = memnew(HBoxContainer);
|
||||
|
||||
Button *add_input_btn = memnew(Button);
|
||||
add_input_btn->set_text(TTR("Add input +"));
|
||||
add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED);
|
||||
hb2->add_child(add_input_btn);
|
||||
|
||||
hb2->add_spacer();
|
||||
|
||||
Button *add_output_btn = memnew(Button);
|
||||
add_output_btn->set_text(TTR("Add output +"));
|
||||
add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED);
|
||||
hb2->add_child(add_output_btn);
|
||||
|
||||
node->add_child(hb2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) {
|
||||
|
||||
if (vsnode->is_port_separator(i)) {
|
||||
|
@ -507,21 +551,75 @@ void VisualShaderEditor::_update_graph() {
|
|||
|
||||
if (valid_left) {
|
||||
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(name_left);
|
||||
label->add_style_override("normal", label_style); //more compact
|
||||
hb->add_child(label);
|
||||
if (is_group) {
|
||||
|
||||
OptionButton *type_box = memnew(OptionButton);
|
||||
hb->add_child(type_box);
|
||||
type_box->add_item(TTR("Scalar"));
|
||||
type_box->add_item(TTR("Vector"));
|
||||
type_box->add_item(TTR("Boolean"));
|
||||
type_box->add_item(TTR("Transform"));
|
||||
type_box->select(group_node->get_input_port_type(i));
|
||||
type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
|
||||
type_box->connect("item_selected", this, "_change_input_port_type", varray(nodes[n_i], i), CONNECT_DEFERRED);
|
||||
|
||||
LineEdit *name_box = memnew(LineEdit);
|
||||
hb->add_child(name_box);
|
||||
name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
|
||||
name_box->set_text(name_left);
|
||||
name_box->set_expand_to_text_length(true);
|
||||
name_box->connect("text_entered", this, "_change_input_port_name", varray(name_box, nodes[n_i], i));
|
||||
name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, nodes[n_i], i, false));
|
||||
|
||||
if (is_group) {
|
||||
Button *remove_btn = memnew(Button);
|
||||
remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
|
||||
remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
|
||||
remove_btn->connect("pressed", this, "_remove_input_port", varray(nodes[n_i], i), CONNECT_DEFERRED);
|
||||
hb->add_child(remove_btn);
|
||||
}
|
||||
} else {
|
||||
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(name_left);
|
||||
label->add_style_override("normal", label_style); //more compact
|
||||
hb->add_child(label);
|
||||
}
|
||||
}
|
||||
|
||||
hb->add_spacer();
|
||||
|
||||
if (valid_right) {
|
||||
if (is_group) {
|
||||
Button *remove_btn = memnew(Button);
|
||||
remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Remove", "EditorIcons"));
|
||||
remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
|
||||
remove_btn->connect("pressed", this, "_remove_output_port", varray(nodes[n_i], i), CONNECT_DEFERRED);
|
||||
hb->add_child(remove_btn);
|
||||
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(name_right);
|
||||
label->set_align(Label::ALIGN_RIGHT);
|
||||
label->add_style_override("normal", label_style); //more compact
|
||||
hb->add_child(label);
|
||||
LineEdit *name_box = memnew(LineEdit);
|
||||
hb->add_child(name_box);
|
||||
name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
|
||||
name_box->set_text(name_right);
|
||||
name_box->set_expand_to_text_length(true);
|
||||
name_box->connect("text_entered", this, "_change_output_port_name", varray(name_box, nodes[n_i], i));
|
||||
name_box->connect("focus_exited", this, "_port_name_focus_out", varray(name_box, nodes[n_i], i, true));
|
||||
|
||||
OptionButton *type_box = memnew(OptionButton);
|
||||
hb->add_child(type_box);
|
||||
type_box->add_item(TTR("Scalar"));
|
||||
type_box->add_item(TTR("Vector"));
|
||||
type_box->add_item(TTR("Boolean"));
|
||||
type_box->add_item(TTR("Transform"));
|
||||
type_box->select(group_node->get_output_port_type(i));
|
||||
type_box->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
|
||||
type_box->connect("item_selected", this, "_change_output_port_type", varray(nodes[n_i], i), CONNECT_DEFERRED);
|
||||
} else {
|
||||
Label *label = memnew(Label);
|
||||
label->set_text(name_right);
|
||||
label->add_style_override("normal", label_style); //more compact
|
||||
hb->add_child(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,18 +638,33 @@ void VisualShaderEditor::_update_graph() {
|
|||
hb->add_child(preview);
|
||||
}
|
||||
|
||||
if (is_group) {
|
||||
offset = memnew(Control);
|
||||
offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
|
||||
node->add_child(offset);
|
||||
port_offset++;
|
||||
}
|
||||
|
||||
node->add_child(hb);
|
||||
|
||||
node->set_slot(i + port_offset, valid_left, port_left, type_color[port_left], valid_right, port_right, type_color[port_right]);
|
||||
}
|
||||
|
||||
if (vsnode->get_output_port_for_preview() >= 0 && vsnode->get_output_port_type(vsnode->get_output_port_for_preview()) != VisualShaderNode::PORT_TYPE_TRANSFORM) {
|
||||
offset = memnew(Control);
|
||||
offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
|
||||
node->add_child(offset);
|
||||
|
||||
VisualShaderNodePortPreview *port_preview = memnew(VisualShaderNodePortPreview);
|
||||
port_preview->setup(visual_shader, type, nodes[n_i], vsnode->get_output_port_for_preview());
|
||||
port_preview->set_h_size_flags(SIZE_SHRINK_CENTER);
|
||||
node->add_child(port_preview);
|
||||
}
|
||||
|
||||
offset = memnew(Control);
|
||||
offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
|
||||
node->add_child(offset);
|
||||
|
||||
String error = vsnode->get_warning(visual_shader->get_mode(), type);
|
||||
if (error != String()) {
|
||||
Label *error_label = memnew(Label);
|
||||
|
@ -560,9 +673,42 @@ void VisualShaderEditor::_update_graph() {
|
|||
node->add_child(error_label);
|
||||
}
|
||||
|
||||
if (is_expression) {
|
||||
|
||||
TextEdit *expression_box = memnew(TextEdit);
|
||||
expression_node->set_control(expression_box, 0);
|
||||
node->add_child(expression_box);
|
||||
|
||||
Color text_color = EDITOR_GET("text_editor/highlighting/text_color");
|
||||
Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color");
|
||||
Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color");
|
||||
Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color");
|
||||
|
||||
expression_box->set_syntax_coloring(true);
|
||||
|
||||
for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) {
|
||||
|
||||
expression_box->add_keyword_color(E->get(), keyword_color);
|
||||
}
|
||||
|
||||
expression_box->add_font_override("font", get_font("expression", "EditorFonts"));
|
||||
expression_box->add_color_override("font_color", text_color);
|
||||
expression_box->add_color_override("symbol_color", symbol_color);
|
||||
expression_box->add_color_region("/*", "*/", comment_color, false);
|
||||
expression_box->add_color_region("//", "", comment_color, false);
|
||||
|
||||
expression_box->set_text(expression);
|
||||
expression_box->set_context_menu_enabled(false);
|
||||
expression_box->set_show_line_numbers(true);
|
||||
|
||||
expression_box->connect("text_changed", this, "_set_expression", varray(nodes[n_i]), CONNECT_DEFERRED);
|
||||
}
|
||||
|
||||
if (!uniform.is_valid()) {
|
||||
graph->add_child(node);
|
||||
_update_created_node(node);
|
||||
if (is_group)
|
||||
call_deferred("_set_node_size", (int)type, nodes[n_i], size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,6 +723,290 @@ void VisualShaderEditor::_update_graph() {
|
|||
}
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type, const String &p_name) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Add input port"));
|
||||
undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name);
|
||||
undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port);
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_type, const String &p_name) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Add output port"));
|
||||
undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name);
|
||||
undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port);
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_port) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Change input port type"));
|
||||
undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type);
|
||||
undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port));
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_port) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Change output port type"));
|
||||
undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type);
|
||||
undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port));
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *line_edit, int p_node_id, int p_port_id) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);
|
||||
ERR_FAIL_COND(!node.is_valid());
|
||||
|
||||
undo_redo->create_action(TTR("Change input port name"));
|
||||
undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, p_text);
|
||||
undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *line_edit, int p_node_id, int p_port_id) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);
|
||||
ERR_FAIL_COND(!node.is_valid());
|
||||
|
||||
undo_redo->create_action(TTR("Change output port name"));
|
||||
undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, p_text);
|
||||
undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, node->get_output_port_name(p_port_id));
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Remove input port"));
|
||||
|
||||
List<VisualShader::Connection> conns;
|
||||
visual_shader->get_node_connections(type, &conns);
|
||||
for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
|
||||
|
||||
int from_node = E->get().from_node;
|
||||
int from_port = E->get().from_port;
|
||||
int to_node = E->get().to_node;
|
||||
int to_port = E->get().to_port;
|
||||
|
||||
if (to_node == p_node) {
|
||||
if (to_port == p_port) {
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
|
||||
} else if (to_port > p_port) {
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
|
||||
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port - 1);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(node.ptr(), "remove_input_port", p_port);
|
||||
undo_redo->add_undo_method(node.ptr(), "add_input_port", p_port, (int)node->get_input_port_type(p_port), node->get_input_port_name(p_port));
|
||||
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Remove output port"));
|
||||
|
||||
List<VisualShader::Connection> conns;
|
||||
visual_shader->get_node_connections(type, &conns);
|
||||
for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
|
||||
|
||||
int from_node = E->get().from_node;
|
||||
int from_port = E->get().from_port;
|
||||
int to_node = E->get().to_node;
|
||||
int to_port = E->get().to_port;
|
||||
|
||||
if (from_node == p_node) {
|
||||
if (from_port == p_port) {
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
|
||||
} else if (from_port > p_port) {
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
|
||||
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port - 1, to_node, to_port);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - 1, to_node, to_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(node.ptr(), "remove_output_port", p_port);
|
||||
undo_redo->add_undo_method(node.ptr(), "add_output_port", p_port, (int)node->get_output_port_type(p_port), node->get_output_port_name(p_port));
|
||||
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
|
||||
undo_redo->add_do_method(this, "_rebuild");
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_set_expression(int p_node) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNodeExpression> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TextEdit *expression_box = Object::cast_to<TextEdit>(node->get_control(0));
|
||||
|
||||
undo_redo->create_action(TTR("Set expression"));
|
||||
undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text());
|
||||
undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression());
|
||||
undo_redo->add_do_method(this, "_start_rebuild_timer", 1.0);
|
||||
undo_redo->add_undo_method(this, "_rebuild");
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_start_rebuild_timer(int p_delay) {
|
||||
build_timer->start(p_delay);
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_rebuild_timeout() {
|
||||
_rebuild();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_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) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(p_type);
|
||||
Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Ref<VisualShaderNodeGroupBase> group_node = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
|
||||
|
||||
if (group_node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 size = p_size;
|
||||
|
||||
group_node->set_size(size);
|
||||
|
||||
GraphNode *gn = NULL;
|
||||
if (edit_type->get_selected() == p_type) { // check - otherwise the error will be emitted
|
||||
Node *node2 = graph->get_node(itos(p_node));
|
||||
gn = Object::cast_to<GraphNode>(node2);
|
||||
if (!gn)
|
||||
return;
|
||||
|
||||
gn->set_custom_minimum_size(size);
|
||||
gn->set_size(Size2(1, 1));
|
||||
}
|
||||
|
||||
Ref<VisualShaderNodeExpression> expression_node = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
|
||||
if (!expression_node.is_null()) {
|
||||
Control *text_box = expression_node->get_control(0);
|
||||
Size2 box_size = size;
|
||||
if (gn != NULL) {
|
||||
if (box_size.x < 150 * EDSCALE || box_size.y < 0) {
|
||||
box_size.x = gn->get_size().x;
|
||||
}
|
||||
}
|
||||
box_size.x -= text_box->get_margin(Margin::MARGIN_LEFT);
|
||||
box_size.x -= 28 * EDSCALE;
|
||||
box_size.y -= text_box->get_margin(Margin::MARGIN_TOP);
|
||||
box_size.y -= 28 * EDSCALE;
|
||||
text_box->set_custom_minimum_size(Size2(box_size.x, box_size.y));
|
||||
text_box->set_size(Size2(1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, int p_node) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(p_type);
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node);
|
||||
if (node.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
undo_redo->create_action(TTR("Resize VisualShader node"), UndoRedo::MERGE_ENDS);
|
||||
undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, p_new_size / EDSCALE);
|
||||
undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size());
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
|
@ -623,6 +1053,52 @@ void VisualShaderEditor::_line_edit_focus_out(Object *line_edit, int p_node_id)
|
|||
_line_edit_changed(text, line_edit, p_node_id);
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
|
||||
Ref<VisualShaderNodeGroupBase> node = visual_shader->get_node(type, p_node_id);
|
||||
ERR_FAIL_COND(!node.is_valid());
|
||||
|
||||
String text = Object::cast_to<LineEdit>(line_edit)->get_text();
|
||||
|
||||
if (!p_output) {
|
||||
if (node->get_input_port_name(p_port_id) == text)
|
||||
return;
|
||||
} else {
|
||||
if (node->get_output_port_name(p_port_id) == text)
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> input_names;
|
||||
List<String> output_names;
|
||||
|
||||
for (int i = 0; i < node->get_input_port_count(); i++) {
|
||||
if (!p_output && i == p_port_id) continue;
|
||||
input_names.push_back(node->get_input_port_name(i));
|
||||
}
|
||||
for (int i = 0; i < node->get_output_port_count(); i++) {
|
||||
if (p_output && i == p_port_id) continue;
|
||||
output_names.push_back(node->get_output_port_name(i));
|
||||
}
|
||||
|
||||
String validated_name = visual_shader->validate_port_name(text, input_names, output_names);
|
||||
if (validated_name == "") {
|
||||
if (!p_output) {
|
||||
Object::cast_to<LineEdit>(line_edit)->set_text(node->get_input_port_name(p_port_id));
|
||||
} else {
|
||||
Object::cast_to<LineEdit>(line_edit)->set_text(node->get_output_port_name(p_port_id));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p_output) {
|
||||
_change_input_port_name(validated_name, line_edit, p_node_id, p_port_id);
|
||||
} else {
|
||||
_change_output_port_name(validated_name, line_edit, p_node_id, p_port_id);
|
||||
}
|
||||
}
|
||||
|
||||
void VisualShaderEditor::_port_edited() {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
|
@ -757,6 +1233,12 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
|
|||
undo_redo->create_action(TTR("Add Node to Visual Shader"));
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, vsnode, position, id_to_use);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_to_use);
|
||||
|
||||
VisualShaderNodeExpression *expr = Object::cast_to<VisualShaderNodeExpression>(vsnode.ptr());
|
||||
if (expr) {
|
||||
undo_redo->add_do_method(expr, "set_size", Size2(250 * EDSCALE, 150 * EDSCALE));
|
||||
}
|
||||
|
||||
undo_redo->add_do_method(this, "_update_graph");
|
||||
undo_redo->add_undo_method(this, "_update_graph");
|
||||
undo_redo->commit_action();
|
||||
|
@ -831,10 +1313,25 @@ void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_s
|
|||
void VisualShaderEditor::_delete_request(int which) {
|
||||
|
||||
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
|
||||
Ref<VisualShaderNode> node = Ref<VisualShaderNode>(visual_shader->get_node(type, which));
|
||||
|
||||
undo_redo->create_action(TTR("Delete Node"));
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, which);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, visual_shader->get_node(type, which), visual_shader->get_node_position(type, which), which);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, which), which);
|
||||
|
||||
// restore size, inputs and outputs if node is group
|
||||
VisualShaderNodeGroupBase *group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
|
||||
if (group) {
|
||||
undo_redo->add_undo_method(group, "set_size", group->get_size());
|
||||
undo_redo->add_undo_method(group, "set_inputs", group->get_inputs());
|
||||
undo_redo->add_undo_method(group, "set_outputs", group->get_outputs());
|
||||
}
|
||||
|
||||
// restore expression text if node is expression
|
||||
VisualShaderNodeExpression *expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
|
||||
if (expression) {
|
||||
undo_redo->add_undo_method(expression, "set_expression", expression->get_expression());
|
||||
}
|
||||
|
||||
List<VisualShader::Connection> conns;
|
||||
visual_shader->get_node_connections(type, &conns);
|
||||
|
@ -1022,6 +1519,19 @@ void VisualShaderEditor::_duplicate_nodes() {
|
|||
undo_redo->add_do_method(visual_shader.ptr(), "add_node", type, dupli, visual_shader->get_node_position(type, E->get()) + Vector2(10, 10) * EDSCALE, id_from);
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "remove_node", type, id_from);
|
||||
|
||||
// duplicate size, inputs and outputs if node is group
|
||||
Ref<VisualShaderNodeGroupBase> group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
|
||||
if (!group.is_null()) {
|
||||
undo_redo->add_do_method(dupli.ptr(), "set_size", group->get_size());
|
||||
undo_redo->add_do_method(dupli.ptr(), "set_inputs", group->get_inputs());
|
||||
undo_redo->add_do_method(dupli.ptr(), "set_outputs", group->get_outputs());
|
||||
}
|
||||
// duplicate expression text if node is expression
|
||||
Ref<VisualShaderNodeExpression> expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
|
||||
if (!expression.is_null()) {
|
||||
undo_redo->add_do_method(dupli.ptr(), "set_expression", expression->get_expression());
|
||||
}
|
||||
|
||||
id_from++;
|
||||
}
|
||||
|
||||
|
@ -1030,7 +1540,7 @@ void VisualShaderEditor::_duplicate_nodes() {
|
|||
|
||||
for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
|
||||
if (connection_remap.has(E->get().from_node) && connection_remap.has(E->get().to_node)) {
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, connection_remap[E->get().from_node], E->get().from_port, connection_remap[E->get().to_node], E->get().to_port);
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, connection_remap[E->get().from_node], E->get().from_port, connection_remap[E->get().to_node], E->get().to_port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1073,8 +1583,25 @@ void VisualShaderEditor::_on_nodes_delete() {
|
|||
undo_redo->create_action(TTR("Delete Nodes"));
|
||||
|
||||
for (List<int>::Element *F = to_erase.front(); F; F = F->next()) {
|
||||
|
||||
Ref<VisualShaderNode> node = visual_shader->get_node(type, F->get());
|
||||
|
||||
undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F->get());
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, visual_shader->get_node(type, F->get()), visual_shader->get_node_position(type, F->get()), F->get());
|
||||
undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, node, visual_shader->get_node_position(type, F->get()), F->get());
|
||||
|
||||
// restore size, inputs and outputs if node is group
|
||||
VisualShaderNodeGroupBase *group = Object::cast_to<VisualShaderNodeGroupBase>(node.ptr());
|
||||
if (group) {
|
||||
undo_redo->add_undo_method(group, "set_size", group->get_size());
|
||||
undo_redo->add_undo_method(group, "set_inputs", group->get_inputs());
|
||||
undo_redo->add_undo_method(group, "set_outputs", group->get_outputs());
|
||||
}
|
||||
|
||||
// restore expression text if node is expression
|
||||
VisualShaderNodeExpression *expression = Object::cast_to<VisualShaderNodeExpression>(node.ptr());
|
||||
if (expression) {
|
||||
undo_redo->add_undo_method(expression, "set_expression", expression->get_expression());
|
||||
}
|
||||
}
|
||||
|
||||
List<VisualShader::Connection> conns;
|
||||
|
@ -1267,8 +1794,12 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
|
|||
}
|
||||
|
||||
void VisualShaderEditor::_bind_methods() {
|
||||
ClassDB::bind_method("_rebuild", &VisualShaderEditor::_rebuild);
|
||||
ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph);
|
||||
ClassDB::bind_method("_update_options_menu", &VisualShaderEditor::_update_options_menu);
|
||||
ClassDB::bind_method("_start_rebuild_timer", &VisualShaderEditor::_start_rebuild_timer);
|
||||
ClassDB::bind_method("_set_expression", &VisualShaderEditor::_set_expression);
|
||||
ClassDB::bind_method("_rebuild_timeout", &VisualShaderEditor::_rebuild_timeout);
|
||||
ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
|
||||
ClassDB::bind_method("_node_dragged", &VisualShaderEditor::_node_dragged);
|
||||
ClassDB::bind_method("_connection_request", &VisualShaderEditor::_connection_request);
|
||||
|
@ -1283,11 +1814,22 @@ void VisualShaderEditor::_bind_methods() {
|
|||
ClassDB::bind_method("_connection_to_empty", &VisualShaderEditor::_connection_to_empty);
|
||||
ClassDB::bind_method("_line_edit_focus_out", &VisualShaderEditor::_line_edit_focus_out);
|
||||
ClassDB::bind_method("_line_edit_changed", &VisualShaderEditor::_line_edit_changed);
|
||||
ClassDB::bind_method("_port_name_focus_out", &VisualShaderEditor::_port_name_focus_out);
|
||||
ClassDB::bind_method("_duplicate_nodes", &VisualShaderEditor::_duplicate_nodes);
|
||||
ClassDB::bind_method("_mode_selected", &VisualShaderEditor::_mode_selected);
|
||||
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
|
||||
ClassDB::bind_method("_preview_select_port", &VisualShaderEditor::_preview_select_port);
|
||||
ClassDB::bind_method("_graph_gui_input", &VisualShaderEditor::_graph_gui_input);
|
||||
ClassDB::bind_method("_add_input_port", &VisualShaderEditor::_add_input_port);
|
||||
ClassDB::bind_method("_change_input_port_type", &VisualShaderEditor::_change_input_port_type);
|
||||
ClassDB::bind_method("_change_input_port_name", &VisualShaderEditor::_change_input_port_name);
|
||||
ClassDB::bind_method("_remove_input_port", &VisualShaderEditor::_remove_input_port);
|
||||
ClassDB::bind_method("_add_output_port", &VisualShaderEditor::_add_output_port);
|
||||
ClassDB::bind_method("_change_output_port_type", &VisualShaderEditor::_change_output_port_type);
|
||||
ClassDB::bind_method("_change_output_port_name", &VisualShaderEditor::_change_output_port_name);
|
||||
ClassDB::bind_method("_remove_output_port", &VisualShaderEditor::_remove_output_port);
|
||||
ClassDB::bind_method("_node_resized", &VisualShaderEditor::_node_resized);
|
||||
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
|
||||
|
||||
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);
|
||||
|
@ -1311,6 +1853,7 @@ VisualShaderEditor::VisualShaderEditor() {
|
|||
updating = false;
|
||||
saved_node_pos_dirty = false;
|
||||
saved_node_pos = Point2(0, 0);
|
||||
ShaderLanguage::get_keyword_list(&keyword_list);
|
||||
|
||||
graph = memnew(GraphEdit);
|
||||
add_child(graph);
|
||||
|
@ -1710,6 +2253,7 @@ VisualShaderEditor::VisualShaderEditor() {
|
|||
|
||||
// SPECIAL
|
||||
|
||||
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
|
||||
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
|
||||
|
||||
add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(GLES3 only) (Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT));
|
||||
|
@ -1743,6 +2287,13 @@ VisualShaderEditor::VisualShaderEditor() {
|
|||
add_child(property_editor);
|
||||
|
||||
property_editor->connect("variant_changed", this, "_port_edited");
|
||||
|
||||
// BUILD TIMER FOR EXPRESSION NODES
|
||||
|
||||
build_timer = memnew(Timer);
|
||||
add_child(build_timer);
|
||||
build_timer->connect("timeout", this, "_rebuild_timeout");
|
||||
build_timer->set_one_shot(true);
|
||||
}
|
||||
|
||||
void VisualShaderEditorPlugin::edit(Object *p_object) {
|
||||
|
|
|
@ -84,6 +84,8 @@ class VisualShaderEditor : public VBoxContainer {
|
|||
LineEdit *node_filter;
|
||||
RichTextLabel *node_desc;
|
||||
|
||||
Timer *build_timer;
|
||||
|
||||
void _tools_menu_option(int p_idx);
|
||||
void _show_members_dialog(bool at_mouse_pos);
|
||||
|
||||
|
@ -128,6 +130,7 @@ class VisualShaderEditor : public VBoxContainer {
|
|||
};
|
||||
|
||||
Vector<AddOption> add_options;
|
||||
List<String> keyword_list;
|
||||
|
||||
void _draw_color_over_button(Object *obj, Color p_color);
|
||||
|
||||
|
@ -160,14 +163,35 @@ class VisualShaderEditor : public VBoxContainer {
|
|||
void _line_edit_changed(const String &p_text, Object *line_edit, int p_node_id);
|
||||
void _line_edit_focus_out(Object *line_edit, int p_node_id);
|
||||
|
||||
void _port_name_focus_out(Object *line_edit, int p_node_id, int p_port_id, bool p_output);
|
||||
|
||||
void _duplicate_nodes();
|
||||
|
||||
Vector<Ref<VisualShaderNodePlugin> > plugins;
|
||||
|
||||
void _mode_selected(int p_id);
|
||||
void _rebuild();
|
||||
|
||||
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
|
||||
|
||||
void _add_input_port(int p_node, int p_port, int p_type, const String &p_name);
|
||||
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_name(const String &p_text, Object *line_edit, int p_node, int p_port);
|
||||
|
||||
void _add_output_port(int p_node, int p_port, int p_type, const String &p_name);
|
||||
void _remove_output_port(int p_node, int p_port);
|
||||
void _change_output_port_type(int p_type, int p_node, int p_port);
|
||||
void _change_output_port_name(const String &p_text, Object *line_edit, int p_node, int p_port);
|
||||
|
||||
void _start_rebuild_timer(int p_delay);
|
||||
|
||||
void _set_expression(int p_node);
|
||||
void _rebuild_timeout();
|
||||
|
||||
void _set_node_size(int p_type, int p_node, const Size2 &p_size);
|
||||
void _node_resized(const Vector2 &p_new_size, int p_type, int p_node);
|
||||
|
||||
void _preview_select_port(int p_node, int p_port);
|
||||
void _graph_gui_input(const Ref<InputEvent> p_event);
|
||||
|
||||
|
|
|
@ -476,6 +476,7 @@ void register_scene_types() {
|
|||
ClassDB::register_virtual_class<VisualShaderNode>();
|
||||
ClassDB::register_class<VisualShaderNodeInput>();
|
||||
ClassDB::register_virtual_class<VisualShaderNodeOutput>();
|
||||
ClassDB::register_class<VisualShaderNodeGroupBase>();
|
||||
ClassDB::register_class<VisualShaderNodeScalarConstant>();
|
||||
ClassDB::register_class<VisualShaderNodeBooleanConstant>();
|
||||
ClassDB::register_class<VisualShaderNodeColorConstant>();
|
||||
|
@ -524,6 +525,7 @@ void register_scene_types() {
|
|||
ClassDB::register_class<VisualShaderNodeIf>();
|
||||
ClassDB::register_class<VisualShaderNodeSwitch>();
|
||||
ClassDB::register_class<VisualShaderNodeFresnel>();
|
||||
ClassDB::register_class<VisualShaderNodeExpression>();
|
||||
|
||||
ClassDB::register_class<ShaderMaterial>();
|
||||
ClassDB::register_virtual_class<CanvasItem>();
|
||||
|
|
|
@ -159,6 +159,7 @@ Vector2 VisualShader::get_node_position(Type p_type, int p_id) const {
|
|||
ERR_FAIL_COND_V(!g->nodes.has(p_id), Vector2());
|
||||
return g->nodes[p_id].position;
|
||||
}
|
||||
|
||||
Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const {
|
||||
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>());
|
||||
const Graph *g = &graph[p_type];
|
||||
|
@ -269,6 +270,18 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
|
|||
return true;
|
||||
}
|
||||
|
||||
void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
|
||||
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
||||
Graph *g = &graph[p_type];
|
||||
Connection c;
|
||||
c.from_node = p_from_node;
|
||||
c.from_port = p_from_port;
|
||||
c.to_node = p_to_node;
|
||||
c.to_port = p_to_port;
|
||||
g->connections.push_back(c);
|
||||
_queue_update();
|
||||
}
|
||||
|
||||
Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
|
||||
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, ERR_CANT_CONNECT);
|
||||
Graph *g = &graph[p_type];
|
||||
|
@ -304,6 +317,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
|
|||
_queue_update();
|
||||
return OK;
|
||||
}
|
||||
|
||||
void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
|
||||
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
||||
Graph *g = &graph[p_type];
|
||||
|
@ -334,6 +348,7 @@ Array VisualShader::_get_node_connections(Type p_type) const {
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connections) const {
|
||||
ERR_FAIL_INDEX(p_type, TYPE_MAX);
|
||||
const Graph *g = &graph[p_type];
|
||||
|
@ -477,6 +492,54 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
|
|||
|
||||
#define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_')
|
||||
|
||||
String VisualShader::validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const {
|
||||
String name = p_name;
|
||||
|
||||
while (name.length() && !IS_INITIAL_CHAR(name[0])) {
|
||||
name = name.substr(1, name.length() - 1);
|
||||
}
|
||||
|
||||
if (name != String()) {
|
||||
|
||||
String valid_name;
|
||||
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
if (IS_SYMBOL_CHAR(name[i])) {
|
||||
valid_name += String::chr(name[i]);
|
||||
} else if (name[i] == ' ') {
|
||||
valid_name += "_";
|
||||
}
|
||||
}
|
||||
|
||||
name = valid_name;
|
||||
}
|
||||
|
||||
String valid_name = name;
|
||||
bool is_equal = false;
|
||||
|
||||
for (int i = 0; i < p_input_ports.size(); i++) {
|
||||
if (name == p_input_ports[i]) {
|
||||
is_equal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_equal) {
|
||||
for (int i = 0; i < p_output_ports.size(); i++) {
|
||||
if (name == p_output_ports[i]) {
|
||||
is_equal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_equal) {
|
||||
name = "";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const {
|
||||
|
||||
String name = p_name; //validate name first
|
||||
|
@ -596,7 +659,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
|
|||
Vector<int> conns = p_value;
|
||||
if (conns.size() % 4 == 0) {
|
||||
for (int i = 0; i < conns.size(); i += 4) {
|
||||
connect_nodes(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]);
|
||||
connect_nodes_forced(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -611,6 +674,18 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
|
|||
} else if (what == "position") {
|
||||
set_node_position(type, id, p_value);
|
||||
return true;
|
||||
} else if (what == "size") {
|
||||
((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_size(p_value);
|
||||
return true;
|
||||
} else if (what == "input_ports") {
|
||||
((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_inputs(p_value);
|
||||
return true;
|
||||
} else if (what == "output_ports") {
|
||||
((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_outputs(p_value);
|
||||
return true;
|
||||
} else if (what == "expression") {
|
||||
((VisualShaderNodeExpression *)get_node(type, id).ptr())->set_expression(p_value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -668,6 +743,18 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
|
|||
} else if (what == "position") {
|
||||
r_ret = get_node_position(type, id);
|
||||
return true;
|
||||
} else if (what == "size") {
|
||||
r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_size();
|
||||
return true;
|
||||
} else if (what == "input_ports") {
|
||||
r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs();
|
||||
return true;
|
||||
} else if (what == "output_ports") {
|
||||
r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_outputs();
|
||||
return true;
|
||||
} else if (what == "expression") {
|
||||
r_ret = ((VisualShaderNodeExpression *)get_node(type, id).ptr())->get_expression();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -727,6 +814,15 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
|
|||
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
|
||||
}
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||
|
||||
if (Object::cast_to<VisualShaderNodeGroupBase>(E->get().node.ptr()) != NULL) {
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/input_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||
}
|
||||
if (Object::cast_to<VisualShaderNodeExpression>(E->get().node.ptr()) != NULL) {
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||
}
|
||||
}
|
||||
p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "nodes/" + String(type_string[i]) + "/connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
||||
}
|
||||
|
@ -993,26 +1089,33 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) {
|
|||
}
|
||||
}
|
||||
|
||||
void VisualShader::rebuild() {
|
||||
dirty = true;
|
||||
_update_shader();
|
||||
}
|
||||
|
||||
void VisualShader::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShader::set_mode);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node);
|
||||
ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_node", "type", "id"), &VisualShader::get_node);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position);
|
||||
ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list);
|
||||
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("rebuild"), &VisualShader::rebuild);
|
||||
|
||||
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::is_node_connection);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes);
|
||||
ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes);
|
||||
ClassDB::bind_method(D_METHOD("connect_nodes_forced", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes_forced);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
|
||||
|
||||
|
@ -1627,3 +1730,553 @@ void VisualShaderNodeUniform::_bind_methods() {
|
|||
|
||||
VisualShaderNodeUniform::VisualShaderNodeUniform() {
|
||||
}
|
||||
|
||||
////////////// GroupBase
|
||||
|
||||
String VisualShaderNodeGroupBase::get_caption() const {
|
||||
return "Group";
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_size(const Vector2 &p_size) {
|
||||
size = p_size;
|
||||
}
|
||||
|
||||
Vector2 VisualShaderNodeGroupBase::get_size() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
|
||||
|
||||
if (inputs == p_inputs)
|
||||
return;
|
||||
|
||||
clear_input_ports();
|
||||
|
||||
inputs = p_inputs;
|
||||
|
||||
Vector<String> input_strings = inputs.split(";", false);
|
||||
|
||||
int input_port_count = input_strings.size();
|
||||
|
||||
for (int i = 0; i < input_port_count; i++) {
|
||||
|
||||
Vector<String> arr = input_strings[i].split(",");
|
||||
|
||||
int port_idx = arr[0].to_int();
|
||||
int port_type = arr[1].to_int();
|
||||
String port_name = arr[2];
|
||||
|
||||
Port port;
|
||||
port.type = (PortType)port_type;
|
||||
port.name = port_name;
|
||||
input_ports[port_idx] = port;
|
||||
}
|
||||
}
|
||||
|
||||
String VisualShaderNodeGroupBase::get_inputs() const {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_outputs(const String &p_outputs) {
|
||||
|
||||
if (outputs == p_outputs)
|
||||
return;
|
||||
|
||||
clear_output_ports();
|
||||
|
||||
outputs = p_outputs;
|
||||
|
||||
Vector<String> output_strings = outputs.split(";", false);
|
||||
|
||||
int output_port_count = output_strings.size();
|
||||
|
||||
for (int i = 0; i < output_port_count; i++) {
|
||||
|
||||
Vector<String> arr = output_strings[i].split(",");
|
||||
|
||||
int port_idx = arr[0].to_int();
|
||||
int port_type = arr[1].to_int();
|
||||
String port_name = arr[2];
|
||||
|
||||
Port port;
|
||||
port.type = (PortType)port_type;
|
||||
port.name = port_name;
|
||||
output_ports[port_idx] = port;
|
||||
}
|
||||
}
|
||||
|
||||
String VisualShaderNodeGroupBase::get_outputs() const {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const String &p_name) {
|
||||
|
||||
String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";";
|
||||
Vector<String> inputs_strings = inputs.split(";", false);
|
||||
int index = 0;
|
||||
if (p_id < inputs_strings.size()) {
|
||||
for (int i = 0; i < inputs_strings.size(); i++) {
|
||||
if (i == p_id) {
|
||||
inputs = inputs.insert(index, str);
|
||||
break;
|
||||
}
|
||||
index += inputs_strings[i].size();
|
||||
}
|
||||
} else {
|
||||
inputs += str;
|
||||
}
|
||||
|
||||
inputs_strings = inputs.split(";", false);
|
||||
index = 0;
|
||||
|
||||
for (int i = 0; i < inputs_strings.size(); i++) {
|
||||
int count = 0;
|
||||
for (int j = 0; j < inputs_strings[i].size(); j++) {
|
||||
if (inputs_strings[i][j] == ',') {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
inputs.erase(index, count);
|
||||
inputs = inputs.insert(index, itos(i));
|
||||
index += inputs_strings[i].size();
|
||||
}
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::remove_input_port(int p_id) {
|
||||
|
||||
Vector<String> inputs_strings = inputs.split(";", false);
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < inputs_strings.size(); i++) {
|
||||
Vector<String> arr = inputs_strings[i].split(",");
|
||||
if (arr[0].to_int() == p_id) {
|
||||
count = inputs_strings[i].size();
|
||||
break;
|
||||
}
|
||||
index += inputs_strings[i].size();
|
||||
}
|
||||
inputs.erase(index, count);
|
||||
|
||||
inputs_strings = inputs.split(";", false);
|
||||
for (int i = p_id; i < inputs_strings.size(); i++) {
|
||||
inputs = inputs.replace_first(inputs_strings[i].split(",")[0], itos(i));
|
||||
}
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
int VisualShaderNodeGroupBase::get_input_port_count() const {
|
||||
return input_ports.size();
|
||||
}
|
||||
|
||||
bool VisualShaderNodeGroupBase::has_input_port(int p_id) const {
|
||||
return input_ports.has(p_id);
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const String &p_name) {
|
||||
|
||||
String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";";
|
||||
Vector<String> outputs_strings = outputs.split(";", false);
|
||||
int index = 0;
|
||||
if (p_id < outputs_strings.size()) {
|
||||
for (int i = 0; i < outputs_strings.size(); i++) {
|
||||
if (i == p_id) {
|
||||
outputs = outputs.insert(index, str);
|
||||
break;
|
||||
}
|
||||
index += outputs_strings[i].size();
|
||||
}
|
||||
} else {
|
||||
outputs += str;
|
||||
}
|
||||
|
||||
outputs_strings = outputs.split(";", false);
|
||||
index = 0;
|
||||
|
||||
for (int i = 0; i < outputs_strings.size(); i++) {
|
||||
int count = 0;
|
||||
for (int j = 0; j < outputs_strings[i].size(); j++) {
|
||||
if (outputs_strings[i][j] == ',') {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
outputs.erase(index, count);
|
||||
outputs = outputs.insert(index, itos(i));
|
||||
index += outputs_strings[i].size();
|
||||
}
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::remove_output_port(int p_id) {
|
||||
|
||||
Vector<String> outputs_strings = outputs.split(";", false);
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < outputs_strings.size(); i++) {
|
||||
Vector<String> arr = outputs_strings[i].split(",");
|
||||
if (arr[0].to_int() == p_id) {
|
||||
count = outputs_strings[i].size();
|
||||
break;
|
||||
}
|
||||
index += outputs_strings[i].size();
|
||||
}
|
||||
outputs.erase(index, count);
|
||||
|
||||
outputs_strings = outputs.split(";", false);
|
||||
for (int i = p_id; i < outputs_strings.size(); i++) {
|
||||
outputs = outputs.replace_first(outputs_strings[i].split(",")[0], itos(i));
|
||||
}
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
int VisualShaderNodeGroupBase::get_output_port_count() const {
|
||||
return output_ports.size();
|
||||
}
|
||||
|
||||
bool VisualShaderNodeGroupBase::has_output_port(int p_id) const {
|
||||
return output_ports.has(p_id);
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::clear_input_ports() {
|
||||
input_ports.clear();
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::clear_output_ports() {
|
||||
output_ports.clear();
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) {
|
||||
|
||||
if (input_ports[p_id].type == p_type)
|
||||
return;
|
||||
|
||||
Vector<String> inputs_strings = inputs.split(";", false);
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < inputs_strings.size(); i++) {
|
||||
Vector<String> arr = inputs_strings[i].split(",");
|
||||
if (arr[0].to_int() == p_id) {
|
||||
index += arr[0].size();
|
||||
count = arr[1].size() - 1;
|
||||
break;
|
||||
}
|
||||
index += inputs_strings[i].size();
|
||||
}
|
||||
|
||||
inputs.erase(index, count);
|
||||
|
||||
inputs = inputs.insert(index, itos(p_type));
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_type(int p_id) const {
|
||||
ERR_FAIL_COND_V(!input_ports.has(p_id), (PortType)0);
|
||||
return input_ports[p_id].type;
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_name) {
|
||||
|
||||
if (input_ports[p_id].name == p_name)
|
||||
return;
|
||||
|
||||
Vector<String> inputs_strings = inputs.split(";", false);
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < inputs_strings.size(); i++) {
|
||||
Vector<String> arr = inputs_strings[i].split(",");
|
||||
if (arr[0].to_int() == p_id) {
|
||||
index += arr[0].size() + arr[1].size();
|
||||
count = arr[2].size() - 1;
|
||||
break;
|
||||
}
|
||||
index += inputs_strings[i].size();
|
||||
}
|
||||
|
||||
inputs.erase(index, count);
|
||||
|
||||
inputs = inputs.insert(index, p_name);
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const {
|
||||
ERR_FAIL_COND_V(!input_ports.has(p_id), "");
|
||||
return input_ports[p_id].name;
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) {
|
||||
|
||||
if (output_ports[p_id].type == p_type)
|
||||
return;
|
||||
|
||||
Vector<String> output_strings = outputs.split(";", false);
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < output_strings.size(); i++) {
|
||||
Vector<String> arr = output_strings[i].split(",");
|
||||
if (arr[0].to_int() == p_id) {
|
||||
index += arr[0].size();
|
||||
count = arr[1].size() - 1;
|
||||
break;
|
||||
}
|
||||
index += output_strings[i].size();
|
||||
}
|
||||
|
||||
outputs.erase(index, count);
|
||||
|
||||
outputs = outputs.insert(index, itos(p_type));
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_type(int p_id) const {
|
||||
ERR_FAIL_COND_V(!output_ports.has(p_id), (PortType)0);
|
||||
return output_ports[p_id].type;
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_name) {
|
||||
if (output_ports[p_id].name == p_name)
|
||||
return;
|
||||
|
||||
Vector<String> output_strings = outputs.split(";", false);
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < output_strings.size(); i++) {
|
||||
Vector<String> arr = output_strings[i].split(",");
|
||||
if (arr[0].to_int() == p_id) {
|
||||
index += arr[0].size() + arr[1].size();
|
||||
count = arr[2].size() - 1;
|
||||
break;
|
||||
}
|
||||
index += output_strings[i].size();
|
||||
}
|
||||
|
||||
outputs.erase(index, count);
|
||||
|
||||
outputs = outputs.insert(index, p_name);
|
||||
|
||||
_apply_port_changes();
|
||||
}
|
||||
|
||||
String VisualShaderNodeGroupBase::get_output_port_name(int p_id) const {
|
||||
ERR_FAIL_COND_V(!output_ports.has(p_id), "");
|
||||
return output_ports[p_id].name;
|
||||
}
|
||||
|
||||
int VisualShaderNodeGroupBase::get_free_input_port_id() const {
|
||||
return input_ports.size();
|
||||
}
|
||||
|
||||
int VisualShaderNodeGroupBase::get_free_output_port_id() const {
|
||||
return output_ports.size();
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::set_control(Control *p_control, int p_index) {
|
||||
controls[p_index] = p_control;
|
||||
}
|
||||
|
||||
Control *VisualShaderNodeGroupBase::get_control(int p_index) {
|
||||
ERR_FAIL_COND_V(!controls.has(p_index), NULL);
|
||||
return controls[p_index];
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::_apply_port_changes() {
|
||||
|
||||
Vector<String> inputs_strings = inputs.split(";", false);
|
||||
Vector<String> outputs_strings = outputs.split(";", false);
|
||||
|
||||
clear_input_ports();
|
||||
clear_output_ports();
|
||||
|
||||
for (int i = 0; i < inputs_strings.size(); i++) {
|
||||
Vector<String> arr = inputs_strings[i].split(",");
|
||||
Port port;
|
||||
port.type = (PortType)arr[1].to_int();
|
||||
port.name = arr[2];
|
||||
input_ports[i] = port;
|
||||
}
|
||||
for (int i = 0; i < outputs_strings.size(); i++) {
|
||||
Vector<String> arr = outputs_strings[i].split(",");
|
||||
Port port;
|
||||
port.type = (PortType)arr[1].to_int();
|
||||
port.name = arr[2];
|
||||
output_ports[i] = port;
|
||||
}
|
||||
}
|
||||
|
||||
void VisualShaderNodeGroupBase::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size);
|
||||
ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeGroupBase::get_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_inputs", "inputs"), &VisualShaderNodeGroupBase::set_inputs);
|
||||
ClassDB::bind_method(D_METHOD("get_inputs"), &VisualShaderNodeGroupBase::get_inputs);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_outputs", "outputs"), &VisualShaderNodeGroupBase::set_outputs);
|
||||
ClassDB::bind_method(D_METHOD("get_outputs"), &VisualShaderNodeGroupBase::get_outputs);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_input_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_input_port);
|
||||
ClassDB::bind_method(D_METHOD("remove_input_port", "id"), &VisualShaderNodeGroupBase::remove_input_port);
|
||||
ClassDB::bind_method(D_METHOD("get_input_port_count"), &VisualShaderNodeGroupBase::get_input_port_count);
|
||||
ClassDB::bind_method(D_METHOD("has_input_port", "id"), &VisualShaderNodeGroupBase::has_input_port);
|
||||
ClassDB::bind_method(D_METHOD("clear_input_ports"), &VisualShaderNodeGroupBase::clear_input_ports);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_output_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_output_port);
|
||||
ClassDB::bind_method(D_METHOD("remove_output_port", "id"), &VisualShaderNodeGroupBase::remove_output_port);
|
||||
ClassDB::bind_method(D_METHOD("get_output_port_count"), &VisualShaderNodeGroupBase::get_output_port_count);
|
||||
ClassDB::bind_method(D_METHOD("has_output_port", "id"), &VisualShaderNodeGroupBase::has_output_port);
|
||||
ClassDB::bind_method(D_METHOD("clear_output_ports"), &VisualShaderNodeGroupBase::clear_output_ports);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_input_port_name"), &VisualShaderNodeGroupBase::set_input_port_name);
|
||||
ClassDB::bind_method(D_METHOD("set_input_port_type"), &VisualShaderNodeGroupBase::set_input_port_type);
|
||||
ClassDB::bind_method(D_METHOD("set_output_port_name"), &VisualShaderNodeGroupBase::set_output_port_name);
|
||||
ClassDB::bind_method(D_METHOD("set_output_port_type"), &VisualShaderNodeGroupBase::set_output_port_type);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id);
|
||||
ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_control", "control", "index"), &VisualShaderNodeGroupBase::set_control);
|
||||
ClassDB::bind_method(D_METHOD("get_control", "index"), &VisualShaderNodeGroupBase::get_control);
|
||||
}
|
||||
|
||||
String VisualShaderNodeGroupBase::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 {
|
||||
return "";
|
||||
}
|
||||
|
||||
VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() {
|
||||
size = Size2(0, 0);
|
||||
inputs = "";
|
||||
outputs = "";
|
||||
}
|
||||
|
||||
////////////// Expression
|
||||
|
||||
String VisualShaderNodeExpression::get_caption() const {
|
||||
return "Expression";
|
||||
}
|
||||
|
||||
void VisualShaderNodeExpression::set_expression(const String &p_expression) {
|
||||
expression = p_expression;
|
||||
}
|
||||
|
||||
void VisualShaderNodeExpression::build() {
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
String VisualShaderNodeExpression::get_expression() const {
|
||||
return expression;
|
||||
}
|
||||
|
||||
String VisualShaderNodeExpression::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 {
|
||||
|
||||
String _expression = expression;
|
||||
|
||||
_expression = _expression.insert(0, "\n");
|
||||
_expression = _expression.replace("\n", "\n\t\t");
|
||||
|
||||
static Vector<String> pre_symbols;
|
||||
if (pre_symbols.empty()) {
|
||||
pre_symbols.push_back("\t");
|
||||
pre_symbols.push_back("{");
|
||||
pre_symbols.push_back("[");
|
||||
pre_symbols.push_back("(");
|
||||
pre_symbols.push_back(" ");
|
||||
pre_symbols.push_back("-");
|
||||
pre_symbols.push_back("*");
|
||||
pre_symbols.push_back("/");
|
||||
pre_symbols.push_back("+");
|
||||
pre_symbols.push_back("=");
|
||||
pre_symbols.push_back("&");
|
||||
pre_symbols.push_back("|");
|
||||
pre_symbols.push_back("!");
|
||||
}
|
||||
|
||||
static Vector<String> post_symbols;
|
||||
if (post_symbols.empty()) {
|
||||
post_symbols.push_back("\t");
|
||||
post_symbols.push_back("\n");
|
||||
post_symbols.push_back("}");
|
||||
post_symbols.push_back("]");
|
||||
post_symbols.push_back(")");
|
||||
post_symbols.push_back(" ");
|
||||
post_symbols.push_back(".");
|
||||
post_symbols.push_back("-");
|
||||
post_symbols.push_back("*");
|
||||
post_symbols.push_back("/");
|
||||
post_symbols.push_back("+");
|
||||
post_symbols.push_back("=");
|
||||
post_symbols.push_back("&");
|
||||
post_symbols.push_back("|");
|
||||
post_symbols.push_back("!");
|
||||
}
|
||||
|
||||
for (int i = 0; i < get_input_port_count(); i++) {
|
||||
for (int j = 0; j < pre_symbols.size(); j++) {
|
||||
for (int k = 0; k < post_symbols.size(); k++) {
|
||||
_expression = _expression.replace(pre_symbols[j] + get_input_port_name(i) + post_symbols[k], pre_symbols[j] + p_input_vars[i] + post_symbols[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < get_output_port_count(); i++) {
|
||||
for (int j = 0; j < pre_symbols.size(); j++) {
|
||||
for (int k = 0; k < post_symbols.size(); k++) {
|
||||
_expression = _expression.replace(pre_symbols[j] + get_output_port_name(i) + post_symbols[k], pre_symbols[j] + p_output_vars[i] + post_symbols[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String output_initializer;
|
||||
|
||||
for (int i = 0; i < get_output_port_count(); i++) {
|
||||
int port_type = get_output_port_type(i);
|
||||
String tk = "";
|
||||
switch (port_type) {
|
||||
case PORT_TYPE_SCALAR:
|
||||
tk = "0.0";
|
||||
break;
|
||||
case PORT_TYPE_VECTOR:
|
||||
tk = "vec3(0.0, 0.0, 0.0)";
|
||||
break;
|
||||
case PORT_TYPE_BOOLEAN:
|
||||
tk = "false";
|
||||
break;
|
||||
case PORT_TYPE_TRANSFORM:
|
||||
tk = "mat4(1.0)";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
output_initializer += "\t" + p_output_vars[i] + "=" + tk + ";\n";
|
||||
}
|
||||
|
||||
String code;
|
||||
code += output_initializer;
|
||||
code += "\t{";
|
||||
code += _expression;
|
||||
code += "\n\t}";
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void VisualShaderNodeExpression::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_expression", "expression"), &VisualShaderNodeExpression::set_expression);
|
||||
ClassDB::bind_method(D_METHOD("get_expression"), &VisualShaderNodeExpression::get_expression);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("build"), &VisualShaderNodeExpression::build);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "expression"), "set_expression", "get_expression");
|
||||
}
|
||||
|
||||
VisualShaderNodeExpression::VisualShaderNodeExpression() {
|
||||
expression = "";
|
||||
}
|
||||
|
|
|
@ -135,7 +135,9 @@ public:
|
|||
bool can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
|
||||
Error connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
|
||||
void disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
|
||||
void connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
|
||||
|
||||
void rebuild();
|
||||
void get_node_connections(Type p_type, List<Connection> *r_connections) const;
|
||||
|
||||
void set_mode(Mode p_mode);
|
||||
|
@ -148,6 +150,7 @@ public:
|
|||
|
||||
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_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const;
|
||||
String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const;
|
||||
|
||||
VisualShader();
|
||||
|
@ -314,4 +317,93 @@ public:
|
|||
VisualShaderNodeUniform();
|
||||
};
|
||||
|
||||
class VisualShaderNodeGroupBase : public VisualShaderNode {
|
||||
GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode)
|
||||
private:
|
||||
void _apply_port_changes();
|
||||
|
||||
protected:
|
||||
Vector2 size;
|
||||
String inputs;
|
||||
String outputs;
|
||||
|
||||
struct Port {
|
||||
PortType type;
|
||||
String name;
|
||||
};
|
||||
|
||||
Map<int, Port> input_ports;
|
||||
Map<int, Port> output_ports;
|
||||
Map<int, Control *> controls;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual String get_caption() const;
|
||||
|
||||
void set_size(const Vector2 &p_size);
|
||||
Vector2 get_size() const;
|
||||
|
||||
void set_inputs(const String &p_inputs);
|
||||
String get_inputs() const;
|
||||
|
||||
void set_outputs(const String &p_outputs);
|
||||
String get_outputs() const;
|
||||
|
||||
void add_input_port(int p_id, int p_type, const String &p_name);
|
||||
void remove_input_port(int p_id);
|
||||
virtual int get_input_port_count() const;
|
||||
bool has_input_port(int p_id) const;
|
||||
void clear_input_ports();
|
||||
|
||||
void add_output_port(int p_id, int p_type, const String &p_name);
|
||||
void remove_output_port(int p_id);
|
||||
virtual int get_output_port_count() const;
|
||||
bool has_output_port(int p_id) const;
|
||||
void clear_output_ports();
|
||||
|
||||
void set_input_port_type(int p_id, int p_type);
|
||||
virtual PortType get_input_port_type(int p_id) const;
|
||||
void set_input_port_name(int p_id, const String &p_name);
|
||||
virtual String get_input_port_name(int p_id) const;
|
||||
|
||||
void set_output_port_type(int p_id, int p_type);
|
||||
virtual PortType get_output_port_type(int p_id) const;
|
||||
void set_output_port_name(int p_id, const String &p_name);
|
||||
virtual String get_output_port_name(int p_id) const;
|
||||
|
||||
int get_free_input_port_id() const;
|
||||
int get_free_output_port_id() const;
|
||||
|
||||
void set_control(Control *p_control, int p_index);
|
||||
Control *get_control(int p_index);
|
||||
|
||||
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;
|
||||
|
||||
VisualShaderNodeGroupBase();
|
||||
};
|
||||
|
||||
class VisualShaderNodeExpression : public VisualShaderNodeGroupBase {
|
||||
GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase)
|
||||
|
||||
private:
|
||||
String expression;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual String get_caption() const;
|
||||
|
||||
void set_expression(const String &p_expression);
|
||||
String get_expression() const;
|
||||
|
||||
void build();
|
||||
|
||||
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;
|
||||
|
||||
VisualShaderNodeExpression();
|
||||
};
|
||||
|
||||
#endif // VISUAL_SHADER_H
|
||||
|
|
Loading…
Reference in a new issue