Fix T49813: crash after changing Alembic cache topology.
authorKévin Dietrich <kevin.dietrich@mailoo.org>
Wed, 30 Nov 2016 08:20:45 +0000 (09:20 +0100)
committerKévin Dietrich <kevin.dietrich@mailoo.org>
Wed, 30 Nov 2016 08:20:45 +0000 (09:20 +0100)
Crash is due by mismatching loops and faces counts between the Alembic
data and the Blender derivedmesh which does not appear so
straightforward to fix (the crash happens deep in the derivedmesh code).

So for now, try to detect if the topology has changed and if so, both
only read vertices (vertex colors and UVs won't be read, as tied to face
loops) and add a warning message in the modifier's UI to let the user
know.

source/blender/alembic/intern/abc_curves.cc
source/blender/alembic/intern/abc_curves.h
source/blender/alembic/intern/abc_mesh.cc
source/blender/alembic/intern/abc_mesh.h
source/blender/alembic/intern/abc_object.h
source/blender/alembic/intern/abc_points.cc
source/blender/alembic/intern/abc_points.h
source/blender/alembic/intern/alembic_capi.cc

index 7e5ea3b1853467650e10f319d42cb0243c51000f..4ecb9d944f20c19cc904191c4be7cae71258ddfe 100644 (file)
@@ -361,7 +361,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
  * object directly and create a new DerivedMesh from that. Also we might need to
  * create new or delete existing NURBS in the curve.
  */
-DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/)
+DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/, const char **/*err_str*/)
 {
        ISampleSelector sample_sel(time);
        const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel);
index 979ee8af639413c68f7a427f958eba4a5d175308..2757d179a47116e339d4ba025337b649ab6bc152 100644 (file)
@@ -56,7 +56,7 @@ public:
        bool valid() const;
 
        void readObjectData(Main *bmain, float time);
-       DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int);
+       DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int read_flag, const char **err_str);
 };
 
 /* ************************************************************************** */
index 5b282e3c5bb59ebf4620d0e93614f0a8e46a12b2..395c3e666f779b5d90c0b9b72746900379a05b34 100644 (file)
@@ -896,7 +896,7 @@ void AbcMeshReader::readObjectData(Main *bmain, float time)
        const ISampleSelector sample_sel(time);
 
        DerivedMesh *dm = CDDM_from_mesh(mesh);
-       DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
+       DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL);
 
        if (ndm != dm) {
                dm->release(dm);
@@ -978,7 +978,7 @@ CDStreamConfig get_config(DerivedMesh *dm)
        return config;
 }
 
-DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
 {
        ISampleSelector sample_sel(time);
        const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
@@ -1003,6 +1003,21 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time,
 
                settings.read_flag |= MOD_MESHSEQ_READ_ALL;
        }
+       else {
+               /* If the face count changed (e.g. by triangulation), only read points.
+                * This prevents crash from T49813
+                * TODO(kevin): perhaps find a better way to do this? */
+               if (face_counts->size() != dm->getNumPolys(dm) ||
+                   face_indices->size() != dm->getNumLoops(dm))
+               {
+                       settings.read_flag = MOD_MESHSEQ_READ_VERT;
+
+                       if (err_str) {
+                               *err_str = "Topology has changed, perhaps by triangulating the"
+                                          " mesh. Only vertices will be read!";
+                       }
+               }
+       }
 
        CDStreamConfig config = get_config(new_dm ? new_dm : dm);
        config.time = time;
@@ -1177,7 +1192,7 @@ void AbcSubDReader::readObjectData(Main *bmain, float time)
        m_object->data = mesh;
 
        DerivedMesh *dm = CDDM_from_mesh(mesh);
