diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/2d/camera_2d.cpp | 9 | ||||
-rw-r--r-- | scene/3d/skeleton_ik_3d.cpp | 15 | ||||
-rw-r--r-- | scene/3d/skeleton_ik_3d.h | 4 | ||||
-rw-r--r-- | scene/gui/color_picker.cpp | 2 | ||||
-rw-r--r-- | scene/gui/rich_text_label.cpp | 41 | ||||
-rw-r--r-- | scene/gui/rich_text_label.h | 2 | ||||
-rw-r--r-- | scene/gui/tree.cpp | 99 | ||||
-rw-r--r-- | scene/gui/tree.h | 8 | ||||
-rw-r--r-- | scene/resources/default_theme/default_theme.cpp | 6 | ||||
-rw-r--r-- | scene/resources/sky_material.cpp | 2 | ||||
-rw-r--r-- | scene/resources/visual_shader.cpp | 147 | ||||
-rw-r--r-- | scene/resources/visual_shader.h | 8 | ||||
-rw-r--r-- | scene/resources/visual_shader_nodes.cpp | 28 | ||||
-rw-r--r-- | scene/resources/visual_shader_nodes.h | 4 |
14 files changed, 310 insertions, 65 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 01045502d5..ca4b8d72a1 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -270,11 +270,10 @@ void Camera2D::_notification(int p_what) { } if (screen_drawing_enabled) { - Color area_axis_color(0.5, 0.42, 0.87, 0.63); + Color area_axis_color(1, 0.4, 1, 0.63); real_t area_axis_width = 1; if (is_current()) { area_axis_width = 3; - area_axis_color.a = 0.83; } Transform2D inv_camera_transform = get_camera_transform().affine_inverse(); @@ -295,10 +294,9 @@ void Camera2D::_notification(int p_what) { } if (limit_drawing_enabled) { - Color limit_drawing_color(1, 1, 0, 0.63); + Color limit_drawing_color(1, 1, 0.25, 0.63); real_t limit_drawing_width = 1; if (is_current()) { - limit_drawing_color.a = 0.83; limit_drawing_width = 3; } @@ -317,11 +315,10 @@ void Camera2D::_notification(int p_what) { } if (margin_drawing_enabled) { - Color margin_drawing_color(0, 1, 1, 0.63); + Color margin_drawing_color(0.25, 1, 1, 0.63); real_t margin_drawing_width = 1; if (is_current()) { margin_drawing_width = 3; - margin_drawing_color.a = 0.83; } Transform2D inv_camera_transform = get_camera_transform().affine_inverse(); diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index bd1c202205..294e313300 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -129,7 +129,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain return true; } -void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) { +void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet, Vector3 p_origin_pos) { real_t distance_to_goal(1e4); real_t previous_distance_to_goal(0); int can_solve(p_task->max_iterations); @@ -138,7 +138,7 @@ void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) { --can_solve; solve_simple_backwards(p_task->chain, p_solve_magnet); - solve_simple_forwards(p_task->chain, p_solve_magnet); + solve_simple_forwards(p_task->chain, p_solve_magnet, p_origin_pos); distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length(); } @@ -176,13 +176,13 @@ void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve } } -void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) { +void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos) { if (p_solve_magnet && !r_chain.middle_chain_item) { return; } ChainItem *sub_chain_root(&r_chain.chain_root); - Vector3 origin(r_chain.chain_root.initial_transform.origin); + Vector3 origin = p_origin_pos; while (sub_chain_root) { // Reach the tip sub_chain_root->current_pos = origin; @@ -273,13 +273,16 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove // Update the initial root transform so its synced with any animation changes _update_chain(p_task->skeleton, &p_task->chain.chain_root); + p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform(), 0.0, false); + Vector3 origin_pos = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone).origin; + make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta); if (p_use_magnet && p_task->chain.middle_chain_item) { p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.lerp(p_magnet_position, blending_delta); - solve_simple(p_task, true); + solve_simple(p_task, true, origin_pos); } - solve_simple(p_task, false); + solve_simple(p_task, false, origin_pos); // Assign new bone position. ChainItem *ci(&p_task->chain.chain_root); diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h index 9255e18b72..9b5ae240f6 100644 --- a/scene/3d/skeleton_ik_3d.h +++ b/scene/3d/skeleton_ik_3d.h @@ -106,10 +106,10 @@ private: /// Init a chain that starts from the root to tip static bool build_chain(Task *p_task, bool p_force_simple_chain = true); - static void solve_simple(Task *p_task, bool p_solve_magnet); + static void solve_simple(Task *p_task, bool p_solve_magnet, Vector3 p_origin_pos); /// Special solvers that solve only chains with one end effector static void solve_simple_backwards(Chain &r_chain, bool p_solve_magnet); - static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet); + static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos); public: static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 9ccb2886e1..c0b4563615 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -91,7 +91,6 @@ void ColorPicker::init_shaders() { wheel_shader.instance(); wheel_shader->set_code( "shader_type canvas_item;" - "const float TAU = 6.28318530718;" "void fragment() {" " float x = UV.x - 0.5;" " float y = UV.y - 0.5;" @@ -111,7 +110,6 @@ void ColorPicker::init_shaders() { circle_shader.instance(); circle_shader->set_code( "shader_type canvas_item;" - "const float TAU = 6.28318530718;" "uniform float v = 1.0;" "void fragment() {" " float x = UV.x - 0.5;" diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 9ed4c937f4..a2c3b4ed8a 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2232,18 +2232,22 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub int size = p_item->subitems.size(); if (size == 0) { p_item->parent->subitems.erase(p_item); + // If a newline was erased, all lines AFTER the newline need to be decremented. if (p_item->type == ITEM_NEWLINE) { current_frame->lines.remove(p_line); - for (int i = p_subitem_line; i < current->subitems.size(); i++) { - if (current->subitems[i]->line > 0) { + for (int i = 0; i < current->subitems.size(); i++) { + if (current->subitems[i]->line > p_subitem_line) { current->subitems[i]->line--; } } } } else { + // First, remove all child items for the provided item. for (int i = 0; i < size; i++) { _remove_item(p_item->subitems.front()->get(), p_line, p_subitem_line); } + // Then remove the provided item itself. + p_item->parent->subitems.erase(p_item); } } @@ -2303,21 +2307,23 @@ bool RichTextLabel::remove_line(const int p_line) { return false; } - int i = 0; - while (i < current->subitems.size() && current->subitems[i]->line < p_line) { - i++; + // Remove all subitems with the same line as that provided. + Vector<int> subitem_indices_to_remove; + for (int i = 0; i < current->subitems.size(); i++) { + if (current->subitems[i]->line == p_line) { + subitem_indices_to_remove.push_back(i); + } } - bool was_newline = false; - while (i < current->subitems.size()) { - was_newline = current->subitems[i]->type == ITEM_NEWLINE; - _remove_item(current->subitems[i], current->subitems[i]->line, p_line); - if (was_newline) { - break; - } + bool had_newline = false; + // Reverse for loop to remove items from the end first. + for (int i = subitem_indices_to_remove.size() - 1; i >= 0; i--) { + int subitem_idx = subitem_indices_to_remove[i]; + had_newline = had_newline || current->subitems[subitem_idx]->type == ITEM_NEWLINE; + _remove_item(current->subitems[subitem_idx], current->subitems[subitem_idx]->line, p_line); } - if (!was_newline) { + if (!had_newline) { current_frame->lines.remove(p_line); if (current_frame->lines.size() == 0) { current_frame->lines.resize(1); @@ -2329,6 +2335,7 @@ bool RichTextLabel::remove_line(const int p_line) { } main->first_invalid_line = 0; // p_line ??? + update(); return true; } @@ -2613,14 +2620,6 @@ void RichTextLabel::pop() { current = current->parent; } -// Creates a new line without adding an ItemNewline to the previous line. -// Useful when wanting to calling remove_line and add a new line immediately after. -void RichTextLabel::increment_line_count() { - _validate_line_caches(main); - current_frame->lines.resize(current_frame->lines.size() + 1); - _invalidate_current_line(current_frame); -} - void RichTextLabel::clear() { main->_clear_children(); current = main; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index afc88e070a..e3e457d1f2 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -483,8 +483,6 @@ public: void push_cell(); void pop(); - void increment_line_count(); - void clear(); void set_offset(int p_pixel); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 927dce7988..d2b98eb0fa 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1184,15 +1184,23 @@ void Tree::update_cache() { cache.font_color = get_theme_color("font_color"); cache.font_selected_color = get_theme_color("font_selected_color"); - cache.guide_color = get_theme_color("guide_color"); cache.drop_position_color = get_theme_color("drop_position_color"); cache.hseparation = get_theme_constant("hseparation"); cache.vseparation = get_theme_constant("vseparation"); cache.item_margin = get_theme_constant("item_margin"); cache.button_margin = get_theme_constant("button_margin"); + cache.draw_guides = get_theme_constant("draw_guides"); + cache.guide_color = get_theme_color("guide_color"); cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines"); + cache.relationship_line_width = get_theme_constant("relationship_line_width"); + cache.parent_hl_line_width = get_theme_constant("parent_hl_line_width"); + cache.children_hl_line_width = get_theme_constant("children_hl_line_width"); + cache.parent_hl_line_margin = get_theme_constant("parent_hl_line_margin"); cache.relationship_line_color = get_theme_color("relationship_line_color"); + cache.parent_hl_line_color = get_theme_color("parent_hl_line_color"); + cache.children_hl_line_color = get_theme_color("children_hl_line_color"); + cache.scroll_border = get_theme_constant("scroll_border"); cache.scroll_speed = get_theme_constant("scroll_speed"); @@ -1813,38 +1821,79 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 TreeItem *c = p_item->first_child; - int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y; + int base_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y; + int prev_ofs = base_ofs; + int prev_hl_ofs = base_ofs; while (c) { if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); - int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); + int parent_ofs = p_pos.x + cache.item_margin; Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; if (c->get_first_child() != nullptr) { root_pos -= Point2i(cache.arrow->get_width(), 0); } - float line_width = 1.0; + float line_width = cache.relationship_line_width; + float parent_line_width = cache.parent_hl_line_width; + float children_line_width = cache.children_hl_line_width; + #ifdef TOOLS_ENABLED line_width *= Math::round(EDSCALE); + parent_line_width *= Math::round(EDSCALE); + children_line_width *= Math::round(EDSCALE); #endif Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; + int more_prev_ofs = 0; + if (root_pos.y + line_width >= 0) { if (rtl) { root_pos.x = get_size().width - root_pos.x; parent_pos.x = get_size().width - parent_pos.x; } - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), Point2i(parent_pos.x, prev_ofs), cache.relationship_line_color, line_width); + + // Order of parts on this bend: the horizontal line first, then the vertical line. + if (_is_branch_selected(c)) { + // If this item or one of its children is selected, we draw the line using parent highlight style. + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + + more_prev_ofs = cache.parent_hl_line_margin; + prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); + } else if (p_item->is_selected(0)) { + // If parent item is selected (but this item is not), we draw the line using children highlight style. + // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. + if (_is_sibling_branch_selected(c)) { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + + prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); + } else { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width); + } + } else { + // If nothing of the above is true, we draw the line using normal style. + // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. + if (_is_sibling_branch_selected(c)) { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + + prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); + } else { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width); + } + } } if (htotal < 0) { return -1; } - prev_ofs = root_pos.y; + prev_ofs = root_pos.y + more_prev_ofs; } if (htotal >= 0) { @@ -1853,10 +1902,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (child_h < 0) { if (cache.draw_relationship_lines == 0) { return -1; // break, stop drawing, no need to anymore - } else { - htotal = -1; - children_pos.y = cache.offset.y + p_draw_size.height; } + + htotal = -1; + children_pos.y = cache.offset.y + p_draw_size.height; } else { htotal += child_h; children_pos.y += child_h; @@ -1889,6 +1938,36 @@ int Tree::_count_selected_items(TreeItem *p_from) const { return count; } +bool Tree::_is_branch_selected(TreeItem *p_from) const { + for (int i = 0; i < columns.size(); i++) { + if (p_from->is_selected(i)) { + return true; + } + } + + TreeItem *child_item = p_from->get_first_child(); + while (child_item) { + if (_is_branch_selected(child_item)) { + return true; + } + child_item = child_item->get_next(); + } + + return false; +} + +bool Tree::_is_sibling_branch_selected(TreeItem *p_from) const { + TreeItem *sibling_item = p_from->get_next(); + while (sibling_item) { + if (_is_branch_selected(sibling_item)) { + return true; + } + sibling_item = sibling_item->get_next(); + } + + return false; +} + void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) { TreeItem::Cell &selected_cell = p_selected->cells.write[p_col]; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 9dbfd93082..c0948f1b80 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -494,6 +494,8 @@ private: Color guide_color; Color drop_position_color; Color relationship_line_color; + Color parent_hl_line_color; + Color children_hl_line_color; Color custom_button_font_highlight; int hseparation = 0; @@ -502,6 +504,10 @@ private: int button_margin = 0; Point2 offset; int draw_relationship_lines = 0; + int relationship_line_width = 0; + int parent_hl_line_width = 0; + int children_hl_line_width = 0; + int parent_hl_line_margin = 0; int draw_guides = 0; int scroll_border = 0; int scroll_speed = 0; @@ -574,6 +580,8 @@ private: bool hide_folding = false; int _count_selected_items(TreeItem *p_from) const; + bool _is_branch_selected(TreeItem *p_from) const; + bool _is_sibling_branch_selected(TreeItem *p_from) const; void _go_left(); void _go_right(); void _go_down(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 6e67daf15f..3a5b3534c6 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -719,6 +719,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1)); theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); + theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27)); + theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27)); theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color); theme->set_constant("hseparation", "Tree", 4 * scale); @@ -726,6 +728,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("item_margin", "Tree", 12 * scale); theme->set_constant("button_margin", "Tree", 4 * scale); theme->set_constant("draw_relationship_lines", "Tree", 0); + theme->set_constant("relationship_line_width", "Tree", 1); + theme->set_constant("parent_hl_line_width", "Tree", 1); + theme->set_constant("children_hl_line_width", "Tree", 1); + theme->set_constant("parent_hl_line_margin", "Tree", 0); theme->set_constant("draw_guides", "Tree", 1); theme->set_constant("scroll_border", "Tree", 4); theme->set_constant("scroll_speed", "Tree", 12); diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index f50ee9c4c8..9d79c22159 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -193,7 +193,6 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { code += "uniform float ground_energy = 1.0;\n\n"; code += "uniform float sun_angle_max = 1.74;\n"; code += "uniform float sun_curve : hint_range(0, 1) = 0.05;\n\n"; - code += "const float PI = 3.1415926535897932384626433833;\n\n"; code += "void sky() {\n"; code += "\tfloat v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));\n"; code += "\tfloat c = (1.0 - v_angle / (PI * 0.5));\n"; @@ -499,7 +498,6 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { code += "uniform sampler2D night_sky : hint_black;"; - code += "const float PI = 3.141592653589793238462643383279502884197169;\n"; code += "const vec3 UP = vec3( 0.0, 1.0, 0.0 );\n\n"; code += "// Sun constants\n"; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index da29f2ebd8..5ac1ad935e 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -94,6 +94,52 @@ bool VisualShaderNode::is_generate_input_var(int p_port) const { return true; } +bool VisualShaderNode::is_output_port_expandable(int p_port) const { + return false; +} + +void VisualShaderNode::_set_output_ports_expanded(const Array &p_values) { + for (int i = 0; i < p_values.size(); i++) { + expanded_output_ports[p_values[i]] = true; + } + emit_changed(); +} + +Array VisualShaderNode::_get_output_ports_expanded() const { + Array arr; + for (int i = 0; i < get_output_port_count(); i++) { + if (_is_output_port_expanded(i)) { + arr.push_back(i); + } + } + return arr; +} + +void VisualShaderNode::_set_output_port_expanded(int p_port, bool p_expanded) { + expanded_output_ports[p_port] = p_expanded; + emit_changed(); +} + +bool VisualShaderNode::_is_output_port_expanded(int p_port) const { + if (expanded_output_ports.has(p_port)) { + return expanded_output_ports[p_port]; + } + return false; +} + +int VisualShaderNode::get_expanded_output_port_count() const { + int count = get_output_port_count(); + int count2 = count; + for (int i = 0; i < count; i++) { + if (is_output_port_expandable(i) && _is_output_port_expanded(i)) { + if (get_output_port_type(i) == PORT_TYPE_VECTOR) { + count2 += 3; + } + } + } + return count2; +} + bool VisualShaderNode::is_code_generated() const { return true; } @@ -157,6 +203,12 @@ void VisualShaderNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_output_port_for_preview", "port"), &VisualShaderNode::set_output_port_for_preview); ClassDB::bind_method(D_METHOD("get_output_port_for_preview"), &VisualShaderNode::get_output_port_for_preview); + ClassDB::bind_method(D_METHOD("_set_output_port_expanded", "port"), &VisualShaderNode::_set_output_port_expanded); + ClassDB::bind_method(D_METHOD("_is_output_port_expanded"), &VisualShaderNode::_is_output_port_expanded); + + ClassDB::bind_method(D_METHOD("_set_output_ports_expanded", "values"), &VisualShaderNode::_set_output_ports_expanded); + ClassDB::bind_method(D_METHOD("_get_output_ports_expanded"), &VisualShaderNode::_get_output_ports_expanded); + ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value); ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value); @@ -165,6 +217,7 @@ 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::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded"); ADD_SIGNAL(MethodInfo("editor_refresh_request")); BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR); @@ -576,7 +629,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po return false; } - if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_output_port_count()) { + if (p_from_port < 0 || p_from_port >= g->nodes[p_from_node].node->get_expanded_output_port_count()) { return false; } @@ -617,7 +670,7 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from Graph *g = &graph[p_type]; ERR_FAIL_COND(!g->nodes.has(p_from_node)); - ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_output_port_count()); + ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count()); ERR_FAIL_COND(!g->nodes.has(p_to_node)); ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count()); @@ -639,7 +692,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, Graph *g = &graph[p_type]; ERR_FAIL_COND_V(!g->nodes.has(p_from_node), ERR_INVALID_PARAMETER); - ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_output_port_count(), ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_from_port, g->nodes[p_from_node].node->get_expanded_output_port_count(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(!g->nodes.has(p_to_node), ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_to_port, g->nodes[p_to_node].node->get_input_port_count(), ERR_INVALID_PARAMETER); @@ -790,7 +843,7 @@ bool VisualShader::is_text_shader() const { String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &default_tex_params) const { Ref<VisualShaderNode> node = get_node(p_type, p_node); ERR_FAIL_COND_V(!node.is_valid(), String()); - ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_output_port_count(), String()); + ERR_FAIL_COND_V(p_port < 0 || p_port >= node->get_expanded_output_port_count(), String()); ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String()); StringBuilder global_code; @@ -1362,13 +1415,30 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } int output_count = vsnode->get_output_port_count(); + int initial_output_count = output_count; + + Map<int, bool> expanded_output_ports; + + for (int i = 0; i < initial_output_count; i++) { + bool expanded = false; + + if (vsnode->is_output_port_expandable(i) && vsnode->_is_output_port_expanded(i)) { + expanded = true; + + if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { + output_count += 3; + } + } + expanded_output_ports.insert(i, expanded); + } + Vector<String> output_vars; - output_vars.resize(vsnode->get_output_port_count()); + output_vars.resize(output_count); String *outputs = output_vars.ptrw(); if (vsnode->is_simple_decl()) { // less code to generate for some simple_decl nodes - for (int i = 0; i < output_count; i++) { - String var_name = "n_out" + itos(node) + "p" + itos(i); + for (int i = 0, j = 0; i < initial_output_count; i++, j++) { + String var_name = "n_out" + itos(node) + "p" + itos(j); switch (vsnode->get_output_port_type(i)) { case VisualShaderNode::PORT_TYPE_SCALAR: outputs[i] = "float " + var_name; @@ -1388,35 +1458,84 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui default: { } } + if (expanded_output_ports[i]) { + if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { + j += 3; + } + } } } else { - for (int i = 0; i < output_count; i++) { - outputs[i] = "n_out" + itos(node) + "p" + itos(i); + for (int i = 0, j = 0; i < initial_output_count; i++, j++) { + outputs[i] = "n_out" + itos(node) + "p" + itos(j); switch (vsnode->get_output_port_type(i)) { case VisualShaderNode::PORT_TYPE_SCALAR: - code += String() + "\tfloat " + outputs[i] + ";\n"; + code += "\tfloat " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_SCALAR_INT: - code += String() + "\tint " + outputs[i] + ";\n"; + code += "\tint " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_VECTOR: - code += String() + "\tvec3 " + outputs[i] + ";\n"; + code += "\tvec3 " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_BOOLEAN: - code += String() + "\tbool " + outputs[i] + ";\n"; + code += "\tbool " + outputs[i] + ";\n"; break; case VisualShaderNode::PORT_TYPE_TRANSFORM: - code += String() + "\tmat4 " + outputs[i] + ";\n"; + code += "\tmat4 " + outputs[i] + ";\n"; break; default: { } } + if (expanded_output_ports[i]) { + if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { + j += 3; + } + } } } code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); + for (int i = 0; i < output_count; i++) { + bool new_line_inserted = false; + if (expanded_output_ports[i]) { + if (vsnode->get_output_port_type(i) == VisualShaderNode::PORT_TYPE_VECTOR) { + if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String r = "n_out" + itos(node) + "p" + itos(i + 1); + code += "\tfloat " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n"; + outputs[i + 1] = r; + } + + if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String g = "n_out" + itos(node) + "p" + itos(i + 2); + code += "\tfloat " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n"; + outputs[i + 2] = g; + } + + if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component + if (!new_line_inserted) { + code += "\n"; + new_line_inserted = true; + } + String b = "n_out" + itos(node) + "p" + itos(i + 3); + code += "\tfloat " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n"; + outputs[i + 3] = b; + } + + i += 3; + } + } + } + code += "\n"; // processed.insert(node); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 841672294e..cc9a867e64 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -199,6 +199,7 @@ class VisualShaderNode : public Resource { Map<int, Variant> default_input_values; Map<int, bool> connected_input_ports; Map<int, int> connected_output_ports; + Map<int, bool> expanded_output_ports; protected: bool simple_decl = true; @@ -245,6 +246,13 @@ public: void set_input_port_connected(int p_port, bool p_connected); virtual bool is_generate_input_var(int p_port) const; + virtual bool is_output_port_expandable(int p_port) const; + void _set_output_ports_expanded(const Array &p_data); + Array _get_output_ports_expanded() const; + void _set_output_port_expanded(int p_port, bool p_expanded); + bool _is_output_port_expanded(int p_port) const; + int get_expanded_output_port_count() const; + virtual bool is_code_generated() const; virtual bool is_show_prop_names() const; virtual bool is_use_prop_slots() const; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index c2a6ad72d7..314333158c 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -242,6 +242,13 @@ String VisualShaderNodeColorConstant::get_output_port_name(int p_port) const { return p_port == 0 ? "" : "alpha"; //no output port means the editor will be used as port } +bool VisualShaderNodeColorConstant::is_output_port_expandable(int p_port) const { + if (p_port == 0) { + return true; + } + return false; +} + String VisualShaderNodeColorConstant::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 code; code += "\t" + p_output_vars[0] + " = " + vformat("vec3(%.6f, %.6f, %.6f)", constant.r, constant.g, constant.b) + ";\n"; @@ -455,6 +462,13 @@ String VisualShaderNodeTexture::get_output_port_name(int p_port) const { return p_port == 0 ? "rgb" : "alpha"; } +bool VisualShaderNodeTexture::is_output_port_expandable(int p_port) const { + if (p_port == 0) { + return true; + } + return false; +} + String VisualShaderNodeTexture::get_input_port_default_hint(int p_port) const { if (p_port == 0) { return "default"; @@ -917,6 +931,13 @@ String VisualShaderNodeSample3D::get_output_port_name(int p_port) const { return p_port == 0 ? "rgb" : "alpha"; } +bool VisualShaderNodeSample3D::is_output_port_expandable(int p_port) const { + if (p_port == 0) { + return true; + } + return false; +} + String VisualShaderNodeSample3D::get_input_port_default_hint(int p_port) const { if (p_port == 0) { return "default"; @@ -1168,6 +1189,13 @@ String VisualShaderNodeCubemap::get_output_port_name(int p_port) const { return p_port == 0 ? "rgb" : "alpha"; } +bool VisualShaderNodeCubemap::is_output_port_expandable(int p_port) const { + if (p_port == 0) { + return true; + } + return false; +} + Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCubemap::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { VisualShader::DefaultTextureParam dtp; dtp.name = make_unique_id(p_type, p_id, "cube"); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index d3397fad6f..50329d122d 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -163,6 +163,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool is_output_port_expandable(int p_port) const override; 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; @@ -275,6 +276,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool is_output_port_expandable(int p_port) const override; virtual String get_input_port_default_hint(int p_port) const override; @@ -359,6 +361,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool is_output_port_expandable(int p_port) const override; 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; @@ -452,6 +455,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool is_output_port_expandable(int p_port) const override; virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; |