Alembic: add option to triangulate meshes upon export.
[blender.git] / source / blender / alembic / intern / abc_mesh.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 #include "abc_mesh.h"
24
25 #include <algorithm>
26
27 #include "abc_transform.h"
28 #include "abc_util.h"
29
30 extern "C" {
31 #include "DNA_material_types.h"
32 #include "DNA_mesh_types.h"
33 #include "DNA_modifier_types.h"
34 #include "DNA_object_fluidsim.h"
35 #include "DNA_object_types.h"
36
37 #include "BLI_math_geom.h"
38 #include "BLI_string.h"
39
40 #include "BKE_cdderivedmesh.h"
41 #include "BKE_depsgraph.h"
42 #include "BKE_main.h"
43 #include "BKE_material.h"
44 #include "BKE_mesh.h"
45 #include "BKE_modifier.h"
46 #include "BKE_object.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "ED_mesh.h"
52
53 #include "bmesh.h"
54 #include "bmesh_tools.h"
55 }
56
57 using Alembic::Abc::FloatArraySample;
58 using Alembic::Abc::ICompoundProperty;
59 using Alembic::Abc::Int32ArraySample;
60 using Alembic::Abc::Int32ArraySamplePtr;
61 using Alembic::Abc::P3fArraySamplePtr;
62 using Alembic::Abc::V2fArraySample;
63 using Alembic::Abc::V3fArraySample;
64 using Alembic::Abc::C4fArraySample;
65
66 using Alembic::AbcGeom::IFaceSet;
67 using Alembic::AbcGeom::IFaceSetSchema;
68 using Alembic::AbcGeom::IObject;
69 using Alembic::AbcGeom::IPolyMesh;
70 using Alembic::AbcGeom::IPolyMeshSchema;
71 using Alembic::AbcGeom::ISampleSelector;
72 using Alembic::AbcGeom::ISubD;
73 using Alembic::AbcGeom::ISubDSchema;
74 using Alembic::AbcGeom::IV2fGeomParam;
75
76 using Alembic::AbcGeom::OArrayProperty;
77 using Alembic::AbcGeom::OBoolProperty;
78 using Alembic::AbcGeom::OC3fArrayProperty;
79 using Alembic::AbcGeom::OC3fGeomParam;
80 using Alembic::AbcGeom::OC4fGeomParam;
81 using Alembic::AbcGeom::OCompoundProperty;
82 using Alembic::AbcGeom::OFaceSet;
83 using Alembic::AbcGeom::OFaceSetSchema;
84 using Alembic::AbcGeom::OFloatGeomParam;
85 using Alembic::AbcGeom::OInt32GeomParam;
86 using Alembic::AbcGeom::ON3fArrayProperty;
87 using Alembic::AbcGeom::ON3fGeomParam;
88 using Alembic::AbcGeom::OPolyMesh;
89 using Alembic::AbcGeom::OPolyMeshSchema;
90 using Alembic::AbcGeom::OSubD;
91 using Alembic::AbcGeom::OSubDSchema;
92 using Alembic::AbcGeom::OV2fGeomParam;
93 using Alembic::AbcGeom::OV3fGeomParam;
94
95 using Alembic::AbcGeom::kFacevaryingScope;
96 using Alembic::AbcGeom::kVaryingScope;
97 using Alembic::AbcGeom::kVertexScope;
98 using Alembic::AbcGeom::kWrapExisting;
99 using Alembic::AbcGeom::UInt32ArraySample;
100 using Alembic::AbcGeom::N3fArraySamplePtr;
101 using Alembic::AbcGeom::IN3fGeomParam;
102
103 /* ************************************************************************** */
104
105 /* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */
106
107 static void get_vertices(DerivedMesh *dm, std::vector<Imath::V3f> &points)
108 {
109         points.clear();
110         points.resize(dm->getNumVerts(dm));
111
112         MVert *verts = dm->getVertArray(dm);
113
114         for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
115                 copy_zup_yup(points[i].getValue(), verts[i].co);
116         }
117 }
118
119 static void get_topology(DerivedMesh *dm,
120                          std::vector<int32_t> &poly_verts,
121                          std::vector<int32_t> &loop_counts,
122                          bool &smooth_normal)
123 {
124         const int num_poly = dm->getNumPolys(dm);
125         const int num_loops = dm->getNumLoops(dm);
126         MLoop *mloop = dm->getLoopArray(dm);
127         MPoly *mpoly = dm->getPolyArray(dm);
128
129         poly_verts.clear();
130         loop_counts.clear();
131         poly_verts.reserve(num_loops);
132         loop_counts.reserve(num_poly);
133
134         /* NOTE: data needs to be written in the reverse order. */
135         for (int i = 0; i < num_poly; ++i) {
136                 MPoly &poly = mpoly[i];
137                 loop_counts.push_back(poly.totloop);
138
139                 smooth_normal |= ((poly.flag & ME_SMOOTH) != 0);
140
141                 MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1);
142
143                 for (int j = 0; j < poly.totloop; ++j, --loop) {
144                         poly_verts.push_back(loop->v);
145                 }
146         }
147 }
148
149 static void get_material_indices(DerivedMesh *dm, std::vector<int32_t> &indices)
150 {
151         indices.clear();
152         indices.reserve(dm->getNumTessFaces(dm));
153
154         MPoly *mpolys = dm->getPolyArray(dm);
155
156         for (int i = 1, e = dm->getNumPolys(dm); i < e; ++i) {
157                 MPoly *mpoly = &mpolys[i];
158                 indices.push_back(mpoly->mat_nr);
159         }
160 }
161
162 static void get_creases(DerivedMesh *dm,
163                         std::vector<int32_t> &indices,
164                         std::vector<int32_t> &lengths,
165                         std::vector<float> &sharpnesses)
166 {
167         const float factor = 1.0f / 255.0f;
168
169         indices.clear();
170         lengths.clear();
171         sharpnesses.clear();
172
173         MEdge *edge = dm->getEdgeArray(dm);
174
175         for (int i = 0, e = dm->getNumEdges(dm); i < e; ++i) {
176                 const float sharpness = static_cast<float>(edge[i].crease) * factor;
177
178                 if (sharpness != 0.0f) {
179                         indices.push_back(edge[i].v1);
180                         indices.push_back(edge[i].v2);
181                         sharpnesses.push_back(sharpness);
182                 }
183         }
184
185         lengths.resize(sharpnesses.size(), 2);
186 }
187
188 static void get_vertex_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
189 {
190         normals.clear();
191         normals.resize(dm->getNumVerts(dm));
192
193         MVert *verts = dm->getVertArray(dm);
194         float no[3];
195
196         for (int i = 0, e = dm->getNumVerts(dm); i < e; ++i) {
197                 normal_short_to_float_v3(no, verts[i].no);
198                 copy_zup_yup(normals[i].getValue(), no);
199         }
200 }
201
202 static void get_loop_normals(DerivedMesh *dm, std::vector<Imath::V3f> &normals)
203 {
204         MPoly *mpoly = dm->getPolyArray(dm);
205         MPoly *mp = mpoly;
206
207         MLoop *mloop = dm->getLoopArray(dm);
208         MLoop *ml = mloop;
209
210         MVert *verts = dm->getVertArray(dm);
211
212         const float (*lnors)[3] = static_cast<float(*)[3]>(dm->getLoopDataArray(dm, CD_NORMAL));
213
214         normals.clear();
215         normals.resize(dm->getNumLoops(dm));
216
217         unsigned loop_index = 0;
218
219         /* NOTE: data needs to be written in the reverse order. */
220
221         if (lnors) {
222                 for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
223                         ml = mloop + mp->loopstart + (mp->totloop - 1);
224
225                         for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
226                                 const int index = ml->v;
227                                 copy_zup_yup(normals[loop_index].getValue(), lnors[index]);
228                         }
229                 }
230         }
231         else {
232                 float no[3];
233
234                 for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i, ++mp) {
235                         ml = mloop + mp->loopstart + (mp->totloop - 1);
236
237                         /* Flat shaded, use common normal for all verts. */
238                         if ((mp->flag & ME_SMOOTH) == 0) {
239                                 BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no);
240
241                                 for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
242                                         copy_zup_yup(normals[loop_index].getValue(), no);
243                                 }
244                         }
245                         else {
246                                 /* Smooth shaded, use individual vert normals. */
247                                 for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) {
248                                         normal_short_to_float_v3(no, verts[ml->v].no);
249                                         copy_zup_yup(normals[loop_index].getValue(), no);
250                                 }
251                         }
252                 }
253         }
254 }
255
256 /* *************** Modifiers *************** */
257
258 /* check if the mesh is a subsurf, ignoring disabled modifiers and
259  * displace if it's after subsurf. */
260 static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob)
261 {
262         ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last);
263
264         for (; md; md = md->prev) {
265                 if (!modifier_isEnabled(scene, md, eModifierMode_Render)) {
266                         continue;
267                 }
268
269                 if (md->type == eModifierType_Subsurf) {
270                         SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData*>(md);
271
272                         if (smd->subdivType == ME_CC_SUBSURF) {
273                                 return md;
274                         }
275                 }
276
277                 /* mesh is not a subsurf. break */
278                 if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) {
279                         return NULL;
280                 }
281         }
282
283         return NULL;
284 }
285
286 static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob)
287 {
288         ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim);
289
290         if (md && (modifier_isEnabled(scene, md, eModifierMode_Render))) {
291                 FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md);
292
293                 if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) {
294                         return md;
295                 }
296         }
297
298         return NULL;
299 }
300
301 /* ************************************************************************** */
302
303 AbcMeshWriter::AbcMeshWriter(Scene *scene,
304                              Object *ob,
305                              AbcTransformWriter *parent,
306                              uint32_t time_sampling,
307                              ExportSettings &settings)
308     : AbcObjectWriter(scene, ob, time_sampling, settings, parent)
309 {
310         m_is_animated = isAnimated();
311         m_subsurf_mod = NULL;
312         m_has_per_face_materials = false;
313         m_is_subd = false;
314
315         /* If the object is static, use the default static time sampling. */
316         if (!m_is_animated) {
317                 time_sampling = 0;
318         }
319
320         if (!m_settings.apply_subdiv) {
321                 m_subsurf_mod = get_subsurf_modifier(m_scene, m_object);
322                 m_is_subd = (m_subsurf_mod != NULL);
323         }
324
325         m_is_liquid = (get_liquid_sim_modifier(m_scene, m_object) != NULL);
326
327         while (parent->alembicXform().getChildHeader(m_name)) {
328                 m_name.append("_");
329         }
330
331         if (m_settings.use_subdiv_schema && m_is_subd) {
332                 OSubD subd(parent->alembicXform(), m_name, m_time_sampling);
333                 m_subdiv_schema = subd.getSchema();
334         }
335         else {
336                 OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling);
337                 m_mesh_schema = mesh.getSchema();
338
339                 OCompoundProperty typeContainer = m_mesh_schema.getUserProperties();
340                 OBoolProperty type(typeContainer, "meshtype");
341                 type.set(m_is_subd);
342         }
343 }
344
345 AbcMeshWriter::~AbcMeshWriter()
346 {
347         if (m_subsurf_mod) {
348                 m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
349         }
350 }
351
352 bool AbcMeshWriter::isAnimated() const
353 {
354         /* Check if object has shape keys. */
355         Mesh *me = static_cast<Mesh *>(m_object->data);
356
357         if (me->key) {
358                 return true;
359         }
360
361         /* Test modifiers. */
362         ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first);
363
364         while (md) {
365                 if (md->type != eModifierType_Subsurf) {
366                         return true;
367                 }
368
369                 md = md->next;
370         }
371
372         return false;
373 }
374
375 void AbcMeshWriter::do_write()
376 {
377         /* We have already stored a sample for this object. */
378         if (!m_first_frame && !m_is_animated)
379                 return;
380
381         DerivedMesh *dm = getFinalMesh();
382
383         try {
384                 if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) {
385                         writeSubD(dm);
386                 }
387                 else {
388                         writeMesh(dm);
389                 }
390
391                 freeMesh(dm);
392         }
393         catch (...) {
394                 freeMesh(dm);
395                 throw;
396         }
397 }
398
399 void AbcMeshWriter::writeMesh(DerivedMesh *dm)
400 {
401         std::vector<Imath::V3f> points, normals;
402         std::vector<int32_t> poly_verts, loop_counts;
403
404         bool smooth_normal = false;
405
406         get_vertices(dm, points);
407         get_topology(dm, poly_verts, loop_counts, smooth_normal);
408
409         if (m_first_frame) {
410                 writeCommonData(dm, m_mesh_schema);
411         }
412
413         m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points),
414                                                 Int32ArraySample(poly_verts),
415                                                 Int32ArraySample(loop_counts));
416
417         UVSample sample;
418         if (m_settings.export_uvs) {
419                 const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
420
421                 if (!sample.indices.empty() && !sample.uvs.empty()) {
422                         OV2fGeomParam::Sample uv_sample;
423                         uv_sample.setVals(V2fArraySample(sample.uvs));
424                         uv_sample.setIndices(UInt32ArraySample(sample.indices));
425                         uv_sample.setScope(kFacevaryingScope);
426
427                         m_mesh_schema.setUVSourceName(name);
428                         m_mesh_sample.setUVs(uv_sample);
429                 }
430
431                 write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
432         }
433
434         if (m_settings.export_normals) {
435                 if (smooth_normal) {
436                         get_loop_normals(dm, normals);
437                 }
438                 else {
439                         get_vertex_normals(dm, normals);
440                 }
441
442                 ON3fGeomParam::Sample normals_sample;
443                 if (!normals.empty()) {
444                         normals_sample.setScope((smooth_normal) ? kFacevaryingScope : kVertexScope);
445                         normals_sample.setVals(V3fArraySample(normals));
446                 }
447
448                 m_mesh_sample.setNormals(normals_sample);
449         }
450
451         if (m_is_liquid) {
452                 std::vector<Imath::V3f> velocities;
453                 getVelocities(dm, velocities);
454
455                 m_mesh_sample.setVelocities(V3fArraySample(velocities));
456         }
457
458         m_mesh_sample.setSelfBounds(bounds());
459
460         m_mesh_schema.set(m_mesh_sample);
461
462         writeArbGeoParams(dm);
463 }
464
465 void AbcMeshWriter::writeSubD(DerivedMesh *dm)
466 {
467         std::vector<float> crease_sharpness;
468         std::vector<Imath::V3f> points;
469         std::vector<int32_t> poly_verts, loop_counts;
470         std::vector<int32_t> crease_indices, crease_lengths;
471
472         bool smooth_normal = false;
473
474         get_vertices(dm, points);
475         get_topology(dm, poly_verts, loop_counts, smooth_normal);
476         get_creases(dm, crease_indices, crease_lengths, crease_sharpness);
477
478         if (m_first_frame) {
479                 /* create materials' face_sets */
480                 writeCommonData(dm, m_subdiv_schema);
481         }
482
483         m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points),
484                                               Int32ArraySample(poly_verts),
485                                               Int32ArraySample(loop_counts));
486
487         UVSample sample;
488         if (m_settings.export_uvs) {
489                 const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
490
491                 if (!sample.indices.empty() && !sample.uvs.empty()) {
492                         OV2fGeomParam::Sample uv_sample;
493                         uv_sample.setVals(V2fArraySample(sample.uvs));
494                         uv_sample.setIndices(UInt32ArraySample(sample.indices));
495                         uv_sample.setScope(kFacevaryingScope);
496
497                         m_subdiv_schema.setUVSourceName(name);
498                         m_subdiv_sample.setUVs(uv_sample);
499                 }
500
501                 write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPUV);
502         }
503
504         if (!crease_indices.empty()) {
505                 m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices));
506                 m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths));
507                 m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness));
508         }
509
510         m_subdiv_sample.setSelfBounds(bounds());
511         m_subdiv_schema.set(m_subdiv_sample);
512
513         writeArbGeoParams(dm);
514 }
515
516 template <typename Schema>
517 void AbcMeshWriter::writeCommonData(DerivedMesh *dm, Schema &schema)
518 {
519         std::map< std::string, std::vector<int32_t> > geo_groups;
520         getGeoGroups(dm, geo_groups);
521
522         std::map< std::string, std::vector<int32_t>  >::iterator it;
523         for (it = geo_groups.begin(); it != geo_groups.end(); ++it) {
524                 OFaceSet face_set = schema.createFaceSet(it->first);
525                 OFaceSetSchema::Sample samp;
526                 samp.setFaces(Int32ArraySample(it->second));
527                 face_set.getSchema().set(samp);
528         }
529 }
530
531 DerivedMesh *AbcMeshWriter::getFinalMesh()
532 {
533         /* We don't want subdivided mesh data */
534         if (m_subsurf_mod) {
535                 m_subsurf_mod->mode |= eModifierMode_DisableTemporary;
536         }
537
538         DerivedMesh *dm = mesh_create_derived_render(m_scene, m_object, CD_MASK_MESH);
539
540         if (m_subsurf_mod) {
541                 m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary;
542         }
543
544         if (m_settings.triangulate) {
545                 const bool tag_only = false;
546                 const int quad_method = m_settings.quad_method;
547                 const int ngon_method = m_settings.ngon_method;
548
549                 BMesh *bm = DM_to_bmesh(dm, true);
550
551                 BM_mesh_triangulate(bm, quad_method, ngon_method, tag_only, NULL, NULL, NULL);
552
553                 DerivedMesh *result = CDDM_from_bmesh(bm, false);
554                 BM_mesh_free(bm);
555
556                 freeMesh(dm);
557
558                 dm = result;
559         }
560
561         m_custom_data_config.pack_uvs = m_settings.pack_uv;
562         m_custom_data_config.mpoly = dm->getPolyArray(dm);
563         m_custom_data_config.mloop = dm->getLoopArray(dm);
564         m_custom_data_config.totpoly = dm->getNumPolys(dm);
565         m_custom_data_config.totloop = dm->getNumLoops(dm);
566         m_custom_data_config.totvert = dm->getNumVerts(dm);
567
568         return dm;
569 }
570
571 void AbcMeshWriter::freeMesh(DerivedMesh *dm)
572 {
573         dm->release(dm);
574 }
575
576 void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
577 {
578         if (m_is_liquid) {
579                 /* We don't need anything more for liquid meshes. */
580                 return;
581         }
582
583         if (m_settings.export_vcols) {
584                 if (m_subdiv_schema.valid()) {
585                         write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
586                 }
587                 else {
588                         write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
589                 }
590         }
591
592         if (m_first_frame && m_has_per_face_materials) {
593                 std::vector<int32_t> material_indices;
594
595                 if (m_settings.export_face_sets) {
596                         get_material_indices(dm, material_indices);
597
598                         OFaceSetSchema::Sample samp;
599                         samp.setFaces(Int32ArraySample(material_indices));
600                         m_face_set.getSchema().set(samp);
601                 }
602         }
603 }
604
605 void AbcMeshWriter::getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels)
606 {
607         const int totverts = dm->getNumVerts(dm);
608
609         vels.clear();
610         vels.resize(totverts);
611
612         ModifierData *md = get_liquid_sim_modifier(m_scene, m_object);
613         FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md);
614         FluidsimSettings *fss = fmd->fss;
615
616         if (fss->meshVelocities) {
617                 float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities);
618
619                 for (int i = 0; i < totverts; ++i) {
620                         copy_zup_yup(vels[i].getValue(), mesh_vels);
621                         mesh_vels += 3;
622                 }
623         }
624         else {
625                 std::fill(vels.begin(), vels.end(), Imath::V3f(0.0f));
626         }
627 }
628
629 void AbcMeshWriter::getGeoGroups(
630         DerivedMesh *dm,
631         std::map<std::string, std::vector<int32_t> > &geo_groups)
632 {
633         const int num_poly = dm->getNumPolys(dm);
634         MPoly *polygons = dm->getPolyArray(dm);
635
636         for (int i = 0; i < num_poly; ++i) {
637                 MPoly &current_poly = polygons[i];
638                 short mnr = current_poly.mat_nr;
639
640                 Material *mat = give_current_material(m_object, mnr + 1);
641
642                 if (!mat) {
643                         continue;
644                 }
645
646                 std::string name = get_id_name(&mat->id);
647
648                 if (geo_groups.find(name) == geo_groups.end()) {
649                         std::vector<int32_t> faceArray;
650                         geo_groups[name] = faceArray;
651                 }
652
653                 geo_groups[name].push_back(i);
654         }
655
656         if (geo_groups.size() == 0) {
657                 Material *mat = give_current_material(m_object, 1);
658
659                 std::string name = (mat) ? get_id_name(&mat->id) : "default";
660
661                 std::vector<int32_t> faceArray;
662
663                 for (int i = 0, e = dm->getNumTessFaces(dm); i < e; ++i) {
664                         faceArray.push_back(i);
665                 }
666
667                 geo_groups[name] = faceArray;
668         }
669 }
670
671 /* ************************************************************************** */
672
673 /* Some helpers for mesh generation */
674 namespace utils {
675
676 void mesh_add_verts(Mesh *mesh, size_t len)
677 {
678         if (len == 0) {
679                 return;
680         }
681
682         const int totvert = mesh->totvert + len;
683         CustomData vdata;
684         CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
685         CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
686
687         if (!CustomData_has_layer(&vdata, CD_MVERT)) {
688                 CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
689         }
690
691         CustomData_free(&mesh->vdata, mesh->totvert);
692         mesh->vdata = vdata;
693         BKE_mesh_update_customdata_pointers(mesh, false);
694
695         mesh->totvert = totvert;
696 }
697
698 static void mesh_add_mloops(Mesh *mesh, size_t len)
699 {
700         if (len == 0) {
701                 return;
702         }
703
704         /* new face count */
705         const int totloops = mesh->totloop + len;
706
707         CustomData ldata;
708         CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloops);
709         CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
710
711         if (!CustomData_has_layer(&ldata, CD_MLOOP)) {
712                 CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloops);
713         }
714
715         CustomData_free(&mesh->ldata, mesh->totloop);
716         mesh->ldata = ldata;
717         BKE_mesh_update_customdata_pointers(mesh, false);
718
719         mesh->totloop = totloops;
720 }
721
722 static void mesh_add_mpolygons(Mesh *mesh, size_t len)
723 {
724         if (len == 0) {
725                 return;
726         }
727
728         const int totpolys = mesh->totpoly + len;
729
730         CustomData pdata;
731         CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpolys);
732         CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
733
734         if (!CustomData_has_layer(&pdata, CD_MPOLY)) {
735                 CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpolys);
736         }
737
738         CustomData_free(&mesh->pdata, mesh->totpoly);
739         mesh->pdata = pdata;
740         BKE_mesh_update_customdata_pointers(mesh, false);
741
742         mesh->totpoly = totpolys;
743 }
744
745 static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map)
746 {
747         Material *material = static_cast<Material *>(bmain->mat.first);
748
749         for (; material; material = static_cast<Material *>(material->id.next)) {
750                 mat_map[material->id.name + 2] = material;
751         }
752 }
753
754 static void assign_materials(Main *bmain, Object *ob, const std::map<std::string, int> &mat_index_map)
755 {
756         bool can_assign = true;
757         std::map<std::string, int>::const_iterator it = mat_index_map.begin();
758
759         int matcount = 0;
760         for (; it != mat_index_map.end(); ++it, ++matcount) {
761                 if (!BKE_object_material_slot_add(ob)) {
762                         can_assign = false;
763                         break;
764                 }
765         }
766
767         /* TODO(kevin): use global map? */
768         std::map<std::string, Material *> mat_map;
769         build_mat_map(bmain, mat_map);
770
771         std::map<std::string, Material *>::iterator mat_iter;
772
773         if (can_assign) {
774                 it = mat_index_map.begin();
775
776                 for (; it != mat_index_map.end(); ++it) {
777                         std::string mat_name = it->first;
778                         mat_iter = mat_map.find(mat_name.c_str());
779
780                         Material *assigned_name;
781
782                         if (mat_iter == mat_map.end()) {
783                                 assigned_name = BKE_material_add(bmain, mat_name.c_str());
784                                 mat_map[mat_name] = assigned_name;
785                         }
786                         else {
787                                 assigned_name = mat_iter->second;
788                         }
789
790                         assign_material(ob, assigned_name, it->second, BKE_MAT_ASSIGN_OBJECT);
791                 }
792         }
793 }
794
795 }  /* namespace utils */
796
797 /* ************************************************************************** */
798
799 using Alembic::AbcGeom::UInt32ArraySamplePtr;
800 using Alembic::AbcGeom::V2fArraySamplePtr;
801
802 struct AbcMeshData {
803         Int32ArraySamplePtr face_indices;
804         Int32ArraySamplePtr face_counts;
805
806         P3fArraySamplePtr positions;
807
808         N3fArraySamplePtr vertex_normals;
809         N3fArraySamplePtr face_normals;
810
811         V2fArraySamplePtr uvs;
812         UInt32ArraySamplePtr uvs_indices;
813 };
814
815 static void *add_customdata_cb(void *user_data, const char *name, int data_type)
816 {
817         Mesh *mesh = static_cast<Mesh *>(user_data);
818         CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
819         void *cd_ptr = NULL;
820
821         int index = -1;
822         if (cd_data_type == CD_MLOOPUV) {
823                 index = ED_mesh_uv_texture_add(mesh, name, true);
824                 cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type);
825         }
826         else if (cd_data_type == CD_MLOOPCOL) {
827                 index = ED_mesh_color_add(mesh, name, true);
828                 cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type);
829         }
830
831         if (index == -1) {
832                 return NULL;
833         }
834
835         return cd_ptr;
836 }
837
838 CDStreamConfig create_config(Mesh *mesh)
839 {
840         CDStreamConfig config;
841
842         config.mvert = mesh->mvert;
843         config.mpoly = mesh->mpoly;
844         config.mloop = mesh->mloop;
845         config.totpoly = mesh->totpoly;
846         config.totloop = mesh->totloop;
847         config.user_data = mesh;
848         config.loopdata = &mesh->ldata;
849         config.add_customdata_cb = add_customdata_cb;
850
851         return config;
852 }
853
854 static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
855 {
856         MVert *mverts = config.mvert;
857         const P3fArraySamplePtr &positions = mesh_data.positions;
858         const N3fArraySamplePtr &normals = mesh_data.vertex_normals;
859
860         read_mverts(mverts, positions, normals);
861 }
862
863 void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArraySamplePtr &normals)
864 {
865         for (int i = 0; i < positions->size(); ++i) {
866                 MVert &mvert = mverts[i];
867                 Imath::V3f pos_in = (*positions)[i];
868
869                 copy_yup_zup(mvert.co, pos_in.getValue());
870
871                 mvert.bweight = 0;
872
873                 if (normals) {
874                         Imath::V3f nor_in = (*normals)[i];
875
876                         short no[3];
877                         normal_float_to_short_v3(no, nor_in.getValue());
878
879                         copy_yup_zup(mvert.no, no);
880                 }
881         }
882 }
883
884 static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
885 {
886         MPoly *mpolys = config.mpoly;
887         MLoop *mloops = config.mloop;
888         MLoopUV *mloopuvs = config.mloopuv;
889
890         const Int32ArraySamplePtr &face_indices = mesh_data.face_indices;
891         const Int32ArraySamplePtr &face_counts = mesh_data.face_counts;
892         const V2fArraySamplePtr &uvs = mesh_data.uvs;
893         const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices;
894         const N3fArraySamplePtr &normals = mesh_data.face_normals;
895
896         const bool do_uvs = (mloopuvs && uvs && uvs_indices) && (uvs_indices->size() == face_indices->size());
897         unsigned int loop_index = 0;
898         unsigned int rev_loop_index = 0;
899         unsigned int uv_index = 0;
900
901         for (int i = 0; i < face_counts->size(); ++i) {
902                 const int face_size = (*face_counts)[i];
903
904                 MPoly &poly = mpolys[i];
905                 poly.loopstart = loop_index;
906                 poly.totloop = face_size;
907
908                 if (normals != NULL) {
909                         poly.flag |= ME_SMOOTH;
910                 }
911
912                 /* NOTE: Alembic data is stored in the reverse order. */
913                 rev_loop_index = loop_index + (face_size - 1);
914
915                 for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) {
916                         MLoop &loop = mloops[rev_loop_index];
917                         loop.v = (*face_indices)[loop_index];
918
919                         if (do_uvs) {
920                                 MLoopUV &loopuv = mloopuvs[rev_loop_index];
921
922                                 uv_index = (*uvs_indices)[loop_index];
923                                 loopuv.uv[0] = (*uvs)[uv_index][0];
924                                 loopuv.uv[1] = (*uvs)[uv_index][1];
925                         }
926                 }
927         }
928 }
929
930 ABC_INLINE void read_uvs_params(CDStreamConfig &config,
931                                 AbcMeshData &abc_data,
932                                 const IV2fGeomParam &uv,
933                                 const ISampleSelector &selector)
934 {
935         if (!uv.valid()) {
936                 return;
937         }
938
939         IV2fGeomParam::Sample uvsamp;
940         uv.getIndexed(uvsamp, selector);
941
942         abc_data.uvs = uvsamp.getVals();
943         abc_data.uvs_indices = uvsamp.getIndices();
944
945         if (abc_data.uvs_indices->size() == config.totloop) {
946                 std::string name = Alembic::Abc::GetSourceName(uv.getMetaData());
947
948                 /* According to the convention, primary UVs should have had their name
949                  * set using Alembic::Abc::SetSourceName, but you can't expect everyone
950                  * to follow it! :) */
951                 if (name.empty()) {
952                         name = uv.getName();
953                 }
954
955                 void *cd_ptr = config.add_customdata_cb(config.user_data, name.c_str(), CD_MLOOPUV);
956                 config.mloopuv = static_cast<MLoopUV *>(cd_ptr);
957         }
958 }
959
960 /* TODO(kevin): normals from Alembic files are not read in anymore, this is due
961  * to the fact that there are many issues that are not so easy to solve, mainly
962  * regarding the way normals are handled in Blender (MPoly.flag vs loop normals).
963  */
964 ABC_INLINE void read_normals_params(AbcMeshData &abc_data,
965                                     const IN3fGeomParam &normals,
966                                     const ISampleSelector &selector)
967 {
968         if (!normals.valid()) {
969                 return;
970         }
971
972         IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector);
973
974         if (normals.getScope() == kFacevaryingScope) {
975                 abc_data.face_normals = normsamp.getVals();
976         }
977         else if ((normals.getScope() == kVertexScope) || (normals.getScope() == kVaryingScope)) {
978                 abc_data.vertex_normals = N3fArraySamplePtr();
979         }
980 }
981
982 /* ************************************************************************** */
983
984 AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings)
985     : AbcObjectReader(object, settings)
986 {
987         m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
988
989         IPolyMesh ipoly_mesh(m_iobject, kWrapExisting);
990         m_schema = ipoly_mesh.getSchema();
991
992         get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
993 }
994
995 bool AbcMeshReader::valid() const
996 {
997         return m_schema.valid();
998 }
999
1000 void AbcMeshReader::readObjectData(Main *bmain, float time)
1001 {
1002         Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
1003
1004         m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
1005         m_object->data = mesh;
1006
1007         const ISampleSelector sample_sel(time);
1008         const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel);
1009
1010         const P3fArraySamplePtr &positions = sample.getPositions();
1011         const Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
1012     const Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
1013
1014         utils::mesh_add_verts(mesh, positions->size());
1015         utils::mesh_add_mpolygons(mesh, face_counts->size());
1016         utils::mesh_add_mloops(mesh, face_indices->size());
1017
1018         m_mesh_data = create_config(mesh);
1019
1020         bool has_smooth_normals = false;
1021         read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals);
1022
1023         BKE_mesh_calc_normals(mesh);
1024         BKE_mesh_calc_edges(mesh, false, false);
1025
1026         if (m_settings->validate_meshes) {
1027                 BKE_mesh_validate(mesh, false, false);
1028         }
1029
1030         readFaceSetsSample(bmain, mesh, 0, sample_sel);
1031
1032         if (has_animations(m_schema, m_settings)) {
1033                 addCacheModifier();
1034         }
1035 }
1036
1037 void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
1038                                        const ISampleSelector &sample_sel)
1039 {
1040         std::vector<std::string> face_sets;
1041         m_schema.getFaceSetNames(face_sets);
1042
1043         if (face_sets.empty()) {
1044                 return;
1045         }
1046
1047         std::map<std::string, int> mat_map;
1048         int current_mat = 0;
1049
1050         for (int i = 0; i < face_sets.size(); ++i) {
1051                 const std::string &grp_name = face_sets[i];
1052
1053                 if (mat_map.find(grp_name) == mat_map.end()) {
1054                         mat_map[grp_name] = 1 + current_mat++;
1055                 }
1056
1057                 const int assigned_mat = mat_map[grp_name];
1058
1059                 const IFaceSet faceset = m_schema.getFaceSet(grp_name);
1060
1061                 if (!faceset.valid()) {
1062                         continue;
1063                 }
1064
1065                 const IFaceSetSchema face_schem = faceset.getSchema();
1066                 const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel);
1067                 const Int32ArraySamplePtr group_faces = face_sample.getFaces();
1068                 const size_t num_group_faces = group_faces->size();
1069
1070                 for (size_t l = 0; l < num_group_faces; l++) {
1071                         size_t pos = (*group_faces)[l] + poly_start;
1072
1073                         if (pos >= mesh->totpoly) {
1074                                 std::cerr << "Faceset overflow on " << faceset.getName() << '\n';
1075                                 break;
1076                         }
1077
1078                         MPoly &poly = mesh->mpoly[pos];
1079                         poly.mat_nr = assigned_mat - 1;
1080                 }
1081         }
1082
1083         utils::assign_materials(bmain, m_object, mat_map);
1084 }
1085
1086 void read_mesh_sample(ImportSettings *settings,
1087                       const IPolyMeshSchema &schema,
1088                       const ISampleSelector &selector,
1089                       CDStreamConfig &config,
1090                       bool &do_normals)
1091 {
1092         const IPolyMeshSchema::Sample sample = schema.getValue(selector);
1093
1094         AbcMeshData abc_mesh_data;
1095         abc_mesh_data.face_counts = sample.getFaceCounts();
1096         abc_mesh_data.face_indices = sample.getFaceIndices();
1097         abc_mesh_data.positions = sample.getPositions();
1098
1099         read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector);
1100
1101         do_normals = (abc_mesh_data.face_normals != NULL);
1102
1103         if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
1104                 read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
1105         }
1106
1107         if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
1108                 read_mverts(config, abc_mesh_data);
1109         }
1110
1111         if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
1112                 read_mpolys(config, abc_mesh_data);
1113         }
1114
1115         if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
1116                 read_custom_data(schema.getArbGeomParams(), config, selector);
1117         }
1118
1119         /* TODO: face sets */
1120 }
1121
1122 /* ************************************************************************** */
1123
1124 ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2)
1125 {
1126         for (int i = 0, e = totedge; i < e; ++i) {
1127                 MEdge &edge = edges[i];
1128
1129                 if (edge.v1 == v1 && edge.v2 == v2) {
1130                         return &edge;
1131                 }
1132         }
1133
1134         return NULL;
1135 }
1136
1137 AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings)
1138     : AbcObjectReader(object, settings)
1139 {
1140         m_settings->read_flag |= MOD_MESHSEQ_READ_ALL;
1141
1142         ISubD isubd_mesh(m_iobject, kWrapExisting);
1143         m_schema = isubd_mesh.getSchema();
1144
1145         get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time);
1146 }
1147
1148 bool AbcSubDReader::valid() const
1149 {
1150         return m_schema.valid();
1151 }
1152
1153 void AbcSubDReader::readObjectData(Main *bmain, float time)
1154 {
1155         Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
1156
1157         m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
1158         m_object->data = mesh;
1159
1160         const ISampleSelector sample_sel(time);
1161         const ISubDSchema::Sample sample = m_schema.getValue(sample_sel);
1162
1163         const P3fArraySamplePtr &positions = sample.getPositions();
1164         const Int32ArraySamplePtr &face_indices = sample.getFaceIndices();
1165     const Int32ArraySamplePtr &face_counts = sample.getFaceCounts();
1166
1167         utils::mesh_add_verts(mesh, positions->size());
1168         utils::mesh_add_mpolygons(mesh, face_counts->size());
1169         utils::mesh_add_mloops(mesh, face_indices->size());
1170
1171         m_mesh_data = create_config(mesh);
1172
1173         read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data);
1174
1175         Int32ArraySamplePtr indices = sample.getCreaseIndices();
1176         Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses();
1177
1178         MEdge *edges = mesh->medge;
1179
1180         if (indices && sharpnesses) {
1181                 for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) {
1182                         MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]);
1183
1184                         if (edge) {
1185                                 edge->crease = FTOCHAR((*sharpnesses)[s]);
1186                         }
1187                 }
1188
1189                 mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
1190         }
1191
1192         BKE_mesh_calc_normals(mesh);
1193         BKE_mesh_calc_edges(mesh, false, false);
1194
1195         if (m_settings->validate_meshes) {
1196                 BKE_mesh_validate(mesh, false, false);
1197         }
1198
1199         if (has_animations(m_schema, m_settings)) {
1200                 addCacheModifier();
1201         }
1202 }
1203
1204 void read_subd_sample(ImportSettings *settings,
1205                       const ISubDSchema &schema,
1206                       const ISampleSelector &selector,
1207                       CDStreamConfig &config)
1208 {
1209         const ISubDSchema::Sample sample = schema.getValue(selector);
1210
1211         AbcMeshData abc_mesh_data;
1212         abc_mesh_data.face_counts = sample.getFaceCounts();
1213         abc_mesh_data.face_indices = sample.getFaceIndices();
1214         abc_mesh_data.vertex_normals = N3fArraySamplePtr();
1215         abc_mesh_data.face_normals = N3fArraySamplePtr();
1216         abc_mesh_data.positions = sample.getPositions();
1217
1218         if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
1219                 read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector);
1220         }
1221
1222         if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) {
1223                 read_mverts(config, abc_mesh_data);
1224         }
1225
1226         if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) {
1227                 read_mpolys(config, abc_mesh_data);
1228         }
1229
1230         if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) {
1231                 read_custom_data(schema.getArbGeomParams(), config, selector);
1232         }
1233
1234         /* TODO: face sets */
1235 }