diff options
author | Sybren A. Stüvel <sybren@blender.org> | 2020-02-17 13:47:13 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@blender.org> | 2020-02-17 13:50:28 +0300 |
commit | 2d1b05a15fa2d53894efd5198784ddde6bfa63a3 (patch) | |
tree | 0710e84c534e660135f66223af959bff7d728078 /source/blender | |
parent | c498abb1032026fac3b84f3622264b34c27212af (diff) |
Cleanup: Alembic, split source files into reader and writer
This separation between reader and writer code is part of Milesone 2 of
T73363.
In this commit the reader and writer classes are separated into their
own files, any `#include` and `using` statements are cleaned up, and
some separator comments have been removed.
No functional changes.
Diffstat (limited to 'source/blender')
41 files changed, 2016 insertions, 1616 deletions
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt index 4618246013a..8bb7051982a 100644 --- a/source/blender/alembic/CMakeLists.txt +++ b/source/blender/alembic/CMakeLists.txt @@ -41,35 +41,51 @@ set(INC_SYS ) set(SRC - intern/abc_archive.cc - intern/abc_camera.cc - intern/abc_curves.cc intern/abc_customdata.cc intern/abc_exporter.cc - intern/abc_hair.cc - intern/abc_mball.cc - intern/abc_mesh.cc - intern/abc_nurbs.cc - intern/abc_object.cc - intern/abc_points.cc - intern/abc_transform.cc + intern/abc_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_archive.h - intern/abc_camera.h - intern/abc_curves.h intern/abc_customdata.h intern/abc_exporter.h - intern/abc_hair.h - intern/abc_mball.h - intern/abc_mesh.h - intern/abc_nurbs.h - intern/abc_object.h - intern/abc_points.h - intern/abc_transform.h + intern/abc_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 diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index 7f04bb77052..c5f60ac3e29 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -32,6 +32,8 @@ extern "C" { #include "DNA_meshdata_types.h" #include "BLI_math_base.h" +#include "BLI_utildefines.h" + #include "BKE_customdata.h" } diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index ea76ade73e9..a58b0a29e5e 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -22,15 +22,15 @@ #include <cmath> -#include "abc_archive.h" -#include "abc_camera.h" -#include "abc_curves.h" -#include "abc_hair.h" -#include "abc_mball.h" -#include "abc_mesh.h" -#include "abc_nurbs.h" -#include "abc_points.h" -#include "abc_transform.h" +#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" { diff --git a/source/blender/alembic/intern/abc_archive.cc b/source/blender/alembic/intern/abc_reader_archive.cc index 15e7efad1c3..6ad44553701 100644 --- a/source/blender/alembic/intern/abc_archive.cc +++ b/source/blender/alembic/intern/abc_reader_archive.cc @@ -21,15 +21,13 @@ * \ingroup balembic */ -#include "abc_archive.h" +#include "abc_reader_archive.h" + extern "C" { -#include "BKE_blender_version.h" #include "BKE_main.h" #include "BLI_path_util.h" #include "BLI_string.h" - -#include "DNA_scene_types.h" } #ifdef WIN32 @@ -42,7 +40,6 @@ using Alembic::Abc::ErrorHandler; using Alembic::Abc::Exception; using Alembic::Abc::IArchive; using Alembic::Abc::kWrapExisting; -using Alembic::Abc::OArchive; static IArchive open_archive(const std::string &filename, const std::vector<std::istream *> &input_streams, @@ -141,77 +138,3 @@ Alembic::Abc::IObject ArchiveReader::getTop() { return m_archive.getTop(); } - -/* ************************************************************************** */ - -/* 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_archive.h b/source/blender/alembic/intern/abc_reader_archive.h index 32b1b72747f..bdb53bd0b8c 100644 --- a/source/blender/alembic/intern/abc_archive.h +++ b/source/blender/alembic/intern/abc_reader_archive.h @@ -21,8 +21,8 @@ * \ingroup balembic */ -#ifndef __ABC_ARCHIVE_H__ -#define __ABC_ARCHIVE_H__ +#ifndef __ABC_READER_ARCHIVE_H__ +#define __ABC_READER_ARCHIVE_H__ #include <Alembic/Abc/All.h> @@ -64,17 +64,4 @@ class ArchiveReader { Alembic::Abc::IObject getTop(); }; -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_ARCHIVE_H__ */ +#endif /* __ABC_READER_ARCHIVE_H__ */ diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_reader_camera.cc index dc7f00b63d9..ab506f32cbe 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_reader_camera.cc @@ -18,9 +18,8 @@ * \ingroup balembic */ -#include "abc_camera.h" - -#include "abc_transform.h" +#include "abc_reader_camera.h" +#include "abc_reader_transform.h" #include "abc_util.h" extern "C" { @@ -31,75 +30,15 @@ extern "C" { #include "BKE_object.h" #include "BLI_math.h" -#include "BLI_string.h" } +using Alembic::AbcGeom::CameraSample; using Alembic::AbcGeom::ICamera; using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::IFloatProperty; using Alembic::AbcGeom::ISampleSelector; - -using Alembic::AbcGeom::OCamera; -using Alembic::AbcGeom::OFloatProperty; - -using Alembic::AbcGeom::CameraSample; using Alembic::AbcGeom::kWrapExisting; -/* ************************************************************************** */ - -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); -} - -/* ************************************************************************** */ - AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { diff --git a/source/blender/alembic/intern/abc_reader_camera.h b/source/blender/alembic/intern/abc_reader_camera.h new file mode 100644 index 00000000000..1d9763b0454 --- /dev/null +++ b/source/blender/alembic/intern/abc_reader_camera.h @@ -0,0 +1,40 @@ +/* + * 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_curves.cc b/source/blender/alembic/intern/abc_reader_curves.cc index 3b143356c04..1be164c7c94 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_reader_curves.cc @@ -21,13 +21,12 @@ * \ingroup balembic */ -#include "abc_curves.h" +#include "abc_reader_curves.h" +#include "abc_reader_transform.h" +#include "abc_util.h" #include <cstdio> -#include "abc_transform.h" -#include "abc_util.h" - #include "MEM_guardedalloc.h" extern "C" { @@ -39,12 +38,9 @@ extern "C" { #include "BKE_curve.h" #include "BKE_mesh.h" #include "BKE_object.h" - -#include "ED_curve.h" } using Alembic::Abc::FloatArraySamplePtr; -using Alembic::Abc::IInt32ArrayProperty; using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::P3fArraySamplePtr; using Alembic::Abc::PropertyHeader; @@ -59,165 +55,6 @@ using Alembic::AbcGeom::IInt16Property; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::OCompoundProperty; -using Alembic::AbcGeom::OCurves; -using Alembic::AbcGeom::OCurvesSchema; -using Alembic::AbcGeom::OInt16Property; -using Alembic::AbcGeom::ON3fGeomParam; -using Alembic::AbcGeom::OV2fGeomParam; - -#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution" - -/* ************************************************************************** */ - -AbcCurveWriter::AbcCurveWriter(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) -{ - if (ob_eval->runtime.mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return ob_eval->runtime.mesh_eval; - } - - r_needsfree = true; - return BKE_mesh_new_nomain_from_curve(ob_eval); -} - -/* ************************************************************************** */ - AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -279,8 +116,6 @@ void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSele } } -/* ************************************************************************** */ - void AbcCurveReader::read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel) diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_reader_curves.h index 6636558356f..1e4f28edc51 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_reader_curves.h @@ -21,42 +21,15 @@ * \ingroup balembic */ -#ifndef __ABC_CURVES_H__ -#define __ABC_CURVES_H__ +#ifndef __ABC_READER_CURVES_H__ +#define __ABC_READER_CURVES_H__ -#include "abc_object.h" -#include "abc_mesh.h" +#include "abc_reader_object.h" +#include "abc_reader_mesh.h" struct Curve; -/* ************************************************************************** */ - -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); -}; - -/* ************************************************************************** */ +#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution" class AbcCurveReader : public AbcObjectReader { Alembic::AbcGeom::ICurvesSchema m_curves_schema; @@ -80,6 +53,4 @@ class AbcCurveReader : public AbcObjectReader { const Alembic::Abc::ISampleSelector &sample_selector); }; -/* ************************************************************************** */ - -#endif /* __ABC_CURVES_H__ */ +#endif /* __ABC_READER_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_reader_mesh.cc index 991fa02e4be..a4e412695c3 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_reader_mesh.cc @@ -18,58 +18,35 @@ * \ingroup balembic */ -#include "abc_mesh.h" +#include "abc_reader_mesh.h" +#include "abc_reader_transform.h" +#include "abc_util.h" #include <algorithm> -#include "abc_transform.h" -#include "abc_util.h" - #include "MEM_guardedalloc.h" extern "C" { #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_fluidsim_types.h" #include "DNA_object_types.h" #include "BLI_math_geom.h" -#include "BLI_string.h" -#include "BKE_animsys.h" -#include "BKE_key.h" -#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_object.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_mesh.h" - -#include "bmesh.h" -#include "bmesh_tools.h" - -#include "DEG_depsgraph_query.h" } -using Alembic::Abc::C4fArraySample; -using Alembic::Abc::FloatArraySample; -using Alembic::Abc::ICompoundProperty; -using Alembic::Abc::Int32ArraySample; using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::P3fArraySamplePtr; -using Alembic::Abc::V2fArraySample; -using Alembic::Abc::V3fArraySample; using Alembic::AbcGeom::IFaceSet; using Alembic::AbcGeom::IFaceSetSchema; +using Alembic::AbcGeom::IN3fGeomParam; using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IPolyMesh; using Alembic::AbcGeom::IPolyMeshSchema; @@ -77,570 +54,14 @@ using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::ISubD; using Alembic::AbcGeom::ISubDSchema; using Alembic::AbcGeom::IV2fGeomParam; - -using Alembic::AbcGeom::OArrayProperty; -using Alembic::AbcGeom::OBoolProperty; -using Alembic::AbcGeom::OC3fArrayProperty; -using Alembic::AbcGeom::OC3fGeomParam; -using Alembic::AbcGeom::OC4fGeomParam; -using Alembic::AbcGeom::OCompoundProperty; -using Alembic::AbcGeom::OFaceSet; -using Alembic::AbcGeom::OFaceSetSchema; -using Alembic::AbcGeom::OFloatGeomParam; -using Alembic::AbcGeom::OInt32GeomParam; -using Alembic::AbcGeom::ON3fArrayProperty; -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::OV3fGeomParam; - -using Alembic::AbcGeom::IN3fGeomParam; -using Alembic::AbcGeom::kFacevaryingScope; -using Alembic::AbcGeom::kVaryingScope; -using Alembic::AbcGeom::kVertexScope; using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::N3fArraySample; using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::UInt32ArraySample; - -/* ************************************************************************** */ +using Alembic::AbcGeom::UInt32ArraySamplePtr; +using Alembic::AbcGeom::V2fArraySamplePtr; /* 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); -} - -/* ************************************************************************** */ - /* Some helpers for mesh generation */ namespace utils { @@ -698,11 +119,6 @@ static void assign_materials(Main *bmain, } /* namespace utils */ -/* ************************************************************************** */ - -using Alembic::AbcGeom::UInt32ArraySamplePtr; -using Alembic::AbcGeom::V2fArraySamplePtr; - struct AbcMeshData { Int32ArraySamplePtr face_indices; Int32ArraySamplePtr face_counts; diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_reader_mesh.h index 38c589bbc32..bc95c7ec134 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_reader_mesh.h @@ -18,79 +18,13 @@ * \ingroup balembic */ -#ifndef __ABC_MESH_H__ -#define __ABC_MESH_H__ +#ifndef __ABC_READER_MESH_H__ +#define __ABC_READER_MESH_H__ #include "abc_customdata.h" -#include "abc_object.h" +#include "abc_reader_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; -}; - -/* ************************************************************************** */ class AbcMeshReader : public AbcObjectReader { Alembic::AbcGeom::IPolyMeshSchema m_schema; @@ -124,8 +58,6 @@ class AbcMeshReader : public AbcObjectReader { std::map<std::string, int> &r_mat_map); }; -/* ************************************************************************** */ - class AbcSubDReader : public AbcObjectReader { Alembic::AbcGeom::ISubDSchema m_schema; @@ -145,12 +77,10 @@ class AbcSubDReader : public AbcObjectReader { 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_MESH_H__ */ +#endif /* __ABC_READER_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_reader_nurbs.cc index c11ca7d57b9..0ada10baba5 100644 --- a/source/blender/alembic/intern/abc_nurbs.cc +++ b/source/blender/alembic/intern/abc_reader_nurbs.cc @@ -18,9 +18,8 @@ * \ingroup balembic */ -#include "abc_nurbs.h" - -#include "abc_transform.h" +#include "abc_reader_nurbs.h" +#include "abc_reader_transform.h" #include "abc_util.h" #include "MEM_guardedalloc.h" @@ -30,169 +29,21 @@ extern "C" { #include "DNA_object_types.h" #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_string.h" #include "BKE_curve.h" #include "BKE_object.h" } -using Alembic::AbcGeom::bool_t; -using Alembic::AbcGeom::FloatArraySample; using Alembic::AbcGeom::FloatArraySamplePtr; using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::MetaData; using Alembic::AbcGeom::P3fArraySamplePtr; -using Alembic::AbcGeom::IBoolProperty; using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::INuPatch; using Alembic::AbcGeom::INuPatchSchema; using Alembic::AbcGeom::IObject; -using Alembic::AbcGeom::ISampleSelector; - -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); - } -} - -/* ************************************************************************** */ AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) diff --git a/source/blender/alembic/intern/abc_nurbs.h b/source/blender/alembic/intern/abc_reader_nurbs.h index 3e12c9a3b62..f4284c136fb 100644 --- a/source/blender/alembic/intern/abc_nurbs.h +++ b/source/blender/alembic/intern/abc_reader_nurbs.h @@ -18,30 +18,10 @@ * \ingroup balembic */ -#ifndef __ABC_NURBS_H__ -#define __ABC_NURBS_H__ +#ifndef __ABC_READER_NURBS_H__ +#define __ABC_READER_NURBS_H__ -#include "abc_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; -}; - -/* ************************************************************************** */ +#include "abc_reader_object.h" class AbcNurbsReader : public AbcObjectReader { std::vector<std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject>> m_schemas; @@ -57,4 +37,4 @@ class AbcNurbsReader : public AbcObjectReader { void getNurbsPatches(const Alembic::Abc::IObject &obj); }; -#endif /* __ABC_NURBS_H__ */ +#endif /* __ABC_READER_NURBS_H__ */ diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_reader_object.cc index 76aec9ad998..3e7f87d78cc 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_reader_object.cc @@ -18,25 +18,23 @@ * \ingroup balembic */ -#include "abc_object.h" - +#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_object_types.h" #include "DNA_space_types.h" /* for FILE_MAX */ #include "BKE_constraint.h" -#include "BKE_idprop.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.h" +#include "BLI_math_geom.h" #include "BLI_string.h" } @@ -44,72 +42,6 @@ using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IXform; using Alembic::AbcGeom::IXformSchema; -using Alembic::AbcGeom::OCompoundProperty; -using Alembic::AbcGeom::ODoubleArrayProperty; -using Alembic::AbcGeom::ODoubleProperty; -using Alembic::AbcGeom::OFloatArrayProperty; -using Alembic::AbcGeom::OFloatProperty; -using Alembic::AbcGeom::OInt32ArrayProperty; -using Alembic::AbcGeom::OInt32Property; -using Alembic::AbcGeom::OStringArrayProperty; -using Alembic::AbcGeom::OStringProperty; - -/* ************************************************************************** */ - -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; -} - -/* ************************************************************************** */ - AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings) : m_name(""), m_object_name(""), diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_reader_object.h index efe78b9017c..94923df2df9 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_reader_object.h @@ -18,61 +18,22 @@ * \ingroup balembic */ -#ifndef __ABC_OBJECT_H__ -#define __ABC_OBJECT_H__ +#ifndef __ABC_READER_OBJECT_H__ +#define __ABC_READER_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 CacheFile; struct Main; +struct Mesh; 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; -}; - -/* ************************************************************************** */ - -struct CacheFile; +using Alembic::AbcCoreAbstract::chrono_t; struct ImportSettings { bool do_convert_mat; @@ -116,12 +77,6 @@ template<typename Schema> static bool has_animations(Schema &schema, ImportSetti return settings->is_sequence || !schema.isConstant(); } -/* ************************************************************************** */ - -struct Mesh; - -using Alembic::AbcCoreAbstract::chrono_t; - class AbcObjectReader { protected: std::string m_name; @@ -213,4 +168,4 @@ class AbcObjectReader { Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); -#endif /* __ABC_OBJECT_H__ */ +#endif /* __ABC_READER_OBJECT_H__ */ diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_reader_points.cc index d691087ca21..e4dc345f868 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_reader_points.cc @@ -21,29 +21,20 @@ * \ingroup balembic */ -#include "abc_points.h" - -#include "abc_mesh.h" -#include "abc_transform.h" +#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_cdderivedmesh.h" -#include "BKE_lattice.h" +#include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_object.h" -#include "BKE_particle.h" -#include "BKE_scene.h" - -#include "BLI_math.h" - -#include "DEG_depsgraph_query.h" } -using Alembic::AbcGeom::kVertexScope; using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::N3fArraySamplePtr; using Alembic::AbcGeom::P3fArraySamplePtr; @@ -54,91 +45,6 @@ using Alembic::AbcGeom::IPoints; using Alembic::AbcGeom::IPointsSchema; using Alembic::AbcGeom::ISampleSelector; -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); -} - -/* ************************************************************************** */ - AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_reader_points.h index 5eb448f0f66..31ad6c4589b 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_reader_points.h @@ -21,33 +21,12 @@ * \ingroup balembic */ -#ifndef __ABC_POINTS_H__ -#define __ABC_POINTS_H__ +#ifndef __ABC_READER_POINTS_H__ +#define __ABC_READER_POINTS_H__ -#include "abc_object.h" +#include "abc_reader_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(); -}; - -/* ************************************************************************** */ - class AbcPointsReader : public AbcObjectReader { Alembic::AbcGeom::IPointsSchema m_schema; Alembic::AbcGeom::IPointsSchema::Sample m_sample; @@ -72,4 +51,4 @@ void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, const Alembic::AbcGeom::ISampleSelector &selector, CDStreamConfig &config); -#endif /* __ABC_POINTS_H__ */ +#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 new file mode 100644 index 00000000000..ce569a9ccb5 --- /dev/null +++ b/source/blender/alembic/intern/abc_reader_transform.cc @@ -0,0 +1,76 @@ +/* + * 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 new file mode 100644 index 00000000000..6b4d23c1884 --- /dev/null +++ b/source/blender/alembic/intern/abc_reader_transform.h @@ -0,0 +1,42 @@ +/* + * 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 index 9a4d4e1a8cc..b26ef8b3b76 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -20,12 +20,12 @@ #include "abc_util.h" -#include "abc_camera.h" -#include "abc_curves.h" -#include "abc_mesh.h" -#include "abc_nurbs.h" -#include "abc_points.h" -#include "abc_transform.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> @@ -33,9 +33,8 @@ extern "C" { #include "DNA_object_types.h" -#include "DNA_layer_types.h" -#include "BLI_math.h" +#include "BLI_math_geom.h" #include "PIL_time.h" } diff --git a/source/blender/alembic/intern/abc_writer_archive.cc b/source/blender/alembic/intern/abc_writer_archive.cc new file mode 100644 index 00000000000..af18d480a18 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_archive.cc @@ -0,0 +1,114 @@ +/* + * 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 new file mode 100644 index 00000000000..e261e60990a --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_archive.h @@ -0,0 +1,58 @@ +/* + * 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 new file mode 100644 index 00000000000..e705e5ba911 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_camera.cc @@ -0,0 +1,81 @@ +/* + * 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_camera.h b/source/blender/alembic/intern/abc_writer_camera.h index 28169cb7d85..3b515911a48 100644 --- a/source/blender/alembic/intern/abc_camera.h +++ b/source/blender/alembic/intern/abc_writer_camera.h @@ -18,10 +18,10 @@ * \ingroup balembic */ -#ifndef __ABC_CAMERA_H__ -#define __ABC_CAMERA_H__ +#ifndef __ABC_WRITER_CAMERA_H__ +#define __ABC_WRITER_CAMERA_H__ -#include "abc_object.h" +#include "abc_writer_object.h" /* ************************************************************************** */ @@ -42,20 +42,4 @@ class AbcCameraWriter : public AbcObjectWriter { virtual void do_write(); }; -/* ************************************************************************** */ - -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_CAMERA_H__ */ +#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 new file mode 100644 index 00000000000..bb9109dc025 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_curves.cc @@ -0,0 +1,187 @@ +/* + * 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" +} + +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) +{ + if (ob_eval->runtime.mesh_eval != NULL) { + /* Mesh_eval only exists when generative modifiers are in use. */ + r_needsfree = false; + return ob_eval->runtime.mesh_eval; + } + + r_needsfree = true; + return BKE_mesh_new_nomain_from_curve(ob_eval); +} diff --git a/source/blender/alembic/intern/abc_writer_curves.h b/source/blender/alembic/intern/abc_writer_curves.h new file mode 100644 index 00000000000..d6d8c0a7f11 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_curves.h @@ -0,0 +1,55 @@ +/* + * 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_hair.cc b/source/blender/alembic/intern/abc_writer_hair.cc index 7eaecd271f4..bbba03ed7f4 100644 --- a/source/blender/alembic/intern/abc_hair.cc +++ b/source/blender/alembic/intern/abc_writer_hair.cc @@ -18,26 +18,22 @@ * \ingroup balembic */ -#include "abc_hair.h" - -#include <cstdio> - -#include "abc_transform.h" +#include "abc_writer_hair.h" +#include "abc_writer_transform.h" #include "abc_util.h" -#include "MEM_guardedalloc.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_listbase.h" #include "BLI_math_geom.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" -#include "BKE_object.h" #include "BKE_particle.h" } diff --git a/source/blender/alembic/intern/abc_hair.h b/source/blender/alembic/intern/abc_writer_hair.h index 21f665a4795..67d1b7b3d23 100644 --- a/source/blender/alembic/intern/abc_hair.h +++ b/source/blender/alembic/intern/abc_writer_hair.h @@ -18,16 +18,14 @@ * \ingroup balembic */ -#ifndef __ABC_HAIR_H__ -#define __ABC_HAIR_H__ +#ifndef __ABC_WRITER_HAIR_H__ +#define __ABC_WRITER_HAIR_H__ -#include "abc_object.h" +#include "abc_writer_object.h" struct ParticleSettings; struct ParticleSystem; -/* ************************************************************************** */ - class AbcHairWriter : public AbcObjectWriter { ParticleSystem *m_psys; @@ -61,4 +59,4 @@ class AbcHairWriter : public AbcObjectWriter { std::vector<int32_t> &hvertices); }; -#endif /* __ABC_HAIR_H__ */ +#endif /* __ABC_WRITER_HAIR_H__ */ diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_writer_mball.cc index 6fc7d8c24c8..aa08146c6e2 100644 --- a/source/blender/alembic/intern/abc_mball.cc +++ b/source/blender/alembic/intern/abc_writer_mball.cc @@ -18,25 +18,20 @@ * \ingroup balembic */ -#include "abc_mball.h" -#include "abc_mesh.h" -#include "abc_transform.h" - -#include "MEM_guardedalloc.h" +#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_curve.h" #include "BKE_displist.h" #include "BKE_lib_id.h" #include "BKE_mball.h" #include "BKE_mesh.h" -#include "BKE_object.h" -#include "DEG_depsgraph.h" +#include "BLI_utildefines.h" } AbcMBallWriter::AbcMBallWriter(Main *bmain, diff --git a/source/blender/alembic/intern/abc_mball.h b/source/blender/alembic/intern/abc_writer_mball.h index 4be977fa8f5..c752472c86d 100644 --- a/source/blender/alembic/intern/abc_mball.h +++ b/source/blender/alembic/intern/abc_writer_mball.h @@ -18,11 +18,11 @@ * \ingroup balembic */ -#ifndef __ABC_MBALL_H__ -#define __ABC_MBALL_H__ +#ifndef __ABC_WRITER_MBALL_H__ +#define __ABC_WRITER_MBALL_H__ -#include "abc_object.h" -#include "abc_mesh.h" +#include "abc_writer_object.h" +#include "abc_writer_mesh.h" struct Main; struct Object; @@ -53,4 +53,4 @@ class AbcMBallWriter : public AbcGenericMeshWriter { bool isAnimated() const override; }; -#endif /* __ABC_MBALL_H__ */ +#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 new file mode 100644 index 00000000000..b55d2473f99 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_mesh.cc @@ -0,0 +1,592 @@ +/* + * 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 new file mode 100644 index 00000000000..9152a370e4f --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_mesh.h @@ -0,0 +1,91 @@ +/* + * 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 new file mode 100644 index 00000000000..9796eaf54c3 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_nurbs.cc @@ -0,0 +1,172 @@ +/* + * 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 new file mode 100644 index 00000000000..c6a3c399b66 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_nurbs.h @@ -0,0 +1,42 @@ +/* + * 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 new file mode 100644 index 00000000000..75dc93bd08e --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_object.cc @@ -0,0 +1,79 @@ +/* + * 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 new file mode 100644 index 00000000000..c3511566372 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_object.h @@ -0,0 +1,71 @@ +/* + * 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 new file mode 100644 index 00000000000..cc4abe8ec4b --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_points.cc @@ -0,0 +1,123 @@ +/* + * 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 new file mode 100644 index 00000000000..77dd10c4b26 --- /dev/null +++ b/source/blender/alembic/intern/abc_writer_points.h @@ -0,0 +1,49 @@ +/* + * 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_transform.cc b/source/blender/alembic/intern/abc_writer_transform.cc index 5135af131b1..d7bcc46d96f 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_writer_transform.cc @@ -18,30 +18,22 @@ * \ingroup balembic */ -#include "abc_transform.h" +#include "abc_writer_transform.h" +#include "abc_util.h" #include <OpenEXR/ImathBoxAlgo.h> -#include "abc_util.h" - extern "C" { #include "DNA_object_types.h" -#include "BLI_listbase.h" #include "BLI_math.h" -#include "BKE_animsys.h" -#include "BKE_object.h" - #include "DEG_depsgraph_query.h" } -using Alembic::Abc::ISampleSelector; using Alembic::AbcGeom::OObject; using Alembic::AbcGeom::OXform; -/* ************************************************************************** */ - AbcTransformWriter::AbcTransformWriter(Object *ob, const OObject &abc_parent, AbcTransformWriter *parent, @@ -127,49 +119,3 @@ bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const { return true; } - -/* ************************************************************************** */ - -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_transform.h b/source/blender/alembic/intern/abc_writer_transform.h index 7fa42cf0299..4397b220761 100644 --- a/source/blender/alembic/intern/abc_transform.h +++ b/source/blender/alembic/intern/abc_writer_transform.h @@ -18,15 +18,13 @@ * \ingroup balembic */ -#ifndef __ABC_TRANSFORM_H__ -#define __ABC_TRANSFORM_H__ +#ifndef __ABC_WRITER_TRANSFORM_H__ +#define __ABC_WRITER_TRANSFORM_H__ -#include "abc_object.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; @@ -59,20 +57,4 @@ class AbcTransformWriter : public AbcObjectWriter { bool hasAnimation(Object *ob) const; }; -/* ************************************************************************** */ - -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_TRANSFORM_H__ */ +#endif /* __ABC_WRITER_TRANSFORM_H__ */ diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 0cab0303fcc..6c7ab4d4b87 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -22,15 +22,21 @@ #include <Alembic/AbcMaterial/IMaterial.h> -#include "abc_archive.h" -#include "abc_camera.h" -#include "abc_curves.h" -#include "abc_hair.h" -#include "abc_mesh.h" -#include "abc_nurbs.h" -#include "abc_points.h" -#include "abc_transform.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" |