diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/alembic | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/alembic')
29 files changed, 4958 insertions, 4931 deletions
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index bc3a1699044..653382017d6 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -35,46 +35,46 @@ struct bContext; typedef struct AbcArchiveHandle AbcArchiveHandle; enum { - ABC_ARCHIVE_OGAWA = 0, - ABC_ARCHIVE_HDF5 = 1, + ABC_ARCHIVE_OGAWA = 0, + ABC_ARCHIVE_HDF5 = 1, }; int ABC_get_version(void); struct AlembicExportParams { - double frame_start; - double frame_end; - - unsigned int frame_samples_xform; - unsigned int frame_samples_shape; - - double shutter_open; - double shutter_close; - - bool selected_only; - bool uvs; - bool normals; - bool vcolors; - bool apply_subdiv; - bool curves_as_mesh; - bool flatten_hierarchy; - bool visible_layers_only; - bool renderable_only; - bool face_sets; - bool use_subdiv_schema; - bool packuv; - bool triangulate; - bool export_hair; - bool export_particles; - - unsigned int compression_type : 1; - - /* See MOD_TRIANGULATE_NGON_xxx and MOD_TRIANGULATE_QUAD_xxx - * in DNA_modifier_types.h */ - int quad_method; - int ngon_method; - - float global_scale; + double frame_start; + double frame_end; + + unsigned int frame_samples_xform; + unsigned int frame_samples_shape; + + double shutter_open; + double shutter_close; + + bool selected_only; + bool uvs; + bool normals; + bool vcolors; + bool apply_subdiv; + bool curves_as_mesh; + bool flatten_hierarchy; + bool visible_layers_only; + bool renderable_only; + bool face_sets; + bool use_subdiv_schema; + bool packuv; + bool triangulate; + bool export_hair; + bool export_particles; + + unsigned int compression_type : 1; + + /* See MOD_TRIANGULATE_NGON_xxx and MOD_TRIANGULATE_QUAD_xxx + * in DNA_modifier_types.h */ + int quad_method; + int ngon_method; + + float global_scale; }; /* The ABC_export and ABC_import functions both take a as_background_job @@ -87,12 +87,11 @@ struct AlembicExportParams { * true when the export was ok, and false if there were any errors. */ -bool ABC_export( - struct Scene *scene, - struct bContext *C, - const char *filepath, - const struct AlembicExportParams *params, - bool as_background_job); +bool ABC_export(struct Scene *scene, + struct bContext *C, + const char *filepath, + const struct AlembicExportParams *params, + bool as_background_job); bool ABC_import(struct bContext *C, const char *filepath, @@ -108,10 +107,7 @@ AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *objec void ABC_free_handle(AbcArchiveHandle *handle); -void ABC_get_transform(struct CacheReader *reader, - float r_mat[4][4], - float time, - float scale); +void ABC_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale); /* Either modifies current_mesh in-place or constructs a new mesh. */ struct Mesh *ABC_read_mesh(struct CacheReader *reader, @@ -133,4 +129,4 @@ struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *han } #endif -#endif /* __ABC_ALEMBIC_H__ */ +#endif /* __ABC_ALEMBIC_H__ */ diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt index 9f94c118492..82812fb81cf 100644 --- a/source/blender/alembic/CMakeLists.txt +++ b/source/blender/alembic/CMakeLists.txt @@ -19,66 +19,66 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - . - ../blenkernel - ../blenlib - ../blenloader - ../bmesh - ../depsgraph - ../editors/include - ../makesdna - ../makesrna - ../windowmanager - ../../../intern/guardedalloc - ../../../intern/utfconv + . + ../blenkernel + ../blenlib + ../blenloader + ../bmesh + ../depsgraph + ../editors/include + ../makesdna + ../makesrna + ../windowmanager + ../../../intern/guardedalloc + ../../../intern/utfconv ) set(INC_SYS - ${ALEMBIC_INCLUDE_DIRS} - ${BOOST_INCLUDE_DIR} - ${HDF5_INCLUDE_DIRS} - ${OPENEXR_INCLUDE_DIRS} + ${ALEMBIC_INCLUDE_DIRS} + ${BOOST_INCLUDE_DIR} + ${HDF5_INCLUDE_DIRS} + ${OPENEXR_INCLUDE_DIRS} ) set(SRC - intern/abc_archive.cc - intern/abc_camera.cc - intern/abc_curves.cc - intern/abc_customdata.cc - intern/abc_exporter.cc - intern/abc_hair.cc - intern/abc_mball.cc - intern/abc_mesh.cc - intern/abc_nurbs.cc - intern/abc_object.cc - intern/abc_points.cc - intern/abc_transform.cc - intern/abc_util.cc - intern/alembic_capi.cc + intern/abc_archive.cc + intern/abc_camera.cc + intern/abc_curves.cc + intern/abc_customdata.cc + intern/abc_exporter.cc + intern/abc_hair.cc + intern/abc_mball.cc + intern/abc_mesh.cc + intern/abc_nurbs.cc + intern/abc_object.cc + intern/abc_points.cc + intern/abc_transform.cc + intern/abc_util.cc + intern/alembic_capi.cc - ABC_alembic.h - intern/abc_archive.h - intern/abc_camera.h - intern/abc_curves.h - intern/abc_customdata.h - intern/abc_exporter.h - intern/abc_hair.h - intern/abc_mball.h - intern/abc_mesh.h - intern/abc_nurbs.h - intern/abc_object.h - intern/abc_points.h - intern/abc_transform.h - intern/abc_util.h + ABC_alembic.h + intern/abc_archive.h + intern/abc_camera.h + intern/abc_curves.h + intern/abc_customdata.h + intern/abc_exporter.h + intern/abc_hair.h + intern/abc_mball.h + intern/abc_mesh.h + intern/abc_nurbs.h + intern/abc_object.h + intern/abc_points.h + intern/abc_transform.h + intern/abc_util.h ) set(LIB - bf_blenkernel - bf_blenlib + bf_blenkernel + bf_blenlib ) if(WITH_ALEMBIC_HDF5) - add_definitions(-DWITH_ALEMBIC_HDF5) + add_definitions(-DWITH_ALEMBIC_HDF5) endif() blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_archive.cc index 7bd3e5af66a..c4252d20d48 100644 --- a/source/blender/alembic/intern/abc_archive.cc +++ b/source/blender/alembic/intern/abc_archive.cc @@ -22,9 +22,8 @@ */ #include "abc_archive.h" -extern "C" -{ - #include "BKE_blender_version.h" +extern "C" { +#include "BKE_blender_version.h" } #ifdef WIN32 @@ -33,8 +32,8 @@ extern "C" #include <fstream> -using Alembic::Abc::Exception; using Alembic::Abc::ErrorHandler; +using Alembic::Abc::Exception; using Alembic::Abc::IArchive; using Alembic::Abc::kWrapExisting; using Alembic::Abc::OArchive; @@ -43,95 +42,94 @@ static IArchive open_archive(const std::string &filename, const std::vector<std::istream *> &input_streams, bool &is_hdf5) { - is_hdf5 = false; + is_hdf5 = false; - try { - Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams); + try { + Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams); - return IArchive(archive_reader(filename), - kWrapExisting, - ErrorHandler::kThrowPolicy); - } - catch (const Exception &e) { - std::cerr << e.what() << '\n'; + return IArchive(archive_reader(filename), kWrapExisting, ErrorHandler::kThrowPolicy); + } + catch (const Exception &e) { + std::cerr << e.what() << '\n'; #ifdef WITH_ALEMBIC_HDF5 - try { - is_hdf5 = true; - Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr; - - return IArchive(Alembic::AbcCoreHDF5::ReadArchive(), - filename.c_str(), ErrorHandler::kThrowPolicy, - cache_ptr); - } - catch (const Exception &) { - std::cerr << e.what() << '\n'; - return IArchive(); - } + try { + is_hdf5 = true; + Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr; + + return IArchive(Alembic::AbcCoreHDF5::ReadArchive(), + filename.c_str(), + ErrorHandler::kThrowPolicy, + cache_ptr); + } + catch (const Exception &) { + std::cerr << e.what() << '\n'; + return IArchive(); + } #else - /* Inspect the file to see whether it's really a HDF5 file. */ - char header[4]; /* char(0x89) + "HDF" */ - std::ifstream the_file(filename.c_str(), std::ios::in | std::ios::binary); - if (!the_file) { - std::cerr << "Unable to open " << filename << std::endl; - } - else if (!the_file.read(header, sizeof(header))) { - std::cerr << "Unable to read from " << filename << std::endl; - } - else if (strncmp(header + 1, "HDF", 3)) { - std::cerr << filename << " has an unknown file format, unable to read." << std::endl; - } - else { - is_hdf5 = true; - std::cerr << filename << " is in the obsolete HDF5 format, unable to read." << std::endl; - } - - if (the_file.is_open()) { - the_file.close(); - } - - return IArchive(); + /* Inspect the file to see whether it's really a HDF5 file. */ + char header[4]; /* char(0x89) + "HDF" */ + std::ifstream the_file(filename.c_str(), std::ios::in | std::ios::binary); + if (!the_file) { + std::cerr << "Unable to open " << filename << std::endl; + } + else if (!the_file.read(header, sizeof(header))) { + std::cerr << "Unable to read from " << filename << std::endl; + } + else if (strncmp(header + 1, "HDF", 3)) { + std::cerr << filename << " has an unknown file format, unable to read." << std::endl; + } + else { + is_hdf5 = true; + std::cerr << filename << " is in the obsolete HDF5 format, unable to read." << std::endl; + } + + if (the_file.is_open()) { + the_file.close(); + } + + return IArchive(); #endif - } + } - return IArchive(); + return IArchive(); } ArchiveReader::ArchiveReader(const char *filename) { #ifdef WIN32 - UTF16_ENCODE(filename); - std::wstring wstr(filename_16); - m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary); - UTF16_UN_ENCODE(filename); + UTF16_ENCODE(filename); + std::wstring wstr(filename_16); + m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary); + UTF16_UN_ENCODE(filename); #else - m_infile.open(filename, std::ios::in | std::ios::binary); + m_infile.open(filename, std::ios::in | std::ios::binary); #endif - m_streams.push_back(&m_infile); + m_streams.push_back(&m_infile); - m_archive = open_archive(filename, m_streams, m_is_hdf5); + m_archive = open_archive(filename, m_streams, m_is_hdf5); - /* We can't open an HDF5 file from a stream, so close it. */ - if (m_is_hdf5) { - m_infile.close(); - m_streams.clear(); - } + /* We can't open an HDF5 file from a stream, so close it. */ + if (m_is_hdf5) { + m_infile.close(); + m_streams.clear(); + } } bool ArchiveReader::is_hdf5() const { - return m_is_hdf5; + return m_is_hdf5; } bool ArchiveReader::valid() const { - return m_archive.valid(); + return m_archive.valid(); } Alembic::Abc::IObject ArchiveReader::getTop() { - return m_archive.getTop(); + return m_archive.getTop(); } /* ************************************************************************** */ @@ -144,64 +142,63 @@ static OArchive create_archive(std::ostream *ostream, Alembic::Abc::MetaData &md, bool ogawa) { - md.set(Alembic::Abc::kApplicationNameKey, "Blender"); - md.set(Alembic::Abc::kUserDescriptionKey, scene_name); - md.set("blender_version", versionstr); + md.set(Alembic::Abc::kApplicationNameKey, "Blender"); + md.set(Alembic::Abc::kUserDescriptionKey, scene_name); + md.set("blender_version", versionstr); - time_t raw_time; - time(&raw_time); - char buffer[128]; + time_t raw_time; + time(&raw_time); + char buffer[128]; #if defined _WIN32 || defined _WIN64 - ctime_s(buffer, 128, &raw_time); + ctime_s(buffer, 128, &raw_time); #else - ctime_r(&raw_time, buffer); + ctime_r(&raw_time, buffer); #endif - const std::size_t buffer_len = strlen(buffer); - if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { - buffer[buffer_len - 1] = '\0'; - } + const std::size_t buffer_len = strlen(buffer); + if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') { + buffer[buffer_len - 1] = '\0'; + } - md.set(Alembic::Abc::kDateWrittenKey, buffer); + md.set(Alembic::Abc::kDateWrittenKey, buffer); - ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; + ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; #ifdef WITH_ALEMBIC_HDF5 - if (!ogawa) { - return OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy); - } + if (!ogawa) { + return OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy); + } #else - static_cast<void>(filename); - static_cast<void>(ogawa); + static_cast<void>(filename); + static_cast<void>(ogawa); #endif - Alembic::AbcCoreOgawa::WriteArchive archive_writer; - return OArchive(archive_writer(ostream, md), kWrapExisting, policy); + Alembic::AbcCoreOgawa::WriteArchive archive_writer; + return OArchive(archive_writer(ostream, md), kWrapExisting, policy); } -ArchiveWriter::ArchiveWriter(const char *filename, const char *scene, bool do_ogawa, Alembic::Abc::MetaData &md) +ArchiveWriter::ArchiveWriter(const char *filename, + const char *scene, + bool do_ogawa, + Alembic::Abc::MetaData &md) { - /* Use stream to support unicode character paths on Windows. */ - if (do_ogawa) { + /* Use stream to support unicode character paths on Windows. */ + if (do_ogawa) { #ifdef WIN32 - UTF16_ENCODE(filename); - std::wstring wstr(filename_16); - m_outfile.open(wstr.c_str(), std::ios::out | std::ios::binary); - UTF16_UN_ENCODE(filename); + UTF16_ENCODE(filename); + std::wstring wstr(filename_16); + m_outfile.open(wstr.c_str(), std::ios::out | std::ios::binary); + UTF16_UN_ENCODE(filename); #else - m_outfile.open(filename, std::ios::out | std::ios::binary); + m_outfile.open(filename, std::ios::out | std::ios::binary); #endif - } + } - m_archive = create_archive(&m_outfile, - filename, - scene, - md, - do_ogawa); + m_archive = create_archive(&m_outfile, filename, scene, md, do_ogawa); } OArchive &ArchiveWriter::archive() { - return m_archive; + return m_archive; } diff --git a/source/blender/alembic/intern/abc_archive.h b/source/blender/alembic/intern/abc_archive.h index ced55f56eac..343a8112aa2 100644 --- a/source/blender/alembic/intern/abc_archive.h +++ b/source/blender/alembic/intern/abc_archive.h @@ -40,35 +40,38 @@ */ class ArchiveReader { - Alembic::Abc::IArchive m_archive; - std::ifstream m_infile; - std::vector<std::istream *> m_streams; - bool m_is_hdf5; + Alembic::Abc::IArchive m_archive; + std::ifstream m_infile; + std::vector<std::istream *> m_streams; + bool m_is_hdf5; -public: - explicit ArchiveReader(const char *filename); + public: + explicit ArchiveReader(const char *filename); - bool valid() const; + bool valid() const; - /** - * Returns true when either Blender is compiled with HDF5 support and - * the archive was successfully opened (valid() will also return true), - * or when Blender was built without HDF5 support but a HDF5 file was - * detected (valid() will return false). - */ - bool is_hdf5() const; + /** + * Returns true when either Blender is compiled with HDF5 support and + * the archive was successfully opened (valid() will also return true), + * or when Blender was built without HDF5 support but a HDF5 file was + * detected (valid() will return false). + */ + bool is_hdf5() const; - Alembic::Abc::IObject getTop(); + Alembic::Abc::IObject getTop(); }; class ArchiveWriter { - std::ofstream m_outfile; - Alembic::Abc::OArchive m_archive; + std::ofstream m_outfile; + Alembic::Abc::OArchive m_archive; -public: - explicit ArchiveWriter(const char *filename, const char *scene, bool do_ogawa, Alembic::Abc::MetaData &md); + public: + explicit ArchiveWriter(const char *filename, + const char *scene, + bool do_ogawa, + Alembic::Abc::MetaData &md); - Alembic::Abc::OArchive &archive(); + Alembic::Abc::OArchive &archive(); }; #endif /* __ABC_ARCHIVE_H__ */ diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc index 572e825299b..b15608703de 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_camera.cc @@ -53,49 +53,49 @@ AbcCameraWriter::AbcCameraWriter(Object *ob, ExportSettings &settings) : AbcObjectWriter(ob, time_sampling, settings, parent) { - OCamera camera(parent->alembicXform(), m_name, m_time_sampling); - m_camera_schema = camera.getSchema(); + OCamera camera(parent->alembicXform(), m_name, m_time_sampling); + m_camera_schema = camera.getSchema(); - m_custom_data_container = m_camera_schema.getUserProperties(); - m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling); - m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling); + m_custom_data_container = m_camera_schema.getUserProperties(); + m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling); + m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling); } void AbcCameraWriter::do_write() { - Camera *cam = static_cast<Camera *>(m_object->data); - - m_stereo_distance.set(cam->stereo.convergence_distance); - m_eye_separation.set(cam->stereo.interocular_distance); - - const double apperture_x = cam->sensor_x / 10.0; - const double apperture_y = cam->sensor_y / 10.0; - const double film_aspect = apperture_x / apperture_y; - - m_camera_sample.setFocalLength(cam->lens); - m_camera_sample.setHorizontalAperture(apperture_x); - m_camera_sample.setVerticalAperture(apperture_y); - m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx); - m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect); - m_camera_sample.setNearClippingPlane(cam->clip_start); - m_camera_sample.setFarClippingPlane(cam->clip_end); - - if (cam->dof_ob) { - Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0], - m_object->loc[1] - cam->dof_ob->loc[1], - m_object->loc[2] - cam->dof_ob->loc[2]); - m_camera_sample.setFocusDistance(v.length()); - } - else { - m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance); - } - - /* Blender camera does not have an fstop param, so try to find a custom prop - * instead. */ - m_camera_sample.setFStop(cam->gpu_dof.fstop); - - m_camera_sample.setLensSqueezeRatio(1.0); - m_camera_schema.set(m_camera_sample); + Camera *cam = static_cast<Camera *>(m_object->data); + + m_stereo_distance.set(cam->stereo.convergence_distance); + m_eye_separation.set(cam->stereo.interocular_distance); + + const double apperture_x = cam->sensor_x / 10.0; + const double apperture_y = cam->sensor_y / 10.0; + const double film_aspect = apperture_x / apperture_y; + + m_camera_sample.setFocalLength(cam->lens); + m_camera_sample.setHorizontalAperture(apperture_x); + m_camera_sample.setVerticalAperture(apperture_y); + m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx); + m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect); + m_camera_sample.setNearClippingPlane(cam->clip_start); + m_camera_sample.setFarClippingPlane(cam->clip_end); + + if (cam->dof_ob) { + Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0], + m_object->loc[1] - cam->dof_ob->loc[1], + m_object->loc[2] - cam->dof_ob->loc[2]); + m_camera_sample.setFocusDistance(v.length()); + } + else { + m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance); + } + + /* Blender camera does not have an fstop param, so try to find a custom prop + * instead. */ + m_camera_sample.setFStop(cam->gpu_dof.fstop); + + m_camera_sample.setLensSqueezeRatio(1.0); + m_camera_schema.set(m_camera_sample); } /* ************************************************************************** */ @@ -103,71 +103,72 @@ void AbcCameraWriter::do_write() AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - ICamera abc_cam(m_iobject, kWrapExisting); - m_schema = abc_cam.getSchema(); + ICamera abc_cam(m_iobject, kWrapExisting); + m_schema = abc_cam.getSchema(); - get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); + get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); } bool AbcCameraReader::valid() const { - return m_schema.valid(); + return m_schema.valid(); } -bool AbcCameraReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const +bool AbcCameraReader::accepts_object_type( + const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const { - if (!Alembic::AbcGeom::ICamera::matches(alembic_header)) { - *err_str = "Object type mismatch, Alembic object path pointed to Camera when importing, but not any more."; - return false; - } - - if (ob->type != OB_CAMERA) { - *err_str = "Object type mismatch, Alembic object path points to Camera."; - return false; - } - - return true; + if (!Alembic::AbcGeom::ICamera::matches(alembic_header)) { + *err_str = + "Object type mismatch, Alembic object path pointed to Camera when importing, but not any " + "more."; + return false; + } + + if (ob->type != OB_CAMERA) { + *err_str = "Object type mismatch, Alembic object path points to Camera."; + return false; + } + + return true; } void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_sel) { - Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str())); - - CameraSample cam_sample; - m_schema.get(cam_sample, sample_sel); - - ICompoundProperty customDataContainer = m_schema.getUserProperties(); - - if (customDataContainer.valid() && - customDataContainer.getPropertyHeader("stereoDistance") && - customDataContainer.getPropertyHeader("eyeSeparation")) - { - IFloatProperty convergence_plane(customDataContainer, "stereoDistance"); - IFloatProperty eye_separation(customDataContainer, "eyeSeparation"); - - bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel); - bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel); - } - - const float lens = static_cast<float>(cam_sample.getFocalLength()); - const float apperture_x = static_cast<float>(cam_sample.getHorizontalAperture()); - const float apperture_y = static_cast<float>(cam_sample.getVerticalAperture()); - const float h_film_offset = static_cast<float>(cam_sample.getHorizontalFilmOffset()); - const float v_film_offset = static_cast<float>(cam_sample.getVerticalFilmOffset()); - const float film_aspect = apperture_x / apperture_y; - - bcam->lens = lens; - bcam->sensor_x = apperture_x * 10; - bcam->sensor_y = apperture_y * 10; - bcam->shiftx = h_film_offset / apperture_x; - bcam->shifty = v_film_offset / apperture_y / film_aspect; - bcam->clip_start = max_ff(0.1f, static_cast<float>(cam_sample.getNearClippingPlane())); - bcam->clip_end = static_cast<float>(cam_sample.getFarClippingPlane()); - bcam->gpu_dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance()); - bcam->gpu_dof.fstop = static_cast<float>(cam_sample.getFStop()); - - m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); - m_object->data = bcam; + Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, m_data_name.c_str())); + + CameraSample cam_sample; + m_schema.get(cam_sample, sample_sel); + + ICompoundProperty customDataContainer = m_schema.getUserProperties(); + + if (customDataContainer.valid() && customDataContainer.getPropertyHeader("stereoDistance") && + customDataContainer.getPropertyHeader("eyeSeparation")) { + IFloatProperty convergence_plane(customDataContainer, "stereoDistance"); + IFloatProperty eye_separation(customDataContainer, "eyeSeparation"); + + bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel); + bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel); + } + + const float lens = static_cast<float>(cam_sample.getFocalLength()); + const float apperture_x = static_cast<float>(cam_sample.getHorizontalAperture()); + const float apperture_y = static_cast<float>(cam_sample.getVerticalAperture()); + const float h_film_offset = static_cast<float>(cam_sample.getHorizontalFilmOffset()); + const float v_film_offset = static_cast<float>(cam_sample.getVerticalFilmOffset()); + const float film_aspect = apperture_x / apperture_y; + + bcam->lens = lens; + bcam->sensor_x = apperture_x * 10; + bcam->sensor_y = apperture_y * 10; + bcam->shiftx = h_film_offset / apperture_x; + bcam->shifty = v_film_offset / apperture_y / film_aspect; + bcam->clip_start = max_ff(0.1f, static_cast<float>(cam_sample.getNearClippingPlane())); + bcam->clip_end = static_cast<float>(cam_sample.getFarClippingPlane()); + bcam->gpu_dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance()); + bcam->gpu_dof.fstop = static_cast<float>(cam_sample.getFStop()); + + m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); + m_object->data = bcam; } diff --git a/source/blender/alembic/intern/abc_camera.h b/source/blender/alembic/intern/abc_camera.h index a5cd8373dc0..28169cb7d85 100644 --- a/source/blender/alembic/intern/abc_camera.h +++ b/source/blender/alembic/intern/abc_camera.h @@ -26,36 +26,36 @@ /* ************************************************************************** */ class AbcCameraWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCameraSchema m_camera_schema; - Alembic::AbcGeom::CameraSample m_camera_sample; - Alembic::AbcGeom::OCompoundProperty m_custom_data_container; - Alembic::AbcGeom::OFloatProperty m_stereo_distance; - Alembic::AbcGeom::OFloatProperty m_eye_separation; - -public: - AbcCameraWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - -private: - virtual void do_write(); + Alembic::AbcGeom::OCameraSchema m_camera_schema; + Alembic::AbcGeom::CameraSample m_camera_sample; + Alembic::AbcGeom::OCompoundProperty m_custom_data_container; + Alembic::AbcGeom::OFloatProperty m_stereo_distance; + Alembic::AbcGeom::OFloatProperty m_eye_separation; + + public: + AbcCameraWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); + + private: + virtual void do_write(); }; /* ************************************************************************** */ class AbcCameraReader : public AbcObjectReader { - Alembic::AbcGeom::ICameraSchema m_schema; + Alembic::AbcGeom::ICameraSchema m_schema; -public: - AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + public: + AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - bool valid() const; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const; + bool valid() const; + bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); }; -#endif /* __ABC_CAMERA_H__ */ +#endif /* __ABC_CAMERA_H__ */ diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index c78f31b671f..13872618d74 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -43,13 +43,14 @@ extern "C" { #include "ED_curve.h" } +using Alembic::Abc::FloatArraySamplePtr; using Alembic::Abc::IInt32ArrayProperty; using Alembic::Abc::Int32ArraySamplePtr; -using Alembic::Abc::FloatArraySamplePtr; using Alembic::Abc::P3fArraySamplePtr; -using Alembic::Abc::UcharArraySamplePtr; using Alembic::Abc::PropertyHeader; +using Alembic::Abc::UcharArraySamplePtr; +using Alembic::AbcGeom::CurvePeriodicity; using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::ICurves; using Alembic::AbcGeom::ICurvesSchema; @@ -57,7 +58,6 @@ 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; @@ -76,358 +76,366 @@ AbcCurveWriter::AbcCurveWriter(Object *ob, ExportSettings &settings) : AbcObjectWriter(ob, time_sampling, settings, parent) { - OCurves curves(parent->alembicXform(), m_name, m_time_sampling); - m_schema = curves.getSchema(); + 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); + 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() { - Curve *curve = static_cast<Curve *>(m_object->data); - - std::vector<Imath::V3f> verts; - std::vector<int32_t> vert_counts; - std::vector<float> widths; - std::vector<float> weights; - std::vector<float> knots; - std::vector<uint8_t> orders; - Imath::V3f temp_vert; - - Alembic::AbcGeom::BasisType curve_basis; - Alembic::AbcGeom::CurveType curve_type; - Alembic::AbcGeom::CurvePeriodicity periodicity; - - Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); - for (; nurbs; nurbs = nurbs->next) { - if (nurbs->bp) { - curve_basis = Alembic::AbcGeom::kNoBasis; - curve_type = Alembic::AbcGeom::kVariableOrder; - - const int totpoint = nurbs->pntsu * nurbs->pntsv; - - const BPoint *point = nurbs->bp; - - for (int i = 0; i < totpoint; ++i, ++point) { - copy_yup_from_zup(temp_vert.getValue(), point->vec); - verts.push_back(temp_vert); - weights.push_back(point->vec[3]); - widths.push_back(point->radius); - } - } - else if (nurbs->bezt) { - curve_basis = Alembic::AbcGeom::kBezierBasis; - curve_type = Alembic::AbcGeom::kCubic; - - const int totpoint = nurbs->pntsu; - - const BezTriple *bezier = nurbs->bezt; - - /* TODO(kevin): store info about handles, Alembic doesn't have this. */ - for (int i = 0; i < totpoint; ++i, ++bezier) { - copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]); - verts.push_back(temp_vert); - widths.push_back(bezier->radius); - } - } - - if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) { - periodicity = Alembic::AbcGeom::kNonPeriodic; - } - else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) { - periodicity = Alembic::AbcGeom::kPeriodic; - - /* Duplicate the start points to indicate that the curve is actually - * cyclic since other software need those. - */ - - for (int i = 0; i < nurbs->orderu; ++i) { - verts.push_back(verts[i]); - } - } - - if (nurbs->knotsu != NULL) { - const size_t num_knots = KNOTSU(nurbs); - - /* Add an extra knot at the beginning and end of the array since most apps - * require/expect them. */ - knots.resize(num_knots + 2); - - for (int i = 0; i < num_knots; ++i) { - knots[i + 1] = nurbs->knotsu[i]; - } - - if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) { - knots[0] = nurbs->knotsu[0]; - knots[num_knots - 1] = nurbs->knotsu[num_knots - 1]; - } - else { - knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]); - knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - nurbs->knotsu[num_knots - 2]); - } - } - - orders.push_back(nurbs->orderu); - vert_counts.push_back(verts.size()); - } - - Alembic::AbcGeom::OFloatGeomParam::Sample width_sample; - width_sample.setVals(widths); - - m_sample = OCurvesSchema::Sample(verts, - vert_counts, - curve_type, - periodicity, - width_sample, - OV2fGeomParam::Sample(), /* UVs */ - ON3fGeomParam::Sample(), /* normals */ - curve_basis, - weights, - orders, - knots); - - m_sample.setSelfBounds(bounds()); - m_schema.set(m_sample); + Curve *curve = static_cast<Curve *>(m_object->data); + + std::vector<Imath::V3f> verts; + std::vector<int32_t> vert_counts; + std::vector<float> widths; + std::vector<float> weights; + std::vector<float> knots; + std::vector<uint8_t> orders; + Imath::V3f temp_vert; + + Alembic::AbcGeom::BasisType curve_basis; + Alembic::AbcGeom::CurveType curve_type; + Alembic::AbcGeom::CurvePeriodicity periodicity; + + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (; nurbs; nurbs = nurbs->next) { + if (nurbs->bp) { + curve_basis = Alembic::AbcGeom::kNoBasis; + curve_type = Alembic::AbcGeom::kVariableOrder; + + const int totpoint = nurbs->pntsu * nurbs->pntsv; + + const BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; ++i, ++point) { + copy_yup_from_zup(temp_vert.getValue(), point->vec); + verts.push_back(temp_vert); + weights.push_back(point->vec[3]); + widths.push_back(point->radius); + } + } + else if (nurbs->bezt) { + curve_basis = Alembic::AbcGeom::kBezierBasis; + curve_type = Alembic::AbcGeom::kCubic; + + const int totpoint = nurbs->pntsu; + + const BezTriple *bezier = nurbs->bezt; + + /* TODO(kevin): store info about handles, Alembic doesn't have this. */ + for (int i = 0; i < totpoint; ++i, ++bezier) { + copy_yup_from_zup(temp_vert.getValue(), bezier->vec[1]); + verts.push_back(temp_vert); + widths.push_back(bezier->radius); + } + } + + if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) { + periodicity = Alembic::AbcGeom::kNonPeriodic; + } + else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) { + periodicity = Alembic::AbcGeom::kPeriodic; + + /* Duplicate the start points to indicate that the curve is actually + * cyclic since other software need those. + */ + + for (int i = 0; i < nurbs->orderu; ++i) { + verts.push_back(verts[i]); + } + } + + if (nurbs->knotsu != NULL) { + const size_t num_knots = KNOTSU(nurbs); + + /* Add an extra knot at the beginning and end of the array since most apps + * require/expect them. */ + knots.resize(num_knots + 2); + + for (int i = 0; i < num_knots; ++i) { + knots[i + 1] = nurbs->knotsu[i]; + } + + if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) { + knots[0] = nurbs->knotsu[0]; + knots[num_knots - 1] = nurbs->knotsu[num_knots - 1]; + } + else { + knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]); + knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - + nurbs->knotsu[num_knots - 2]); + } + } + + orders.push_back(nurbs->orderu); + vert_counts.push_back(verts.size()); + } + + Alembic::AbcGeom::OFloatGeomParam::Sample width_sample; + width_sample.setVals(widths); + + m_sample = OCurvesSchema::Sample(verts, + vert_counts, + curve_type, + periodicity, + width_sample, + OV2fGeomParam::Sample(), /* UVs */ + ON3fGeomParam::Sample(), /* normals */ + curve_basis, + weights, + orders, + knots); + + m_sample.setSelfBounds(bounds()); + m_schema.set(m_sample); } - AbcCurveMeshWriter::AbcCurveMeshWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) : AbcGenericMeshWriter(ob, parent, time_sampling, settings) -{} - -Mesh *AbcCurveMeshWriter::getEvaluatedMesh(Scene * /*scene_eval*/, Object *ob_eval, bool &r_needsfree) { - if (ob_eval->runtime.mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return ob_eval->runtime.mesh_eval; - } - - r_needsfree = true; - return BKE_mesh_new_nomain_from_curve(ob_eval); } +Mesh *AbcCurveMeshWriter::getEvaluatedMesh(Scene * /*scene_eval*/, + Object *ob_eval, + bool &r_needsfree) +{ + if (ob_eval->runtime.mesh_eval != NULL) { + /* Mesh_eval only exists when generative modifiers are in use. */ + r_needsfree = false; + return ob_eval->runtime.mesh_eval; + } + + r_needsfree = true; + return BKE_mesh_new_nomain_from_curve(ob_eval); +} /* ************************************************************************** */ AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - ICurves abc_curves(object, kWrapExisting); - m_curves_schema = abc_curves.getSchema(); + ICurves abc_curves(object, kWrapExisting); + m_curves_schema = abc_curves.getSchema(); - get_min_max_time(m_iobject, m_curves_schema, m_min_time, m_max_time); + get_min_max_time(m_iobject, m_curves_schema, m_min_time, m_max_time); } bool AbcCurveReader::valid() const { - return m_curves_schema.valid(); + return m_curves_schema.valid(); } -bool AbcCurveReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const +bool AbcCurveReader::accepts_object_type( + const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const { - if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) { - *err_str = "Object type mismatch, Alembic object path pointed to Curves when importing, but not any more."; - return false; - } - - if (ob->type != OB_CURVE) { - *err_str = "Object type mismatch, Alembic object path points to Curves."; - return false; - } - - return true; + if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) { + *err_str = + "Object type mismatch, Alembic object path pointed to Curves when importing, but not any " + "more."; + return false; + } + + if (ob->type != OB_CURVE) { + *err_str = "Object type mismatch, Alembic object path points to Curves."; + return false; + } + + return true; } void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) { - Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE); + Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE); - cu->flag |= CU_DEFORM_FILL | CU_3D; - cu->actvert = CU_ACT_NONE; - cu->resolu = 1; + cu->flag |= CU_DEFORM_FILL | CU_3D; + cu->actvert = CU_ACT_NONE; + cu->resolu = 1; - ICompoundProperty user_props = m_curves_schema.getUserProperties(); - if (user_props) { - 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); - } - } + ICompoundProperty user_props = m_curves_schema.getUserProperties(); + if (user_props) { + 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); + } + } - m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str()); - m_object->data = cu; + 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, sample_sel); + read_curve_sample(cu, m_curves_schema, sample_sel); - if (has_animations(m_curves_schema, m_settings)) { - addCacheModifier(); - } + if (has_animations(m_curves_schema, m_settings)) { + addCacheModifier(); + } } /* ************************************************************************** */ -void AbcCurveReader::read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel) +void AbcCurveReader::read_curve_sample(Curve *cu, + const ICurvesSchema &schema, + const ISampleSelector &sample_sel) { - ICurvesSchema::Sample smp; - try { - smp = schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return; - } - - const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices(); - const P3fArraySamplePtr positions = smp.getPositions(); - const FloatArraySamplePtr weights = smp.getPositionWeights(); - const FloatArraySamplePtr knots = smp.getKnots(); - const CurvePeriodicity periodicity = smp.getWrap(); - const UcharArraySamplePtr orders = smp.getOrders(); - - const IFloatGeomParam widths_param = schema.getWidthsParam(); - FloatArraySamplePtr radiuses; - - if (widths_param.valid()) { - IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel); - radiuses = wsample.getVals(); - } - - int knot_offset = 0; - - size_t idx = 0; - for (size_t i = 0; i < num_vertices->size(); ++i) { - const int num_verts = (*num_vertices)[i]; - - Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb")); - nu->resolu = cu->resolu; - nu->resolv = cu->resolv; - nu->pntsu = num_verts; - nu->pntsv = 1; - nu->flag |= CU_SMOOTH; - - switch (smp.getType()) { - case Alembic::AbcGeom::kCubic: - nu->orderu = 4; - break; - case Alembic::AbcGeom::kVariableOrder: - if (orders && orders->size() > i) { - nu->orderu = static_cast<short>((*orders)[i]); - break; - } - ATTR_FALLTHROUGH; - case Alembic::AbcGeom::kLinear: - default: - nu->orderu = 2; - } - - if (periodicity == Alembic::AbcGeom::kNonPeriodic) { - nu->flagu |= CU_NURB_ENDPOINT; - } - else if (periodicity == Alembic::AbcGeom::kPeriodic) { - nu->flagu |= CU_NURB_CYCLIC; - - /* Check the number of points which overlap, we don't have - * overlapping points in Blender, but other software do use them to - * indicate that a curve is actually cyclic. Usually the number of - * overlapping points is equal to the order/degree of the curve. - */ - - const int start = idx; - const int end = idx + num_verts; - int overlap = 0; - - for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) { - const Imath::V3f &p1 = (*positions)[j]; - const Imath::V3f &p2 = (*positions)[k]; - - if (p1 != p2) { - break; - } - - ++overlap; - } - - /* TODO: Special case, need to figure out how it coincides with knots. */ - if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) { - overlap = 1; - } - - /* There is no real cycles. */ - if (overlap == 0) { - nu->flagu &= ~CU_NURB_CYCLIC; - nu->flagu |= CU_NURB_ENDPOINT; - } - - nu->pntsu -= overlap; - } - - const bool do_weights = (weights != NULL) && (weights->size() > 1); - float weight = 1.0f; - - const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1); - float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f; - - nu->type = CU_NURBS; - - nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb")); - BPoint *bp = nu->bp; - - for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) { - const Imath::V3f &pos = (*positions)[idx]; - - if (do_radius) { - radius = (*radiuses)[idx]; - } - - if (do_weights) { - weight = (*weights)[idx]; - } - - copy_zup_from_yup(bp->vec, pos.getValue()); - bp->vec[3] = weight; - bp->f1 = SELECT; - bp->radius = radius; - bp->weight = 1.0f; - } - - if (knots && knots->size() != 0) { - nu->knotsu = static_cast<float *>(MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu")); - - /* TODO: second check is temporary, for until the check for cycles is rock solid. */ - if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) { - /* Skip first and last knots. */ - for (size_t i = 1; i < knots->size() - 1; ++i) { - nu->knotsu[i - 1] = (*knots)[knot_offset + i]; - } - } - else { - /* TODO: figure out how to use the knots array from other - * software in this case. */ - BKE_nurb_knot_calc_u(nu); - } - - knot_offset += knots->size(); - } - else { - BKE_nurb_knot_calc_u(nu); - } - - BLI_addtail(BKE_curve_nurbs_get(cu), nu); - } + ICurvesSchema::Sample smp; + try { + smp = schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return; + } + + const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices(); + const P3fArraySamplePtr positions = smp.getPositions(); + const FloatArraySamplePtr weights = smp.getPositionWeights(); + const FloatArraySamplePtr knots = smp.getKnots(); + const CurvePeriodicity periodicity = smp.getWrap(); + const UcharArraySamplePtr orders = smp.getOrders(); + + const IFloatGeomParam widths_param = schema.getWidthsParam(); + FloatArraySamplePtr radiuses; + + if (widths_param.valid()) { + IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel); + radiuses = wsample.getVals(); + } + + int knot_offset = 0; + + size_t idx = 0; + for (size_t i = 0; i < num_vertices->size(); ++i) { + const int num_verts = (*num_vertices)[i]; + + Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb")); + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + nu->pntsu = num_verts; + nu->pntsv = 1; + nu->flag |= CU_SMOOTH; + + switch (smp.getType()) { + case Alembic::AbcGeom::kCubic: + nu->orderu = 4; + break; + case Alembic::AbcGeom::kVariableOrder: + if (orders && orders->size() > i) { + nu->orderu = static_cast<short>((*orders)[i]); + break; + } + ATTR_FALLTHROUGH; + case Alembic::AbcGeom::kLinear: + default: + nu->orderu = 2; + } + + if (periodicity == Alembic::AbcGeom::kNonPeriodic) { + nu->flagu |= CU_NURB_ENDPOINT; + } + else if (periodicity == Alembic::AbcGeom::kPeriodic) { + nu->flagu |= CU_NURB_CYCLIC; + + /* Check the number of points which overlap, we don't have + * overlapping points in Blender, but other software do use them to + * indicate that a curve is actually cyclic. Usually the number of + * overlapping points is equal to the order/degree of the curve. + */ + + const int start = idx; + const int end = idx + num_verts; + int overlap = 0; + + for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) { + const Imath::V3f &p1 = (*positions)[j]; + const Imath::V3f &p2 = (*positions)[k]; + + if (p1 != p2) { + break; + } + + ++overlap; + } + + /* TODO: Special case, need to figure out how it coincides with knots. */ + if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) { + overlap = 1; + } + + /* There is no real cycles. */ + if (overlap == 0) { + nu->flagu &= ~CU_NURB_CYCLIC; + nu->flagu |= CU_NURB_ENDPOINT; + } + + nu->pntsu -= overlap; + } + + const bool do_weights = (weights != NULL) && (weights->size() > 1); + float weight = 1.0f; + + const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1); + float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f; + + nu->type = CU_NURBS; + + nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb")); + BPoint *bp = nu->bp; + + for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) { + const Imath::V3f &pos = (*positions)[idx]; + + if (do_radius) { + radius = (*radiuses)[idx]; + } + + if (do_weights) { + weight = (*weights)[idx]; + } + + copy_zup_from_yup(bp->vec, pos.getValue()); + bp->vec[3] = weight; + bp->f1 = SELECT; + bp->radius = radius; + bp->weight = 1.0f; + } + + if (knots && knots->size() != 0) { + nu->knotsu = static_cast<float *>( + MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu")); + + /* TODO: second check is temporary, for until the check for cycles is rock solid. */ + if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) { + /* Skip first and last knots. */ + for (size_t i = 1; i < knots->size() - 1; ++i) { + nu->knotsu[i - 1] = (*knots)[knot_offset + i]; + } + } + else { + /* TODO: figure out how to use the knots array from other + * software in this case. */ + BKE_nurb_knot_calc_u(nu); + } + + knot_offset += knots->size(); + } + else { + BKE_nurb_knot_calc_u(nu); + } + + BLI_addtail(BKE_curve_nurbs_get(cu), nu); + } } /* NOTE: Alembic only stores data about control points, but the Mesh @@ -441,71 +449,71 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh, int /*read_flag*/, const char **err_str) { - ICurvesSchema::Sample sample; - - try { - sample = m_curves_schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - *err_str = "Error reading curve sample; more detail on the console"; - printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - m_curves_schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return existing_mesh; - } - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); - - int vertex_idx = 0; - int curve_idx; - Curve *curve = static_cast<Curve *>(m_object->data); - - const int curve_count = BLI_listbase_count(&curve->nurb); - bool same_topology = curve_count == num_vertices->size(); - - if (same_topology) { - Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); - for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) { - const int num_in_alembic = (*num_vertices)[curve_idx]; - const int num_in_blender = nurbs->pntsu; - - if (num_in_alembic != num_in_blender) { - same_topology = false; - break; - } - } - } - - if (!same_topology) { - BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, m_curves_schema, sample_sel); - } - else { - Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); - for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) { - const int totpoint = (*num_vertices)[curve_idx]; - - if (nurbs->bp) { - BPoint *point = nurbs->bp; - - for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_zup_from_yup(point->vec, pos.getValue()); - } - } - else if (nurbs->bezt) { - BezTriple *bezier = nurbs->bezt; - - for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_zup_from_yup(bezier->vec[1], pos.getValue()); - } - } - } - } - - return BKE_mesh_new_nomain_from_curve(m_object); + ICurvesSchema::Sample sample; + + try { + sample = m_curves_schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + *err_str = "Error reading curve sample; more detail on the console"; + printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_curves_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); + + int vertex_idx = 0; + int curve_idx; + Curve *curve = static_cast<Curve *>(m_object->data); + + const int curve_count = BLI_listbase_count(&curve->nurb); + bool same_topology = curve_count == num_vertices->size(); + + if (same_topology) { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) { + const int num_in_alembic = (*num_vertices)[curve_idx]; + const int num_in_blender = nurbs->pntsu; + + if (num_in_alembic != num_in_blender) { + same_topology = false; + break; + } + } + } + + if (!same_topology) { + BKE_nurbList_free(&curve->nurb); + read_curve_sample(curve, m_curves_schema, sample_sel); + } + else { + Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); + for (curve_idx = 0; nurbs; nurbs = nurbs->next, ++curve_idx) { + const int totpoint = (*num_vertices)[curve_idx]; + + if (nurbs->bp) { + BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_zup_from_yup(point->vec, pos.getValue()); + } + } + else if (nurbs->bezt) { + BezTriple *bezier = nurbs->bezt; + + for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_zup_from_yup(bezier->vec[1], pos.getValue()); + } + } + } + } + + return BKE_mesh_new_nomain_from_curve(m_object); } diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index e03feceed64..6636558356f 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -32,55 +32,54 @@ struct Curve; /* ************************************************************************** */ class AbcCurveWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; + Alembic::AbcGeom::OCurvesSchema m_schema; + Alembic::AbcGeom::OCurvesSchema::Sample m_sample; -public: - AbcCurveWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + public: + AbcCurveWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); -protected: - void do_write(); + protected: + void do_write(); }; class AbcCurveMeshWriter : public AbcGenericMeshWriter { -public: - AbcCurveMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - -protected: - Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree); + public: + AbcCurveMeshWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); + + protected: + Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree); }; /* ************************************************************************** */ class AbcCurveReader : public AbcObjectReader { - Alembic::AbcGeom::ICurvesSchema m_curves_schema; + Alembic::AbcGeom::ICurvesSchema m_curves_schema; -public: - AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + public: + AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - bool valid() const; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const; + bool valid() const; + bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - struct Mesh *read_mesh(struct Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); - - void read_curve_sample(Curve *cu, - const Alembic::AbcGeom::ICurvesSchema &schema, - const Alembic::Abc::ISampleSelector &sample_selector); + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); + void read_curve_sample(Curve *cu, + const Alembic::AbcGeom::ICurvesSchema &schema, + const Alembic::Abc::ISampleSelector &sample_selector); }; /* ************************************************************************** */ -#endif /* __ABC_CURVES_H__ */ +#endif /* __ABC_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index 1587f333e3d..20ca659d32f 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -41,101 +41,101 @@ extern "C" { * such data in a way that lets other DCC know what they are for. See comments * in the write code for the conventions. */ -using Alembic::AbcGeom::kVertexScope; using Alembic::AbcGeom::kFacevaryingScope; +using Alembic::AbcGeom::kVertexScope; using Alembic::Abc::C4fArraySample; using Alembic::Abc::UInt32ArraySample; using Alembic::Abc::V2fArraySample; -using Alembic::AbcGeom::OV2fGeomParam; using Alembic::AbcGeom::OC4fGeomParam; +using Alembic::AbcGeom::OV2fGeomParam; static void get_uvs(const CDStreamConfig &config, std::vector<Imath::V2f> &uvs, std::vector<uint32_t> &uvidx, void *cd_data) { - MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data); - - if (!mloopuv_array) { - return; - } - - const int num_poly = config.totpoly; - MPoly *polygons = config.mpoly; - MLoop *mloop = config.mloop; - - if (!config.pack_uvs) { - int cnt = 0; - uvidx.resize(config.totloop); - uvs.resize(config.totloop); - - /* Iterate in reverse order to match exported polygons. */ - for (int i = 0; i < num_poly; ++i) { - MPoly ¤t_poly = polygons[i]; - MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop; - - for (int j = 0; j < current_poly.totloop; ++j, ++cnt) { - --loopuv; - - uvidx[cnt] = cnt; - uvs[cnt][0] = loopuv->uv[0]; - uvs[cnt][1] = loopuv->uv[1]; - } - } - } - else { - /* Mapping for indexed UVs, deduplicating UV coordinates at vertices. */ - std::vector<std::vector<uint32_t>> idx_map(config.totvert); - int idx_count = 0; - - for (int i = 0; i < num_poly; ++i) { - MPoly ¤t_poly = polygons[i]; - MLoop *looppoly = mloop + current_poly.loopstart + current_poly.totloop; - MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop; - - for (int j = 0; j < current_poly.totloop; ++j) { - --looppoly; - --loopuv; - - Imath::V2f uv(loopuv->uv[0], loopuv->uv[1]); - bool found_same = false; - - /* Find UV already in uvs array. */ - for (uint32_t uv_idx : idx_map[looppoly->v]) { - if (uvs[uv_idx] == uv) { - found_same = true; - uvidx.push_back(uv_idx); - break; - } - } - - /* UV doesn't exists for this vertex, add it. */ - if (!found_same) { - uint32_t uv_idx = idx_count++; - idx_map[looppoly->v].push_back(uv_idx); - uvidx.push_back(uv_idx); - uvs.push_back(uv); - } - } - } - } + MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data); + + if (!mloopuv_array) { + return; + } + + const int num_poly = config.totpoly; + MPoly *polygons = config.mpoly; + MLoop *mloop = config.mloop; + + if (!config.pack_uvs) { + int cnt = 0; + uvidx.resize(config.totloop); + uvs.resize(config.totloop); + + /* Iterate in reverse order to match exported polygons. */ + for (int i = 0; i < num_poly; ++i) { + MPoly ¤t_poly = polygons[i]; + MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop; + + for (int j = 0; j < current_poly.totloop; ++j, ++cnt) { + --loopuv; + + uvidx[cnt] = cnt; + uvs[cnt][0] = loopuv->uv[0]; + uvs[cnt][1] = loopuv->uv[1]; + } + } + } + else { + /* Mapping for indexed UVs, deduplicating UV coordinates at vertices. */ + std::vector<std::vector<uint32_t>> idx_map(config.totvert); + int idx_count = 0; + + for (int i = 0; i < num_poly; ++i) { + MPoly ¤t_poly = polygons[i]; + MLoop *looppoly = mloop + current_poly.loopstart + current_poly.totloop; + MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop; + + for (int j = 0; j < current_poly.totloop; ++j) { + --looppoly; + --loopuv; + + Imath::V2f uv(loopuv->uv[0], loopuv->uv[1]); + bool found_same = false; + + /* Find UV already in uvs array. */ + for (uint32_t uv_idx : idx_map[looppoly->v]) { + if (uvs[uv_idx] == uv) { + found_same = true; + uvidx.push_back(uv_idx); + break; + } + } + + /* UV doesn't exists for this vertex, add it. */ + if (!found_same) { + uint32_t uv_idx = idx_count++; + idx_map[looppoly->v].push_back(uv_idx); + uvidx.push_back(uv_idx); + uvs.push_back(uv); + } + } + } + } } const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data) { - const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV); + const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV); - if (active_uvlayer < 0) { - return ""; - } + if (active_uvlayer < 0) { + return ""; + } - void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer); + void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer); - get_uvs(config, sample.uvs, sample.indices, cd_data); + get_uvs(config, sample.uvs, sample.indices, cd_data); - return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer); + return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer); } /* Convention to write UVs: @@ -143,102 +143,109 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom * - set scope as face varying * - (optional due to its behavior) tag as UV using Alembic::AbcGeom::SetIsUV */ -static void write_uv(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name) +static void write_uv(const OCompoundProperty &prop, + const CDStreamConfig &config, + void *data, + const char *name) { - std::vector<uint32_t> indices; - std::vector<Imath::V2f> uvs; + std::vector<uint32_t> indices; + std::vector<Imath::V2f> uvs; - get_uvs(config, uvs, indices, data); + get_uvs(config, uvs, indices, data); - if (indices.empty() || uvs.empty()) { - return; - } + if (indices.empty() || uvs.empty()) { + return; + } - OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1); + OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1); - OV2fGeomParam::Sample sample( - V2fArraySample(&uvs.front(), uvs.size()), - UInt32ArraySample(&indices.front(), indices.size()), - kFacevaryingScope); + OV2fGeomParam::Sample sample(V2fArraySample(&uvs.front(), uvs.size()), + UInt32ArraySample(&indices.front(), indices.size()), + kFacevaryingScope); - param.set(sample); + param.set(sample); } /* Convention to write Vertex Colors: * - C3fGeomParam/C4fGeomParam on the arbGeomParam * - set scope as vertex varying */ -static void write_mcol(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name) +static void write_mcol(const OCompoundProperty &prop, + const CDStreamConfig &config, + void *data, + const char *name) { - const float cscale = 1.0f / 255.0f; - MPoly *polys = config.mpoly; - MLoop *mloops = config.mloop; - MCol *cfaces = static_cast<MCol *>(data); + const float cscale = 1.0f / 255.0f; + MPoly *polys = config.mpoly; + MLoop *mloops = config.mloop; + MCol *cfaces = static_cast<MCol *>(data); - std::vector<Imath::C4f> buffer; - std::vector<uint32_t> indices; + std::vector<Imath::C4f> buffer; + std::vector<uint32_t> indices; - buffer.reserve(config.totvert); - indices.reserve(config.totvert); + buffer.reserve(config.totvert); + indices.reserve(config.totvert); - Imath::C4f col; + Imath::C4f col; - for (int i = 0; i < config.totpoly; ++i) { - MPoly *p = &polys[i]; - MCol *cface = &cfaces[p->loopstart + p->totloop]; - MLoop *mloop = &mloops[p->loopstart + p->totloop]; + for (int i = 0; i < config.totpoly; ++i) { + MPoly *p = &polys[i]; + MCol *cface = &cfaces[p->loopstart + p->totloop]; + MLoop *mloop = &mloops[p->loopstart + p->totloop]; - for (int j = 0; j < p->totloop; ++j) { - cface--; - mloop--; + for (int j = 0; j < p->totloop; ++j) { + cface--; + mloop--; - col[0] = cface->a * cscale; - col[1] = cface->r * cscale; - col[2] = cface->g * cscale; - col[3] = cface->b * cscale; + col[0] = cface->a * cscale; + col[1] = cface->r * cscale; + col[2] = cface->g * cscale; + col[3] = cface->b * cscale; - buffer.push_back(col); - indices.push_back(buffer.size() - 1); - } - } + buffer.push_back(col); + indices.push_back(buffer.size() - 1); + } + } - OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1); + OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1); - OC4fGeomParam::Sample sample( - C4fArraySample(&buffer.front(), buffer.size()), - UInt32ArraySample(&indices.front(), indices.size()), - kVertexScope); + OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()), + UInt32ArraySample(&indices.front(), indices.size()), + kVertexScope); - param.set(sample); + param.set(sample); } -void write_custom_data(const OCompoundProperty &prop, const CDStreamConfig &config, CustomData *data, int data_type) +void write_custom_data(const OCompoundProperty &prop, + const CDStreamConfig &config, + CustomData *data, + int data_type) { - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); - - if (!CustomData_has_layer(data, cd_data_type)) { - return; - } - - const int active_layer = CustomData_get_active_layer(data, cd_data_type); - const int tot_layers = CustomData_number_of_layers(data, cd_data_type); - - for (int i = 0; i < tot_layers; ++i) { - void *cd_data = CustomData_get_layer_n(data, cd_data_type, i); - const char *name = CustomData_get_layer_name(data, cd_data_type, i); - - if (cd_data_type == CD_MLOOPUV) { - /* Already exported. */ - if (i == active_layer) { - continue; - } - - write_uv(prop, config, cd_data, name); - } - else if (cd_data_type == CD_MLOOPCOL) { - write_mcol(prop, config, cd_data, name); - } - } + CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + + if (!CustomData_has_layer(data, cd_data_type)) { + return; + } + + const int active_layer = CustomData_get_active_layer(data, cd_data_type); + const int tot_layers = CustomData_number_of_layers(data, cd_data_type); + + for (int i = 0; i < tot_layers; ++i) { + void *cd_data = CustomData_get_layer_n(data, cd_data_type, i); + const char *name = CustomData_get_layer_name(data, cd_data_type, i); + + if (cd_data_type == CD_MLOOPUV) { + /* Already exported. */ + if (i == active_layer) { + continue; + } + + write_uv(prop, config, cd_data, name); + } + else if (cd_data_type == CD_MLOOPCOL) { + write_mcol(prop, config, cd_data, name); + } + } } /* ************************************************************************** */ @@ -251,167 +258,165 @@ using Alembic::AbcGeom::IC3fGeomParam; using Alembic::AbcGeom::IC4fGeomParam; using Alembic::AbcGeom::IV2fGeomParam; - -static void read_uvs(const CDStreamConfig &config, void *data, +static void read_uvs(const CDStreamConfig &config, + void *data, const Alembic::AbcGeom::V2fArraySamplePtr &uvs, const Alembic::AbcGeom::UInt32ArraySamplePtr &indices) { - MPoly *mpolys = config.mpoly; - MLoopUV *mloopuvs = static_cast<MLoopUV *>(data); - - unsigned int uv_index, loop_index, rev_loop_index; - - for (int i = 0; i < config.totpoly; ++i) { - MPoly &poly = mpolys[i]; - unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1; - - for (int f = 0; f < poly.totloop; ++f) { - loop_index = poly.loopstart + f; - rev_loop_index = rev_loop_offset - f; - uv_index = (*indices)[loop_index]; - const Imath::V2f &uv = (*uvs)[uv_index]; - - MLoopUV &loopuv = mloopuvs[rev_loop_index]; - loopuv.uv[0] = uv[0]; - loopuv.uv[1] = uv[1]; - } - } + MPoly *mpolys = config.mpoly; + MLoopUV *mloopuvs = static_cast<MLoopUV *>(data); + + unsigned int uv_index, loop_index, rev_loop_index; + + for (int i = 0; i < config.totpoly; ++i) { + MPoly &poly = mpolys[i]; + unsigned int rev_loop_offset = poly.loopstart + poly.totloop - 1; + + for (int f = 0; f < poly.totloop; ++f) { + loop_index = poly.loopstart + f; + rev_loop_index = rev_loop_offset - f; + uv_index = (*indices)[loop_index]; + const Imath::V2f &uv = (*uvs)[uv_index]; + + MLoopUV &loopuv = mloopuvs[rev_loop_index]; + loopuv.uv[0] = uv[0]; + loopuv.uv[1] = uv[1]; + } + } } -static size_t mcols_out_of_bounds_check( - const size_t color_index, - const size_t array_size, - const std::string & iobject_full_name, - const PropertyHeader &prop_header, - bool &r_is_out_of_bounds, - bool &r_bounds_warning_given) +static size_t mcols_out_of_bounds_check(const size_t color_index, + const size_t array_size, + const std::string &iobject_full_name, + const PropertyHeader &prop_header, + bool &r_is_out_of_bounds, + bool &r_bounds_warning_given) { - if (color_index < array_size) { - return color_index; - } - - if (!r_bounds_warning_given) { - std::cerr << "Alembic: color index out of bounds " - "reading face colors for object " - << iobject_full_name - << ", property " - << prop_header.getName() << std::endl; - r_bounds_warning_given = true; - } - r_is_out_of_bounds = true; - return 0; + if (color_index < array_size) { + return color_index; + } + + if (!r_bounds_warning_given) { + std::cerr << "Alembic: color index out of bounds " + "reading face colors for object " + << iobject_full_name << ", property " << prop_header.getName() << std::endl; + r_bounds_warning_given = true; + } + r_is_out_of_bounds = true; + return 0; } -static void read_custom_data_mcols(const std::string & iobject_full_name, +static void read_custom_data_mcols(const std::string &iobject_full_name, const ICompoundProperty &arbGeomParams, const PropertyHeader &prop_header, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) { - C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr(); - C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr(); - Alembic::Abc::UInt32ArraySamplePtr indices; - bool use_c3f_ptr; - bool is_facevarying; - - /* Find the correct interpretation of the data */ - if (IC3fGeomParam::matches(prop_header)) { - IC3fGeomParam color_param(arbGeomParams, prop_header.getName()); - IC3fGeomParam::Sample sample; - BLI_assert(!strcmp("rgb", color_param.getInterpretation())); - - color_param.getIndexed(sample, iss); - is_facevarying = sample.getScope() == kFacevaryingScope && - config.totloop == sample.getIndices()->size(); - - c3f_ptr = sample.getVals(); - indices = sample.getIndices(); - use_c3f_ptr = true; - } - else if (IC4fGeomParam::matches(prop_header)) { - IC4fGeomParam color_param(arbGeomParams, prop_header.getName()); - IC4fGeomParam::Sample sample; - BLI_assert(!strcmp("rgba", color_param.getInterpretation())); - - color_param.getIndexed(sample, iss); - is_facevarying = sample.getScope() == kFacevaryingScope && - config.totloop == sample.getIndices()->size(); - - c4f_ptr = sample.getVals(); - indices = sample.getIndices(); - use_c3f_ptr = false; - } - else { - /* this won't happen due to the checks in read_custom_data() */ - return; - } - BLI_assert(c3f_ptr || c4f_ptr); - - /* Read the vertex colors */ - void *cd_data = config.add_customdata_cb(config.user_data, - prop_header.getName().c_str(), - CD_MLOOPCOL); - MCol *cfaces = static_cast<MCol *>(cd_data); - MPoly *mpolys = config.mpoly; - MLoop *mloops = config.mloop; - - size_t face_index = 0; - size_t color_index; - bool bounds_warning_given = false; - - /* The colors can go through two layers of indexing. Often the 'indices' - * array doesn't do anything (i.e. indices[n] = n), but when it does, it's - * important. Blender 2.79 writes indices incorrectly (see T53745), which - * is why we have to check for indices->size() > 0 */ - bool use_dual_indexing = is_facevarying && indices->size() > 0; - - for (int i = 0; i < config.totpoly; ++i) { - MPoly *poly = &mpolys[i]; - MCol *cface = &cfaces[poly->loopstart + poly->totloop]; - MLoop *mloop = &mloops[poly->loopstart + poly->totloop]; - - for (int j = 0; j < poly->totloop; ++j, ++face_index) { - --cface; - --mloop; - - color_index = is_facevarying ? face_index : mloop->v; - if (use_dual_indexing) { - color_index = (*indices)[color_index]; - } - if (use_c3f_ptr) { - bool is_mcols_out_of_bounds = false; - color_index = mcols_out_of_bounds_check( - color_index, - c3f_ptr->size(), - iobject_full_name, prop_header, - is_mcols_out_of_bounds, bounds_warning_given); - if (is_mcols_out_of_bounds) { - continue; - } - const Imath::C3f &color = (*c3f_ptr)[color_index]; - cface->a = unit_float_to_uchar_clamp(color[0]); - cface->r = unit_float_to_uchar_clamp(color[1]); - cface->g = unit_float_to_uchar_clamp(color[2]); - cface->b = 255; - } - else { - bool is_mcols_out_of_bounds = false; - color_index = mcols_out_of_bounds_check( - color_index, - c4f_ptr->size(), - iobject_full_name, prop_header, - is_mcols_out_of_bounds, bounds_warning_given); - if (is_mcols_out_of_bounds) { - continue; - } - const Imath::C4f &color = (*c4f_ptr)[color_index]; - cface->a = unit_float_to_uchar_clamp(color[0]); - cface->r = unit_float_to_uchar_clamp(color[1]); - cface->g = unit_float_to_uchar_clamp(color[2]); - cface->b = unit_float_to_uchar_clamp(color[3]); - } - } - } + C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr(); + C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr(); + Alembic::Abc::UInt32ArraySamplePtr indices; + bool use_c3f_ptr; + bool is_facevarying; + + /* Find the correct interpretation of the data */ + if (IC3fGeomParam::matches(prop_header)) { + IC3fGeomParam color_param(arbGeomParams, prop_header.getName()); + IC3fGeomParam::Sample sample; + BLI_assert(!strcmp("rgb", color_param.getInterpretation())); + + color_param.getIndexed(sample, iss); + is_facevarying = sample.getScope() == kFacevaryingScope && + config.totloop == sample.getIndices()->size(); + + c3f_ptr = sample.getVals(); + indices = sample.getIndices(); + use_c3f_ptr = true; + } + else if (IC4fGeomParam::matches(prop_header)) { + IC4fGeomParam color_param(arbGeomParams, prop_header.getName()); + IC4fGeomParam::Sample sample; + BLI_assert(!strcmp("rgba", color_param.getInterpretation())); + + color_param.getIndexed(sample, iss); + is_facevarying = sample.getScope() == kFacevaryingScope && + config.totloop == sample.getIndices()->size(); + + c4f_ptr = sample.getVals(); + indices = sample.getIndices(); + use_c3f_ptr = false; + } + else { + /* this won't happen due to the checks in read_custom_data() */ + return; + } + BLI_assert(c3f_ptr || c4f_ptr); + + /* Read the vertex colors */ + void *cd_data = config.add_customdata_cb( + config.user_data, prop_header.getName().c_str(), CD_MLOOPCOL); + MCol *cfaces = static_cast<MCol *>(cd_data); + MPoly *mpolys = config.mpoly; + MLoop *mloops = config.mloop; + + size_t face_index = 0; + size_t color_index; + bool bounds_warning_given = false; + + /* The colors can go through two layers of indexing. Often the 'indices' + * array doesn't do anything (i.e. indices[n] = n), but when it does, it's + * important. Blender 2.79 writes indices incorrectly (see T53745), which + * is why we have to check for indices->size() > 0 */ + bool use_dual_indexing = is_facevarying && indices->size() > 0; + + for (int i = 0; i < config.totpoly; ++i) { + MPoly *poly = &mpolys[i]; + MCol *cface = &cfaces[poly->loopstart + poly->totloop]; + MLoop *mloop = &mloops[poly->loopstart + poly->totloop]; + + for (int j = 0; j < poly->totloop; ++j, ++face_index) { + --cface; + --mloop; + + color_index = is_facevarying ? face_index : mloop->v; + if (use_dual_indexing) { + color_index = (*indices)[color_index]; + } + if (use_c3f_ptr) { + bool is_mcols_out_of_bounds = false; + color_index = mcols_out_of_bounds_check(color_index, + c3f_ptr->size(), + iobject_full_name, + prop_header, + is_mcols_out_of_bounds, + bounds_warning_given); + if (is_mcols_out_of_bounds) { + continue; + } + const Imath::C3f &color = (*c3f_ptr)[color_index]; + cface->a = unit_float_to_uchar_clamp(color[0]); + cface->r = unit_float_to_uchar_clamp(color[1]); + cface->g = unit_float_to_uchar_clamp(color[2]); + cface->b = 255; + } + else { + bool is_mcols_out_of_bounds = false; + color_index = mcols_out_of_bounds_check(color_index, + c4f_ptr->size(), + iobject_full_name, + prop_header, + is_mcols_out_of_bounds, + bounds_warning_given); + if (is_mcols_out_of_bounds) { + continue; + } + const Imath::C4f &color = (*c4f_ptr)[color_index]; + cface->a = unit_float_to_uchar_clamp(color[0]); + cface->r = unit_float_to_uchar_clamp(color[1]); + cface->g = unit_float_to_uchar_clamp(color[2]); + cface->b = unit_float_to_uchar_clamp(color[3]); + } + } + } } static void read_custom_data_uvs(const ICompoundProperty &prop, @@ -419,61 +424,60 @@ static void read_custom_data_uvs(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) { - IV2fGeomParam uv_param(prop, prop_header.getName()); + IV2fGeomParam uv_param(prop, prop_header.getName()); - if (!uv_param.isIndexed()) { - return; - } + if (!uv_param.isIndexed()) { + return; + } - IV2fGeomParam::Sample sample; - uv_param.getIndexed(sample, iss); + IV2fGeomParam::Sample sample; + uv_param.getIndexed(sample, iss); - if (uv_param.getScope() != kFacevaryingScope) { - return; - } + if (uv_param.getScope() != kFacevaryingScope) { + return; + } - void *cd_data = config.add_customdata_cb(config.user_data, - prop_header.getName().c_str(), - CD_MLOOPUV); + void *cd_data = config.add_customdata_cb( + config.user_data, prop_header.getName().c_str(), CD_MLOOPUV); - read_uvs(config, cd_data, sample.getVals(), sample.getIndices()); + read_uvs(config, cd_data, sample.getVals(), sample.getIndices()); } -void read_custom_data(const std::string & iobject_full_name, +void read_custom_data(const std::string &iobject_full_name, const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss) { - if (!prop.valid()) { - return; - } - - int num_uvs = 0; - int num_colors = 0; - - const size_t num_props = prop.getNumProperties(); - - for (size_t i = 0; i < num_props; ++i) { - const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i); - - /* Read UVs according to convention. */ - if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) { - if (++num_uvs > MAX_MTFACE) { - continue; - } - - read_custom_data_uvs(prop, prop_header, config, iss); - continue; - } - - /* Read vertex colors according to convention. */ - if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) { - if (++num_colors > MAX_MCOL) { - continue; - } - - read_custom_data_mcols(iobject_full_name, prop, prop_header, config, iss); - continue; - } - } + if (!prop.valid()) { + return; + } + + int num_uvs = 0; + int num_colors = 0; + + const size_t num_props = prop.getNumProperties(); + + for (size_t i = 0; i < num_props; ++i) { + const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i); + + /* Read UVs according to convention. */ + if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) { + if (++num_uvs > MAX_MTFACE) { + continue; + } + + read_custom_data_uvs(prop, prop_header, config, iss); + continue; + } + + /* Read vertex colors according to convention. */ + if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) { + if (++num_colors > MAX_MCOL) { + continue; + } + + read_custom_data_mcols(iobject_full_name, prop, prop_header, config, iss); + continue; + } + } } diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h index 88520b47a55..c36029d5116 100644 --- a/source/blender/alembic/intern/abc_customdata.h +++ b/source/blender/alembic/intern/abc_customdata.h @@ -37,51 +37,52 @@ using Alembic::Abc::ICompoundProperty; using Alembic::Abc::OCompoundProperty; struct UVSample { - std::vector<Imath::V2f> uvs; - std::vector<uint32_t> indices; + std::vector<Imath::V2f> uvs; + std::vector<uint32_t> indices; }; struct CDStreamConfig { - MLoop *mloop; - int totloop; - - MPoly *mpoly; - int totpoly; - - MVert *mvert; - int totvert; - - MLoopUV *mloopuv; - - CustomData *loopdata; - - bool pack_uvs; - - /* TODO(kevin): might need a better way to handle adding and/or updating - * custom datas such that it updates the custom data holder and its pointers - * properly. */ - void *user_data; - void *(*add_customdata_cb)(void *user_data, const char *name, int data_type); - - float weight; - float time; - Alembic::AbcGeom::index_t index; - Alembic::AbcGeom::index_t ceil_index; - - CDStreamConfig() - : mloop(NULL) - , totloop(0) - , mpoly(NULL) - , totpoly(0) - , totvert(0) - , pack_uvs(false) - , user_data(NULL) - , add_customdata_cb(NULL) - , weight(0.0f) - , time(0.0f) - , index(0) - , ceil_index(0) - {} + MLoop *mloop; + int totloop; + + MPoly *mpoly; + int totpoly; + + MVert *mvert; + int totvert; + + MLoopUV *mloopuv; + + CustomData *loopdata; + + bool pack_uvs; + + /* TODO(kevin): might need a better way to handle adding and/or updating + * custom datas such that it updates the custom data holder and its pointers + * properly. */ + void *user_data; + void *(*add_customdata_cb)(void *user_data, const char *name, int data_type); + + float weight; + float time; + Alembic::AbcGeom::index_t index; + Alembic::AbcGeom::index_t ceil_index; + + CDStreamConfig() + : mloop(NULL), + totloop(0), + mpoly(NULL), + totpoly(0), + totvert(0), + pack_uvs(false), + user_data(NULL), + add_customdata_cb(NULL), + weight(0.0f), + time(0.0f), + index(0), + ceil_index(0) + { + } }; /* Get the UVs for the main UV property on a OSchema. @@ -95,9 +96,9 @@ void write_custom_data(const OCompoundProperty &prop, CustomData *data, int data_type); -void read_custom_data(const std::string & iobject_full_name, +void read_custom_data(const std::string &iobject_full_name, const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss); -#endif /* __ABC_CUSTOMDATA_H__ */ +#endif /* __ABC_CUSTOMDATA_H__ */ diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index f37dbab3b57..4a7f26d2e18 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -41,7 +41,7 @@ extern "C" { #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_space_types.h" /* for FILE_MAX */ +#include "DNA_space_types.h" /* for FILE_MAX */ #include "BLI_string.h" @@ -62,79 +62,79 @@ extern "C" { #include "DEG_depsgraph_query.h" } -using Alembic::Abc::TimeSamplingPtr; using Alembic::Abc::OBox3dProperty; +using Alembic::Abc::TimeSamplingPtr; /* ************************************************************************** */ ExportSettings::ExportSettings() - : scene(NULL) - , view_layer(NULL) - , depsgraph(NULL) - , logger() - , selected_only(false) - , visible_layers_only(false) - , renderable_only(false) - , frame_start(1) - , frame_end(1) - , frame_samples_xform(1) - , frame_samples_shape(1) - , shutter_open(0.0) - , shutter_close(1.0) - , global_scale(1.0f) - , flatten_hierarchy(false) - , export_normals(false) - , export_uvs(false) - , export_vcols(false) - , export_face_sets(false) - , export_vweigths(false) - , export_hair(true) - , export_particles(true) - , apply_subdiv(false) - , use_subdiv_schema(false) - , export_child_hairs(true) - , export_ogawa(true) - , pack_uv(false) - , triangulate(false) - , quad_method(0) - , ngon_method(0) - , do_convert_axis(false) -{} + : scene(NULL), + view_layer(NULL), + depsgraph(NULL), + logger(), + selected_only(false), + visible_layers_only(false), + renderable_only(false), + frame_start(1), + frame_end(1), + frame_samples_xform(1), + frame_samples_shape(1), + shutter_open(0.0), + shutter_close(1.0), + global_scale(1.0f), + flatten_hierarchy(false), + export_normals(false), + export_uvs(false), + export_vcols(false), + export_face_sets(false), + export_vweigths(false), + export_hair(true), + export_particles(true), + apply_subdiv(false), + use_subdiv_schema(false), + export_child_hairs(true), + export_ogawa(true), + pack_uv(false), + triangulate(false), + quad_method(0), + ngon_method(0), + do_convert_axis(false) +{ +} static bool object_is_smoke_sim(Object *ob) { - ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke); + ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke); - if (md) { - SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md); - return (smd->type == MOD_SMOKE_TYPE_DOMAIN); - } + if (md) { + SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md); + return (smd->type == MOD_SMOKE_TYPE_DOMAIN); + } - return false; + return false; } static bool object_type_is_exportable(Scene *scene, Object *ob) { - switch (ob->type) { - case OB_MESH: - if (object_is_smoke_sim(ob)) { - return false; - } - - return true; - case OB_EMPTY: - case OB_CURVE: - case OB_SURF: - case OB_CAMERA: - return true; - case OB_MBALL: - return AbcMBallWriter::isBasisBall(scene, ob); - default: - return false; - } + switch (ob->type) { + case OB_MESH: + if (object_is_smoke_sim(ob)) { + return false; + } + + return true; + case OB_EMPTY: + case OB_CURVE: + case OB_SURF: + case OB_CAMERA: + return true; + case OB_MBALL: + return AbcMBallWriter::isBasisBall(scene, ob); + default: + return false; + } } - /** * Returns whether this object should be exported into the Alembic file. * @@ -145,518 +145,521 @@ static bool object_type_is_exportable(Scene *scene, Object *ob) * This ignores selection and layer visibility, * and assumes that the dupli-object itself (e.g. the group-instantiating empty) is exported. */ -static bool export_object(const ExportSettings * const settings, const Base * const base, +static bool export_object(const ExportSettings *const settings, + const Base *const base, bool is_duplicated) { - if (!is_duplicated) { - View3D *v3d = NULL; - - /* These two tests only make sense when the object isn't being instanced - * into the scene. When it is, its exportability is determined by - * its dupli-object and the DupliObject::no_draw property. */ - if (settings->selected_only && !BASE_SELECTED(v3d, base)) { - return false; - } - // FIXME Sybren: handle these cleanly (maybe just remove code), now using active scene layer instead. - if (settings->visible_layers_only && !BASE_VISIBLE(v3d, base)) { - return false; - } - } - - // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { - // return false; - // } - - return true; + if (!is_duplicated) { + View3D *v3d = NULL; + + /* These two tests only make sense when the object isn't being instanced + * into the scene. When it is, its exportability is determined by + * its dupli-object and the DupliObject::no_draw property. */ + if (settings->selected_only && !BASE_SELECTED(v3d, base)) { + return false; + } + // FIXME Sybren: handle these cleanly (maybe just remove code), now using active scene layer instead. + if (settings->visible_layers_only && !BASE_VISIBLE(v3d, base)) { + return false; + } + } + + // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { + // return false; + // } + + return true; } /* ************************************************************************** */ AbcExporter::AbcExporter(Main *bmain, const char *filename, ExportSettings &settings) - : m_bmain(bmain) - , m_settings(settings) - , m_filename(filename) - , m_trans_sampling_index(0) - , m_shape_sampling_index(0) - , m_writer(NULL) -{} + : m_bmain(bmain), + m_settings(settings), + m_filename(filename), + m_trans_sampling_index(0), + m_shape_sampling_index(0), + m_writer(NULL) +{ +} AbcExporter::~AbcExporter() { - /* Free xforms map */ - m_xforms_type::iterator it_x, e_x; - for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) { - delete it_x->second; - } - - /* Free shapes vector */ - for (int i = 0, e = m_shapes.size(); i != e; ++i) { - delete m_shapes[i]; - } - - delete m_writer; + /* Free xforms map */ + m_xforms_type::iterator it_x, e_x; + for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) { + delete it_x->second; + } + + /* Free shapes vector */ + for (int i = 0, e = m_shapes.size(); i != e; ++i) { + delete m_shapes[i]; + } + + delete m_writer; } void AbcExporter::getShutterSamples(unsigned int nr_of_samples, bool time_relative, std::vector<double> &samples) { - Scene *scene = m_settings.scene; /* for use in the FPS macro */ - samples.clear(); - - unsigned int frame_offset = time_relative ? m_settings.frame_start : 0; - double time_factor = time_relative ? FPS : 1.0; - double shutter_open = m_settings.shutter_open; - double shutter_close = m_settings.shutter_close; - double time_inc = (shutter_close - shutter_open) / nr_of_samples; - - /* sample between shutter open & close */ - for (int sample=0; sample < nr_of_samples; ++sample) { - double sample_time = shutter_open + time_inc * sample; - double time = (frame_offset + sample_time) / time_factor; - - samples.push_back(time); - } + Scene *scene = m_settings.scene; /* for use in the FPS macro */ + samples.clear(); + + unsigned int frame_offset = time_relative ? m_settings.frame_start : 0; + double time_factor = time_relative ? FPS : 1.0; + double shutter_open = m_settings.shutter_open; + double shutter_close = m_settings.shutter_close; + double time_inc = (shutter_close - shutter_open) / nr_of_samples; + + /* sample between shutter open & close */ + for (int sample = 0; sample < nr_of_samples; ++sample) { + double sample_time = shutter_open + time_inc * sample; + double time = (frame_offset + sample_time) / time_factor; + + samples.push_back(time); + } } Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step) { - std::vector<double> samples; + std::vector<double> samples; - if (m_settings.frame_start == m_settings.frame_end) { - return TimeSamplingPtr(new Alembic::Abc::TimeSampling()); - } + if (m_settings.frame_start == m_settings.frame_end) { + return TimeSamplingPtr(new Alembic::Abc::TimeSampling()); + } - getShutterSamples(step, true, samples); + getShutterSamples(step, true, samples); - Alembic::Abc::TimeSamplingType ts( - static_cast<uint32_t>(samples.size()), - 1.0 / m_settings.scene->r.frs_sec); /* TODO(Sybren): shouldn't we use the FPS macro here? */ + Alembic::Abc::TimeSamplingType ts( + static_cast<uint32_t>(samples.size()), + 1.0 / m_settings.scene->r.frs_sec); /* TODO(Sybren): shouldn't we use the FPS macro here? */ - return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); + return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); } -void AbcExporter::getFrameSet(unsigned int nr_of_samples, - std::set<double> &frames) +void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &frames) { - frames.clear(); + frames.clear(); - std::vector<double> shutter_samples; + std::vector<double> shutter_samples; - getShutterSamples(nr_of_samples, false, shutter_samples); + getShutterSamples(nr_of_samples, false, shutter_samples); - for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) { - for (size_t j = 0; j < nr_of_samples; ++j) { - frames.insert(frame + shutter_samples[j]); - } - } + for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) { + for (size_t j = 0; j < nr_of_samples; ++j) { + frames.insert(frame + shutter_samples[j]); + } + } } void AbcExporter::operator()(float &progress, bool &was_canceled) { - std::string scene_name; + std::string scene_name; - if (m_bmain->name[0] != '\0') { - char scene_file_name[FILE_MAX]; - BLI_strncpy(scene_file_name, m_bmain->name, FILE_MAX); - scene_name = scene_file_name; - } - else { - scene_name = "untitled"; - } + if (m_bmain->name[0] != '\0') { + char scene_file_name[FILE_MAX]; + BLI_strncpy(scene_file_name, m_bmain->name, FILE_MAX); + scene_name = scene_file_name; + } + else { + scene_name = "untitled"; + } - Scene *scene = m_settings.scene; - const double fps = FPS; - char buf[16]; - snprintf(buf, 15, "%f", fps); - const std::string str_fps = buf; + Scene *scene = m_settings.scene; + const double fps = FPS; + char buf[16]; + snprintf(buf, 15, "%f", fps); + const std::string str_fps = buf; - Alembic::AbcCoreAbstract::MetaData md; - md.set("FramesPerTimeUnit", str_fps); + Alembic::AbcCoreAbstract::MetaData md; + md.set("FramesPerTimeUnit", str_fps); - m_writer = new ArchiveWriter(m_filename, scene_name.c_str(), m_settings.export_ogawa, md); + m_writer = new ArchiveWriter(m_filename, scene_name.c_str(), m_settings.export_ogawa, md); - /* Create time samplings for transforms and shapes. */ + /* Create time samplings for transforms and shapes. */ - TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform); + TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform); - m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time); + m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time); - TimeSamplingPtr shape_time; + TimeSamplingPtr shape_time; - if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) || - (m_settings.frame_start == m_settings.frame_end)) - { - shape_time = trans_time; - m_shape_sampling_index = m_trans_sampling_index; - } - else { - shape_time = createTimeSampling(m_settings.frame_samples_shape); - m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time); - } + if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) || + (m_settings.frame_start == m_settings.frame_end)) { + shape_time = trans_time; + m_shape_sampling_index = m_trans_sampling_index; + } + else { + shape_time = createTimeSampling(m_settings.frame_samples_shape); + m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time); + } - OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index); + OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds( + m_writer->archive(), m_trans_sampling_index); - createTransformWritersHierarchy(); - createShapeWriters(); + createTransformWritersHierarchy(); + createShapeWriters(); - /* Make a list of frames to export. */ + /* Make a list of frames to export. */ - std::set<double> xform_frames; - getFrameSet(m_settings.frame_samples_xform, xform_frames); + std::set<double> xform_frames; + getFrameSet(m_settings.frame_samples_xform, xform_frames); - std::set<double> shape_frames; - getFrameSet(m_settings.frame_samples_shape, shape_frames); + std::set<double> shape_frames; + getFrameSet(m_settings.frame_samples_shape, shape_frames); - /* Merge all frames needed. */ - std::set<double> frames(xform_frames); - frames.insert(shape_frames.begin(), shape_frames.end()); + /* Merge all frames needed. */ + std::set<double> frames(xform_frames); + frames.insert(shape_frames.begin(), shape_frames.end()); - /* Export all frames. */ + /* Export all frames. */ - std::set<double>::const_iterator begin = frames.begin(); - std::set<double>::const_iterator end = frames.end(); + std::set<double>::const_iterator begin = frames.begin(); + std::set<double>::const_iterator end = frames.end(); - const float size = static_cast<float>(frames.size()); - size_t i = 0; + const float size = static_cast<float>(frames.size()); + size_t i = 0; - for (; begin != end; ++begin) { - progress = (++i / size); + for (; begin != end; ++begin) { + progress = (++i / size); - if (G.is_break) { - was_canceled = true; - break; - } + if (G.is_break) { + was_canceled = true; + break; + } - const double frame = *begin; + const double frame = *begin; - /* 'frame' is offset by start frame, so need to cancel the offset. */ - setCurrentFrame(m_bmain, frame); + /* 'frame' is offset by start frame, so need to cancel the offset. */ + setCurrentFrame(m_bmain, frame); - if (shape_frames.count(frame) != 0) { - for (int i = 0, e = m_shapes.size(); i != e; ++i) { - m_shapes[i]->write(); - } - } + if (shape_frames.count(frame) != 0) { + for (int i = 0, e = m_shapes.size(); i != e; ++i) { + m_shapes[i]->write(); + } + } - if (xform_frames.count(frame) == 0) { - continue; - } + if (xform_frames.count(frame) == 0) { + continue; + } - m_xforms_type::iterator xit, xe; - for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { - xit->second->write(); - } + m_xforms_type::iterator xit, xe; + for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { + xit->second->write(); + } - /* Save the archive 's bounding box. */ - Imath::Box3d bounds; + /* Save the archive 's bounding box. */ + Imath::Box3d bounds; - for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { - Imath::Box3d box = xit->second->bounds(); - bounds.extendBy(box); - } + for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { + Imath::Box3d box = xit->second->bounds(); + bounds.extendBy(box); + } - archive_bounds_prop.set(bounds); - } + archive_bounds_prop.set(bounds); + } } void AbcExporter::createTransformWritersHierarchy() { - for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) { - Object *ob = base->object; - - if (export_object(&m_settings, base, false)) { - switch (ob->type) { - case OB_LAMP: - case OB_LATTICE: - case OB_SPEAKER: - /* We do not export transforms for objects of these classes. */ - break; - default: - exploreTransform(base, ob, ob->parent, NULL); - } - } - } + for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; + base = base->next) { + Object *ob = base->object; + + if (export_object(&m_settings, base, false)) { + switch (ob->type) { + case OB_LAMP: + case OB_LATTICE: + case OB_SPEAKER: + /* We do not export transforms for objects of these classes. */ + break; + default: + exploreTransform(base, ob, ob->parent, NULL); + } + } + } } -void AbcExporter::exploreTransform(Base *base, Object *object, Object *parent, Object *dupliObParent) +void AbcExporter::exploreTransform(Base *base, + Object *object, + Object *parent, + Object *dupliObParent) { - /* If an object isn't exported itself, its duplilist shouldn't be - * exported either. */ - if (!export_object(&m_settings, base, dupliObParent != NULL)) { - return; - } - - Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); - if (object_type_is_exportable(m_settings.scene, ob)) { - createTransformWriter(ob, parent, dupliObParent); - } - - ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); - - if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - Object *dupli_ob = NULL; - Object *dupli_parent = NULL; - - for (; link; link = link->next) { - /* This skips things like custom bone shapes. */ - if (m_settings.renderable_only && link->no_draw) { - continue; - } - - if (link->type == OB_DUPLICOLLECTION) { - dupli_ob = link->ob; - dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; - - exploreTransform(base, dupli_ob, dupli_parent, ob); - } - } - - free_object_duplilist(lb); - } + /* If an object isn't exported itself, its duplilist shouldn't be + * exported either. */ + if (!export_object(&m_settings, base, dupliObParent != NULL)) { + return; + } + + Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); + if (object_type_is_exportable(m_settings.scene, ob)) { + createTransformWriter(ob, parent, dupliObParent); + } + + ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); + + if (lb) { + DupliObject *link = static_cast<DupliObject *>(lb->first); + Object *dupli_ob = NULL; + Object *dupli_parent = NULL; + + for (; link; link = link->next) { + /* This skips things like custom bone shapes. */ + if (m_settings.renderable_only && link->no_draw) { + continue; + } + + if (link->type == OB_DUPLICOLLECTION) { + dupli_ob = link->ob; + dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; + + exploreTransform(base, dupli_ob, dupli_parent, ob); + } + } + + free_object_duplilist(lb); + } } -AbcTransformWriter *AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) +AbcTransformWriter *AbcExporter::createTransformWriter(Object *ob, + Object *parent, + Object *dupliObParent) { - /* An object should not be its own parent, or we'll get infinite loops. */ - BLI_assert(ob != parent); - BLI_assert(ob != dupliObParent); - - std::string name; - if (m_settings.flatten_hierarchy) { - name = get_id_name(ob); - } - else { - name = get_object_dag_path_name(ob, dupliObParent); - } - - /* check if we have already created a transform writer for this object */ - AbcTransformWriter *my_writer = getXForm(name); - if (my_writer != NULL) { - return my_writer; - } - - AbcTransformWriter *parent_writer = NULL; - Alembic::Abc::OObject alembic_parent; - - if (m_settings.flatten_hierarchy || parent == NULL) { - /* Parentless objects still have the "top object" as parent - * in Alembic. */ - alembic_parent = m_writer->archive().getTop(); - } - else { - /* Since there are so many different ways to find parents (as evident - * in the number of conditions below), we can't really look up the - * parent by name. We'll just call createTransformWriter(), which will - * return the parent's AbcTransformWriter pointer. */ - if (parent->parent) { - if (parent == dupliObParent) { - parent_writer = createTransformWriter(parent, parent->parent, NULL); - } - else { - parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); - } - } - else if (parent == dupliObParent) { - if (dupliObParent->parent == NULL) { - parent_writer = createTransformWriter(parent, NULL, NULL); - } - else { - parent_writer = createTransformWriter(parent, dupliObParent->parent, dupliObParent->parent); - } - } - else { - parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); - } - - BLI_assert(parent_writer); - alembic_parent = parent_writer->alembicXform(); - } - - my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer, - m_trans_sampling_index, m_settings); - - /* When flattening, the matrix of the dupliobject has to be added. */ - if (m_settings.flatten_hierarchy && dupliObParent) { - my_writer->m_proxy_from = dupliObParent; - } - - m_xforms[name] = my_writer; - return my_writer; + /* An object should not be its own parent, or we'll get infinite loops. */ + BLI_assert(ob != parent); + BLI_assert(ob != dupliObParent); + + std::string name; + if (m_settings.flatten_hierarchy) { + name = get_id_name(ob); + } + else { + name = get_object_dag_path_name(ob, dupliObParent); + } + + /* check if we have already created a transform writer for this object */ + AbcTransformWriter *my_writer = getXForm(name); + if (my_writer != NULL) { + return my_writer; + } + + AbcTransformWriter *parent_writer = NULL; + Alembic::Abc::OObject alembic_parent; + + if (m_settings.flatten_hierarchy || parent == NULL) { + /* Parentless objects still have the "top object" as parent + * in Alembic. */ + alembic_parent = m_writer->archive().getTop(); + } + else { + /* Since there are so many different ways to find parents (as evident + * in the number of conditions below), we can't really look up the + * parent by name. We'll just call createTransformWriter(), which will + * return the parent's AbcTransformWriter pointer. */ + if (parent->parent) { + if (parent == dupliObParent) { + parent_writer = createTransformWriter(parent, parent->parent, NULL); + } + else { + parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); + } + } + else if (parent == dupliObParent) { + if (dupliObParent->parent == NULL) { + parent_writer = createTransformWriter(parent, NULL, NULL); + } + else { + parent_writer = createTransformWriter( + parent, dupliObParent->parent, dupliObParent->parent); + } + } + else { + parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); + } + + BLI_assert(parent_writer); + alembic_parent = parent_writer->alembicXform(); + } + + my_writer = new AbcTransformWriter( + ob, alembic_parent, parent_writer, m_trans_sampling_index, m_settings); + + /* When flattening, the matrix of the dupliobject has to be added. */ + if (m_settings.flatten_hierarchy && dupliObParent) { + my_writer->m_proxy_from = dupliObParent; + } + + m_xforms[name] = my_writer; + return my_writer; } void AbcExporter::createShapeWriters() { - for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; base = base->next) { - exploreObject(base, base->object, NULL); - } + for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; + base = base->next) { + exploreObject(base, base->object, NULL); + } } void AbcExporter::exploreObject(Base *base, Object *object, Object *dupliObParent) { - /* If an object isn't exported itself, its duplilist shouldn't be - * exported either. */ - if (!export_object(&m_settings, base, dupliObParent != NULL)) { - return; - } - - Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); - createShapeWriter(ob, dupliObParent); - - ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); - - if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - - for (; link; link = link->next) { - /* This skips things like custom bone shapes. */ - if (m_settings.renderable_only && link->no_draw) { - continue; - } - if (link->type == OB_DUPLICOLLECTION) { - exploreObject(base, link->ob, ob); - } - } - - free_object_duplilist(lb); - } + /* If an object isn't exported itself, its duplilist shouldn't be + * exported either. */ + if (!export_object(&m_settings, base, dupliObParent != NULL)) { + return; + } + + Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); + createShapeWriter(ob, dupliObParent); + + ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); + + if (lb) { + DupliObject *link = static_cast<DupliObject *>(lb->first); + + for (; link; link = link->next) { + /* This skips things like custom bone shapes. */ + if (m_settings.renderable_only && link->no_draw) { + continue; + } + if (link->type == OB_DUPLICOLLECTION) { + exploreObject(base, link->ob, ob); + } + } + + free_object_duplilist(lb); + } } void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform) { - if (!m_settings.export_hair && !m_settings.export_particles) { - return; - } - - ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); - - for (; psys; psys = psys->next) { - if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { - continue; - } - - if (m_settings.export_hair && psys->part->type == PART_HAIR) { - m_settings.export_child_hairs = true; - m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); - } - else if (m_settings.export_particles && psys->part->type == PART_EMITTER) { - m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); - } - } + if (!m_settings.export_hair && !m_settings.export_particles) { + return; + } + + ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); + + for (; psys; psys = psys->next) { + if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { + continue; + } + + if (m_settings.export_hair && psys->part->type == PART_HAIR) { + m_settings.export_child_hairs = true; + m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); + } + else if (m_settings.export_particles && psys->part->type == PART_EMITTER) { + m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); + } + } } void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) { - if (!object_type_is_exportable(m_settings.scene, ob)) { - return; - } - - std::string name; - - if (m_settings.flatten_hierarchy) { - name = get_id_name(ob); - } - else { - name = get_object_dag_path_name(ob, dupliObParent); - } - - AbcTransformWriter *xform = getXForm(name); - - if (!xform) { - ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n"; - return; - } - - createParticleSystemsWriters(ob, xform); - - switch (ob->type) { - case OB_MESH: - { - Mesh *me = static_cast<Mesh *>(ob->data); - - if (!me) { - return; - } - - m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings)); - break; - } - case OB_SURF: - { - Curve *cu = static_cast<Curve *>(ob->data); - - if (!cu) { - return; - } - - AbcObjectWriter *writer; - if (m_settings.curves_as_mesh) { - writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); - } - else { - writer = new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings); - } - m_shapes.push_back(writer); - break; - } - case OB_CURVE: - { - Curve *cu = static_cast<Curve *>(ob->data); - - if (!cu) { - return; - } - - AbcObjectWriter *writer; - if (m_settings.curves_as_mesh) { - writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); - } - else { - writer = new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings); - } - m_shapes.push_back(writer); - break; - } - case OB_CAMERA: - { - Camera *cam = static_cast<Camera *>(ob->data); - - if (cam->type == CAM_PERSP) { - m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings)); - } - - break; - } - case OB_MBALL: - { - MetaBall *mball = static_cast<MetaBall *>(ob->data); - if (!mball) { - return; - } - - m_shapes.push_back(new AbcMBallWriter( - m_bmain, ob, xform, - m_shape_sampling_index, m_settings)); - break; - } - } + if (!object_type_is_exportable(m_settings.scene, ob)) { + return; + } + + std::string name; + + if (m_settings.flatten_hierarchy) { + name = get_id_name(ob); + } + else { + name = get_object_dag_path_name(ob, dupliObParent); + } + + AbcTransformWriter *xform = getXForm(name); + + if (!xform) { + ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n"; + return; + } + + createParticleSystemsWriters(ob, xform); + + switch (ob->type) { + case OB_MESH: { + Mesh *me = static_cast<Mesh *>(ob->data); + + if (!me) { + return; + } + + m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings)); + break; + } + case OB_SURF: { + Curve *cu = static_cast<Curve *>(ob->data); + + if (!cu) { + return; + } + + AbcObjectWriter *writer; + if (m_settings.curves_as_mesh) { + writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); + } + else { + writer = new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings); + } + m_shapes.push_back(writer); + break; + } + case OB_CURVE: { + Curve *cu = static_cast<Curve *>(ob->data); + + if (!cu) { + return; + } + + AbcObjectWriter *writer; + if (m_settings.curves_as_mesh) { + writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); + } + else { + writer = new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings); + } + m_shapes.push_back(writer); + break; + } + case OB_CAMERA: { + Camera *cam = static_cast<Camera *>(ob->data); + + if (cam->type == CAM_PERSP) { + m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings)); + } + + break; + } + case OB_MBALL: { + MetaBall *mball = static_cast<MetaBall *>(ob->data); + if (!mball) { + return; + } + + m_shapes.push_back( + new AbcMBallWriter(m_bmain, ob, xform, m_shape_sampling_index, m_settings)); + break; + } + } } AbcTransformWriter *AbcExporter::getXForm(const std::string &name) { - std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name); + std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name); - if (it == m_xforms.end()) { - return NULL; - } + if (it == m_xforms.end()) { + return NULL; + } - return it->second; + return it->second; } void AbcExporter::setCurrentFrame(Main *bmain, double t) { - m_settings.scene->r.cfra = static_cast<int>(t); - m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra; - BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain); + m_settings.scene->r.cfra = static_cast<int>(t); + m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra; + BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain); } diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index 5e00ccdff07..6ed6a97f935 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -40,91 +40,92 @@ struct Scene; struct ViewLayer; struct ExportSettings { - ExportSettings(); - - Scene *scene; - ViewLayer *view_layer; // Scene layer to export; all its objects will be exported, unless selected_only=true - Depsgraph *depsgraph; - SimpleLogger logger; - - bool selected_only; - bool visible_layers_only; - bool renderable_only; - - double frame_start, frame_end; - double frame_samples_xform; - double frame_samples_shape; - double shutter_open; - double shutter_close; - float global_scale; - - bool flatten_hierarchy; - - bool export_normals; - bool export_uvs; - bool export_vcols; - bool export_face_sets; - bool export_vweigths; - bool export_hair; - bool export_particles; - - bool apply_subdiv; - bool curves_as_mesh; - bool use_subdiv_schema; - bool export_child_hairs; - bool export_ogawa; - bool pack_uv; - bool triangulate; - - int quad_method; - int ngon_method; - - bool do_convert_axis; - float convert_matrix[3][3]; + ExportSettings(); + + Scene *scene; + ViewLayer * + view_layer; // Scene layer to export; all its objects will be exported, unless selected_only=true + Depsgraph *depsgraph; + SimpleLogger logger; + + bool selected_only; + bool visible_layers_only; + bool renderable_only; + + double frame_start, frame_end; + double frame_samples_xform; + double frame_samples_shape; + double shutter_open; + double shutter_close; + float global_scale; + + bool flatten_hierarchy; + + bool export_normals; + bool export_uvs; + bool export_vcols; + bool export_face_sets; + bool export_vweigths; + bool export_hair; + bool export_particles; + + bool apply_subdiv; + bool curves_as_mesh; + bool use_subdiv_schema; + bool export_child_hairs; + bool export_ogawa; + bool pack_uv; + bool triangulate; + + int quad_method; + int ngon_method; + + bool do_convert_axis; + float convert_matrix[3][3]; }; class AbcExporter { - Main *m_bmain; - ExportSettings &m_settings; + Main *m_bmain; + ExportSettings &m_settings; - const char *m_filename; + const char *m_filename; - unsigned int m_trans_sampling_index, m_shape_sampling_index; + unsigned int m_trans_sampling_index, m_shape_sampling_index; - ArchiveWriter *m_writer; + ArchiveWriter *m_writer; - /* mapping from name to transform writer */ - typedef std::map<std::string, AbcTransformWriter *> m_xforms_type; - m_xforms_type m_xforms; + /* mapping from name to transform writer */ + typedef std::map<std::string, AbcTransformWriter *> m_xforms_type; + m_xforms_type m_xforms; - std::vector<AbcObjectWriter *> m_shapes; + std::vector<AbcObjectWriter *> m_shapes; -public: - AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); - ~AbcExporter(); + public: + AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); + ~AbcExporter(); - void operator()(float &progress, bool &was_canceled); + void operator()(float &progress, bool &was_canceled); -protected: - void getShutterSamples(unsigned int nr_of_samples, - bool time_relative, - std::vector<double> &samples); - void getFrameSet(unsigned int nr_of_samples, std::set<double> &frames); + protected: + void getShutterSamples(unsigned int nr_of_samples, + bool time_relative, + std::vector<double> &samples); + void getFrameSet(unsigned int nr_of_samples, std::set<double> &frames); -private: - Alembic::Abc::TimeSamplingPtr createTimeSampling(double step); + private: + Alembic::Abc::TimeSamplingPtr createTimeSampling(double step); - void createTransformWritersHierarchy(); - AbcTransformWriter *createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); - void exploreTransform(Base *base, Object *object, Object *parent, Object *dupliObParent); - void exploreObject(Base *base, Object *object, Object *dupliObParent); - void createShapeWriters(); - void createShapeWriter(Object *ob, Object *dupliObParent); - void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform); + void createTransformWritersHierarchy(); + AbcTransformWriter *createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); + void exploreTransform(Base *base, Object *object, Object *parent, Object *dupliObParent); + void exploreObject(Base *base, Object *object, Object *dupliObParent); + void createShapeWriters(); + void createShapeWriter(Object *ob, Object *dupliObParent); + void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform); - AbcTransformWriter *getXForm(const std::string &name); + AbcTransformWriter *getXForm(const std::string &name); - void setCurrentFrame(Main *bmain, double t); + void setCurrentFrame(Main *bmain, double t); }; -#endif /* __ABC_EXPORTER_H__ */ +#endif /* __ABC_EXPORTER_H__ */ diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc index a587e2a2cd1..b2489169856 100644 --- a/source/blender/alembic/intern/abc_hair.cc +++ b/source/blender/alembic/intern/abc_hair.cc @@ -55,58 +55,58 @@ AbcHairWriter::AbcHairWriter(Object *ob, uint32_t time_sampling, ExportSettings &settings, ParticleSystem *psys) - : AbcObjectWriter(ob, time_sampling, settings, parent) - , m_uv_warning_shown(false) + : AbcObjectWriter(ob, time_sampling, settings, parent), m_uv_warning_shown(false) { - m_psys = psys; + m_psys = psys; - OCurves curves(parent->alembicXform(), psys->name, m_time_sampling); - m_schema = curves.getSchema(); + OCurves curves(parent->alembicXform(), psys->name, m_time_sampling); + m_schema = curves.getSchema(); } void AbcHairWriter::do_write() { - if (!m_psys) { - return; - } - Mesh *mesh = mesh_get_eval_final(m_settings.depsgraph, m_settings.scene, m_object, &CD_MASK_MESH); - BKE_mesh_tessface_ensure(mesh); - - std::vector<Imath::V3f> verts; - std::vector<int32_t> hvertices; - std::vector<Imath::V2f> uv_values; - std::vector<Imath::V3f> norm_values; - - if (m_psys->pathcache) { - ParticleSettings *part = m_psys->part; - - write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); - - if (m_settings.export_child_hairs && m_psys->childcache) { - write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices); - } - } - - Alembic::Abc::P3fArraySample iPos(verts); - m_sample = OCurvesSchema::Sample(iPos, hvertices); - m_sample.setBasis(Alembic::AbcGeom::kNoBasis); - m_sample.setType(Alembic::AbcGeom::kLinear); - m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic); - - if (!uv_values.empty()) { - OV2fGeomParam::Sample uv_smp; - uv_smp.setVals(uv_values); - m_sample.setUVs(uv_smp); - } - - if (!norm_values.empty()) { - ON3fGeomParam::Sample norm_smp; - norm_smp.setVals(norm_values); - m_sample.setNormals(norm_smp); - } - - m_sample.setSelfBounds(bounds()); - m_schema.set(m_sample); + if (!m_psys) { + return; + } + Mesh *mesh = mesh_get_eval_final( + m_settings.depsgraph, m_settings.scene, m_object, &CD_MASK_MESH); + BKE_mesh_tessface_ensure(mesh); + + std::vector<Imath::V3f> verts; + std::vector<int32_t> hvertices; + std::vector<Imath::V2f> uv_values; + std::vector<Imath::V3f> norm_values; + + if (m_psys->pathcache) { + ParticleSettings *part = m_psys->part; + + write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); + + if (m_settings.export_child_hairs && m_psys->childcache) { + write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices); + } + } + + Alembic::Abc::P3fArraySample iPos(verts); + m_sample = OCurvesSchema::Sample(iPos, hvertices); + m_sample.setBasis(Alembic::AbcGeom::kNoBasis); + m_sample.setType(Alembic::AbcGeom::kLinear); + m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic); + + if (!uv_values.empty()) { + OV2fGeomParam::Sample uv_smp; + uv_smp.setVals(uv_values); + m_sample.setUVs(uv_smp); + } + + if (!norm_values.empty()) { + ON3fGeomParam::Sample norm_smp; + norm_smp.setVals(norm_values); + m_sample.setNormals(norm_smp); + } + + m_sample.setSelfBounds(bounds()); + m_schema.set(m_sample); } void AbcHairWriter::write_hair_sample(Mesh *mesh, @@ -116,109 +116,109 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices) { - /* Get untransformed vertices, there's a xform under the hair. */ - float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, m_object->obmat); - - MTFace *mtface = mesh->mtface; - MFace *mface = mesh->mface; - MVert *mverts = mesh->mvert; - - if ((!mtface || !mface) && !m_uv_warning_shown) { - std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n", - m_object->id.name + 2); - m_uv_warning_shown = true; - } - - ParticleData *pa = m_psys->particles; - int k; - - ParticleCacheKey **cache = m_psys->pathcache; - ParticleCacheKey *path; - float normal[3]; - Imath::V3f tmp_nor; - - for (int p = 0; p < m_psys->totpart; ++p, ++pa) { - /* underlying info for faces-only emission */ - path = cache[p]; - - /* Write UV and normal vectors */ - if (part->from == PART_FROM_FACE && mtface) { - const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num; - - if (num < mesh->totface) { - /* TODO(Sybren): check whether the NULL check here and if(mface) are actually required */ - MFace *face = mface == NULL ? NULL : &mface[num]; - MTFace *tface = mtface + num; - - if (mface) { - float r_uv[2], mapfw[4], vec[3]; - - psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv); - uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1])); - - psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL); - - copy_yup_from_zup(tmp_nor.getValue(), normal); - norm_values.push_back(tmp_nor); - } - } - else { - std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, mesh->totface); - } - } - else if (part->from == PART_FROM_VERT && mtface) { - /* vertex id */ - const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num; - - /* iterate over all faces to find a corresponding underlying UV */ - for (int n = 0; n < mesh->totface; ++n) { - MFace *face = &mface[n]; - MTFace *tface = mtface + n; - unsigned int vtx[4]; - vtx[0] = face->v1; - vtx[1] = face->v2; - vtx[2] = face->v3; - vtx[3] = face->v4; - bool found = false; - - for (int o = 0; o < 4; ++o) { - if (o > 2 && vtx[o] == 0) { - break; - } - - if (vtx[o] == num) { - uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1])); - - MVert *mv = mverts + vtx[o]; - - normal_short_to_float_v3(normal, mv->no); - copy_yup_from_zup(tmp_nor.getValue(), normal); - norm_values.push_back(tmp_nor); - found = true; - break; - } - } - - if (found) { - break; - } - } - } - - int steps = path->segments + 1; - hvertices.push_back(steps); - - for (k = 0; k < steps; ++k, ++path) { - float vert[3]; - copy_v3_v3(vert, path->co); - mul_m4_v3(inv_mat, vert); - - /* Convert Z-up to Y-up. */ - verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1])); - - } - } + /* Get untransformed vertices, there's a xform under the hair. */ + float inv_mat[4][4]; + invert_m4_m4_safe(inv_mat, m_object->obmat); + + MTFace *mtface = mesh->mtface; + MFace *mface = mesh->mface; + MVert *mverts = mesh->mvert; + + if ((!mtface || !mface) && !m_uv_warning_shown) { + std::fprintf(stderr, + "Warning, no UV set found for underlying geometry of %s.\n", + m_object->id.name + 2); + m_uv_warning_shown = true; + } + + ParticleData *pa = m_psys->particles; + int k; + + ParticleCacheKey **cache = m_psys->pathcache; + ParticleCacheKey *path; + float normal[3]; + Imath::V3f tmp_nor; + + for (int p = 0; p < m_psys->totpart; ++p, ++pa) { + /* underlying info for faces-only emission */ + path = cache[p]; + + /* Write UV and normal vectors */ + if (part->from == PART_FROM_FACE && mtface) { + const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num; + + if (num < mesh->totface) { + /* TODO(Sybren): check whether the NULL check here and if(mface) are actually required */ + MFace *face = mface == NULL ? NULL : &mface[num]; + MTFace *tface = mtface + num; + + if (mface) { + float r_uv[2], mapfw[4], vec[3]; + + psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv); + uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1])); + + psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL); + + copy_yup_from_zup(tmp_nor.getValue(), normal); + norm_values.push_back(tmp_nor); + } + } + else { + std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, mesh->totface); + } + } + else if (part->from == PART_FROM_VERT && mtface) { + /* vertex id */ + const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num; + + /* iterate over all faces to find a corresponding underlying UV */ + for (int n = 0; n < mesh->totface; ++n) { + MFace *face = &mface[n]; + MTFace *tface = mtface + n; + unsigned int vtx[4]; + vtx[0] = face->v1; + vtx[1] = face->v2; + vtx[2] = face->v3; + vtx[3] = face->v4; + bool found = false; + + for (int o = 0; o < 4; ++o) { + if (o > 2 && vtx[o] == 0) { + break; + } + + if (vtx[o] == num) { + uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1])); + + MVert *mv = mverts + vtx[o]; + + normal_short_to_float_v3(normal, mv->no); + copy_yup_from_zup(tmp_nor.getValue(), normal); + norm_values.push_back(tmp_nor); + found = true; + break; + } + } + + if (found) { + break; + } + } + } + + int steps = path->segments + 1; + hvertices.push_back(steps); + + for (k = 0; k < steps; ++k, ++path) { + float vert[3]; + copy_v3_v3(vert, path->co); + mul_m4_v3(inv_mat, vert); + + /* Convert Z-up to Y-up. */ + verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1])); + } + } } void AbcHairWriter::write_hair_child_sample(Mesh *mesh, @@ -228,68 +228,65 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices) { - /* Get untransformed vertices, there's a xform under the hair. */ - float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, m_object->obmat); - - MTFace *mtface = mesh->mtface; - MVert *mverts = mesh->mvert; - - ParticleCacheKey **cache = m_psys->childcache; - ParticleCacheKey *path; - - ChildParticle *pc = m_psys->child; - - for (int p = 0; p < m_psys->totchild; ++p, ++pc) { - path = cache[p]; - - if (part->from == PART_FROM_FACE && - part->childtype != PART_CHILD_PARTICLES && - mtface) - { - const int num = pc->num; - if (num < 0) { - ABC_LOG(m_settings.logger) - << "Warning, child particle of hair system " << m_psys->name - << " has unknown face index of geometry of "<< (m_object->id.name + 2) - << ", skipping child hair." << std::endl; - continue; - } - - MFace *face = &mesh->mface[num]; - MTFace *tface = mtface + num; - - float r_uv[2], tmpnor[3], mapfw[4], vec[3]; - - psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv); - uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1])); - - psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL); - - /* Convert Z-up to Y-up. */ - norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1])); - } - else { - if (uv_values.size()) { - uv_values.push_back(uv_values[pc->parent]); - } - if (norm_values.size()) { - norm_values.push_back(norm_values[pc->parent]); - } - } - - int steps = path->segments + 1; - hvertices.push_back(steps); - - for (int k = 0; k < steps; ++k) { - float vert[3]; - copy_v3_v3(vert, path->co); - mul_m4_v3(inv_mat, vert); - - /* Convert Z-up to Y-up. */ - verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1])); - - ++path; - } - } + /* Get untransformed vertices, there's a xform under the hair. */ + float inv_mat[4][4]; + invert_m4_m4_safe(inv_mat, m_object->obmat); + + MTFace *mtface = mesh->mtface; + MVert *mverts = mesh->mvert; + + ParticleCacheKey **cache = m_psys->childcache; + ParticleCacheKey *path; + + ChildParticle *pc = m_psys->child; + + for (int p = 0; p < m_psys->totchild; ++p, ++pc) { + path = cache[p]; + + if (part->from == PART_FROM_FACE && part->childtype != PART_CHILD_PARTICLES && mtface) { + const int num = pc->num; + if (num < 0) { + ABC_LOG(m_settings.logger) + << "Warning, child particle of hair system " << m_psys->name + << " has unknown face index of geometry of " << (m_object->id.name + 2) + << ", skipping child hair." << std::endl; + continue; + } + + MFace *face = &mesh->mface[num]; + MTFace *tface = mtface + num; + + float r_uv[2], tmpnor[3], mapfw[4], vec[3]; + + psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv); + uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1])); + + psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL); + + /* Convert Z-up to Y-up. */ + norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1])); + } + else { + if (uv_values.size()) { + uv_values.push_back(uv_values[pc->parent]); + } + if (norm_values.size()) { + norm_values.push_back(norm_values[pc->parent]); + } + } + + int steps = path->segments + 1; + hvertices.push_back(steps); + + for (int k = 0; k < steps; ++k) { + float vert[3]; + copy_v3_v3(vert, path->co); + mul_m4_v3(inv_mat, vert); + + /* Convert Z-up to Y-up. */ + verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1])); + + ++path; + } + } } diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_hair.h index 7b6500196a3..21f665a4795 100644 --- a/source/blender/alembic/intern/abc_hair.h +++ b/source/blender/alembic/intern/abc_hair.h @@ -29,36 +29,36 @@ struct ParticleSystem; /* ************************************************************************** */ class AbcHairWriter : public AbcObjectWriter { - ParticleSystem *m_psys; + ParticleSystem *m_psys; - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; + Alembic::AbcGeom::OCurvesSchema m_schema; + Alembic::AbcGeom::OCurvesSchema::Sample m_sample; - bool m_uv_warning_shown; + bool m_uv_warning_shown; -public: - AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys); + public: + AbcHairWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings, + ParticleSystem *psys); -private: - virtual void do_write(); + private: + virtual void do_write(); - void write_hair_sample(struct Mesh *mesh, - ParticleSettings *part, - std::vector<Imath::V3f> &verts, - std::vector<Imath::V3f> &norm_values, - std::vector<Imath::V2f> &uv_values, - std::vector<int32_t> &hvertices); + void write_hair_sample(struct Mesh *mesh, + ParticleSettings *part, + std::vector<Imath::V3f> &verts, + std::vector<Imath::V3f> &norm_values, + std::vector<Imath::V2f> &uv_values, + std::vector<int32_t> &hvertices); - void write_hair_child_sample(struct Mesh *mesh, - ParticleSettings *part, - std::vector<Imath::V3f> &verts, - std::vector<Imath::V3f> &norm_values, - std::vector<Imath::V2f> &uv_values, - std::vector<int32_t> &hvertices); + void write_hair_child_sample(struct Mesh *mesh, + ParticleSettings *part, + std::vector<Imath::V3f> &verts, + std::vector<Imath::V3f> &norm_values, + std::vector<Imath::V2f> &uv_values, + std::vector<int32_t> &hvertices); }; -#endif /* __ABC_HAIR_H__ */ +#endif /* __ABC_HAIR_H__ */ diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc index bb6ab57643f..3ee26a5081a 100644 --- a/source/blender/alembic/intern/abc_mball.cc +++ b/source/blender/alembic/intern/abc_mball.cc @@ -38,64 +38,62 @@ extern "C" { #include "MEM_guardedalloc.h" } -AbcMBallWriter::AbcMBallWriter( - Main *bmain, - Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings) - , m_bmain(bmain) +AbcMBallWriter::AbcMBallWriter(Main *bmain, + Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings) + : AbcGenericMeshWriter(ob, parent, time_sampling, settings), m_bmain(bmain) { - m_is_animated = isAnimated(); + m_is_animated = isAnimated(); } - AbcMBallWriter::~AbcMBallWriter() -{} +{ +} bool AbcMBallWriter::isAnimated() const { - return true; + return true; } Mesh *AbcMBallWriter::getEvaluatedMesh(Scene * /*scene_eval*/, Object *ob_eval, bool &r_needsfree) { - if (ob_eval->runtime.mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return ob_eval->runtime.mesh_eval; - } - r_needsfree = true; - - /* The approach below is copied from BKE_mesh_new_from_object() */ - Mesh *tmpmesh = BKE_mesh_add(m_bmain, ((ID *)m_object->data)->name + 2); - BLI_assert(tmpmesh != NULL); - - /* BKE_mesh_add gives us a user count we don't need */ - id_us_min(&tmpmesh->id); - - ListBase disp = {NULL, NULL}; - /* TODO(sergey): This is gonna to work for until Depsgraph - * only contains for_render flag. As soon as CoW is - * implemented, this is to be rethinked. - */ - BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp); - BKE_mesh_from_metaball(&disp, tmpmesh); - BKE_displist_free(&disp); - - BKE_mesh_texspace_copy_from_object(tmpmesh, m_object); - - return tmpmesh; + if (ob_eval->runtime.mesh_eval != NULL) { + /* Mesh_eval only exists when generative modifiers are in use. */ + r_needsfree = false; + return ob_eval->runtime.mesh_eval; + } + r_needsfree = true; + + /* The approach below is copied from BKE_mesh_new_from_object() */ + Mesh *tmpmesh = BKE_mesh_add(m_bmain, ((ID *)m_object->data)->name + 2); + BLI_assert(tmpmesh != NULL); + + /* BKE_mesh_add gives us a user count we don't need */ + id_us_min(&tmpmesh->id); + + ListBase disp = {NULL, NULL}; + /* TODO(sergey): This is gonna to work for until Depsgraph + * only contains for_render flag. As soon as CoW is + * implemented, this is to be rethinked. + */ + BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp); + BKE_mesh_from_metaball(&disp, tmpmesh); + BKE_displist_free(&disp); + + BKE_mesh_texspace_copy_from_object(tmpmesh, m_object); + + return tmpmesh; } void AbcMBallWriter::freeEvaluatedMesh(struct Mesh *mesh) { - BKE_id_free(m_bmain, mesh); + BKE_id_free(m_bmain, mesh); } bool AbcMBallWriter::isBasisBall(Scene *scene, Object *ob) { - Object *basis_ob = BKE_mball_basis_find(scene, ob); - return ob == basis_ob; + Object *basis_ob = BKE_mball_basis_find(scene, ob); + return ob == basis_ob; } diff --git a/source/blender/alembic/intern/abc_mball.h b/source/blender/alembic/intern/abc_mball.h index d2bdb8f297a..770fa6fdf8c 100644 --- a/source/blender/alembic/intern/abc_mball.h +++ b/source/blender/alembic/intern/abc_mball.h @@ -34,26 +34,25 @@ struct Object; * to the Alembic file. Only the basis balls are exported, as this * results in the entire shape as one mesh. */ class AbcMBallWriter : public AbcGenericMeshWriter { - Main *m_bmain; -public: - explicit AbcMBallWriter( - Main *bmain, - Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + Main *m_bmain; - ~AbcMBallWriter(); + public: + explicit AbcMBallWriter(Main *bmain, + Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); - static bool isBasisBall(Scene *scene, Object *ob); + ~AbcMBallWriter(); -protected: - Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; - void freeEvaluatedMesh(struct Mesh *mesh) override; + static bool isBasisBall(Scene *scene, Object *ob); -private: - bool isAnimated() const override; -}; + protected: + Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; + void freeEvaluatedMesh(struct Mesh *mesh) override; + private: + bool isAnimated() const override; +}; -#endif /* __ABC_MBALL_H__ */ +#endif /* __ABC_MBALL_H__ */ diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 97cd6ffc0e3..5ccb9be02a3 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -57,6 +57,7 @@ extern "C" { #include "DEG_depsgraph_query.h" } +using Alembic::Abc::C4fArraySample; using Alembic::Abc::FloatArraySample; using Alembic::Abc::ICompoundProperty; using Alembic::Abc::Int32ArraySample; @@ -64,7 +65,6 @@ using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::P3fArraySamplePtr; using Alembic::Abc::V2fArraySample; using Alembic::Abc::V3fArraySample; -using Alembic::Abc::C4fArraySample; using Alembic::AbcGeom::IFaceSet; using Alembic::AbcGeom::IFaceSetSchema; @@ -95,13 +95,13 @@ using Alembic::AbcGeom::OSubDSchema; using Alembic::AbcGeom::OV2fGeomParam; using Alembic::AbcGeom::OV3fGeomParam; +using Alembic::AbcGeom::IN3fGeomParam; using Alembic::AbcGeom::kFacevaryingScope; using Alembic::AbcGeom::kVaryingScope; using Alembic::AbcGeom::kVertexScope; using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::UInt32ArraySample; using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::IN3fGeomParam; +using Alembic::AbcGeom::UInt32ArraySample; /* ************************************************************************** */ @@ -109,14 +109,14 @@ using Alembic::AbcGeom::IN3fGeomParam; static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) { - points.clear(); - points.resize(mesh->totvert); + points.clear(); + points.resize(mesh->totvert); - MVert *verts = mesh->mvert; + MVert *verts = mesh->mvert; - for (int i = 0, e = mesh->totvert; i < e; ++i) { - copy_yup_from_zup(points[i].getValue(), verts[i].co); - } + for (int i = 0, e = mesh->totvert; i < e; ++i) { + copy_yup_from_zup(points[i].getValue(), verts[i].co); + } } static void get_topology(struct Mesh *mesh, @@ -124,29 +124,29 @@ static void get_topology(struct Mesh *mesh, std::vector<int32_t> &loop_counts, bool &smooth_normal) { - const int num_poly = mesh->totpoly; - const int num_loops = mesh->totloop; - MLoop *mloop = mesh->mloop; - MPoly *mpoly = mesh->mpoly; + const int num_poly = mesh->totpoly; + const int num_loops = mesh->totloop; + MLoop *mloop = mesh->mloop; + MPoly *mpoly = mesh->mpoly; - poly_verts.clear(); - loop_counts.clear(); - poly_verts.reserve(num_loops); - loop_counts.reserve(num_poly); + poly_verts.clear(); + loop_counts.clear(); + poly_verts.reserve(num_loops); + loop_counts.reserve(num_poly); - /* NOTE: data needs to be written in the reverse order. */ - for (int i = 0; i < num_poly; ++i) { - MPoly &poly = mpoly[i]; - loop_counts.push_back(poly.totloop); + /* NOTE: data needs to be written in the reverse order. */ + for (int i = 0; i < num_poly; ++i) { + MPoly &poly = mpoly[i]; + loop_counts.push_back(poly.totloop); - smooth_normal |= ((poly.flag & ME_SMOOTH) != 0); + smooth_normal |= ((poly.flag & ME_SMOOTH) != 0); - MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); + MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); - for (int j = 0; j < poly.totloop; ++j, --loop) { - poly_verts.push_back(loop->v); - } - } + for (int j = 0; j < poly.totloop; ++j, --loop) { + poly_verts.push_back(loop->v); + } + } } static void get_creases(struct Mesh *mesh, @@ -154,92 +154,92 @@ static void get_creases(struct Mesh *mesh, std::vector<int32_t> &lengths, std::vector<float> &sharpnesses) { - const float factor = 1.0f / 255.0f; + const float factor = 1.0f / 255.0f; - indices.clear(); - lengths.clear(); - sharpnesses.clear(); + indices.clear(); + lengths.clear(); + sharpnesses.clear(); - MEdge *edge = mesh->medge; + MEdge *edge = mesh->medge; - for (int i = 0, e = mesh->totedge; i < e; ++i) { - const float sharpness = static_cast<float>(edge[i].crease) * factor; + for (int i = 0, e = mesh->totedge; i < e; ++i) { + const float sharpness = static_cast<float>(edge[i].crease) * factor; - if (sharpness != 0.0f) { - indices.push_back(edge[i].v1); - indices.push_back(edge[i].v2); - sharpnesses.push_back(sharpness); - } - } + if (sharpness != 0.0f) { + indices.push_back(edge[i].v1); + indices.push_back(edge[i].v2); + sharpnesses.push_back(sharpness); + } + } - lengths.resize(sharpnesses.size(), 2); + lengths.resize(sharpnesses.size(), 2); } static void get_vertex_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals) { - normals.clear(); - normals.resize(mesh->totvert); + normals.clear(); + normals.resize(mesh->totvert); - MVert *verts = mesh->mvert; - float no[3]; + MVert *verts = mesh->mvert; + float no[3]; - for (int i = 0, e = mesh->totvert; i < e; ++i) { - normal_short_to_float_v3(no, verts[i].no); - copy_yup_from_zup(normals[i].getValue(), no); - } + for (int i = 0, e = mesh->totvert; i < e; ++i) { + normal_short_to_float_v3(no, verts[i].no); + copy_yup_from_zup(normals[i].getValue(), no); + } } static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals) { - MPoly *mp = mesh->mpoly; - - MLoop *mloop = mesh->mloop; - MLoop *ml = mloop; - - MVert *verts = mesh->mvert; - - const float (*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); - - normals.clear(); - normals.resize(mesh->totloop); - - unsigned loop_index = 0; - - /* NOTE: data needs to be written in the reverse order. */ - - if (lnors) { - for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) { - ml = mloop + mp->loopstart + (mp->totloop - 1); - - for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { - const int index = ml->v; - copy_yup_from_zup(normals[loop_index].getValue(), lnors[index]); - } - } - } - else { - float no[3]; - - for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) { - ml = mloop + mp->loopstart + (mp->totloop - 1); - - /* Flat shaded, use common normal for all verts. */ - if ((mp->flag & ME_SMOOTH) == 0) { - BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no); - - for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { - copy_yup_from_zup(normals[loop_index].getValue(), no); - } - } - else { - /* Smooth shaded, use individual vert normals. */ - for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { - normal_short_to_float_v3(no, verts[ml->v].no); - copy_yup_from_zup(normals[loop_index].getValue(), no); - } - } - } - } + MPoly *mp = mesh->mpoly; + + MLoop *mloop = mesh->mloop; + MLoop *ml = mloop; + + MVert *verts = mesh->mvert; + + const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); + + normals.clear(); + normals.resize(mesh->totloop); + + unsigned loop_index = 0; + + /* NOTE: data needs to be written in the reverse order. */ + + if (lnors) { + for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) { + ml = mloop + mp->loopstart + (mp->totloop - 1); + + for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { + const int index = ml->v; + copy_yup_from_zup(normals[loop_index].getValue(), lnors[index]); + } + } + } + else { + float no[3]; + + for (int i = 0, e = mesh->totpoly; i < e; ++i, ++mp) { + ml = mloop + mp->loopstart + (mp->totloop - 1); + + /* Flat shaded, use common normal for all verts. */ + if ((mp->flag & ME_SMOOTH) == 0) { + BKE_mesh_calc_poly_normal(mp, ml - (mp->totloop - 1), verts, no); + + for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { + copy_yup_from_zup(normals[loop_index].getValue(), no); + } + } + else { + /* Smooth shaded, use individual vert normals. */ + for (int j = 0; j < mp->totloop; --ml, ++j, ++loop_index) { + normal_short_to_float_v3(no, verts[ml->v].no); + copy_yup_from_zup(normals[loop_index].getValue(), no); + } + } + } + } } /* *************** Modifiers *************** */ @@ -248,43 +248,43 @@ static void get_loop_normals(struct Mesh *mesh, std::vector<Imath::V3f> &normals * displace if it's after subsurf. */ static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob) { - ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); + ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); - for (; md; md = md->prev) { - if (!modifier_isEnabled(scene, md, eModifierMode_Render)) { - continue; - } + for (; md; md = md->prev) { + if (!modifier_isEnabled(scene, md, eModifierMode_Render)) { + continue; + } - if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData*>(md); + if (md->type == eModifierType_Subsurf) { + SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(md); - if (smd->subdivType == ME_CC_SUBSURF) { - return md; - } - } + if (smd->subdivType == ME_CC_SUBSURF) { + return md; + } + } - /* mesh is not a subsurf. break */ - if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) { - return NULL; - } - } + /* mesh is not a subsurf. break */ + if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) { + return NULL; + } + } - return NULL; + return NULL; } static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) { - ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim); + ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim); - if (md && (modifier_isEnabled(scene, md, eModifierMode_Render))) { - FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md); + if (md && (modifier_isEnabled(scene, md, eModifierMode_Render))) { + FluidsimModifierData *fsmd = reinterpret_cast<FluidsimModifierData *>(md); - if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) { - return md; - } - } + if (fsmd->fss && fsmd->fss->type == OB_FLUIDSIM_DOMAIN) { + return md; + } + } - return NULL; + return NULL; } /* ************************************************************************** */ @@ -295,390 +295,394 @@ AbcGenericMeshWriter::AbcGenericMeshWriter(Object *ob, ExportSettings &settings) : AbcObjectWriter(ob, time_sampling, settings, parent) { - m_is_animated = isAnimated(); - m_subsurf_mod = NULL; - m_is_subd = false; - - /* If the object is static, use the default static time sampling. */ - if (!m_is_animated) { - time_sampling = 0; - } - - if (!m_settings.apply_subdiv) { - m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object); - m_is_subd = (m_subsurf_mod != NULL); - } - - m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL); - - while (parent->alembicXform().getChildHeader(m_name)) { - m_name.append("_"); - } - - if (m_settings.use_subdiv_schema && m_is_subd) { - OSubD subd(parent->alembicXform(), m_name, m_time_sampling); - m_subdiv_schema = subd.getSchema(); - } - else { - OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling); - m_mesh_schema = mesh.getSchema(); - - OCompoundProperty typeContainer = m_mesh_schema.getUserProperties(); - OBoolProperty type(typeContainer, "meshtype"); - type.set(m_is_subd); - } + m_is_animated = isAnimated(); + m_subsurf_mod = NULL; + m_is_subd = false; + + /* If the object is static, use the default static time sampling. */ + if (!m_is_animated) { + time_sampling = 0; + } + + if (!m_settings.apply_subdiv) { + m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object); + m_is_subd = (m_subsurf_mod != NULL); + } + + m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL); + + while (parent->alembicXform().getChildHeader(m_name)) { + m_name.append("_"); + } + + if (m_settings.use_subdiv_schema && m_is_subd) { + OSubD subd(parent->alembicXform(), m_name, m_time_sampling); + m_subdiv_schema = subd.getSchema(); + } + else { + OPolyMesh mesh(parent->alembicXform(), m_name, m_time_sampling); + m_mesh_schema = mesh.getSchema(); + + OCompoundProperty typeContainer = m_mesh_schema.getUserProperties(); + OBoolProperty type(typeContainer, "meshtype"); + type.set(m_is_subd); + } } AbcGenericMeshWriter::~AbcGenericMeshWriter() { - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } + if (m_subsurf_mod) { + m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; + } } bool AbcGenericMeshWriter::isAnimated() const { - if (m_object->data != NULL) { - AnimData *adt = BKE_animdata_from_id(static_cast<ID*>(m_object->data)); - /* TODO(Sybren): make this check more strict, as the AnimationData may - * actually be empty (no fcurves, drivers, etc.) and thus effectively - * have no animation at all. */ - if (adt != NULL) { - return true; - } - } - if (BKE_key_from_object(m_object) != NULL) { - return true; - } - - /* Test modifiers. */ - ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first); - while (md) { - - if (md->type != eModifierType_Subsurf) { - return true; - } - - md = md->next; - } - - return false; + if (m_object->data != NULL) { + AnimData *adt = BKE_animdata_from_id(static_cast<ID *>(m_object->data)); + /* TODO(Sybren): make this check more strict, as the AnimationData may + * actually be empty (no fcurves, drivers, etc.) and thus effectively + * have no animation at all. */ + if (adt != NULL) { + return true; + } + } + if (BKE_key_from_object(m_object) != NULL) { + return true; + } + + /* Test modifiers. */ + ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first); + while (md) { + + if (md->type != eModifierType_Subsurf) { + return true; + } + + md = md->next; + } + + return false; } void AbcGenericMeshWriter::setIsAnimated(bool is_animated) { - m_is_animated = is_animated; + m_is_animated = is_animated; } void AbcGenericMeshWriter::do_write() { - /* We have already stored a sample for this object. */ - if (!m_first_frame && !m_is_animated) - return; - - bool needsfree; - struct Mesh *mesh = getFinalMesh(needsfree); - - try { - if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) { - writeSubD(mesh); - } - else { - writeMesh(mesh); - } - - if (needsfree) freeEvaluatedMesh(mesh); - } - catch (...) { - if (needsfree) freeEvaluatedMesh(mesh); - throw; - } + /* We have already stored a sample for this object. */ + if (!m_first_frame && !m_is_animated) + return; + + bool needsfree; + struct Mesh *mesh = getFinalMesh(needsfree); + + try { + if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) { + writeSubD(mesh); + } + else { + writeMesh(mesh); + } + + if (needsfree) + freeEvaluatedMesh(mesh); + } + catch (...) { + if (needsfree) + freeEvaluatedMesh(mesh); + throw; + } } void AbcGenericMeshWriter::freeEvaluatedMesh(struct Mesh *mesh) { - BKE_id_free(NULL, mesh); + BKE_id_free(NULL, mesh); } void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) { - std::vector<Imath::V3f> points, normals; - std::vector<int32_t> poly_verts, loop_counts; + std::vector<Imath::V3f> points, normals; + std::vector<int32_t> poly_verts, loop_counts; - bool smooth_normal = false; + bool smooth_normal = false; - get_vertices(mesh, points); - get_topology(mesh, poly_verts, loop_counts, smooth_normal); + get_vertices(mesh, points); + get_topology(mesh, poly_verts, loop_counts, smooth_normal); - if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(mesh, m_mesh_schema); - } + if (m_first_frame && m_settings.export_face_sets) { + writeFaceSets(mesh, m_mesh_schema); + } - m_mesh_sample = OPolyMeshSchema::Sample(V3fArraySample(points), - Int32ArraySample(poly_verts), - Int32ArraySample(loop_counts)); + m_mesh_sample = OPolyMeshSchema::Sample( + V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); - UVSample sample; - if (m_first_frame && m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); + UVSample sample; + if (m_first_frame && m_settings.export_uvs) { + const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); - if (!sample.indices.empty() && !sample.uvs.empty()) { - OV2fGeomParam::Sample uv_sample; - uv_sample.setVals(V2fArraySample(sample.uvs)); - uv_sample.setIndices(UInt32ArraySample(sample.indices)); - uv_sample.setScope(kFacevaryingScope); + if (!sample.indices.empty() && !sample.uvs.empty()) { + OV2fGeomParam::Sample uv_sample; + uv_sample.setVals(V2fArraySample(sample.uvs)); + uv_sample.setIndices(UInt32ArraySample(sample.indices)); + uv_sample.setScope(kFacevaryingScope); - m_mesh_schema.setUVSourceName(name); - m_mesh_sample.setUVs(uv_sample); - } + m_mesh_schema.setUVSourceName(name); + m_mesh_sample.setUVs(uv_sample); + } - write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); - } + write_custom_data( + m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + } - if (m_settings.export_normals) { - if (smooth_normal) { - get_loop_normals(mesh, normals); - } - else { - get_vertex_normals(mesh, normals); - } + if (m_settings.export_normals) { + if (smooth_normal) { + get_loop_normals(mesh, normals); + } + else { + get_vertex_normals(mesh, normals); + } - ON3fGeomParam::Sample normals_sample; - if (!normals.empty()) { - normals_sample.setScope((smooth_normal) ? kFacevaryingScope : kVertexScope); - normals_sample.setVals(V3fArraySample(normals)); - } + ON3fGeomParam::Sample normals_sample; + if (!normals.empty()) { + normals_sample.setScope((smooth_normal) ? kFacevaryingScope : kVertexScope); + normals_sample.setVals(V3fArraySample(normals)); + } - m_mesh_sample.setNormals(normals_sample); - } + m_mesh_sample.setNormals(normals_sample); + } - if (m_is_liquid) { - std::vector<Imath::V3f> velocities; - getVelocities(mesh, velocities); + if (m_is_liquid) { + std::vector<Imath::V3f> velocities; + getVelocities(mesh, velocities); - m_mesh_sample.setVelocities(V3fArraySample(velocities)); - } + m_mesh_sample.setVelocities(V3fArraySample(velocities)); + } - m_mesh_sample.setSelfBounds(bounds()); + m_mesh_sample.setSelfBounds(bounds()); - m_mesh_schema.set(m_mesh_sample); + m_mesh_schema.set(m_mesh_sample); - writeArbGeoParams(mesh); + writeArbGeoParams(mesh); } void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) { - std::vector<float> crease_sharpness; - std::vector<Imath::V3f> points; - std::vector<int32_t> poly_verts, loop_counts; - std::vector<int32_t> crease_indices, crease_lengths; + std::vector<float> crease_sharpness; + std::vector<Imath::V3f> points; + std::vector<int32_t> poly_verts, loop_counts; + std::vector<int32_t> crease_indices, crease_lengths; - bool smooth_normal = false; + bool smooth_normal = false; - get_vertices(mesh, points); - get_topology(mesh, poly_verts, loop_counts, smooth_normal); - get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); + get_vertices(mesh, points); + get_topology(mesh, poly_verts, loop_counts, smooth_normal); + get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); - if (m_first_frame && m_settings.export_face_sets) { - writeFaceSets(mesh, m_subdiv_schema); - } + if (m_first_frame && m_settings.export_face_sets) { + writeFaceSets(mesh, m_subdiv_schema); + } - m_subdiv_sample = OSubDSchema::Sample(V3fArraySample(points), - Int32ArraySample(poly_verts), - Int32ArraySample(loop_counts)); + m_subdiv_sample = OSubDSchema::Sample( + V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); - UVSample sample; - if (m_first_frame && m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); + UVSample sample; + if (m_first_frame && m_settings.export_uvs) { + const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); - if (!sample.indices.empty() && !sample.uvs.empty()) { - OV2fGeomParam::Sample uv_sample; - uv_sample.setVals(V2fArraySample(sample.uvs)); - uv_sample.setIndices(UInt32ArraySample(sample.indices)); - uv_sample.setScope(kFacevaryingScope); + if (!sample.indices.empty() && !sample.uvs.empty()) { + OV2fGeomParam::Sample uv_sample; + uv_sample.setVals(V2fArraySample(sample.uvs)); + uv_sample.setIndices(UInt32ArraySample(sample.indices)); + uv_sample.setScope(kFacevaryingScope); - m_subdiv_schema.setUVSourceName(name); - m_subdiv_sample.setUVs(uv_sample); - } + m_subdiv_schema.setUVSourceName(name); + m_subdiv_sample.setUVs(uv_sample); + } - write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); - } + write_custom_data( + m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + } - if (!crease_indices.empty()) { - m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); - m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); - m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); - } + if (!crease_indices.empty()) { + m_subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); + m_subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); + m_subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); + } - m_subdiv_sample.setSelfBounds(bounds()); - m_subdiv_schema.set(m_subdiv_sample); + m_subdiv_sample.setSelfBounds(bounds()); + m_subdiv_schema.set(m_subdiv_sample); - writeArbGeoParams(mesh); + writeArbGeoParams(mesh); } -template <typename Schema> -void AbcGenericMeshWriter::writeFaceSets(struct Mesh *me, Schema &schema) +template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh *me, Schema &schema) { - std::map< std::string, std::vector<int32_t>> geo_groups; - getGeoGroups(me, geo_groups); - - std::map< std::string, std::vector<int32_t>>::iterator it; - for (it = geo_groups.begin(); it != geo_groups.end(); ++it) { - OFaceSet face_set = schema.createFaceSet(it->first); - OFaceSetSchema::Sample samp; - samp.setFaces(Int32ArraySample(it->second)); - face_set.getSchema().set(samp); - } + std::map<std::string, std::vector<int32_t>> geo_groups; + getGeoGroups(me, geo_groups); + + std::map<std::string, std::vector<int32_t>>::iterator it; + for (it = geo_groups.begin(); it != geo_groups.end(); ++it) { + OFaceSet face_set = schema.createFaceSet(it->first); + OFaceSetSchema::Sample samp; + samp.setFaces(Int32ArraySample(it->second)); + face_set.getSchema().set(samp); + } } Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree) { - /* We don't want subdivided mesh data */ - if (m_subsurf_mod) { - m_subsurf_mod->mode |= eModifierMode_DisableTemporary; - } + /* We don't want subdivided mesh data */ + if (m_subsurf_mod) { + m_subsurf_mod->mode |= eModifierMode_DisableTemporary; + } - r_needsfree = false; + r_needsfree = false; - Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph); - Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); - struct Mesh *mesh = getEvaluatedMesh(scene, ob_eval, r_needsfree); + Scene *scene = DEG_get_evaluated_scene(m_settings.depsgraph); + Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); + struct Mesh *mesh = getEvaluatedMesh(scene, ob_eval, r_needsfree); - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } + if (m_subsurf_mod) { + m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; + } - if (m_settings.triangulate) { - const bool tag_only = false; - const int quad_method = m_settings.quad_method; - const int ngon_method = m_settings.ngon_method; + if (m_settings.triangulate) { + const bool tag_only = false; + const int quad_method = m_settings.quad_method; + const int ngon_method = m_settings.ngon_method; - struct BMeshCreateParams bmcp = {false}; - struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; - BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); + struct BMeshCreateParams bmcp = {false}; + struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); - BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL); + BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL); - Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); - BM_mesh_free(bm); + Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL); + BM_mesh_free(bm); - if (r_needsfree) { - BKE_id_free(NULL, mesh); - } + if (r_needsfree) { + BKE_id_free(NULL, mesh); + } - mesh = result; - r_needsfree = true; - } + mesh = result; + r_needsfree = true; + } - m_custom_data_config.pack_uvs = m_settings.pack_uv; - m_custom_data_config.mpoly = mesh->mpoly; - m_custom_data_config.mloop = mesh->mloop; - m_custom_data_config.totpoly = mesh->totpoly; - m_custom_data_config.totloop = mesh->totloop; - m_custom_data_config.totvert = mesh->totvert; + m_custom_data_config.pack_uvs = m_settings.pack_uv; + m_custom_data_config.mpoly = mesh->mpoly; + m_custom_data_config.mloop = mesh->mloop; + m_custom_data_config.totpoly = mesh->totpoly; + m_custom_data_config.totloop = mesh->totloop; + m_custom_data_config.totvert = mesh->totvert; - return mesh; + return mesh; } void AbcGenericMeshWriter::writeArbGeoParams(struct Mesh *me) { - if (m_is_liquid) { - /* We don't need anything more for liquid meshes. */ - return; - } - - if (m_first_frame && m_settings.export_vcols) { - if (m_subdiv_schema.valid()) { - write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); - } - else { - write_custom_data(m_mesh_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); - } - } + if (m_is_liquid) { + /* We don't need anything more for liquid meshes. */ + return; + } + + if (m_first_frame && m_settings.export_vcols) { + if (m_subdiv_schema.valid()) { + write_custom_data( + m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); + } + else { + write_custom_data( + m_mesh_schema.getArbGeomParams(), m_custom_data_config, &me->ldata, CD_MLOOPCOL); + } + } } void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) { - const int totverts = mesh->totvert; - - vels.clear(); - vels.resize(totverts); - - ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object); - FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md); - FluidsimSettings *fss = fmd->fss; - - if (fss->meshVelocities) { - float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities); - - for (int i = 0; i < totverts; ++i) { - copy_yup_from_zup(vels[i].getValue(), mesh_vels); - mesh_vels += 3; - } - } - else { - std::fill(vels.begin(), vels.end(), Imath::V3f(0.0f)); - } + const int totverts = mesh->totvert; + + vels.clear(); + vels.resize(totverts); + + ModifierData *md = get_liquid_sim_modifier(m_settings.scene, m_object); + FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(md); + FluidsimSettings *fss = fmd->fss; + + if (fss->meshVelocities) { + float *mesh_vels = reinterpret_cast<float *>(fss->meshVelocities); + + for (int i = 0; i < totverts; ++i) { + copy_yup_from_zup(vels[i].getValue(), mesh_vels); + mesh_vels += 3; + } + } + else { + std::fill(vels.begin(), vels.end(), Imath::V3f(0.0f)); + } } -void AbcGenericMeshWriter::getGeoGroups( - struct Mesh *mesh, - std::map<std::string, std::vector<int32_t>> &geo_groups) +void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, + std::map<std::string, std::vector<int32_t>> &geo_groups) { - const int num_poly = mesh->totpoly; - MPoly *polygons = mesh->mpoly; + const int num_poly = mesh->totpoly; + MPoly *polygons = mesh->mpoly; - for (int i = 0; i < num_poly; ++i) { - MPoly ¤t_poly = polygons[i]; - short mnr = current_poly.mat_nr; + for (int i = 0; i < num_poly; ++i) { + MPoly ¤t_poly = polygons[i]; + short mnr = current_poly.mat_nr; - Material *mat = give_current_material(m_object, mnr + 1); + Material *mat = give_current_material(m_object, mnr + 1); - if (!mat) { - continue; - } + if (!mat) { + continue; + } - std::string name = get_id_name(&mat->id); + std::string name = get_id_name(&mat->id); - if (geo_groups.find(name) == geo_groups.end()) { - std::vector<int32_t> faceArray; - geo_groups[name] = faceArray; - } + if (geo_groups.find(name) == geo_groups.end()) { + std::vector<int32_t> faceArray; + geo_groups[name] = faceArray; + } - geo_groups[name].push_back(i); - } + geo_groups[name].push_back(i); + } - if (geo_groups.size() == 0) { - Material *mat = give_current_material(m_object, 1); + if (geo_groups.size() == 0) { + Material *mat = give_current_material(m_object, 1); - std::string name = (mat) ? get_id_name(&mat->id) : "default"; + std::string name = (mat) ? get_id_name(&mat->id) : "default"; - std::vector<int32_t> faceArray; + std::vector<int32_t> faceArray; - for (int i = 0, e = mesh->totface; i < e; ++i) { - faceArray.push_back(i); - } + for (int i = 0, e = mesh->totface; i < e; ++i) { + faceArray.push_back(i); + } - geo_groups[name] = faceArray; - } + geo_groups[name] = faceArray; + } } - AbcMeshWriter::AbcMeshWriter(Object *ob, AbcTransformWriter *parent, uint32_t time_sampling, ExportSettings &settings) : AbcGenericMeshWriter(ob, parent, time_sampling, settings) -{} +{ +} AbcMeshWriter::~AbcMeshWriter() -{} - -Mesh *AbcMeshWriter::getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &UNUSED(r_needsfree)) { - return mesh_get_eval_final(m_settings.depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); } +Mesh *AbcMeshWriter::getEvaluatedMesh(Scene *scene_eval, + Object *ob_eval, + bool &UNUSED(r_needsfree)) +{ + return mesh_get_eval_final(m_settings.depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); +} /* ************************************************************************** */ @@ -687,55 +691,57 @@ namespace utils { static void build_mat_map(const Main *bmain, std::map<std::string, Material *> &mat_map) { - Material *material = static_cast<Material *>(bmain->materials.first); + Material *material = static_cast<Material *>(bmain->materials.first); - for (; material; material = static_cast<Material *>(material->id.next)) { - mat_map[material->id.name + 2] = material; - } + for (; material; material = static_cast<Material *>(material->id.next)) { + mat_map[material->id.name + 2] = material; + } } -static void assign_materials(Main *bmain, Object *ob, const std::map<std::string, int> &mat_index_map) +static void assign_materials(Main *bmain, + Object *ob, + const std::map<std::string, int> &mat_index_map) { - bool can_assign = true; - std::map<std::string, int>::const_iterator it = mat_index_map.begin(); - - int matcount = 0; - for (; it != mat_index_map.end(); ++it, ++matcount) { - if (!BKE_object_material_slot_add(bmain, ob)) { - can_assign = false; - break; - } - } - - /* TODO(kevin): use global map? */ - std::map<std::string, Material *> mat_map; - build_mat_map(bmain, mat_map); - - std::map<std::string, Material *>::iterator mat_iter; - - if (can_assign) { - it = mat_index_map.begin(); - - for (; it != mat_index_map.end(); ++it) { - std::string mat_name = it->first; - mat_iter = mat_map.find(mat_name.c_str()); - - Material *assigned_mat; - - if (mat_iter == mat_map.end()) { - assigned_mat = BKE_material_add(bmain, mat_name.c_str()); - mat_map[mat_name] = assigned_mat; - } - else { - assigned_mat = mat_iter->second; - } - - assign_material(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); - } - } + bool can_assign = true; + std::map<std::string, int>::const_iterator it = mat_index_map.begin(); + + int matcount = 0; + for (; it != mat_index_map.end(); ++it, ++matcount) { + if (!BKE_object_material_slot_add(bmain, ob)) { + can_assign = false; + break; + } + } + + /* TODO(kevin): use global map? */ + std::map<std::string, Material *> mat_map; + build_mat_map(bmain, mat_map); + + std::map<std::string, Material *>::iterator mat_iter; + + if (can_assign) { + it = mat_index_map.begin(); + + for (; it != mat_index_map.end(); ++it) { + std::string mat_name = it->first; + mat_iter = mat_map.find(mat_name.c_str()); + + Material *assigned_mat; + + if (mat_iter == mat_map.end()) { + assigned_mat = BKE_material_add(bmain, mat_name.c_str()); + mat_map[mat_name] = assigned_mat; + } + else { + assigned_mat = mat_iter->second; + } + + assign_material(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); + } + } } -} /* namespace utils */ +} /* namespace utils */ /* ************************************************************************** */ @@ -743,116 +749,120 @@ using Alembic::AbcGeom::UInt32ArraySamplePtr; using Alembic::AbcGeom::V2fArraySamplePtr; struct AbcMeshData { - Int32ArraySamplePtr face_indices; - Int32ArraySamplePtr face_counts; + Int32ArraySamplePtr face_indices; + Int32ArraySamplePtr face_counts; - P3fArraySamplePtr positions; - P3fArraySamplePtr ceil_positions; + P3fArraySamplePtr positions; + P3fArraySamplePtr ceil_positions; - N3fArraySamplePtr vertex_normals; - N3fArraySamplePtr face_normals; + N3fArraySamplePtr vertex_normals; + N3fArraySamplePtr face_normals; - V2fArraySamplePtr uvs; - UInt32ArraySamplePtr uvs_indices; + V2fArraySamplePtr uvs; + UInt32ArraySamplePtr uvs_indices; }; -static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const float weight) +static void read_mverts_interp(MVert *mverts, + const P3fArraySamplePtr &positions, + const P3fArraySamplePtr &ceil_positions, + const float weight) { - float tmp[3]; - for (int i = 0; i < positions->size(); ++i) { - MVert &mvert = mverts[i]; - const Imath::V3f &floor_pos = (*positions)[i]; - const Imath::V3f &ceil_pos = (*ceil_positions)[i]; + float tmp[3]; + for (int i = 0; i < positions->size(); ++i) { + MVert &mvert = mverts[i]; + const Imath::V3f &floor_pos = (*positions)[i]; + const Imath::V3f &ceil_pos = (*ceil_positions)[i]; - interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight); - copy_zup_from_yup(mvert.co, tmp); + interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight); + copy_zup_from_yup(mvert.co, tmp); - mvert.bweight = 0; - } + mvert.bweight = 0; + } } static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data) { - MVert *mverts = config.mvert; - const P3fArraySamplePtr &positions = mesh_data.positions; - const N3fArraySamplePtr &normals = mesh_data.vertex_normals; - - if ( config.weight != 0.0f - && mesh_data.ceil_positions != NULL - && mesh_data.ceil_positions->size() == positions->size()) - { - read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight); - return; - } - - read_mverts(mverts, positions, normals); + MVert *mverts = config.mvert; + const P3fArraySamplePtr &positions = mesh_data.positions; + const N3fArraySamplePtr &normals = mesh_data.vertex_normals; + + if (config.weight != 0.0f && mesh_data.ceil_positions != NULL && + mesh_data.ceil_positions->size() == positions->size()) { + read_mverts_interp(mverts, positions, mesh_data.ceil_positions, config.weight); + return; + } + + read_mverts(mverts, positions, normals); } -void read_mverts(MVert *mverts, const P3fArraySamplePtr &positions, const N3fArraySamplePtr &normals) +void read_mverts(MVert *mverts, + const P3fArraySamplePtr &positions, + const N3fArraySamplePtr &normals) { - for (int i = 0; i < positions->size(); ++i) { - MVert &mvert = mverts[i]; - Imath::V3f pos_in = (*positions)[i]; + for (int i = 0; i < positions->size(); ++i) { + MVert &mvert = mverts[i]; + Imath::V3f pos_in = (*positions)[i]; - copy_zup_from_yup(mvert.co, pos_in.getValue()); + copy_zup_from_yup(mvert.co, pos_in.getValue()); - mvert.bweight = 0; + mvert.bweight = 0; - if (normals) { - Imath::V3f nor_in = (*normals)[i]; + if (normals) { + Imath::V3f nor_in = (*normals)[i]; - short no[3]; - normal_float_to_short_v3(no, nor_in.getValue()); + short no[3]; + normal_float_to_short_v3(no, nor_in.getValue()); - copy_zup_from_yup(mvert.no, no); - } - } + copy_zup_from_yup(mvert.no, no); + } + } } static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data) { - MPoly *mpolys = config.mpoly; - MLoop *mloops = config.mloop; - MLoopUV *mloopuvs = config.mloopuv; - - const Int32ArraySamplePtr &face_indices = mesh_data.face_indices; - const Int32ArraySamplePtr &face_counts = mesh_data.face_counts; - const V2fArraySamplePtr &uvs = mesh_data.uvs; - const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices; - const N3fArraySamplePtr &normals = mesh_data.face_normals; - - const bool do_uvs = (mloopuvs && uvs && uvs_indices) && (uvs_indices->size() == face_indices->size()); - unsigned int loop_index = 0; - unsigned int rev_loop_index = 0; - unsigned int uv_index = 0; - - for (int i = 0; i < face_counts->size(); ++i) { - const int face_size = (*face_counts)[i]; - - MPoly &poly = mpolys[i]; - poly.loopstart = loop_index; - poly.totloop = face_size; - - if (normals != NULL) { - poly.flag |= ME_SMOOTH; - } - - /* NOTE: Alembic data is stored in the reverse order. */ - rev_loop_index = loop_index + (face_size - 1); - - for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) { - MLoop &loop = mloops[rev_loop_index]; - loop.v = (*face_indices)[loop_index]; - - if (do_uvs) { - MLoopUV &loopuv = mloopuvs[rev_loop_index]; - - uv_index = (*uvs_indices)[loop_index]; - loopuv.uv[0] = (*uvs)[uv_index][0]; - loopuv.uv[1] = (*uvs)[uv_index][1]; - } - } - } + MPoly *mpolys = config.mpoly; + MLoop *mloops = config.mloop; + MLoopUV *mloopuvs = config.mloopuv; + + const Int32ArraySamplePtr &face_indices = mesh_data.face_indices; + const Int32ArraySamplePtr &face_counts = mesh_data.face_counts; + const V2fArraySamplePtr &uvs = mesh_data.uvs; + const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices; + const N3fArraySamplePtr &normals = mesh_data.face_normals; + + const bool do_uvs = (mloopuvs && uvs && uvs_indices) && + (uvs_indices->size() == face_indices->size()); + unsigned int loop_index = 0; + unsigned int rev_loop_index = 0; + unsigned int uv_index = 0; + + for (int i = 0; i < face_counts->size(); ++i) { + const int face_size = (*face_counts)[i]; + + MPoly &poly = mpolys[i]; + poly.loopstart = loop_index; + poly.totloop = face_size; + + if (normals != NULL) { + poly.flag |= ME_SMOOTH; + } + + /* NOTE: Alembic data is stored in the reverse order. */ + rev_loop_index = loop_index + (face_size - 1); + + for (int f = 0; f < face_size; ++f, ++loop_index, --rev_loop_index) { + MLoop &loop = mloops[rev_loop_index]; + loop.v = (*face_indices)[loop_index]; + + if (do_uvs) { + MLoopUV &loopuv = mloopuvs[rev_loop_index]; + + uv_index = (*uvs_indices)[loop_index]; + loopuv.uv[0] = (*uvs)[uv_index][0]; + loopuv.uv[1] = (*uvs)[uv_index][1]; + } + } + } } ABC_INLINE void read_uvs_params(CDStreamConfig &config, @@ -860,29 +870,29 @@ ABC_INLINE void read_uvs_params(CDStreamConfig &config, const IV2fGeomParam &uv, const ISampleSelector &selector) { - if (!uv.valid()) { - return; - } + if (!uv.valid()) { + return; + } - IV2fGeomParam::Sample uvsamp; - uv.getIndexed(uvsamp, selector); + IV2fGeomParam::Sample uvsamp; + uv.getIndexed(uvsamp, selector); - abc_data.uvs = uvsamp.getVals(); - abc_data.uvs_indices = uvsamp.getIndices(); + abc_data.uvs = uvsamp.getVals(); + abc_data.uvs_indices = uvsamp.getIndices(); - if (abc_data.uvs_indices->size() == config.totloop) { - std::string name = Alembic::Abc::GetSourceName(uv.getMetaData()); + if (abc_data.uvs_indices->size() == config.totloop) { + std::string name = Alembic::Abc::GetSourceName(uv.getMetaData()); - /* According to the convention, primary UVs should have had their name - * set using Alembic::Abc::SetSourceName, but you can't expect everyone - * to follow it! :) */ - if (name.empty()) { - name = uv.getName(); - } + /* According to the convention, primary UVs should have had their name + * set using Alembic::Abc::SetSourceName, but you can't expect everyone + * to follow it! :) */ + if (name.empty()) { + name = uv.getName(); + } - void *cd_ptr = config.add_customdata_cb(config.user_data, name.c_str(), CD_MLOOPUV); - config.mloopuv = static_cast<MLoopUV *>(cd_ptr); - } + void *cd_ptr = config.add_customdata_cb(config.user_data, name.c_str(), CD_MLOOPUV); + config.mloopuv = static_cast<MLoopUV *>(cd_ptr); + } } /* TODO(kevin): normals from Alembic files are not read in anymore, this is due @@ -893,149 +903,143 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data, const IN3fGeomParam &normals, const ISampleSelector &selector) { - if (!normals.valid()) { - return; - } - - IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector); - - if (normals.getScope() == kFacevaryingScope) { - abc_data.face_normals = normsamp.getVals(); - } - else if ((normals.getScope() == kVertexScope) || (normals.getScope() == kVaryingScope)) { - abc_data.vertex_normals = N3fArraySamplePtr(); - } + if (!normals.valid()) { + return; + } + + IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector); + + if (normals.getScope() == kFacevaryingScope) { + abc_data.face_normals = normsamp.getVals(); + } + else if ((normals.getScope() == kVertexScope) || (normals.getScope() == kVaryingScope)) { + abc_data.vertex_normals = N3fArraySamplePtr(); + } } static bool check_smooth_poly_flag(Mesh *mesh) { - MPoly *mpolys = mesh->mpoly; + MPoly *mpolys = mesh->mpoly; - for (int i = 0, e = mesh->totpoly; i < e; ++i) { - MPoly &poly = mpolys[i]; + for (int i = 0, e = mesh->totpoly; i < e; ++i) { + MPoly &poly = mpolys[i]; - if ((poly.flag & ME_SMOOTH) != 0) { - return true; - } - } + if ((poly.flag & ME_SMOOTH) != 0) { + return true; + } + } - return false; + return false; } static void set_smooth_poly_flag(Mesh *mesh) { - MPoly *mpolys = mesh->mpoly; + MPoly *mpolys = mesh->mpoly; - for (int i = 0, e = mesh->totpoly; i < e; ++i) { - MPoly &poly = mpolys[i]; - poly.flag |= ME_SMOOTH; - } + for (int i = 0, e = mesh->totpoly; i < e; ++i) { + MPoly &poly = mpolys[i]; + poly.flag |= ME_SMOOTH; + } } static void *add_customdata_cb(void *user_data, const char *name, int data_type) { - Mesh *mesh = static_cast<Mesh *>(user_data); - CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); - void *cd_ptr; - CustomData *loopdata; - int numloops; - - /* unsupported custom data type -- don't do anything. */ - if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { - return NULL; - } - - loopdata = &mesh->ldata; - cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name); - if (cd_ptr != NULL) { - /* layer already exists, so just return it. */ - return cd_ptr; - } - - /* create a new layer, taking care to construct the hopefully-soon-to-be-removed - * CD_MTEXPOLY layer too, with the same name. */ - numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, - NULL, numloops, name); - return cd_ptr; + Mesh *mesh = static_cast<Mesh *>(user_data); + CustomDataType cd_data_type = static_cast<CustomDataType>(data_type); + void *cd_ptr; + CustomData *loopdata; + int numloops; + + /* unsupported custom data type -- don't do anything. */ + if (!ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { + return NULL; + } + + loopdata = &mesh->ldata; + cd_ptr = CustomData_get_layer_named(loopdata, cd_data_type, name); + if (cd_ptr != NULL) { + /* layer already exists, so just return it. */ + return cd_ptr; + } + + /* create a new layer, taking care to construct the hopefully-soon-to-be-removed + * CD_MTEXPOLY layer too, with the same name. */ + numloops = mesh->totloop; + cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_DEFAULT, NULL, numloops, name); + return cd_ptr; } static void get_weight_and_index(CDStreamConfig &config, Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling, size_t samples_number) { - Alembic::AbcGeom::index_t i0, i1; + Alembic::AbcGeom::index_t i0, i1; - config.weight = get_weight_and_index(config.time, - time_sampling, - samples_number, - i0, - i1); + config.weight = get_weight_and_index(config.time, time_sampling, samples_number, i0, i1); - config.index = i0; - config.ceil_index = i1; + config.index = i0; + config.ceil_index = i1; } -static void read_mesh_sample(const std::string & iobject_full_name, +static void read_mesh_sample(const std::string &iobject_full_name, ImportSettings *settings, const IPolyMeshSchema &schema, const ISampleSelector &selector, CDStreamConfig &config, bool &do_normals) { - const IPolyMeshSchema::Sample sample = schema.getValue(selector); + const IPolyMeshSchema::Sample sample = schema.getValue(selector); - AbcMeshData abc_mesh_data; - abc_mesh_data.face_counts = sample.getFaceCounts(); - abc_mesh_data.face_indices = sample.getFaceIndices(); - abc_mesh_data.positions = sample.getPositions(); + AbcMeshData abc_mesh_data; + abc_mesh_data.face_counts = sample.getFaceCounts(); + abc_mesh_data.face_indices = sample.getFaceIndices(); + abc_mesh_data.positions = sample.getPositions(); - read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); + read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); - do_normals = (abc_mesh_data.face_normals != NULL); + do_normals = (abc_mesh_data.face_normals != NULL); - get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); + get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); - if (config.weight != 0.0f) { - Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; - schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); - abc_mesh_data.ceil_positions = ceil_sample.getPositions(); - } + if (config.weight != 0.0f) { + Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; + schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); + abc_mesh_data.ceil_positions = ceil_sample.getPositions(); + } - if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { - read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); - } + if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { + read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); + } - if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { - read_mverts(config, abc_mesh_data); - } + if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { + read_mverts(config, abc_mesh_data); + } - if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { - read_mpolys(config, abc_mesh_data); - } + if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { + read_mpolys(config, abc_mesh_data); + } - if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(iobject_full_name, - schema.getArbGeomParams(), config, selector); - } + if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { + read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); + } } CDStreamConfig get_config(Mesh *mesh) { - CDStreamConfig config; + CDStreamConfig config; - BLI_assert(mesh->mvert || mesh->totvert == 0); + BLI_assert(mesh->mvert || mesh->totvert == 0); - config.user_data = mesh; - config.mvert = mesh->mvert; - config.mloop = mesh->mloop; - config.mpoly = mesh->mpoly; - config.totloop = mesh->totloop; - config.totpoly = mesh->totpoly; - config.loopdata = &mesh->ldata; - config.add_customdata_cb = add_customdata_cb; + config.user_data = mesh; + config.mvert = mesh->mvert; + config.mloop = mesh->mloop; + config.mpoly = mesh->mpoly; + config.totloop = mesh->totloop; + config.totpoly = mesh->totpoly; + config.loopdata = &mesh->ldata; + config.add_customdata_cb = add_customdata_cb; - return config; + return config; } /* ************************************************************************** */ @@ -1043,57 +1047,60 @@ CDStreamConfig get_config(Mesh *mesh) AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; + m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; - IPolyMesh ipoly_mesh(m_iobject, kWrapExisting); - m_schema = ipoly_mesh.getSchema(); + IPolyMesh ipoly_mesh(m_iobject, kWrapExisting); + m_schema = ipoly_mesh.getSchema(); - get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); + get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); } bool AbcMeshReader::valid() const { - return m_schema.valid(); + return m_schema.valid(); } void AbcMeshReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) { - Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); + Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); - m_object->data = mesh; + m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); + m_object->data = mesh; - Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); - if (read_mesh != mesh) { - BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); - } + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + if (read_mesh != mesh) { + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); + } - if (m_settings->validate_meshes) { - BKE_mesh_validate(mesh, false, false); - } + if (m_settings->validate_meshes) { + BKE_mesh_validate(mesh, false, false); + } - readFaceSetsSample(bmain, mesh, 0, sample_sel); + readFaceSetsSample(bmain, mesh, 0, sample_sel); - if (has_animations(m_schema, m_settings)) { - addCacheModifier(); - } + if (has_animations(m_schema, m_settings)) { + addCacheModifier(); + } } -bool AbcMeshReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const +bool AbcMeshReader::accepts_object_type( + const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const { - if (!Alembic::AbcGeom::IPolyMesh::matches(alembic_header)) { - *err_str = "Object type mismatch, Alembic object path pointed to PolyMesh when importing, but not any more."; - return false; - } - - if (ob->type != OB_MESH) { - *err_str = "Object type mismatch, Alembic object path points to PolyMesh."; - return false; - } - - return true; + if (!Alembic::AbcGeom::IPolyMesh::matches(alembic_header)) { + *err_str = + "Object type mismatch, Alembic object path pointed to PolyMesh when importing, but not " + "any more."; + return false; + } + + if (ob->type != OB_MESH) { + *err_str = "Object type mismatch, Alembic object path points to PolyMesh."; + return false; + } + + return true; } Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, @@ -1101,209 +1108,202 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, int read_flag, const char **err_str) { - IPolyMeshSchema::Sample sample; - try { - sample = m_schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - *err_str = "Error reading mesh sample; more detail on the console"; - printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - m_schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return existing_mesh; - } - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - Mesh *new_mesh = NULL; - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - ImportSettings settings; - settings.read_flag |= read_flag; - - bool topology_changed = positions->size() != existing_mesh->totvert || - face_counts->size() != existing_mesh->totpoly || - face_indices->size() != existing_mesh->totloop; - if (topology_changed) { - new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - 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() != existing_mesh->totpoly || - face_indices->size() != existing_mesh->totloop) - { - 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_mesh ? new_mesh : existing_mesh); - config.time = sample_sel.getRequestedTime(); - - bool do_normals = false; - read_mesh_sample(m_iobject.getFullName(), - &settings, m_schema, sample_sel, config, do_normals); - - if (new_mesh) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (!do_normals && check_smooth_poly_flag(existing_mesh)) { - set_smooth_poly_flag(new_mesh); - } - - BKE_mesh_calc_normals(new_mesh); - BKE_mesh_calc_edges(new_mesh, false, false); - - /* Here we assume that the number of materials doesn't change, i.e. that - * the material slots that were created when the object was loaded from - * Alembic are still valid now. */ - size_t num_polys = new_mesh->totpoly; - if (num_polys > 0) { - std::map<std::string, int> mat_map; - assign_facesets_to_mpoly(sample_sel, 0, new_mesh->mpoly, num_polys, mat_map); - } - - return new_mesh; - } - - if (do_normals) { - BKE_mesh_calc_normals(existing_mesh); - } - - return existing_mesh; + IPolyMeshSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + *err_str = "Error reading mesh sample; more detail on the console"; + printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + Mesh *new_mesh = NULL; + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + ImportSettings settings; + settings.read_flag |= read_flag; + + bool topology_changed = positions->size() != existing_mesh->totvert || + face_counts->size() != existing_mesh->totpoly || + face_indices->size() != existing_mesh->totloop; + if (topology_changed) { + new_mesh = BKE_mesh_new_nomain_from_template( + existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); + + 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() != existing_mesh->totpoly || + face_indices->size() != existing_mesh->totloop) { + 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_mesh ? new_mesh : existing_mesh); + config.time = sample_sel.getRequestedTime(); + + bool do_normals = false; + read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config, do_normals); + + if (new_mesh) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (!do_normals && check_smooth_poly_flag(existing_mesh)) { + set_smooth_poly_flag(new_mesh); + } + + BKE_mesh_calc_normals(new_mesh); + BKE_mesh_calc_edges(new_mesh, false, false); + + /* Here we assume that the number of materials doesn't change, i.e. that + * the material slots that were created when the object was loaded from + * Alembic are still valid now. */ + size_t num_polys = new_mesh->totpoly; + if (num_polys > 0) { + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(sample_sel, 0, new_mesh->mpoly, num_polys, mat_map); + } + + return new_mesh; + } + + if (do_normals) { + BKE_mesh_calc_normals(existing_mesh); + } + + return existing_mesh; } -void AbcMeshReader::assign_facesets_to_mpoly( - const ISampleSelector &sample_sel, - size_t poly_start, - MPoly *mpoly, int totpoly, - std::map<std::string, int> & r_mat_map) +void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, + size_t poly_start, + MPoly *mpoly, + int totpoly, + std::map<std::string, int> &r_mat_map) { - std::vector<std::string> face_sets; - m_schema.getFaceSetNames(face_sets); - - if (face_sets.empty()) { - return; - } + std::vector<std::string> face_sets; + m_schema.getFaceSetNames(face_sets); - int current_mat = 0; + if (face_sets.empty()) { + return; + } - for (int i = 0; i < face_sets.size(); ++i) { - const std::string &grp_name = face_sets[i]; + int current_mat = 0; - if (r_mat_map.find(grp_name) == r_mat_map.end()) { - r_mat_map[grp_name] = 1 + current_mat++; - } + for (int i = 0; i < face_sets.size(); ++i) { + const std::string &grp_name = face_sets[i]; - const int assigned_mat = r_mat_map[grp_name]; + if (r_mat_map.find(grp_name) == r_mat_map.end()) { + r_mat_map[grp_name] = 1 + current_mat++; + } - const IFaceSet faceset = m_schema.getFaceSet(grp_name); + const int assigned_mat = r_mat_map[grp_name]; - if (!faceset.valid()) { - std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n"; - continue; - } + const IFaceSet faceset = m_schema.getFaceSet(grp_name); - const IFaceSetSchema face_schem = faceset.getSchema(); - const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel); - const Int32ArraySamplePtr group_faces = face_sample.getFaces(); - const size_t num_group_faces = group_faces->size(); + if (!faceset.valid()) { + std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n"; + continue; + } - for (size_t l = 0; l < num_group_faces; l++) { - size_t pos = (*group_faces)[l] + poly_start; + const IFaceSetSchema face_schem = faceset.getSchema(); + const IFaceSetSchema::Sample face_sample = face_schem.getValue(sample_sel); + const Int32ArraySamplePtr group_faces = face_sample.getFaces(); + const size_t num_group_faces = group_faces->size(); - if (pos >= totpoly) { - std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; - break; - } + for (size_t l = 0; l < num_group_faces; l++) { + size_t pos = (*group_faces)[l] + poly_start; - MPoly &poly = mpoly[pos]; - poly.mat_nr = assigned_mat - 1; - } - } + if (pos >= totpoly) { + std::cerr << "Faceset overflow on " << faceset.getName() << '\n'; + break; + } + MPoly &poly = mpoly[pos]; + poly.mat_nr = assigned_mat - 1; + } + } } -void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, +void AbcMeshReader::readFaceSetsSample(Main *bmain, + Mesh *mesh, + size_t poly_start, const ISampleSelector &sample_sel) { - std::map<std::string, int> mat_map; - assign_facesets_to_mpoly(sample_sel, - poly_start, mesh->mpoly, mesh->totpoly, - mat_map); - utils::assign_materials(bmain, m_object, mat_map); + std::map<std::string, int> mat_map; + assign_facesets_to_mpoly(sample_sel, poly_start, mesh->mpoly, mesh->totpoly, mat_map); + utils::assign_materials(bmain, m_object, mat_map); } /* ************************************************************************** */ ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) { - for (int i = 0, e = totedge; i < e; ++i) { - MEdge &edge = edges[i]; + for (int i = 0, e = totedge; i < e; ++i) { + MEdge &edge = edges[i]; - if (edge.v1 == v1 && edge.v2 == v2) { - return &edge; - } - } + if (edge.v1 == v1 && edge.v2 == v2) { + return &edge; + } + } - return NULL; + return NULL; } -static void read_subd_sample(const std::string & iobject_full_name, +static void read_subd_sample(const std::string &iobject_full_name, ImportSettings *settings, const ISubDSchema &schema, const ISampleSelector &selector, CDStreamConfig &config) { - const ISubDSchema::Sample sample = schema.getValue(selector); - - AbcMeshData abc_mesh_data; - abc_mesh_data.face_counts = sample.getFaceCounts(); - abc_mesh_data.face_indices = sample.getFaceIndices(); - abc_mesh_data.vertex_normals = N3fArraySamplePtr(); - abc_mesh_data.face_normals = N3fArraySamplePtr(); - abc_mesh_data.positions = sample.getPositions(); - - get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); - - if (config.weight != 0.0f) { - Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; - schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); - abc_mesh_data.ceil_positions = ceil_sample.getPositions(); - } - - if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { - read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); - } - - if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { - read_mverts(config, abc_mesh_data); - } - - if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { - read_mpolys(config, abc_mesh_data); - } - - if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(iobject_full_name, - schema.getArbGeomParams(), config, selector); - } + const ISubDSchema::Sample sample = schema.getValue(selector); + + AbcMeshData abc_mesh_data; + abc_mesh_data.face_counts = sample.getFaceCounts(); + abc_mesh_data.face_indices = sample.getFaceIndices(); + abc_mesh_data.vertex_normals = N3fArraySamplePtr(); + abc_mesh_data.face_normals = N3fArraySamplePtr(); + abc_mesh_data.positions = sample.getPositions(); + + get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); + + if (config.weight != 0.0f) { + Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; + schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); + abc_mesh_data.ceil_positions = ceil_sample.getPositions(); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { + read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { + read_mverts(config, abc_mesh_data); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { + read_mpolys(config, abc_mesh_data); + } + + if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { + read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); + } } /* ************************************************************************** */ @@ -1311,88 +1311,91 @@ static void read_subd_sample(const std::string & iobject_full_name, AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; + m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; - ISubD isubd_mesh(m_iobject, kWrapExisting); - m_schema = isubd_mesh.getSchema(); + ISubD isubd_mesh(m_iobject, kWrapExisting); + m_schema = isubd_mesh.getSchema(); - get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); + get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); } bool AbcSubDReader::valid() const { - return m_schema.valid(); + return m_schema.valid(); } -bool AbcSubDReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const +bool AbcSubDReader::accepts_object_type( + const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const { - if (!Alembic::AbcGeom::ISubD::matches(alembic_header)) { - *err_str = "Object type mismatch, Alembic object path pointed to SubD when importing, but not any more."; - return false; - } - - if (ob->type != OB_MESH) { - *err_str = "Object type mismatch, Alembic object path points to SubD."; - return false; - } - - return true; + if (!Alembic::AbcGeom::ISubD::matches(alembic_header)) { + *err_str = + "Object type mismatch, Alembic object path pointed to SubD when importing, but not any " + "more."; + return false; + } + + if (ob->type != OB_MESH) { + *err_str = "Object type mismatch, Alembic object path points to SubD."; + return false; + } + + return true; } void AbcSubDReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) { - Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - - m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); - m_object->data = mesh; - - Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); - if (read_mesh != mesh) { - BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); - } - - ISubDSchema::Sample sample; - try { - sample = m_schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - m_schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return; - } - - Int32ArraySamplePtr indices = sample.getCreaseIndices(); - Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); - - MEdge *edges = mesh->medge; - - if (indices && sharpnesses) { - for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) { - MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]); - - if (edge) { - edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]); - } - } - - mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; - } - - BKE_mesh_calc_normals(mesh); - BKE_mesh_calc_edges(mesh, false, false); - - if (m_settings->validate_meshes) { - BKE_mesh_validate(mesh, false, false); - } - - if (has_animations(m_schema, m_settings)) { - addCacheModifier(); - } + Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); + + m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); + m_object->data = mesh; + + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, MOD_MESHSEQ_READ_ALL, NULL); + if (read_mesh != mesh) { + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); + } + + ISubDSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return; + } + + Int32ArraySamplePtr indices = sample.getCreaseIndices(); + Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); + + MEdge *edges = mesh->medge; + + if (indices && sharpnesses) { + for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, ++s) { + MEdge *edge = find_edge(edges, mesh->totedge, (*indices)[i], (*indices)[i + 1]); + + if (edge) { + edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]); + } + } + + mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; + } + + BKE_mesh_calc_normals(mesh); + BKE_mesh_calc_edges(mesh, false, false); + + if (m_settings->validate_meshes) { + BKE_mesh_validate(mesh, false, false); + } + + if (has_animations(m_schema, m_settings)) { + addCacheModifier(); + } } Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, @@ -1400,72 +1403,67 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, int read_flag, const char **err_str) { - ISubDSchema::Sample sample; - try { - sample = m_schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - *err_str = "Error reading mesh sample; more detail on the console"; - printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - m_schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return existing_mesh; - } - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - Mesh *new_mesh = NULL; - - ImportSettings settings; - settings.read_flag |= read_flag; - - if (existing_mesh->totvert != positions->size()) { - new_mesh = BKE_mesh_new_nomain_from_template(existing_mesh, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - 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() != existing_mesh->totpoly || - face_indices->size() != existing_mesh->totpoly) - { - 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_mesh ? new_mesh : existing_mesh); - config.time = sample_sel.getRequestedTime(); - read_subd_sample(m_iobject.getFullName(), - &settings, m_schema, sample_sel, config); - - if (new_mesh) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (check_smooth_poly_flag(existing_mesh)) { - set_smooth_poly_flag(new_mesh); - } - - BKE_mesh_calc_normals(new_mesh); - BKE_mesh_calc_edges(new_mesh, false, false); - - return new_mesh; - } - - return existing_mesh; + ISubDSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + *err_str = "Error reading mesh sample; more detail on the console"; + printf("Alembic: error reading mesh sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + Mesh *new_mesh = NULL; + + ImportSettings settings; + settings.read_flag |= read_flag; + + if (existing_mesh->totvert != positions->size()) { + new_mesh = BKE_mesh_new_nomain_from_template( + existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size()); + + 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() != existing_mesh->totpoly || + face_indices->size() != existing_mesh->totpoly) { + 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_mesh ? new_mesh : existing_mesh); + config.time = sample_sel.getRequestedTime(); + read_subd_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); + + if (new_mesh) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (check_smooth_poly_flag(existing_mesh)) { + set_smooth_poly_flag(new_mesh); + } + + BKE_mesh_calc_normals(new_mesh); + BKE_mesh_calc_edges(new_mesh, false, false); + + return new_mesh; + } + + return existing_mesh; } diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 35ad0f8b297..6cbaeea6536 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -31,117 +31,118 @@ struct ModifierData; /* Writer for Alembic meshes. Does not assume the object is a mesh object. */ class AbcGenericMeshWriter : public AbcObjectWriter { -protected: - Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema; - Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample; + protected: + Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema; + Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample; - Alembic::AbcGeom::OSubDSchema m_subdiv_schema; - Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample; + Alembic::AbcGeom::OSubDSchema m_subdiv_schema; + Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample; - Alembic::Abc::OArrayProperty m_mat_indices; + Alembic::Abc::OArrayProperty m_mat_indices; - bool m_is_animated; - ModifierData *m_subsurf_mod; + bool m_is_animated; + ModifierData *m_subsurf_mod; - CDStreamConfig m_custom_data_config; + CDStreamConfig m_custom_data_config; - bool m_is_liquid; - bool m_is_subd; + bool m_is_liquid; + bool m_is_subd; -public: - AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + public: + AbcGenericMeshWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); - ~AbcGenericMeshWriter(); - void setIsAnimated(bool is_animated); + ~AbcGenericMeshWriter(); + void setIsAnimated(bool is_animated); -protected: - virtual void do_write(); - virtual bool isAnimated() const; - virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) = 0; - virtual void freeEvaluatedMesh(struct Mesh *mesh); + protected: + virtual void do_write(); + virtual bool isAnimated() const; + virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) = 0; + virtual void freeEvaluatedMesh(struct Mesh *mesh); - Mesh *getFinalMesh(bool &r_needsfree); + Mesh *getFinalMesh(bool &r_needsfree); - void writeMesh(struct Mesh *mesh); - void writeSubD(struct Mesh *mesh); + void writeMesh(struct Mesh *mesh); + void writeSubD(struct Mesh *mesh); - void writeArbGeoParams(struct Mesh *mesh); - void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t>> &geoGroups); + void writeArbGeoParams(struct Mesh *mesh); + void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t>> &geoGroups); - /* fluid surfaces support */ - void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels); + /* fluid surfaces support */ + void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels); - template <typename Schema> - void writeFaceSets(struct Mesh *mesh, Schema &schema); + template<typename Schema> void writeFaceSets(struct Mesh *mesh, Schema &schema); }; - class AbcMeshWriter : public AbcGenericMeshWriter { -public: - AbcMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcMeshWriter(); -protected: - virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; -}; + public: + AbcMeshWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); + ~AbcMeshWriter(); + + protected: + virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; +}; /* ************************************************************************** */ class AbcMeshReader : public AbcObjectReader { - Alembic::AbcGeom::IPolyMeshSchema m_schema; - - CDStreamConfig m_mesh_data; - -public: - AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - - bool valid() const; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - - struct Mesh *read_mesh(struct Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); - -private: - void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, - const Alembic::AbcGeom::ISampleSelector &sample_sel); - - void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, - size_t poly_start, - MPoly *mpoly, int totpoly, - std::map<std::string, int> & r_mat_map); + Alembic::AbcGeom::IPolyMeshSchema m_schema; + + CDStreamConfig m_mesh_data; + + public: + AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + + bool valid() const; + bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const; + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); + + private: + void readFaceSetsSample(Main *bmain, + Mesh *mesh, + size_t poly_start, + const Alembic::AbcGeom::ISampleSelector &sample_sel); + + void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, + size_t poly_start, + MPoly *mpoly, + int totpoly, + std::map<std::string, int> &r_mat_map); }; /* ************************************************************************** */ class AbcSubDReader : public AbcObjectReader { - Alembic::AbcGeom::ISubDSchema m_schema; - - CDStreamConfig m_mesh_data; - -public: - AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - - bool valid() const; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - struct Mesh *read_mesh(struct Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + Alembic::AbcGeom::ISubDSchema m_schema; + + CDStreamConfig m_mesh_data; + + public: + AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + + bool valid() const; + bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const; + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); }; /* ************************************************************************** */ @@ -152,4 +153,4 @@ void read_mverts(MVert *mverts, CDStreamConfig get_config(struct Mesh *mesh); -#endif /* __ABC_MESH_H__ */ +#endif /* __ABC_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc index 463396c0b65..c78cc4570c9 100644 --- a/source/blender/alembic/intern/abc_nurbs.cc +++ b/source/blender/alembic/intern/abc_nurbs.cc @@ -40,9 +40,9 @@ extern "C" { using Alembic::AbcGeom::bool_t; using Alembic::AbcGeom::FloatArraySample; using Alembic::AbcGeom::FloatArraySamplePtr; +using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::MetaData; using Alembic::AbcGeom::P3fArraySamplePtr; -using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::IBoolProperty; using Alembic::AbcGeom::ICompoundProperty; @@ -64,132 +64,132 @@ AbcNurbsWriter::AbcNurbsWriter(Object *ob, ExportSettings &settings) : AbcObjectWriter(ob, time_sampling, settings, parent) { - m_is_animated = isAnimated(); + m_is_animated = isAnimated(); - /* if the object is static, use the default static time sampling */ - if (!m_is_animated) { - m_time_sampling = 0; - } + /* if the object is static, use the default static time sampling */ + if (!m_is_animated) { + m_time_sampling = 0; + } - Curve *curve = static_cast<Curve *>(m_object->data); - size_t numNurbs = BLI_listbase_count(&curve->nurb); + Curve *curve = static_cast<Curve *>(m_object->data); + size_t numNurbs = BLI_listbase_count(&curve->nurb); - for (size_t i = 0; i < numNurbs; ++i) { - std::stringstream str; - str << m_name << '_' << i; + for (size_t i = 0; i < numNurbs; ++i) { + std::stringstream str; + str << m_name << '_' << i; - while (parent->alembicXform().getChildHeader(str.str())) { - str << "_"; - } + while (parent->alembicXform().getChildHeader(str.str())) { + str << "_"; + } - ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling); - m_nurbs_schema.push_back(nurbs.getSchema()); - } + ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling); + m_nurbs_schema.push_back(nurbs.getSchema()); + } } bool AbcNurbsWriter::isAnimated() const { - /* check if object has shape keys */ - Curve *cu = static_cast<Curve *>(m_object->data); - return (cu->key != NULL); + /* check if object has shape keys */ + Curve *cu = static_cast<Curve *>(m_object->data); + return (cu->key != NULL); } static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots) { - if (num_knots <= 1) { - return; - } + if (num_knots <= 1) { + return; + } - /* Add an extra knot at the beginning and end of the array since most apps - * require/expect them. */ - knots.reserve(num_knots + 2); + /* Add an extra knot at the beginning and end of the array since most apps + * require/expect them. */ + knots.reserve(num_knots + 2); - knots.push_back(0.0f); + knots.push_back(0.0f); - for (int i = 0; i < num_knots; ++i) { - knots.push_back(nu_knots[i]); - } + for (int i = 0; i < num_knots; ++i) { + knots.push_back(nu_knots[i]); + } - knots[0] = 2.0f * knots[1] - knots[2]; - knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]); + knots[0] = 2.0f * knots[1] - knots[2]; + knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]); } void AbcNurbsWriter::do_write() { - /* we have already stored a sample for this object. */ - if (!m_first_frame && !m_is_animated) { - return; - } - - if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) { - return; - } - - Curve *curve = static_cast<Curve *>(m_object->data); - ListBase *nulb; - - if (m_object->runtime.curve_cache->deformed_nurbs.first != NULL) { - nulb = &m_object->runtime.curve_cache->deformed_nurbs; - } - else { - nulb = BKE_curve_nurbs_get(curve); - } - - size_t count = 0; - for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) { - std::vector<float> knotsU; - get_knots(knotsU, KNOTSU(nu), nu->knotsu); - - std::vector<float> knotsV; - get_knots(knotsV, KNOTSV(nu), nu->knotsv); - - const int size = nu->pntsu * nu->pntsv; - std::vector<Imath::V3f> positions(size); - std::vector<float> weights(size); - - const BPoint *bp = nu->bp; - - for (int i = 0; i < size; ++i, ++bp) { - copy_yup_from_zup(positions[i].getValue(), bp->vec); - weights[i] = bp->vec[3]; - } - - ONuPatchSchema::Sample sample; - sample.setUOrder(nu->orderu + 1); - sample.setVOrder(nu->orderv + 1); - sample.setPositions(positions); - sample.setPositionWeights(weights); - sample.setUKnot(FloatArraySample(knotsU)); - sample.setVKnot(FloatArraySample(knotsV)); - sample.setNu(nu->pntsu); - sample.setNv(nu->pntsv); - - /* TODO(kevin): to accommodate other software we should duplicate control - * points to indicate that a NURBS is cyclic. */ - OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties(); - - if ((nu->flagu & CU_NURB_ENDPOINT) != 0) { - OBoolProperty prop(user_props, "endpoint_u"); - prop.set(true); - } - - if ((nu->flagv & CU_NURB_ENDPOINT) != 0) { - OBoolProperty prop(user_props, "endpoint_v"); - prop.set(true); - } - - if ((nu->flagu & CU_NURB_CYCLIC) != 0) { - OBoolProperty prop(user_props, "cyclic_u"); - prop.set(true); - } - - if ((nu->flagv & CU_NURB_CYCLIC) != 0) { - OBoolProperty prop(user_props, "cyclic_v"); - prop.set(true); - } - - m_nurbs_schema[count].set(sample); - } + /* we have already stored a sample for this object. */ + if (!m_first_frame && !m_is_animated) { + return; + } + + if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) { + return; + } + + Curve *curve = static_cast<Curve *>(m_object->data); + ListBase *nulb; + + if (m_object->runtime.curve_cache->deformed_nurbs.first != NULL) { + nulb = &m_object->runtime.curve_cache->deformed_nurbs; + } + else { + nulb = BKE_curve_nurbs_get(curve); + } + + size_t count = 0; + for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) { + std::vector<float> knotsU; + get_knots(knotsU, KNOTSU(nu), nu->knotsu); + + std::vector<float> knotsV; + get_knots(knotsV, KNOTSV(nu), nu->knotsv); + + const int size = nu->pntsu * nu->pntsv; + std::vector<Imath::V3f> positions(size); + std::vector<float> weights(size); + + const BPoint *bp = nu->bp; + + for (int i = 0; i < size; ++i, ++bp) { + copy_yup_from_zup(positions[i].getValue(), bp->vec); + weights[i] = bp->vec[3]; + } + + ONuPatchSchema::Sample sample; + sample.setUOrder(nu->orderu + 1); + sample.setVOrder(nu->orderv + 1); + sample.setPositions(positions); + sample.setPositionWeights(weights); + sample.setUKnot(FloatArraySample(knotsU)); + sample.setVKnot(FloatArraySample(knotsV)); + sample.setNu(nu->pntsu); + sample.setNv(nu->pntsv); + + /* TODO(kevin): to accommodate other software we should duplicate control + * points to indicate that a NURBS is cyclic. */ + OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties(); + + if ((nu->flagu & CU_NURB_ENDPOINT) != 0) { + OBoolProperty prop(user_props, "endpoint_u"); + prop.set(true); + } + + if ((nu->flagv & CU_NURB_ENDPOINT) != 0) { + OBoolProperty prop(user_props, "endpoint_v"); + prop.set(true); + } + + if ((nu->flagu & CU_NURB_CYCLIC) != 0) { + OBoolProperty prop(user_props, "cyclic_u"); + prop.set(true); + } + + if ((nu->flagv & CU_NURB_CYCLIC) != 0) { + OBoolProperty prop(user_props, "cyclic_v"); + prop.set(true); + } + + m_nurbs_schema[count].set(sample); + } } /* ************************************************************************** */ @@ -197,179 +197,178 @@ void AbcNurbsWriter::do_write() AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - getNurbsPatches(m_iobject); - get_min_max_time(m_iobject, m_schemas[0].first, m_min_time, m_max_time); + getNurbsPatches(m_iobject); + get_min_max_time(m_iobject, m_schemas[0].first, m_min_time, m_max_time); } bool AbcNurbsReader::valid() const { - if (m_schemas.empty()) { - return false; - } + if (m_schemas.empty()) { + return false; + } - std::vector<std::pair<INuPatchSchema, IObject>>::const_iterator it; - for (it = m_schemas.begin(); it != m_schemas.end(); ++it) { - const INuPatchSchema &schema = it->first; + std::vector<std::pair<INuPatchSchema, IObject>>::const_iterator it; + for (it = m_schemas.begin(); it != m_schemas.end(); ++it) { + const INuPatchSchema &schema = it->first; - if (!schema.valid()) { - return false; - } - } + if (!schema.valid()) { + return false; + } + } - return true; + return true; } static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots) { - if (!knots || knots->size() == 0) { - return false; - } + if (!knots || knots->size() == 0) { + return false; + } - /* Skip first and last knots, as they are used for padding. */ - const size_t num_knots = knots->size() - 2; - nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu")); + /* Skip first and last knots, as they are used for padding. */ + const size_t num_knots = knots->size() - 2; + nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu")); - for (size_t i = 0; i < num_knots; ++i) { - nu_knots[i] = (*knots)[i + 1]; - } + for (size_t i = 0; i < num_knots; ++i) { + nu_knots[i] = (*knots)[i + 1]; + } - return true; + return true; } void AbcNurbsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) { - Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF)); - cu->actvert = CU_ACT_NONE; - - std::vector<std::pair<INuPatchSchema, IObject>>::iterator it; + Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF)); + cu->actvert = CU_ACT_NONE; - for (it = m_schemas.begin(); it != m_schemas.end(); ++it) { - Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb")); - nu->flag = CU_SMOOTH; - nu->type = CU_NURBS; - nu->resolu = cu->resolu; - nu->resolv = cu->resolv; + std::vector<std::pair<INuPatchSchema, IObject>>::iterator it; - const INuPatchSchema &schema = it->first; - INuPatchSchema::Sample smp; - try { - smp = schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - printf("Alembic: error reading nurbs sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return; - } + for (it = m_schemas.begin(); it != m_schemas.end(); ++it) { + Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb")); + nu->flag = CU_SMOOTH; + nu->type = CU_NURBS; + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + const INuPatchSchema &schema = it->first; + INuPatchSchema::Sample smp; + try { + smp = schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + printf("Alembic: error reading nurbs sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return; + } - nu->orderu = smp.getUOrder() - 1; - nu->orderv = smp.getVOrder() - 1; - nu->pntsu = smp.getNumU(); - nu->pntsv = smp.getNumV(); + nu->orderu = smp.getUOrder() - 1; + nu->orderv = smp.getVOrder() - 1; + nu->pntsu = smp.getNumU(); + nu->pntsv = smp.getNumV(); - /* Read positions and weights. */ + /* Read positions and weights. */ - const P3fArraySamplePtr positions = smp.getPositions(); - const FloatArraySamplePtr weights = smp.getPositionWeights(); + const P3fArraySamplePtr positions = smp.getPositions(); + const FloatArraySamplePtr weights = smp.getPositionWeights(); - const size_t num_points = positions->size(); + const size_t num_points = positions->size(); - nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype")); + nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype")); - BPoint *bp = nu->bp; - float posw_in = 1.0f; + BPoint *bp = nu->bp; + float posw_in = 1.0f; - for (int i = 0; i < num_points; ++i, ++bp) { - const Imath::V3f &pos_in = (*positions)[i]; + for (int i = 0; i < num_points; ++i, ++bp) { + const Imath::V3f &pos_in = (*positions)[i]; - if (weights) { - posw_in = (*weights)[i]; - } + if (weights) { + posw_in = (*weights)[i]; + } - copy_zup_from_yup(bp->vec, pos_in.getValue()); - bp->vec[3] = posw_in; - bp->f1 = SELECT; - bp->radius = 1.0f; - bp->weight = 1.0f; - } + copy_zup_from_yup(bp->vec, pos_in.getValue()); + bp->vec[3] = posw_in; + bp->f1 = SELECT; + bp->radius = 1.0f; + bp->weight = 1.0f; + } - /* Read knots. */ + /* Read knots. */ - if (!set_knots(smp.getUKnot(), nu->knotsu)) { - BKE_nurb_knot_calc_u(nu); - } + if (!set_knots(smp.getUKnot(), nu->knotsu)) { + BKE_nurb_knot_calc_u(nu); + } - if (!set_knots(smp.getVKnot(), nu->knotsv)) { - BKE_nurb_knot_calc_v(nu); - } + if (!set_knots(smp.getVKnot(), nu->knotsv)) { + BKE_nurb_knot_calc_v(nu); + } - /* Read flags. */ + /* Read flags. */ - ICompoundProperty user_props = schema.getUserProperties(); + ICompoundProperty user_props = schema.getUserProperties(); - if (has_property(user_props, "enpoint_u")) { - nu->flagu |= CU_NURB_ENDPOINT; - } + if (has_property(user_props, "enpoint_u")) { + nu->flagu |= CU_NURB_ENDPOINT; + } - if (has_property(user_props, "enpoint_v")) { - nu->flagv |= CU_NURB_ENDPOINT; - } + if (has_property(user_props, "enpoint_v")) { + nu->flagv |= CU_NURB_ENDPOINT; + } - if (has_property(user_props, "cyclic_u")) { - nu->flagu |= CU_NURB_CYCLIC; - } + if (has_property(user_props, "cyclic_u")) { + nu->flagu |= CU_NURB_CYCLIC; + } - if (has_property(user_props, "cyclic_v")) { - nu->flagv |= CU_NURB_CYCLIC; - } + if (has_property(user_props, "cyclic_v")) { + nu->flagv |= CU_NURB_CYCLIC; + } - BLI_addtail(BKE_curve_nurbs_get(cu), nu); - } + BLI_addtail(BKE_curve_nurbs_get(cu), nu); + } - BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1); + BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1); - m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str()); - m_object->data = cu; + m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str()); + m_object->data = cu; } void AbcNurbsReader::getNurbsPatches(const IObject &obj) { - if (!obj.valid()) { - return; - } + if (!obj.valid()) { + return; + } - const int num_children = obj.getNumChildren(); + const int num_children = obj.getNumChildren(); - if (num_children == 0) { - INuPatch abc_nurb(obj, kWrapExisting); - INuPatchSchema schem = abc_nurb.getSchema(); - m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj)); - return; - } + if (num_children == 0) { + INuPatch abc_nurb(obj, kWrapExisting); + INuPatchSchema schem = abc_nurb.getSchema(); + m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj)); + return; + } - for (int i = 0; i < num_children; ++i) { - bool ok = true; - IObject child(obj, obj.getChildHeader(i).getName()); + for (int i = 0; i < num_children; ++i) { + bool ok = true; + IObject child(obj, obj.getChildHeader(i).getName()); - if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) { - ok = false; - } + if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) { + ok = false; + } - if (!child.valid()) { - continue; - } + if (!child.valid()) { + continue; + } - const MetaData &md = child.getMetaData(); + const MetaData &md = child.getMetaData(); - if (INuPatch::matches(md) && ok) { - INuPatch abc_nurb(child, kWrapExisting); - INuPatchSchema schem = abc_nurb.getSchema(); - m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child)); - } + if (INuPatch::matches(md) && ok) { + INuPatch abc_nurb(child, kWrapExisting); + INuPatchSchema schem = abc_nurb.getSchema(); + m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child)); + } - getNurbsPatches(child); - } + getNurbsPatches(child); + } } diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_nurbs.h index 89c54ba9c16..3e12c9a3b62 100644 --- a/source/blender/alembic/intern/abc_nurbs.h +++ b/source/blender/alembic/intern/abc_nurbs.h @@ -26,35 +26,35 @@ /* ************************************************************************** */ class AbcNurbsWriter : public AbcObjectWriter { - std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema; - bool m_is_animated; + std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema; + bool m_is_animated; -public: - AbcNurbsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + public: + AbcNurbsWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings); -private: - virtual void do_write(); + private: + virtual void do_write(); - bool isAnimated() const; + bool isAnimated() const; }; /* ************************************************************************** */ class AbcNurbsReader : public AbcObjectReader { - std::vector<std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject>> m_schemas; + std::vector<std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject>> m_schemas; -public: - AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + public: + AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - bool valid() const; + bool valid() const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); -private: - void getNurbsPatches(const Alembic::Abc::IObject &obj); + private: + void getNurbsPatches(const Alembic::Abc::IObject &obj); }; -#endif /* __ABC_NURBS_H__ */ +#endif /* __ABC_NURBS_H__ */ diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index d8bd92121aa..dddd985d796 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -27,7 +27,7 @@ extern "C" { #include "DNA_constraint_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "DNA_space_types.h" /* for FILE_MAX */ +#include "DNA_space_types.h" /* for FILE_MAX */ #include "BKE_constraint.h" #include "BKE_idprop.h" @@ -60,186 +60,182 @@ AbcObjectWriter::AbcObjectWriter(Object *ob, uint32_t time_sampling, ExportSettings &settings, AbcObjectWriter *parent) - : m_object(ob) - , m_settings(settings) - , m_time_sampling(time_sampling) - , m_first_frame(true) + : m_object(ob), m_settings(settings), m_time_sampling(time_sampling), m_first_frame(true) { - m_name = get_id_name(m_object) + "Shape"; + m_name = get_id_name(m_object) + "Shape"; - if (parent) { - parent->addChild(this); - } + if (parent) { + parent->addChild(this); + } } AbcObjectWriter::~AbcObjectWriter() -{} +{ +} void AbcObjectWriter::addChild(AbcObjectWriter *child) { - m_children.push_back(child); + m_children.push_back(child); } Imath::Box3d AbcObjectWriter::bounds() { - BoundBox *bb = BKE_object_boundbox_get(this->m_object); + BoundBox *bb = BKE_object_boundbox_get(this->m_object); - if (!bb) { - if (this->m_object->type != OB_CAMERA) { - ABC_LOG(m_settings.logger) << "Bounding box is null!\n"; - } + if (!bb) { + if (this->m_object->type != OB_CAMERA) { + ABC_LOG(m_settings.logger) << "Bounding box is null!\n"; + } - return Imath::Box3d(); - } + return Imath::Box3d(); + } - /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */ - this->m_bounds.min.x = bb->vec[0][0]; - this->m_bounds.min.y = bb->vec[0][2]; - this->m_bounds.min.z = -bb->vec[6][1]; + /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */ + this->m_bounds.min.x = bb->vec[0][0]; + this->m_bounds.min.y = bb->vec[0][2]; + this->m_bounds.min.z = -bb->vec[6][1]; - this->m_bounds.max.x = bb->vec[6][0]; - this->m_bounds.max.y = bb->vec[6][2]; - this->m_bounds.max.z = -bb->vec[0][1]; + this->m_bounds.max.x = bb->vec[6][0]; + this->m_bounds.max.y = bb->vec[6][2]; + this->m_bounds.max.z = -bb->vec[0][1]; - return this->m_bounds; + return this->m_bounds; } void AbcObjectWriter::write() { - do_write(); - m_first_frame = false; + do_write(); + m_first_frame = false; } /* ************************************************************************** */ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings) - : m_name("") - , m_object_name("") - , m_data_name("") - , m_object(NULL) - , m_iobject(object) - , m_settings(&settings) - , m_min_time(std::numeric_limits<chrono_t>::max()) - , m_max_time(std::numeric_limits<chrono_t>::min()) - , m_refcount(0) - , parent_reader(NULL) + : m_name(""), + m_object_name(""), + m_data_name(""), + m_object(NULL), + m_iobject(object), + m_settings(&settings), + m_min_time(std::numeric_limits<chrono_t>::max()), + m_max_time(std::numeric_limits<chrono_t>::min()), + m_refcount(0), + parent_reader(NULL) { - m_name = object.getFullName(); - std::vector<std::string> parts; - split(m_name, '/', parts); - - if (parts.size() >= 2) { - m_object_name = parts[parts.size() - 2]; - m_data_name = parts[parts.size() - 1]; - } - else { - m_object_name = m_data_name = parts[parts.size() - 1]; - } - - determine_inherits_xform(); + m_name = object.getFullName(); + std::vector<std::string> parts; + split(m_name, '/', parts); + + if (parts.size() >= 2) { + m_object_name = parts[parts.size() - 2]; + m_data_name = parts[parts.size() - 1]; + } + else { + m_object_name = m_data_name = parts[parts.size() - 1]; + } + + determine_inherits_xform(); } /* Determine whether we can inherit our parent's XForm */ void AbcObjectReader::determine_inherits_xform() { - m_inherits_xform = false; - - IXform ixform = xform(); - if (!ixform) { - return; - } - - const IXformSchema & schema(ixform.getSchema()); - if (!schema.valid()) { - std::cerr << "Alembic object " << ixform.getFullName() - << " has an invalid schema." << std::endl; - return; - } - - m_inherits_xform = schema.getInheritsXforms(); - - IObject ixform_parent = ixform.getParent(); - if (!ixform_parent.getParent()) { - /* The archive top object certainly is not a transform itself, so handle - * it as "no parent". */ - m_inherits_xform = false; - } - else { - m_inherits_xform = ixform_parent && m_inherits_xform; - } + m_inherits_xform = false; + + IXform ixform = xform(); + if (!ixform) { + return; + } + + const IXformSchema &schema(ixform.getSchema()); + if (!schema.valid()) { + std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema." + << std::endl; + return; + } + + m_inherits_xform = schema.getInheritsXforms(); + + IObject ixform_parent = ixform.getParent(); + if (!ixform_parent.getParent()) { + /* The archive top object certainly is not a transform itself, so handle + * it as "no parent". */ + m_inherits_xform = false; + } + else { + m_inherits_xform = ixform_parent && m_inherits_xform; + } } AbcObjectReader::~AbcObjectReader() -{} +{ +} const IObject &AbcObjectReader::iobject() const { - return m_iobject; + return m_iobject; } Object *AbcObjectReader::object() const { - return m_object; + return m_object; } void AbcObjectReader::object(Object *ob) { - m_object = ob; + m_object = ob; } static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight) { - float mat0[4][4], mat1[4][4], ret[4][4]; + float mat0[4][4], mat1[4][4], ret[4][4]; - /* Cannot use Imath::M44d::getValue() since this returns a pointer to - * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert - * the matrices manually. - */ + /* Cannot use Imath::M44d::getValue() since this returns a pointer to + * doubles and interp_m4_m4m4 expects pointers to floats. So need to convert + * the matrices manually. + */ - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - mat0[i][j] = static_cast<float>(m0[i][j]); - } - } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + mat0[i][j] = static_cast<float>(m0[i][j]); + } + } - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - mat1[i][j] = static_cast<float>(m1[i][j]); - } - } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + mat1[i][j] = static_cast<float>(m1[i][j]); + } + } - interp_m4_m4m4(ret, mat0, mat1, weight); + interp_m4_m4m4(ret, mat0, mat1, weight); - Imath::M44d m; + Imath::M44d m; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - m[i][j] = ret[i][j]; - } - } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + m[i][j] = ret[i][j]; + } + } - return m; + return m; } Imath::M44d get_matrix(const IXformSchema &schema, const float time) { - Alembic::AbcGeom::index_t i0, i1; - Alembic::AbcGeom::XformSample s0, s1; + Alembic::AbcGeom::index_t i0, i1; + Alembic::AbcGeom::XformSample s0, s1; - const float weight = get_weight_and_index(time, - schema.getTimeSampling(), - schema.getNumSamples(), - i0, - i1); + const float weight = get_weight_and_index( + time, schema.getTimeSampling(), schema.getNumSamples(), i0, i1); - schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0)); + schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0)); - if (i0 != i1) { - schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1)); - return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight); - } + if (i0 != i1) { + schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1)); + return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight); + } - return s0.getMatrix(); + return s0.getMatrix(); } struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh, @@ -247,137 +243,138 @@ struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh, int UNUSED(read_flag), const char **UNUSED(err_str)) { - return existing_mesh; + return existing_mesh; } void AbcObjectReader::setupObjectTransform(const float time) { - bool is_constant = false; + bool is_constant = false; - this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant); - invert_m4_m4(m_object->imat, m_object->obmat); + this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant); + invert_m4_m4(m_object->imat, m_object->obmat); - BKE_object_apply_mat4(m_object, m_object->obmat, false, false); + BKE_object_apply_mat4(m_object, m_object->obmat, false, false); - if (!is_constant) { - bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); - bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); - BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + if (!is_constant) { + bConstraint *con = BKE_constraint_add_for_object( + m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data); + BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); - data->cache_file = m_settings->cache_file; - id_us_plus(&data->cache_file->id); + data->cache_file = m_settings->cache_file; + id_us_plus(&data->cache_file->id); - data->reader = reinterpret_cast<CacheReader *>(this); - this->incref(); - } + data->reader = reinterpret_cast<CacheReader *>(this); + this->incref(); + } } Alembic::AbcGeom::IXform AbcObjectReader::xform() { - /* Check that we have an empty object (locator, bone head/tail...). */ - if (IXform::matches(m_iobject.getMetaData())) { - return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting); - } - - /* Check that we have an object with actual data, in which case the - * parent Alembic object should contain the transform. */ - IObject abc_parent = m_iobject.getParent(); - - /* The archive's top object can be recognised by not having a parent. */ - if (abc_parent.getParent() - && IXform::matches(abc_parent.getMetaData())) - { - return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting); - } - - /* This can happen in certain cases. For example, MeshLab exports - * point clouds without parent XForm. */ - return IXform(); + /* Check that we have an empty object (locator, bone head/tail...). */ + if (IXform::matches(m_iobject.getMetaData())) { + return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting); + } + + /* Check that we have an object with actual data, in which case the + * parent Alembic object should contain the transform. */ + IObject abc_parent = m_iobject.getParent(); + + /* The archive's top object can be recognised by not having a parent. */ + if (abc_parent.getParent() && IXform::matches(abc_parent.getMetaData())) { + return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting); + } + + /* This can happen in certain cases. For example, MeshLab exports + * point clouds without parent XForm. */ + return IXform(); } -void AbcObjectReader::read_matrix(float r_mat[4][4], const float time, - const float scale, bool &is_constant) +void AbcObjectReader::read_matrix(float r_mat[4][4], + const float time, + const float scale, + bool &is_constant) { - IXform ixform = xform(); - if (!ixform) { - unit_m4(r_mat); - is_constant = true; - return; - } - - const IXformSchema & schema(ixform.getSchema()); - if (!schema.valid()) { - std::cerr << "Alembic object " << ixform.getFullName() - << " has an invalid schema." << std::endl; - return; - } - - const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, m_object, r_mat); - - if (m_inherits_xform) { - /* In this case, the matrix in Alembic is in local coordinates, so - * convert to world matrix. To prevent us from reading and accumulating - * all parent matrices in the Alembic file, we assume that the Blender - * parent object is already updated for the current timekey, and use its - * world matrix. */ - if (m_object->parent) { - mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat); - } - else { - /* This can happen if the user deleted the parent object. */ - unit_m4(r_mat); - } - } - else { - /* Only apply scaling to root objects, parenting will propagate it. */ - float scale_mat[4][4]; - scale_m4_fl(scale_mat, scale); - scale_mat[3][3] = scale; /* scale translations too */ - mul_m4_m4m4(r_mat, r_mat, scale_mat); - } - - is_constant = schema.isConstant(); + IXform ixform = xform(); + if (!ixform) { + unit_m4(r_mat); + is_constant = true; + return; + } + + const IXformSchema &schema(ixform.getSchema()); + if (!schema.valid()) { + std::cerr << "Alembic object " << ixform.getFullName() << " has an invalid schema." + << std::endl; + return; + } + + const Imath::M44d matrix = get_matrix(schema, time); + convert_matrix(matrix, m_object, r_mat); + + if (m_inherits_xform) { + /* In this case, the matrix in Alembic is in local coordinates, so + * convert to world matrix. To prevent us from reading and accumulating + * all parent matrices in the Alembic file, we assume that the Blender + * parent object is already updated for the current timekey, and use its + * world matrix. */ + if (m_object->parent) { + mul_m4_m4m4(r_mat, m_object->parent->obmat, r_mat); + } + else { + /* This can happen if the user deleted the parent object. */ + unit_m4(r_mat); + } + } + else { + /* Only apply scaling to root objects, parenting will propagate it. */ + float scale_mat[4][4]; + scale_m4_fl(scale_mat, scale); + scale_mat[3][3] = scale; /* scale translations too */ + mul_m4_m4m4(r_mat, r_mat, scale_mat); + } + + is_constant = schema.isConstant(); } void AbcObjectReader::addCacheModifier() { - ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); - BLI_addtail(&m_object->modifiers, md); + ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); + BLI_addtail(&m_object->modifiers, md); - MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); + MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); - mcmd->cache_file = m_settings->cache_file; - id_us_plus(&mcmd->cache_file->id); + mcmd->cache_file = m_settings->cache_file; + id_us_plus(&mcmd->cache_file->id); - BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX); - mcmd->reader = reinterpret_cast<CacheReader *>(this); - this->incref(); + mcmd->reader = reinterpret_cast<CacheReader *>(this); + this->incref(); } chrono_t AbcObjectReader::minTime() const { - return m_min_time; + return m_min_time; } chrono_t AbcObjectReader::maxTime() const { - return m_max_time; + return m_max_time; } int AbcObjectReader::refcount() const { - return m_refcount; + return m_refcount; } void AbcObjectReader::incref() { - ++m_refcount; + ++m_refcount; } void AbcObjectReader::decref() { - --m_refcount; - BLI_assert(m_refcount >= 0); + --m_refcount; + BLI_assert(m_refcount >= 0); } diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index d87bfb315d9..537f24ab7d6 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -38,36 +38,36 @@ struct Object; /* ************************************************************************** */ class AbcObjectWriter { -protected: - Object *m_object; - ExportSettings &m_settings; + protected: + Object *m_object; + ExportSettings &m_settings; - uint32_t m_time_sampling; + uint32_t m_time_sampling; - Imath::Box3d m_bounds; - std::vector<AbcObjectWriter *> m_children; + Imath::Box3d m_bounds; + std::vector<AbcObjectWriter *> m_children; - std::vector<std::pair<std::string, IDProperty *>> m_props; + std::vector<std::pair<std::string, IDProperty *>> m_props; - bool m_first_frame; - std::string m_name; + bool m_first_frame; + std::string m_name; -public: - AbcObjectWriter(Object *ob, - uint32_t time_sampling, - ExportSettings &settings, - AbcObjectWriter *parent = NULL); + public: + AbcObjectWriter(Object *ob, + uint32_t time_sampling, + ExportSettings &settings, + AbcObjectWriter *parent = NULL); - virtual ~AbcObjectWriter(); + virtual ~AbcObjectWriter(); - void addChild(AbcObjectWriter *child); + void addChild(AbcObjectWriter *child); - virtual Imath::Box3d bounds(); + virtual Imath::Box3d bounds(); - void write(); + void write(); -private: - virtual void do_write() = 0; + private: + virtual void do_write() = 0; }; /* ************************************************************************** */ @@ -75,45 +75,45 @@ private: struct CacheFile; struct ImportSettings { - bool do_convert_mat; - float conversion_mat[4][4]; - - int from_up; - int from_forward; - float scale; - bool is_sequence; - bool set_frame_range; - - /* Length and frame offset of file sequences. */ - int sequence_len; - int sequence_offset; - - /* From MeshSeqCacheModifierData.read_flag */ - int read_flag; - - bool validate_meshes; - - CacheFile *cache_file; - - ImportSettings() - : do_convert_mat(false) - , from_up(0) - , from_forward(0) - , scale(1.0f) - , is_sequence(false) - , set_frame_range(false) - , sequence_len(1) - , sequence_offset(0) - , read_flag(0) - , validate_meshes(false) - , cache_file(NULL) - {} + bool do_convert_mat; + float conversion_mat[4][4]; + + int from_up; + int from_forward; + float scale; + bool is_sequence; + bool set_frame_range; + + /* Length and frame offset of file sequences. */ + int sequence_len; + int sequence_offset; + + /* From MeshSeqCacheModifierData.read_flag */ + int read_flag; + + bool validate_meshes; + + CacheFile *cache_file; + + ImportSettings() + : do_convert_mat(false), + from_up(0), + from_forward(0), + scale(1.0f), + is_sequence(false), + set_frame_range(false), + sequence_len(1), + sequence_offset(0), + read_flag(0), + validate_meshes(false), + cache_file(NULL) + { + } }; -template <typename Schema> -static bool has_animations(Schema &schema, ImportSettings *settings) +template<typename Schema> static bool has_animations(Schema &schema, ImportSettings *settings) { - return settings->is_sequence || !schema.isConstant(); + return settings->is_sequence || !schema.isConstant(); } /* ************************************************************************** */ @@ -123,81 +123,92 @@ struct Mesh; using Alembic::AbcCoreAbstract::chrono_t; class AbcObjectReader { -protected: - std::string m_name; - std::string m_object_name; - std::string m_data_name; - Object *m_object; - Alembic::Abc::IObject m_iobject; + protected: + std::string m_name; + std::string m_object_name; + std::string m_data_name; + Object *m_object; + Alembic::Abc::IObject m_iobject; - ImportSettings *m_settings; + ImportSettings *m_settings; - chrono_t m_min_time; - chrono_t m_max_time; + chrono_t m_min_time; + chrono_t m_max_time; - /* Use reference counting since the same reader may be used by multiple - * modifiers and/or constraints. */ - int m_refcount; + /* Use reference counting since the same reader may be used by multiple + * modifiers and/or constraints. */ + int m_refcount; - bool m_inherits_xform; + bool m_inherits_xform; -public: - AbcObjectReader *parent_reader; + public: + AbcObjectReader *parent_reader; -public: - explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + public: + explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - virtual ~AbcObjectReader(); + virtual ~AbcObjectReader(); - const Alembic::Abc::IObject &iobject() const; + const Alembic::Abc::IObject &iobject() const; - typedef std::vector<AbcObjectReader *> ptr_vector; + typedef std::vector<AbcObjectReader *> ptr_vector; - /** - * Returns the transform of this object. This can be the Alembic object - * itself (in case of an Empty) or it can be the parent Alembic object. - */ - virtual Alembic::AbcGeom::IXform xform(); + /** + * Returns the transform of this object. This can be the Alembic object + * itself (in case of an Empty) or it can be the parent Alembic object. + */ + virtual Alembic::AbcGeom::IXform xform(); - Object *object() const; - void object(Object *ob); + Object *object() const; + void object(Object *ob); - const std::string & name() const { return m_name; } - const std::string & object_name() const { return m_object_name; } - const std::string & data_name() const { return m_data_name; } - bool inherits_xform() const { return m_inherits_xform; } + const std::string &name() const + { + return m_name; + } + const std::string &object_name() const + { + return m_object_name; + } + const std::string &data_name() const + { + return m_data_name; + } + bool inherits_xform() const + { + return m_inherits_xform; + } - virtual bool valid() const = 0; - virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const = 0; + virtual bool valid() const = 0; + virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const = 0; - virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0; + virtual void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) = 0; - virtual struct Mesh *read_mesh(struct Mesh *mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + virtual struct Mesh *read_mesh(struct Mesh *mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); - /** Reads the object matrix and sets up an object transform if animated. */ - void setupObjectTransform(const float time); + /** Reads the object matrix and sets up an object transform if animated. */ + void setupObjectTransform(const float time); - void addCacheModifier(); + void addCacheModifier(); - chrono_t minTime() const; - chrono_t maxTime() const; + chrono_t minTime() const; + chrono_t maxTime() const; - int refcount() const; - void incref(); - void decref(); + int refcount() const; + void incref(); + void decref(); - void read_matrix(float r_mat[4][4], const float time, - const float scale, bool &is_constant); + void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant); -protected: - void determine_inherits_xform(); + protected: + void determine_inherits_xform(); }; Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); -#endif /* __ABC_OBJECT_H__ */ +#endif /* __ABC_OBJECT_H__ */ diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index bc8c1e2debb..d691087ca21 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -45,8 +45,8 @@ extern "C" { using Alembic::AbcGeom::kVertexScope; using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::P3fArraySamplePtr; using Alembic::AbcGeom::N3fArraySamplePtr; +using Alembic::AbcGeom::P3fArraySamplePtr; using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::IN3fArrayProperty; @@ -66,75 +66,75 @@ AbcPointsWriter::AbcPointsWriter(Object *ob, ParticleSystem *psys) : AbcObjectWriter(ob, time_sampling, settings, parent) { - m_psys = psys; + m_psys = psys; - OPoints points(parent->alembicXform(), psys->name, m_time_sampling); - m_schema = points.getSchema(); + OPoints points(parent->alembicXform(), psys->name, m_time_sampling); + m_schema = points.getSchema(); } void AbcPointsWriter::do_write() { - if (!m_psys) { - return; - } + if (!m_psys) { + return; + } - std::vector<Imath::V3f> points; - std::vector<Imath::V3f> velocities; - std::vector<float> widths; - std::vector<uint64_t> ids; + std::vector<Imath::V3f> points; + std::vector<Imath::V3f> velocities; + std::vector<float> widths; + std::vector<uint64_t> ids; - ParticleKey state; + ParticleKey state; - ParticleSimulationData sim; - sim.depsgraph = m_settings.depsgraph; - sim.scene = m_settings.scene; - sim.ob = m_object; - sim.psys = m_psys; + ParticleSimulationData sim; + sim.depsgraph = m_settings.depsgraph; + sim.scene = m_settings.scene; + sim.ob = m_object; + sim.psys = m_psys; - m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - uint64_t index = 0; - for (int p = 0; p < m_psys->totpart; p++) { - float pos[3], vel[3]; + uint64_t index = 0; + for (int p = 0; p < m_psys->totpart; p++) { + float pos[3], vel[3]; - if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { - continue; - } + if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { + continue; + } - state.time = DEG_get_ctime(m_settings.depsgraph); + state.time = DEG_get_ctime(m_settings.depsgraph); - if (psys_get_particle_state(&sim, p, &state, 0) == 0) { - continue; - } + if (psys_get_particle_state(&sim, p, &state, 0) == 0) { + continue; + } - /* location */ - mul_v3_m4v3(pos, m_object->imat, state.co); + /* location */ + mul_v3_m4v3(pos, m_object->imat, state.co); - /* velocity */ - sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co); + /* velocity */ + sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co); - /* Convert Z-up to Y-up. */ - points.push_back(Imath::V3f(pos[0], pos[2], -pos[1])); - velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1])); - widths.push_back(m_psys->particles[p].size); - ids.push_back(index++); - } + /* Convert Z-up to Y-up. */ + points.push_back(Imath::V3f(pos[0], pos[2], -pos[1])); + velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1])); + widths.push_back(m_psys->particles[p].size); + ids.push_back(index++); + } - if (m_psys->lattice_deform_data) { - end_latt_deform(m_psys->lattice_deform_data); - m_psys->lattice_deform_data = NULL; - } + if (m_psys->lattice_deform_data) { + end_latt_deform(m_psys->lattice_deform_data); + m_psys->lattice_deform_data = NULL; + } - Alembic::Abc::P3fArraySample psample(points); - Alembic::Abc::UInt64ArraySample idsample(ids); - Alembic::Abc::V3fArraySample vsample(velocities); - Alembic::Abc::FloatArraySample wsample_array(widths); - Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope); + Alembic::Abc::P3fArraySample psample(points); + Alembic::Abc::UInt64ArraySample idsample(ids); + Alembic::Abc::V3fArraySample vsample(velocities); + Alembic::Abc::FloatArraySample wsample_array(widths); + Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope); - m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample); - m_sample.setSelfBounds(bounds()); + m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample); + m_sample.setSelfBounds(bounds()); - m_schema.set(m_sample); + m_schema.set(m_sample); } /* ************************************************************************** */ @@ -142,75 +142,79 @@ void AbcPointsWriter::do_write() AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - IPoints ipoints(m_iobject, kWrapExisting); - m_schema = ipoints.getSchema(); - get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); + IPoints ipoints(m_iobject, kWrapExisting); + m_schema = ipoints.getSchema(); + get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); } bool AbcPointsReader::valid() const { - return m_schema.valid(); + return m_schema.valid(); } -bool AbcPointsReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const +bool AbcPointsReader::accepts_object_type( + const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const { - if (!Alembic::AbcGeom::IPoints::matches(alembic_header)) { - *err_str = "Object type mismatch, Alembic object path pointed to Points when importing, but not any more."; - return false; - } - - if (ob->type != OB_MESH) { - *err_str = "Object type mismatch, Alembic object path points to Points."; - return false; - } - - return true; + if (!Alembic::AbcGeom::IPoints::matches(alembic_header)) { + *err_str = + "Object type mismatch, Alembic object path pointed to Points when importing, but not any " + "more."; + return false; + } + + if (ob->type != OB_MESH) { + *err_str = "Object type mismatch, Alembic object path points to Points."; + return false; + } + + return true; } void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) { - Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, NULL); + Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); + Mesh *read_mesh = this->read_mesh(mesh, sample_sel, 0, NULL); - if (read_mesh != mesh) { - BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); - } + if (read_mesh != mesh) { + BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); + } - if (m_settings->validate_meshes) { - BKE_mesh_validate(mesh, false, false); - } + if (m_settings->validate_meshes) { + BKE_mesh_validate(mesh, false, false); + } - m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); - m_object->data = mesh; + m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); + m_object->data = mesh; - if (has_animations(m_schema, m_settings)) { - addCacheModifier(); - } + if (has_animations(m_schema, m_settings)) { + addCacheModifier(); + } } void read_points_sample(const IPointsSchema &schema, const ISampleSelector &selector, CDStreamConfig &config) { - Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector); + Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector); - const P3fArraySamplePtr &positions = sample.getPositions(); + const P3fArraySamplePtr &positions = sample.getPositions(); - ICompoundProperty prop = schema.getArbGeomParams(); - N3fArraySamplePtr vnormals; + ICompoundProperty prop = schema.getArbGeomParams(); + N3fArraySamplePtr vnormals; - if (has_property(prop, "N")) { - const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>(selector.getRequestedTime()); - const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime); + if (has_property(prop, "N")) { + const Alembic::Util::uint32_t itime = static_cast<Alembic::Util::uint32_t>( + selector.getRequestedTime()); + const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime); - if (normals_prop) { - vnormals = normals_prop.getValue(selector); - } - } + if (normals_prop) { + vnormals = normals_prop.getValue(selector); + } + } - read_mverts(config.mvert, positions, vnormals); + read_mverts(config.mvert, positions, vnormals); } struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh, @@ -218,30 +222,30 @@ struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh, int /*read_flag*/, const char **err_str) { - IPointsSchema::Sample sample; - try { - sample = m_schema.getValue(sample_sel); - } - catch(Alembic::Util::Exception &ex) { - *err_str = "Error reading points sample; more detail on the console"; - printf("Alembic: error reading points sample for '%s/%s' at time %f: %s\n", - m_iobject.getFullName().c_str(), - m_schema.getName().c_str(), - sample_sel.getRequestedTime(), - ex.what()); - return existing_mesh; - } - - const P3fArraySamplePtr &positions = sample.getPositions(); - - Mesh *new_mesh = NULL; - - if (existing_mesh->totvert != positions->size()) { - new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0); - } - - CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); - read_points_sample(m_schema, sample_sel, config); - - return new_mesh ? new_mesh : existing_mesh; + IPointsSchema::Sample sample; + try { + sample = m_schema.getValue(sample_sel); + } + catch (Alembic::Util::Exception &ex) { + *err_str = "Error reading points sample; more detail on the console"; + printf("Alembic: error reading points sample for '%s/%s' at time %f: %s\n", + m_iobject.getFullName().c_str(), + m_schema.getName().c_str(), + sample_sel.getRequestedTime(), + ex.what()); + return existing_mesh; + } + + const P3fArraySamplePtr &positions = sample.getPositions(); + + Mesh *new_mesh = NULL; + + if (existing_mesh->totvert != positions->size()) { + new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0, 0); + } + + CDStreamConfig config = get_config(new_mesh ? new_mesh : existing_mesh); + read_points_sample(m_schema, sample_sel, config); + + return new_mesh ? new_mesh : existing_mesh; } diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index 64c032d6c2f..5eb448f0f66 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -32,44 +32,44 @@ struct ParticleSystem; /* ************************************************************************** */ class AbcPointsWriter : public AbcObjectWriter { - Alembic::AbcGeom::OPointsSchema m_schema; - Alembic::AbcGeom::OPointsSchema::Sample m_sample; - ParticleSystem *m_psys; - -public: - AbcPointsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys); - - void do_write(); + Alembic::AbcGeom::OPointsSchema m_schema; + Alembic::AbcGeom::OPointsSchema::Sample m_sample; + ParticleSystem *m_psys; + + public: + AbcPointsWriter(Object *ob, + AbcTransformWriter *parent, + uint32_t time_sampling, + ExportSettings &settings, + ParticleSystem *psys); + + void do_write(); }; /* ************************************************************************** */ class AbcPointsReader : public AbcObjectReader { - Alembic::AbcGeom::IPointsSchema m_schema; - Alembic::AbcGeom::IPointsSchema::Sample m_sample; + Alembic::AbcGeom::IPointsSchema m_schema; + Alembic::AbcGeom::IPointsSchema::Sample m_sample; -public: - AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + public: + AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - bool valid() const; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const; + bool valid() const; + bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - struct Mesh *read_mesh(struct Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); + struct Mesh *read_mesh(struct Mesh *existing_mesh, + const Alembic::Abc::ISampleSelector &sample_sel, + int read_flag, + const char **err_str); }; void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, const Alembic::AbcGeom::ISampleSelector &selector, CDStreamConfig &config); -#endif /* __ABC_POINTS_H__ */ +#endif /* __ABC_POINTS_H__ */ diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index 83473bd0fe6..8b8ed6c5c4b 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -34,25 +34,25 @@ extern "C" { #include "DEG_depsgraph_query.h" } +using Alembic::Abc::ISampleSelector; using Alembic::AbcGeom::OObject; using Alembic::AbcGeom::OXform; -using Alembic::Abc::ISampleSelector; /* ************************************************************************** */ static bool has_parent_camera(Object *ob) { - if (!ob->parent) { - return false; - } + if (!ob->parent) { + return false; + } - Object *parent = ob->parent; + Object *parent = ob->parent; - if (parent->type == OB_CAMERA) { - return true; - } + if (parent->type == OB_CAMERA) { + return true; + } - return has_parent_camera(parent); + return has_parent_camera(parent); } /* ************************************************************************** */ @@ -62,79 +62,78 @@ AbcTransformWriter::AbcTransformWriter(Object *ob, AbcTransformWriter *parent, unsigned int time_sampling, ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) - , m_proxy_from(NULL) + : AbcObjectWriter(ob, time_sampling, settings, parent), m_proxy_from(NULL) { - m_is_animated = hasAnimation(m_object); + m_is_animated = hasAnimation(m_object); - if (!m_is_animated) { - time_sampling = 0; - } + if (!m_is_animated) { + time_sampling = 0; + } - m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling); - m_schema = m_xform.getSchema(); + m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling); + m_schema = m_xform.getSchema(); - /* Blender objects can't have a parent without inheriting the transform. */ - m_inherits_xform = parent != NULL; + /* Blender objects can't have a parent without inheriting the transform. */ + m_inherits_xform = parent != NULL; } void AbcTransformWriter::do_write() { - Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); - - if (m_first_frame) { - m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling()); - } - - m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEW)); - - if (!m_first_frame && !m_is_animated) { - return; - } - - float yup_mat[4][4]; - create_transform_matrix(ob_eval, yup_mat, - m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, - m_proxy_from); - - /* Only apply rotation to root camera, parenting will propagate it. */ - if (ob_eval->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(ob_eval))) { - float rot_mat[4][4]; - axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); - mul_m4_m4m4(yup_mat, yup_mat, rot_mat); - } - - if (!ob_eval->parent || !m_inherits_xform) { - /* Only apply scaling to root objects, parenting will propagate it. */ - float scale_mat[4][4]; - scale_m4_fl(scale_mat, m_settings.global_scale); - scale_mat[3][3] = m_settings.global_scale; /* also scale translation */ - mul_m4_m4m4(yup_mat, yup_mat, scale_mat); - yup_mat[3][3] /= m_settings.global_scale; /* normalise the homogeneous component */ - } - - m_matrix = convert_matrix(yup_mat); - m_sample.setMatrix(m_matrix); - m_sample.setInheritsXforms(m_inherits_xform); - m_schema.set(m_sample); + Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); + + if (m_first_frame) { + m_visibility = Alembic::AbcGeom::CreateVisibilityProperty( + m_xform, m_xform.getSchema().getTimeSampling()); + } + + m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEW)); + + if (!m_first_frame && !m_is_animated) { + return; + } + + float yup_mat[4][4]; + create_transform_matrix( + ob_eval, yup_mat, m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, m_proxy_from); + + /* Only apply rotation to root camera, parenting will propagate it. */ + if (ob_eval->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(ob_eval))) { + float rot_mat[4][4]; + axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); + mul_m4_m4m4(yup_mat, yup_mat, rot_mat); + } + + if (!ob_eval->parent || !m_inherits_xform) { + /* Only apply scaling to root objects, parenting will propagate it. */ + float scale_mat[4][4]; + scale_m4_fl(scale_mat, m_settings.global_scale); + scale_mat[3][3] = m_settings.global_scale; /* also scale translation */ + mul_m4_m4m4(yup_mat, yup_mat, scale_mat); + yup_mat[3][3] /= m_settings.global_scale; /* normalise the homogeneous component */ + } + + m_matrix = convert_matrix(yup_mat); + m_sample.setMatrix(m_matrix); + m_sample.setInheritsXforms(m_inherits_xform); + m_schema.set(m_sample); } Imath::Box3d AbcTransformWriter::bounds() { - Imath::Box3d bounds; + Imath::Box3d bounds; - for (int i = 0; i < m_children.size(); ++i) { - Imath::Box3d box(m_children[i]->bounds()); - bounds.extendBy(box); - } + for (int i = 0; i < m_children.size(); ++i) { + Imath::Box3d box(m_children[i]->bounds()); + bounds.extendBy(box); + } - return Imath::transform(bounds, m_matrix); + return Imath::transform(bounds, m_matrix); } bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const { - /* TODO(kevin): implement this. */ - return true; + /* TODO(kevin): implement this. */ + return true; } /* ************************************************************************** */ @@ -142,41 +141,43 @@ bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { - /* Empties have no data. It makes the import of Alembic files easier to - * understand when we name the empty after its name in Alembic. */ - m_object_name = object.getName(); + /* Empties have no data. It makes the import of Alembic files easier to + * understand when we name the empty after its name in Alembic. */ + m_object_name = object.getName(); - Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting); - m_schema = xform.getSchema(); + Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting); + m_schema = xform.getSchema(); - get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); + get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); } bool AbcEmptyReader::valid() const { - return m_schema.valid(); + return m_schema.valid(); } -bool AbcEmptyReader::accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const +bool AbcEmptyReader::accepts_object_type( + const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const { - if (!Alembic::AbcGeom::IXform::matches(alembic_header)) { - *err_str = "Object type mismatch, Alembic object path pointed to XForm when importing, but not any more."; - return false; - } - - if (ob->type != OB_EMPTY) { - *err_str = "Object type mismatch, Alembic object path points to XForm."; - return false; - } - - return true; + if (!Alembic::AbcGeom::IXform::matches(alembic_header)) { + *err_str = + "Object type mismatch, Alembic object path pointed to XForm when importing, but not any " + "more."; + return false; + } + + if (ob->type != OB_EMPTY) { + *err_str = "Object type mismatch, Alembic object path points to XForm."; + return false; + } + + return true; } void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(sample_sel)) { - m_object = BKE_object_add_only_object(bmain, OB_EMPTY, - m_object_name.c_str()); - m_object->data = NULL; + m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str()); + m_object->data = NULL; } diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h index 79d278ce587..7fa42cf0299 100644 --- a/source/blender/alembic/intern/abc_transform.h +++ b/source/blender/alembic/intern/abc_transform.h @@ -28,48 +28,51 @@ /* ************************************************************************** */ class AbcTransformWriter : public AbcObjectWriter { - Alembic::AbcGeom::OXform m_xform; - Alembic::AbcGeom::OXformSchema m_schema; - Alembic::AbcGeom::XformSample m_sample; - Alembic::AbcGeom::OVisibilityProperty m_visibility; - Alembic::Abc::M44d m_matrix; - - bool m_is_animated; - bool m_inherits_xform; - -public: - Object *m_proxy_from; - -public: - AbcTransformWriter(Object *ob, - const Alembic::AbcGeom::OObject &abc_parent, - AbcTransformWriter *parent, - unsigned int time_sampling, - ExportSettings &settings); - - Alembic::AbcGeom::OXform &alembicXform() { return m_xform;} - virtual Imath::Box3d bounds(); - -private: - virtual void do_write(); - - bool hasAnimation(Object *ob) const; + Alembic::AbcGeom::OXform m_xform; + Alembic::AbcGeom::OXformSchema m_schema; + Alembic::AbcGeom::XformSample m_sample; + Alembic::AbcGeom::OVisibilityProperty m_visibility; + Alembic::Abc::M44d m_matrix; + + bool m_is_animated; + bool m_inherits_xform; + + public: + Object *m_proxy_from; + + public: + AbcTransformWriter(Object *ob, + const Alembic::AbcGeom::OObject &abc_parent, + AbcTransformWriter *parent, + unsigned int time_sampling, + ExportSettings &settings); + + Alembic::AbcGeom::OXform &alembicXform() + { + return m_xform; + } + virtual Imath::Box3d bounds(); + + private: + virtual void do_write(); + + bool hasAnimation(Object *ob) const; }; /* ************************************************************************** */ class AbcEmptyReader : public AbcObjectReader { - Alembic::AbcGeom::IXformSchema m_schema; + Alembic::AbcGeom::IXformSchema m_schema; -public: - AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings); + public: + AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - bool valid() const; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const; + bool valid() const; + bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, + const Object *const ob, + const char **err_str) const; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); + void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); }; -#endif /* __ABC_TRANSFORM_H__ */ +#endif /* __ABC_TRANSFORM_H__ */ diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index a4a7256b783..380ceff80cf 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -40,23 +40,23 @@ extern "C" { #include "PIL_time.h" } -std::string get_id_name(const Object * const ob) +std::string get_id_name(const Object *const ob) { - if (!ob) { - return ""; - } + if (!ob) { + return ""; + } - return get_id_name(&ob->id); + return get_id_name(&ob->id); } -std::string get_id_name(const ID * const id) +std::string get_id_name(const ID *const id) { - std::string name(id->name + 2); - std::replace(name.begin(), name.end(), ' ', '_'); - std::replace(name.begin(), name.end(), '.', '_'); - std::replace(name.begin(), name.end(), ':', '_'); + std::string name(id->name + 2); + std::replace(name.begin(), name.end(), ' ', '_'); + std::replace(name.begin(), name.end(), '.', '_'); + std::replace(name.begin(), name.end(), ':', '_'); - return name; + return name; } /** @@ -68,209 +68,212 @@ std::string get_id_name(const ID * const id) * \param dupli_parent: * \return */ -std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent) +std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent) { - std::string name = get_id_name(ob); + std::string name = get_id_name(ob); - Object *p = ob->parent; + Object *p = ob->parent; - while (p) { - name = get_id_name(p) + "/" + name; - p = p->parent; - } + while (p) { + name = get_id_name(p) + "/" + name; + p = p->parent; + } - if (dupli_parent && (ob != dupli_parent)) { - name = get_id_name(dupli_parent) + "/" + name; - } + if (dupli_parent && (ob != dupli_parent)) { + name = get_id_name(dupli_parent) + "/" + name; + } - return name; + return name; } Imath::M44d convert_matrix(float mat[4][4]) { - Imath::M44d m; + Imath::M44d m; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - m[i][j] = mat[i][j]; - } - } + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + m[i][j] = mat[i][j]; + } + } - return m; + return m; } void split(const std::string &s, const char delim, std::vector<std::string> &tokens) { - tokens.clear(); + tokens.clear(); - std::stringstream ss(s); - std::string item; + std::stringstream ss(s); + std::string item; - while (std::getline(ss, item, delim)) { - if (!item.empty()) { - tokens.push_back(item); - } - } + while (std::getline(ss, item, delim)) { + if (!item.empty()) { + tokens.push_back(item); + } + } } -void create_swapped_rotation_matrix( - float rot_x_mat[3][3], float rot_y_mat[3][3], - float rot_z_mat[3][3], const float euler[3], - AbcAxisSwapMode mode) +void create_swapped_rotation_matrix(float rot_x_mat[3][3], + float rot_y_mat[3][3], + float rot_z_mat[3][3], + const float euler[3], + AbcAxisSwapMode mode) { - const float rx = euler[0]; - float ry; - float rz; - - /* Apply transformation */ - switch (mode) { - case ABC_ZUP_FROM_YUP: - ry = -euler[2]; - rz = euler[1]; - break; - case ABC_YUP_FROM_ZUP: - ry = euler[2]; - rz = -euler[1]; - break; - default: - ry = 0.0f; - rz = 0.0f; - BLI_assert(false); - break; - } - - unit_m3(rot_x_mat); - unit_m3(rot_y_mat); - unit_m3(rot_z_mat); - - rot_x_mat[1][1] = cos(rx); - rot_x_mat[2][1] = -sin(rx); - rot_x_mat[1][2] = sin(rx); - rot_x_mat[2][2] = cos(rx); - - rot_y_mat[2][2] = cos(ry); - rot_y_mat[0][2] = -sin(ry); - rot_y_mat[2][0] = sin(ry); - rot_y_mat[0][0] = cos(ry); - - rot_z_mat[0][0] = cos(rz); - rot_z_mat[1][0] = -sin(rz); - rot_z_mat[0][1] = sin(rz); - rot_z_mat[1][1] = cos(rz); + const float rx = euler[0]; + float ry; + float rz; + + /* Apply transformation */ + switch (mode) { + case ABC_ZUP_FROM_YUP: + ry = -euler[2]; + rz = euler[1]; + break; + case ABC_YUP_FROM_ZUP: + ry = euler[2]; + rz = -euler[1]; + break; + default: + ry = 0.0f; + rz = 0.0f; + BLI_assert(false); + break; + } + + unit_m3(rot_x_mat); + unit_m3(rot_y_mat); + unit_m3(rot_z_mat); + + rot_x_mat[1][1] = cos(rx); + rot_x_mat[2][1] = -sin(rx); + rot_x_mat[1][2] = sin(rx); + rot_x_mat[2][2] = cos(rx); + + rot_y_mat[2][2] = cos(ry); + rot_y_mat[0][2] = -sin(ry); + rot_y_mat[2][0] = sin(ry); + rot_y_mat[0][0] = cos(ry); + + rot_z_mat[0][0] = cos(rz); + rot_z_mat[1][0] = -sin(rz); + rot_z_mat[0][1] = sin(rz); + rot_z_mat[1][1] = cos(rz); } /* Convert matrix from Z=up to Y=up or vice versa. Use yup_mat = zup_mat for in-place conversion. */ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode) { - float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4]; - float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3]; - float src_trans[3], dst_scale[3], src_scale[3], euler[3]; - - zero_v3(src_trans); - zero_v3(dst_scale); - zero_v3(src_scale); - zero_v3(euler); - unit_m3(src_rot); - unit_m3(dst_rot); - unit_m4(dst_scale_mat); - - /* TODO(Sybren): This code assumes there is no sheer component and no - * homogeneous scaling component, which is not always true when writing - * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform - * scale and the child rotates). This is currently not taken into account - * when axis-swapping. */ - - /* Extract translation, rotation, and scale form matrix. */ - mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat); - - /* Get euler angles from rotation matrix. */ - mat3_to_eulO(euler, ROT_MODE_XZY, src_rot); - - /* Create X, Y, Z rotation matrices from euler angles. */ - create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode); - - /* Concatenate rotation matrices. */ - mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat); - mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat); - mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat); - - mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot); - - /* Start construction of dst_mat from rotation matrix */ - unit_m4(dst_mat); - copy_m4_m3(dst_mat, dst_rot); - - /* Apply translation */ - switch (mode) { - case ABC_ZUP_FROM_YUP: - copy_zup_from_yup(dst_mat[3], src_trans); - break; - case ABC_YUP_FROM_ZUP: - copy_yup_from_zup(dst_mat[3], src_trans); - break; - default: - BLI_assert(false); - } - - /* Apply scale matrix. Swaps y and z, but does not - * negate like translation does. */ - dst_scale[0] = src_scale[0]; - dst_scale[1] = src_scale[2]; - dst_scale[2] = src_scale[1]; - - size_to_mat4(dst_scale_mat, dst_scale); - mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat); + float dst_rot[3][3], src_rot[3][3], dst_scale_mat[4][4]; + float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3]; + float src_trans[3], dst_scale[3], src_scale[3], euler[3]; + + zero_v3(src_trans); + zero_v3(dst_scale); + zero_v3(src_scale); + zero_v3(euler); + unit_m3(src_rot); + unit_m3(dst_rot); + unit_m4(dst_scale_mat); + + /* TODO(Sybren): This code assumes there is no sheer component and no + * homogeneous scaling component, which is not always true when writing + * non-hierarchical (e.g. flat) objects (e.g. when parent has non-uniform + * scale and the child rotates). This is currently not taken into account + * when axis-swapping. */ + + /* Extract translation, rotation, and scale form matrix. */ + mat4_to_loc_rot_size(src_trans, src_rot, src_scale, src_mat); + + /* Get euler angles from rotation matrix. */ + mat3_to_eulO(euler, ROT_MODE_XZY, src_rot); + + /* Create X, Y, Z rotation matrices from euler angles. */ + create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, mode); + + /* Concatenate rotation matrices. */ + mul_m3_m3m3(dst_rot, dst_rot, rot_z_mat); + mul_m3_m3m3(dst_rot, dst_rot, rot_y_mat); + mul_m3_m3m3(dst_rot, dst_rot, rot_x_mat); + + mat3_to_eulO(euler, ROT_MODE_XZY, dst_rot); + + /* Start construction of dst_mat from rotation matrix */ + unit_m4(dst_mat); + copy_m4_m3(dst_mat, dst_rot); + + /* Apply translation */ + switch (mode) { + case ABC_ZUP_FROM_YUP: + copy_zup_from_yup(dst_mat[3], src_trans); + break; + case ABC_YUP_FROM_ZUP: + copy_yup_from_zup(dst_mat[3], src_trans); + break; + default: + BLI_assert(false); + } + + /* Apply scale matrix. Swaps y and z, but does not + * negate like translation does. */ + dst_scale[0] = src_scale[0]; + dst_scale[1] = src_scale[2]; + dst_scale[2] = src_scale[1]; + + size_to_mat4(dst_scale_mat, dst_scale); + mul_m4_m4m4(dst_mat, dst_mat, dst_scale_mat); } void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]) { - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 4; ++j) { - r_mat[i][j] = static_cast<float>(xform[i][j]); - } - } - - if (ob->type == OB_CAMERA) { - float cam_to_yup[4][4]; - axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2); - mul_m4_m4m4(r_mat, r_mat, cam_to_yup); - } - - copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP); + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + r_mat[i][j] = static_cast<float>(xform[i][j]); + } + } + + if (ob->type == OB_CAMERA) { + float cam_to_yup[4][4]; + axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2); + mul_m4_m4m4(r_mat, r_mat, cam_to_yup); + } + + copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP); } /* Recompute transform matrix of object in new coordinate system * (from Z-Up to Y-Up). */ -void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode, +void create_transform_matrix(Object *obj, + float r_yup_mat[4][4], + AbcMatrixMode mode, Object *proxy_from) { - float zup_mat[4][4]; - - /* get local or world matrix. */ - if (mode == ABC_MATRIX_LOCAL && obj->parent) { - /* Note that this produces another matrix than the local matrix, due to - * constraints and modifiers as well as the obj->parentinv matrix. */ - invert_m4_m4(obj->parent->imat, obj->parent->obmat); - mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat); - } - else { - copy_m4_m4(zup_mat, obj->obmat); - } - - if (proxy_from) { - mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat); - } - - copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); + float zup_mat[4][4]; + + /* get local or world matrix. */ + if (mode == ABC_MATRIX_LOCAL && obj->parent) { + /* Note that this produces another matrix than the local matrix, due to + * constraints and modifiers as well as the obj->parentinv matrix. */ + invert_m4_m4(obj->parent->imat, obj->parent->obmat); + mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat); + } + else { + copy_m4_m4(zup_mat, obj->obmat); + } + + if (proxy_from) { + mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat); + } + + copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); } bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name) { - if (!prop.valid()) { - return false; - } + if (!prop.valid()) { + return false; + } - return prop.getPropertyHeader(name) != NULL; + return prop.getPropertyHeader(name) != NULL; } typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t; @@ -281,125 +284,123 @@ float get_weight_and_index(float time, Alembic::AbcGeom::index_t &i0, Alembic::AbcGeom::index_t &i1) { - samples_number = std::max(samples_number, 1); + samples_number = std::max(samples_number, 1); - index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number); - i0 = i1 = t0.first; + index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number); + i0 = i1 = t0.first; - if (samples_number == 1 || (fabs(time - t0.second) < 0.0001f)) { - return 0.0f; - } + if (samples_number == 1 || (fabs(time - t0.second) < 0.0001f)) { + return 0.0f; + } - index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number); - i1 = t1.first; + index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number); + i1 = t1.first; - if (i0 == i1) { - return 0.0f; - } + if (i0 == i1) { + return 0.0f; + } - const float bias = (time - t0.second) / (t1.second - t0.second); + const float bias = (time - t0.second) / (t1.second - t0.second); - if (fabs(1.0f - bias) < 0.0001f) { - i0 = i1; - return 0.0f; - } + if (fabs(1.0f - bias) < 0.0001f) { + i0 = i1; + return 0.0f; + } - return bias; + return bias; } //#define USE_NURBS AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings) { - AbcObjectReader *reader = NULL; - - const Alembic::AbcGeom::MetaData &md = object.getMetaData(); - - if (Alembic::AbcGeom::IXform::matches(md)) { - reader = new AbcEmptyReader(object, settings); - } - else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { - reader = new AbcMeshReader(object, settings); - } - else if (Alembic::AbcGeom::ISubD::matches(md)) { - reader = new AbcSubDReader(object, settings); - } - else if (Alembic::AbcGeom::INuPatch::matches(md)) { + AbcObjectReader *reader = NULL; + + const Alembic::AbcGeom::MetaData &md = object.getMetaData(); + + if (Alembic::AbcGeom::IXform::matches(md)) { + reader = new AbcEmptyReader(object, settings); + } + else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { + reader = new AbcMeshReader(object, settings); + } + else if (Alembic::AbcGeom::ISubD::matches(md)) { + reader = new AbcSubDReader(object, settings); + } + else if (Alembic::AbcGeom::INuPatch::matches(md)) { #ifdef USE_NURBS - /* TODO(kevin): importing cyclic NURBS from other software crashes - * at the moment. This is due to the fact that NURBS in other - * software have duplicated points which causes buffer overflows in - * Blender. Need to figure out exactly how these points are - * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). - * Until this is fixed, disabling NURBS reading. */ - reader = new AbcNurbsReader(child, settings); + /* TODO(kevin): importing cyclic NURBS from other software crashes + * at the moment. This is due to the fact that NURBS in other + * software have duplicated points which causes buffer overflows in + * Blender. Need to figure out exactly how these points are + * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). + * Until this is fixed, disabling NURBS reading. */ + reader = new AbcNurbsReader(child, settings); #endif - } - else if (Alembic::AbcGeom::ICamera::matches(md)) { - reader = new AbcCameraReader(object, settings); - } - else if (Alembic::AbcGeom::IPoints::matches(md)) { - reader = new AbcPointsReader(object, settings); - } - else if (Alembic::AbcMaterial::IMaterial::matches(md)) { - /* Pass for now. */ - } - else if (Alembic::AbcGeom::ILight::matches(md)) { - /* Pass for now. */ - } - else if (Alembic::AbcGeom::IFaceSet::matches(md)) { - /* Pass, those are handled in the mesh reader. */ - } - else if (Alembic::AbcGeom::ICurves::matches(md)) { - reader = new AbcCurveReader(object, settings); - } - else { - std::cerr << "Alembic: unknown how to handle objects of schema '" - << md.get("schemaObjTitle") - << "', skipping object '" - << object.getFullName() << "'" << std::endl; - } - - return reader; + } + else if (Alembic::AbcGeom::ICamera::matches(md)) { + reader = new AbcCameraReader(object, settings); + } + else if (Alembic::AbcGeom::IPoints::matches(md)) { + reader = new AbcPointsReader(object, settings); + } + else if (Alembic::AbcMaterial::IMaterial::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::ILight::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::IFaceSet::matches(md)) { + /* Pass, those are handled in the mesh reader. */ + } + else if (Alembic::AbcGeom::ICurves::matches(md)) { + reader = new AbcCurveReader(object, settings); + } + else { + std::cerr << "Alembic: unknown how to handle objects of schema '" << md.get("schemaObjTitle") + << "', skipping object '" << object.getFullName() << "'" << std::endl; + } + + return reader; } /* ********************** */ ScopeTimer::ScopeTimer(const char *message) - : m_message(message) - , m_start(PIL_check_seconds_timer()) -{} + : m_message(message), m_start(PIL_check_seconds_timer()) +{ +} ScopeTimer::~ScopeTimer() { - fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start); + fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start); } /* ********************** */ bool SimpleLogger::empty() { - return ((size_t)m_stream.tellp()) == 0ul; + return ((size_t)m_stream.tellp()) == 0ul; } std::string SimpleLogger::str() const { - return m_stream.str(); + return m_stream.str(); } void SimpleLogger::clear() { - m_stream.clear(); - m_stream.str(""); + m_stream.clear(); + m_stream.str(""); } std::ostringstream &SimpleLogger::stream() { - return m_stream; + return m_stream; } std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger) { - os << logger.str(); - return os; + os << logger.str(); + return os; } diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index d21fe7a78ce..44ad4bca2f7 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -36,7 +36,7 @@ * pointers to AbcObjectReader (or subclasses thereof). */ struct CacheReader { - int unused; + int unused; }; using Alembic::Abc::chrono_t; @@ -48,58 +48,61 @@ struct Base; struct ID; struct Object; -std::string get_id_name(const ID * const id); -std::string get_id_name(const Object * const ob); -std::string get_object_dag_path_name(const Object * const ob, Object *dupli_parent); +std::string get_id_name(const ID *const id); +std::string get_id_name(const Object *const ob); +std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent); Imath::M44d convert_matrix(float mat[4][4]); typedef enum { - ABC_MATRIX_WORLD = 1, - ABC_MATRIX_LOCAL = 2, + ABC_MATRIX_WORLD = 1, + ABC_MATRIX_LOCAL = 2, } AbcMatrixMode; -void create_transform_matrix(Object *obj, float r_transform_mat[4][4], - AbcMatrixMode mode, Object *proxy_from); +void create_transform_matrix(Object *obj, + float r_transform_mat[4][4], + AbcMatrixMode mode, + Object *proxy_from); void split(const std::string &s, const char delim, std::vector<std::string> &tokens); -template<class TContainer> -bool begins_with(const TContainer &input, const TContainer &match) +template<class TContainer> bool begins_with(const TContainer &input, const TContainer &match) { - return input.size() >= match.size() - && std::equal(match.begin(), match.end(), input.begin()); + return input.size() >= match.size() && std::equal(match.begin(), match.end(), input.begin()); } void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]); -template <typename Schema> +template<typename Schema> void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max) { - const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling(); + const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling(); - if (!schema.isConstant()) { - const size_t num_samps = schema.getNumSamples(); + if (!schema.isConstant()) { + const size_t num_samps = schema.getNumSamples(); - if (num_samps > 0) { - const chrono_t min_time = time_samp->getSampleTime(0); - min = std::min(min, min_time); + if (num_samps > 0) { + const chrono_t min_time = time_samp->getSampleTime(0); + min = std::min(min, min_time); - const chrono_t max_time = time_samp->getSampleTime(num_samps - 1); - max = std::max(max, max_time); - } - } + const chrono_t max_time = time_samp->getSampleTime(num_samps - 1); + max = std::max(max, max_time); + } + } } -template <typename Schema> -void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max) +template<typename Schema> +void get_min_max_time(const Alembic::AbcGeom::IObject &object, + const Schema &schema, + chrono_t &min, + chrono_t &max) { - get_min_max_time_ex(schema, min, max); + get_min_max_time_ex(schema, min, max); - const Alembic::AbcGeom::IObject &parent = object.getParent(); - if (parent.valid() && Alembic::AbcGeom::IXform::matches(parent.getMetaData())) { - Alembic::AbcGeom::IXform xform(parent, Alembic::AbcGeom::kWrapExisting); - get_min_max_time_ex(xform.getSchema(), min, max); - } + const Alembic::AbcGeom::IObject &parent = object.getParent(); + if (parent.valid() && Alembic::AbcGeom::IXform::matches(parent.getMetaData())) { + Alembic::AbcGeom::IXform xform(parent, Alembic::AbcGeom::kWrapExisting); + get_min_max_time_ex(xform.getSchema(), min, max); + } } bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name); @@ -123,51 +126,52 @@ AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSe ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) { - const float old_yup1 = yup[1]; /* in case zup == yup */ - zup[0] = yup[0]; - zup[1] = -yup[2]; - zup[2] = old_yup1; + const float old_yup1 = yup[1]; /* in case zup == yup */ + zup[0] = yup[0]; + zup[1] = -yup[2]; + zup[2] = old_yup1; } ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) { - const short old_yup1 = yup[1]; /* in case zup == yup */ - zup[0] = yup[0]; - zup[1] = -yup[2]; - zup[2] = old_yup1; + const short old_yup1 = yup[1]; /* in case zup == yup */ + zup[0] = yup[0]; + zup[1] = -yup[2]; + zup[2] = old_yup1; } /* Copy from Z-up to Y-up. */ ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) { - const float old_zup1 = zup[1]; /* in case yup == zup */ - yup[0] = zup[0]; - yup[1] = zup[2]; - yup[2] = -old_zup1; + const float old_zup1 = zup[1]; /* in case yup == zup */ + yup[0] = zup[0]; + yup[1] = zup[2]; + yup[2] = -old_zup1; } ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) { - const short old_zup1 = zup[1]; /* in case yup == zup */ - yup[0] = zup[0]; - yup[1] = zup[2]; - yup[2] = -old_zup1; + const short old_zup1 = zup[1]; /* in case yup == zup */ + yup[0] = zup[0]; + yup[1] = zup[2]; + yup[2] = -old_zup1; } /* Names are given in (dst, src) order, just like * the parameters of copy_m44_axis_swap() */ typedef enum { - ABC_ZUP_FROM_YUP = 1, - ABC_YUP_FROM_ZUP = 2, + ABC_ZUP_FROM_YUP = 1, + ABC_YUP_FROM_ZUP = 2, } AbcAxisSwapMode; /* Create a rotation matrix for each axis from euler angles. * Euler angles are swapped to change coordinate system. */ -void create_swapped_rotation_matrix( - float rot_x_mat[3][3], float rot_y_mat[3][3], - float rot_z_mat[3][3], const float euler[3], - AbcAxisSwapMode mode); +void create_swapped_rotation_matrix(float rot_x_mat[3][3], + float rot_y_mat[3][3], + float rot_z_mat[3][3], + const float euler[3], + AbcAxisSwapMode mode); void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode); @@ -176,18 +180,18 @@ void copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMod #undef ABC_DEBUG_TIME class ScopeTimer { - const char *m_message; - double m_start; + const char *m_message; + double m_start; -public: - ScopeTimer(const char *message); - ~ScopeTimer(); + public: + ScopeTimer(const char *message); + ~ScopeTimer(); }; #ifdef ABC_DEBUG_TIME -# define SCOPE_TIMER(message) ScopeTimer prof(message) +# define SCOPE_TIMER(message) ScopeTimer prof(message) #else -# define SCOPE_TIMER(message) +# define SCOPE_TIMER(message) #endif /* *************************** */ @@ -202,29 +206,29 @@ public: * conditions. */ class SimpleLogger { - std::ostringstream m_stream; - -public: - /** - * Check whether or not the SimpleLogger's stream is empty. - */ - bool empty(); - - /** - * Return a copy of the string contained in the SimpleLogger's stream. - */ - std::string str() const; - - /** - * Remove the bits set on the SimpleLogger's stream and clear its string. - */ - void clear(); - - /** - * Return a reference to the SimpleLogger's stream, in order to e.g. push - * content into it. - */ - std::ostringstream &stream(); + std::ostringstream m_stream; + + public: + /** + * Check whether or not the SimpleLogger's stream is empty. + */ + bool empty(); + + /** + * Return a copy of the string contained in the SimpleLogger's stream. + */ + std::string str() const; + + /** + * Remove the bits set on the SimpleLogger's stream and clear its string. + */ + void clear(); + + /** + * Return a reference to the SimpleLogger's stream, in order to e.g. push + * content into it. + */ + std::ostringstream &stream(); }; #define ABC_LOG(logger) logger.stream() @@ -234,4 +238,4 @@ public: */ std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger); -#endif /* __ABC_UTIL_H__ */ +#endif /* __ABC_UTIL_H__ */ diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 541db514bb0..0bc4eb2385b 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -74,15 +74,18 @@ extern "C" { using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::ObjectHeader; +using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::MetaData; using Alembic::AbcGeom::P3fArraySamplePtr; -using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::ICamera; +using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::ICurves; using Alembic::AbcGeom::ICurvesSchema; using Alembic::AbcGeom::IFaceSet; using Alembic::AbcGeom::ILight; +using Alembic::AbcGeom::IN3fArrayProperty; +using Alembic::AbcGeom::IN3fGeomParam; using Alembic::AbcGeom::INuPatch; using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IPoints; @@ -95,26 +98,23 @@ using Alembic::AbcGeom::IV2fGeomParam; using Alembic::AbcGeom::IXform; using Alembic::AbcGeom::IXformSchema; using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::XformSample; -using Alembic::AbcGeom::ICompoundProperty; -using Alembic::AbcGeom::IN3fArrayProperty; -using Alembic::AbcGeom::IN3fGeomParam; using Alembic::AbcGeom::V3fArraySamplePtr; +using Alembic::AbcGeom::XformSample; using Alembic::AbcMaterial::IMaterial; struct AbcArchiveHandle { - int unused; + int unused; }; ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) { - return reinterpret_cast<ArchiveReader *>(handle); + return reinterpret_cast<ArchiveReader *>(handle); } ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) { - return reinterpret_cast<AbcArchiveHandle *>(archive); + return reinterpret_cast<AbcArchiveHandle *>(archive); } //#define USE_NURBS @@ -123,297 +123,289 @@ ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) * sync. */ static bool gather_objects_paths(const IObject &object, ListBase *object_paths) { - if (!object.valid()) { - return false; - } - - - size_t children_claiming_this_object = 0; - size_t num_children = object.getNumChildren(); - - for (size_t i = 0; i < num_children; ++i) { - bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths); - children_claiming_this_object += child_claims_this_object ? 1 : 0; - } - - const MetaData &md = object.getMetaData(); - bool get_path = false; - bool parent_is_part_of_this_object = false; - - if (!object.getParent()) { - /* The root itself is not an object we should import. */ - } - else if (IXform::matches(md)) { - if (has_property(object.getProperties(), "locator")) { - get_path = true; - } - else { - get_path = children_claiming_this_object == 0; - } - - /* Transforms are never "data" for their parent. */ - parent_is_part_of_this_object = false; - } - else { - /* These types are "data" for their parent. */ - get_path = - IPolyMesh::matches(md) || - ISubD::matches(md) || + if (!object.valid()) { + return false; + } + + size_t children_claiming_this_object = 0; + size_t num_children = object.getNumChildren(); + + for (size_t i = 0; i < num_children; ++i) { + bool child_claims_this_object = gather_objects_paths(object.getChild(i), object_paths); + children_claiming_this_object += child_claims_this_object ? 1 : 0; + } + + const MetaData &md = object.getMetaData(); + bool get_path = false; + bool parent_is_part_of_this_object = false; + + if (!object.getParent()) { + /* The root itself is not an object we should import. */ + } + else if (IXform::matches(md)) { + if (has_property(object.getProperties(), "locator")) { + get_path = true; + } + else { + get_path = children_claiming_this_object == 0; + } + + /* Transforms are never "data" for their parent. */ + parent_is_part_of_this_object = false; + } + else { + /* These types are "data" for their parent. */ + get_path = IPolyMesh::matches(md) || ISubD::matches(md) || #ifdef USE_NURBS - INuPatch::matches(md) || + INuPatch::matches(md) || #endif - ICamera::matches(md) || - IPoints::matches(md) || - ICurves::matches(md); - parent_is_part_of_this_object = get_path; - } + ICamera::matches(md) || IPoints::matches(md) || ICurves::matches(md); + parent_is_part_of_this_object = get_path; + } - if (get_path) { - void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"); - AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void); + if (get_path) { + void *abc_path_void = MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath"); + AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>(abc_path_void); - BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path)); - BLI_addtail(object_paths, abc_path); - } + BLI_strncpy(abc_path->path, object.getFullName().c_str(), sizeof(abc_path->path)); + BLI_addtail(object_paths, abc_path); + } - return parent_is_part_of_this_object; + return parent_is_part_of_this_object; } AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths) { - ArchiveReader *archive = new ArchiveReader(filename); + ArchiveReader *archive = new ArchiveReader(filename); - if (!archive->valid()) { - delete archive; - return NULL; - } + if (!archive->valid()) { + delete archive; + return NULL; + } - if (object_paths) { - gather_objects_paths(archive->getTop(), object_paths); - } + if (object_paths) { + gather_objects_paths(archive->getTop(), object_paths); + } - return handle_from_archive(archive); + return handle_from_archive(archive); } void ABC_free_handle(AbcArchiveHandle *handle) { - delete archive_from_handle(handle); + delete archive_from_handle(handle); } int ABC_get_version() { - return ALEMBIC_LIBRARY_VERSION; + return ALEMBIC_LIBRARY_VERSION; } -static void find_iobject(const IObject &object, IObject &ret, - const std::string &path) +static void find_iobject(const IObject &object, IObject &ret, const std::string &path) { - if (!object.valid()) { - return; - } + if (!object.valid()) { + return; + } - std::vector<std::string> tokens; - split(path, '/', tokens); + std::vector<std::string> tokens; + split(path, '/', tokens); - IObject tmp = object; + IObject tmp = object; - std::vector<std::string>::iterator iter; - for (iter = tokens.begin(); iter != tokens.end(); ++iter) { - IObject child = tmp.getChild(*iter); - tmp = child; - } + std::vector<std::string>::iterator iter; + for (iter = tokens.begin(); iter != tokens.end(); ++iter) { + IObject child = tmp.getChild(*iter); + tmp = child; + } - ret = tmp; + ret = tmp; } struct ExportJobData { - ViewLayer *view_layer; - Main *bmain; + ViewLayer *view_layer; + Main *bmain; - char filename[1024]; - ExportSettings settings; + char filename[1024]; + ExportSettings settings; - short *stop; - short *do_update; - float *progress; + short *stop; + short *do_update; + float *progress; - bool was_canceled; - bool export_ok; + bool was_canceled; + bool export_ok; }; static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) { - ExportJobData *data = static_cast<ExportJobData *>(customdata); + ExportJobData *data = static_cast<ExportJobData *>(customdata); - data->stop = stop; - data->do_update = do_update; - data->progress = progress; + data->stop = stop; + data->do_update = do_update; + data->progress = progress; - /* XXX annoying hack: needed to prevent data corruption when changing - * scene frame in separate threads - */ - G.is_rendering = true; - BKE_spacedata_draw_locks(true); + /* XXX annoying hack: needed to prevent data corruption when changing + * scene frame in separate threads + */ + G.is_rendering = true; + BKE_spacedata_draw_locks(true); - G.is_break = false; + G.is_break = false; - DEG_graph_build_from_view_layer(data->settings.depsgraph, - data->bmain, - data->settings.scene, - data->view_layer); - BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain); + DEG_graph_build_from_view_layer( + data->settings.depsgraph, data->bmain, data->settings.scene, data->view_layer); + BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain); - try { - AbcExporter exporter(data->bmain, data->filename, data->settings); + try { + AbcExporter exporter(data->bmain, data->filename, data->settings); - Scene *scene = data->settings.scene; /* for the CFRA macro */ - const int orig_frame = CFRA; + Scene *scene = data->settings.scene; /* for the CFRA macro */ + const int orig_frame = CFRA; - data->was_canceled = false; - exporter(*data->progress, data->was_canceled); + data->was_canceled = false; + exporter(*data->progress, data->was_canceled); - if (CFRA != orig_frame) { - CFRA = orig_frame; + if (CFRA != orig_frame) { + CFRA = orig_frame; - BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain); - } + BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain); + } - data->export_ok = !data->was_canceled; - } - catch (const std::exception &e) { - ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n'; - } - catch (...) { - ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n"; - } + data->export_ok = !data->was_canceled; + } + catch (const std::exception &e) { + ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n'; + } + catch (...) { + ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n"; + } } static void export_endjob(void *customdata) { - ExportJobData *data = static_cast<ExportJobData *>(customdata); + ExportJobData *data = static_cast<ExportJobData *>(customdata); - DEG_graph_free(data->settings.depsgraph); + DEG_graph_free(data->settings.depsgraph); - if (data->was_canceled && BLI_exists(data->filename)) { - BLI_delete(data->filename, false, false); - } + if (data->was_canceled && BLI_exists(data->filename)) { + BLI_delete(data->filename, false, false); + } - if (!data->settings.logger.empty()) { - std::cerr << data->settings.logger; - WM_report(RPT_ERROR, "Errors occurred during the export, look in the console to know more..."); - } + if (!data->settings.logger.empty()) { + std::cerr << data->settings.logger; + WM_report(RPT_ERROR, "Errors occurred during the export, look in the console to know more..."); + } - G.is_rendering = false; - BKE_spacedata_draw_locks(false); + G.is_rendering = false; + BKE_spacedata_draw_locks(false); } -bool ABC_export( - Scene *scene, - bContext *C, - const char *filepath, - const struct AlembicExportParams *params, - bool as_background_job) +bool ABC_export(Scene *scene, + bContext *C, + const char *filepath, + const struct AlembicExportParams *params, + bool as_background_job) { - ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); - - job->view_layer = CTX_data_view_layer(C); - job->bmain = CTX_data_main(C); - job->export_ok = false; - BLI_strncpy(job->filename, filepath, 1024); - - /* Alright, alright, alright.... - * - * ExportJobData contains an ExportSettings containing a SimpleLogger. - * - * Since ExportJobData is a C-style struct dynamically allocated with - * MEM_mallocN (see above), its constructor is never called, therefore the - * ExportSettings constructor is not called which implies that the - * SimpleLogger one is not called either. SimpleLogger in turn does not call - * the constructor of its data members which ultimately means that its - * std::ostringstream member has a NULL pointer. To be able to properly use - * the stream's operator<<, the pointer needs to be set, therefore we have - * to properly construct everything. And this is done using the placement - * new operator as here below. It seems hackish, but I'm too lazy to - * do bigger refactor and maybe there is a better way which does not involve - * hardcore refactoring. */ - new (&job->settings) ExportSettings(); - job->settings.scene = scene; - job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER); - - /* TODO(Sybren): for now we only export the active scene layer. - * Later in the 2.8 development process this may be replaced by using - * a specific collection for Alembic I/O, which can then be toggled - * between "real" objects and cached Alembic files. */ - job->settings.view_layer = job->view_layer; - - job->settings.frame_start = params->frame_start; - job->settings.frame_end = params->frame_end; - job->settings.frame_samples_xform = params->frame_samples_xform; - job->settings.frame_samples_shape = params->frame_samples_shape; - job->settings.shutter_open = params->shutter_open; - job->settings.shutter_close = params->shutter_close; - - /* TODO(Sybren): For now this is ignored, until we can get selection - * detection working through Base pointers (instead of ob->flags). */ - job->settings.selected_only = params->selected_only; - - job->settings.export_face_sets = params->face_sets; - job->settings.export_normals = params->normals; - job->settings.export_uvs = params->uvs; - job->settings.export_vcols = params->vcolors; - job->settings.export_hair = params->export_hair; - job->settings.export_particles = params->export_particles; - job->settings.apply_subdiv = params->apply_subdiv; - job->settings.curves_as_mesh = params->curves_as_mesh; - job->settings.flatten_hierarchy = params->flatten_hierarchy; - - /* TODO(Sybren): visible_layer & renderable only is ignored for now, - * to be replaced with collections later in the 2.8 dev process - * (also see note above). */ - job->settings.visible_layers_only = params->visible_layers_only; - job->settings.renderable_only = params->renderable_only; - - job->settings.use_subdiv_schema = params->use_subdiv_schema; - job->settings.export_ogawa = (params->compression_type == ABC_ARCHIVE_OGAWA); - job->settings.pack_uv = params->packuv; - job->settings.global_scale = params->global_scale; - job->settings.triangulate = params->triangulate; - job->settings.quad_method = params->quad_method; - job->settings.ngon_method = params->ngon_method; - - if (job->settings.frame_start > job->settings.frame_end) { - std::swap(job->settings.frame_start, job->settings.frame_end); - } - - bool export_ok = false; - if (as_background_job) { - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - job->settings.scene, - "Alembic Export", - WM_JOB_PROGRESS, - WM_JOB_TYPE_ALEMBIC); - - /* setup job */ - WM_jobs_customdata_set(wm_job, job, MEM_freeN); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob); - - WM_jobs_start(CTX_wm_manager(C), wm_job); - } - else { - /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ - short stop = 0, do_update = 0; - float progress = 0.f; - - export_startjob(job, &stop, &do_update, &progress); - export_endjob(job); - export_ok = job->export_ok; - - MEM_freeN(job); - } - - return export_ok; + ExportJobData *job = static_cast<ExportJobData *>( + MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); + + job->view_layer = CTX_data_view_layer(C); + job->bmain = CTX_data_main(C); + job->export_ok = false; + BLI_strncpy(job->filename, filepath, 1024); + + /* Alright, alright, alright.... + * + * ExportJobData contains an ExportSettings containing a SimpleLogger. + * + * Since ExportJobData is a C-style struct dynamically allocated with + * MEM_mallocN (see above), its constructor is never called, therefore the + * ExportSettings constructor is not called which implies that the + * SimpleLogger one is not called either. SimpleLogger in turn does not call + * the constructor of its data members which ultimately means that its + * std::ostringstream member has a NULL pointer. To be able to properly use + * the stream's operator<<, the pointer needs to be set, therefore we have + * to properly construct everything. And this is done using the placement + * new operator as here below. It seems hackish, but I'm too lazy to + * do bigger refactor and maybe there is a better way which does not involve + * hardcore refactoring. */ + new (&job->settings) ExportSettings(); + job->settings.scene = scene; + job->settings.depsgraph = DEG_graph_new(scene, job->view_layer, DAG_EVAL_RENDER); + + /* TODO(Sybren): for now we only export the active scene layer. + * Later in the 2.8 development process this may be replaced by using + * a specific collection for Alembic I/O, which can then be toggled + * between "real" objects and cached Alembic files. */ + job->settings.view_layer = job->view_layer; + + job->settings.frame_start = params->frame_start; + job->settings.frame_end = params->frame_end; + job->settings.frame_samples_xform = params->frame_samples_xform; + job->settings.frame_samples_shape = params->frame_samples_shape; + job->settings.shutter_open = params->shutter_open; + job->settings.shutter_close = params->shutter_close; + + /* TODO(Sybren): For now this is ignored, until we can get selection + * detection working through Base pointers (instead of ob->flags). */ + job->settings.selected_only = params->selected_only; + + job->settings.export_face_sets = params->face_sets; + job->settings.export_normals = params->normals; + job->settings.export_uvs = params->uvs; + job->settings.export_vcols = params->vcolors; + job->settings.export_hair = params->export_hair; + job->settings.export_particles = params->export_particles; + job->settings.apply_subdiv = params->apply_subdiv; + job->settings.curves_as_mesh = params->curves_as_mesh; + job->settings.flatten_hierarchy = params->flatten_hierarchy; + + /* TODO(Sybren): visible_layer & renderable only is ignored for now, + * to be replaced with collections later in the 2.8 dev process + * (also see note above). */ + job->settings.visible_layers_only = params->visible_layers_only; + job->settings.renderable_only = params->renderable_only; + + job->settings.use_subdiv_schema = params->use_subdiv_schema; + job->settings.export_ogawa = (params->compression_type == ABC_ARCHIVE_OGAWA); + job->settings.pack_uv = params->packuv; + job->settings.global_scale = params->global_scale; + job->settings.triangulate = params->triangulate; + job->settings.quad_method = params->quad_method; + job->settings.ngon_method = params->ngon_method; + + if (job->settings.frame_start > job->settings.frame_end) { + std::swap(job->settings.frame_start, job->settings.frame_end); + } + + bool export_ok = false; + if (as_background_job) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + job->settings.scene, + "Alembic Export", + WM_JOB_PROGRESS, + WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, MEM_freeN); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + export_startjob(job, &stop, &do_update, &progress); + export_endjob(job); + export_ok = job->export_ok; + + MEM_freeN(job); + } + + return export_ok; } /* ********************** Import file ********************** */ @@ -439,499 +431,505 @@ bool ABC_export( * NOTE: this function is similar to gather_object_paths above, need to keep * them in sync. */ static std::pair<bool, AbcObjectReader *> visit_object( - const IObject &object, - AbcObjectReader::ptr_vector &readers, - ImportSettings &settings, - AbcObjectReader::ptr_vector &r_assign_as_parent) + const IObject &object, + AbcObjectReader::ptr_vector &readers, + ImportSettings &settings, + AbcObjectReader::ptr_vector &r_assign_as_parent) { - const std::string & full_name = object.getFullName(); - - if (!object.valid()) { - std::cerr << " - " - << full_name - << ": object is invalid, skipping it and all its children.\n"; - return std::make_pair(false, static_cast<AbcObjectReader *>(NULL)); - } - - /* The interpretation of data by the children determine the role of this - * object. This is especially important for Xform objects, as they can be - * either part of a Blender object or a Blender object (Empty) themselves. - */ - size_t children_claiming_this_object = 0; - size_t num_children = object.getNumChildren(); - AbcObjectReader::ptr_vector claiming_child_readers; - AbcObjectReader::ptr_vector nonclaiming_child_readers; - AbcObjectReader::ptr_vector assign_as_parent; - for (size_t i = 0; i < num_children; ++i) { - const IObject ichild = object.getChild(i); - - /* TODO: When we only support C++11, use std::tie() instead. */ - std::pair<bool, AbcObjectReader *> child_result; - child_result = visit_object(ichild, readers, settings, assign_as_parent); - - bool child_claims_this_object = child_result.first; - AbcObjectReader *child_reader = child_result.second; - - if (child_reader == NULL) { - BLI_assert(!child_claims_this_object); - } - else { - if (child_claims_this_object) { - claiming_child_readers.push_back(child_reader); - } - else { - nonclaiming_child_readers.push_back(child_reader); - } - } - - children_claiming_this_object += child_claims_this_object ? 1 : 0; - } - BLI_assert(children_claiming_this_object == claiming_child_readers.size()); - - AbcObjectReader *reader = NULL; - const MetaData &md = object.getMetaData(); - bool parent_is_part_of_this_object = false; - - if (!object.getParent()) { - /* The root itself is not an object we should import. */ - } - else if (IXform::matches(md)) { - bool create_empty; - - /* An xform can either be a Blender Object (if it contains a mesh, for - * example), but it can also be an Empty. Its correct translation to - * Blender's data model depends on its children. */ - - /* Check whether or not this object is a Maya locator, which is - * similar to empties used as parent object in Blender. */ - if (has_property(object.getProperties(), "locator")) { - create_empty = true; - } - else { - create_empty = claiming_child_readers.empty(); - } - - if (create_empty) { - reader = new AbcEmptyReader(object, settings); - } - } - else if (IPolyMesh::matches(md)) { - reader = new AbcMeshReader(object, settings); - parent_is_part_of_this_object = true; - } - else if (ISubD::matches(md)) { - reader = new AbcSubDReader(object, settings); - parent_is_part_of_this_object = true; - } - else if (INuPatch::matches(md)) { + const std::string &full_name = object.getFullName(); + + if (!object.valid()) { + std::cerr << " - " << full_name << ": object is invalid, skipping it and all its children.\n"; + return std::make_pair(false, static_cast<AbcObjectReader *>(NULL)); + } + + /* The interpretation of data by the children determine the role of this + * object. This is especially important for Xform objects, as they can be + * either part of a Blender object or a Blender object (Empty) themselves. + */ + size_t children_claiming_this_object = 0; + size_t num_children = object.getNumChildren(); + AbcObjectReader::ptr_vector claiming_child_readers; + AbcObjectReader::ptr_vector nonclaiming_child_readers; + AbcObjectReader::ptr_vector assign_as_parent; + for (size_t i = 0; i < num_children; ++i) { + const IObject ichild = object.getChild(i); + + /* TODO: When we only support C++11, use std::tie() instead. */ + std::pair<bool, AbcObjectReader *> child_result; + child_result = visit_object(ichild, readers, settings, assign_as_parent); + + bool child_claims_this_object = child_result.first; + AbcObjectReader *child_reader = child_result.second; + + if (child_reader == NULL) { + BLI_assert(!child_claims_this_object); + } + else { + if (child_claims_this_object) { + claiming_child_readers.push_back(child_reader); + } + else { + nonclaiming_child_readers.push_back(child_reader); + } + } + + children_claiming_this_object += child_claims_this_object ? 1 : 0; + } + BLI_assert(children_claiming_this_object == claiming_child_readers.size()); + + AbcObjectReader *reader = NULL; + const MetaData &md = object.getMetaData(); + bool parent_is_part_of_this_object = false; + + if (!object.getParent()) { + /* The root itself is not an object we should import. */ + } + else if (IXform::matches(md)) { + bool create_empty; + + /* An xform can either be a Blender Object (if it contains a mesh, for + * example), but it can also be an Empty. Its correct translation to + * Blender's data model depends on its children. */ + + /* Check whether or not this object is a Maya locator, which is + * similar to empties used as parent object in Blender. */ + if (has_property(object.getProperties(), "locator")) { + create_empty = true; + } + else { + create_empty = claiming_child_readers.empty(); + } + + if (create_empty) { + reader = new AbcEmptyReader(object, settings); + } + } + else if (IPolyMesh::matches(md)) { + reader = new AbcMeshReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (ISubD::matches(md)) { + reader = new AbcSubDReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (INuPatch::matches(md)) { #ifdef USE_NURBS - /* TODO(kevin): importing cyclic NURBS from other software crashes - * at the moment. This is due to the fact that NURBS in other - * software have duplicated points which causes buffer overflows in - * Blender. Need to figure out exactly how these points are - * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). - * Until this is fixed, disabling NURBS reading. */ - reader = new AbcNurbsReader(object, settings); - parent_is_part_of_this_object = true; + /* TODO(kevin): importing cyclic NURBS from other software crashes + * at the moment. This is due to the fact that NURBS in other + * software have duplicated points which causes buffer overflows in + * Blender. Need to figure out exactly how these points are + * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). + * Until this is fixed, disabling NURBS reading. */ + reader = new AbcNurbsReader(object, settings); + parent_is_part_of_this_object = true; #endif - } - else if (ICamera::matches(md)) { - reader = new AbcCameraReader(object, settings); - parent_is_part_of_this_object = true; - } - else if (IPoints::matches(md)) { - reader = new AbcPointsReader(object, settings); - parent_is_part_of_this_object = true; - } - else if (IMaterial::matches(md)) { - /* Pass for now. */ - } - else if (ILight::matches(md)) { - /* Pass for now. */ - } - else if (IFaceSet::matches(md)) { - /* Pass, those are handled in the mesh reader. */ - } - else if (ICurves::matches(md)) { - reader = new AbcCurveReader(object, settings); - parent_is_part_of_this_object = true; - } - else { - std::cerr << "Alembic object " << full_name - << " is of unsupported schema type '" - << object.getMetaData().get("schemaObjTitle") << "'" - << std::endl; - } - - if (reader) { - /* We have created a reader, which should imply that this object is - * not claimed as part of any child Alembic object. */ - BLI_assert(claiming_child_readers.empty()); - - readers.push_back(reader); - reader->incref(); - - AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( - MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); - BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path)); - BLI_addtail(&settings.cache_file->object_paths, abc_path); - - /* We can now assign this reader as parent for our children. */ - if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) { - /* TODO: When we only support C++11, use for (a: b) instead. */ - BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) { - child_reader->parent_reader = reader; - } - BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) { - child_reader->parent_reader = reader; - } - } - } - else if (object.getParent()) { - if (claiming_child_readers.size() > 0) { - /* The first claiming child will serve just fine as parent to - * our non-claiming children. Since all claiming children share - * the same XForm, it doesn't really matter which one we pick. */ - AbcObjectReader *claiming_child = claiming_child_readers[0]; - BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) { - child_reader->parent_reader = claiming_child; - } - BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) { - child_reader->parent_reader = claiming_child; - } - /* Claiming children should have our parent set as their parent. */ - BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) { - r_assign_as_parent.push_back(child_reader); - } - } - else { - /* This object isn't claimed by any child, and didn't produce - * a reader. Odd situation, could be the top Alembic object, or - * an unsupported Alembic schema. Delegate to our parent. */ - BOOST_FOREACH(AbcObjectReader *child_reader, claiming_child_readers) { - r_assign_as_parent.push_back(child_reader); - } - BOOST_FOREACH(AbcObjectReader *child_reader, nonclaiming_child_readers) { - r_assign_as_parent.push_back(child_reader); - } - BOOST_FOREACH(AbcObjectReader *child_reader, assign_as_parent) { - r_assign_as_parent.push_back(child_reader); - } - } - } - - return std::make_pair(parent_is_part_of_this_object, reader); + } + else if (ICamera::matches(md)) { + reader = new AbcCameraReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (IPoints::matches(md)) { + reader = new AbcPointsReader(object, settings); + parent_is_part_of_this_object = true; + } + else if (IMaterial::matches(md)) { + /* Pass for now. */ + } + else if (ILight::matches(md)) { + /* Pass for now. */ + } + else if (IFaceSet::matches(md)) { + /* Pass, those are handled in the mesh reader. */ + } + else if (ICurves::matches(md)) { + reader = new AbcCurveReader(object, settings); + parent_is_part_of_this_object = true; + } + else { + std::cerr << "Alembic object " << full_name << " is of unsupported schema type '" + << object.getMetaData().get("schemaObjTitle") << "'" << std::endl; + } + + if (reader) { + /* We have created a reader, which should imply that this object is + * not claimed as part of any child Alembic object. */ + BLI_assert(claiming_child_readers.empty()); + + readers.push_back(reader); + reader->incref(); + + AlembicObjectPath *abc_path = static_cast<AlembicObjectPath *>( + MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); + BLI_strncpy(abc_path->path, full_name.c_str(), sizeof(abc_path->path)); + BLI_addtail(&settings.cache_file->object_paths, abc_path); + + /* We can now assign this reader as parent for our children. */ + if (nonclaiming_child_readers.size() + assign_as_parent.size() > 0) { + /* TODO: When we only support C++11, use for (a: b) instead. */ + BOOST_FOREACH (AbcObjectReader *child_reader, nonclaiming_child_readers) { + child_reader->parent_reader = reader; + } + BOOST_FOREACH (AbcObjectReader *child_reader, assign_as_parent) { + child_reader->parent_reader = reader; + } + } + } + else if (object.getParent()) { + if (claiming_child_readers.size() > 0) { + /* The first claiming child will serve just fine as parent to + * our non-claiming children. Since all claiming children share + * the same XForm, it doesn't really matter which one we pick. */ + AbcObjectReader *claiming_child = claiming_child_readers[0]; + BOOST_FOREACH (AbcObjectReader *child_reader, nonclaiming_child_readers) { + child_reader->parent_reader = claiming_child; + } + BOOST_FOREACH (AbcObjectReader *child_reader, assign_as_parent) { + child_reader->parent_reader = claiming_child; + } + /* Claiming children should have our parent set as their parent. */ + BOOST_FOREACH (AbcObjectReader *child_reader, claiming_child_readers) { + r_assign_as_parent.push_back(child_reader); + } + } + else { + /* This object isn't claimed by any child, and didn't produce + * a reader. Odd situation, could be the top Alembic object, or + * an unsupported Alembic schema. Delegate to our parent. */ + BOOST_FOREACH (AbcObjectReader *child_reader, claiming_child_readers) { + r_assign_as_parent.push_back(child_reader); + } + BOOST_FOREACH (AbcObjectReader *child_reader, nonclaiming_child_readers) { + r_assign_as_parent.push_back(child_reader); + } + BOOST_FOREACH (AbcObjectReader *child_reader, assign_as_parent) { + r_assign_as_parent.push_back(child_reader); + } + } + } + + return std::make_pair(parent_is_part_of_this_object, reader); } enum { - ABC_NO_ERROR = 0, - ABC_ARCHIVE_FAIL, - ABC_UNSUPPORTED_HDF5, + ABC_NO_ERROR = 0, + ABC_ARCHIVE_FAIL, + ABC_UNSUPPORTED_HDF5, }; struct ImportJobData { - Main *bmain; - Scene *scene; - ViewLayer *view_layer; - wmWindowManager *wm; + Main *bmain; + Scene *scene; + ViewLayer *view_layer; + wmWindowManager *wm; - char filename[1024]; - ImportSettings settings; + char filename[1024]; + ImportSettings settings; - std::vector<AbcObjectReader *> readers; + std::vector<AbcObjectReader *> readers; - short *stop; - short *do_update; - float *progress; + short *stop; + short *do_update; + float *progress; - char error_code; - bool was_cancelled; - bool import_ok; + char error_code; + bool was_cancelled; + bool import_ok; }; static void import_startjob(void *user_data, short *stop, short *do_update, float *progress) { - SCOPE_TIMER("Alembic import, objects reading and creation"); + SCOPE_TIMER("Alembic import, objects reading and creation"); - ImportJobData *data = static_cast<ImportJobData *>(user_data); + ImportJobData *data = static_cast<ImportJobData *>(user_data); - data->stop = stop; - data->do_update = do_update; - data->progress = progress; + data->stop = stop; + data->do_update = do_update; + data->progress = progress; - WM_set_locked_interface(data->wm, true); + WM_set_locked_interface(data->wm, true); - ArchiveReader *archive = new ArchiveReader(data->filename); + ArchiveReader *archive = new ArchiveReader(data->filename); - if (!archive->valid()) { + if (!archive->valid()) { #ifndef WITH_ALEMBIC_HDF5 - data->error_code = archive->is_hdf5() ? ABC_UNSUPPORTED_HDF5 : ABC_ARCHIVE_FAIL; + data->error_code = archive->is_hdf5() ? ABC_UNSUPPORTED_HDF5 : ABC_ARCHIVE_FAIL; #else - data->error_code = ABC_ARCHIVE_FAIL; + data->error_code = ABC_ARCHIVE_FAIL; #endif - delete archive; - return; - } - - CacheFile *cache_file = static_cast<CacheFile *>(BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename))); - - /* Decrement the ID ref-count because it is going to be incremented for each - * modifier and constraint that it will be attached to, so since currently - * it is not used by anyone, its use count will off by one. */ - id_us_min(&cache_file->id); - - cache_file->is_sequence = data->settings.is_sequence; - cache_file->scale = data->settings.scale; - cache_file->handle = handle_from_archive(archive); - BLI_strncpy(cache_file->filepath, data->filename, 1024); - - data->settings.cache_file = cache_file; - - *data->do_update = true; - *data->progress = 0.05f; - - /* Parse Alembic Archive. */ - AbcObjectReader::ptr_vector assign_as_parent; - visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent); - - /* There shouldn't be any orphans. */ - BLI_assert(assign_as_parent.size() == 0); - - if (G.is_break) { - data->was_cancelled = true; - return; - } - - *data->do_update = true; - *data->progress = 0.1f; - - /* Create objects and set scene frame range. */ - - const float size = static_cast<float>(data->readers.size()); - size_t i = 0; - - chrono_t min_time = std::numeric_limits<chrono_t>::max(); - chrono_t max_time = std::numeric_limits<chrono_t>::min(); - - ISampleSelector sample_sel(0.0f); - std::vector<AbcObjectReader *>::iterator iter; - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - AbcObjectReader *reader = *iter; - - if (reader->valid()) { - reader->readObjectData(data->bmain, sample_sel); - - min_time = std::min(min_time, reader->minTime()); - max_time = std::max(max_time, reader->maxTime()); - } - else { - std::cerr << "Object " << reader->name() << " in Alembic file " - << data->filename << " is invalid.\n"; - } - - *data->progress = 0.1f + 0.3f * (++i / size); - *data->do_update = true; - - if (G.is_break) { - data->was_cancelled = true; - return; - } - } - - if (data->settings.set_frame_range) { - Scene *scene = data->scene; - - if (data->settings.is_sequence) { - SFRA = data->settings.sequence_offset; - EFRA = SFRA + (data->settings.sequence_len - 1); - CFRA = SFRA; - } - else if (min_time < max_time) { - SFRA = static_cast<int>(round(min_time * FPS)); - EFRA = static_cast<int>(round(max_time * FPS)); - CFRA = SFRA; - } - } - - /* Setup parenthood. */ - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - const AbcObjectReader *reader = *iter; - const AbcObjectReader *parent_reader = reader->parent_reader; - Object *ob = reader->object(); - - if (parent_reader == NULL || !reader->inherits_xform()) { - ob->parent = NULL; - } - else { - ob->parent = parent_reader->object(); - } - } - - /* Setup transformations and constraints. */ - i = 0; - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - AbcObjectReader *reader = *iter; - reader->setupObjectTransform(0.0f); - - *data->progress = 0.7f + 0.3f * (++i / size); - *data->do_update = true; - - if (G.is_break) { - data->was_cancelled = true; - return; - } - } + delete archive; + return; + } + + CacheFile *cache_file = static_cast<CacheFile *>( + BKE_cachefile_add(data->bmain, BLI_path_basename(data->filename))); + + /* Decrement the ID ref-count because it is going to be incremented for each + * modifier and constraint that it will be attached to, so since currently + * it is not used by anyone, its use count will off by one. */ + id_us_min(&cache_file->id); + + cache_file->is_sequence = data->settings.is_sequence; + cache_file->scale = data->settings.scale; + cache_file->handle = handle_from_archive(archive); + BLI_strncpy(cache_file->filepath, data->filename, 1024); + + data->settings.cache_file = cache_file; + + *data->do_update = true; + *data->progress = 0.05f; + + /* Parse Alembic Archive. */ + AbcObjectReader::ptr_vector assign_as_parent; + visit_object(archive->getTop(), data->readers, data->settings, assign_as_parent); + + /* There shouldn't be any orphans. */ + BLI_assert(assign_as_parent.size() == 0); + + if (G.is_break) { + data->was_cancelled = true; + return; + } + + *data->do_update = true; + *data->progress = 0.1f; + + /* Create objects and set scene frame range. */ + + const float size = static_cast<float>(data->readers.size()); + size_t i = 0; + + chrono_t min_time = std::numeric_limits<chrono_t>::max(); + chrono_t max_time = std::numeric_limits<chrono_t>::min(); + + ISampleSelector sample_sel(0.0f); + std::vector<AbcObjectReader *>::iterator iter; + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + AbcObjectReader *reader = *iter; + + if (reader->valid()) { + reader->readObjectData(data->bmain, sample_sel); + + min_time = std::min(min_time, reader->minTime()); + max_time = std::max(max_time, reader->maxTime()); + } + else { + std::cerr << "Object " << reader->name() << " in Alembic file " << data->filename + << " is invalid.\n"; + } + + *data->progress = 0.1f + 0.3f * (++i / size); + *data->do_update = true; + + if (G.is_break) { + data->was_cancelled = true; + return; + } + } + + if (data->settings.set_frame_range) { + Scene *scene = data->scene; + + if (data->settings.is_sequence) { + SFRA = data->settings.sequence_offset; + EFRA = SFRA + (data->settings.sequence_len - 1); + CFRA = SFRA; + } + else if (min_time < max_time) { + SFRA = static_cast<int>(round(min_time * FPS)); + EFRA = static_cast<int>(round(max_time * FPS)); + CFRA = SFRA; + } + } + + /* Setup parenthood. */ + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + const AbcObjectReader *reader = *iter; + const AbcObjectReader *parent_reader = reader->parent_reader; + Object *ob = reader->object(); + + if (parent_reader == NULL || !reader->inherits_xform()) { + ob->parent = NULL; + } + else { + ob->parent = parent_reader->object(); + } + } + + /* Setup transformations and constraints. */ + i = 0; + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + AbcObjectReader *reader = *iter; + reader->setupObjectTransform(0.0f); + + *data->progress = 0.7f + 0.3f * (++i / size); + *data->do_update = true; + + if (G.is_break) { + data->was_cancelled = true; + return; + } + } } static void import_endjob(void *user_data) { - SCOPE_TIMER("Alembic import, cleanup"); - - ImportJobData *data = static_cast<ImportJobData *>(user_data); - - std::vector<AbcObjectReader *>::iterator iter; - - /* Delete objects on cancelation. */ - if (data->was_cancelled) { - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - Object *ob = (*iter)->object(); - - /* It's possible that cancellation occurred between the creation of - * the reader and the creation of the Blender object. */ - if (ob == NULL) continue; - - BKE_id_free_us(data->bmain, ob); - } - } - else { - /* Add object to scene. */ - Base *base; - LayerCollection *lc; - ViewLayer *view_layer = data->view_layer; - - BKE_view_layer_base_deselect_all(view_layer); - - lc = BKE_layer_collection_get_active(view_layer); - - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - Object *ob = (*iter)->object(); - - BKE_collection_object_add(data->bmain, lc->collection, ob); - - base = BKE_view_layer_base_find(view_layer, ob); - /* TODO: is setting active needed? */ - BKE_view_layer_base_select_and_set_active(view_layer, base); - - DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE); - DEG_id_tag_update_ex(data->bmain, &ob->id, - ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION | ID_RECALC_BASE_FLAGS); - } - - DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS); - DEG_relations_tag_update(data->bmain); - } - - for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - AbcObjectReader *reader = *iter; - reader->decref(); - - if (reader->refcount() == 0) { - delete reader; - } - } - - WM_set_locked_interface(data->wm, false); - - switch (data->error_code) { - default: - case ABC_NO_ERROR: - data->import_ok = !data->was_cancelled; - break; - case ABC_ARCHIVE_FAIL: - WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail."); - break; - case ABC_UNSUPPORTED_HDF5: - WM_report(RPT_ERROR, "Alembic archive in obsolete HDF5 format is not supported."); - break; - } - - WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene); + SCOPE_TIMER("Alembic import, cleanup"); + + ImportJobData *data = static_cast<ImportJobData *>(user_data); + + std::vector<AbcObjectReader *>::iterator iter; + + /* Delete objects on cancelation. */ + if (data->was_cancelled) { + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + Object *ob = (*iter)->object(); + + /* It's possible that cancellation occurred between the creation of + * the reader and the creation of the Blender object. */ + if (ob == NULL) + continue; + + BKE_id_free_us(data->bmain, ob); + } + } + else { + /* Add object to scene. */ + Base *base; + LayerCollection *lc; + ViewLayer *view_layer = data->view_layer; + + BKE_view_layer_base_deselect_all(view_layer); + + lc = BKE_layer_collection_get_active(view_layer); + + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + Object *ob = (*iter)->object(); + + BKE_collection_object_add(data->bmain, lc->collection, ob); + + base = BKE_view_layer_base_find(view_layer, ob); + /* TODO: is setting active needed? */ + BKE_view_layer_base_select_and_set_active(view_layer, base); + + DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update_ex(data->bmain, + &ob->id, + ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION | + ID_RECALC_BASE_FLAGS); + } + + DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS); + DEG_relations_tag_update(data->bmain); + } + + for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { + AbcObjectReader *reader = *iter; + reader->decref(); + + if (reader->refcount() == 0) { + delete reader; + } + } + + WM_set_locked_interface(data->wm, false); + + switch (data->error_code) { + default: + case ABC_NO_ERROR: + data->import_ok = !data->was_cancelled; + break; + case ABC_ARCHIVE_FAIL: + WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail."); + break; + case ABC_UNSUPPORTED_HDF5: + WM_report(RPT_ERROR, "Alembic archive in obsolete HDF5 format is not supported."); + break; + } + + WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene); } static void import_freejob(void *user_data) { - ImportJobData *data = static_cast<ImportJobData *>(user_data); - delete data; + ImportJobData *data = static_cast<ImportJobData *>(user_data); + delete data; } -bool ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, - bool set_frame_range, int sequence_len, int offset, - bool validate_meshes, bool as_background_job) +bool ABC_import(bContext *C, + const char *filepath, + float scale, + bool is_sequence, + bool set_frame_range, + int sequence_len, + int offset, + bool validate_meshes, + bool as_background_job) { - /* Using new here since MEM_* funcs do not call ctor to properly initialize - * data. */ - ImportJobData *job = new ImportJobData(); - job->bmain = CTX_data_main(C); - job->scene = CTX_data_scene(C); - job->view_layer = CTX_data_view_layer(C); - job->wm = CTX_wm_manager(C); - job->import_ok = false; - BLI_strncpy(job->filename, filepath, 1024); - - job->settings.scale = scale; - job->settings.is_sequence = is_sequence; - job->settings.set_frame_range = set_frame_range; - job->settings.sequence_len = sequence_len; - job->settings.sequence_offset = offset; - job->settings.validate_meshes = validate_meshes; - job->error_code = ABC_NO_ERROR; - job->was_cancelled = false; - - G.is_break = false; - - bool import_ok = false; - if (as_background_job) { - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - job->scene, - "Alembic Import", - WM_JOB_PROGRESS, - WM_JOB_TYPE_ALEMBIC); - - /* setup job */ - WM_jobs_customdata_set(wm_job, job, import_freejob); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob); - - WM_jobs_start(CTX_wm_manager(C), wm_job); - } - else { - /* Fake a job context, so that we don't need NULL pointer checks while importing. */ - short stop = 0, do_update = 0; - float progress = 0.f; - - import_startjob(job, &stop, &do_update, &progress); - import_endjob(job); - import_ok = job->import_ok; - - import_freejob(job); - } - - return import_ok; + /* Using new here since MEM_* funcs do not call ctor to properly initialize + * data. */ + ImportJobData *job = new ImportJobData(); + job->bmain = CTX_data_main(C); + job->scene = CTX_data_scene(C); + job->view_layer = CTX_data_view_layer(C); + job->wm = CTX_wm_manager(C); + job->import_ok = false; + BLI_strncpy(job->filename, filepath, 1024); + + job->settings.scale = scale; + job->settings.is_sequence = is_sequence; + job->settings.set_frame_range = set_frame_range; + job->settings.sequence_len = sequence_len; + job->settings.sequence_offset = offset; + job->settings.validate_meshes = validate_meshes; + job->error_code = ABC_NO_ERROR; + job->was_cancelled = false; + + G.is_break = false; + + bool import_ok = false; + if (as_background_job) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + job->scene, + "Alembic Import", + WM_JOB_PROGRESS, + WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, import_freejob); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while importing. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + import_startjob(job, &stop, &do_update, &progress); + import_endjob(job); + import_ok = job->import_ok; + + import_freejob(job); + } + + return import_ok; } /* ************************************************************************** */ void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale) { - if (!reader) { - return; - } + if (!reader) { + return; + } - AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - bool is_constant = false; - abc_reader->read_matrix(r_mat, time, scale, is_constant); + bool is_constant = false; + abc_reader->read_matrix(r_mat, time, scale, is_constant); } /* ************************************************************************** */ @@ -943,71 +941,74 @@ Mesh *ABC_read_mesh(CacheReader *reader, const char **err_str, int read_flag) { - AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - IObject iobject = abc_reader->iobject(); - - if (!iobject.valid()) { - *err_str = "Invalid object: verify object path"; - return NULL; - } - - const ObjectHeader &header = iobject.getHeader(); - if (!abc_reader->accepts_object_type(header, ob, err_str)) { - /* err_str is set by acceptsObjectType() */ - return NULL; - } - - /* kFloorIndex is used to be compatible with non-interpolating - * properties; they use the floor. */ - ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex); - return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str); + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); + IObject iobject = abc_reader->iobject(); + + if (!iobject.valid()) { + *err_str = "Invalid object: verify object path"; + return NULL; + } + + const ObjectHeader &header = iobject.getHeader(); + if (!abc_reader->accepts_object_type(header, ob, err_str)) { + /* err_str is set by acceptsObjectType() */ + return NULL; + } + + /* kFloorIndex is used to be compatible with non-interpolating + * properties; they use the floor. */ + ISampleSelector sample_sel(time, ISampleSelector::kFloorIndex); + return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str); } /* ************************************************************************** */ void CacheReader_free(CacheReader *reader) { - AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - abc_reader->decref(); + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); + abc_reader->decref(); - if (abc_reader->refcount() == 0) { - delete abc_reader; - } + if (abc_reader->refcount() == 0) { + delete abc_reader; + } } void CacheReader_incref(CacheReader *reader) { - AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - abc_reader->incref(); + AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); + abc_reader->incref(); } -CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path) +CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, + CacheReader *reader, + Object *object, + const char *object_path) { - if (object_path[0] == '\0') { - return reader; - } + if (object_path[0] == '\0') { + return reader; + } - ArchiveReader *archive = archive_from_handle(handle); + ArchiveReader *archive = archive_from_handle(handle); - if (!archive || !archive->valid()) { - return reader; - } + if (!archive || !archive->valid()) { + return reader; + } - IObject iobject; - find_iobject(archive->getTop(), iobject, object_path); + IObject iobject; + find_iobject(archive->getTop(), iobject, object_path); - if (reader) { - CacheReader_free(reader); - } + if (reader) { + CacheReader_free(reader); + } - ImportSettings settings; - AbcObjectReader *abc_reader = create_reader(iobject, settings); - if (abc_reader == NULL) { - /* This object is not supported */ - return NULL; - } - abc_reader->object(object); - abc_reader->incref(); + ImportSettings settings; + AbcObjectReader *abc_reader = create_reader(iobject, settings); + if (abc_reader == NULL) { + /* This object is not supported */ + return NULL; + } + abc_reader->object(object); + abc_reader->incref(); - return reinterpret_cast<CacheReader *>(abc_reader); + return reinterpret_cast<CacheReader *>(abc_reader); } |