diff options
author | Sybren A. Stüvel <sybren@blender.org> | 2020-03-06 18:19:35 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@blender.org> | 2020-03-06 18:19:45 +0300 |
commit | eb522af4fec58876ac1b0a73ad9bcdae2d82d33f (patch) | |
tree | 485c6a1fb23b5be256757375e2157378d3a5c61b /source/blender/alembic | |
parent | ff60dd8b18ed00902e5bdfd36882072db7af8735 (diff) |
Cleanup: move Alembic, AVI, Collada, and USD to `source/blender/io`
This moves the `alembic`, `avi`, `collada`, and `usd` modules into a common
`io` directory.
This also cleans up some `#include "../../{somedir}/{somefile}.h"` by
adding `../../io/{somedir}` to `CMakeLists.txt` and then just using
`#include "{somefile}.h"`.
No functional changes.
Diffstat (limited to 'source/blender/alembic')
45 files changed, 0 insertions, 8617 deletions
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h deleted file mode 100644 index 878dbfc2a53..00000000000 --- a/source/blender/alembic/ABC_alembic.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_ALEMBIC_H__ -#define __ABC_ALEMBIC_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct CacheReader; -struct ListBase; -struct Main; -struct Mesh; -struct Object; -struct Scene; -struct bContext; - -typedef struct AbcArchiveHandle AbcArchiveHandle; - -enum { - 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_objects_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 - * parameter, and return a boolean. - * - * When as_background_job=true, returns false immediately after scheduling - * a background job. - * - * When as_background_job=false, performs the export synchronously, and returns - * 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_import(struct 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); - -AbcArchiveHandle *ABC_create_handle(struct Main *bmain, - const char *filename, - struct ListBase *object_paths); - -void ABC_free_handle(AbcArchiveHandle *handle); - -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, - struct Object *ob, - struct Mesh *current_mesh, - const float time, - const char **err_str, - int flags); - -bool ABC_mesh_topology_changed(struct CacheReader *reader, - struct Object *ob, - struct Mesh *existing_mesh, - const float time, - const char **err_str); - -void CacheReader_incref(struct CacheReader *reader); -void CacheReader_free(struct CacheReader *reader); - -struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle, - struct CacheReader *reader, - struct Object *object, - const char *object_path); - -#ifdef __cplusplus -} -#endif - -#endif /* __ABC_ALEMBIC_H__ */ diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt deleted file mode 100644 index 8bb7051982a..00000000000 --- a/source/blender/alembic/CMakeLists.txt +++ /dev/null @@ -1,110 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# The Original Code is Copyright (C) 2006, Blender Foundation -# All rights reserved. -# ***** END GPL LICENSE BLOCK ***** - -set(INC - . - ../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} -) - -set(SRC - intern/abc_customdata.cc - intern/abc_exporter.cc - intern/abc_reader_archive.cc - intern/abc_reader_camera.cc - intern/abc_reader_curves.cc - intern/abc_reader_mesh.cc - intern/abc_reader_nurbs.cc - intern/abc_reader_object.cc - intern/abc_reader_points.cc - intern/abc_reader_transform.cc - intern/abc_util.cc - intern/abc_writer_archive.cc - intern/abc_writer_camera.cc - intern/abc_writer_curves.cc - intern/abc_writer_hair.cc - intern/abc_writer_mball.cc - intern/abc_writer_mesh.cc - intern/abc_writer_nurbs.cc - intern/abc_writer_object.cc - intern/abc_writer_points.cc - intern/abc_writer_transform.cc - intern/alembic_capi.cc - - ABC_alembic.h - intern/abc_customdata.h - intern/abc_exporter.h - intern/abc_reader_archive.h - intern/abc_reader_camera.h - intern/abc_reader_curves.h - intern/abc_reader_mesh.h - intern/abc_reader_nurbs.h - intern/abc_reader_object.h - intern/abc_reader_points.h - intern/abc_reader_transform.h - intern/abc_util.h - intern/abc_writer_archive.h - intern/abc_writer_camera.h - intern/abc_writer_curves.h - intern/abc_writer_hair.h - intern/abc_writer_mball.h - intern/abc_writer_mesh.h - intern/abc_writer_nurbs.h - intern/abc_writer_object.h - intern/abc_writer_points.h - intern/abc_writer_transform.h -) - -set(LIB - bf_blenkernel - bf_blenlib - - ${ALEMBIC_LIBRARIES} - ${OPENEXR_LIBRARIES} -) - -if(WITH_ALEMBIC_HDF5) - add_definitions(-DWITH_ALEMBIC_HDF5) - list(APPEND LIB - ${HDF5_LIBRARIES} - ) -endif() - -list(APPEND LIB - ${BOOST_LIBRARIES} -) - -blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc deleted file mode 100644 index c5f60ac3e29..00000000000 --- a/source/blender/alembic/intern/abc_customdata.cc +++ /dev/null @@ -1,484 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_customdata.h" - -#include <Alembic/AbcGeom/All.h> -#include <algorithm> -#include <unordered_map> - -extern "C" { -#include "DNA_customdata_types.h" -#include "DNA_meshdata_types.h" - -#include "BLI_math_base.h" -#include "BLI_utildefines.h" - -#include "BKE_customdata.h" -} - -/* NOTE: for now only UVs and Vertex Colors are supported for streaming. - * Although Alembic only allows for a single UV layer per {I|O}Schema, and does - * not have a vertex color concept, there is a convention between DCCs to write - * 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::kFacevaryingScope; -using Alembic::AbcGeom::kVertexScope; - -using Alembic::Abc::C4fArraySample; -using Alembic::Abc::UInt32ArraySample; -using Alembic::Abc::V2fArraySample; - -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); - } - } - } - } -} - -const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data) -{ - const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV); - - if (active_uvlayer < 0) { - return ""; - } - - void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer); - - get_uvs(config, sample.uvs, sample.indices, cd_data); - - return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer); -} - -/* Convention to write UVs: - * - V2fGeomParam on the arbGeomParam - * - 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) -{ - std::vector<uint32_t> indices; - std::vector<Imath::V2f> uvs; - - get_uvs(config, uvs, indices, data); - - if (indices.empty() || uvs.empty()) { - return; - } - - OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1); - - OV2fGeomParam::Sample sample(V2fArraySample(&uvs.front(), uvs.size()), - UInt32ArraySample(&indices.front(), indices.size()), - kFacevaryingScope); - - 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) -{ - 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; - - buffer.reserve(config.totvert); - indices.reserve(config.totvert); - - 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 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; - - buffer.push_back(col); - indices.push_back(buffer.size() - 1); - } - } - - OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1); - - OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()), - UInt32ArraySample(&indices.front(), indices.size()), - kVertexScope); - - param.set(sample); -} - -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); - } - } -} - -/* ************************************************************************** */ - -using Alembic::Abc::C3fArraySamplePtr; -using Alembic::Abc::C4fArraySamplePtr; -using Alembic::Abc::PropertyHeader; - -using Alembic::AbcGeom::IC3fGeomParam; -using Alembic::AbcGeom::IC4fGeomParam; -using Alembic::AbcGeom::IV2fGeomParam; - -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]; - } - } -} - -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; -} - -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.mesh, 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, - const PropertyHeader &prop_header, - const CDStreamConfig &config, - const Alembic::Abc::ISampleSelector &iss) -{ - IV2fGeomParam uv_param(prop, prop_header.getName()); - - if (!uv_param.isIndexed()) { - return; - } - - IV2fGeomParam::Sample sample; - uv_param.getIndexed(sample, iss); - - if (uv_param.getScope() != kFacevaryingScope) { - return; - } - - void *cd_data = config.add_customdata_cb(config.mesh, prop_header.getName().c_str(), CD_MLOOPUV); - - read_uvs(config, cd_data, sample.getVals(), sample.getIndices()); -} - -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; - } - } -} diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h deleted file mode 100644 index 6107e230627..00000000000 --- a/source/blender/alembic/intern/abc_customdata.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_CUSTOMDATA_H__ -#define __ABC_CUSTOMDATA_H__ - -#include <Alembic/Abc/All.h> -#include <Alembic/AbcGeom/All.h> - -struct CustomData; -struct MLoop; -struct MLoopUV; -struct MPoly; -struct MVert; -struct Mesh; - -using Alembic::Abc::ICompoundProperty; -using Alembic::Abc::OCompoundProperty; - -struct UVSample { - 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 data such that it updates the custom data holder and its pointers properly. */ - Mesh *mesh; - void *(*add_customdata_cb)(Mesh *mesh, 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), - mesh(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. - * Returns the name of the UV layer. - * - * For now the active layer is used, maybe needs a better way to choose this. */ -const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data); - -void write_custom_data(const OCompoundProperty &prop, - const CDStreamConfig &config, - CustomData *data, - int data_type); - -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__ */ diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc deleted file mode 100644 index a58b0a29e5e..00000000000 --- a/source/blender/alembic/intern/abc_exporter.cc +++ /dev/null @@ -1,677 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_exporter.h" - -#include <cmath> - -#include "abc_writer_archive.h" -#include "abc_writer_camera.h" -#include "abc_writer_curves.h" -#include "abc_writer_hair.h" -#include "abc_writer_mball.h" -#include "abc_writer_mesh.h" -#include "abc_writer_nurbs.h" -#include "abc_writer_points.h" -#include "abc_writer_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_meta_types.h" -#include "DNA_mesh_types.h" -#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_fluid_types.h" - -#include "BLI_string.h" - -#ifdef WIN32 -/* needed for MSCV because of snprintf from BLI_string */ -# include "BLI_winstuff.h" -#endif - -#include "BKE_anim.h" -#include "BKE_global.h" -#include "BKE_idprop.h" -#include "BKE_layer.h" -#include "BKE_main.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_particle.h" -#include "BKE_scene.h" - -#include "DEG_depsgraph_query.h" -} - -using Alembic::Abc::OBox3dProperty; -using Alembic::Abc::TimeSamplingPtr; - -/* ************************************************************************** */ - -ExportSettings::ExportSettings() - : scene(NULL), - view_layer(NULL), - depsgraph(NULL), - logger(), - selected_only(false), - visible_objects_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) -{ -} - -static bool object_is_smoke_sim(Object *ob) -{ - ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid); - - if (md) { - FluidModifierData *smd = reinterpret_cast<FluidModifierData *>(md); - return (smd->type == MOD_FLUID_TYPE_DOMAIN && smd->domain && - smd->domain->type == FLUID_DOMAIN_TYPE_GAS); - } - - 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; - } -} - -/** - * Returns whether this object should be exported into the Alembic file. - * - * \param settings: export settings, used for options like 'selected only'. - * \param ob: the object's base in question. - * \param is_duplicated: Normally false; true when the object is instanced - * into the scene by a dupli-object (e.g. part of a dupligroup). - * 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, - 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_objects_only && !BASE_VISIBLE(v3d, base)) { - return false; - } - } - - Object *ob_eval = DEG_get_evaluated_object(settings->depsgraph, base->object); - if ((ob_eval->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { - /* XXX fix after 2.80: the object was not part of the depsgraph, and thus we cannot get the - * evaluated copy to export. This will be handled more elegantly in the new - * AbstractHierarchyIterator that Sybren is working on. This condition is temporary, and avoids - * a BLI_assert() failure getting the evaluated mesh of this object. */ - 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) -{ -} - -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; -} - -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); - } -} - -Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step) -{ - std::vector<double> samples; - - if (m_settings.frame_start == m_settings.frame_end) { - return TimeSamplingPtr(new Alembic::Abc::TimeSampling()); - } - - getShutterSamples(step, true, samples); - - /* 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); - - return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); -} - -void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &frames) -{ - frames.clear(); - - std::vector<double> 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]); - } - } -} - -void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled) -{ - std::string abc_scene_name; - - if (m_bmain->name[0] != '\0') { - char scene_file_name[FILE_MAX]; - BLI_strncpy(scene_file_name, m_bmain->name, FILE_MAX); - abc_scene_name = scene_file_name; - } - else { - abc_scene_name = "untitled"; - } - - m_writer = new ArchiveWriter( - m_filename, abc_scene_name, m_settings.scene, m_settings.export_ogawa); - - /* Create time samplings for transforms and shapes. */ - - TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform); - - m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_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); - } - - OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds( - m_writer->archive(), m_trans_sampling_index); - - createTransformWritersHierarchy(); - createShapeWriters(); - - /* Make a list of frames to export. */ - - 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); - - /* Merge all frames needed. */ - std::set<double> frames(xform_frames); - frames.insert(shape_frames.begin(), shape_frames.end()); - - /* Export all frames. */ - - 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; - - for (; begin != end; ++begin) { - *progress = (++i / size); - *do_update = 1; - - if (G.is_break) { - *was_canceled = true; - break; - } - - const double frame = *begin; - - /* '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 (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(); - } - - /* 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); - } - - 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); - } - } - } -} - -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); - } -} - -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; -} - -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); - } -} - -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); - } -} - -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 || psys->part->type == PART_FLUID_FLIP || - psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_BUBBLE || - psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_TRACER || - psys->part->type == PART_FLUID_SPRAYFOAM || - psys->part->type == PART_FLUID_SPRAYBUBBLE || - psys->part->type == PART_FLUID_FOAMBUBBLE || - psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE)) { - 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; - } - } -} - -AbcTransformWriter *AbcExporter::getXForm(const std::string &name) -{ - std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name); - - if (it == m_xforms.end()) { - return NULL; - } - - 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); -} diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h deleted file mode 100644 index 398004d2ec5..00000000000 --- a/source/blender/alembic/intern/abc_exporter.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_EXPORTER_H__ -#define __ABC_EXPORTER_H__ - -#include <Alembic/Abc/All.h> -#include <map> -#include <set> -#include <vector> - -#include "abc_util.h" - -class AbcObjectWriter; -class AbcTransformWriter; -class ArchiveWriter; - -struct Base; -struct Depsgraph; -struct Main; -struct Object; -struct Scene; -struct ViewLayer; - -struct ExportSettings { - ExportSettings(); - - Scene *scene; - /** Scene layer to export; all its objects will be exported, unless selected_only=true. */ - ViewLayer *view_layer; - Depsgraph *depsgraph; - SimpleLogger logger; - - bool selected_only; - bool visible_objects_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; -}; - -class AbcExporter { - Main *m_bmain; - ExportSettings &m_settings; - - const char *m_filename; - - unsigned int m_trans_sampling_index, m_shape_sampling_index; - - ArchiveWriter *m_writer; - - /* 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; - - public: - AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); - ~AbcExporter(); - - void operator()(short *do_update, 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); - - 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); - - AbcTransformWriter *getXForm(const std::string &name); - - void setCurrentFrame(Main *bmain, double t); -}; - -#endif /* __ABC_EXPORTER_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_archive.cc b/source/blender/alembic/intern/abc_reader_archive.cc deleted file mode 100644 index 6ad44553701..00000000000 --- a/source/blender/alembic/intern/abc_reader_archive.cc +++ /dev/null @@ -1,140 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_archive.h" - -extern "C" { -#include "BKE_main.h" - -#include "BLI_path_util.h" -#include "BLI_string.h" -} - -#ifdef WIN32 -# include "utfconv.h" -#endif - -#include <fstream> - -using Alembic::Abc::ErrorHandler; -using Alembic::Abc::Exception; -using Alembic::Abc::IArchive; -using Alembic::Abc::kWrapExisting; - -static IArchive open_archive(const std::string &filename, - const std::vector<std::istream *> &input_streams, - bool &is_hdf5) -{ - is_hdf5 = false; - - 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'; - -#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(); - } -#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(); -#endif - } - - return IArchive(); -} - -ArchiveReader::ArchiveReader(struct Main *bmain, const char *filename) -{ - char abs_filename[FILE_MAX]; - BLI_strncpy(abs_filename, filename, FILE_MAX); - BLI_path_abs(abs_filename, BKE_main_blendfile_path(bmain)); - -#ifdef WIN32 - UTF16_ENCODE(abs_filename); - std::wstring wstr(abs_filename_16); - m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary); - UTF16_UN_ENCODE(abs_filename); -#else - m_infile.open(abs_filename, std::ios::in | std::ios::binary); -#endif - - m_streams.push_back(&m_infile); - - m_archive = open_archive(abs_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(); - } -} - -bool ArchiveReader::is_hdf5() const -{ - return m_is_hdf5; -} - -bool ArchiveReader::valid() const -{ - return m_archive.valid(); -} - -Alembic::Abc::IObject ArchiveReader::getTop() -{ - return m_archive.getTop(); -} diff --git a/source/blender/alembic/intern/abc_reader_archive.h b/source/blender/alembic/intern/abc_reader_archive.h deleted file mode 100644 index bdb53bd0b8c..00000000000 --- a/source/blender/alembic/intern/abc_reader_archive.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_ARCHIVE_H__ -#define __ABC_READER_ARCHIVE_H__ - -#include <Alembic/Abc/All.h> - -#ifdef WITH_ALEMBIC_HDF5 -# include <Alembic/AbcCoreHDF5/All.h> -#endif - -#include <Alembic/AbcCoreOgawa/All.h> - -#include <fstream> - -struct Main; -struct Scene; - -/* Wrappers around input and output archives. The goal is to be able to use - * streams so that unicode paths work on Windows (T49112), and to make sure that - * the stream objects remain valid as long as the archives are open. - */ - -class ArchiveReader { - Alembic::Abc::IArchive m_archive; - std::ifstream m_infile; - std::vector<std::istream *> m_streams; - bool m_is_hdf5; - - public: - ArchiveReader(struct Main *bmain, const char *filename); - - 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; - - Alembic::Abc::IObject getTop(); -}; - -#endif /* __ABC_READER_ARCHIVE_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_camera.cc b/source/blender/alembic/intern/abc_reader_camera.cc deleted file mode 100644 index ab506f32cbe..00000000000 --- a/source/blender/alembic/intern/abc_reader_camera.cc +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_camera.h" -#include "abc_reader_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_camera_types.h" -#include "DNA_object_types.h" - -#include "BKE_camera.h" -#include "BKE_object.h" - -#include "BLI_math.h" -} - -using Alembic::AbcGeom::CameraSample; -using Alembic::AbcGeom::ICamera; -using Alembic::AbcGeom::ICompoundProperty; -using Alembic::AbcGeom::IFloatProperty; -using Alembic::AbcGeom::ISampleSelector; -using Alembic::AbcGeom::kWrapExisting; - -AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings) - : AbcObjectReader(object, settings) -{ - 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); -} - -bool AbcCameraReader::valid() const -{ - return m_schema.valid(); -} - -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; -} - -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->dof.focus_distance = static_cast<float>(cam_sample.getFocusDistance()); - bcam->dof.aperture_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_reader_camera.h b/source/blender/alembic/intern/abc_reader_camera.h deleted file mode 100644 index 1d9763b0454..00000000000 --- a/source/blender/alembic/intern/abc_reader_camera.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_CAMERA_H__ -#define __ABC_READER_CAMERA_H__ - -#include "abc_reader_object.h" - -class AbcCameraReader : public AbcObjectReader { - Alembic::AbcGeom::ICameraSchema m_schema; - - 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; - - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); -}; - -#endif /* __ABC_READER_CAMERA_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_curves.cc b/source/blender/alembic/intern/abc_reader_curves.cc deleted file mode 100644 index 1be164c7c94..00000000000 --- a/source/blender/alembic/intern/abc_reader_curves.cc +++ /dev/null @@ -1,354 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_curves.h" -#include "abc_reader_transform.h" -#include "abc_util.h" - -#include <cstdio> - -#include "MEM_guardedalloc.h" - -extern "C" { -#include "DNA_curve_types.h" -#include "DNA_object_types.h" - -#include "BLI_listbase.h" - -#include "BKE_curve.h" -#include "BKE_mesh.h" -#include "BKE_object.h" -} - -using Alembic::Abc::FloatArraySamplePtr; -using Alembic::Abc::Int32ArraySamplePtr; -using Alembic::Abc::P3fArraySamplePtr; -using Alembic::Abc::PropertyHeader; -using Alembic::Abc::UcharArraySamplePtr; - -using Alembic::AbcGeom::CurvePeriodicity; -using Alembic::AbcGeom::ICompoundProperty; -using Alembic::AbcGeom::ICurves; -using Alembic::AbcGeom::ICurvesSchema; -using Alembic::AbcGeom::IFloatGeomParam; -using Alembic::AbcGeom::IInt16Property; -using Alembic::AbcGeom::ISampleSelector; -using Alembic::AbcGeom::kWrapExisting; - -AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings) - : AbcObjectReader(object, settings) -{ - 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); -} - -bool AbcCurveReader::valid() const -{ - 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 -{ - 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); - - 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); - } - } - - 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); - - if (has_animations(m_curves_schema, m_settings)) { - addCacheModifier(); - } -} - -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); - } -} - -/* NOTE: Alembic only stores data about control points, but the Mesh - * passed from the cache modifier contains the displist, which has more data - * than the control points, so to avoid corrupting the displist we modify the - * object directly and create a new Mesh from that. Also we might need to - * create new or delete existing NURBS in the curve. - */ -Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh, - const ISampleSelector &sample_sel, - 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); -} diff --git a/source/blender/alembic/intern/abc_reader_curves.h b/source/blender/alembic/intern/abc_reader_curves.h deleted file mode 100644 index 1e4f28edc51..00000000000 --- a/source/blender/alembic/intern/abc_reader_curves.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_CURVES_H__ -#define __ABC_READER_CURVES_H__ - -#include "abc_reader_object.h" -#include "abc_reader_mesh.h" - -struct Curve; - -#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution" - -class AbcCurveReader : public AbcObjectReader { - Alembic::AbcGeom::ICurvesSchema m_curves_schema; - - 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; - - 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_READER_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_mesh.cc b/source/blender/alembic/intern/abc_reader_mesh.cc deleted file mode 100644 index a4e412695c3..00000000000 --- a/source/blender/alembic/intern/abc_reader_mesh.cc +++ /dev/null @@ -1,889 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_mesh.h" -#include "abc_reader_transform.h" -#include "abc_util.h" - -#include <algorithm> - -#include "MEM_guardedalloc.h" - -extern "C" { -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" - -#include "BLI_math_geom.h" - -#include "BKE_main.h" -#include "BKE_material.h" -#include "BKE_mesh.h" -#include "BKE_modifier.h" -#include "BKE_object.h" -} - -using Alembic::Abc::Int32ArraySamplePtr; -using Alembic::Abc::P3fArraySamplePtr; - -using Alembic::AbcGeom::IFaceSet; -using Alembic::AbcGeom::IFaceSetSchema; -using Alembic::AbcGeom::IN3fGeomParam; -using Alembic::AbcGeom::IObject; -using Alembic::AbcGeom::IPolyMesh; -using Alembic::AbcGeom::IPolyMeshSchema; -using Alembic::AbcGeom::ISampleSelector; -using Alembic::AbcGeom::ISubD; -using Alembic::AbcGeom::ISubDSchema; -using Alembic::AbcGeom::IV2fGeomParam; -using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::N3fArraySample; -using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::UInt32ArraySamplePtr; -using Alembic::AbcGeom::V2fArraySamplePtr; - -/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ - -/* Some helpers for mesh generation */ -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); - - 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) -{ - 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; - } - - BKE_object_material_assign(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA); - } - } -} - -} /* namespace utils */ - -struct AbcMeshData { - Int32ArraySamplePtr face_indices; - Int32ArraySamplePtr face_counts; - - P3fArraySamplePtr positions; - P3fArraySamplePtr ceil_positions; - - V2fArraySamplePtr uvs; - UInt32ArraySamplePtr uvs_indices; -}; - -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]; - - interp_v3_v3v3(tmp, floor_pos.getValue(), ceil_pos.getValue(), weight); - copy_zup_from_yup(mvert.co, tmp); - - mvert.bweight = 0; - } -} - -static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data) -{ - MVert *mverts = config.mvert; - const P3fArraySamplePtr &positions = mesh_data.positions; - - 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, nullptr); -} - -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]; - - copy_zup_from_yup(mvert.co, pos_in.getValue()); - - mvert.bweight = 0; - - if (normals) { - Imath::V3f nor_in = (*normals)[i]; - - short no[3]; - normal_float_to_short_v3(no, nor_in.getValue()); - - 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 size_t uvs_size = uvs == nullptr ? 0 : uvs->size(); - - const UInt32ArraySamplePtr &uvs_indices = mesh_data.uvs_indices; - - 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; - - /* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded, - * this is encoded in custom loop normals. See T71246. */ - 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]; - - /* Some Alembic files are broken (or at least export UVs in a way we don't expect). */ - if (uv_index >= uvs_size) { - continue; - } - - loopuv.uv[0] = (*uvs)[uv_index][0]; - loopuv.uv[1] = (*uvs)[uv_index][1]; - } - } - } - - BKE_mesh_calc_edges(config.mesh, false, false); -} - -static void process_no_normals(CDStreamConfig &config) -{ - /* Absense of normals in the Alembic mesh is interpreted as 'smooth'. */ - BKE_mesh_calc_normals(config.mesh); -} - -static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr loop_normals_ptr) -{ - size_t loop_count = loop_normals_ptr->size(); - - if (loop_count == 0) { - process_no_normals(config); - return; - } - - float(*lnors)[3] = static_cast<float(*)[3]>( - MEM_malloc_arrayN(loop_count, sizeof(float[3]), "ABC::FaceNormals")); - - Mesh *mesh = config.mesh; - MPoly *mpoly = mesh->mpoly; - const N3fArraySample &loop_normals = *loop_normals_ptr; - int abc_index = 0; - for (int i = 0, e = mesh->totpoly; i < e; i++, mpoly++) { - /* As usual, ABC orders the loops in reverse. */ - for (int j = mpoly->totloop - 1; j >= 0; j--, abc_index++) { - int blender_index = mpoly->loopstart + j; - copy_zup_from_yup(lnors[blender_index], loop_normals[abc_index].getValue()); - } - } - - mesh->flag |= ME_AUTOSMOOTH; - BKE_mesh_set_custom_normals(mesh, lnors); - - MEM_freeN(lnors); -} - -static void process_vertex_normals(CDStreamConfig &config, - const N3fArraySamplePtr vertex_normals_ptr) -{ - size_t normals_count = vertex_normals_ptr->size(); - if (normals_count == 0) { - process_no_normals(config); - return; - } - - float(*vnors)[3] = static_cast<float(*)[3]>( - MEM_malloc_arrayN(normals_count, sizeof(float[3]), "ABC::VertexNormals")); - - const N3fArraySample &vertex_normals = *vertex_normals_ptr; - for (int index = 0; index < normals_count; index++) { - copy_zup_from_yup(vnors[index], vertex_normals[index].getValue()); - } - - config.mesh->flag |= ME_AUTOSMOOTH; - BKE_mesh_set_custom_normals_from_vertices(config.mesh, vnors); - MEM_freeN(vnors); -} - -static void process_normals(CDStreamConfig &config, - const IN3fGeomParam &normals, - const ISampleSelector &selector) -{ - if (!normals.valid()) { - process_no_normals(config); - return; - } - - IN3fGeomParam::Sample normsamp = normals.getExpandedValue(selector); - Alembic::AbcGeom::GeometryScope scope = normals.getScope(); - - switch (scope) { - case Alembic::AbcGeom::kFacevaryingScope: // 'Vertex Normals' in Houdini. - process_loop_normals(config, normsamp.getVals()); - break; - case Alembic::AbcGeom::kVertexScope: - case Alembic::AbcGeom::kVaryingScope: // 'Point Normals' in Houdini. - process_vertex_normals(config, normsamp.getVals()); - break; - case Alembic::AbcGeom::kConstantScope: - case Alembic::AbcGeom::kUniformScope: - case Alembic::AbcGeom::kUnknownScope: - process_no_normals(config); - break; - } -} - -ABC_INLINE void read_uvs_params(CDStreamConfig &config, - AbcMeshData &abc_data, - const IV2fGeomParam &uv, - const ISampleSelector &selector) -{ - if (!uv.valid()) { - return; - } - - IV2fGeomParam::Sample uvsamp; - uv.getIndexed(uvsamp, selector); - - 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()); - - /* 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.mesh, name.c_str(), CD_MLOOPUV); - config.mloopuv = static_cast<MLoopUV *>(cd_ptr); - } -} - -static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) -{ - 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. */ - 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; - - config.weight = get_weight_and_index(config.time, time_sampling, samples_number, i0, i1); - - config.index = i0; - config.ceil_index = i1; -} - -static void read_mesh_sample(const std::string &iobject_full_name, - ImportSettings *settings, - const IPolyMeshSchema &schema, - const ISampleSelector &selector, - CDStreamConfig &config) -{ - 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(); - - 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 ((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); - process_normals(config, schema.getNormalsParam(), 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; - - BLI_assert(mesh->mvert || mesh->totvert == 0); - - config.mesh = 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; -} - -/* ************************************************************************** */ - -AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings) - : AbcObjectReader(object, settings) -{ - m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; - - 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); -} - -bool AbcMeshReader::valid() const -{ - 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()); - - 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) { - /* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_nomain_to_mesh() */ - /* read_mesh can be freed by BKE_mesh_nomain_to_mesh(), so get the flag before that happens. */ - short autosmooth = (read_mesh->flag & ME_AUTOSMOOTH); - BKE_mesh_nomain_to_mesh(read_mesh, mesh, m_object, &CD_MASK_MESH, true); - mesh->flag |= autosmooth; - } - - if (m_settings->validate_meshes) { - BKE_mesh_validate(mesh, false, false); - } - - readFaceSetsSample(bmain, mesh, sample_sel); - - 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 -{ - 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; -} - -bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel) -{ - IPolyMeshSchema::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()); - // A similar error in read_mesh() would just return existing_mesh. - return false; - } - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - return positions->size() != existing_mesh->totvert || - face_counts->size() != existing_mesh->totpoly || - face_indices->size() != existing_mesh->totloop; -} - -Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh, - const ISampleSelector &sample_sel, - int read_flag, - const char **err_str) -{ - IPolyMeshSchema::Sample sample; - try { - sample = m_schema.getValue(sample_sel); - } - catch (Alembic::Util::Exception &ex) { - if (err_str != nullptr) { - *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; - - if (topology_changed(existing_mesh, sample_sel)) { - 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(); - - read_mesh_sample(m_iobject.getFullName(), &settings, m_schema, sample_sel, config); - - if (new_mesh) { - /* 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, new_mesh->mpoly, num_polys, mat_map); - } - - return new_mesh; - } - - return existing_mesh; -} - -void AbcMeshReader::assign_facesets_to_mpoly(const ISampleSelector &sample_sel, - 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; - } - - int current_mat = 0; - - for (int i = 0; i < face_sets.size(); i++) { - const std::string &grp_name = face_sets[i]; - - if (r_mat_map.find(grp_name) == r_mat_map.end()) { - r_mat_map[grp_name] = 1 + current_mat++; - } - - const int assigned_mat = r_mat_map[grp_name]; - - const IFaceSet faceset = m_schema.getFaceSet(grp_name); - - if (!faceset.valid()) { - std::cerr << " Face set " << grp_name << " invalid for " << m_object_name << "\n"; - continue; - } - - 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(); - - for (size_t l = 0; l < num_group_faces; l++) { - size_t pos = (*group_faces)[l]; - - 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, const ISampleSelector &sample_sel) -{ - std::map<std::string, int> mat_map; - assign_facesets_to_mpoly(sample_sel, 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]; - - if (edge.v1 == v1 && edge.v2 == v2) { - return &edge; - } - } - - return NULL; -} - -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.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) { - /* Alembic's 'SubD' scheme is used to store subdivision surfaces, i.e. the pre-subdivision - * mesh. Currently we don't add a subdivision modifier when we load such data. This code is - * assuming that the subdivided surface should be smooth. */ - read_mpolys(config, abc_mesh_data); - process_no_normals(config); - } - - if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(iobject_full_name, schema.getArbGeomParams(), config, selector); - } -} - -/* ************************************************************************** */ - -AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) - : AbcObjectReader(object, settings) -{ - m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; - - 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); -} - -bool AbcSubDReader::valid() const -{ - return m_schema.valid(); -} - -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; -} - -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(); - - if (indices && sharpnesses) { - MEdge *edges = mesh->medge; - int totedge = mesh->totedge; - - for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) { - int v1 = (*indices)[i]; - int v2 = (*indices)[i + 1]; - - if (v2 < v1) { - /* It appears to be common to store edges with the smallest index first, in which case this - * prevents us from doing the second search below. */ - std::swap(v1, v2); - } - - MEdge *edge = find_edge(edges, totedge, v1, v2); - if (edge == NULL) { - edge = find_edge(edges, totedge, v2, v1); - } - - if (edge) { - edge->crease = unit_float_to_uchar_clamp((*sharpnesses)[s]); - } - } - - mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE; - } - - 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, - const ISampleSelector &sample_sel, - int read_flag, - const char **err_str) -{ - ISubDSchema::Sample sample; - try { - sample = m_schema.getValue(sample_sel); - } - catch (Alembic::Util::Exception &ex) { - if (err_str != nullptr) { - *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->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!"; - } - } - } - - /* 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); - - return config.mesh; -} diff --git a/source/blender/alembic/intern/abc_reader_mesh.h b/source/blender/alembic/intern/abc_reader_mesh.h deleted file mode 100644 index bc95c7ec134..00000000000 --- a/source/blender/alembic/intern/abc_reader_mesh.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_MESH_H__ -#define __ABC_READER_MESH_H__ - -#include "abc_customdata.h" -#include "abc_reader_object.h" - -struct Mesh; - -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 override; - bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, - const Object *const ob, - const char **err_str) const override; - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override; - - struct Mesh *read_mesh(struct Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str) override; - bool topology_changed(Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel) override; - - private: - void readFaceSetsSample(Main *bmain, - Mesh *mesh, - const Alembic::AbcGeom::ISampleSelector &sample_sel); - - void assign_facesets_to_mpoly(const Alembic::Abc::ISampleSelector &sample_sel, - 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); -}; - -void read_mverts(MVert *mverts, - const Alembic::AbcGeom::P3fArraySamplePtr positions, - const Alembic::AbcGeom::N3fArraySamplePtr normals); - -CDStreamConfig get_config(struct Mesh *mesh); - -#endif /* __ABC_READER_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_nurbs.cc b/source/blender/alembic/intern/abc_reader_nurbs.cc deleted file mode 100644 index 0ada10baba5..00000000000 --- a/source/blender/alembic/intern/abc_reader_nurbs.cc +++ /dev/null @@ -1,225 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_nurbs.h" -#include "abc_reader_transform.h" -#include "abc_util.h" - -#include "MEM_guardedalloc.h" - -extern "C" { -#include "DNA_curve_types.h" -#include "DNA_object_types.h" - -#include "BLI_listbase.h" -#include "BLI_string.h" - -#include "BKE_curve.h" -#include "BKE_object.h" -} - -using Alembic::AbcGeom::FloatArraySamplePtr; -using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::MetaData; -using Alembic::AbcGeom::P3fArraySamplePtr; - -using Alembic::AbcGeom::ICompoundProperty; -using Alembic::AbcGeom::INuPatch; -using Alembic::AbcGeom::INuPatchSchema; -using Alembic::AbcGeom::IObject; - -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); -} - -bool AbcNurbsReader::valid() const -{ - 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; - - if (!schema.valid()) { - return false; - } - } - - return true; -} - -static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots) -{ - 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")); - - for (size_t i = 0; i < num_knots; i++) { - nu_knots[i] = (*knots)[i + 1]; - } - - 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; - - 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(); - - /* Read positions and weights. */ - - const P3fArraySamplePtr positions = smp.getPositions(); - const FloatArraySamplePtr weights = smp.getPositionWeights(); - - const size_t num_points = positions->size(); - - nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype")); - - 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]; - - 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; - } - - /* Read knots. */ - - 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); - } - - /* Read flags. */ - - ICompoundProperty user_props = schema.getUserProperties(); - - 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, "cyclic_u")) { - nu->flagu |= CU_NURB_CYCLIC; - } - - if (has_property(user_props, "cyclic_v")) { - nu->flagv |= CU_NURB_CYCLIC; - } - - BLI_addtail(BKE_curve_nurbs_get(cu), nu); - } - - 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; -} - -void AbcNurbsReader::getNurbsPatches(const IObject &obj) -{ - if (!obj.valid()) { - return; - } - - 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; - } - - 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 (!child.valid()) { - continue; - } - - 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)); - } - - getNurbsPatches(child); - } -} diff --git a/source/blender/alembic/intern/abc_reader_nurbs.h b/source/blender/alembic/intern/abc_reader_nurbs.h deleted file mode 100644 index f4284c136fb..00000000000 --- a/source/blender/alembic/intern/abc_reader_nurbs.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_NURBS_H__ -#define __ABC_READER_NURBS_H__ - -#include "abc_reader_object.h" - -class AbcNurbsReader : public AbcObjectReader { - std::vector<std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject>> m_schemas; - - public: - AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - - bool valid() const; - - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); - - private: - void getNurbsPatches(const Alembic::Abc::IObject &obj); -}; - -#endif /* __ABC_READER_NURBS_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_object.cc b/source/blender/alembic/intern/abc_reader_object.cc deleted file mode 100644 index 3e7f87d78cc..00000000000 --- a/source/blender/alembic/intern/abc_reader_object.cc +++ /dev/null @@ -1,333 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_object.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_cachefile_types.h" -#include "DNA_constraint_types.h" -#include "DNA_modifier_types.h" -#include "DNA_space_types.h" /* for FILE_MAX */ - -#include "BKE_constraint.h" -#include "BKE_lib_id.h" -#include "BKE_modifier.h" -#include "BKE_object.h" - -#include "BLI_utildefines.h" -#include "BLI_listbase.h" -#include "BLI_math_geom.h" -#include "BLI_string.h" -} - -using Alembic::AbcGeom::IObject; -using Alembic::AbcGeom::IXform; -using Alembic::AbcGeom::IXformSchema; - -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 = 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; - } -} - -AbcObjectReader::~AbcObjectReader() -{ -} - -const IObject &AbcObjectReader::iobject() const -{ - return m_iobject; -} - -Object *AbcObjectReader::object() const -{ - return m_object; -} - -void AbcObjectReader::object(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]; - - /* 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++) { - mat1[i][j] = static_cast<float>(m1[i][j]); - } - } - - interp_m4_m4m4(ret, mat0, mat1, weight); - - Imath::M44d m; - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - m[i][j] = ret[i][j]; - } - } - - return m; -} - -Imath::M44d get_matrix(const IXformSchema &schema, const float time) -{ - 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); - - 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); - } - - return s0.getMatrix(); -} - -struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &UNUSED(sample_sel), - int UNUSED(read_flag), - const char **UNUSED(err_str)) -{ - return existing_mesh; -} - -bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/, - const Alembic::Abc::ISampleSelector & /*sample_sel*/) -{ - /* The default implementation of read_mesh() just returns the original mesh, so never changes the - * topology. */ - return false; -} - -void AbcObjectReader::setupObjectTransform(const float time) -{ - bool is_constant = false; - float transform_from_alembic[4][4]; - - /* If the parent is a camera, apply the inverse rotation to make up for the from-Maya rotation. - * This assumes that the parent object also was imported from Alembic. */ - if (m_object->parent != nullptr && m_object->parent->type == OB_CAMERA) { - axis_angle_to_mat4_single(m_object->parentinv, 'X', -M_PI_2); - } - - this->read_matrix(transform_from_alembic, time, m_settings->scale, is_constant); - - /* Apply the matrix to the object. */ - BKE_object_apply_mat4(m_object, transform_from_alembic, true, false); - BKE_object_to_mat4(m_object, m_object->obmat); - - 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); - } -} - -Alembic::AbcGeom::IXform AbcObjectReader::xform() -{ - /* Check that we have an empty object (locator, bone head/tail...). */ - if (IXform::matches(m_iobject.getMetaData())) { - try { - return IXform(m_iobject, Alembic::AbcGeom::kWrapExisting); - } - catch (Alembic::Util::Exception &ex) { - printf("Alembic: error reading object transform for '%s': %s\n", - m_iobject.getFullName().c_str(), - ex.what()); - return IXform(); - } - } - - /* 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())) { - try { - return IXform(abc_parent, Alembic::AbcGeom::kWrapExisting); - } - catch (Alembic::Util::Exception &ex) { - printf("Alembic: error reading object transform for '%s': %s\n", - abc_parent.getFullName().c_str(), - ex.what()); - return IXform(); - } - } - - /* 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] /* local matrix */, - 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_datatype(matrix, r_mat); - copy_m44_axis_swap(r_mat, r_mat, ABC_ZUP_FROM_YUP); - - /* Convert from Maya to Blender camera orientation. Children of this camera - * will have the opposite transform as their Parent Inverse matrix. - * See AbcObjectReader::setupObjectTransform(). */ - if (m_object->type == OB_CAMERA) { - float camera_rotation[4][4]; - axis_angle_to_mat4_single(camera_rotation, 'X', M_PI_2); - mul_m4_m4m4(r_mat, r_mat, camera_rotation); - } - - if (!m_inherits_xform) { - /* Only apply scaling to root objects, parenting will propagate it. */ - float scale_mat[4][4]; - scale_m4_fl(scale_mat, scale); - mul_m4_m4m4(r_mat, scale_mat, r_mat); - } - - is_constant = schema.isConstant(); -} - -void AbcObjectReader::addCacheModifier() -{ - ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); - BLI_addtail(&m_object->modifiers, md); - - MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md); - - 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); -} - -chrono_t AbcObjectReader::minTime() const -{ - return m_min_time; -} - -chrono_t AbcObjectReader::maxTime() const -{ - return m_max_time; -} - -int AbcObjectReader::refcount() const -{ - return m_refcount; -} - -void AbcObjectReader::incref() -{ - m_refcount++; -} - -void AbcObjectReader::decref() -{ - m_refcount--; - BLI_assert(m_refcount >= 0); -} diff --git a/source/blender/alembic/intern/abc_reader_object.h b/source/blender/alembic/intern/abc_reader_object.h deleted file mode 100644 index 94923df2df9..00000000000 --- a/source/blender/alembic/intern/abc_reader_object.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_OBJECT_H__ -#define __ABC_READER_OBJECT_H__ - -#include <Alembic/Abc/All.h> -#include <Alembic/AbcGeom/All.h> - -extern "C" { -#include "DNA_ID.h" -} - -struct CacheFile; -struct Main; -struct Mesh; -struct Object; - -using Alembic::AbcCoreAbstract::chrono_t; - -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) - { - } -}; - -template<typename Schema> static bool has_animations(Schema &schema, ImportSettings *settings) -{ - return settings->is_sequence || !schema.isConstant(); -} - -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; - - ImportSettings *m_settings; - - 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; - - bool m_inherits_xform; - - public: - AbcObjectReader *parent_reader; - - public: - explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); - - virtual ~AbcObjectReader(); - - const Alembic::Abc::IObject &iobject() const; - - 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(); - - 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; - } - - 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 struct Mesh *read_mesh(struct Mesh *mesh, - const Alembic::Abc::ISampleSelector &sample_sel, - int read_flag, - const char **err_str); - virtual bool topology_changed(Mesh *existing_mesh, - const Alembic::Abc::ISampleSelector &sample_sel); - - /** Reads the object matrix and sets up an object transform if animated. */ - void setupObjectTransform(const float time); - - void addCacheModifier(); - - chrono_t minTime() const; - chrono_t maxTime() const; - - int refcount() const; - void incref(); - void decref(); - - void read_matrix(float r_mat[4][4], const float time, const float scale, bool &is_constant); - - protected: - void determine_inherits_xform(); -}; - -Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); - -#endif /* __ABC_READER_OBJECT_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_points.cc b/source/blender/alembic/intern/abc_reader_points.cc deleted file mode 100644 index e4dc345f868..00000000000 --- a/source/blender/alembic/intern/abc_reader_points.cc +++ /dev/null @@ -1,157 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_points.h" -#include "abc_reader_mesh.h" -#include "abc_reader_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_mesh_types.h" -#include "DNA_object_types.h" - -#include "BKE_customdata.h" -#include "BKE_mesh.h" -#include "BKE_object.h" -} - -using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::P3fArraySamplePtr; - -using Alembic::AbcGeom::ICompoundProperty; -using Alembic::AbcGeom::IN3fArrayProperty; -using Alembic::AbcGeom::IPoints; -using Alembic::AbcGeom::IPointsSchema; -using Alembic::AbcGeom::ISampleSelector; - -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); -} - -bool AbcPointsReader::valid() const -{ - return m_schema.valid(); -} - -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; -} - -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); - - 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); - } - - 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(); - } -} - -void read_points_sample(const IPointsSchema &schema, - const ISampleSelector &selector, - CDStreamConfig &config) -{ - Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector); - - const P3fArraySamplePtr &positions = sample.getPositions(); - - 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 (normals_prop) { - vnormals = normals_prop.getValue(selector); - } - } - - read_mverts(config.mvert, positions, vnormals); -} - -struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh, - const ISampleSelector &sample_sel, - 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; -} diff --git a/source/blender/alembic/intern/abc_reader_points.h b/source/blender/alembic/intern/abc_reader_points.h deleted file mode 100644 index 31ad6c4589b..00000000000 --- a/source/blender/alembic/intern/abc_reader_points.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_POINTS_H__ -#define __ABC_READER_POINTS_H__ - -#include "abc_reader_object.h" -#include "abc_customdata.h" - -class AbcPointsReader : public AbcObjectReader { - Alembic::AbcGeom::IPointsSchema m_schema; - Alembic::AbcGeom::IPointsSchema::Sample m_sample; - - 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; - - 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_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, - const Alembic::AbcGeom::ISampleSelector &selector, - CDStreamConfig &config); - -#endif /* __ABC_READER_POINTS_H__ */ diff --git a/source/blender/alembic/intern/abc_reader_transform.cc b/source/blender/alembic/intern/abc_reader_transform.cc deleted file mode 100644 index ce569a9ccb5..00000000000 --- a/source/blender/alembic/intern/abc_reader_transform.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_reader_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_object_types.h" - -#include "BLI_utildefines.h" - -#include "BKE_object.h" -} - -using Alembic::Abc::ISampleSelector; - -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(); - - 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); -} - -bool AbcEmptyReader::valid() const -{ - return m_schema.valid(); -} - -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; -} - -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; -} diff --git a/source/blender/alembic/intern/abc_reader_transform.h b/source/blender/alembic/intern/abc_reader_transform.h deleted file mode 100644 index 6b4d23c1884..00000000000 --- a/source/blender/alembic/intern/abc_reader_transform.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_READER_TRANSFORM_H__ -#define __ABC_READER_TRANSFORM_H__ - -#include "abc_reader_object.h" - -#include <Alembic/AbcGeom/All.h> - -class AbcEmptyReader : public AbcObjectReader { - Alembic::AbcGeom::IXformSchema m_schema; - - 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; - - void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); -}; - -#endif /* __ABC_READER_TRANSFORM_H__ */ diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc deleted file mode 100644 index b26ef8b3b76..00000000000 --- a/source/blender/alembic/intern/abc_util.cc +++ /dev/null @@ -1,393 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_util.h" - -#include "abc_reader_camera.h" -#include "abc_reader_curves.h" -#include "abc_reader_mesh.h" -#include "abc_reader_nurbs.h" -#include "abc_reader_points.h" -#include "abc_reader_transform.h" - -#include <Alembic/AbcMaterial/IMaterial.h> - -#include <algorithm> - -extern "C" { -#include "DNA_object_types.h" - -#include "BLI_math_geom.h" - -#include "PIL_time.h" -} - -std::string get_id_name(const Object *const ob) -{ - if (!ob) { - return ""; - } - - return get_id_name(&ob->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(), ':', '_'); - - return name; -} - -/** - * \brief get_object_dag_path_name returns the name under which the object - * will be exported in the Alembic file. It is of the form - * "[../grandparent/]parent/object" if dupli_parent is NULL, or - * "dupli_parent/[../grandparent/]parent/object" otherwise. - * \param ob: - * \param dupli_parent: - * \return - */ -std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent) -{ - std::string name = get_id_name(ob); - - Object *p = ob->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; - } - - return name; -} - -Imath::M44d convert_matrix_datatype(float mat[4][4]) -{ - Imath::M44d m; - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - m[i][j] = mat[i][j]; - } - } - - return m; -} - -void convert_matrix_datatype(const Imath::M44d &xform, 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]); - } - } -} - -void split(const std::string &s, const char delim, std::vector<std::string> &tokens) -{ - tokens.clear(); - - std::stringstream ss(s); - std::string 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) -{ - 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); -} - -/* 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, - 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); -} - -bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name) -{ - if (!prop.valid()) { - return false; - } - - return prop.getPropertyHeader(name) != NULL; -} - -typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t; - -float get_weight_and_index(float time, - const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling, - int samples_number, - Alembic::AbcGeom::index_t &i0, - Alembic::AbcGeom::index_t &i1) -{ - samples_number = std::max(samples_number, 1); - - 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; - } - - index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number); - i1 = t1.first; - - if (i0 == i1) { - return 0.0f; - } - - const float bias = (time - t0.second) / (t1.second - t0.second); - - if (fabs(1.0f - bias) < 0.0001f) { - i0 = i1; - return 0.0f; - } - - 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)) { -#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); -#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; -} - -/* ********************** */ - -ScopeTimer::ScopeTimer(const char *message) - : m_message(message), m_start(PIL_check_seconds_timer()) -{ -} - -ScopeTimer::~ScopeTimer() -{ - fprintf(stderr, "%s: %fs\n", m_message, PIL_check_seconds_timer() - m_start); -} - -/* ********************** */ - -std::string SimpleLogger::str() const -{ - return m_stream.str(); -} - -void SimpleLogger::clear() -{ - m_stream.clear(); - m_stream.str(""); -} - -std::ostringstream &SimpleLogger::stream() -{ - return m_stream; -} - -std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger) -{ - os << logger.str(); - return os; -} diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h deleted file mode 100644 index 0b3462c2132..00000000000 --- a/source/blender/alembic/intern/abc_util.h +++ /dev/null @@ -1,236 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_UTIL_H__ -#define __ABC_UTIL_H__ - -#include <Alembic/Abc/All.h> -#include <Alembic/AbcGeom/All.h> - -#ifdef _MSC_VER -# define ABC_INLINE static __forceinline -#else -# define ABC_INLINE static inline -#endif - -/** - * \brief The CacheReader struct is only used for anonymous pointers, - * to interface between C and C++ code. This library only creates - * pointers to AbcObjectReader (or subclasses thereof). - */ -struct CacheReader { - int unused; -}; - -using Alembic::Abc::chrono_t; - -class AbcObjectReader; -struct ImportSettings; - -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); - -/* Convert from float to Alembic matrix representations. Does NOT convert from Z-up to Y-up. */ -Imath::M44d convert_matrix_datatype(float mat[4][4]); -/* Convert from Alembic to float matrix representations. Does NOT convert from Y-up to Z-up. */ -void convert_matrix_datatype(const Imath::M44d &xform, float r_mat[4][4]); - -typedef enum { - 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 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) -{ - return input.size() >= match.size() && std::equal(match.begin(), match.end(), input.begin()); -} - -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(); - - 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); - - 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) -{ - 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); - } -} - -bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name); - -float get_weight_and_index(float time, - const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling, - int samples_number, - Alembic::AbcGeom::index_t &i0, - Alembic::AbcGeom::index_t &i1); - -AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings); - -/* ************************** */ - -/* TODO(kevin): for now keeping these transformations hardcoded to make sure - * everything works properly, and also because Alembic is almost exclusively - * used in Y-up software, but eventually they'll be set by the user in the UI - * like other importers/exporters do, to support other axis. */ - -/* Copy from Y-up to Z-up. */ - -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; -} - -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; -} - -/* 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; -} - -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; -} - -/* 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, -} 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 copy_m44_axis_swap(float dst_mat[4][4], float src_mat[4][4], AbcAxisSwapMode mode); - -/* *************************** */ - -#undef ABC_DEBUG_TIME - -class ScopeTimer { - const char *m_message; - double m_start; - - public: - ScopeTimer(const char *message); - ~ScopeTimer(); -}; - -#ifdef ABC_DEBUG_TIME -# define SCOPE_TIMER(message) ScopeTimer prof(message) -#else -# define SCOPE_TIMER(message) -#endif - -/* *************************** */ - -/** - * Utility class whose purpose is to more easily log related information. An - * instance of the SimpleLogger can be created in any context, and will hold a - * copy of all the strings passed to its output stream. - * - * Different instances of the class may be accessed from different threads, - * although accessing the same instance from different threads will lead to race - * conditions. - */ -class SimpleLogger { - std::ostringstream m_stream; - - public: - /** - * 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() - -/** - * Pass the content of the logger's stream to the specified std::ostream. - */ -std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger); - -#endif /* __ABC_UTIL_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_archive.cc b/source/blender/alembic/intern/abc_writer_archive.cc deleted file mode 100644 index af18d480a18..00000000000 --- a/source/blender/alembic/intern/abc_writer_archive.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_archive.h" -extern "C" { -#include "BKE_blender_version.h" - -#include "BLI_path_util.h" -#include "BLI_string.h" - -#include "DNA_scene_types.h" -} - -#ifdef WIN32 -# include "utfconv.h" -#endif - -#include <fstream> - -using Alembic::Abc::ErrorHandler; -using Alembic::Abc::kWrapExisting; -using Alembic::Abc::OArchive; - -/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to - * have a version supporting streams. */ -static OArchive create_archive(std::ostream *ostream, - const std::string &filename, - const std::string &scene_name, - double scene_fps, - bool ogawa) -{ - Alembic::Abc::MetaData abc_metadata; - - abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender"); - abc_metadata.set(Alembic::Abc::kUserDescriptionKey, scene_name); - abc_metadata.set("blender_version", versionstr); - abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps)); - - time_t raw_time; - time(&raw_time); - char buffer[128]; - -#if defined _WIN32 || defined _WIN64 - ctime_s(buffer, 128, &raw_time); -#else - 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'; - } - - abc_metadata.set(Alembic::Abc::kDateWrittenKey, buffer); - - ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; - -#ifdef WITH_ALEMBIC_HDF5 - if (!ogawa) { - return OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, abc_metadata, policy); - } -#else - static_cast<void>(filename); - static_cast<void>(ogawa); -#endif - - Alembic::AbcCoreOgawa::WriteArchive archive_writer; - return OArchive(archive_writer(ostream, abc_metadata), kWrapExisting, policy); -} - -ArchiveWriter::ArchiveWriter(const char *filename, - const std::string &abc_scene_name, - const Scene *scene, - bool 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); -#else - m_outfile.open(filename, std::ios::out | std::ios::binary); -#endif - } - - m_archive = create_archive(&m_outfile, filename, abc_scene_name, FPS, do_ogawa); -} - -OArchive &ArchiveWriter::archive() -{ - return m_archive; -} diff --git a/source/blender/alembic/intern/abc_writer_archive.h b/source/blender/alembic/intern/abc_writer_archive.h deleted file mode 100644 index e261e60990a..00000000000 --- a/source/blender/alembic/intern/abc_writer_archive.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_ARCHIVE_H__ -#define __ABC_WRITER_ARCHIVE_H__ - -#include <Alembic/Abc/All.h> - -#ifdef WITH_ALEMBIC_HDF5 -# include <Alembic/AbcCoreHDF5/All.h> -#endif - -#include <Alembic/AbcCoreOgawa/All.h> - -#include <fstream> - -struct Main; -struct Scene; - -/* Wrappers around input and output archives. The goal is to be able to use - * streams so that unicode paths work on Windows (T49112), and to make sure that - * the stream objects remain valid as long as the archives are open. - */ - -class ArchiveWriter { - std::ofstream m_outfile; - Alembic::Abc::OArchive m_archive; - - public: - ArchiveWriter(const char *filename, - const std::string &abc_scene_name, - const Scene *scene, - bool do_ogawa); - - Alembic::Abc::OArchive &archive(); -}; - -#endif /* __ABC_WRITER_ARCHIVE_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_camera.cc b/source/blender/alembic/intern/abc_writer_camera.cc deleted file mode 100644 index e705e5ba911..00000000000 --- a/source/blender/alembic/intern/abc_writer_camera.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_camera.h" -#include "abc_writer_transform.h" - -extern "C" { -#include "DNA_camera_types.h" -#include "DNA_object_types.h" -} - -using Alembic::AbcGeom::OCamera; -using Alembic::AbcGeom::OFloatProperty; - -AbcCameraWriter::AbcCameraWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) -{ - 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); -} - -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.focus_object) { - Imath::V3f v(m_object->loc[0] - cam->dof.focus_object->loc[0], - m_object->loc[1] - cam->dof.focus_object->loc[1], - m_object->loc[2] - cam->dof.focus_object->loc[2]); - m_camera_sample.setFocusDistance(v.length()); - } - else { - m_camera_sample.setFocusDistance(cam->dof.focus_distance); - } - - /* Blender camera does not have an fstop param, so try to find a custom prop - * instead. */ - m_camera_sample.setFStop(cam->dof.aperture_fstop); - - m_camera_sample.setLensSqueezeRatio(1.0); - m_camera_schema.set(m_camera_sample); -} diff --git a/source/blender/alembic/intern/abc_writer_camera.h b/source/blender/alembic/intern/abc_writer_camera.h deleted file mode 100644 index 3b515911a48..00000000000 --- a/source/blender/alembic/intern/abc_writer_camera.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_CAMERA_H__ -#define __ABC_WRITER_CAMERA_H__ - -#include "abc_writer_object.h" - -/* ************************************************************************** */ - -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(); -}; - -#endif /* __ABC_WRITER_CAMERA_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_curves.cc b/source/blender/alembic/intern/abc_writer_curves.cc deleted file mode 100644 index 3ab9b365a72..00000000000 --- a/source/blender/alembic/intern/abc_writer_curves.cc +++ /dev/null @@ -1,189 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_curves.h" -#include "abc_reader_curves.h" -#include "abc_writer_transform.h" - -extern "C" { -#include "DNA_curve_types.h" -#include "DNA_object_types.h" - -#include "BKE_curve.h" -#include "BKE_mesh.h" -#include "BKE_object.h" -} - -using Alembic::AbcGeom::OCompoundProperty; -using Alembic::AbcGeom::OCurves; -using Alembic::AbcGeom::OCurvesSchema; -using Alembic::AbcGeom::OInt16Property; -using Alembic::AbcGeom::ON3fGeomParam; -using Alembic::AbcGeom::OV2fGeomParam; - -AbcCurveWriter::AbcCurveWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) -{ - OCurves curves(parent->alembicXform(), m_name, m_time_sampling); - m_schema = curves.getSchema(); - - Curve *cu = static_cast<Curve *>(m_object->data); - OCompoundProperty user_props = m_schema.getUserProperties(); - OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME); - user_prop_resolu.set(cu->resolu); -} - -void AbcCurveWriter::do_write() -{ - 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) -{ - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return mesh_eval; - } - - r_needsfree = true; - return BKE_mesh_new_nomain_from_curve(ob_eval); -} diff --git a/source/blender/alembic/intern/abc_writer_curves.h b/source/blender/alembic/intern/abc_writer_curves.h deleted file mode 100644 index d6d8c0a7f11..00000000000 --- a/source/blender/alembic/intern/abc_writer_curves.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_CURVES_H__ -#define __ABC_WRITER_CURVES_H__ - -#include "abc_writer_object.h" -#include "abc_writer_mesh.h" - -class AbcCurveWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; - - public: - AbcCurveWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - 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); -}; - -#endif /* __ABC_WRITER_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_hair.cc b/source/blender/alembic/intern/abc_writer_hair.cc deleted file mode 100644 index bbba03ed7f4..00000000000 --- a/source/blender/alembic/intern/abc_writer_hair.cc +++ /dev/null @@ -1,292 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_hair.h" -#include "abc_writer_transform.h" -#include "abc_util.h" - -#include <cstdio> - -extern "C" { -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" - -#include "BLI_math_geom.h" - -#include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" -#include "BKE_particle.h" -} - -using Alembic::Abc::P3fArraySamplePtr; - -using Alembic::AbcGeom::OCurves; -using Alembic::AbcGeom::OCurvesSchema; -using Alembic::AbcGeom::ON3fGeomParam; -using Alembic::AbcGeom::OV2fGeomParam; - -/* ************************************************************************** */ - -AbcHairWriter::AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys) - : AbcObjectWriter(ob, time_sampling, settings, parent), m_uv_warning_shown(false) -{ - m_psys = psys; - - 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; - bool export_children = m_settings.export_child_hairs && m_psys->childcache && - part->childtype != 0; - - if (!export_children || part->draw & PART_DRAW_PARENT) { - write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); - } - - if (export_children) { - 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, - ParticleSettings *part, - std::vector<Imath::V3f> &verts, - std::vector<Imath::V3f> &norm_values, - 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])); - } - } -} - -void AbcHairWriter::write_hair_child_sample(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) -{ - /* 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_writer_hair.h b/source/blender/alembic/intern/abc_writer_hair.h deleted file mode 100644 index 67d1b7b3d23..00000000000 --- a/source/blender/alembic/intern/abc_writer_hair.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_HAIR_H__ -#define __ABC_WRITER_HAIR_H__ - -#include "abc_writer_object.h" - -struct ParticleSettings; -struct ParticleSystem; - -class AbcHairWriter : public AbcObjectWriter { - ParticleSystem *m_psys; - - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; - - bool m_uv_warning_shown; - - public: - AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys); - - 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_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_WRITER_HAIR_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_mball.cc b/source/blender/alembic/intern/abc_writer_mball.cc deleted file mode 100644 index cc0775bd537..00000000000 --- a/source/blender/alembic/intern/abc_writer_mball.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_mball.h" -#include "abc_writer_mesh.h" - -extern "C" { -#include "DNA_meta_types.h" -#include "DNA_mesh_types.h" -#include "DNA_object_types.h" - -#include "BKE_displist.h" -#include "BKE_lib_id.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_object.h" - -#include "BLI_utildefines.h" -} - -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(); -} - -AbcMBallWriter::~AbcMBallWriter() -{ -} - -bool AbcMBallWriter::isAnimated() const -{ - return true; -} - -Mesh *AbcMBallWriter::getEvaluatedMesh(Scene * /*scene_eval*/, Object *ob_eval, bool &r_needsfree) -{ - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return 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 rethought. - */ - 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); -} - -bool AbcMBallWriter::isBasisBall(Scene *scene, Object *ob) -{ - Object *basis_ob = BKE_mball_basis_find(scene, ob); - return ob == basis_ob; -} diff --git a/source/blender/alembic/intern/abc_writer_mball.h b/source/blender/alembic/intern/abc_writer_mball.h deleted file mode 100644 index c752472c86d..00000000000 --- a/source/blender/alembic/intern/abc_writer_mball.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_MBALL_H__ -#define __ABC_WRITER_MBALL_H__ - -#include "abc_writer_object.h" -#include "abc_writer_mesh.h" - -struct Main; -struct Object; - -/* AbcMBallWriter converts the metaballs to meshes at every frame, - * and defers to AbcGenericMeshWriter to perform the writing - * 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); - - ~AbcMBallWriter(); - - static bool isBasisBall(Scene *scene, Object *ob); - - 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_WRITER_MBALL_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_mesh.cc b/source/blender/alembic/intern/abc_writer_mesh.cc deleted file mode 100644 index b55d2473f99..00000000000 --- a/source/blender/alembic/intern/abc_writer_mesh.cc +++ /dev/null @@ -1,592 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_mesh.h" -#include "abc_writer_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim_types.h" - -#include "BKE_animsys.h" -#include "BKE_key.h" -#include "BKE_lib_id.h" -#include "BKE_material.h" -#include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" -#include "BKE_modifier.h" - -#include "bmesh.h" -#include "bmesh_tools.h" - -#include "DEG_depsgraph_query.h" -} - -using Alembic::Abc::FloatArraySample; -using Alembic::Abc::Int32ArraySample; -using Alembic::Abc::V2fArraySample; -using Alembic::Abc::V3fArraySample; - -using Alembic::AbcGeom::kFacevaryingScope; -using Alembic::AbcGeom::OBoolProperty; -using Alembic::AbcGeom::OCompoundProperty; -using Alembic::AbcGeom::OFaceSet; -using Alembic::AbcGeom::OFaceSetSchema; -using Alembic::AbcGeom::ON3fGeomParam; -using Alembic::AbcGeom::OPolyMesh; -using Alembic::AbcGeom::OPolyMeshSchema; -using Alembic::AbcGeom::OSubD; -using Alembic::AbcGeom::OSubDSchema; -using Alembic::AbcGeom::OV2fGeomParam; -using Alembic::AbcGeom::UInt32ArraySample; - -/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ - -static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points) -{ - points.clear(); - points.resize(mesh->totvert); - - MVert *verts = mesh->mvert; - - 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, - std::vector<int32_t> &poly_verts, - std::vector<int32_t> &loop_counts, - bool &r_has_flat_shaded_poly) -{ - const int num_poly = mesh->totpoly; - const int num_loops = mesh->totloop; - MLoop *mloop = mesh->mloop; - MPoly *mpoly = mesh->mpoly; - r_has_flat_shaded_poly = false; - - 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); - - r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; - - MLoop *loop = mloop + poly.loopstart + (poly.totloop - 1); - - for (int j = 0; j < poly.totloop; j++, loop--) { - poly_verts.push_back(loop->v); - } - } -} - -static void get_creases(struct Mesh *mesh, - std::vector<int32_t> &indices, - std::vector<int32_t> &lengths, - std::vector<float> &sharpnesses) -{ - const float factor = 1.0f / 255.0f; - - indices.clear(); - lengths.clear(); - sharpnesses.clear(); - - MEdge *edge = mesh->medge; - - 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); - } - } - - lengths.resize(sharpnesses.size(), 2); -} - -static void get_loop_normals(struct Mesh *mesh, - std::vector<Imath::V3f> &normals, - bool has_flat_shaded_poly) -{ - normals.clear(); - - /* If all polygons are smooth shaded, and there are no custom normals, we don't need to export - * normals at all. This is also done by other software, see T71246. */ - if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL)) { - return; - } - - BKE_mesh_calc_normals_split(mesh); - const float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); - BLI_assert(lnors != NULL || !"BKE_mesh_calc_normals_split() should have computed CD_NORMAL"); - - normals.resize(mesh->totloop); - - /* NOTE: data needs to be written in the reverse order. */ - int abc_index = 0; - MPoly *mp = mesh->mpoly; - for (int i = 0, e = mesh->totpoly; i < e; i++, mp++) { - for (int j = mp->totloop - 1; j >= 0; j--, abc_index++) { - int blender_index = mp->loopstart + j; - copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]); - } - } -} - -/* *************** Modifiers *************** */ - -/* check if the mesh is a subsurf, ignoring disabled modifiers and - * displace if it's after subsurf. */ -static ModifierData *get_subsurf_modifier(Scene *scene, Object *ob) -{ - ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); - - 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 (smd->subdivType == ME_CC_SUBSURF) { - return md; - } - } - - /* mesh is not a subsurf. break */ - if ((md->type != eModifierType_Displace) && (md->type != eModifierType_ParticleSystem)) { - return NULL; - } - } - - return NULL; -} - -static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) -{ - ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim); - - 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; - } - } - - return NULL; -} - -/* ************************************************************************** */ - -AbcGenericMeshWriter::AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - 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); - } -} - -AbcGenericMeshWriter::~AbcGenericMeshWriter() -{ - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } -} - -bool AbcGenericMeshWriter::isAnimated() const -{ - if (BKE_animdata_id_is_animated(static_cast<ID *>(m_object->data))) { - 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; -} - -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; - } -} - -void AbcGenericMeshWriter::freeEvaluatedMesh(struct Mesh *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> velocities; - bool has_flat_shaded_poly = false; - - get_vertices(mesh, points); - get_topology(mesh, poly_verts, loop_counts, has_flat_shaded_poly); - - 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)); - - 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); - - 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); - } - - if (m_settings.export_normals) { - get_loop_normals(mesh, normals, has_flat_shaded_poly); - - ON3fGeomParam::Sample normals_sample; - if (!normals.empty()) { - normals_sample.setScope(kFacevaryingScope); - normals_sample.setVals(V3fArraySample(normals)); - } - - m_mesh_sample.setNormals(normals_sample); - } - - if (m_is_liquid) { - getVelocities(mesh, velocities); - m_mesh_sample.setVelocities(V3fArraySample(velocities)); - } - - m_mesh_sample.setSelfBounds(bounds()); - - m_mesh_schema.set(m_mesh_sample); - - 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; - bool has_flat_poly = false; - - get_vertices(mesh, points); - get_topology(mesh, poly_verts, loop_counts, has_flat_poly); - get_creases(mesh, crease_indices, crease_lengths, crease_sharpness); - - 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)); - - 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); - - 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); - } - - 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); - - writeArbGeoParams(mesh); -} - -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); - } -} - -Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree) -{ - /* We don't want subdivided mesh data */ - if (m_subsurf_mod) { - m_subsurf_mod->mode |= eModifierMode_DisableTemporary; - } - - 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); - - 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; - - 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); - - Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); - BM_mesh_free(bm); - - if (r_needsfree) { - BKE_id_free(NULL, mesh); - } - - 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; - - 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); - } - } -} - -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)); - } -} - -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; - - for (int i = 0; i < num_poly; i++) { - MPoly ¤t_poly = polygons[i]; - short mnr = current_poly.mat_nr; - - Material *mat = BKE_object_material_get(m_object, mnr + 1); - - if (!mat) { - continue; - } - - 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; - } - - geo_groups[name].push_back(i); - } - - if (geo_groups.size() == 0) { - Material *mat = BKE_object_material_get(m_object, 1); - - std::string name = (mat) ? get_id_name(&mat->id) : "default"; - - std::vector<int32_t> faceArray; - - for (int i = 0, e = mesh->totface; i < e; i++) { - faceArray.push_back(i); - } - - 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); -} diff --git a/source/blender/alembic/intern/abc_writer_mesh.h b/source/blender/alembic/intern/abc_writer_mesh.h deleted file mode 100644 index 9152a370e4f..00000000000 --- a/source/blender/alembic/intern/abc_writer_mesh.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_MESH_H__ -#define __ABC_WRITER_MESH_H__ - -#include "abc_customdata.h" -#include "abc_writer_object.h" - -struct Mesh; -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; - - Alembic::AbcGeom::OSubDSchema m_subdiv_schema; - Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample; - - Alembic::Abc::OArrayProperty m_mat_indices; - - bool m_is_animated; - ModifierData *m_subsurf_mod; - - CDStreamConfig m_custom_data_config; - - bool m_is_liquid; - bool m_is_subd; - - public: - AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~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); - - Mesh *getFinalMesh(bool &r_needsfree); - - 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); - - /* fluid surfaces support */ - void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels); - - 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; -}; - -#endif /* __ABC_WRITER_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_nurbs.cc b/source/blender/alembic/intern/abc_writer_nurbs.cc deleted file mode 100644 index 9796eaf54c3..00000000000 --- a/source/blender/alembic/intern/abc_writer_nurbs.cc +++ /dev/null @@ -1,172 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_nurbs.h" -#include "abc_writer_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_curve_types.h" -#include "DNA_object_types.h" - -#include "BLI_listbase.h" - -#include "BKE_curve.h" -} - -using Alembic::AbcGeom::FloatArraySample; -using Alembic::AbcGeom::OBoolProperty; -using Alembic::AbcGeom::OCompoundProperty; -using Alembic::AbcGeom::ONuPatch; -using Alembic::AbcGeom::ONuPatchSchema; - -AbcNurbsWriter::AbcNurbsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) -{ - m_is_animated = isAnimated(); - - /* 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); - - for (size_t i = 0; i < numNurbs; i++) { - std::stringstream str; - str << m_name << '_' << i; - - 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()); - } -} - -bool AbcNurbsWriter::isAnimated() const -{ - /* 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; - } - - /* 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); - - 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]); -} - -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); - } -} diff --git a/source/blender/alembic/intern/abc_writer_nurbs.h b/source/blender/alembic/intern/abc_writer_nurbs.h deleted file mode 100644 index c6a3c399b66..00000000000 --- a/source/blender/alembic/intern/abc_writer_nurbs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_NURBS_H__ -#define __ABC_WRITER_NURBS_H__ - -#include "abc_writer_object.h" - -class AbcNurbsWriter : public AbcObjectWriter { - std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema; - bool m_is_animated; - - public: - AbcNurbsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - private: - virtual void do_write(); - - bool isAnimated() const; -}; - -#endif /* __ABC_WRITER_NURBS_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_object.cc b/source/blender/alembic/intern/abc_writer_object.cc deleted file mode 100644 index 75dc93bd08e..00000000000 --- a/source/blender/alembic/intern/abc_writer_object.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_object.h" - -extern "C" { -#include "DNA_object_types.h" - -#include "BKE_object.h" -} - -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_name = get_id_name(m_object) + "Shape"; - - if (parent) { - parent->addChild(this); - } -} - -AbcObjectWriter::~AbcObjectWriter() -{ -} - -void AbcObjectWriter::addChild(AbcObjectWriter *child) -{ - m_children.push_back(child); -} - -Imath::Box3d AbcObjectWriter::bounds() -{ - 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"; - } - - 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]; - - 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; -} - -void AbcObjectWriter::write() -{ - do_write(); - m_first_frame = false; -} diff --git a/source/blender/alembic/intern/abc_writer_object.h b/source/blender/alembic/intern/abc_writer_object.h deleted file mode 100644 index c3511566372..00000000000 --- a/source/blender/alembic/intern/abc_writer_object.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_OBJECT_H__ -#define __ABC_WRITER_OBJECT_H__ - -#include <Alembic/Abc/All.h> -#include <Alembic/AbcGeom/All.h> - -#include "abc_exporter.h" - -extern "C" { -#include "DNA_ID.h" -} - -class AbcTransformWriter; - -struct Main; -struct Object; - -class AbcObjectWriter { - protected: - Object *m_object; - ExportSettings &m_settings; - - uint32_t m_time_sampling; - - Imath::Box3d m_bounds; - std::vector<AbcObjectWriter *> m_children; - - std::vector<std::pair<std::string, IDProperty *>> m_props; - - bool m_first_frame; - std::string m_name; - - public: - AbcObjectWriter(Object *ob, - uint32_t time_sampling, - ExportSettings &settings, - AbcObjectWriter *parent = NULL); - - virtual ~AbcObjectWriter(); - - void addChild(AbcObjectWriter *child); - - virtual Imath::Box3d bounds(); - - void write(); - - private: - virtual void do_write() = 0; -}; - -#endif /* __ABC_WRITER_OBJECT_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_points.cc b/source/blender/alembic/intern/abc_writer_points.cc deleted file mode 100644 index cc4abe8ec4b..00000000000 --- a/source/blender/alembic/intern/abc_writer_points.cc +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_points.h" -#include "abc_writer_mesh.h" -#include "abc_writer_transform.h" -#include "abc_util.h" - -extern "C" { -#include "DNA_object_types.h" -#include "DNA_particle_types.h" - -#include "BKE_lattice.h" -#include "BKE_particle.h" - -#include "BLI_math.h" - -#include "DEG_depsgraph_query.h" -} - -using Alembic::AbcGeom::kVertexScope; -using Alembic::AbcGeom::OPoints; -using Alembic::AbcGeom::OPointsSchema; - -/* ************************************************************************** */ - -AbcPointsWriter::AbcPointsWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys) - : AbcObjectWriter(ob, time_sampling, settings, parent) -{ - m_psys = psys; - - OPoints points(parent->alembicXform(), psys->name, m_time_sampling); - m_schema = points.getSchema(); -} - -void AbcPointsWriter::do_write() -{ - if (!m_psys) { - return; - } - - std::vector<Imath::V3f> points; - std::vector<Imath::V3f> velocities; - std::vector<float> widths; - std::vector<uint64_t> ids; - - ParticleKey state; - - 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); - - 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; - } - - state.time = DEG_get_ctime(m_settings.depsgraph); - - if (psys_get_particle_state(&sim, p, &state, 0) == 0) { - continue; - } - - /* location */ - mul_v3_m4v3(pos, m_object->imat, 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++); - } - - 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); - - m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample); - m_sample.setSelfBounds(bounds()); - - m_schema.set(m_sample); -} diff --git a/source/blender/alembic/intern/abc_writer_points.h b/source/blender/alembic/intern/abc_writer_points.h deleted file mode 100644 index 77dd10c4b26..00000000000 --- a/source/blender/alembic/intern/abc_writer_points.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_POINTS_H__ -#define __ABC_WRITER_POINTS_H__ - -#include "abc_writer_object.h" -#include "abc_customdata.h" - -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(); -}; - -#endif /* __ABC_WRITER_POINTS_H__ */ diff --git a/source/blender/alembic/intern/abc_writer_transform.cc b/source/blender/alembic/intern/abc_writer_transform.cc deleted file mode 100644 index d7bcc46d96f..00000000000 --- a/source/blender/alembic/intern/abc_writer_transform.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_transform.h" -#include "abc_util.h" - -#include <OpenEXR/ImathBoxAlgo.h> - -extern "C" { -#include "DNA_object_types.h" - -#include "BLI_math.h" - -#include "DEG_depsgraph_query.h" -} - -using Alembic::AbcGeom::OObject; -using Alembic::AbcGeom::OXform; - -AbcTransformWriter::AbcTransformWriter(Object *ob, - const OObject &abc_parent, - AbcTransformWriter *parent, - unsigned int time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent), m_proxy_from(NULL) -{ - m_is_animated = hasAnimation(m_object); - - if (!m_is_animated) { - time_sampling = 0; - } - - 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; -} - -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_VIEWPORT)); - - 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); - - /* If the parent is a camera, undo its to-Maya rotation (see below). */ - bool is_root_object = !m_inherits_xform || ob_eval->parent == nullptr; - if (!is_root_object && ob_eval->parent->type == OB_CAMERA) { - float rot_mat[4][4]; - axis_angle_to_mat4_single(rot_mat, 'X', M_PI_2); - mul_m4_m4m4(yup_mat, rot_mat, yup_mat); - } - - /* If the object is a camera, apply an extra rotation to Maya camera orientation. */ - if (ob_eval->type == OB_CAMERA) { - 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 (is_root_object) { - /* 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_datatype(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; - - 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); -} - -bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const -{ - return true; -} diff --git a/source/blender/alembic/intern/abc_writer_transform.h b/source/blender/alembic/intern/abc_writer_transform.h deleted file mode 100644 index 4397b220761..00000000000 --- a/source/blender/alembic/intern/abc_writer_transform.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_TRANSFORM_H__ -#define __ABC_WRITER_TRANSFORM_H__ - -#include "abc_writer_object.h" - -#include <Alembic/AbcGeom/All.h> - -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; -}; - -#endif /* __ABC_WRITER_TRANSFORM_H__ */ diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc deleted file mode 100644 index c6f9e284d53..00000000000 --- a/source/blender/alembic/intern/alembic_capi.cc +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "../ABC_alembic.h" - -#include <Alembic/AbcMaterial/IMaterial.h> - -#include "abc_reader_archive.h" -#include "abc_reader_camera.h" -#include "abc_reader_curves.h" -#include "abc_reader_mesh.h" -#include "abc_reader_nurbs.h" -#include "abc_reader_points.h" -#include "abc_reader_transform.h" -#include "abc_util.h" -#include "abc_writer_camera.h" -#include "abc_writer_curves.h" -#include "abc_writer_hair.h" -#include "abc_writer_mesh.h" -#include "abc_writer_nurbs.h" -#include "abc_writer_points.h" -#include "abc_writer_transform.h" - -#include "MEM_guardedalloc.h" - -extern "C" { -#include "DNA_cachefile_types.h" -#include "DNA_curve_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BKE_cachefile.h" -#include "BKE_context.h" -#include "BKE_curve.h" -#include "BKE_global.h" -#include "BKE_layer.h" -#include "BKE_lib_id.h" -#include "BKE_scene.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_build.h" - -/* SpaceType struct has a member called 'new' which obviously conflicts with C++ - * so temporarily redefining the new keyword to make it compile. */ -#define new extern_new -#include "BKE_screen.h" -#undef new - -#include "BLI_fileops.h" -#include "BLI_ghash.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_path_util.h" -#include "BLI_string.h" - -#include "WM_api.h" -#include "WM_types.h" -} - -using Alembic::Abc::Int32ArraySamplePtr; -using Alembic::Abc::ObjectHeader; - -using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::MetaData; -using Alembic::AbcGeom::P3fArraySamplePtr; - -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; -using Alembic::AbcGeom::IPointsSchema; -using Alembic::AbcGeom::IPolyMesh; -using Alembic::AbcGeom::IPolyMeshSchema; -using Alembic::AbcGeom::ISampleSelector; -using Alembic::AbcGeom::ISubD; -using Alembic::AbcGeom::IV2fGeomParam; -using Alembic::AbcGeom::IXform; -using Alembic::AbcGeom::IXformSchema; -using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::V3fArraySamplePtr; -using Alembic::AbcGeom::XformSample; - -using Alembic::AbcMaterial::IMaterial; - -struct AbcArchiveHandle { - int unused; -}; - -ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) -{ - return reinterpret_cast<ArchiveReader *>(handle); -} - -ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) -{ - return reinterpret_cast<AbcArchiveHandle *>(archive); -} - -//#define USE_NURBS - -/* NOTE: this function is similar to visit_objects below, need to keep them in - * 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) || -#ifdef USE_NURBS - INuPatch::matches(md) || -#endif - 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); - - 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; -} - -AbcArchiveHandle *ABC_create_handle(struct Main *bmain, - const char *filename, - ListBase *object_paths) -{ - ArchiveReader *archive = new ArchiveReader(bmain, filename); - - if (!archive->valid()) { - delete archive; - return NULL; - } - - if (object_paths) { - gather_objects_paths(archive->getTop(), object_paths); - } - - return handle_from_archive(archive); -} - -void ABC_free_handle(AbcArchiveHandle *handle) -{ - delete archive_from_handle(handle); -} - -int ABC_get_version() -{ - return ALEMBIC_LIBRARY_VERSION; -} - -static void find_iobject(const IObject &object, IObject &ret, const std::string &path) -{ - if (!object.valid()) { - return; - } - - std::vector<std::string> tokens; - split(path, '/', tokens); - - IObject tmp = object; - - std::vector<std::string>::iterator iter; - for (iter = tokens.begin(); iter != tokens.end(); ++iter) { - IObject child = tmp.getChild(*iter); - tmp = child; - } - - ret = tmp; -} - -struct ExportJobData { - ViewLayer *view_layer; - Main *bmain; - wmWindowManager *wm; - - char filename[1024]; - ExportSettings settings; - - short *stop; - short *do_update; - float *progress; - - 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); - - 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; - WM_set_locked_interface(data->wm, true); - 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); - - try { - AbcExporter exporter(data->bmain, data->filename, data->settings); - - Scene *scene = data->settings.scene; /* for the CFRA macro */ - const int orig_frame = CFRA; - - data->was_canceled = false; - exporter(do_update, progress, &data->was_canceled); - - if (CFRA != orig_frame) { - CFRA = orig_frame; - - 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"; - } -} - -static void export_endjob(void *customdata) -{ - ExportJobData *data = static_cast<ExportJobData *>(customdata); - - DEG_graph_free(data->settings.depsgraph); - - if (data->was_canceled && BLI_exists(data->filename)) { - BLI_delete(data->filename, false, false); - } - - std::string log = data->settings.logger.str(); - if (!log.empty()) { - std::cerr << log; - WM_report(RPT_ERROR, "Errors occurred during the export, look in the console to know more..."); - } - - G.is_rendering = false; - WM_set_locked_interface(data->wm, false); -} - -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->wm = CTX_wm_manager(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(job->bmain, 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_objects_only = params->visible_objects_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 ********************** */ - -/** - * Generates an AbcObjectReader for this Alembic object and its children. - * - * \param object: The Alembic IObject to visit. - * \param readers: The created AbcObjectReader * will be appended to this vector. - * \param settings: Import settings, not used directly but passed to the - * AbcObjectReader subclass constructors. - * \param r_assign_as_parent: Return parameter, contains a list of reader - * pointers, whose parent pointer should still be set. - * This is filled when this call to visit_object() didn't create - * a reader that should be the parent. - * \return A pair of boolean and reader pointer. The boolean indicates whether - * this IObject claims its parent as part of the same object - * (for example an IPolyMesh object would claim its parent, as the mesh - * is interpreted as the object's data, and the parent IXform as its - * Blender object). The pointer is the AbcObjectReader that represents - * the IObject parameter. - * - * 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 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; -#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) { - for (AbcObjectReader *child_reader : nonclaiming_child_readers) { - child_reader->parent_reader = reader; - } - for (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]; - for (AbcObjectReader *child_reader : nonclaiming_child_readers) { - child_reader->parent_reader = claiming_child; - } - for (AbcObjectReader *child_reader : assign_as_parent) { - child_reader->parent_reader = claiming_child; - } - /* Claiming children should have our parent set as their parent. */ - for (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. */ - for (AbcObjectReader *child_reader : claiming_child_readers) { - r_assign_as_parent.push_back(child_reader); - } - for (AbcObjectReader *child_reader : nonclaiming_child_readers) { - r_assign_as_parent.push_back(child_reader); - } - for (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, -}; - -struct ImportJobData { - Main *bmain; - Scene *scene; - ViewLayer *view_layer; - wmWindowManager *wm; - - char filename[1024]; - ImportSettings settings; - - ArchiveReader *archive; - std::vector<AbcObjectReader *> readers; - - short *stop; - short *do_update; - float *progress; - - 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"); - - ImportJobData *data = static_cast<ImportJobData *>(user_data); - - data->stop = stop; - data->do_update = do_update; - data->progress = progress; - - WM_set_locked_interface(data->wm, true); - - ArchiveReader *archive = new ArchiveReader(data->bmain, data->filename); - - if (!archive->valid()) { -#ifndef WITH_ALEMBIC_HDF5 - data->error_code = archive->is_hdf5() ? ABC_UNSUPPORTED_HDF5 : ABC_ARCHIVE_FAIL; -#else - 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; - STRNCPY(cache_file->filepath, data->filename); - - data->archive = archive; - 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 cancellation. */ - 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->archive; - 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) -{ - /* 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; - job->archive = NULL; - - 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; - } - - AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - - bool is_constant = false; - abc_reader->read_matrix(r_mat, time, scale, is_constant); -} - -/* ************************************************************************** */ - -static AbcObjectReader *get_abc_reader(CacheReader *reader, Object *ob, const char **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; - } - - return abc_reader; -} - -static ISampleSelector sample_selector_for_time(float time) -{ - /* kFloorIndex is used to be compatible with non-interpolating - * properties; they use the floor. */ - return ISampleSelector(time, ISampleSelector::kFloorIndex); -} - -Mesh *ABC_read_mesh(CacheReader *reader, - Object *ob, - Mesh *existing_mesh, - const float time, - const char **err_str, - int read_flag) -{ - AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str); - if (abc_reader == NULL) { - return NULL; - } - - ISampleSelector sample_sel = sample_selector_for_time(time); - return abc_reader->read_mesh(existing_mesh, sample_sel, read_flag, err_str); -} - -bool ABC_mesh_topology_changed( - CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str) -{ - AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str); - if (abc_reader == NULL) { - return false; - } - - ISampleSelector sample_sel = sample_selector_for_time(time); - return abc_reader->topology_changed(existing_mesh, sample_sel); -} - -/* ************************************************************************** */ - -void CacheReader_free(CacheReader *reader) -{ - AbcObjectReader *abc_reader = reinterpret_cast<AbcObjectReader *>(reader); - abc_reader->decref(); - - if (abc_reader->refcount() == 0) { - delete abc_reader; - } -} - -void CacheReader_incref(CacheReader *reader) -{ - 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) -{ - if (object_path[0] == '\0') { - return reader; - } - - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { - return reader; - } - - IObject iobject; - find_iobject(archive->getTop(), iobject, object_path); - - 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(); - - return reinterpret_cast<CacheReader *>(abc_reader); -} |