Blender V4.5
node_geo_collection_info.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_listbase.h"
6#include "BLI_string.h"
7
9
10#include "NOD_rna_define.hh"
11
12#include "UI_interface.hh"
13#include "UI_resources.hh"
14
15#include "BKE_collection.hh"
16#include "BKE_instances.hh"
17
19
20#include "node_geometry_util.hh"
21
22#include <algorithm>
23
25
27
29{
30 b.add_input<decl::Collection>("Collection").hide_label();
31 b.add_input<decl::Bool>("Separate Children")
33 "Output each child of the collection as a separate instance, sorted alphabetically");
34 b.add_input<decl::Bool>("Reset Children")
36 "Reset the transforms of every child instance in the output. Only used when Separate "
37 "Children is enabled");
38 b.add_output<decl::Geometry>("Instances");
39}
40
41static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
42{
43 layout->prop(ptr, "transform_space", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
44}
45
46static void node_node_init(bNodeTree * /*tree*/, bNode *node)
47{
49 data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
50 node->storage = data;
51}
52
58
60{
61 Collection *collection = params.extract_input<Collection *>("Collection");
62
63 if (collection == nullptr) {
64 params.set_default_remaining_outputs();
65 return;
66 }
67 const Object *self_object = params.self_object();
68 /* Compare by `orig_id` because objects may be copied into separate depsgraphs. */
70 collection, const_cast<Object *>(self_object));
71 if (is_recursive) {
72 params.error_message_add(NodeWarningType::Error, TIP_("Collection contains current object"));
73 params.set_default_remaining_outputs();
74 return;
75 }
76 if (!DEG_collection_geometry_is_evaluated(*collection)) {
77 params.error_message_add(NodeWarningType::Error,
78 TIP_("Can't access collections geometry because it's not evaluated "
79 "yet. This can happen when there is a dependency cycle"));
80 params.set_default_remaining_outputs();
81 return;
82 }
83
84 const NodeGeometryCollectionInfo &storage = node_storage(params.node());
85 const bool use_relative_transform = (storage.transform_space ==
87
88 std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
89
90 const bool separate_children = params.extract_input<bool>("Separate Children");
91 if (separate_children) {
92 const bool reset_children = params.extract_input<bool>("Reset Children");
93 Vector<Collection *> children_collections;
94 LISTBASE_FOREACH (CollectionChild *, collection_child, &collection->children) {
95 children_collections.append(collection_child->collection);
96 }
97 Vector<Object *> children_objects;
98 LISTBASE_FOREACH (CollectionObject *, collection_object, &collection->gobject) {
99 children_objects.append(collection_object->ob);
100 }
101
103 entries.reserve(children_collections.size() + children_objects.size());
104
105 for (Collection *child_collection : children_collections) {
107 if (!reset_children) {
108 transform.location() += float3(child_collection->instance_offset);
109 if (use_relative_transform) {
110 transform = self_object->world_to_object() * transform;
111 }
112 else {
113 transform.location() -= float3(collection->instance_offset);
114 }
115 }
116 const int handle = instances->add_reference(*child_collection);
117 entries.append({handle, &(child_collection->id.name[2]), transform});
118 }
119 for (Object *child_object : children_objects) {
120 const int handle = instances->add_reference(*child_object);
122 if (!reset_children) {
123 if (use_relative_transform) {
124 transform = self_object->world_to_object();
125 }
126 else {
127 transform.location() -= float3(collection->instance_offset);
128 }
129 transform *= child_object->object_to_world();
130 }
131 entries.append({handle, &(child_object->id.name[2]), transform});
132 }
133
134 std::sort(entries.begin(),
135 entries.end(),
136 [](const InstanceListEntry &a, const InstanceListEntry &b) {
137 return BLI_strcasecmp_natural(a.name, b.name) < 0;
138 });
139 for (const InstanceListEntry &entry : entries) {
140 instances->add_instance(entry.handle, entry.transform);
141 }
142 }
143 else {
145 if (use_relative_transform) {
146 transform.location() = collection->instance_offset;
147 transform = self_object->world_to_object() * transform;
148 }
149
150 const int handle = instances->add_reference(*collection);
151 instances->add_instance(handle, transform);
152 }
153 GeometrySet geometry = GeometrySet::from_instances(instances.release());
154 geometry.name = collection->id.name + 2;
155
156 params.set_output("Instances", std::move(geometry));
157}
158
159static void node_rna(StructRNA *srna)
160{
161 static const EnumPropertyItem rna_node_geometry_collection_info_transform_space_items[] = {
163 "ORIGINAL",
164 0,
165 "Original",
166 "Output the geometry relative to the collection offset"},
168 "RELATIVE",
169 0,
170 "Relative",
171 "Bring the input collection geometry into the modified object, maintaining the relative "
172 "position between the objects in the scene"},
173 {0, nullptr, 0, nullptr, nullptr},
174 };
175
177 srna,
178 "transform_space",
179 "Transform Space",
180 "The transformation of the instances output. Does not affect the internal geometry",
181 rna_node_geometry_collection_info_transform_space_items,
182 NOD_storage_enum_accessors(transform_space),
185}
186
187static void node_register()
188{
189 static blender::bke::bNodeType ntype;
190
191 geo_node_type_base(&ntype, "GeometryNodeCollectionInfo", GEO_NODE_COLLECTION_INFO);
192 ntype.ui_name = "Collection Info";
193 ntype.ui_description = "Retrieve geometry instances from a collection";
194 ntype.enum_name_legacy = "COLLECTION_INFO";
195 ntype.nclass = NODE_CLASS_INPUT;
196 ntype.declare = node_declare;
197 ntype.initfunc = node_node_init;
199 ntype, "NodeGeometryCollectionInfo", node_free_standard_storage, node_copy_standard_storage);
203
204 node_rna(ntype.rna_ext.srna);
205}
207
208} // namespace blender::nodes::node_geo_collection_info_cc
bool BKE_collection_has_object_recursive_instanced_orig_id(Collection *collection_eval, Object *object_eval)
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1215
#define NODE_CLASS_INPUT
Definition BKE_node.hh:433
#define GEO_NODE_COLLECTION_INFO
#define LISTBASE_FOREACH(type, var, list)
#define TIP_(msgid)
bool DEG_collection_geometry_is_evaluated(const Collection &collection)
Object groups, one object can be in many groups at once.
@ GEO_NODE_TRANSFORM_SPACE_RELATIVE
@ GEO_NODE_TRANSFORM_SPACE_ORIGINAL
#define NOD_REGISTER_NODE(REGISTER_FUNC)
void rna_Node_update_relations(Main *bmain, Scene *scne, PointerRNA *ptr)
#define NOD_storage_enum_accessors(member)
@ UI_ITEM_R_EXPAND
BMesh const char void * data
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
int64_t size() const
void append(const T &value)
void reserve(const int64_t min_capacity)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5603
static void node_declare(NodeDeclarationBuilder &b)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_node_init(bNodeTree *, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
StructRNA * srna
Definition RNA_types.hh:909
char name[66]
Definition DNA_ID.h:415
void * storage
Defines a node type.
Definition BKE_node.hh:226
std::string ui_description
Definition BKE_node.hh:232
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:347
const char * enum_name_legacy
Definition BKE_node.hh:235
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:355
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
PointerRNA * ptr
Definition wm_files.cc:4227