Merge branch 'master' into geometry-nodes-simulation

This commit is contained in:
Hans Goudey 2022-12-02 14:32:09 -06:00
commit cff291d1f3
17 changed files with 262 additions and 279 deletions

View File

@ -970,16 +970,9 @@ if(WITH_COMPILER_CCACHE)
endif()
endif()
# On some platforms certain atomic operations are not possible with assembly and/or intrinsics and
# they are emulated in software with locks. For example, on armel there is no intrinsics to grant
# 64 bit atomic operations and STL library uses libatomic to offload software emulation of atomics
# to.
# This function will check whether libatomic is required and if so will configure linker flags.
# If atomic operations are possible without libatomic then linker flags are left as-is.
function(CONFIGURE_ATOMIC_LIB_IF_NEEDED)
# Source which is used to enforce situation when software emulation of atomics is required.
# Assume that using 64bit integer gives a definitive answer (as in, if 64bit atomic operations
# are possible using assembly/intrinsics 8, 16, and 32 bit operations will also be possible.
# Always link with libatomic if available, as it is required for data types
# which don't have intrinsics.
function(configure_atomic_lib_if_needed)
set(_source
"#include <atomic>
#include <cstdint>
@ -990,25 +983,12 @@ function(CONFIGURE_ATOMIC_LIB_IF_NEEDED)
)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("${_source}" ATOMIC_OPS_WITHOUT_LIBATOMIC)
set(CMAKE_REQUIRED_LIBRARIES atomic)
check_cxx_source_compiles("${_source}" ATOMIC_OPS_WITH_LIBATOMIC)
unset(CMAKE_REQUIRED_LIBRARIES)
if(NOT ATOMIC_OPS_WITHOUT_LIBATOMIC)
# Compilation of the test program has failed.
# Try it again with -latomic to see if this is what is needed, or whether something else is
# going on.
set(CMAKE_REQUIRED_LIBRARIES atomic)
check_cxx_source_compiles("${_source}" ATOMIC_OPS_WITH_LIBATOMIC)
unset(CMAKE_REQUIRED_LIBRARIES)
if(ATOMIC_OPS_WITH_LIBATOMIC)
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -latomic" PARENT_SCOPE)
else()
# Atomic operations are required part of Blender and it is not possible to process forward.
# We expect that either standard library or libatomic will make atomics to work. If both
# cases has failed something fishy o na bigger scope is going on.
message(FATAL_ERROR "Failed to detect required configuration for atomic operations")
endif()
if(ATOMIC_OPS_WITH_LIBATOMIC)
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -latomic" PARENT_SCOPE)
endif()
endfunction()

View File

