Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_node/node_add.cc')
-rw-r--r--source/blender/editors/space_node/node_add.cc315
1 files changed, 124 insertions, 191 deletions
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 975d4eda7e3..9949037479e 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -5,6 +5,8 @@
* \ingroup spnode
*/
+#include <numeric>
+
#include "MEM_guardedalloc.h"
#include "DNA_collection_types.h"
@@ -20,6 +22,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -49,29 +52,48 @@ namespace blender::ed::space_node {
/** \name Utilities
* \{ */
-bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy)
+static void position_node_based_on_mouse(bNode &node, const float2 &location)
+{
+ node.locx = location.x - NODE_DY * 1.5f / UI_DPI_FAC;
+ node.locy = location.y + NODE_DY * 0.5f / UI_DPI_FAC;
+}
+
+bNode *add_node(const bContext &C, const StringRef idname, const float2 &location)
{
SpaceNode &snode = *CTX_wm_space_node(&C);
Main &bmain = *CTX_data_main(&C);
- bNode *node = nullptr;
node_deselect_all(snode);
- if (idname) {
- node = nodeAddNode(&C, snode.edittree, idname);
- }
- else {
- node = nodeAddStaticNode(&C, snode.edittree, type);
- }
+ const std::string idname_str = idname;
+
+ bNode *node = nodeAddNode(&C, snode.edittree, idname_str.c_str());
BLI_assert(node && node->typeinfo);
- /* Position mouse in node header. */
- node->locx = locx - NODE_DY * 1.5f / UI_DPI_FAC;
- node->locy = locy + NODE_DY * 0.5f / UI_DPI_FAC;
+ position_node_based_on_mouse(*node, location);
nodeSetSelected(node, true);
+ ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
+ ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
+ return node;
+}
+
+bNode *add_static_node(const bContext &C, int type, const float2 &location)
+{
+ SpaceNode &snode = *CTX_wm_space_node(&C);
+ Main &bmain = *CTX_data_main(&C);
+
+ node_deselect_all(snode);
+
+ bNode *node = nodeAddStaticNode(&C, snode.edittree, type);
+ BLI_assert(node && node->typeinfo);
+
+ position_node_based_on_mouse(*node, location);
+
+ nodeSetSelected(node, true);
ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
+
ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
return node;
}
@@ -82,191 +104,113 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx
/** \name Add Reroute Operator
* \{ */
-static bool add_reroute_intersect_check(const bNodeLink &link,
- float mcoords[][2],
- int tot,
- float result[2])
+std::optional<float2> link_path_intersection(const bNodeLink &link, const Span<float2> path)
{
- float coord_array[NODE_LINK_RESOL + 1][2];
-
- if (node_link_bezier_points(nullptr, nullptr, link, coord_array, NODE_LINK_RESOL)) {
- for (int i = 0; i < tot - 1; i++) {
- for (int b = 0; b < NODE_LINK_RESOL; b++) {
- if (isect_seg_seg_v2_point(
- mcoords[i], mcoords[i + 1], coord_array[b], coord_array[b + 1], result) > 0) {
- return true;
- }
+ std::array<float2, NODE_LINK_RESOL + 1> coords;
+ node_link_bezier_points_evaluated(link, coords);
+
+ for (const int i : path.index_range().drop_back(1)) {
+ for (const int j : IndexRange(NODE_LINK_RESOL)) {
+ float2 result;
+ if (isect_seg_seg_v2_point(path[i], path[i + 1], coords[j], coords[j + 1], result) > 0) {
+ return result;
}
}
}
- return false;
-}
-struct bNodeSocketLink {
- struct bNodeSocketLink *next, *prev;
+ return std::nullopt;
+}
- struct bNodeSocket *sock;
- struct bNodeLink *link;
- float point[2];
+struct RerouteCutsForSocket {
+ /* The output socket's owner node. */
+ bNode *from_node;
+ /* Intersected links connected to the socket and their path intersection locations. */
+ Map<bNodeLink *, float2> links;
};
-static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
- bNodeSocket *sock,
- bNodeLink *link,
- const float point[2])
+static int add_reroute_exec(bContext *C, wmOperator *op)
{
- bNodeSocketLink *socklink, *prev;
-
- socklink = MEM_cnew<bNodeSocketLink>("socket link");
- socklink->sock = sock;
- socklink->link = link;
- copy_v2_v2(socklink->point, point);
+ const ARegion &region = *CTX_wm_region(C);
+ SpaceNode &snode = *CTX_wm_space_node(C);
+ bNodeTree &ntree = *snode.edittree;
- for (prev = (bNodeSocketLink *)lb->last; prev; prev = prev->prev) {
- if (prev->sock == sock) {
+ Vector<float2> path;
+ RNA_BEGIN (op->ptr, itemptr, "path") {
+ float2 loc_region;
+ RNA_float_get_array(&itemptr, "loc", loc_region);
+ float2 loc_view;
+ UI_view2d_region_to_view(&region.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y);
+ path.append(loc_view);
+ if (path.size() >= 256) {
break;
}
}
- BLI_insertlinkafter(lb, prev, socklink);
- return socklink;
-}
-
-static bNodeSocketLink *add_reroute_do_socket_section(bContext *C,
- bNodeSocketLink *socklink,
- int in_out)
-{
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- bNode *reroute_node = nullptr;
- bNodeSocket *cursock = socklink->sock;
- float insert_point[2];
- int num_links;
-
- zero_v2(insert_point);
- num_links = 0;
-
- while (socklink && socklink->sock == cursock) {
- if (!(socklink->link->flag & NODE_LINK_TEST)) {
- socklink->link->flag |= NODE_LINK_TEST;
-
- /* create the reroute node for this cursock */
- if (!reroute_node) {
- reroute_node = nodeAddStaticNode(C, ntree, NODE_REROUTE);
-
- /* add a single link to/from the reroute node to replace multiple links */
- if (in_out == SOCK_OUT) {
- nodeAddLink(ntree,
- socklink->link->fromnode,
- socklink->link->fromsock,
- reroute_node,
- (bNodeSocket *)reroute_node->inputs.first);
- }
- else {
- nodeAddLink(ntree,
- reroute_node,
- (bNodeSocket *)reroute_node->outputs.first,
- socklink->link->tonode,
- socklink->link->tosock);
- }
- }
-
- /* insert the reroute node into the link */
- if (in_out == SOCK_OUT) {
- socklink->link->fromnode = reroute_node;
- socklink->link->fromsock = (bNodeSocket *)reroute_node->outputs.first;
- }
- else {
- socklink->link->tonode = reroute_node;
- socklink->link->tosock = (bNodeSocket *)reroute_node->inputs.first;
- }
-
- add_v2_v2(insert_point, socklink->point);
- num_links++;
- }
- socklink = socklink->next;
- }
-
- if (num_links > 0) {
- /* average cut point from shared links */
- mul_v2_fl(insert_point, 1.0f / num_links);
+ RNA_END;
- reroute_node->locx = insert_point[0] / UI_DPI_FAC;
- reroute_node->locy = insert_point[1] / UI_DPI_FAC;
+ if (path.is_empty()) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- return socklink;
-}
+ ntree.ensure_topology_cache();
+ const Vector<bNode *> frame_nodes = ntree.nodes_by_type("NodeFrame");
-static int add_reroute_exec(bContext *C, wmOperator *op)
-{
- SpaceNode &snode = *CTX_wm_space_node(C);
- ARegion &region = *CTX_wm_region(C);
- bNodeTree &ntree = *snode.edittree;
- float mcoords[256][2];
- int i = 0;
+ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+ node_deselect_all(snode);
- /* Get the cut path */
- RNA_BEGIN (op->ptr, itemptr, "path") {
- float loc[2];
+ /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per
+ * output socket is useful because it allows reusing reroutes for connected intersections.
+ * Further deduplication using the second map means we only have one cut per link. */
+ Map<bNodeSocket *, RerouteCutsForSocket> cuts_per_socket;
- RNA_float_get_array(&itemptr, "loc", loc);
- UI_view2d_region_to_view(
- &region.v2d, (short)loc[0], (short)loc[1], &mcoords[i][0], &mcoords[i][1]);
- i++;
- if (i >= 256) {
- break;
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
+ continue;
+ }
+ const std::optional<float2> intersection = link_path_intersection(*link, path);
+ if (!intersection) {
+ continue;
}
+ RerouteCutsForSocket &from_cuts = cuts_per_socket.lookup_or_add_default(link->fromsock);
+ from_cuts.from_node = link->fromnode;
+ from_cuts.links.add(link, *intersection);
}
- RNA_END;
-
- if (i > 1) {
- ListBase output_links, input_links;
- bNodeSocketLink *socklink;
- float insert_point[2];
- /* always first */
- ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
+ for (const auto item : cuts_per_socket.items()) {
+ const Map<bNodeLink *, float2> &cuts = item.value.links;
- node_deselect_all(snode);
+ bNode *reroute = nodeAddStaticNode(C, &ntree, NODE_REROUTE);
- /* Find cut links and sort them by sockets */
- BLI_listbase_clear(&output_links);
- BLI_listbase_clear(&input_links);
+ nodeAddLink(&ntree,
+ item.value.from_node,
+ item.key,
+ reroute,
+ static_cast<bNodeSocket *>(reroute->inputs.first));
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
- continue;
- }
- if (add_reroute_intersect_check(*link, mcoords, i, insert_point)) {
- add_reroute_insert_socket_link(&output_links, link->fromsock, link, insert_point);
- add_reroute_insert_socket_link(&input_links, link->tosock, link, insert_point);
-
- /* Clear flag */
- link->flag &= ~NODE_LINK_TEST;
- }
+ /* Reconnect links from the original output socket to the new reroute. */
+ for (bNodeLink *link : cuts.keys()) {
+ link->fromnode = reroute;
+ link->fromsock = static_cast<bNodeSocket *>(reroute->outputs.first);
+ BKE_ntree_update_tag_link_changed(&ntree);
}
- /* Create reroute nodes for intersected links.
- * Only one reroute if links share the same input/output socket.
- */
- socklink = (bNodeSocketLink *)output_links.first;
- while (socklink) {
- socklink = add_reroute_do_socket_section(C, socklink, SOCK_OUT);
- }
- socklink = (bNodeSocketLink *)input_links.first;
- while (socklink) {
- socklink = add_reroute_do_socket_section(C, socklink, SOCK_IN);
+ /* Place the new reroute at the average location of all connected cuts. */
+ const float2 loc = std::accumulate(cuts.values().begin(), cuts.values().end(), float2(0)) /
+ cuts.size() / UI_DPI_FAC;
+ reroute->locx = loc.x;
+ reroute->locy = loc.y;
+
+ /* Attach the reroute node to frame nodes behind it. */
+ for (const int i : frame_nodes.index_range()) {
+ bNode *frame_node = frame_nodes.last(i);
+ if (BLI_rctf_isect_pt_v(&frame_node->totr, loc)) {
+ nodeAttachNode(reroute, frame_node);
+ break;
+ }
}
-
- BLI_freelistN(&output_links);
- BLI_freelistN(&input_links);
-
- /* always last */
- ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
- return OPERATOR_FINISHED;
}
- return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
+ return OPERATOR_FINISHED;
}
void NODE_OT_add_reroute(wmOperatorType *ot)
@@ -338,9 +282,9 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
- bNodeTree *node_group;
- if (!(node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree))) {
+ bNodeTree *node_group = node_add_group_get_and_poll_group_node_tree(bmain, op, ntree);
+ if (!node_group) {
return OPERATOR_CANCELLED;
}
@@ -352,12 +296,7 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- bNode *group_node = node_add_node(*C,
- node_idname,
- (node_group->type == NTREE_CUSTOM) ? NODE_CUSTOM_GROUP :
- NODE_GROUP,
- snode->runtime->cursor[0],
- snode->runtime->cursor[1]);
+ bNode *group_node = add_node(*C, node_idname, snode->runtime->cursor);
if (!group_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node group");
return OPERATOR_CANCELLED;
@@ -382,7 +321,7 @@ static bool node_add_group_poll(bContext *C)
if (snode->edittree->type == NTREE_CUSTOM) {
CTX_wm_operator_poll_msg_set(C,
"This node editor displays a custom (Python defined) node tree. "
- "Dropping node groups isn't supported for this.");
+ "Dropping node groups isn't supported for this");
return false;
}
return true;
@@ -445,8 +384,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *object_node = node_add_node(
- *C, nullptr, GEO_NODE_OBJECT_INFO, snode->runtime->cursor[0], snode->runtime->cursor[1]);
+ bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor);
if (!object_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node object");
return OPERATOR_CANCELLED;
@@ -522,7 +460,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- bNodeTree *ntree = snode.edittree;
+ bNodeTree &ntree = *snode.edittree;
Collection *collection = reinterpret_cast<Collection *>(
WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_GR));
@@ -533,8 +471,7 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- bNode *collection_node = node_add_node(
- *C, nullptr, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor[0], snode.runtime->cursor[1]);
+ bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor);
if (!collection_node) {
BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
return OPERATOR_CANCELLED;
@@ -550,8 +487,8 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
socket_data->value = collection;
id_us_plus(&collection->id);
- nodeSetActive(ntree, collection_node);
- ED_node_tree_propagate_change(C, bmain, ntree);
+ nodeSetActive(&ntree, collection_node);
+ ED_node_tree_propagate_change(C, bmain, &ntree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -617,11 +554,9 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- bNode *node;
- Image *ima;
int type = 0;
- ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
+ Image *ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!ima) {
return OPERATOR_CANCELLED;
}
@@ -645,7 +580,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(*C, nullptr, type, snode.runtime->cursor[0], snode.runtime->cursor[1]);
+ bNode *node = add_static_node(*C, type, snode.runtime->cursor);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
@@ -690,8 +625,8 @@ static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *even
snode->runtime->cursor[0] /= UI_DPI_FAC;
snode->runtime->cursor[1] /= UI_DPI_FAC;
- if (RNA_struct_property_is_set(op->ptr, "filepath") ||
- RNA_struct_property_is_set(op->ptr, "name")) {
+ if (WM_operator_properties_id_lookup_is_set(op->ptr) ||
+ RNA_struct_property_is_set(op->ptr, "filepath")) {
return node_add_file_exec(C, op);
}
return WM_operator_filesel(C, op, event);
@@ -739,7 +674,6 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
- bNode *node;
ID *mask = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, ID_MSK);
if (!mask) {
@@ -748,8 +682,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
- node = node_add_node(
- *C, nullptr, CMP_NODE_MASK, snode.runtime->cursor[0], snode.runtime->cursor[1]);
+ bNode *node = add_static_node(*C, CMP_NODE_MASK, snode.runtime->cursor);
if (!node) {
BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");