-       DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL);
+       DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL);
 
        if (ndm != dm) {
                dm->release(dm);
@@ -1257,7 +1272,7 @@ void read_subd_sample(ImportSettings *settings,
        /* TODO: face sets */
 }
 
-DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
 {
        ISampleSelector sample_sel(time);
        const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
@@ -1281,6 +1296,21 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time,
 
                settings.read_flag |= MOD_MESHSEQ_READ_ALL;
        }
+       else {
+               /* If the face count changed (e.g. by triangulation), only read points.
+                * This prevents crash from T49813
+                * TODO(kevin): perhaps find a better way to do this? */
+               if (face_counts->size() != dm->getNumPolys(dm) ||
+                   face_indices->size() != dm->getNumLoops(dm))
+               {
+                       settings.read_flag = MOD_MESHSEQ_READ_VERT;
+
+                       if (err_str) {
+                               *err_str = "Topology has changed, perhaps by triangulating the"
+                                          " mesh. Only vertices will be read!";
+                       }
+               }
+       }
 
        /* Only read point data when streaming meshes, unless we need to create new ones. */
        CDStreamConfig config = get_config(new_dm ? new_dm : dm);
index 66e6585a3d339080506b3e2192605ec4b82124bc..28d17105480fa93bd78907928a77dca31dcac22f 100644 (file)
@@ -102,7 +102,7 @@ public:
 
        void readObjectData(Main *bmain, float time);
 
-       DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+       DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
 
 private:
        void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
@@ -128,7 +128,7 @@ public:
        bool valid() const;
 
        void readObjectData(Main *bmain, float time);
-       DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+       DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
 };
 
 void read_subd_sample(ImportSettings *settings,
index 7ff927b4d33f58274102cc2a549db39984c7177c..d1bcbbe6cbe9f993a8246ea0a1db917b5ee6ac6a 100644 (file)
@@ -165,10 +165,11 @@ public:
 
        virtual void readObjectData(Main *bmain, float time) = 0;
 
-       virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag)
+       virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str)
        {
                (void)time;
                (void)read_flag;
+               (void)err_str;
                return dm;
        }
 
index c16da621c779795eba1e0a91acaf22979f74a59c..6ddba350b0a816fae1e8510737c1a85a2f97a846 100644 (file)
@@ -156,7 +156,7 @@ void AbcPointsReader::readObjectData(Main *bmain, float time)
        Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
 
        DerivedMesh *dm = CDDM_from_mesh(mesh);
-       DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0);
+       DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0, NULL);
 
        if (ndm != dm) {
                dm->release(dm);
@@ -199,7 +199,7 @@ void read_points_sample(const IPointsSchema &schema,
        read_mverts(config.mvert, positions, vnormals);
 }
 
-DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/)
+DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char **/*err_str*/)
 {
        ISampleSelector sample_sel(time);
        const IPointsSchema::Sample sample = m_schema.getValue(sample_sel);
index 54873eed34615c213641a7245c46571f77e5fac6..792283f04d31c8f8c57586dac8e83b6519e45f3a 100644 (file)
@@ -61,7 +61,7 @@ public:
 
        void readObjectData(Main *bmain, float time);
 
-       DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag);
+       DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str);
 };
 
 void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
index e690a25550539625a78b89ebc854507d1bf1916d..d0eb9900f4f1f6f16794fb5665ee62fca3acd02a 100644 (file)
@@ -816,7 +816,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
                        return NULL;
                }
 
-               return abc_reader->read_derivedmesh(dm, time, read_flag);
+               return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
        }
        else if (ISubD::matches(header)) {
                if (ob->type != OB_MESH) {
@@ -824,7 +824,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
                        return NULL;
                }
 
-               return abc_reader->read_derivedmesh(dm, time, read_flag);
+               return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
        }
        else if (IPoints::matches(header)) {
                if (ob->type != OB_MESH) {
@@ -832,7 +832,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
                        return NULL;
                }
 
-               return abc_reader->read_derivedmesh(dm, time, read_flag);
+               return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
        }
        else if (ICurves::matches(header)) {
                if (ob->type != OB_CURVE) {
@@ -840,7 +840,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader,
                        return NULL;
                }
 
-               return abc_reader->read_derivedmesh(dm, time, read_flag);
+               return abc_reader->read_derivedmesh(dm, time, read_flag, err_str);
        }
 
        *err_str = "Unsupported object type: verify object path"; // or poke developer