Alembic import/export: write curve resolution to user property
authorSybren A. Stüvel <sybren@stuvel.eu>
Tue, 18 Apr 2017 14:36:33 +0000 (16:36 +0200)
committerSybren A. Stüvel <sybren@stuvel.eu>
Tue, 18 Apr 2017 14:36:33 +0000 (16:36 +0200)
Curve resolution isn't natively supported by Alembic, hence it is stored
in a user property "blender:resolution". I've looked at a Maya curves
example file, but that also didn't contain any information about curve
resolution.

Differential Revision: https://developer.blender.org/D2634

Reviewers: kevindietrich

source/blender/alembic/intern/abc_curves.cc
source/blender/alembic/intern/abc_curves.h
tests/python/alembic_tests.py

index e6a5b289c6b86e0375b9a88fef441b50b634b262..c096ac036b4105e595a6507728be1ffcce4bba42 100644 (file)
@@ -49,19 +49,26 @@ using Alembic::Abc::Int32ArraySamplePtr;
 using Alembic::Abc::FloatArraySamplePtr;
 using Alembic::Abc::P3fArraySamplePtr;
 using Alembic::Abc::UcharArraySamplePtr;
+using Alembic::Abc::PropertyHeader;
 
+using Alembic::AbcGeom::ICompoundProperty;
 using Alembic::AbcGeom::ICurves;
 using Alembic::AbcGeom::ICurvesSchema;
 using Alembic::AbcGeom::IFloatGeomParam;
+using Alembic::AbcGeom::IInt16Property;
 using Alembic::AbcGeom::ISampleSelector;
 using Alembic::AbcGeom::kWrapExisting;
 using Alembic::AbcGeom::CurvePeriodicity;
 
+using Alembic::AbcGeom::OCompoundProperty;
 using Alembic::AbcGeom::OCurves;
 using Alembic::AbcGeom::OCurvesSchema;
+using Alembic::AbcGeom::OInt16Property;
 using Alembic::AbcGeom::ON3fGeomParam;
 using Alembic::AbcGeom::OV2fGeomParam;
 
+#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution"
+
 /* ************************************************************************** */
 
 AbcCurveWriter::AbcCurveWriter(Scene *scene,
@@ -73,6 +80,11 @@ AbcCurveWriter::AbcCurveWriter(Scene *scene,
 {
        OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
        m_schema = curves.getSchema();
+
+       Curve *cu = static_cast<Curve *>(m_object->data);
+       OCompoundProperty user_props = m_schema.getUserProperties();
+       OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME);
+       user_prop_resolu.set(cu->resolu);
 }
 
 void AbcCurveWriter::do_write()
@@ -205,12 +217,22 @@ void AbcCurveReader::readObjectData(Main *bmain, float time)
 
        cu->flag |= CU_DEFORM_FILL | CU_3D;
        cu->actvert = CU_ACT_NONE;
-       cu->resolu = 1;
+
+       const ISampleSelector sample_sel(time);
+       ICompoundProperty user_props = m_curves_schema.getUserProperties();
+       const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
+       if (header != NULL && header->isScalar() && IInt16Property::matches(*header)) {
+               IInt16Property resolu(user_props, header->getName());
+               cu->resolu = resolu.getValue(sample_sel);
+       }
+       else {
+               cu->resolu = 1;
+       }
 
        m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
        m_object->data = cu;
 
-       read_curve_sample(cu, m_curves_schema, time);
+       read_curve_sample(cu, m_curves_schema, sample_sel);
 
        if (has_animations(m_curves_schema, m_settings)) {
                addCacheModifier();
@@ -219,9 +241,8 @@ void AbcCurveReader::readObjectData(Main *bmain, float time)
 
 /* ************************************************************************** */
 
-void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
+void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel)
 {
-       const ISampleSelector sample_sel(time);
        ICurvesSchema::Sample smp = schema.getValue(sample_sel);
        const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
        const P3fArraySamplePtr positions = smp.getPositions();
@@ -383,7 +404,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/, const float
 
        if (curve_count != num_vertices->size()) {
                BKE_nurbList_free(&curve->nurb);
-               read_curve_sample(curve, m_curves_schema, time);
+               read_curve_sample(curve, m_curves_schema, sample_sel);
        }
        else {
                Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
index 2757d179a47116e339d4ba025337b649ab6bc152..71b0d20582045f0df1baeb51b5bf5dfcf74c5c39 100644 (file)
@@ -61,6 +61,8 @@ public:
 
 /* ************************************************************************** */
 
-void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
+void read_curve_sample(Curve *cu,
+                       const Alembic::AbcGeom::ICurvesSchema &schema,
+                       const Alembic::Abc::ISampleSelector &sample_selector);
 
 #endif  /* __ABC_CURVES_H__ */
index 845b9bd62885bfdd8fedba35d40f3bb30c861ae3..155cbd545f03a4d24dd0c9ef435db4e248227a38 100755 (executable)
@@ -128,6 +128,7 @@ class AbstractAlembicTest(unittest.TestCase):
         converters = {
             'bool_t': int,
             'uint8_t': int,
+            'int16_t': int,
             'int32_t': int,
             'float64_t': float,
             'float32_t': float,
@@ -141,7 +142,13 @@ class AbstractAlembicTest(unittest.TestCase):
             info = lines.popleft()
             if not info:
                 continue
-            proptype, valtype_and_arrsize, name_and_extent = info.split()
+            parts = info.split()
+            proptype = parts[0]
+
+            if proptype == 'CompoundProperty':
+                # To read those, call self.abcprop() on it.
+                continue
+            valtype_and_arrsize, name_and_extent = parts[1:]
 
             # Parse name and extent
             m = self.abcls_array.match(name_and_extent)
@@ -291,6 +298,9 @@ class CurveExportTest(AbstractAlembicTest):
         abcprop = self.abcprop(abc, '/NurbsCurve/NurbsCurveShape/.geom')
         self.assertEqual(abcprop['.orders'], [4])
 
+        abcprop = self.abcprop(abc, '/NurbsCurve/NurbsCurveShape/.geom/.userProperties')
+        self.assertEqual(abcprop['blender:resolution'], 10)
+
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser()