Blender  V3.3
abc_reader_curves.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2016 Kévin Dietrich. All rights reserved. */
3 
8 #include "abc_reader_curves.h"
9 #include "abc_axis_conversion.h"
10 #include "abc_reader_transform.h"
11 #include "abc_util.h"
12 
13 #include <cstdio>
14 
15 #include "MEM_guardedalloc.h"
16 
17 #include "DNA_curve_types.h"
18 #include "DNA_object_types.h"
19 
20 #include "BLI_listbase.h"
21 
22 #include "BKE_curve.h"
23 #include "BKE_mesh.h"
24 #include "BKE_object.h"
25 
26 using Alembic::Abc::FloatArraySamplePtr;
27 using Alembic::Abc::Int32ArraySamplePtr;
28 using Alembic::Abc::P3fArraySamplePtr;
29 using Alembic::Abc::PropertyHeader;
30 using Alembic::Abc::UcharArraySamplePtr;
31 
32 using Alembic::AbcGeom::CurvePeriodicity;
33 using Alembic::AbcGeom::ICompoundProperty;
34 using Alembic::AbcGeom::ICurves;
35 using Alembic::AbcGeom::ICurvesSchema;
36 using Alembic::AbcGeom::IFloatGeomParam;
37 using Alembic::AbcGeom::IInt16Property;
38 using Alembic::AbcGeom::ISampleSelector;
39 using Alembic::AbcGeom::kWrapExisting;
40 
41 namespace blender::io::alembic {
42 
43 AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
44  : AbcObjectReader(object, settings)
45 {
46  ICurves abc_curves(object, kWrapExisting);
47  m_curves_schema = abc_curves.getSchema();
48 
49  get_min_max_time(m_iobject, m_curves_schema, m_min_time, m_max_time);
50 }
51 
53 {
54  return m_curves_schema.valid();
55 }
56 
58  const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
59  const Object *const ob,
60  const char **err_str) const
61 {
62  if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
63  *err_str =
64  "Object type mismatch, Alembic object path pointed to Curves when importing, but not any "
65  "more.";
66  return false;
67  }
68 
69  if (ob->type != OB_CURVES_LEGACY) {
70  *err_str = "Object type mismatch, Alembic object path points to Curves.";
71  return false;
72  }
73 
74  return true;
75 }
76 
77 void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
78 {
79  Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVES_LEGACY);
80 
81  cu->flag |= CU_3D;
82  cu->actvert = CU_ACT_NONE;
83  cu->resolu = 1;
84 
85  ICompoundProperty user_props = m_curves_schema.getUserProperties();
86  if (user_props) {
87  const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
88  if (header != nullptr && header->isScalar() && IInt16Property::matches(*header)) {
89  IInt16Property resolu(user_props, header->getName());
90  cu->resolu = resolu.getValue(sample_sel);
91  }
92  }
93 
95  m_object->data = cu;
96 
97  read_curve_sample(cu, m_curves_schema, sample_sel);
98 
99  if (m_settings->always_add_cache_reader || has_animations(m_curves_schema, m_settings)) {
101  }
102 }
103 
105  const ICurvesSchema &schema,
106  const ISampleSelector &sample_sel)
107 {
108  ICurvesSchema::Sample smp;
109  try {
110  smp = schema.getValue(sample_sel);
111  }
112  catch (Alembic::Util::Exception &ex) {
113  printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
114  m_iobject.getFullName().c_str(),
115  schema.getName().c_str(),
116  sample_sel.getRequestedTime(),
117  ex.what());
118  return;
119  }
120 
121  const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
122  const P3fArraySamplePtr positions = smp.getPositions();
123  const FloatArraySamplePtr weights = smp.getPositionWeights();
124  const FloatArraySamplePtr knots = smp.getKnots();
125  const CurvePeriodicity periodicity = smp.getWrap();
126  const UcharArraySamplePtr orders = smp.getOrders();
127 
128  const IFloatGeomParam widths_param = schema.getWidthsParam();
129  FloatArraySamplePtr radiuses;
130 
131  if (widths_param.valid()) {
132  IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
133  radiuses = wsample.getVals();
134  }
135 
136  int knot_offset = 0;
137 
138  size_t idx = 0;
139  for (size_t i = 0; i < num_vertices->size(); i++) {
140  const int num_verts = (*num_vertices)[i];
141 
142  Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
143  nu->resolu = cu->resolu;
144  nu->resolv = cu->resolv;
145  nu->pntsu = num_verts;
146  nu->pntsv = 1;
147  nu->flag |= CU_SMOOTH;
148 
149  switch (smp.getType()) {
150  case Alembic::AbcGeom::kCubic:
151  nu->orderu = 4;
152  break;
153  case Alembic::AbcGeom::kVariableOrder:
154  if (orders && orders->size() > i) {
155  nu->orderu = static_cast<short>((*orders)[i]);
156  break;
157  }
159  case Alembic::AbcGeom::kLinear:
160  default:
161  nu->orderu = 2;
162  }
163 
164  if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
165  nu->flagu |= CU_NURB_ENDPOINT;
166  }
167  else if (periodicity == Alembic::AbcGeom::kPeriodic) {
168  nu->flagu |= CU_NURB_CYCLIC;
169 
170  /* Check the number of points which overlap, we don't have
171  * overlapping points in Blender, but other software do use them to
172  * indicate that a curve is actually cyclic. Usually the number of
173  * overlapping points is equal to the order/degree of the curve.
174  */
175 
176  const int start = idx;
177  const int end = idx + num_verts;
178  int overlap = 0;
179 
180  for (int j = start, k = end - nu->orderu; j < nu->orderu; j++, k++) {
181  const Imath::V3f &p1 = (*positions)[j];
182  const Imath::V3f &p2 = (*positions)[k];
183 
184  if (p1 != p2) {
185  break;
186  }
187 
188  overlap++;
189  }
190 
191  /* TODO: Special case, need to figure out how it coincides with knots. */
192  if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
193  overlap = 1;
194  }
195 
196  /* There is no real cycles. */
197  if (overlap == 0) {
198  nu->flagu &= ~CU_NURB_CYCLIC;
199  nu->flagu |= CU_NURB_ENDPOINT;
200  }
201 
202  nu->pntsu -= overlap;
203  }
204 
205  const bool do_weights = (weights != nullptr) && (weights->size() > 1);
206  float weight = 1.0f;
207 
208  const bool do_radius = (radiuses != nullptr) && (radiuses->size() > 1);
209  float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
210 
211  nu->type = CU_NURBS;
212 
213  nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
214  BPoint *bp = nu->bp;
215 
216  for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
217  const Imath::V3f &pos = (*positions)[idx];
218 
219  if (do_radius) {
220  radius = (*radiuses)[idx];
221  }
222 
223  if (do_weights) {
224  weight = (*weights)[idx];
225  }
226 
227  copy_zup_from_yup(bp->vec, pos.getValue());
228  bp->vec[3] = weight;
229  bp->f1 = SELECT;
230  bp->radius = radius;
231  bp->weight = 1.0f;
232  }
233 
234  if (knots && knots->size() != 0) {
235  nu->knotsu = static_cast<float *>(
236  MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
237 
238  /* TODO: second check is temporary, for until the check for cycles is rock solid. */
239  if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
240  /* Skip first and last knots. */
241  for (size_t i = 1; i < knots->size() - 1; i++) {
242  nu->knotsu[i - 1] = (*knots)[knot_offset + i];
243  }
244  }
245  else {
246  /* TODO: figure out how to use the knots array from other
247  * software in this case. */
249  }
250 
251  knot_offset += knots->size();
252  }
253  else {
255  }
256 
258  }
259 }
260 
262  const ISampleSelector &sample_sel,
263  int /*read_flag*/,
264  const char * /*velocity_name*/,
265  const float /*velocity_scale*/,
266  const char **err_str)
267 {
268  ICurvesSchema::Sample sample;
269 
270  try {
271  sample = m_curves_schema.getValue(sample_sel);
272  }
273  catch (Alembic::Util::Exception &ex) {
274  *err_str = "Error reading curve sample; more detail on the console";
275  printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
276  m_iobject.getFullName().c_str(),
277  m_curves_schema.getName().c_str(),
278  sample_sel.getRequestedTime(),
279  ex.what());
280  return existing_mesh;
281  }
282 
283  const P3fArraySamplePtr &positions = sample.getPositions();
284  const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices();
285 
286  int vertex_idx = 0;
287  int curve_idx;
288  Curve *curve = static_cast<Curve *>(m_object->data);
289 
290  const int curve_count = BLI_listbase_count(&curve->nurb);
291  bool same_topology = curve_count == num_vertices->size();
292 
293  if (same_topology) {
294  Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
295  for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
296  const int num_in_alembic = (*num_vertices)[curve_idx];
297  const int num_in_blender = nurbs->pntsu;
298 
299  if (num_in_alembic != num_in_blender) {
300  same_topology = false;
301  break;
302  }
303  }
304  }
305 
306  if (!same_topology) {
308  read_curve_sample(curve, m_curves_schema, sample_sel);
309  }
310  else {
311  Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
312  for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
313  const int totpoint = (*num_vertices)[curve_idx];
314 
315  if (nurbs->bp) {
316  BPoint *point = nurbs->bp;
317 
318  for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
319  const Imath::V3f &pos = (*positions)[vertex_idx];
320  copy_zup_from_yup(point->vec, pos.getValue());
321  }
322  }
323  else if (nurbs->bezt) {
324  BezTriple *bezier = nurbs->bezt;
325 
326  for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
327  const Imath::V3f &pos = (*positions)[vertex_idx];
328  copy_zup_from_yup(bezier->vec[1], pos.getValue());
329  }
330  }
331  }
332  }
333 
335 }
336 
337 } // namespace blender::io::alembic
#define KNOTSU(nu)
Definition: BKE_curve.h:52
struct Curve * BKE_curve_add(struct Main *bmain, const char *name, int type)
Definition: curve.cc:414
void BKE_nurb_knot_calc_u(struct Nurb *nu)
Definition: curve.cc:1234
void BKE_nurbList_free(struct ListBase *lb)
Definition: curve.cc:649
ListBase * BKE_curve_nurbs_get(struct Curve *cu)
Definition: curve.cc:4976
struct Mesh * BKE_mesh_new_nomain_from_curve(const struct Object *ob)
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_add_only_object(struct Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
Definition: object.cc:2241
#define ATTR_FALLTHROUGH
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ CU_NURBS
@ CU_SMOOTH
#define CU_ACT_NONE
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
@ CU_3D
Object is a sort of wrapper for general info.
@ OB_CURVES_LEGACY
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **err_str) const override
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override
void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const Alembic::Abc::ISampleSelector &sample_selector)
struct Mesh * read_mesh(struct Mesh *existing_mesh, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **err_str) override
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
#define SELECT
Curve curve
uint pos
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max)
Definition: abc_util.h:66
BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
const std::string ABC_CURVE_RESOLUTION_U_PROPNAME
bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
MutableSpan< float3 > positions
float weight
uint8_t f1
float vec[4]
float radius
float vec[3][3]
short resolv
short resolu
ListBase nurb
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
short flagu
short orderu
struct Nurb * next
float * knotsu
short flag
short type
BezTriple * bezt
BPoint * bp
short resolu
short resolv
void * data