@ -265,7 +265,7 @@ bool LightManager::object_usable_as_light(Object *object)
return false;
}
void LightManager::device_update_distribution(Device *device,
void LightManager::device_update_distribution(Device *,
DeviceScene *dscene,
Scene *scene,
Progress &progress)

View File

@ -307,8 +307,10 @@ class NODE_MT_select(Menu):
class NODE_MT_node(Menu):
bl_label = "Node"
def draw(self, _context):
def draw(self, context):
layout = self.layout
snode = context.space_data
is_compositor = snode.tree_type == 'CompositorNodeTree'
layout.operator("transform.translate")
layout.operator("transform.rotate")
@ -346,14 +348,17 @@ class NODE_MT_node(Menu):
layout.operator("node.hide_toggle")
layout.operator("node.mute_toggle")
layout.operator("node.preview_toggle")
if is_compositor:
layout.operator("node.preview_toggle")
layout.operator("node.hide_socket_toggle")
layout.operator("node.options_toggle")
layout.operator("node.collapse_hide_unused_toggle")
layout.separator()
layout.operator("node.read_viewlayers")
if is_compositor:
layout.separator()
layout.operator("node.read_viewlayers")
class NODE_MT_view_pie(Menu):

View File

@ -670,6 +670,13 @@ void nodeUnlinkNode(struct bNodeTree *ntree, struct bNode *node);
void nodeUniqueName(struct bNodeTree *ntree, struct bNode *node);
void nodeUniqueID(struct bNodeTree *ntree, struct bNode *node);
/**
* Rebuild the `node_by_id` runtime vector set. Call after removing a node if not handled
* separately. This is important instead of just using `nodes_by_id.remove()` since it maintains
* the node order.
*/
void nodeRebuildIDVector(struct bNodeTree *node_tree);
/**
* Delete node, associated animation data and ID user count.
*/

View File

@ -214,9 +214,6 @@ class bNodeRuntime : NonCopyable, NonMovable {
/** #eNodeTreeChangedFlag. */
uint32_t changed_flag = 0;
/** For dependency and sorting. */
short done = 0;
/** Used as a boolean for execution. */
uint8_t need_exec = 0;

View File

@ -33,8 +33,8 @@ AssetMetaData *BKE_asset_metadata_create()
void BKE_asset_metadata_free(AssetMetaData **asset_data)
{
(*asset_data)->~AssetMetaData();
MEM_SAFE_FREE(*asset_data);
MEM_delete(*asset_data);
*asset_data = nullptr;
}
AssetMetaData::~AssetMetaData()

View File

@ -2936,12 +2936,12 @@ static void node_unlink_attached(bNodeTree *ntree, bNode *parent)
}
}
static void rebuild_nodes_vector(bNodeTree &node_tree)
void nodeRebuildIDVector(bNodeTree *node_tree)
{
/* Rebuild nodes #VectorSet which must have the same order as the list. */
node_tree.runtime->nodes_by_id.clear();
LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) {
node_tree.runtime->nodes_by_id.add_new(node);
node_tree->runtime->nodes_by_id.clear();
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
node_tree->runtime->nodes_by_id.add_new(node);
}
}
@ -2958,7 +2958,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
if (ntree) {
BLI_remlink(&ntree->nodes, node);
/* Rebuild nodes #VectorSet which must have the same order as the list. */
rebuild_nodes_vector(*ntree);
nodeRebuildIDVector(ntree);
/* texture node has bad habit of keeping exec data around */
if (ntree->type == NTREE_TEXTURE && ntree->runtime->execdata) {
@ -3016,7 +3016,7 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
node_unlink_attached(ntree, node);
node_free_node(ntree, node);
rebuild_nodes_vector(*ntree);
nodeRebuildIDVector(ntree);
}
void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
@ -3079,7 +3079,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
/* Free node itself. */
node_free_node(ntree, node);
rebuild_nodes_vector(*ntree);
nodeRebuildIDVector(ntree);
}
static void node_socket_interface_free(bNodeTree * /*ntree*/,

View File

@ -2001,6 +2001,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
*/
link = MEM_callocN(sizeof(bNodeLink), "link");
BLI_addtail(&ntree->links, link);
nodeUniqueID(ntree, node);
link->fromnode = NULL;
link->fromsock = gsock;
link->tonode = node;
@ -2024,6 +2025,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
*/
link = MEM_callocN(sizeof(bNodeLink), "link");
BLI_addtail(&ntree->links, link);
nodeUniqueID(ntree, node);
link->fromnode = node;
link->fromsock = sock;
link->tonode = NULL;

View File

@ -581,9 +581,9 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert)
* Also not correct but it's better then having it zeroed for e.g.
*
* - Missing key-index layer.
* In this case the basis key wont apply it's deltas to other keys and in the case
* a shape-key layer is missing, its coordinates will be initialized from the edit-mesh
* vertex locations instead of attempting to remap the shape-keys coordinates.
* In this case the basis key won't apply its deltas to other keys and if a shape-key layer is
* missing, its coordinates will be initialized from the edit-mesh vertex locations instead of
* attempting to remap the shape-keys coordinates.
*
* \note These cases are considered abnormal and shouldn't occur in typical usage.
* A warning is logged in this case to help troubleshooting bugs with shape-keys.

View File

