diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index adb60b91de8..3d0ab49548a 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -12,6 +12,7 @@ #include "MEM_guardedalloc.h" #include "BLI_array.hh" +#include "BLI_hash.hh" #include "BLI_listbase.h" #include "BLI_math_vector_types.hh" #include "BLI_multi_value_map.hh" @@ -107,38 +108,65 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier); } -static void add_used_ids_from_sockets(const ListBase &sockets, Set &ids) +enum eNodeModifierIDRelation : int8_t { + GEOMETRY = 1 << 0, + TRANSFORM = 1 << 1, + + COLLECTION = 1 << 2, + CURVES = 1 << 3, + + NOTHING = 0, + ALL = ~0, +}; + +inline eNodeModifierIDRelation &operator|=(eNodeModifierIDRelation &a, eNodeModifierIDRelation b) +{ + return (eNodeModifierIDRelation &)((int8_t &)a |= (int8_t)b); +} + +inline eNodeModifierIDRelation operator|(eNodeModifierIDRelation a, eNodeModifierIDRelation b) +{ + return (eNodeModifierIDRelation)((int8_t)a | (int8_t)b); +} + +inline eNodeModifierIDRelation operator&(eNodeModifierIDRelation a, eNodeModifierIDRelation b) +{ + return (eNodeModifierIDRelation)((int8_t)a & (int8_t)b); +} + +static void add_used_ids_from_sockets(const ListBase &sockets, + Map &ids) { LISTBASE_FOREACH (const bNodeSocket *, socket, &sockets) { switch (socket->type) { case SOCK_OBJECT: { if (Object *object = ((bNodeSocketValueObject *)socket->default_value)->value) { - ids.add(&object->id); + ids.lookup_or_add(&object->id, NOTHING) |= ALL; } break; } case SOCK_COLLECTION: { if (Collection *collection = ((bNodeSocketValueCollection *)socket->default_value)->value) { - ids.add(&collection->id); + ids.lookup_or_add(&collection->id, NOTHING) |= ALL; } break; } case SOCK_MATERIAL: { if (Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value) { - ids.add(&material->id); + ids.lookup_or_add(&material->id, NOTHING) |= ALL; } break; } case SOCK_TEXTURE: { if (Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value) { - ids.add(&texture->id); + ids.lookup_or_add(&texture->id, NOTHING) |= ALL; } break; } case SOCK_IMAGE: { if (Image *image = ((bNodeSocketValueImage *)socket->default_value)->value) { - ids.add(&image->id); + ids.lookup_or_add(&image->id, NOTHING) |= ALL; } break; } @@ -152,34 +180,10 @@ static void add_used_ids_from_sockets(const ListBase &sockets, Set &ids) * more properties like whether the node is muted, but we would have to accept the cost of updating * relations when those properties are changed. */ -static bool node_needs_own_transform_relation(const bNode &node) -{ - if (node.type == GEO_NODE_COLLECTION_INFO) { - const NodeGeometryCollectionInfo &storage = *static_cast( - node.storage); - return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE; - } - - if (node.type == GEO_NODE_OBJECT_INFO) { - const NodeGeometryObjectInfo &storage = *static_cast( - node.storage); - return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE; - } - - if (node.type == GEO_NODE_SELF_OBJECT) { - return true; - } - if (node.type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) { - return true; - } - - return false; -} - static void process_nodes_for_depsgraph(const bNodeTree &tree, - Set &ids, - bool &r_needs_own_transform_relation, - Set &checked_groups) + Map &ids, + Set &checked_groups, + bool &r_needs_own_transform_relation) { if (!checked_groups.add(&tree)) { return; @@ -187,28 +191,81 @@ static void process_nodes_for_depsgraph(const bNodeTree &tree, tree.ensure_topology_cache(); for (const bNode *node : tree.all_nodes()) { - add_used_ids_from_sockets(node->inputs, ids); - add_used_ids_from_sockets(node->outputs, ids); - r_needs_own_transform_relation |= node_needs_own_transform_relation(*node); - } + if (node->is_group()) { + const bNodeTree *group = reinterpret_cast(node->id); + if (group != nullptr) { + process_nodes_for_depsgraph(*group, ids, checked_groups, r_needs_own_transform_relation); + } + } - for (const bNode *node : tree.group_nodes()) { - if (const bNodeTree *sub_tree = reinterpret_cast(node->id)) { - process_nodes_for_depsgraph(*sub_tree, ids, r_needs_own_transform_relation, checked_groups); + switch (node->type) { + case (GEO_NODE_COLLECTION_INFO): { + const NodeGeometryCollectionInfo &storage = + *reinterpret_cast(node->storage); + const bool own_transform_relation = storage.transform_space == + GEO_NODE_TRANSFORM_SPACE_RELATIVE; + bNodeSocket *collection_socket = nodeFindSocket(node, SOCK_IN, "Collection"); + Collection *collection = + collection_socket->default_value_typed()->value; + if (collection == nullptr) { + break; + } + eNodeModifierIDRelation &id_relation = ids.lookup_or_add(&collection->id, NOTHING); + id_relation |= COLLECTION; + if (own_transform_relation) { + r_needs_own_transform_relation = true; + } + break; + } + case (GEO_NODE_OBJECT_INFO): { + const NodeGeometryObjectInfo &storage = *reinterpret_cast( + node->storage); + const bool own_transform_relation = storage.transform_space == + GEO_NODE_TRANSFORM_SPACE_RELATIVE; + bNodeSocket *object_socket = nodeFindSocket(node, SOCK_IN, "Object"); + Object *object = object_socket->default_value_typed()->value; + if (object == nullptr) { + break; + } + eNodeModifierIDRelation &id_relation = ids.lookup_or_add(&object->id, NOTHING); + id_relation |= GEOMETRY | TRANSFORM; + if (own_transform_relation) { + r_needs_own_transform_relation = true; + } + break; + } + case (GEO_NODE_SELF_OBJECT): { + r_needs_own_transform_relation = true; + add_used_ids_from_sockets(node->inputs, ids); + add_used_ids_from_sockets(node->outputs, ids); + break; + } + case (GEO_NODE_DEFORM_CURVES_ON_SURFACE): { + r_needs_own_transform_relation = true; + add_used_ids_from_sockets(node->inputs, ids); + add_used_ids_from_sockets(node->outputs, ids); + break; + } + default: { + add_used_ids_from_sockets(node->inputs, ids); + add_used_ids_from_sockets(node->outputs, ids); + break; + } } } } -static void find_used_ids_from_settings(const NodesModifierSettings &settings, Set &ids) +static void find_used_ids_from_settings(const NodesModifierSettings &settings, + Map &ids) { IDP_foreach_property( settings.properties, IDP_TYPE_FILTER_ID, [](IDProperty *property, void *user_data) { - Set *ids = (Set *)user_data; + Map *ids = (Map *)user_data; ID *id = IDP_Id(property); if (id != nullptr) { - ids->add(id); + ids->lookup_or_add(id, NOTHING) |= ALL; } }, &ids); @@ -222,20 +279,36 @@ static const CustomData_MeshMasks dependency_data_mask{CD_MASK_PROP_ALL | CD_MAS CD_MASK_PROP_ALL}; static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx, - Collection &collection) + const eNodeModifierIDRelation & /*relation*/, + ID *collection_id) { - DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier"); - DEG_add_collection_geometry_customdata_mask(ctx->node, &collection, &dependency_data_mask); + Collection *collection = reinterpret_cast(collection_id); + DEG_add_collection_geometry_relation(ctx->node, collection, "Nodes Modifier"); + DEG_add_collection_geometry_customdata_mask(ctx->node, collection, &dependency_data_mask); } -static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object) +static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, + const eNodeModifierIDRelation &relation, + ID *object_id) { - DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier"); - if (&(ID &)object != &ctx->object->id) { + Object &object = *reinterpret_cast(object_id); + + if (object_id == &ctx->object->id) { + return; + } + + if (relation & TRANSFORM) { + DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier"); + } + + if (relation & COLLECTION) { if (object.type == OB_EMPTY && object.instance_collection != nullptr) { - add_collection_relation(ctx, *object.instance_collection); + add_collection_relation(ctx, relation, reinterpret_cast(object.instance_collection)); } - else if (DEG_object_has_geometry_component(&object)) { + } + + if (relation & GEOMETRY) { + if (DEG_object_has_geometry_component(&object)) { DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier"); DEG_add_customdata_mask(ctx->node, &object, &dependency_data_mask); } @@ -252,29 +325,27 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier"); bool needs_own_transform_relation = false; - Set used_ids; + Map used_ids; find_used_ids_from_settings(nmd->settings, used_ids); Set checked_groups; process_nodes_for_depsgraph( - *nmd->node_group, used_ids, needs_own_transform_relation, checked_groups); + *nmd->node_group, used_ids, checked_groups, needs_own_transform_relation); if (ctx->object->type == OB_CURVES) { Curves *curves_id = static_cast(ctx->object->data); if (curves_id->surface != nullptr) { - used_ids.add(&curves_id->surface->id); + used_ids.lookup_or_add(&curves_id->surface->id, NOTHING) |= CURVES; } } - for (ID *id : used_ids) { + for (auto [id, relation] : used_ids.items()) { switch ((ID_Type)GS(id->name)) { case ID_OB: { - Object *object = reinterpret_cast(id); - add_object_relation(ctx, *object); + add_object_relation(ctx, relation, id); break; } case ID_GR: { - Collection *collection = reinterpret_cast(id); - add_collection_relation(ctx, *collection); + add_collection_relation(ctx, relation, id); break; } case ID_IM: