27using Alembic::Abc::FloatArraySamplePtr;
28using Alembic::Abc::Int32ArraySamplePtr;
29using Alembic::Abc::P3fArraySamplePtr;
30using Alembic::Abc::PropertyHeader;
31using Alembic::Abc::UcharArraySamplePtr;
33using Alembic::AbcGeom::CurvePeriodicity;
34using Alembic::AbcGeom::ICompoundProperty;
35using Alembic::AbcGeom::ICurves;
36using Alembic::AbcGeom::ICurvesSchema;
37using Alembic::AbcGeom::IFloatGeomParam;
38using Alembic::AbcGeom::IInt16Property;
39using Alembic::AbcGeom::ISampleSelector;
40using Alembic::AbcGeom::kWrapExisting;
44 const Alembic::Abc::ISampleSelector &sample_sel)
46 ICompoundProperty user_props = schema.getUserProperties();
52 if (!header || !header->isScalar() || !IInt16Property::matches(*header)) {
56 IInt16Property resolu(user_props, header->getName());
57 return resolu.getValue(sample_sel);
61 const UcharArraySamplePtr orders,
62 const size_t curve_index)
64 switch (abc_curve_type) {
65 case Alembic::AbcGeom::kCubic:
67 case Alembic::AbcGeom::kVariableOrder:
68 if (orders && orders->size() > curve_index) {
69 return int16_t((*orders)[curve_index]);
72 case Alembic::AbcGeom::kLinear:
80 if (abc_curve_type == Alembic::AbcGeom::kCubic) {
97 const int start = idx;
98 const int end = idx + num_verts;
101 const int safe_order = order <= num_verts ? order : num_verts;
102 for (
int j = start, k = end - safe_order; j < (start + safe_order); j++, k++) {
103 const Imath::V3f &p1 = (*positions)[j];
104 const Imath::V3f &p2 = (*positions)[k];
114 if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
124 case Alembic::AbcGeom::kNoBasis:
126 case Alembic::AbcGeom::kBezierBasis:
128 case Alembic::AbcGeom::kBsplineBasis:
130 case Alembic::AbcGeom::kCatmullromBasis:
132 case Alembic::AbcGeom::kHermiteBasis:
133 case Alembic::AbcGeom::kPowerBasis:
142 return is_cyclic ? (alembic_count / 3) : ((alembic_count / 3) + 1);
155 if (curves.offsets() != preprocessed_offsets) {
186 P3fArraySamplePtr positions =
nullptr;
188 FloatArraySamplePtr radii =
nullptr;
195 const ICurvesSchema &schema,
196 const ISampleSelector sample_sel)
199 ICurvesSchema::Sample smp;
201 smp = schema.getValue(sample_sel);
203 catch (Alembic::Util::Exception &ex) {
204 printf(
"Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
205 iobject_name.
c_str(),
206 schema.getName().c_str(),
207 sample_sel.getRequestedTime(),
214 const Int32ArraySamplePtr per_curve_vertices_count = smp.getCurvesNumVertices();
215 const P3fArraySamplePtr positions = smp.getPositions();
216 const FloatArraySamplePtr weights = smp.getPositionWeights();
217 const CurvePeriodicity periodicity = smp.getWrap();
218 const UcharArraySamplePtr orders = smp.getOrders();
220 if (positions->size() == 0) {
224 const IFloatGeomParam widths_param = schema.getWidthsParam();
225 FloatArraySamplePtr radii;
226 if (widths_param.valid()) {
227 IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
228 radii = wsample.getVals();
231 const int curve_count = per_curve_vertices_count->size();
236 data.offset_in_alembic.resize(curve_count + 1);
237 data.curves_cyclic.resize(curve_count);
240 data.do_cyclic = periodicity == Alembic::AbcGeom::kPeriodic;
245 if (smp.getType() == Alembic::AbcGeom::kVariableOrder && !orders) {
248 data.do_cyclic =
false;
252 data.curves_orders.resize(curve_count);
257 int blender_offset = 0;
258 int alembic_offset = 0;
259 for (
size_t i = 0; i < curve_count; i++) {
260 const int vertices_count = (*per_curve_vertices_count)[i];
264 data.offset_in_blender[i] = blender_offset;
265 data.offset_in_alembic[i] = alembic_offset;
266 data.curves_cyclic[i] = data.do_cyclic;
269 data.curves_orders[i] = curve_order;
274 const int overlap = data.do_cyclic ?
276 positions, alembic_offset, vertices_count, curve_order) :
283 blender_offset += (overlap >= vertices_count) ? vertices_count : (vertices_count - overlap);
286 alembic_offset += vertices_count;
288 data.offset_in_blender[curve_count] = blender_offset;
289 data.offset_in_alembic[curve_count] = alembic_offset;
293 data.positions = positions;
295 if (weights && weights->size() > 1) {
296 data.weights = weights;
299 if (radii && radii->size() > 1) {
309 ICurves abc_curves(
object, kWrapExisting);
310 m_curves_schema = abc_curves.getSchema();
317 return m_curves_schema.valid();
321 const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
323 const char **r_err_str)
const
325 if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
327 "Object type mismatch, Alembic object path pointed to Curves when importing, but not "
333 *r_err_str =
RPT_(
"Object type mismatch, Alembic object path points to Curves.");
363 handles_right[cp] =
to_zup_float3(alembic_positions[offset + 1]);
364 handles_left[cp] = 2.0f * positions[cp] - handles_right[cp];
366 else if (offset == alembic_positions.
size() - 1) {
368 handles_left[cp] =
to_zup_float3(alembic_positions[offset - 1]);
369 handles_right[cp] = 2.0f * positions[cp] - handles_left[cp];
373 handles_left[cp] =
to_zup_float3(alembic_positions[offset - 1]);
374 handles_right[cp] =
to_zup_float3(alembic_positions[offset + 1]);
379 const ICurvesSchema &schema,
380 const ISampleSelector &sample_sel)
383 m_iobject.getFullName(), schema, sample_sel);
384 if (!opt_preprocess) {
391 const int curve_count = data.offset_in_blender.size() - 1;
396 curves.resize(point_count, curve_count);
397 curves.offsets_for_write().copy_from(data.offset_in_blender);
400 curves.fill_curve_types(data.curve_type);
404 if (curve_resolution > 0) {
405 curves.resolution_for_write().fill(curve_resolution);
419 int point_offset = 0;
420 for (
const int i_curve : curves.curves_range()) {
421 const int alembic_point_offset = data.offset_in_alembic[i_curve];
422 const int alembic_point_count = data.offset_in_alembic[i_curve + 1] - alembic_point_offset;
423 const int cp_count = data.offset_in_blender[i_curve + 1] - data.offset_in_blender[i_curve];
429 alembic_points.slice(alembic_point_offset, alembic_point_count),
430 curves_positions.
slice(point_offset, point_count),
431 handles_left.
slice(point_offset, point_count),
432 handles_right.
slice(point_offset, point_count));
436 point_offset += cp_count;
440 for (
const int i_curve : curves.curves_range()) {
441 int position_offset = data.offset_in_alembic[i_curve];
442 for (
const int i_point : curves.points_by_curve()[i_curve]) {
443 curves_positions[i_point] =
to_zup_float3(alembic_points[position_offset++]);
448 if (data.do_cyclic) {
449 curves.cyclic_for_write().copy_from(data.curves_cyclic);
454 curves.attributes_for_write().lookup_or_add_for_write_span<
float>(
"radius",
457 Alembic::Abc::FloatArraySample alembic_widths = *data.radii;
458 for (
const int i_point : curves.points_range()) {
459 radii.
span[i_point] = alembic_widths[i_point] / 2.0f;
466 curves.nurbs_orders_for_write().copy_from(data.curves_orders);
467 curves.nurbs_knots_modes_for_write().fill(data.knot_mode);
472 for (
const int i_curve : curves.curves_range()) {
473 const int alembic_offset = data.offset_in_alembic[i_curve];
474 const IndexRange points = curves.points_by_curve()[i_curve];
476 data_weights_span.
slice(alembic_offset, points.size()));
483 const Alembic::Abc::ISampleSelector &sample_sel,
void * BKE_curves_add(struct Main *bmain, const char *name)
Low-level operations for curves.
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
@ NURBS_KNOT_MODE_ENDPOINT
Object is a sort of wrapper for general info.
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr void copy_from(Span< T > values) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const char * c_str() const
const T & last(const int64_t n=0) const
void resize(const int64_t new_size)
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override
void read_geometry(bke::GeometrySet &geometry_set, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **r_err_str) override
bool valid() const override
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **r_err_str) const override
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
void read_curves_sample(Curves *curves_id, const Alembic::AbcGeom::ICurvesSchema &schema, const Alembic::Abc::ISampleSelector &sample_selector)
std::string m_object_name
Alembic::Abc::IObject m_iobject
ImportSettings * m_settings
static bool is_cyclic(const Nurb *nu)
static float3 to_zup_float3(Imath::V3f v)
static int16_t get_curve_resolution(const ICurvesSchema &schema, const Alembic::Abc::ISampleSelector &sample_sel)
void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max)
static bool curves_topology_changed(const bke::CurvesGeometry &curves, Span< int > preprocessed_offsets)
BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
static int8_t get_knot_mode(const Alembic::AbcGeom::CurveType abc_curve_type)
static CurveType get_curve_type(const Alembic::AbcGeom::BasisType basis)
const std::string ABC_CURVE_RESOLUTION_U_PROPNAME
static int16_t get_curve_order(const Alembic::AbcGeom::CurveType abc_curve_type, const UcharArraySamplePtr orders, const size_t curve_index)
static std::optional< PreprocessedSampleData > preprocess_sample(StringRefNull iobject_name, const ICurvesSchema &schema, const ISampleSelector sample_sel)
bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
static void add_bezier_control_point(int cp, int offset, const Span< Imath::V3f > alembic_positions, MutableSpan< float3 > positions, MutableSpan< float3 > handles_left, MutableSpan< float3 > handles_right)
static int bezier_point_count(int alembic_count, bool is_cyclic)
static int get_curve_overlap(const P3fArraySamplePtr positions, const int idx, const int num_verts, const int16_t order)
Curves * get_curves_for_write()
MutableVArraySpan< T > span
bool always_add_cache_reader
Vector< int > offset_in_blender
Vector< int > offset_in_alembic
Vector< bool > curves_cyclic
FloatArraySamplePtr weights
Vector< int8_t > curves_orders