Blender  V3.3
geometry_component_curves.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 
5 #include "DNA_ID_enums.h"
6 #include "DNA_curve_types.h"
7 
8 #include "BKE_attribute_math.hh"
9 #include "BKE_curve.h"
10 #include "BKE_curves.hh"
11 #include "BKE_geometry_fields.hh"
12 #include "BKE_geometry_set.hh"
13 #include "BKE_lib_id.h"
14 
16 
17 using blender::GVArray;
18 
19 /* -------------------------------------------------------------------- */
24 {
25 }
26 
28 {
29  this->clear();
30 }
31 
33 {
34  CurveComponent *new_component = new CurveComponent();
35  if (curves_ != nullptr) {
36  new_component->curves_ = BKE_curves_copy_for_eval(curves_, false);
37  new_component->ownership_ = GeometryOwnershipType::Owned;
38  }
39  return new_component;
40 }
41 
43 {
44  BLI_assert(this->is_mutable());
45  if (curves_ != nullptr) {
46  if (ownership_ == GeometryOwnershipType::Owned) {
47  BKE_id_free(nullptr, curves_);
48  }
49  if (curve_for_render_ != nullptr) {
50  /* The curve created by this component should not have any edit mode data. */
51  BLI_assert(curve_for_render_->editfont == nullptr && curve_for_render_->editnurb == nullptr);
52  BKE_id_free(nullptr, curve_for_render_);
53  curve_for_render_ = nullptr;
54  }
55 
56  curves_ = nullptr;
57  }
58 }
59 
61 {
62  return curves_ != nullptr;
63 }
64 
66 {
67  BLI_assert(this->is_mutable());
68  this->clear();
69  curves_ = curves;
70  ownership_ = ownership;
71 }
72 
74 {
75  BLI_assert(this->is_mutable());
76  Curves *curves = curves_;
77  curves_ = nullptr;
78  return curves;
79 }
80 
82 {
83  return curves_;
84 }
85 
87 {
88  BLI_assert(this->is_mutable());
89  if (ownership_ == GeometryOwnershipType::ReadOnly) {
90  curves_ = BKE_curves_copy_for_eval(curves_, false);
91  ownership_ = GeometryOwnershipType::Owned;
92  }
93  return curves_;
94 }
95 
97 {
98  return curves_ == nullptr;
99 }
100 
102 {
103  return ownership_ == GeometryOwnershipType::Owned;
104 }
105 
107 {
108  BLI_assert(this->is_mutable());
109  if (ownership_ != GeometryOwnershipType::Owned) {
110  curves_ = BKE_curves_copy_for_eval(curves_, false);
111  ownership_ = GeometryOwnershipType::Owned;
112  }
113 }
114 
116 {
117  if (curves_ == nullptr) {
118  return nullptr;
119  }
120  if (curve_for_render_ != nullptr) {
121  return curve_for_render_;
122  }
123  std::lock_guard lock{curve_for_render_mutex_};
124  if (curve_for_render_ != nullptr) {
125  return curve_for_render_;
126  }
127 
128  curve_for_render_ = (Curve *)BKE_id_new_nomain(ID_CU_LEGACY, nullptr);
129  curve_for_render_->curve_eval = curves_;
130 
131  return curve_for_render_;
132 }
133 
136 namespace blender::bke {
137 
138 /* -------------------------------------------------------------------- */
143 {
144  const VArray<int8_t> types = curves.curve_types();
145  const VArray<int> resolutions = curves.resolution();
146  const VArray<bool> curves_cyclic = curves.cyclic();
147 
148  const Span<float3> positions = curves.positions();
149  const VArray<int8_t> normal_modes = curves.normal_mode();
150 
151  const Span<float3> evaluated_normals = curves.evaluated_normals();
152 
153  Array<float3> results(curves.points_num());
154 
155  threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
156  Vector<float3> nurbs_tangents;
157 
158  for (const int i_curve : range) {
159  const IndexRange points = curves.points_for_curve(i_curve);
160  const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve);
161 
162  MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points);
163 
164  switch (types[i_curve]) {
165  case CURVE_TYPE_CATMULL_ROM: {
166  const Span<float3> normals = evaluated_normals.slice(evaluated_points);
167  const int resolution = resolutions[i_curve];
168  for (const int i : IndexRange(points.size())) {
169  curve_normals[i] = normals[resolution * i];
170  }
171  break;
172  }
173  case CURVE_TYPE_POLY:
174  curve_normals.copy_from(evaluated_normals.slice(evaluated_points));
175  break;
176  case CURVE_TYPE_BEZIER: {
177  const Span<float3> normals = evaluated_normals.slice(evaluated_points);
178  curve_normals.first() = normals.first();
179  const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
180  for (const int i : IndexRange(points.size()).drop_front(1)) {
181  curve_normals[i] = normals[offsets[i - 1]];
182  }
183  break;
184  }
185  case CURVE_TYPE_NURBS: {
186  /* For NURBS curves there is no obvious correspondence between specific evaluated points
187  * and control points, so normals are determined by treating them as poly curves. */
188  nurbs_tangents.clear();
189  nurbs_tangents.resize(points.size());
190  const bool cyclic = curves_cyclic[i_curve];
191  const Span<float3> curve_positions = positions.slice(points);
192  bke::curves::poly::calculate_tangents(curve_positions, cyclic, nurbs_tangents);
193  switch (NormalMode(normal_modes[i_curve])) {
194  case NORMAL_MODE_Z_UP:
195  bke::curves::poly::calculate_normals_z_up(nurbs_tangents, curve_normals);
196  break;
197  case NORMAL_MODE_MINIMUM_TWIST:
198  bke::curves::poly::calculate_normals_minimum(nurbs_tangents, cyclic, curve_normals);
199  break;
200  }
201  break;
202  }
203  }
204  }
205  });
206  return results;
207 }
208 
210 {
211  if (!component.has_curves()) {
212  return {};
213  }
214 
215  const Curves &curves_id = *component.get_for_read();
217 
218  const VArray<int8_t> types = curves.curve_types();
219  if (curves.is_single_type(CURVE_TYPE_POLY)) {
220  return component.attributes()->adapt_domain<float3>(
221  VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
222  }
223 
225 
226  if (domain == ATTR_DOMAIN_POINT) {
227  return VArray<float3>::ForContainer(std::move(normals));
228  }
229 
230  if (domain == ATTR_DOMAIN_CURVE) {
231  return component.attributes()->adapt_domain<float3>(
233  }
234 
235  return nullptr;
236 }
237 
240 /* -------------------------------------------------------------------- */
245  const eAttrDomain domain)
246 {
247  if (!component.has_curves()) {
248  return {};
249  }
250  const Curves &curves_id = *component.get_for_read();
252 
253  curves.ensure_evaluated_lengths();
254 
255  VArray<bool> cyclic = curves.cyclic();
257  curves.curves_num(), [&curves, cyclic = std::move(cyclic)](int64_t index) {
258  return curves.evaluated_length_total_for_curve(index, cyclic[index]);
259  });
260 
261  if (domain == ATTR_DOMAIN_CURVE) {
262  return lengths;
263  }
264 
265  if (domain == ATTR_DOMAIN_POINT) {
266  return component.attributes()->adapt_domain<float>(
267  std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
268  }
269 
270  return {};
271 }
272 
273 CurveLengthFieldInput::CurveLengthFieldInput()
274  : GeometryFieldInput(CPPType::get<float>(), "Spline Length node")
275 {
277 }
278 
280  const eAttrDomain domain,
281  IndexMask UNUSED(mask)) const
282 {
283  if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
284  const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
285  return construct_curve_length_gvarray(curve_component, domain);
286  }
287  return {};
288 }
289 
291 {
292  /* Some random constant hash. */
293  return 3549623580;
294 }
295 
297 {
298  return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr;
299 }
300 
303 } // namespace blender::bke
304 
305 /* -------------------------------------------------------------------- */
309 static void tag_component_topology_changed(void *owner)
310 {
312  curves.tag_topology_changed();
313 }
314 
315 static void tag_component_curve_types_changed(void *owner)
316 {
318  curves.update_curve_types();
319  curves.tag_topology_changed();
320 }
321 
322 static void tag_component_positions_changed(void *owner)
323 {
325  curves.tag_positions_changed();
326 }
327 
328 static void tag_component_normals_changed(void *owner)
329 {
331  curves.tag_normals_changed();
332 }
333 
336 namespace blender::bke {
337 
338 /* -------------------------------------------------------------------- */
347 {
348  static CustomDataAccessInfo curve_access = {
349  [](void *owner) -> CustomData * {
350  CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
351  return &curves.curve_data;
352  },
353  [](const void *owner) -> const CustomData * {
354  const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
355  return &curves.curve_data;
356  },
357  [](const void *owner) -> int {
358  const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
359  return curves.curves_num();
360  },
361  [](void * /*owner*/) {}};
362  static CustomDataAccessInfo point_access = {
363  [](void *owner) -> CustomData * {
364  CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
365  return &curves.point_data;
366  },
367  [](const void *owner) -> const CustomData * {
368  const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
369  return &curves.point_data;
370  },
371  [](const void *owner) -> int {
372  const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
373  return curves.points_num();
374  },
375  [](void * /*owner*/) {}};
376 
377  static BuiltinCustomDataLayerProvider position("position",
384  point_access,
385  make_array_read_attribute<float3>,
386  make_array_write_attribute<float3>,
388 
389  static BuiltinCustomDataLayerProvider radius("radius",
396  point_access,
397  make_array_read_attribute<float>,
398  make_array_write_attribute<float>,
399  nullptr);
400 
408  point_access,
409  make_array_read_attribute<int>,
410  make_array_write_attribute<int>,
411  nullptr);
412 
413  static BuiltinCustomDataLayerProvider tilt("tilt",
420  point_access,
421  make_array_read_attribute<float>,
422  make_array_write_attribute<float>,
424 
425  static BuiltinCustomDataLayerProvider handle_right("handle_right",
432  point_access,
433  make_array_read_attribute<float3>,
434  make_array_write_attribute<float3>,
436 
437  static BuiltinCustomDataLayerProvider handle_left("handle_left",
444  point_access,
445  make_array_read_attribute<float3>,
446  make_array_write_attribute<float3>,
448 
449  static BuiltinCustomDataLayerProvider handle_type_right("handle_type_right",
451  CD_PROP_INT8,
452  CD_PROP_INT8,
456  point_access,
457  make_array_read_attribute<int8_t>,
458  make_array_write_attribute<int8_t>,
460 
461  static BuiltinCustomDataLayerProvider handle_type_left("handle_type_left",
463  CD_PROP_INT8,
464  CD_PROP_INT8,
468  point_access,
469  make_array_read_attribute<int8_t>,
470  make_array_write_attribute<int8_t>,
472 
473  static BuiltinCustomDataLayerProvider nurbs_weight("nurbs_weight",
480  point_access,
481  make_array_read_attribute<float>,
482  make_array_write_attribute<float>,
484 
485  static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
487  CD_PROP_INT8,
488  CD_PROP_INT8,
492  curve_access,
493  make_array_read_attribute<int8_t>,
494  make_array_write_attribute<int8_t>,
496 
497  static BuiltinCustomDataLayerProvider normal_mode("normal_mode",
499  CD_PROP_INT8,
500  CD_PROP_INT8,
504  curve_access,
505  make_array_read_attribute<int8_t>,
506  make_array_write_attribute<int8_t>,
508 
509  static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
511  CD_PROP_INT8,
512  CD_PROP_INT8,
516  curve_access,
517  make_array_read_attribute<int8_t>,
518  make_array_write_attribute<int8_t>,
520 
521  static BuiltinCustomDataLayerProvider curve_type("curve_type",
523  CD_PROP_INT8,
524  CD_PROP_INT8,
528  curve_access,
529  make_array_read_attribute<int8_t>,
530  make_array_write_attribute<int8_t>,
532 
533  static BuiltinCustomDataLayerProvider resolution("resolution",
540  curve_access,
541  make_array_read_attribute<int>,
542  make_array_write_attribute<int>,
544 
545  static BuiltinCustomDataLayerProvider cyclic("cyclic",
547  CD_PROP_BOOL,
548  CD_PROP_BOOL,
552  curve_access,
553  make_array_read_attribute<bool>,
554  make_array_write_attribute<bool>,
556 
557  static CustomDataAttributeProvider curve_custom_data(ATTR_DOMAIN_CURVE, curve_access);
558  static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
559 
560  return ComponentAttributeProviders({&position,
561  &radius,
562  &id,
563  &tilt,
564  &handle_right,
565  &handle_left,
566  &handle_type_right,
567  &handle_type_left,
568  &normal_mode,
569  &nurbs_order,
570  &nurbs_knots_mode,
571  &nurbs_weight,
572  &curve_type,
573  &resolution,
574  &cyclic},
575  {&curve_custom_data, &point_custom_data});
576 }
577 
581 {
584  attribute_accessor_functions::accessor_functions_for_providers<providers>();
585  fn.domain_size = [](const void *owner, const eAttrDomain domain) {
586  if (owner == nullptr) {
587  return 0;
588  }
589  const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
590  switch (domain) {
591  case ATTR_DOMAIN_POINT:
592  return curves.points_num();
593  case ATTR_DOMAIN_CURVE:
594  return curves.curves_num();
595  default:
596  return 0;
597  }
598  };
599  fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
600  return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
601  };
602  fn.adapt_domain = [](const void *owner,
603  const blender::GVArray &varray,
604  const eAttrDomain from_domain,
605  const eAttrDomain to_domain) -> GVArray {
606  if (owner == nullptr) {
607  return {};
608  }
609  const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
610  return curves.adapt_domain(varray, from_domain, to_domain);
611  };
612  return fn;
613 }
614 
616 {
618  return fn;
619 }
620 
622 {
624 }
625 
627 {
629 }
630 
631 } // namespace blender::bke
632 
633 std::optional<blender::bke::AttributeAccessor> CurveComponent::attributes() const
634 {
635  return blender::bke::AttributeAccessor(curves_ ? &curves_->geometry : nullptr,
637 }
638 
639 std::optional<blender::bke::MutableAttributeAccessor> CurveComponent::attributes_for_write()
640 {
641  Curves *curves = this->get_for_write();
642  return blender::bke::MutableAttributeAccessor(curves ? &curves->geometry : nullptr,
644 }
typedef float(TangentPoint)[2]
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
struct Curves * BKE_curves_copy_for_eval(struct Curves *curves_src, bool reference)
Definition: curves.cc:271
Low-level operations for curves.
@ GEO_COMPONENT_TYPE_CURVE
GeometryOwnershipType
void * BKE_id_new_nomain(short type, const char *name)
Definition: lib_id.c:1173
void BKE_id_free(struct Main *bmain, void *idv)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED(x)
#define ELEM(...)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
Enumerations for DNA_ID.h.
@ ID_CU_LEGACY
Definition: DNA_ID_enums.h:49
@ CURVE_TYPE_POLY
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_INT8
@ CD_PROP_INT32
@ CD_PROP_BOOL
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
volatile int lock
void ensure_owns_direct_data() override
GeometryComponent * copy() const override
const Curve * get_curve_for_render() const
const Curves * get_for_read() const
bool owns_direct_data() const override
bool is_empty() const final
void replace(Curves *curve, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
std::optional< blender::bke::AttributeAccessor > attributes() const final
std::optional< blender::bke::MutableAttributeAccessor > attributes_for_write() final
bool is_mutable() const
Definition: geometry_set.cc:97
bool is_equal_to(const fn::FieldNode &other) const override
GVArray get_varray_for_context(const GeometryComponent &component, eAttrDomain domain, IndexMask mask) const final
MutableAttributeAccessor attributes_for_write()
AttributeAccessor attributes() const
static void tag_component_topology_changed(void *owner)
static void tag_component_curve_types_changed(void *owner)
static void tag_component_normals_changed(void *owner)
static char ** types
Definition: makesdna.c:67
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
VArray< float3 > curve_normals_varray(const CurveComponent &component, const eAttrDomain domain)
static Array< float3 > curve_normal_point_domain(const bke::CurvesGeometry &curves)
static void tag_component_positions_changed(void *owner)
static AttributeAccessorFunctions get_curves_accessor_functions()
static const AttributeAccessorFunctions & get_curves_accessor_functions_ref()
static ComponentAttributeProviders create_attribute_providers_for_curve()
static VArray< float > construct_curve_length_gvarray(const CurveComponent &component, const eAttrDomain domain)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
MutableSpan< float3 > positions
MutableSpan< float3 > normals
__int64 int64_t
Definition: stdint.h:89
unsigned __int64 uint64_t
Definition: stdint.h:90
const struct Curves * curve_eval
struct EditFont * editfont
EditNurb * editnurb
CurvesGeometry geometry
bool(* domain_supported)(const void *owner, eAttrDomain domain)
GVArray(* adapt_domain)(const void *owner, const GVArray &varray, eAttrDomain from_domain, eAttrDomain to_domain)
int(* domain_size)(const void *owner, eAttrDomain domain)