Blender V4.5
curves_attributes.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_listbase.h"
6
7#include "DNA_object_types.h"
8
9#include "BKE_curves.hh"
10#include "BKE_deform.hh"
11
13
15
16namespace blender::bke::curves {
17
18static void tag_component_topology_changed(void *owner)
19{
20 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
21 curves.tag_topology_changed();
22}
23
24static void tag_component_curve_types_changed(void *owner)
25{
26 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
27 curves.update_curve_types();
28 curves.tag_topology_changed();
29}
30
31static void tag_component_positions_changed(void *owner)
32{
33 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
34 curves.tag_positions_changed();
35}
36
37static void tag_component_radii_changed(void *owner)
38{
39 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
40 curves.tag_radii_changed();
41}
42
43static void tag_component_normals_changed(void *owner)
44{
45 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
46 curves.tag_normals_changed();
47}
48
50{
51 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
52 curves.tag_material_index_changed();
53}
54
59 public:
60 GAttributeReader try_get_for_read(const void *owner, const StringRef attribute_id) const final
61 {
62 const CurvesGeometry *curves = static_cast<const CurvesGeometry *>(owner);
63 if (curves == nullptr) {
64 return {};
65 }
66 const int vertex_group_index = BKE_defgroup_name_index(&curves->vertex_group_names,
67 attribute_id);
68 if (vertex_group_index < 0) {
69 return {};
70 }
71 const Span<MDeformVert> dverts = curves->deform_verts();
72 return this->get_for_vertex_group_index(*curves, dverts, vertex_group_index);
73 }
74
76 const Span<MDeformVert> dverts,
77 const int vertex_group_index) const
78 {
79 BLI_assert(vertex_group_index >= 0);
80 if (dverts.is_empty()) {
81 return {VArray<float>::ForSingle(0.0f, curves.points_num()), AttrDomain::Point};
82 }
83 return {varray_for_deform_verts(dverts, vertex_group_index), AttrDomain::Point};
84 }
85
86 GAttributeWriter try_get_for_write(void *owner, const StringRef attribute_id) const final
87 {
88 CurvesGeometry *curves = static_cast<CurvesGeometry *>(owner);
89 if (curves == nullptr) {
90 return {};
91 }
92 const int vertex_group_index = BKE_defgroup_name_index(&curves->vertex_group_names,
93 attribute_id);
94 if (vertex_group_index < 0) {
95 return {};
96 }
97 MutableSpan<MDeformVert> dverts = curves->deform_verts_for_write();
98 return {varray_for_mutable_deform_verts(dverts, vertex_group_index), AttrDomain::Point};
99 }
100
101 bool try_delete(void *owner, const StringRef name) const final
102 {
103 CurvesGeometry *curves = static_cast<CurvesGeometry *>(owner);
104 if (curves == nullptr) {
105 return true;
106 }
107
108 int index;
109 bDeformGroup *group;
110 if (!BKE_defgroup_listbase_name_find(&curves->vertex_group_names, name, &index, &group)) {
111 return false;
112 }
113 BLI_remlink(&curves->vertex_group_names, group);
114 MEM_freeN(group);
115 if (curves->deform_verts().is_empty()) {
116 return true;
117 }
118
119 MutableSpan<MDeformVert> dverts = curves->deform_verts_for_write();
120 remove_defgroup_index(dverts, index);
121 return true;
122 }
123
124 bool foreach_attribute(const void *owner,
125 FunctionRef<void(const AttributeIter &)> fn) const final
126 {
127 const CurvesGeometry *curves = static_cast<const CurvesGeometry *>(owner);
128 if (curves == nullptr) {
129 return true;
130 }
131 const Span<MDeformVert> dverts = curves->deform_verts();
132
133 int group_index = 0;
134 LISTBASE_FOREACH_INDEX (const bDeformGroup *, group, &curves->vertex_group_names, group_index)
135 {
136 const auto get_fn = [&]() {
137 return this->get_for_vertex_group_index(*curves, dverts, group_index);
138 };
139 AttributeIter iter{group->name, AttrDomain::Point, CD_PROP_FLOAT, get_fn};
140 fn(iter);
141 if (iter.is_stopped()) {
142 return false;
143 }
144 }
145 return true;
146 }
147
148 void foreach_domain(const FunctionRef<void(AttrDomain)> callback) const final
149 {
150 callback(AttrDomain::Point);
151 }
152};
153
159{
160 static CustomDataAccessInfo curve_access = {
161 [](void *owner) -> CustomData * {
162 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
163 return &curves.curve_data;
164 },
165 [](const void *owner) -> const CustomData * {
166 const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
167 return &curves.curve_data;
168 },
169 [](const void *owner) -> int {
170 const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
171 return curves.curves_num();
172 }};
173 static CustomDataAccessInfo point_access = {
174 [](void *owner) -> CustomData * {
175 CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
176 return &curves.point_data;
177 },
178 [](const void *owner) -> const CustomData * {
179 const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
180 return &curves.point_data;
181 },
182 [](const void *owner) -> int {
183 const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
184 return curves.points_num();
185 }};
186
187 static BuiltinCustomDataLayerProvider position("position",
191 point_access,
193
194 static BuiltinCustomDataLayerProvider radius("radius",
198 point_access,
200
205 point_access,
206 nullptr);
207
208 static BuiltinCustomDataLayerProvider tilt("tilt",
212 point_access,
214
215 static BuiltinCustomDataLayerProvider handle_right("handle_right",
219 point_access,
221
222 static BuiltinCustomDataLayerProvider handle_left("handle_left",
226 point_access,
228
229 static auto handle_type_clamp = mf::build::SI1_SO<int8_t, int8_t>(
230 "Handle Type Validate",
231 [](int8_t value) {
232 return std::clamp<int8_t>(value, BEZIER_HANDLE_FREE, BEZIER_HANDLE_ALIGN);
233 },
234 mf::build::exec_presets::AllSpanOrSingle());
235 static BuiltinCustomDataLayerProvider handle_type_right("handle_type_right",
239 point_access,
241 AttributeValidator{&handle_type_clamp});
242
243 static BuiltinCustomDataLayerProvider handle_type_left("handle_type_left",
247 point_access,
249 AttributeValidator{&handle_type_clamp});
250
251 static float default_nurbs_weight = 1.0f;
252 static BuiltinCustomDataLayerProvider nurbs_weight("nurbs_weight",
256 point_access,
258 {},
259 &default_nurbs_weight);
260
261 static const auto nurbs_order_clamp = mf::build::SI1_SO<int8_t, int8_t>(
262 "NURBS Order Validate",
263 [](int8_t value) { return std::max<int8_t>(value, 1); },
264 mf::build::exec_presets::AllSpanOrSingle());
265 static int nurbs_order_default = 4;
266 static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
270 curve_access,
272 AttributeValidator{&nurbs_order_clamp},
273 &nurbs_order_default);
274
275 static const auto normal_mode_clamp = mf::build::SI1_SO<int8_t, int8_t>(
276 "Normal Mode Validate",
277 [](int8_t value) {
278 return std::clamp<int8_t>(value, NORMAL_MODE_MINIMUM_TWIST, NORMAL_MODE_FREE);
279 },
280 mf::build::exec_presets::AllSpanOrSingle());
281 static BuiltinCustomDataLayerProvider normal_mode("normal_mode",
285 curve_access,
287 AttributeValidator{&normal_mode_clamp});
288
289 static BuiltinCustomDataLayerProvider custom_normal("custom_normal",
293 point_access,
295
296 static const auto knots_mode_clamp = mf::build::SI1_SO<int8_t, int8_t>(
297 "Knots Mode Validate",
298 [](int8_t value) {
299 return std::clamp<int8_t>(value, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
300 },
301 mf::build::exec_presets::AllSpanOrSingle());
302 static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
306 curve_access,
308 AttributeValidator{&knots_mode_clamp});
309
310 static const auto curve_type_clamp = mf::build::SI1_SO<int8_t, int8_t>(
311 "Curve Type Validate",
312 [](int8_t value) {
313 return std::clamp<int8_t>(value, CURVE_TYPE_CATMULL_ROM, CURVE_TYPES_NUM);
314 },
315 mf::build::exec_presets::AllSpanOrSingle());
316 static BuiltinCustomDataLayerProvider curve_type("curve_type",
320 curve_access,
322 AttributeValidator{&curve_type_clamp});
323
324 static const auto resolution_clamp = mf::build::SI1_SO<int, int>(
325 "Resolution Validate",
326 [](int value) { return std::max<int>(value, 1); },
327 mf::build::exec_presets::AllSpanOrSingle());
328 static int resolution_default = 12;
329 static BuiltinCustomDataLayerProvider resolution("resolution",
333 curve_access,
335 AttributeValidator{&resolution_clamp},
336 &resolution_default);
337
338 static BuiltinCustomDataLayerProvider cyclic("cyclic",
342 curve_access,
344
345 static const auto material_index_clamp = mf::build::SI1_SO<int, int>(
346 "Material Index Validate",
347 [](int value) {
348 /* Use #short for the maximum since many areas still use that type for indices. */
349 return std::clamp<int>(value, 0, std::numeric_limits<short>::max());
350 },
351 mf::build::exec_presets::AllSpanOrSingle());
352 static BuiltinCustomDataLayerProvider material_index("material_index",
356 curve_access,
358 AttributeValidator{&material_index_clamp});
359
360 static CurvesVertexGroupsAttributeProvider vertex_groups;
361 static CustomDataAttributeProvider curve_custom_data(AttrDomain::Curve, curve_access);
362 static CustomDataAttributeProvider point_custom_data(AttrDomain::Point, point_access);
363
364 return GeometryAttributeProviders({&position,
365 &radius,
366 &id,
367 &tilt,
368 &handle_right,
369 &handle_left,
370 &handle_type_right,
371 &handle_type_left,
372 &normal_mode,
373 &custom_normal,
374 &nurbs_order,
375 &nurbs_knots_mode,
376 &nurbs_weight,
377 &curve_type,
378 &resolution,
379 &cyclic,
380 &material_index},
381 {&vertex_groups, &curve_custom_data, &point_custom_data});
382}
383
385
387{
391 fn.domain_size = [](const void *owner, const AttrDomain domain) {
392 if (owner == nullptr) {
393 return 0;
394 }
395 const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
396 switch (domain) {
398 return curves.points_num();
400 return curves.curves_num();
401 default:
402 return 0;
403 }
404 };
405 fn.domain_supported = [](const void * /*owner*/, const AttrDomain domain) {
407 };
408 fn.adapt_domain = [](const void *owner,
409 const GVArray &varray,
410 const AttrDomain from_domain,
411 const AttrDomain to_domain) -> GVArray {
412 if (owner == nullptr) {
413 return {};
414 }
415 const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
416 return curves.adapt_domain(varray, from_domain, to_domain);
417 };
418 return fn;
419}
420
426
427} // namespace blender::bke::curves
Low-level operations for curves.
support for deformation groups and hooks.
bool BKE_defgroup_listbase_name_find(const ListBase *defbase, blender::StringRef name, int *r_index, bDeformGroup **r_group)
Definition deform.cc:543
int BKE_defgroup_name_index(const ListBase *defbase, blender::StringRef name)
Definition deform.cc:529
#define BLI_assert(a)
Definition BLI_assert.h:46
#define final(a, b, c)
Definition BLI_hash.h:19
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
#define ELEM(...)
@ CURVE_TYPE_CATMULL_ROM
@ NORMAL_MODE_MINIMUM_TWIST
@ NORMAL_MODE_FREE
#define CURVE_TYPES_NUM
@ BEZIER_HANDLE_FREE
@ BEZIER_HANDLE_ALIGN
@ NURBS_KNOT_MODE_NORMAL
@ NURBS_KNOT_MODE_ENDPOINT_BEZIER
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT32
Object is a sort of wrapper for general info.
constexpr bool is_empty() const
Definition BLI_span.hh:260
static VArray ForSingle(T value, const int64_t size)
bool foreach_attribute(const void *owner, FunctionRef< void(const AttributeIter &)> fn) const final
GAttributeReader try_get_for_read(const void *owner, const StringRef attribute_id) const final
void foreach_domain(const FunctionRef< void(AttrDomain)> callback) const final
GAttributeWriter try_get_for_write(void *owner, const StringRef attribute_id) const final
bool try_delete(void *owner, const StringRef name) const final
GAttributeReader get_for_vertex_group_index(const CurvesGeometry &curves, const Span< MDeformVert > dverts, const int vertex_group_index) const
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
AttributeAccessorFunctions accessor_functions_for_providers()
static GeometryAttributeProviders create_attribute_providers_for_curve()
static void tag_component_curve_types_changed(void *owner)
static void tag_component_positions_changed(void *owner)
const AttributeAccessorFunctions & get_attribute_accessor_functions()
static void tag_component_topology_changed(void *owner)
static void tag_component_radii_changed(void *owner)
static AttributeAccessorFunctions get_curves_accessor_functions()
static void tag_component_material_index_changed(void *owner)
static void tag_component_normals_changed(void *owner)
void remove_defgroup_index(MutableSpan< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1793
VMutableArray< float > varray_for_mutable_deform_verts(MutableSpan< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1787
VArray< float > varray_for_deform_verts(Span< MDeformVert > dverts, int defgroup_index)
Definition deform.cc:1783