37 b.add_input<
decl::Geometry>(
"Geometry").description(
"Geometry to duplicate elements of");
43 .description(
"The number of duplicates to create for each element")
48 .
description(
"The duplicated geometry, not including the original geometry");
51 .
description(
"The indices of the duplicates for each element");
57 data->domain = int8_t(AttrDomain::Point);
102 for (const int i : range) {
103 MutableSpan<int> dst = all_dst.slice(offsets[i]);
104 if (dst.is_empty()) {
107 dst.first() = src[i];
108 for (const int i_duplicate : dst.index_range().drop_front(1)) {
109 dst[i_duplicate] = noise::hash(src[i], i_duplicate);
126 for (
const int i :
indices.index_range()) {
130 duplicate_indices.
finish();
142 if (!src_attribute) {
145 if (!
ELEM(src_attribute.
domain, AttrDomain::Point, AttrDomain::Instance)) {
152 "id", AttrDomain::Point);
153 if (!dst_attribute) {
188 switch (attribute.meta_data.domain) {
189 case AttrDomain::Curve:
191 curve_offsets, selection, attribute.src, attribute.dst.span);
193 case AttrDomain::Point:
195 using T = decltype(dummy);
196 const Span<T> src = attribute.src.typed<T>();
197 MutableSpan<T> dst = attribute.dst.span.typed<T>();
198 selection.foreach_index(
199 GrainSize(512), [&](const int64_t index, const int64_t i_selection) {
200 const Span<T> curve_src = src.slice(src_points_by_curve[index]);
201 for (const int dst_curve_index : curve_offsets[i_selection]) {
202 dst.slice(dst_points_by_curve[dst_curve_index]).copy_from(curve_src);
211 attribute.dst.finish();
227 if (!src_attribute) {
230 if (src_attribute.
domain != AttrDomain::Point) {
240 if (!dst_attribute) {
252 const Span<int> curve_src = src.
slice(src_points_by_curve[i_src_curve]);
253 const IndexRange duplicates_range = offsets[i_selection];
254 for (
const int i_duplicate :
IndexRange(offsets[i_selection].
size()).drop_front(1)) {
255 const int i_dst_curve = duplicates_range[i_duplicate];
271 evaluator.
add(count_field);
280 Array<int> curve_offset_data(selection.size() + 1);
281 Array<int> point_offset_data(selection.size() + 1);
283 int dst_curves_num = 0;
284 int dst_points_num = 0;
286 selection.foreach_index_optimized<
int>([&](
const int index,
const int i_curve) {
287 const int count = counts[index];
288 curve_offset_data[i_curve] = dst_curves_num;
289 point_offset_data[i_curve] = dst_points_num;
290 dst_curves_num +=
count;
291 dst_points_num +=
count * points_by_curve[index].
size();
294 if (dst_points_num == 0) {
298 curve_offset_data.
last() = dst_curves_num;
299 point_offset_data.
last() = dst_points_num;
308 const IndexRange src_curve_range = points_by_curve[i_src_curve];
309 const IndexRange dst_curves_range = curve_offsets[i_selection];
311 for (
const int i_duplicate :
IndexRange(dst_curves_range.
size())) {
312 dst_offsets[i_duplicate] = point_offsets[i_selection].start() +
313 src_curve_range.
size() * i_duplicate;
316 all_dst_offsets.
last() = dst_points_num;
339 geometry_set.
keep_only({GeometryComponent::Type::Curve,
340 GeometryComponent::Type::GreasePencil,
341 GeometryComponent::Type::Edit});
358 grease_pencil->layers().index_range(), 16, [&](
const IndexRange layers_range) {
359 for (const int layer_i : layers_range) {
360 Layer &layer = grease_pencil->layer(layer_i);
361 Drawing *drawing = grease_pencil->get_eval_drawing(layer);
365 bke::CurvesGeometry &curves = drawing->strokes_for_write();
366 const bke::GreasePencilLayerFieldContext field_context{
367 *grease_pencil, AttrDomain::Curve, layer_i};
368 curves = duplicate_curves_CurveGeometry(curves,
374 drawing->tag_topology_changed();
404 attribute_filter, {
"id",
".corner_vert",
".corner_edge",
".edge_verts"})))
406 switch (attribute.meta_data.domain) {
407 case AttrDomain::Point:
410 case AttrDomain::Edge:
413 case AttrDomain::Face:
415 offsets, selection, attribute.src, attribute.dst.span);
417 case AttrDomain::Corner:
424 attribute.dst.finish();
443 if (!src_attribute) {
446 if (src_attribute.
domain != AttrDomain::Point) {
453 "id", AttrDomain::Point);
454 if (!dst_attribute) {
464 const IndexRange range = face_offsets[i_face];
469 for ([[maybe_unused]]
const int i_duplicate :
IndexRange(range.
size())) {
470 for ([[maybe_unused]]
const int i_loops :
IndexRange(source.
size())) {
471 if (i_duplicate == 0) {
472 dst[loop_index] = src[vert_mapping[loop_index]];
475 dst[loop_index] =
noise::hash(src[vert_mapping[loop_index]], i_duplicate);
492 geometry_set.
clear();
495 geometry_set.
keep_only({GeometryComponent::Type::Mesh, GeometryComponent::Type::Edit});
499 const Span<int> corner_verts = mesh.corner_verts();
500 const Span<int> corner_edges = mesh.corner_edges();
504 evaluator.
add(count_field);
514 const int count = counts[index];
515 offset_data[i_selection] = total_faces;
516 total_faces +=
count;
519 offset_data[selection.
size()] = total_faces;
536 const IndexRange face_range = duplicates[i_selection];
538 for ([[maybe_unused]]
const int i_duplicate : face_range.
index_range()) {
539 new_face_offsets[face_index] = loop_index;
540 for (
const int src_corner : source) {
541 loop_mapping[loop_index] = src_corner;
542 vert_mapping[loop_index] = corner_verts[src_corner];
543 edge_mapping[loop_index] = corner_edges[src_corner];
544 new_edges[loop_index][0] = loop_index;
545 if (src_corner != source.last()) {
546 new_edges[loop_index][1] = loop_index + 1;
549 new_edges[loop_index][1] = new_face_offsets[face_index];
559 new_mesh->tag_loose_verts_none();
560 new_mesh->tag_loose_edges_none();
561 new_mesh->tag_overlapping_none();
570 new_mesh->attributes_for_write());
577 new_mesh->attributes_for_write());
613 switch (attribute.meta_data.domain) {
614 case AttrDomain::Edge:
616 offsets, selection, attribute.src, attribute.dst.span);
618 case AttrDomain::Point:
625 attribute.dst.finish();
640 if (!src_attribute) {
643 if (src_attribute.
domain != AttrDomain::Point) {
650 "id", AttrDomain::Point);
651 if (!dst_attribute) {
660 const IndexRange edge_range = offsets[i_selection];
664 const int2 &edge = edges[index];
667 dst[vert_range[0]] = src[edge[0]];
668 dst[vert_range[1]] = src[edge[1]];
669 for (
const int i_duplicate :
IndexRange(1, edge_range.
size() - 1)) {
670 dst[vert_range[i_duplicate * 2]] =
noise::hash(src[edge[0]], i_duplicate);
671 dst[vert_range[i_duplicate * 2 + 1]] =
noise::hash(src[edge[1]], i_duplicate);
684 geometry_set.
clear();
692 evaluator.
add(count_field);
700 selection, counts, offset_data);
701 const int output_edges_num = duplicates.
total_size();
706 Array<int> vert_orig_indices(output_edges_num * 2);
708 const int2 &edge = edges[index];
709 const IndexRange edge_range = duplicates[i_selection];
713 vert_orig_indices[vert_range[i_duplicate * 2]] = edge[0];
714 vert_orig_indices[vert_range[i_duplicate * 2 + 1]] = edge[1];
719 for (const int i_selection : range) {
720 const IndexRange edge_range = duplicates[i_selection];
721 const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
722 for (const int i_duplicate : IndexRange(edge_range.size())) {
723 int2 &new_edge = new_edges[edge_range[i_duplicate]];
724 new_edge[0] = vert_range[i_duplicate * 2];
725 new_edge[1] = vert_range[i_duplicate * 2] + 1;
730 copy_edge_attributes_without_id(vert_orig_indices,
735 new_mesh->attributes_for_write());
737 copy_stable_id_edges(
738 mesh, selection, duplicates, mesh.attributes(), new_mesh->attributes_for_write());
740 if (attribute_outputs.duplicate_index) {
741 create_duplicate_index_attribute(new_mesh->attributes_for_write(),
748 new_mesh->tag_overlapping_none();
750 geometry_set.replace_mesh(new_mesh);
772 evaluator.
add(count_field);
780 selection, counts, offset_data);
803 using T = decltype(dummy);
804 const Span<T> src = attribute.src.typed<T>();
805 MutableSpan<T> dst = attribute.dst.span.typed<T>();
806 selection.foreach_index(GrainSize(512), [&](const int64_t index, const int64_t i_selection) {
807 const T &src_value = src[point_to_curve_map[index]];
808 dst.slice(duplicates[i_selection]).fill(src_value);
811 attribute.dst.finish();
814 copy_stable_id_point(duplicates, src_curves.attributes(), new_curves.attributes_for_write());
816 if (attribute_outputs.duplicate_index) {
817 create_duplicate_index_attribute(new_curves.attributes_for_write(),
864 grease_pencil.layers().index_range(), 16, [&](
const IndexRange layers_range) {
865 for (const int layer_i : layers_range) {
866 Layer &layer = grease_pencil.layer(layer_i);
867 Drawing *drawing = grease_pencil.get_eval_drawing(layer);
871 bke::CurvesGeometry &curves = drawing->strokes_for_write();
872 const bke::GreasePencilLayerFieldContext field_context{
873 grease_pencil, AttrDomain::Point, layer_i};
874 curves = duplicate_points_CurvesGeometry(curves,
880 drawing->tag_topology_changed();
901 evaluator.
add(count_field);
909 selection, counts, offset_data);
919 new_mesh->attributes_for_write());
931 new_mesh->tag_overlapping_none();
952 evaluator.
add(count_field);
960 selection, counts, offset_data);
970 pointcloud->attributes_for_write());
999 switch (component_type) {
1000 case GeometryComponent::Type::PointCloud:
1003 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1006 case GeometryComponent::Type::Mesh:
1009 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1012 case GeometryComponent::Type::Curve:
1015 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1018 case GeometryComponent::Type::GreasePencil: {
1021 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1029 component_types.
append(GeometryComponent::Type::Edit);
1030 geometry_set.
keep_only(component_types);
1047 geometry_set.
clear();
1050 geometry_set.
keep_only({GeometryComponent::Type::GreasePencil, GeometryComponent::Type::Edit});
1055 FieldEvaluator evaluator{field_context, src_grease_pencil.layers().size()};
1056 evaluator.
add(count_field);
1064 selection, counts, offset_data);
1065 const int new_layers_num = duplicates.
total_size();
1066 if (new_layers_num == 0) {
1067 geometry_set.
clear();
1074 new_grease_pencil->add_layers_with_empty_drawings_for_eval(new_layers_num);
1081 const Layer &src_layer = src_grease_pencil.layer(src_layer_i);
1082 const Drawing *src_drawing = src_grease_pencil.get_eval_drawing(src_layer);
1084 static_empty_curves;
1086 for (
Layer *new_layer : new_grease_pencil->layers_for_write().slice(range)) {
1088 new_layer->set_name(src_layer_name);
1089 Drawing *new_drawing = new_grease_pencil->get_eval_drawing(*new_layer);
1100 new_grease_pencil->attributes_for_write());
1126 geometry_set.
clear();
1134 evaluator.
add(count_field);
1142 selection, counts, offset_data);
1144 geometry_set.
clear();
1148 std::unique_ptr<bke::Instances> dst_instances = std::make_unique<bke::Instances>();
1150 dst_instances->resize(duplicates.
total_size());
1151 selection.
foreach_index([&](
const int i_src,
const int i_dst) {
1158 const int new_handle = dst_instances->add_reference(reference);
1159 dst_instances->reference_handles_for_write().slice(range).fill(new_handle);
1164 AttrDomain::Instance,
1165 AttrDomain::Instance,
1169 dst_instances->attributes_for_write());
1173 AttrDomain::Instance,
1195 static auto max_zero_fn = mf::build::SI1_SO<int, int>(
1197 [](
int value) {
return std::max(0, value); },
1198 mf::build::exec_presets::AllSpanOrSingle());
1204 attribute_outputs.duplicate_index =
params.get_output_anonymous_attribute_id_if_needed(
1209 if (duplicate_domain == AttrDomain::Instance) {
1211 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1215 switch (duplicate_domain) {
1216 case AttrDomain::Curve:
1218 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1220 case AttrDomain::Face:
1222 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1224 case AttrDomain::Edge:
1226 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1228 case AttrDomain::Point:
1230 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1232 case AttrDomain::Layer:
1234 geometry_set, count_field, selection_field, attribute_outputs, attribute_filter);
1244 params.set_default_remaining_outputs();
1248 params.set_output(
"Geometry", std::move(geometry_set));
1256 {int(AttrDomain::Point),
"POINT", 0,
"Point",
""},
1257 {int(AttrDomain::Edge),
"EDGE", 0,
"Edge",
""},
1258 {int(AttrDomain::Face),
"FACE", 0,
"Face",
""},
1259 {int(AttrDomain::Curve),
"SPLINE", 0,
"Spline",
""},
1260 {int(AttrDomain::Layer),
"LAYER", 0,
"Layer",
""},
1261 {int(AttrDomain::Instance),
"INSTANCE", 0,
"Instance",
""},
1262 {0,
nullptr, 0,
nullptr,
nullptr},
1268 "Which domain to duplicate",
1271 int(AttrDomain::Point),
1280 ntype.
ui_name =
"Duplicate Elements";
1281 ntype.
ui_description =
"Generate an arbitrary number copies of each selected input element";
1285 "NodeGeometryDuplicateElements",
Low-level operations for curves.
Low-level operations for grease pencil.
void BKE_grease_pencil_copy_parameters(const GreasePencil &src, GreasePencil &dst)
GreasePencil * BKE_grease_pencil_new_nomain()
void BKE_grease_pencil_copy_layer_parameters(const blender::bke::greasepencil::Layer &src, blender::bke::greasepencil::Layer &dst)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
#define NODE_STORAGE_FUNCS(StorageT)
#define NODE_CLASS_GEOMETRY
#define GEO_NODE_DUPLICATE_ELEMENTS
General operations for point clouds.
PointCloud * BKE_pointcloud_new_nomain(int totpoint)
#define BLI_assert_unreachable()
#define BLT_I18NCONTEXT_COUNTABLE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_storage_enum_accessors(member)
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
MutableSpan< T > as_mutable_span()
const T & last(const int64_t n=0) const
void reinitialize(const int64_t new_size)
const CPPType & type() const
VArray< T > typed() const
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr T & last(const int64_t n=0) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
std::optional< T > get_if_single() const
void append(const T &value)
GAttributeReader lookup(const StringRef attribute_id) const
Array< int > point_to_curve_map() const
OffsetIndices< int > points_by_curve() const
void update_curve_types()
MutableAttributeAccessor attributes_for_write()
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
Span< int > reference_handles() const
Span< InstanceReference > references() const
bke::AttributeAccessor attributes() const
int instances_num() const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void set_selection(Field< bool > selection)
int add(GField field, GVArray *varray_ptr)
IndexMask get_evaluated_selection_as_mask() const
const GVArray & get_evaluated(const int field_index) const
void foreach_index_optimized(Fn &&fn) const
IndexRange index_range() const
void foreach_index(Fn &&fn) const
static std::shared_ptr< FieldOperation > from(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
static void remember_deformed_positions_if_necessary(GeometrySet &geometry)
IndexRange index_range() const
void * MEM_callocN(size_t len, const char *str)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void fill_index_range(MutableSpan< T > span, const T start=0)
void gather(GSpan src, Span< int > map, GMutableSpan dst)
void gather_to_groups(OffsetIndices< int > dst_offsets, const IndexMask &src_selection, GSpan src, GMutableSpan dst)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void curves_copy_parameters(const Curves &src, Curves &dst)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
void gather_attributes_to_groups(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, OffsetIndices< int > dst_offsets, const IndexMask &src_selection, MutableAttributeAccessor dst_attributes)
void node_register_type(bNodeType &ntype)
auto attribute_filter_with_skip_ref(AttributeFilter filter, const Span< StringRef > skip)
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))
Curves * curves_new_nomain(int points_num, int curves_num)
void foreach_real_geometry(bke::GeometrySet &geometry, FunctionRef< void(bke::GeometrySet &geometry_set)> fn)
static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const OffsetIndices< int > offsets, bke::CurvesGeometry &dst_curves)
static void duplicate_points_grease_pencil(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void duplicate_points_pointcloud(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void duplicate_faces(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static OffsetIndices< int > accumulate_counts_to_offsets(const IndexMask &selection, const VArray< int > &counts, Array< int > &r_offset_data)
static void node_rna(StructRNA *srna)
static void node_init(bNodeTree *, bNode *node)
static void copy_edge_attributes_without_id(const Span< int > point_mapping, const OffsetIndices< int > offsets, const IndexMask &selection, const AttributeFilter &attribute_filter, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void duplicate_instances(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static bke::CurvesGeometry duplicate_curves_CurveGeometry(const bke::CurvesGeometry &curves, const FieldContext &field_context, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void copy_stable_id_faces(const Mesh &mesh, const IndexMask &selection, const OffsetIndices< int > face_offsets, const Span< int > vert_mapping, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void copy_hashed_ids(const Span< int > src, const int hash, MutableSpan< int > dst)
static void duplicate_layers(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void duplicate_curves(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void copy_stable_id_edges(const Mesh &mesh, const IndexMask &selection, const OffsetIndices< int > offsets, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void copy_face_attributes_without_id(const Span< int > edge_mapping, const Span< int > vert_mapping, const Span< int > loop_mapping, const OffsetIndices< int > offsets, const IndexMask &selection, const AttributeFilter &attribute_filter, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void node_declare(NodeDeclarationBuilder &b)
static void duplicate_points_curve(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static bke::CurvesGeometry duplicate_points_CurvesGeometry(const bke::CurvesGeometry &src_curves, const FieldContext &field_context, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void duplicate_points_mesh(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void copy_curve_attributes_without_id(const bke::CurvesGeometry &src_curves, const IndexMask &selection, const OffsetIndices< int > curve_offsets, const AttributeFilter &attribute_filter, bke::CurvesGeometry &dst_curves)
static void node_geo_exec(GeoNodeExecParams params)
static void create_duplicate_index_attribute(bke::MutableAttributeAccessor attributes, const AttrDomain output_domain, const IndexMask &selection, const IndexAttributes &attribute_outputs, const OffsetIndices< int > offsets)
static void duplicate_edges(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void threaded_id_offset_copy(const OffsetIndices< int > offsets, const Span< int > src, MutableSpan< int > all_dst)
static void copy_stable_id_point(const OffsetIndices< int > offsets, const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes)
static void duplicate_points(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs, const AttributeFilter &attribute_filter)
static void node_register()
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)
uint32_t hash(uint32_t kx)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void fill_constant_group_size(int size, int start_offset, MutableSpan< int > offsets)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
VecBase< int32_t, 2 > int2
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)
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void keep_only(Span< GeometryComponent::Type > component_types)
const GreasePencil * get_grease_pencil() const
bool has_pointcloud() const
void replace_pointcloud(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Curves * get_curves() const
const Instances * get_instances() const
bool has_grease_pencil() const
bool has_instances() const
void replace_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const PointCloud * get_pointcloud() const
const Mesh * get_mesh() const
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GreasePencil * get_grease_pencil_for_write()
Vector< GeometryComponent::Type > gather_component_types(bool include_instances, bool ignore_empty) const
void replace_grease_pencil(GreasePencil *grease_pencil, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
MutableVArraySpan< T > span
std::string ui_description
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeGeometryExecFunction geometry_node_execute
const char * enum_name_legacy
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeDeclareFunction declare
std::optional< std::string > duplicate_index
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)