@ -1709,7 +1709,7 @@ void NODE_OT_preview_toggle(wmOperatorType *ot)
/* callbacks */
ot->exec = node_preview_toggle_exec;
ot->poll = ED_operator_node_active;
ot->poll = composite_node_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@ -2795,7 +2795,7 @@ static bool node_shader_script_update_text_recursive(RenderEngine *engine,
RenderEngineType *type,
bNodeTree *ntree,
Text *text,
Set<bNodeTree *> &done_trees)
VectorSet<bNodeTree *> &done_trees)
{
bool found = false;
@ -2855,7 +2855,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
if (text) {
Set<bNodeTree *> done_trees;
VectorSet<bNodeTree *> done_trees;
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {

View File

@ -269,6 +269,7 @@ static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
node->flag |= NODE_SELECT;
}
wgroup->runtime->nodes_by_id.clear();
bNodeLink *glinks_first = (bNodeLink *)ntree->links.last;
@ -446,30 +447,24 @@ static bool node_group_separate_selected(
ListBase anim_basepaths = {nullptr, nullptr};
Map<const bNode *, bNode *> node_map;
Map<const bNodeSocket *, bNodeSocket *> socket_map;
/* add selected nodes into the ntree */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
continue;
}
/* ignore interface nodes */
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
nodeSetSelected(node, false);
continue;
}
/* Add selected nodes into the ntree, ignoring interface nodes. */
VectorSet<bNode *> nodes_to_move = get_selected_nodes(ngroup);
nodes_to_move.remove_if(
[](const bNode *node) { return node->is_group_input() || node->is_group_output(); });
for (bNode *node : nodes_to_move) {
bNode *newnode;
if (make_copy) {
/* make a copy */
newnode = bke::node_copy_with_mapping(&ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
node_map.add_new(node, newnode);
newnode = bke::node_copy_with_mapping(&ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
}
else {
/* use the existing node */
newnode = node;
BLI_remlink(&ngroup.nodes, newnode);
BLI_addtail(&ntree.nodes, newnode);
nodeUniqueID(&ntree, newnode);
nodeUniqueName(&ntree, newnode);
}
/* Keep track of this node's RNA "base" path (the part of the path identifying the node)
@ -491,17 +486,14 @@ static bool node_group_separate_selected(
nodeDetachNode(&ngroup, newnode);
}
/* migrate node */
BLI_remlink(&ngroup.nodes, newnode);
BLI_addtail(&ntree.nodes, newnode);
nodeUniqueID(&ntree, newnode);
nodeUniqueName(&ntree, newnode);
if (!newnode->parent) {
newnode->locx += offset.x;
newnode->locy += offset.y;
}
}
if (!make_copy) {
nodeRebuildIDVector(&ngroup);
}
/* add internal links to the ntree */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup.links) {
@ -512,9 +504,9 @@ static bool node_group_separate_selected(
/* make a copy of internal links */
if (fromselect && toselect) {
nodeAddLink(&ntree,
node_map.lookup(link->fromnode),
ntree.node_by_id(link->fromnode->identifier),
socket_map.lookup(link->fromsock),
node_map.lookup(link->tonode),
ntree.node_by_id(link->tonode->identifier),
socket_map.lookup(link->tosock));
}
}
@ -642,97 +634,97 @@ void NODE_OT_group_separate(wmOperatorType *ot)
/** \name Make Group Operator
* \{ */
static bool node_group_make_use_node(const bNode &node, bNode *gnode)
static VectorSet<bNode *> get_nodes_to_group(bNodeTree &node_tree, bNode *group_node)
{
return (&node != gnode && !ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT) &&
(node.flag & NODE_SELECT));
VectorSet<bNode *> nodes_to_group = get_selected_nodes(node_tree);
nodes_to_group.remove_if(
[](bNode *node) { return node->is_group_input() || node->is_group_output(); });
nodes_to_group.remove(group_node);
return nodes_to_group;
}
static bool node_group_make_test_selected(bNodeTree &ntree,
bNode *gnode,
const VectorSet<bNode *> &nodes_to_group,
const char *ntree_idname,
ReportList &reports)
{
int ok = true;
if (nodes_to_group.is_empty()) {
return false;
}
/* make a local pseudo node tree to pass to the node poll functions */
bNodeTree *ngroup = ntreeAddTree(nullptr, "Pseudo Node Group", ntree_idname);
BLI_SCOPED_DEFER([&]() {
ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
});
/* check poll functions for selected nodes */
for (bNode *node : ntree.all_nodes()) {
if (node_group_make_use_node(*node, gnode)) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
ok = false;
break;
for (bNode *node : nodes_to_group) {
const char *disabled_hint = nullptr;
if (node->typeinfo->poll_instance &&
!node->typeinfo->poll_instance(node, ngroup, &disabled_hint)) {
if (disabled_hint) {
BKE_reportf(&reports,
RPT_WARNING,
"Can not add node '%s' in a group:\n %s",
node->name,
disabled_hint);
}
else {
BKE_reportf(&reports, RPT_WARNING, "Can not add node '%s' in a group", node->name);
}
return false;
}
node->runtime->done = 0;
}
/* free local pseudo node tree again */
ntreeFreeTree(ngroup);
MEM_freeN(ngroup);
if (!ok) {
return false;
}
/* check if all connections are OK, no unselected node has both
* inputs and outputs to a selection */
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
if (node_group_make_use_node(*link->fromnode, gnode)) {
link->tonode->runtime->done |= 1;
}
if (node_group_make_use_node(*link->tonode, gnode)) {
link->fromnode->runtime->done |= 2;
}
}
ntree.ensure_topology_cache();
for (bNode *node : ntree.all_nodes()) {
if (!(node->flag & NODE_SELECT) && node != gnode && node->runtime->done == 3) {
if (nodes_to_group.contains(node)) {
continue;
}
auto sockets_connected_to_group = [&](const Span<bNodeSocket *> sockets) {
for (const bNodeSocket *socket : sockets) {
for (const bNodeSocket *other_socket : socket->directly_linked_sockets()) {
if (nodes_to_group.contains(const_cast<bNode *>(&other_socket->owner_node()))) {
return true;
}
}
}
return false;
};
if (sockets_connected_to_group(node->input_sockets()) &&
sockets_connected_to_group(node->output_sockets())) {
return false;
}
}
return true;
}
static int node_get_selected_minmax(
bNodeTree &ntree, bNode *gnode, float2 &min, float2 &max, bool use_size)
static void get_min_max_of_nodes(const Span<bNode *> nodes,
const bool use_size,
float2 &min,
float2 &max)
{
int totselect = 0;
if (nodes.is_empty()) {
min = float2(0);
max = float2(0);
return;
}
INIT_MINMAX2(min, max);
for (const bNode *node : ntree.all_nodes()) {
if (node_group_make_use_node(*node, gnode)) {
float2 loc;
nodeToView(node, node->offsetx, node->offsety, &loc.x, &loc.y);
for (const bNode *node : nodes) {
float2 loc;
nodeToView(node, node->offsetx, node->offsety, &loc.x, &loc.y);
math::min_max(loc, min, max);
if (use_size) {
loc.x += node->width;
loc.y -= node->height;
math::min_max(loc, min, max);
if (use_size) {
loc.x += node->width;
loc.y -= node->height;
math::min_max(loc, min, max);
}
totselect++;
}
}
/* sane min/max if no selected nodes */
if (totselect == 0) {
min[0] = min[1] = max[0] = max[1] = 0.0f;
}
return totselect;
}
/**
@ -803,11 +795,14 @@ static void node_group_make_redirect_incoming_link(
}
}
static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, bNode *gnode)
static void node_group_make_insert_selected(const bContext &C,
bNodeTree &ntree,
bNode *gnode,
const VectorSet<bNode *> &nodes_to_move)
{
Main *bmain = CTX_data_main(&C);
bNodeTree *ngroup = (bNodeTree *)gnode->id;
bool expose_visible = false;
BLI_assert(!nodes_to_move.contains(gnode));
/* XXX rough guess, not nice but we don't have access to UI constants here ... */
static const float offsetx = 200;
@ -818,18 +813,16 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
nodeSetSelected(node, false);
}
/* auto-add interface for "solo" nodes */
const bool expose_visible = nodes_to_move.size() == 1;
float2 center, min, max;
const int totselect = node_get_selected_minmax(ntree, gnode, min, max, false);
get_min_max_of_nodes(nodes_to_move, false, min, max);
add_v2_v2v2(center, min, max);
mul_v2_fl(center, 0.5f);
float2 real_min, real_max;
node_get_selected_minmax(ntree, gnode, real_min, real_max, true);
/* auto-add interface for "solo" nodes */
if (totselect == 1) {
expose_visible = true;
}
get_min_max_of_nodes(nodes_to_move, true, real_min, real_max);
ListBase anim_basepaths = {nullptr, nullptr};
@ -839,44 +832,42 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
if (node->parent == nullptr) {
continue;
}
if (node_group_make_use_node(*node->parent, gnode) &&
!node_group_make_use_node(*node, gnode)) {
if (nodes_to_move.contains(node->parent) && nodes_to_move.contains(node)) {
nodeDetachNode(&ntree, node);
}
}
/* move nodes over */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
if (node_group_make_use_node(*node, gnode)) {
/* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
* if the old node-tree has animation data which potentially covers this node. */
if (ntree.adt) {
PointerRNA ptr;
char *path;
for (bNode *node : nodes_to_move) {
/* Keep track of this node's RNA "base" path (the part of the pat identifying the node)
* if the old node-tree has animation data which potentially covers this node. */
if (ntree.adt) {
PointerRNA ptr;
char *path;
RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
RNA_pointer_create(&ntree.id, &RNA_Node, node, &ptr);
path = RNA_path_from_ID_to_struct(&ptr);
if (path) {
BLI_addtail(&anim_basepaths, animation_basepath_change_new(path, path));
}
if (path) {
BLI_addtail(&anim_basepaths, animation_basepath_change_new(path, path));
}
/* ensure valid parent pointers, detach if parent stays outside the group */
if (node->parent && !(node->parent->flag & NODE_SELECT)) {
nodeDetachNode(&ntree, node);
}
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
nodeUniqueID(ngroup, node);
nodeUniqueName(ngroup, node);
BKE_ntree_update_tag_node_removed(&ntree);
BKE_ntree_update_tag_node_new(ngroup, node);
}
/* ensure valid parent pointers, detach if parent stays outside the group */
if (node->parent && !(node->parent->flag & NODE_SELECT)) {
nodeDetachNode(&ntree, node);
}
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
nodeUniqueID(ngroup, node);
nodeUniqueName(ngroup, node);
BKE_ntree_update_tag_node_removed(&ntree);
BKE_ntree_update_tag_node_new(ngroup, node);
}
nodeRebuildIDVector(&ntree);
/* move animation data over */
if (ntree.adt) {
@ -904,8 +895,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
Map<bNodeSocket *, bNodeSocket *> reusable_sockets;
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
const bool fromselect = node_group_make_use_node(*link->fromnode, gnode);
const bool toselect = node_group_make_use_node(*link->tonode, gnode);
const bool fromselect = nodes_to_move.contains(link->fromnode);
const bool toselect = nodes_to_move.contains(link->tonode);
if ((fromselect && link->tonode == gnode) || (toselect && link->fromnode == gnode)) {
/* remove all links to/from the gnode.
@ -969,8 +960,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* move internal links */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) {
const bool fromselect = node_group_make_use_node(*link->fromnode, gnode);
const bool toselect = node_group_make_use_node(*link->tonode, gnode);
const bool fromselect = nodes_to_move.contains(link->fromnode);
const bool toselect = nodes_to_move.contains(link->tonode);
if (fromselect && toselect) {
BLI_remlink(&ntree.links, link);
@ -979,8 +970,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
}
/* move nodes in the group to the center */
for (bNode *node : ngroup->all_nodes()) {
if (node_group_make_use_node(*node, gnode) && !node->parent) {
for (bNode *node : nodes_to_move) {
if (!node->parent) {
node->locx -= center[0];
node->locy -= center[1];
}
@ -988,73 +979,67 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* Expose all unlinked sockets too but only the visible ones. */
if (expose_visible) {
for (bNode *node : ngroup->all_nodes()) {
if (node_group_make_use_node(*node, gnode)) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->tosock == sock) {
skip = true;
break;
}
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
for (bNode *node : nodes_to_move) {
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->tosock == sock) {
skip = true;
break;
}
if (skip) {
continue;
}
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_input_update(ngroup, input_node);
/* create new internal link */
bNodeSocket *input_sock = node_group_input_find_socket(input_node, iosock->identifier);
nodeAddLink(ngroup, input_node, input_sock, node, sock);
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
skip = true;
}
if (skip) {
continue;
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->fromsock == sock) {
skip = true;
}
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_input_update(ngroup, input_node);
/* create new internal link */
bNodeSocket *input_sock = node_group_input_find_socket(input_node, iosock->identifier);
nodeAddLink(ngroup, input_node, input_sock, node, sock);
}
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
bool skip = false;
LISTBASE_FOREACH (bNodeLink *, link, &ngroup->links) {
if (link->fromsock == sock) {
skip = true;
}
if (skip) {
continue;
}
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_output_update(ngroup, output_node);
/* create new internal link */
bNodeSocket *output_sock = node_group_output_find_socket(output_node,
iosock->identifier);
nodeAddLink(ngroup, node, sock, output_node, output_sock);
}
if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
skip = true;
}
if (skip) {
continue;
}
bNodeSocket *iosock = ntreeAddSocketInterfaceFromSocket(ngroup, node, sock);
node_group_output_update(ngroup, output_node);
/* create new internal link */
bNodeSocket *output_sock = node_group_output_find_socket(output_node, iosock->identifier);
nodeAddLink(ngroup, node, sock, output_node, output_sock);
}
}
}
}
static bNode *node_group_make_from_selected(const bContext &C,
bNodeTree &ntree,
const char *ntype,
const char *ntreetype)
static bNode *node_group_make_from_nodes(const bContext &C,
bNodeTree &ntree,
const VectorSet<bNode *> &nodes_to_group,
const char *ntype,
const char *ntreetype)
{
Main *bmain = CTX_data_main(&C);
float2 min, max;
const int totselect = node_get_selected_minmax(ntree, nullptr, min, max, false);
/* don't make empty group */
if (totselect == 0) {
return nullptr;
}
get_min_max_of_nodes(nodes_to_group, false, min, max);
/* New node-tree. */
bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype);
@ -1066,7 +1051,7 @@ static bNode *node_group_make_from_selected(const bContext &C,
gnode->locx = 0.5f * (min[0] + max[0]);
gnode->locy = 0.5f * (min[1] + max[1]);
node_group_make_insert_selected(C, ntree, gnode);
node_group_make_insert_selected(C, ntree, gnode, nodes_to_group);
return gnode;
}
@ -1081,11 +1066,12 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
if (!node_group_make_test_selected(ntree, nullptr, ntree_idname, *op->reports)) {
VectorSet<bNode *> nodes_to_group = get_nodes_to_group(ntree, nullptr);
if (!node_group_make_test_selected(ntree, nodes_to_group, ntree_idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
bNode *gnode = node_group_make_from_selected(*C, ntree, node_idname, ntree_idname);
bNode *gnode = node_group_make_from_nodes(*C, ntree, nodes_to_group, node_idname, ntree_idname);
if (gnode) {
bNodeTree *ngroup = (bNodeTree *)gnode->id;
@ -1137,17 +1123,17 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
bNode *gnode = node_group_get_active(C, node_idname);
if (!gnode || !gnode->id) {
return OPERATOR_CANCELLED;
}
bNodeTree *ngroup = (bNodeTree *)gnode->id;
if (!node_group_make_test_selected(*ntree, gnode, ngroup->idname, *op->reports)) {
VectorSet<bNode *> nodes_to_group = get_nodes_to_group(*ntree, gnode);
if (!node_group_make_test_selected(*ntree, nodes_to_group, ngroup->idname, *op->reports)) {
return OPERATOR_CANCELLED;
}
node_group_make_insert_selected(*C, *ntree, gnode);
node_group_make_insert_selected(*C, *ntree, gnode, nodes_to_group);
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);

View File

@ -9,8 +9,8 @@
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_set.hh"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "BKE_node.h"
@ -183,7 +183,7 @@ void node_keymap(wmKeyConfig *keyconf);
rctf node_frame_rect_inside(const bNode &node);
bool node_or_socket_isect_event(const bContext &C, const wmEvent &event);
Set<bNode *> get_selected_nodes(bNodeTree &node_tree);
VectorSet<bNode *> get_selected_nodes(bNodeTree &node_tree);
void node_deselect_all(SpaceNode &snode);
void node_socket_select(bNode *node, bNodeSocket &sock);
void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node);

View File

@ -1630,40 +1630,42 @@ void NODE_OT_parent_set(wmOperatorType *ot)
/** \name Join Nodes Operator
* \{ */
/* tags for depth-first search */
#define NODE_JOIN_DONE 1
#define NODE_JOIN_IS_DESCENDANT 2
struct NodeJoinState {
bool done;
bool descendent;
};
static void node_join_attach_recursive(bNodeTree &ntree,
MutableSpan<NodeJoinState> join_states,
bNode *node,
bNode *frame,
const Set<bNode *> &selected_nodes)
const VectorSet<bNode *> &selected_nodes)
{
node->runtime->done |= NODE_JOIN_DONE;
join_states[node->runtime->index_in_tree].done = true;
if (node == frame) {
node->runtime->done |= NODE_JOIN_IS_DESCENDANT;
join_states[node->runtime->index_in_tree].descendent = true;
}
else if (node->parent) {
/* call recursively */
if (!(node->parent->runtime->done & NODE_JOIN_DONE)) {
node_join_attach_recursive(ntree, node->parent, frame, selected_nodes);
if (!join_states[node->parent->runtime->index_in_tree].done) {
node_join_attach_recursive(ntree, join_states, node->parent, frame, selected_nodes);
}
/* in any case: if the parent is a descendant, so is the child */
if (node->parent->runtime->done & NODE_JOIN_IS_DESCENDANT) {
node->runtime->done |= NODE_JOIN_IS_DESCENDANT;
if (join_states[node->parent->runtime->index_in_tree].descendent) {
join_states[node->runtime->index_in_tree].descendent = true;
}
else if (selected_nodes.contains(node)) {
/* if parent is not an descendant of the frame, reattach the node */
nodeDetachNode(&ntree, node);
nodeAttachNode(&ntree, node, frame);
node->runtime->done |= NODE_JOIN_IS_DESCENDANT;
join_states[node->runtime->index_in_tree].descendent = true;
}
}
else if (selected_nodes.contains(node)) {
nodeAttachNode(&ntree, node, frame);
node->runtime->done |= NODE_JOIN_IS_DESCENDANT;
join_states[node->runtime->index_in_tree].descendent = true;
}
}
@ -1673,19 +1675,16 @@ static int node_join_exec(bContext *C, wmOperator * /*op*/)
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
const Set<bNode *> selected_nodes = get_selected_nodes(ntree);
const VectorSet<bNode *> selected_nodes = get_selected_nodes(ntree);
bNode *frame_node = nodeAddStaticNode(C, &ntree, NODE_FRAME);
nodeSetActive(&ntree, frame_node);
/* reset tags */
for (bNode *node : ntree.all_nodes()) {
node->runtime->done = 0;
}
Array<NodeJoinState> join_states(ntree.all_nodes().size(), NodeJoinState{false, false});
for (bNode *node : ntree.all_nodes()) {
if (!(node->runtime->done & NODE_JOIN_DONE)) {
node_join_attach_recursive(ntree, node, frame_node, selected_nodes);
if (!join_states[node->runtime->index_in_tree].done) {
node_join_attach_recursive(ntree, join_states, node, frame_node, selected_nodes);
}
}
@ -1808,32 +1807,35 @@ void NODE_OT_attach(wmOperatorType *ot)
/** \name Detach Operator
* \{ */
/* tags for depth-first search */
#define NODE_DETACH_DONE 1
#define NODE_DETACH_IS_DESCENDANT 2
struct NodeDetachstate {
bool done;
bool descendent;
};
static void node_detach_recursive(bNodeTree &ntree, bNode *node)
static void node_detach_recursive(bNodeTree &ntree,
MutableSpan<NodeDetachstate> detach_states,
bNode *node)
{
node->runtime->done |= NODE_DETACH_DONE;
detach_states[node->runtime->index_in_tree].done = true;
if (node->parent) {
/* call recursively */
if (!(node->parent->runtime->done & NODE_DETACH_DONE)) {
node_detach_recursive(ntree, node->parent);
if (!detach_states[node->parent->runtime->index_in_tree].done) {
node_detach_recursive(ntree, detach_states, node->parent);
}
/* in any case: if the parent is a descendant, so is the child */
if (node->parent->runtime->done & NODE_DETACH_IS_DESCENDANT) {
node->runtime->done |= NODE_DETACH_IS_DESCENDANT;
if (detach_states[node->parent->runtime->index_in_tree].descendent) {
detach_states[node->runtime->index_in_tree].descendent = true;
}
else if (node->flag & NODE_SELECT) {
/* if parent is not a descendant of a selected node, detach */
nodeDetachNode(&ntree, node);
node->runtime->done |= NODE_DETACH_IS_DESCENDANT;
detach_states[node->runtime->index_in_tree].descendent = true;
}
}
else if (node->flag & NODE_SELECT) {
node->runtime->done |= NODE_DETACH_IS_DESCENDANT;
detach_states[node->runtime->index_in_tree].descendent = true;
}
}
@ -1843,16 +1845,14 @@ static int node_detach_exec(bContext *C, wmOperator * /*op*/)
SpaceNode &snode = *CTX_wm_space_node(C);
bNodeTree &ntree = *snode.edittree;
/* reset tags */
for (bNode *node : ntree.all_nodes()) {
node->runtime->done = 0;
}
Array<NodeDetachstate> detach_states(ntree.all_nodes().size(), NodeDetachstate{false, false});
/* detach nodes recursively
* relative order is preserved here!
*/
for (bNode *node : ntree.all_nodes()) {
if (!(node->runtime->done & NODE_DETACH_DONE)) {
node_detach_recursive(ntree, node);
if (!detach_states[node->runtime->index_in_tree].done) {
node_detach_recursive(ntree, detach_states, node);
}
}

View File

@ -312,9 +312,9 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node
}
}
Set<bNode *> get_selected_nodes(bNodeTree &node_tree)
VectorSet<bNode *> get_selected_nodes(bNodeTree &node_tree)
{
Set<bNode *> selected_nodes;
VectorSet<bNode *> selected_nodes;
for (bNode *node : node_tree.all_nodes()) {
if (node->flag & NODE_SELECT) {
selected_nodes.add(node);
@ -1142,7 +1142,7 @@ static int node_select_linked_to_exec(bContext *C, wmOperator * /*op*/)
node_tree.ensure_topology_cache();
Set<bNode *> initial_selection = get_selected_nodes(node_tree);
VectorSet<bNode *> initial_selection = get_selected_nodes(node_tree);
for (bNode *node : initial_selection) {
for (bNodeSocket *output_socket : node->output_sockets()) {
@ -1192,7 +1192,7 @@ static int node_select_linked_from_exec(bContext *C, wmOperator * /*op*/)
node_tree.ensure_topology_cache();
Set<bNode *> initial_selection = get_selected_nodes(node_tree);
VectorSet<bNode *> initial_selection = get_selected_nodes(node_tree);
for (bNode *node : initial_selection) {
for (bNodeSocket *input_socket : node->input_sockets()) {

View File

@ -469,7 +469,9 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
}
/* Still have to copy over the data in the destination provided by the caller. */
if (dst_varray.is_span()) {
array_utils::copy(computed_varray, mask, dst_varray.get_internal_span());
array_utils::copy(computed_varray,
mask,
dst_varray.get_internal_span().take_front(mask.min_array_size()));
}
else {
/* Slower materialize into a different structure. */

View File

@ -446,10 +446,12 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&ngroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
nodeUniqueID(ntree, node);
/* ensure unique node name in the node tree */
/* This is very slow and it has no use for GPU nodetree. (see T70609) */
// nodeUniqueName(ntree, node);
}
ngroup->runtime->nodes_by_id.clear();
/* Save first and last link to iterate over flattened group links. */
bNodeLink *glinks_first = static_cast<bNodeLink *>(ntree->links.last);

View File

@ -7,6 +7,8 @@
#include "DNA_node_types.h"
#include "BKE_node_runtime.hh"
#include "node_shader_util.hh"
#include "NOD_socket_search_link.hh"