diff options
Diffstat (limited to 'source/blender/io')
89 files changed, 3102 insertions, 2641 deletions
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt index bc2f8d628e2..360cacc4360 100644 --- a/source/blender/io/CMakeLists.txt +++ b/source/blender/io/CMakeLists.txt @@ -18,6 +18,8 @@ # All rights reserved. # ***** END GPL LICENSE BLOCK ***** +add_subdirectory(common) + if(WITH_ALEMBIC) add_subdirectory(alembic) endif() diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h index ba430752b29..ddf75aa3258 100644 --- a/source/blender/io/alembic/ABC_alembic.h +++ b/source/blender/io/alembic/ABC_alembic.h @@ -13,14 +13,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_ALEMBIC_H__ -#define __ABC_ALEMBIC_H__ - #ifdef __cplusplus extern "C" { #endif @@ -133,5 +131,3 @@ struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *han #ifdef __cplusplus } #endif - -#endif /* __ABC_ALEMBIC_H__ */ diff --git a/source/blender/io/alembic/CMakeLists.txt b/source/blender/io/alembic/CMakeLists.txt index 16f2d944876..da36272b850 100644 --- a/source/blender/io/alembic/CMakeLists.txt +++ b/source/blender/io/alembic/CMakeLists.txt @@ -20,6 +20,7 @@ set(INC . + ../common ../../blenkernel ../../blenlib ../../blenloader @@ -29,6 +30,7 @@ set(INC ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/clog ../../../../intern/guardedalloc ../../../../intern/utfconv ) @@ -42,7 +44,6 @@ set(INC_SYS set(SRC intern/abc_axis_conversion.cc intern/abc_customdata.cc - intern/abc_exporter.cc intern/abc_reader_archive.cc intern/abc_reader_camera.cc intern/abc_reader_curves.cc @@ -52,22 +53,25 @@ set(SRC 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 + exporter/abc_archive.cc + exporter/abc_export_capi.cc + exporter/abc_hierarchy_iterator.cc + exporter/abc_subdiv_disabler.cc + exporter/abc_writer_abstract.cc + exporter/abc_writer_camera.cc + exporter/abc_writer_curves.cc + exporter/abc_writer_hair.cc + exporter/abc_writer_mesh.cc + exporter/abc_writer_mball.cc + exporter/abc_writer_nurbs.cc + exporter/abc_writer_points.cc + exporter/abc_writer_transform.cc + ABC_alembic.h intern/abc_axis_conversion.h intern/abc_customdata.h - intern/abc_exporter.h intern/abc_reader_archive.h intern/abc_reader_camera.h intern/abc_reader_curves.h @@ -77,21 +81,25 @@ set(SRC 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 + + exporter/abc_archive.h + exporter/abc_hierarchy_iterator.h + exporter/abc_subdiv_disabler.h + exporter/abc_writer_abstract.h + exporter/abc_writer_camera.h + exporter/abc_writer_curves.h + exporter/abc_writer_hair.h + exporter/abc_writer_mesh.h + exporter/abc_writer_mball.h + exporter/abc_writer_nurbs.h + exporter/abc_writer_points.h + exporter/abc_writer_transform.h ) set(LIB bf_blenkernel bf_blenlib + bf_io_common ${ALEMBIC_LIBRARIES} ${OPENEXR_LIBRARIES} diff --git a/source/blender/io/alembic/exporter/abc_archive.cc b/source/blender/io/alembic/exporter/abc_archive.cc new file mode 100644 index 00000000000..5fbf74f0705 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_archive.cc @@ -0,0 +1,265 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +#include "abc_archive.h" + +#include "BKE_blender_version.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph_query.h" + +#include "DNA_scene_types.h" + +#include <Alembic/AbcCoreOgawa/All.h> +#include <Alembic/AbcGeom/All.h> + +#ifdef WIN32 +# include "BLI_path_util.h" +# include "BLI_string.h" + +# include "utfconv.h" +#endif + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::ErrorHandler; +using Alembic::Abc::kWrapExisting; +using Alembic::Abc::MetaData; +using Alembic::Abc::OArchive; +using Alembic::Abc::TimeSampling; +using Alembic::Abc::TimeSamplingPtr; +using Alembic::Abc::TimeSamplingType; + +static MetaData create_abc_metadata(const Main *bmain, double scene_fps) +{ + MetaData abc_metadata; + + std::string abc_user_description(bmain->name); + if (abc_user_description.empty()) { + abc_user_description = "unknown"; + } + + abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender"); + abc_metadata.set(Alembic::Abc::kUserDescriptionKey, abc_user_description); + abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string()); + 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); + return abc_metadata; +} + +static OArchive *create_archive(std::ofstream *abc_ostream, + const std::string &filename, + MetaData &abc_metadata) +{ + /* Use stream to support unicode character paths on Windows. */ +#ifdef WIN32 + char filename_cstr[FILE_MAX]; + BLI_strncpy(filename_cstr, filename.c_str(), FILE_MAX); + + UTF16_ENCODE(filename_cstr); + std::wstring wstr(filename_cstr_16); + abc_ostream->open(wstr.c_str(), std::ios::out | std::ios::binary); + UTF16_UN_ENCODE(filename_cstr); +#else + abc_ostream->open(filename, std::ios::out | std::ios::binary); +#endif + + ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy; + + Alembic::AbcCoreOgawa::WriteArchive archive_writer; + return new OArchive(archive_writer(abc_ostream, abc_metadata), kWrapExisting, policy); +} + +/* Construct list of shutter samples. + * + * These are taken from the interval [shutter open, shutter close), + * uniformly sampled with 'nr_of_samples' samples. + * + * TODO(Sybren): test that the above interval is indeed half-open. + * + * If 'time_relative' is true, samples are returned as time (in seconds) from params.frame_start. + * If 'time_relative' is false, samples are returned as fractional frames from 0. + * */ +static void get_shutter_samples(double scene_fps, + const AlembicExportParams ¶ms, + int nr_of_samples, + bool time_relative, + std::vector<double> &r_samples) +{ + int frame_offset = time_relative ? params.frame_start : 0; + double time_factor = time_relative ? scene_fps : 1.0; + double shutter_open = params.shutter_open; + double shutter_close = params.shutter_close; + double time_inc = (shutter_close - shutter_open) / nr_of_samples; + + /* sample between shutter open & close */ + for (int sample = 0; sample < nr_of_samples; sample++) { + double sample_time = shutter_open + time_inc * sample; + double time = (frame_offset + sample_time) / time_factor; + + r_samples.push_back(time); + } +} + +static TimeSamplingPtr create_time_sampling(double scene_fps, + const AlembicExportParams ¶ms, + int nr_of_samples) +{ + std::vector<double> samples; + + if (params.frame_start == params.frame_end) { + return TimeSamplingPtr(new TimeSampling()); + } + + get_shutter_samples(scene_fps, params, nr_of_samples, true, samples); + + TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / scene_fps); + return TimeSamplingPtr(new TimeSampling(ts, samples)); +} + +static void get_frames(double scene_fps, + const AlembicExportParams ¶ms, + unsigned int nr_of_samples, + std::set<double> &r_frames) +{ + /* Get one set of shutter samples, then add those around each frame to export. */ + std::vector<double> shutter_samples; + get_shutter_samples(scene_fps, params, nr_of_samples, false, shutter_samples); + + for (double frame = params.frame_start; frame <= params.frame_end; frame += 1.0) { + for (size_t j = 0; j < nr_of_samples; j++) { + r_frames.insert(frame + shutter_samples[j]); + } + } +} + +/* ****************************************************************** */ + +ABCArchive::ABCArchive(const Main *bmain, + const Scene *scene, + AlembicExportParams params, + std::string filename) + : archive(nullptr) +{ + double scene_fps = FPS; + MetaData abc_metadata = create_abc_metadata(bmain, scene_fps); + + // Create the Archive. + archive = create_archive(&abc_ostream_, filename, abc_metadata); + + // Create time samples for transforms and shapes. + TimeSamplingPtr ts_xform; + TimeSamplingPtr ts_shapes; + + ts_xform = create_time_sampling(scene_fps, params, params.frame_samples_xform); + time_sampling_index_transforms_ = archive->addTimeSampling(*ts_xform); + + const bool export_animation = params.frame_start != params.frame_end; + if (!export_animation || params.frame_samples_shape == params.frame_samples_xform) { + ts_shapes = ts_xform; + time_sampling_index_shapes_ = time_sampling_index_transforms_; + } + else { + ts_shapes = create_time_sampling(scene_fps, params, params.frame_samples_shape); + time_sampling_index_shapes_ = archive->addTimeSampling(*ts_shapes); + } + + // Construct the frames to export. + get_frames(scene_fps, params, params.frame_samples_xform, xform_frames_); + get_frames(scene_fps, params, params.frame_samples_shape, shape_frames_); + + // Merge all frames to get the final set of frames to export. + export_frames_.insert(xform_frames_.begin(), xform_frames_.end()); + export_frames_.insert(shape_frames_.begin(), shape_frames_.end()); + + abc_archive_bbox_ = Alembic::AbcGeom::CreateOArchiveBounds(*archive, + time_sampling_index_transforms_); +} + +ABCArchive::~ABCArchive() +{ + delete archive; +} + +uint32_t ABCArchive::time_sampling_index_transforms() const +{ + return time_sampling_index_transforms_; +} + +uint32_t ABCArchive::time_sampling_index_shapes() const +{ + return time_sampling_index_shapes_; +} + +ABCArchive::Frames::const_iterator ABCArchive::frames_begin() const +{ + return export_frames_.begin(); +} +ABCArchive::Frames::const_iterator ABCArchive::frames_end() const +{ + return export_frames_.end(); +} +size_t ABCArchive::total_frame_count() const +{ + return export_frames_.size(); +} + +bool ABCArchive::is_xform_frame(double frame) const +{ + return xform_frames_.find(frame) != xform_frames_.end(); +} +bool ABCArchive::is_shape_frame(double frame) const +{ + return shape_frames_.find(frame) != shape_frames_.end(); +} +ExportSubset ABCArchive::export_subset_for_frame(double frame) const +{ + ExportSubset subset; + subset.transforms = is_xform_frame(frame); + subset.shapes = is_shape_frame(frame); + return subset; +} + +void ABCArchive::update_bounding_box(const Imath::Box3d &bounds) +{ + abc_archive_bbox_.set(bounds); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_archive.h b/source/blender/io/alembic/exporter/abc_archive.h new file mode 100644 index 00000000000..43d0acf2520 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_archive.h @@ -0,0 +1,87 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup Alembic + */ + +#pragma once + +#include "ABC_alembic.h" +#include "IO_abstract_hierarchy_iterator.h" + +#include <Alembic/Abc/OArchive.h> +#include <Alembic/Abc/OTypedScalarProperty.h> + +#include <fstream> +#include <set> +#include <string> + +struct Main; +struct Scene; + +namespace blender { +namespace io { +namespace alembic { + +/* Container for an Alembic archive and time sampling info. + * + * Constructor arguments are used to create the correct output stream and to set the archive's + * metadata. */ +class ABCArchive { + public: + typedef std::set<double> Frames; + + Alembic::Abc::OArchive *archive; + + ABCArchive(const Main *bmain, + const Scene *scene, + AlembicExportParams params, + std::string filename); + ~ABCArchive(); + + uint32_t time_sampling_index_transforms() const; + uint32_t time_sampling_index_shapes() const; + + Frames::const_iterator frames_begin() const; + Frames::const_iterator frames_end() const; + size_t total_frame_count() const; + + bool is_xform_frame(double frame) const; + bool is_shape_frame(double frame) const; + + ExportSubset export_subset_for_frame(double frame) const; + + void update_bounding_box(const Imath::Box3d &bounds); + + private: + std::ofstream abc_ostream_; + uint32_t time_sampling_index_transforms_; + uint32_t time_sampling_index_shapes_; + + Frames xform_frames_; + Frames shape_frames_; + Frames export_frames_; + + Alembic::Abc::OBox3dProperty abc_archive_bbox_; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_export_capi.cc b/source/blender/io/alembic/exporter/abc_export_capi.cc new file mode 100644 index 00000000000..fbc5b2d5c02 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_export_capi.cc @@ -0,0 +1,220 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +#include "ABC_alembic.h" +#include "abc_archive.h" +#include "abc_hierarchy_iterator.h" +#include "abc_subdiv_disabler.h" + +#include "MEM_guardedalloc.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "DNA_modifier_types.h" +#include "DNA_scene_types.h" + +#include "BKE_blender_version.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +#include <algorithm> + +struct ExportJobData { + Main *bmain; + Depsgraph *depsgraph; + wmWindowManager *wm; + + char filename[FILE_MAX]; + AlembicExportParams params; + + bool was_canceled; + bool export_ok; +}; + +namespace blender { +namespace io { +namespace alembic { + +// Construct the depsgraph for exporting. +static void build_depsgraph(Depsgraph *depsgraph, Main *bmain) +{ + Scene *scene = DEG_get_input_scene(depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + DEG_graph_build_from_view_layer(depsgraph, bmain, scene, view_layer); +} + +static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + ExportJobData *data = static_cast<ExportJobData *>(customdata); + data->was_canceled = false; + + G.is_rendering = true; + WM_set_locked_interface(data->wm, true); + G.is_break = false; + + *progress = 0.0f; + *do_update = true; + + build_depsgraph(data->depsgraph, data->bmain); + SubdivModifierDisabler subdiv_disabler(data->depsgraph); + if (!data->params.apply_subdiv) { + subdiv_disabler.disable_modifiers(); + } + BKE_scene_graph_update_tagged(data->depsgraph, data->bmain); + + // For restoring the current frame after exporting animation is done. + Scene *scene = DEG_get_input_scene(data->depsgraph); + const int orig_frame = CFRA; + const bool export_animation = (data->params.frame_start != data->params.frame_end); + + // Create the Alembic archive. + ABCArchive abc_archive(data->bmain, scene, data->params, std::string(data->filename)); + + ABCHierarchyIterator iter(data->depsgraph, &abc_archive, data->params); + + if (export_animation) { + CLOG_INFO(&LOG, 2, "Exporting animation"); + + // Writing the animated frames is not 100% of the work, but it's our best guess. + const float progress_per_frame = 1.0f / std::max(size_t(1), abc_archive.total_frame_count()); + ABCArchive::Frames::const_iterator frame_it = abc_archive.frames_begin(); + const ABCArchive::Frames::const_iterator frames_end = abc_archive.frames_end(); + + for (; frame_it != frames_end; frame_it++) { + double frame = *frame_it; + + if (G.is_break || (stop != nullptr && *stop)) { + break; + } + + // Update the scene for the next frame to render. + scene->r.cfra = static_cast<int>(frame); + scene->r.subframe = frame - scene->r.cfra; + BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + + CLOG_INFO(&LOG, 2, "Exporting frame %.2f", frame); + ExportSubset export_subset = abc_archive.export_subset_for_frame(frame); + iter.set_export_subset(export_subset); + iter.iterate_and_write(); + + *progress += progress_per_frame; + *do_update = true; + } + } + else { + // If we're not animating, a single iteration over all objects is enough. + iter.iterate_and_write(); + } + + iter.release_writers(); + + // Finish up by going back to the keyframe that was current before we started. + if (CFRA != orig_frame) { + CFRA = orig_frame; + BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + } + + data->export_ok = !data->was_canceled; + + *progress = 1.0f; + *do_update = true; +} + +static void export_endjob(void *customdata) +{ + ExportJobData *data = static_cast<ExportJobData *>(customdata); + + DEG_graph_free(data->depsgraph); + + if (data->was_canceled && BLI_exists(data->filename)) { + BLI_delete(data->filename, false, false); + } + + G.is_rendering = false; + WM_set_locked_interface(data->wm, false); +} + +} // namespace alembic +} // namespace io +} // namespace blender + +bool ABC_export(Scene *scene, + bContext *C, + const char *filepath, + const AlembicExportParams *params, + bool as_background_job) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + + ExportJobData *job = static_cast<ExportJobData *>( + MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); + + job->bmain = CTX_data_main(C); + job->wm = CTX_wm_manager(C); + job->export_ok = false; + BLI_strncpy(job->filename, filepath, sizeof(job->filename)); + + job->depsgraph = DEG_graph_new( + job->bmain, scene, view_layer, DAG_EVAL_RENDER /* TODO(Sybren): params->evaluation_mode */); + job->params = *params; + + bool export_ok = false; + if (as_background_job) { + wmJob *wm_job = WM_jobs_get( + job->wm, CTX_wm_window(C), scene, "Alembic Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, MEM_freeN); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, + blender::io::alembic::export_startjob, + NULL, + NULL, + blender::io::alembic::export_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + blender::io::alembic::export_startjob(job, &stop, &do_update, &progress); + blender::io::alembic::export_endjob(job); + export_ok = job->export_ok; + + MEM_freeN(job); + } + + return export_ok; +} diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc new file mode 100644 index 00000000000..90004c0e85b --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc @@ -0,0 +1,261 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +#include "abc_hierarchy_iterator.h" +#include "abc_writer_abstract.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 <memory> +#include <string> + +#include "BLI_assert.h" + +#include "DEG_depsgraph_query.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" + +namespace blender { +namespace io { +namespace alembic { + +ABCHierarchyIterator::ABCHierarchyIterator(Depsgraph *depsgraph, + ABCArchive *abc_archive, + const AlembicExportParams ¶ms) + : AbstractHierarchyIterator(depsgraph), abc_archive_(abc_archive), params_(params) +{ +} + +void ABCHierarchyIterator::iterate_and_write() +{ + AbstractHierarchyIterator::iterate_and_write(); + update_archive_bounding_box(); +} + +void ABCHierarchyIterator::update_archive_bounding_box() +{ + Imath::Box3d bounds; + update_bounding_box_recursive(bounds, HierarchyContext::root()); + abc_archive_->update_bounding_box(bounds); +} + +void ABCHierarchyIterator::update_bounding_box_recursive(Imath::Box3d &bounds, + const HierarchyContext *context) +{ + if (context != nullptr) { + AbstractHierarchyWriter *abstract_writer = writers_[context->export_path]; + ABCAbstractWriter *abc_writer = static_cast<ABCAbstractWriter *>(abstract_writer); + + if (abc_writer != nullptr) { + bounds.extendBy(abc_writer->bounding_box()); + } + } + + for (HierarchyContext *child_context : graph_children(context)) { + update_bounding_box_recursive(bounds, child_context); + } +} + +bool ABCHierarchyIterator::mark_as_weak_export(const Object *object) const +{ + if (params_.selected_only && (object->base_flag & BASE_SELECTED) == 0) { + return true; + } + /* TODO(Sybren): handle other flags too? */ + return false; +} + +void ABCHierarchyIterator::delete_object_writer(AbstractHierarchyWriter *writer) +{ + delete writer; +} + +std::string ABCHierarchyIterator::make_valid_name(const std::string &name) const +{ + std::string abc_name(name); + std::replace(abc_name.begin(), abc_name.end(), ' ', '_'); + std::replace(abc_name.begin(), abc_name.end(), '.', '_'); + std::replace(abc_name.begin(), abc_name.end(), ':', '_'); + return abc_name; +} + +AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator:: + determine_graph_index_object(const HierarchyContext *context) +{ + if (params_.flatten_hierarchy) { + return std::make_pair(nullptr, nullptr); + } + + return AbstractHierarchyIterator::determine_graph_index_object(context); +} + +AbstractHierarchyIterator::ExportGraph::key_type ABCHierarchyIterator::determine_graph_index_dupli( + const HierarchyContext *context, const std::set<Object *> &dupli_set) +{ + if (params_.flatten_hierarchy) { + return std::make_pair(nullptr, nullptr); + } + + return AbstractHierarchyIterator::determine_graph_index_dupli(context, dupli_set); +} + +Alembic::Abc::OObject ABCHierarchyIterator::get_alembic_parent( + const HierarchyContext *context) const +{ + Alembic::Abc::OObject parent; + + if (!context->higher_up_export_path.empty()) { + AbstractHierarchyWriter *writer = get_writer(context->higher_up_export_path); + ABCAbstractWriter *abc_writer = static_cast<ABCAbstractWriter *>(writer); + parent = abc_writer->get_alembic_object(); + } + + if (!parent.valid()) { + /* An invalid parent object means "no parent", which should be translated to Alembic's top + * archive object. */ + return abc_archive_->archive->getTop(); + } + + return parent; +} + +ABCWriterConstructorArgs ABCHierarchyIterator::writer_constructor_args( + const HierarchyContext *context) const +{ + ABCWriterConstructorArgs constructor_args; + constructor_args.depsgraph = depsgraph_; + constructor_args.abc_archive = abc_archive_; + constructor_args.abc_parent = get_alembic_parent(context); + constructor_args.abc_name = context->export_name; + constructor_args.abc_path = context->export_path; + constructor_args.hierarchy_iterator = this; + constructor_args.export_params = ¶ms_; + return constructor_args; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_transform_writer( + const HierarchyContext *context) +{ + ABCAbstractWriter *transform_writer = new ABCTransformWriter(writer_constructor_args(context)); + transform_writer->create_alembic_objects(context); + return transform_writer; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_data_writer(const HierarchyContext *context) +{ + const ABCWriterConstructorArgs writer_args = writer_constructor_args(context); + ABCAbstractWriter *data_writer = nullptr; + + switch (context->object->type) { + case OB_MESH: + data_writer = new ABCMeshWriter(writer_args); + break; + case OB_CAMERA: + data_writer = new ABCCameraWriter(writer_args); + break; + case OB_CURVE: + if (params_.curves_as_mesh) { + data_writer = new ABCCurveMeshWriter(writer_args); + } + else { + data_writer = new ABCCurveWriter(writer_args); + } + break; + case OB_SURF: + if (params_.curves_as_mesh) { + data_writer = new ABCCurveMeshWriter(writer_args); + } + else { + data_writer = new ABCNurbsWriter(writer_args); + } + break; + case OB_MBALL: + data_writer = new ABCMetaballWriter(writer_args); + break; + + case OB_EMPTY: + case OB_LAMP: + case OB_FONT: + case OB_SPEAKER: + case OB_LIGHTPROBE: + case OB_LATTICE: + case OB_ARMATURE: + case OB_GPENCIL: + return nullptr; + case OB_TYPE_MAX: + BLI_assert(!"OB_TYPE_MAX should not be used"); + return nullptr; + } + + if (!data_writer->is_supported(context)) { + delete data_writer; + return nullptr; + } + + data_writer->create_alembic_objects(context); + return data_writer; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_hair_writer(const HierarchyContext *context) +{ + if (!params_.export_hair) { + return nullptr; + } + + const ABCWriterConstructorArgs writer_args = writer_constructor_args(context); + ABCAbstractWriter *hair_writer = new ABCHairWriter(writer_args); + + if (!hair_writer->is_supported(context)) { + delete hair_writer; + return nullptr; + } + + hair_writer->create_alembic_objects(context); + return hair_writer; +} + +AbstractHierarchyWriter *ABCHierarchyIterator::create_particle_writer( + const HierarchyContext *context) +{ + if (!params_.export_particles) { + return nullptr; + } + + const ABCWriterConstructorArgs writer_args = writer_constructor_args(context); + std::unique_ptr<ABCPointsWriter> particle_writer(std::make_unique<ABCPointsWriter>(writer_args)); + + if (!particle_writer->is_supported(context)) { + return nullptr; + } + + particle_writer->create_alembic_objects(context); + return particle_writer.release(); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h new file mode 100644 index 00000000000..edcb31806ba --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h @@ -0,0 +1,90 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ +#pragma once + +#include "ABC_alembic.h" +#include "abc_archive.h" + +#include "IO_abstract_hierarchy_iterator.h" + +#include <string> + +#include <Alembic/Abc/OArchive.h> +#include <Alembic/Abc/OObject.h> + +struct Depsgraph; +struct ID; +struct Object; + +namespace blender { +namespace io { +namespace alembic { + +class ABCHierarchyIterator; + +struct ABCWriterConstructorArgs { + Depsgraph *depsgraph; + ABCArchive *abc_archive; + Alembic::Abc::OObject abc_parent; + std::string abc_name; + std::string abc_path; + const ABCHierarchyIterator *hierarchy_iterator; + const AlembicExportParams *export_params; +}; + +class ABCHierarchyIterator : public AbstractHierarchyIterator { + private: + ABCArchive *abc_archive_; + const AlembicExportParams ¶ms_; + + public: + ABCHierarchyIterator(Depsgraph *depsgraph, + ABCArchive *abc_archive_, + const AlembicExportParams ¶ms); + + virtual void iterate_and_write() override; + virtual std::string make_valid_name(const std::string &name) const override; + + protected: + virtual bool mark_as_weak_export(const Object *object) const override; + + virtual ExportGraph::key_type determine_graph_index_object( + const HierarchyContext *context) override; + virtual AbstractHierarchyIterator::ExportGraph::key_type determine_graph_index_dupli( + const HierarchyContext *context, const std::set<Object *> &dupli_set) override; + + virtual AbstractHierarchyWriter *create_transform_writer( + const HierarchyContext *context) override; + virtual AbstractHierarchyWriter *create_data_writer(const HierarchyContext *context) override; + virtual AbstractHierarchyWriter *create_hair_writer(const HierarchyContext *context) override; + virtual AbstractHierarchyWriter *create_particle_writer( + const HierarchyContext *context) override; + + virtual void delete_object_writer(AbstractHierarchyWriter *writer) override; + + private: + Alembic::Abc::OObject get_alembic_parent(const HierarchyContext *context) const; + ABCWriterConstructorArgs writer_constructor_args(const HierarchyContext *context) const; + void update_archive_bounding_box(); + void update_bounding_box_recursive(Imath::Box3d &bounds, const HierarchyContext *context); +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc new file mode 100644 index 00000000000..7c147076975 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.cc @@ -0,0 +1,107 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ +#include "abc_subdiv_disabler.h" + +#include <stdio.h> + +#include "BLI_listbase.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "DNA_layer_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "BKE_modifier.h" + +namespace blender { +namespace io { +namespace alembic { + +SubdivModifierDisabler::SubdivModifierDisabler(Depsgraph *depsgraph) : depsgraph_(depsgraph) +{ +} + +SubdivModifierDisabler::~SubdivModifierDisabler() +{ + for (ModifierData *modifier : disabled_modifiers_) { + modifier->mode &= ~eModifierMode_DisableTemporary; + } +} + +void SubdivModifierDisabler::disable_modifiers() +{ + Scene *scene = DEG_get_input_scene(depsgraph_); + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph_); + + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + Object *object = base->object; + + if (object->type != OB_MESH) { + continue; + } + + ModifierData *subdiv = get_subdiv_modifier(scene, object); + if (subdiv == nullptr) { + continue; + } + + /* This disables more modifiers than necessary, as it doesn't take restrictions like + * "export selected objects only" into account. However, with the subsurfs disabled, + * moving to a different frame is also going to be faster, so in the end this is probably + * a good thing to do. */ + subdiv->mode |= eModifierMode_DisableTemporary; + disabled_modifiers_.insert(subdiv); + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + } +} + +/* Check if the mesh is a subsurf, ignoring disabled modifiers and + * displace if it's after subsurf. */ +ModifierData *SubdivModifierDisabler::get_subdiv_modifier(Scene *scene, Object *ob) +{ + ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); + + for (; md; md = md->prev) { + if (!BKE_modifier_is_enabled(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 nullptr; + } + } + + return nullptr; +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_subdiv_disabler.h b/source/blender/io/alembic/exporter/abc_subdiv_disabler.h new file mode 100644 index 00000000000..677847f3f63 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_subdiv_disabler.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) 2020 Blender Foundation. + * All rights reserved. + */ +#pragma once + +#include <set> + +struct Depsgraph; +struct ModifierData; +struct Object; +struct Scene; + +namespace blender { +namespace io { +namespace alembic { + +/** + * Temporarily all subdivision modifiers on mesh objects. + * The destructor restores all disabled modifiers. + * + * This is used to export unsubdivided meshes to Alembic. It is done in a separate step before the + * exporter starts iterating over all the frames, so that it only has to happen once per export. + */ +class SubdivModifierDisabler final { + private: + Depsgraph *depsgraph_; + std::set<ModifierData *> disabled_modifiers_; + + public: + explicit SubdivModifierDisabler(Depsgraph *depsgraph); + ~SubdivModifierDisabler(); + + void disable_modifiers(); + + static ModifierData *get_subdiv_modifier(Scene *scene, Object *ob); +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.cc b/source/blender/io/alembic/exporter/abc_writer_abstract.cc new file mode 100644 index 00000000000..e43b394e27f --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.cc @@ -0,0 +1,101 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ +#include "abc_writer_abstract.h" +#include "abc_hierarchy_iterator.h" + +#include "BKE_animsys.h" +#include "BKE_key.h" +#include "BKE_object.h" + +#include "DNA_modifier_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::OObject; +using Alembic::Abc::TimeSamplingPtr; + +ABCAbstractWriter::ABCAbstractWriter(const ABCWriterConstructorArgs &args) + : args_(args), + frame_has_been_written_(false), + is_animated_(false), + timesample_index_(args_.abc_archive->time_sampling_index_shapes()) +{ +} + +ABCAbstractWriter::~ABCAbstractWriter() +{ +} + +bool ABCAbstractWriter::is_supported(const HierarchyContext * /*context*/) const +{ + return true; +} + +void ABCAbstractWriter::write(HierarchyContext &context) +{ + if (!frame_has_been_written_) { + is_animated_ = (args_.export_params->frame_start != args_.export_params->frame_end) && + check_is_animated(context); + } + else if (!is_animated_) { + /* A frame has already been written, and without animation one frame is enough. */ + return; + } + + do_write(context); + + frame_has_been_written_ = true; +} + +const Imath::Box3d &ABCAbstractWriter::bounding_box() const +{ + return bounding_box_; +} + +void ABCAbstractWriter::update_bounding_box(Object *object) +{ + BoundBox *bb = BKE_object_boundbox_get(object); + + if (!bb) { + if (object->type != OB_CAMERA) { + CLOG_WARN(&LOG, "Bounding box is null!\n"); + } + bounding_box_.min.x = bounding_box_.min.y = bounding_box_.min.z = 0; + bounding_box_.max.x = bounding_box_.max.y = bounding_box_.max.z = 0; + return; + } + + /* Convert Z-up to Y-up. This also changes which vector goes into which min/max property. */ + bounding_box_.min.x = bb->vec[0][0]; + bounding_box_.min.y = bb->vec[0][2]; + bounding_box_.min.z = -bb->vec[6][1]; + + bounding_box_.max.x = bb->vec[6][0]; + bounding_box_.max.y = bb->vec[6][2]; + bounding_box_.max.z = -bb->vec[0][1]; +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.h b/source/blender/io/alembic/exporter/abc_writer_abstract.h new file mode 100644 index 00000000000..a83373a567a --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.h @@ -0,0 +1,77 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ +#pragma once + +#include "IO_abstract_hierarchy_iterator.h" +#include "abc_hierarchy_iterator.h" + +#include <Alembic/Abc/OObject.h> +#include <vector> + +#include "DEG_depsgraph_query.h" +#include "DNA_material_types.h" + +struct Material; +struct Object; + +namespace blender { +namespace io { +namespace alembic { + +class ABCAbstractWriter : public AbstractHierarchyWriter { + protected: + const ABCWriterConstructorArgs args_; + + bool frame_has_been_written_; + bool is_animated_; + uint32_t timesample_index_; + Imath::Box3d bounding_box_; + + public: + explicit ABCAbstractWriter(const ABCWriterConstructorArgs &args); + virtual ~ABCAbstractWriter(); + + virtual void write(HierarchyContext &context) override; + + /* Returns true if the data to be written is actually supported. This would, for example, allow a + * hypothetical camera writer accept a perspective camera but reject an orthogonal one. + * + * Returning false from a transform writer will prevent the object and all its descendants from + * being exported. Returning false from a data writer (object data, hair, or particles) will + * only prevent that data from being written (and thus cause the object to be exported as an + * Empty). */ + virtual bool is_supported(const HierarchyContext *context) const; + + const Imath::Box3d &bounding_box() const; + + /* Called by AlembicHierarchyCreator after checking that the data is supported via + * is_supported(). */ + virtual void create_alembic_objects(const HierarchyContext *context) = 0; + + virtual const Alembic::Abc::OObject get_alembic_object() const = 0; + + protected: + virtual void do_write(HierarchyContext &context) = 0; + + virtual void update_bounding_box(Object *object); +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_camera.cc b/source/blender/io/alembic/exporter/abc_writer_camera.cc new file mode 100644 index 00000000000..7e7277cb4ea --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_camera.cc @@ -0,0 +1,110 @@ +/* + * 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_hierarchy_iterator.h" + +#include "BKE_camera.h" + +#include "BLI_assert.h" + +#include "DNA_camera_types.h" +#include "DNA_scene_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::AbcGeom::CameraSample; +using Alembic::AbcGeom::OCamera; +using Alembic::AbcGeom::OFloatProperty; + +ABCCameraWriter::ABCCameraWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) +{ +} + +bool ABCCameraWriter::is_supported(const HierarchyContext *context) const +{ + Camera *camera = static_cast<Camera *>(context->object->data); + return camera->type == CAM_PERSP; +} + +void ABCCameraWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_camera_ = OCamera(args_.abc_parent, args_.abc_name, timesample_index_); + abc_camera_schema_ = abc_camera_.getSchema(); + + abc_custom_data_container_ = abc_camera_schema_.getUserProperties(); + abc_stereo_distance_ = OFloatProperty( + abc_custom_data_container_, "stereoDistance", timesample_index_); + abc_eye_separation_ = OFloatProperty( + abc_custom_data_container_, "eyeSeparation", timesample_index_); +} + +const Alembic::Abc::OObject ABCCameraWriter::get_alembic_object() const +{ + return abc_camera_; +} + +void ABCCameraWriter::do_write(HierarchyContext &context) +{ + Camera *cam = static_cast<Camera *>(context.object->data); + + abc_stereo_distance_.set(cam->stereo.convergence_distance); + abc_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; + + CameraSample camera_sample; + camera_sample.setFocalLength(cam->lens); + camera_sample.setHorizontalAperture(apperture_x); + camera_sample.setVerticalAperture(apperture_y); + camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx); + camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect); + camera_sample.setNearClippingPlane(cam->clip_start); + camera_sample.setFarClippingPlane(cam->clip_end); + + if (cam->dof.focus_object) { + Imath::V3f v(context.object->loc[0] - cam->dof.focus_object->loc[0], + context.object->loc[1] - cam->dof.focus_object->loc[1], + context.object->loc[2] - cam->dof.focus_object->loc[2]); + camera_sample.setFocusDistance(v.length()); + } + else { + camera_sample.setFocusDistance(cam->dof.focus_distance); + } + + /* Blender camera does not have an fstop param, so try to find a custom prop + * instead. */ + camera_sample.setFStop(cam->dof.aperture_fstop); + + camera_sample.setLensSqueezeRatio(1.0); + abc_camera_schema_.set(camera_sample); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_camera.h b/source/blender/io/alembic/exporter/abc_writer_camera.h new file mode 100644 index 00000000000..a72cfa2f357 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_camera.h @@ -0,0 +1,52 @@ +/* + * 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. + */ +#pragma once + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_abstract.h" + +#include <Alembic/AbcGeom/OCamera.h> + +namespace blender { +namespace io { +namespace alembic { + +class ABCCameraWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OCamera abc_camera_; + Alembic::AbcGeom::OCameraSchema abc_camera_schema_; + + Alembic::AbcGeom::OCompoundProperty abc_custom_data_container_; + Alembic::AbcGeom::OFloatProperty abc_stereo_distance_; + Alembic::AbcGeom::OFloatProperty abc_eye_separation_; + + public: + explicit ABCCameraWriter(const ABCWriterConstructorArgs &args); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; + + protected: + virtual bool is_supported(const HierarchyContext *context) const override; + virtual void do_write(HierarchyContext &context) override; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_curves.cc b/source/blender/io/alembic/exporter/abc_writer_curves.cc index db93ac1920e..f2a46c5e4fe 100644 --- a/source/blender/io/alembic/intern/abc_writer_curves.cc +++ b/source/blender/io/alembic/exporter/abc_writer_curves.cc @@ -22,9 +22,7 @@ */ #include "abc_writer_curves.h" -#include "abc_axis_conversion.h" -#include "abc_reader_curves.h" -#include "abc_writer_transform.h" +#include "intern/abc_axis_conversion.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -33,6 +31,9 @@ #include "BKE_mesh.h" #include "BKE_object.h" +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + using Alembic::AbcGeom::OCompoundProperty; using Alembic::AbcGeom::OCurves; using Alembic::AbcGeom::OCurvesSchema; @@ -40,24 +41,36 @@ 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) +namespace blender { +namespace io { +namespace alembic { + +const std::string ABC_CURVE_RESOLUTION_U_PROPNAME("blender:resolution"); + +ABCCurveWriter::ABCCurveWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) +{ +} + +void ABCCurveWriter::create_alembic_objects(const HierarchyContext *context) { - OCurves curves(parent->alembicXform(), m_name, m_time_sampling); - m_schema = curves.getSchema(); + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_curve_ = OCurves(args_.abc_parent, args_.abc_name, timesample_index_); + abc_curve_schema_ = abc_curve_.getSchema(); - Curve *cu = static_cast<Curve *>(m_object->data); - OCompoundProperty user_props = m_schema.getUserProperties(); + Curve *cu = static_cast<Curve *>(context->object->data); + OCompoundProperty user_props = abc_curve_schema_.getUserProperties(); OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME); user_prop_resolu.set(cu->resolu); } -void AbcCurveWriter::do_write() +const Alembic::Abc::OObject ABCCurveWriter::get_alembic_object() const { - Curve *curve = static_cast<Curve *>(m_object->data); + return abc_curve_; +} + +void ABCCurveWriter::do_write(HierarchyContext &context) +{ + Curve *curve = static_cast<Curve *>(context.object->data); std::vector<Imath::V3f> verts; std::vector<int32_t> vert_counts; @@ -148,35 +161,31 @@ void AbcCurveWriter::do_write() 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); + OCurvesSchema::Sample sample(verts, + vert_counts, + curve_type, + periodicity, + width_sample, + OV2fGeomParam::Sample(), /* UVs */ + ON3fGeomParam::Sample(), /* normals */ + curve_basis, + weights, + orders, + knots); + + update_bounding_box(context.object); + sample.setSelfBounds(bounding_box_); + abc_curve_schema_.set(sample); } -AbcCurveMeshWriter::AbcCurveMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings) +ABCCurveMeshWriter::ABCCurveMeshWriter(const ABCWriterConstructorArgs &args) + : ABCGenericMeshWriter(args) { } -Mesh *AbcCurveMeshWriter::getEvaluatedMesh(Scene * /*scene_eval*/, - Object *ob_eval, - bool &r_needsfree) +Mesh *ABCCurveMeshWriter::get_export_mesh(Object *object_eval, bool &r_needsfree) { - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object_eval); if (mesh_eval != NULL) { /* Mesh_eval only exists when generative modifiers are in use. */ r_needsfree = false; @@ -184,5 +193,9 @@ Mesh *AbcCurveMeshWriter::getEvaluatedMesh(Scene * /*scene_eval*/, } r_needsfree = true; - return BKE_mesh_new_nomain_from_curve(ob_eval); + return BKE_mesh_new_nomain_from_curve(object_eval); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_curves.h b/source/blender/io/alembic/exporter/abc_writer_curves.h index 83f0289dd2d..12a909761f5 100644 --- a/source/blender/io/alembic/intern/abc_writer_curves.h +++ b/source/blender/io/alembic/exporter/abc_writer_curves.h @@ -16,40 +16,46 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_CURVES_H__ -#define __ABC_WRITER_CURVES_H__ - +#include "abc_writer_abstract.h" #include "abc_writer_mesh.h" -#include "abc_writer_object.h" -class AbcCurveWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; +#include <Alembic/AbcGeom/OCurves.h> + +namespace blender { +namespace io { +namespace alembic { + +extern const std::string ABC_CURVE_RESOLUTION_U_PROPNAME; + +class ABCCurveWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OCurves abc_curve_; + Alembic::AbcGeom::OCurvesSchema abc_curve_schema_; public: - AbcCurveWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + explicit ABCCurveWriter(const ABCWriterConstructorArgs &args); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; protected: - void do_write(); + virtual void do_write(HierarchyContext &context) override; }; -class AbcCurveMeshWriter : public AbcGenericMeshWriter { +class ABCCurveMeshWriter : public ABCGenericMeshWriter { public: - AbcCurveMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + ABCCurveMeshWriter(const ABCWriterConstructorArgs &args); protected: - Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree); + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; }; -#endif /* __ABC_WRITER_CURVES_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index ed62889b03d..ac4deddd9b4 100644 --- a/source/blender/io/alembic/intern/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -19,8 +19,7 @@ */ #include "abc_writer_hair.h" -#include "abc_axis_conversion.h" -#include "abc_writer_transform.h" +#include "intern/abc_axis_conversion.h" #include <cstdio> @@ -35,35 +34,46 @@ #include "BKE_mesh_runtime.h" #include "BKE_particle.h" -using Alembic::Abc::P3fArraySamplePtr; +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; +using Alembic::Abc::P3fArraySamplePtr; using Alembic::AbcGeom::OCurves; using Alembic::AbcGeom::OCurvesSchema; using Alembic::AbcGeom::ON3fGeomParam; using Alembic::AbcGeom::OV2fGeomParam; -/* ************************************************************************** */ +namespace blender { +namespace io { +namespace alembic { -AbcHairWriter::AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys) - : AbcObjectWriter(ob, time_sampling, settings, parent), m_uv_warning_shown(false) +ABCHairWriter::ABCHairWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args), uv_warning_shown_(false) { - m_psys = psys; +} - OCurves curves(parent->alembicXform(), psys->name, m_time_sampling); - m_schema = curves.getSchema(); +void ABCHairWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_curves_ = OCurves(args_.abc_parent, args_.abc_name, timesample_index_); + abc_curves_schema_ = abc_curves_.getSchema(); } -void AbcHairWriter::do_write() +const Alembic::Abc::OObject ABCHairWriter::get_alembic_object() const { - if (!m_psys) { - return; - } - Mesh *mesh = mesh_get_eval_final( - m_settings.depsgraph, m_settings.scene, m_object, &CD_MASK_MESH); + return abc_curves_; +} + +bool ABCHairWriter::check_is_animated(const HierarchyContext & /*context*/) const +{ + /* We assume that hair particles are always animated. */ + return true; +} + +void ABCHairWriter::do_write(HierarchyContext &context) +{ + Scene *scene_eval = DEG_get_evaluated_scene(args_.depsgraph); + Mesh *mesh = mesh_get_eval_final(args_.depsgraph, scene_eval, context.object, &CD_MASK_MESH); BKE_mesh_tessface_ensure(mesh); std::vector<Imath::V3f> verts; @@ -71,44 +81,45 @@ void AbcHairWriter::do_write() std::vector<Imath::V2f> uv_values; std::vector<Imath::V3f> norm_values; - if (m_psys->pathcache) { - ParticleSettings *part = m_psys->part; - bool export_children = m_settings.export_child_hairs && m_psys->childcache && - part->childtype != 0; + ParticleSystem *psys = context.particle_system; + if (psys->pathcache) { + ParticleSettings *part = psys->part; + bool export_children = psys->childcache && part->childtype != 0; if (!export_children || part->draw & PART_DRAW_PARENT) { - write_hair_sample(mesh, part, verts, norm_values, uv_values, hvertices); + write_hair_sample(context, mesh, verts, norm_values, uv_values, hvertices); } if (export_children) { - write_hair_child_sample(mesh, part, verts, norm_values, uv_values, hvertices); + write_hair_child_sample(context, mesh, verts, norm_values, uv_values, hvertices); } } Alembic::Abc::P3fArraySample iPos(verts); - m_sample = OCurvesSchema::Sample(iPos, hvertices); - m_sample.setBasis(Alembic::AbcGeom::kNoBasis); - m_sample.setType(Alembic::AbcGeom::kLinear); - m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic); + OCurvesSchema::Sample sample(iPos, hvertices); + sample.setBasis(Alembic::AbcGeom::kNoBasis); + sample.setType(Alembic::AbcGeom::kLinear); + sample.setWrap(Alembic::AbcGeom::kNonPeriodic); if (!uv_values.empty()) { OV2fGeomParam::Sample uv_smp; uv_smp.setVals(uv_values); - m_sample.setUVs(uv_smp); + sample.setUVs(uv_smp); } if (!norm_values.empty()) { ON3fGeomParam::Sample norm_smp; norm_smp.setVals(norm_values); - m_sample.setNormals(norm_smp); + sample.setNormals(norm_smp); } - m_sample.setSelfBounds(bounds()); - m_schema.set(m_sample); + update_bounding_box(context.object); + sample.setSelfBounds(bounding_box_); + abc_curves_schema_.set(sample); } -void AbcHairWriter::write_hair_sample(Mesh *mesh, - ParticleSettings *part, +void ABCHairWriter::write_hair_sample(const HierarchyContext &context, + Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, @@ -116,28 +127,30 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, m_object->obmat); + invert_m4_m4_safe(inv_mat, context.object->obmat); MTFace *mtface = mesh->mtface; MFace *mface = mesh->mface; MVert *mverts = mesh->mvert; - if ((!mtface || !mface) && !m_uv_warning_shown) { + if ((!mtface || !mface) && !uv_warning_shown_) { std::fprintf(stderr, "Warning, no UV set found for underlying geometry of %s.\n", - m_object->id.name + 2); - m_uv_warning_shown = true; + context.object->id.name + 2); + uv_warning_shown_ = true; } - ParticleData *pa = m_psys->particles; + ParticleSystem *psys = context.particle_system; + ParticleSettings *part = psys->part; + ParticleData *pa = psys->particles; int k; - ParticleCacheKey **cache = m_psys->pathcache; + ParticleCacheKey **cache = psys->pathcache; ParticleCacheKey *path; float normal[3]; Imath::V3f tmp_nor; - for (int p = 0; p < m_psys->totpart; p++, pa++) { + for (int p = 0; p < psys->totpart; p++, pa++) { /* underlying info for faces-only emission */ path = cache[p]; @@ -219,8 +232,8 @@ void AbcHairWriter::write_hair_sample(Mesh *mesh, } } -void AbcHairWriter::write_hair_child_sample(Mesh *mesh, - ParticleSettings *part, +void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context, + Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, @@ -228,26 +241,30 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh, { /* Get untransformed vertices, there's a xform under the hair. */ float inv_mat[4][4]; - invert_m4_m4_safe(inv_mat, m_object->obmat); + invert_m4_m4_safe(inv_mat, context.object->obmat); MTFace *mtface = mesh->mtface; MVert *mverts = mesh->mvert; - ParticleCacheKey **cache = m_psys->childcache; + ParticleSystem *psys = context.particle_system; + ParticleSettings *part = psys->part; + ParticleCacheKey **cache = psys->childcache; ParticleCacheKey *path; - ChildParticle *pc = m_psys->child; + ChildParticle *pc = psys->child; - for (int p = 0; p < m_psys->totchild; p++, pc++) { + for (int p = 0; p < psys->totchild; p++, pc++) { path = cache[p]; if (part->from == PART_FROM_FACE && part->childtype != PART_CHILD_PARTICLES && mtface) { const int num = pc->num; if (num < 0) { - ABC_LOG(m_settings.logger) - << "Warning, child particle of hair system " << m_psys->name - << " has unknown face index of geometry of " << (m_object->id.name + 2) - << ", skipping child hair." << std::endl; + CLOG_WARN( + &LOG, + "Child particle of hair system %s has unknown face index of geometry of %s, skipping " + "child hair.", + psys->name, + context.object->id.name + 2); continue; } @@ -288,3 +305,7 @@ void AbcHairWriter::write_hair_child_sample(Mesh *mesh, } } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_hair.h b/source/blender/io/alembic/exporter/abc_writer_hair.h index 67d1b7b3d23..af1372a08f3 100644 --- a/source/blender/io/alembic/intern/abc_writer_hair.h +++ b/source/blender/io/alembic/exporter/abc_writer_hair.h @@ -13,50 +13,56 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_HAIR_H__ -#define __ABC_WRITER_HAIR_H__ - -#include "abc_writer_object.h" +#include "abc_writer_abstract.h" +#include <Alembic/AbcGeom/OCurves.h> +#include <vector> struct ParticleSettings; struct ParticleSystem; -class AbcHairWriter : public AbcObjectWriter { - ParticleSystem *m_psys; +namespace blender { +namespace io { +namespace alembic { - Alembic::AbcGeom::OCurvesSchema m_schema; - Alembic::AbcGeom::OCurvesSchema::Sample m_sample; +class ABCHairWriter : public ABCAbstractWriter { + private: + Alembic::AbcGeom::OCurves abc_curves_; + Alembic::AbcGeom::OCurvesSchema abc_curves_schema_; - bool m_uv_warning_shown; + bool uv_warning_shown_; public: - AbcHairWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings, - ParticleSystem *psys); + explicit ABCHairWriter(const ABCWriterConstructorArgs &args); - private: - virtual void do_write(); + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; - void write_hair_sample(struct Mesh *mesh, - ParticleSettings *part, + protected: + virtual void do_write(HierarchyContext &context) override; + virtual bool check_is_animated(const HierarchyContext &context) const override; + + private: + void write_hair_sample(const HierarchyContext &context, + struct Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices); - void write_hair_child_sample(struct Mesh *mesh, - ParticleSettings *part, + void write_hair_child_sample(const HierarchyContext &context, + struct Mesh *mesh, std::vector<Imath::V3f> &verts, std::vector<Imath::V3f> &norm_values, std::vector<Imath::V2f> &uv_values, std::vector<int32_t> &hvertices); }; -#endif /* __ABC_WRITER_HAIR_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_mball.cc b/source/blender/io/alembic/exporter/abc_writer_mball.cc new file mode 100644 index 00000000000..167e392eb96 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_mball.cc @@ -0,0 +1,90 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_mball.h" +#include "abc_hierarchy_iterator.h" + +#include "BLI_assert.h" + +#include "BKE_displist.h" +#include "BKE_lib_id.h" +#include "BKE_mball.h" +#include "BKE_mesh.h" +#include "BKE_object.h" + +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" + +namespace blender { +namespace io { +namespace alembic { + +ABCMetaballWriter::ABCMetaballWriter(const ABCWriterConstructorArgs &args) + : ABCGenericMeshWriter(args) +{ +} + +bool ABCMetaballWriter::is_supported(const HierarchyContext *context) const +{ + Scene *scene = DEG_get_input_scene(args_.depsgraph); + bool supported = is_basis_ball(scene, context->object) && + ABCGenericMeshWriter::is_supported(context); + return supported; +} + +bool ABCMetaballWriter::check_is_animated(const HierarchyContext & /*context*/) const +{ + /* We assume that metaballs are always animated, as the current object may + * not be animated but another ball in the same group may be. */ + return true; +} + +bool ABCMetaballWriter::export_as_subdivision_surface(Object * /*ob_eval*/) const +{ + /* Metaballs should be exported to subdivision surfaces, if the export options allow. */ + return true; +} + +Mesh *ABCMetaballWriter::get_export_mesh(Object *object_eval, bool &r_needsfree) +{ + Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object_eval); + if (mesh_eval != nullptr) { + /* Mesh_eval only exists when generative modifiers are in use. */ + r_needsfree = false; + return mesh_eval; + } + r_needsfree = true; + return BKE_mesh_new_from_object(args_.depsgraph, object_eval, false); +} + +void ABCMetaballWriter::free_export_mesh(Mesh *mesh) +{ + BKE_id_free(nullptr, mesh); +} + +bool ABCMetaballWriter::is_basis_ball(Scene *scene, Object *ob) const +{ + Object *basis_ob = BKE_mball_basis_find(scene, ob); + return ob == basis_ob; +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_camera.h b/source/blender/io/alembic/exporter/abc_writer_mball.h index 3b515911a48..90d8c4d4b15 100644 --- a/source/blender/io/alembic/intern/abc_writer_camera.h +++ b/source/blender/io/alembic/exporter/abc_writer_mball.h @@ -13,33 +13,33 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_CAMERA_H__ -#define __ABC_WRITER_CAMERA_H__ +#include "abc_writer_mesh.h" -#include "abc_writer_object.h" - -/* ************************************************************************** */ - -class AbcCameraWriter : public AbcObjectWriter { - Alembic::AbcGeom::OCameraSchema m_camera_schema; - Alembic::AbcGeom::CameraSample m_camera_sample; - Alembic::AbcGeom::OCompoundProperty m_custom_data_container; - Alembic::AbcGeom::OFloatProperty m_stereo_distance; - Alembic::AbcGeom::OFloatProperty m_eye_separation; +namespace blender { +namespace io { +namespace alembic { +class ABCMetaballWriter : public ABCGenericMeshWriter { public: - AbcCameraWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); + explicit ABCMetaballWriter(const ABCWriterConstructorArgs &args); + + protected: + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; + virtual void free_export_mesh(Mesh *mesh) override; + virtual bool is_supported(const HierarchyContext *context) const override; + virtual bool check_is_animated(const HierarchyContext &context) const override; + virtual bool export_as_subdivision_surface(Object *ob_eval) const override; private: - virtual void do_write(); + bool is_basis_ball(Scene *scene, Object *ob) const; }; -#endif /* __ABC_WRITER_CAMERA_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index df1734c9de1..07196f2b81f 100644 --- a/source/blender/io/alembic/intern/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -19,29 +19,37 @@ */ #include "abc_writer_mesh.h" -#include "abc_axis_conversion.h" -#include "abc_writer_transform.h" +#include "abc_hierarchy_iterator.h" +#include "intern/abc_axis_conversion.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim_types.h" +#include "BLI_assert.h" +#include "BLI_math_vector.h" -#include "BKE_anim_data.h" -#include "BKE_key.h" +#include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "bmesh.h" #include "bmesh_tools.h" -#include "DEG_depsgraph_query.h" +#include "DEG_depsgraph.h" + +#include "DNA_layer_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_particle_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; using Alembic::Abc::FloatArraySample; using Alembic::Abc::Int32ArraySample; +using Alembic::Abc::OObject; using Alembic::Abc::V2fArraySample; using Alembic::Abc::V3fArraySample; @@ -58,138 +66,83 @@ 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); +namespace blender { +namespace io { +namespace alembic { - MVert *verts = mesh->mvert; - - for (int i = 0, e = mesh->totvert; i < e; i++) { - copy_yup_from_zup(points[i].getValue(), verts[i].co); - } -} +/* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ +static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points); 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); - } - } -} - + bool &r_has_flat_shaded_poly); 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; + std::vector<float> &sharpnesses); +static void get_loop_normals(struct Mesh *mesh, + std::vector<Imath::V3f> &normals, + bool has_flat_shaded_poly); - indices.clear(); - lengths.clear(); - sharpnesses.clear(); +ABCGenericMeshWriter::ABCGenericMeshWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args), is_subd_(false) +{ +} - MEdge *edge = mesh->medge; +void ABCGenericMeshWriter::create_alembic_objects(const HierarchyContext *context) +{ + if (!args_.export_params->apply_subdiv && export_as_subdivision_surface(context->object)) { + is_subd_ = args_.export_params->use_subdiv_schema; + } - for (int i = 0, e = mesh->totedge; i < e; i++) { - const float sharpness = static_cast<float>(edge[i].crease) * factor; + if (is_subd_) { + CLOG_INFO(&LOG, 2, "exporting OSubD %s", args_.abc_path.c_str()); + abc_subdiv_ = OSubD(args_.abc_parent, args_.abc_name, timesample_index_); + abc_subdiv_schema_ = abc_subdiv_.getSchema(); + } + else { + CLOG_INFO(&LOG, 2, "exporting OPolyMesh %s", args_.abc_path.c_str()); + abc_poly_mesh_ = OPolyMesh(args_.abc_parent, args_.abc_name, timesample_index_); + abc_poly_mesh_schema_ = abc_poly_mesh_.getSchema(); - if (sharpness != 0.0f) { - indices.push_back(edge[i].v1); - indices.push_back(edge[i].v2); - sharpnesses.push_back(sharpness); - } + OCompoundProperty typeContainer = abc_poly_mesh_.getSchema().getUserProperties(); + OBoolProperty type(typeContainer, "meshtype"); + type.set(subsurf_modifier_ == nullptr); } - lengths.resize(sharpnesses.size(), 2); + Scene *scene_eval = DEG_get_evaluated_scene(args_.depsgraph); + liquid_sim_modifier_ = get_liquid_sim_modifier(scene_eval, context->object); } -static void get_loop_normals(struct Mesh *mesh, - std::vector<Imath::V3f> &normals, - bool has_flat_shaded_poly) +ABCGenericMeshWriter::~ABCGenericMeshWriter() { - 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) && - (mesh->flag & ME_AUTOSMOOTH) == 0) { - 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]); - } +const Alembic::Abc::OObject ABCGenericMeshWriter::get_alembic_object() const +{ + if (is_subd_) { + return abc_subdiv_; } + return abc_poly_mesh_; } -/* *************** 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) +bool ABCGenericMeshWriter::export_as_subdivision_surface(Object *ob_eval) const { - ModifierData *md = static_cast<ModifierData *>(ob->modifiers.last); + ModifierData *md = static_cast<ModifierData *>(ob_eval->modifiers.last); for (; md; md = md->prev) { - if (!BKE_modifier_is_enabled(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; + /* This modifier has been temporarily disabled by SubdivModifierDisabler, + * so this indicates this is to be exported as subdivision surface. */ + if (md->type == eModifierType_Subsurf && (md->mode & eModifierMode_DisableTemporary)) { + return true; } } - return NULL; + return false; } -static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) +ModifierData *ABCGenericMeshWriter::get_liquid_sim_modifier(Scene *scene, Object *ob) { ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluidsim); @@ -201,122 +154,99 @@ static ModifierData *get_liquid_sim_modifier(Scene *scene, Object *ob) } } - return NULL; + return nullptr; } -/* ************************************************************************** */ - -AbcGenericMeshWriter::AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent) +bool ABCGenericMeshWriter::is_supported(const HierarchyContext *context) const { - 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; - } + Object *object = context->object; + bool is_dupli = context->duplicator != nullptr; + int base_flag; - if (!m_settings.apply_subdiv) { - m_subsurf_mod = get_subsurf_modifier(m_settings.scene, m_object); - m_is_subd = (m_subsurf_mod != NULL); + if (is_dupli) { + /* Construct the object's base flags from its dupli-parent, just like is done in + * deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing + * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents + * copying the Object for every dupli. */ + base_flag = object->base_flag; + object->base_flag = context->duplicator->base_flag | BASE_FROM_DUPLI; } - m_is_liquid = (get_liquid_sim_modifier(m_settings.scene, m_object) != NULL); + int visibility = BKE_object_visibility( + object, DAG_EVAL_RENDER /* TODO(Sybren): add evaluation mode to export options? */); - while (parent->alembicXform().getChildHeader(m_name)) { - m_name.append("_"); + if (is_dupli) { + object->base_flag = base_flag; } - 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); - } + return (visibility & OB_VISIBLE_SELF) != 0; } -AbcGenericMeshWriter::~AbcGenericMeshWriter() +void ABCGenericMeshWriter::do_write(HierarchyContext &context) { - if (m_subsurf_mod) { - m_subsurf_mod->mode &= ~eModifierMode_DisableTemporary; - } -} + Object *object = context.object; + bool needsfree = false; -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; - } + Mesh *mesh = get_export_mesh(object, needsfree); - /* Test modifiers. */ - ModifierData *md = static_cast<ModifierData *>(m_object->modifiers.first); - while (md) { + if (mesh == nullptr) { + return; + } - if (md->type != eModifierType_Subsurf) { - return true; - } + if (args_.export_params->triangulate) { + const bool tag_only = false; + const int quad_method = args_.export_params->quad_method; + const int ngon_method = args_.export_params->ngon_method; - md = md->next; - } + struct BMeshCreateParams bmcp = {false}; + struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); - return false; -} + BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr); -void AbcGenericMeshWriter::setIsAnimated(bool is_animated) -{ - m_is_animated = is_animated; -} + Mesh *triangulated_mesh = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); + BM_mesh_free(bm); -void AbcGenericMeshWriter::do_write() -{ - /* We have already stored a sample for this object. */ - if (!m_first_frame && !m_is_animated) { - return; + if (needsfree) { + free_export_mesh(mesh); + } + mesh = triangulated_mesh; + needsfree = true; } - bool needsfree; - struct Mesh *mesh = getFinalMesh(needsfree); + m_custom_data_config.pack_uvs = args_.export_params->packuv; + 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; try { - if (m_settings.use_subdiv_schema && m_subdiv_schema.valid()) { - writeSubD(mesh); + if (is_subd_) { + write_subd(context, mesh); } else { - writeMesh(mesh); + write_mesh(context, mesh); } if (needsfree) { - freeEvaluatedMesh(mesh); + free_export_mesh(mesh); } } catch (...) { if (needsfree) { - freeEvaluatedMesh(mesh); + free_export_mesh(mesh); } throw; } } -void AbcGenericMeshWriter::freeEvaluatedMesh(struct Mesh *mesh) +void ABCGenericMeshWriter::free_export_mesh(Mesh *mesh) { - BKE_id_free(NULL, mesh); + BKE_id_free(nullptr, mesh); } -void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) +void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh) { std::vector<Imath::V3f> points, normals; std::vector<int32_t> poly_verts, loop_counts; @@ -326,32 +256,33 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) 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); + if (!frame_has_been_written_ && args_.export_params->face_sets) { + write_face_sets(context.object, mesh, abc_poly_mesh_schema_); } - m_mesh_sample = OPolyMeshSchema::Sample( + OPolyMeshSchema::Sample mesh_sample = OPolyMeshSchema::Sample( V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); - UVSample sample; - if (m_settings.export_uvs) { - const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); + UVSample uvs_and_indices; - if (!sample.indices.empty() && !sample.uvs.empty()) { + if (!frame_has_been_written_ && args_.export_params->uvs) { + const char *name = get_uv_sample(uvs_and_indices, m_custom_data_config, &mesh->ldata); + + if (!uvs_and_indices.indices.empty() && !uvs_and_indices.uvs.empty()) { OV2fGeomParam::Sample uv_sample; - uv_sample.setVals(V2fArraySample(sample.uvs)); - uv_sample.setIndices(UInt32ArraySample(sample.indices)); + uv_sample.setVals(V2fArraySample(uvs_and_indices.uvs)); + uv_sample.setIndices(UInt32ArraySample(uvs_and_indices.indices)); uv_sample.setScope(kFacevaryingScope); - m_mesh_schema.setUVSourceName(name); - m_mesh_sample.setUVs(uv_sample); + abc_poly_mesh_schema_.setUVSourceName(name); + mesh_sample.setUVs(uv_sample); } write_custom_data( - m_mesh_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + abc_poly_mesh_schema_.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); } - if (m_settings.export_normals) { + if (args_.export_params->normals) { get_loop_normals(mesh, normals, has_flat_shaded_poly); ON3fGeomParam::Sample normals_sample; @@ -360,22 +291,23 @@ void AbcGenericMeshWriter::writeMesh(struct Mesh *mesh) normals_sample.setVals(V3fArraySample(normals)); } - m_mesh_sample.setNormals(normals_sample); + mesh_sample.setNormals(normals_sample); } - if (m_is_liquid) { - getVelocities(mesh, velocities); - m_mesh_sample.setVelocities(V3fArraySample(velocities)); + if (liquid_sim_modifier_ != nullptr) { + get_velocities(mesh, velocities); + mesh_sample.setVelocities(V3fArraySample(velocities)); } - m_mesh_sample.setSelfBounds(bounds()); + update_bounding_box(context.object); + mesh_sample.setSelfBounds(bounding_box_); - m_mesh_schema.set(m_mesh_sample); + abc_poly_mesh_schema_.set(mesh_sample); - writeArbGeoParams(mesh); + write_arb_geo_params(mesh); } -void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) +void ABCGenericMeshWriter::write_subd(HierarchyContext &context, struct Mesh *mesh) { std::vector<float> crease_sharpness; std::vector<Imath::V3f> points; @@ -387,15 +319,15 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) 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); + if (!frame_has_been_written_ && args_.export_params->face_sets) { + write_face_sets(context.object, mesh, abc_subdiv_schema_); } - m_subdiv_sample = OSubDSchema::Sample( + OSubDSchema::Sample subdiv_sample = OSubDSchema::Sample( V3fArraySample(points), Int32ArraySample(poly_verts), Int32ArraySample(loop_counts)); UVSample sample; - if (m_first_frame && m_settings.export_uvs) { + if (!frame_has_been_written_ && args_.export_params->uvs) { const char *name = get_uv_sample(sample, m_custom_data_config, &mesh->ldata); if (!sample.indices.empty() && !sample.uvs.empty()) { @@ -404,30 +336,32 @@ void AbcGenericMeshWriter::writeSubD(struct Mesh *mesh) uv_sample.setIndices(UInt32ArraySample(sample.indices)); uv_sample.setScope(kFacevaryingScope); - m_subdiv_schema.setUVSourceName(name); - m_subdiv_sample.setUVs(uv_sample); + abc_subdiv_schema_.setUVSourceName(name); + subdiv_sample.setUVs(uv_sample); } write_custom_data( - m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &mesh->ldata, CD_MLOOPUV); + abc_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)); + subdiv_sample.setCreaseIndices(Int32ArraySample(crease_indices)); + subdiv_sample.setCreaseLengths(Int32ArraySample(crease_lengths)); + subdiv_sample.setCreaseSharpnesses(FloatArraySample(crease_sharpness)); } - m_subdiv_sample.setSelfBounds(bounds()); - m_subdiv_schema.set(m_subdiv_sample); + update_bounding_box(context.object); + subdiv_sample.setSelfBounds(bounding_box_); + abc_subdiv_schema_.set(subdiv_sample); - writeArbGeoParams(mesh); + write_arb_geo_params(mesh); } -template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh *me, Schema &schema) +template<typename Schema> +void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Schema &schema) { std::map<std::string, std::vector<int32_t>> geo_groups; - getGeoGroups(me, geo_groups); + get_geo_groups(object, mesh, geo_groups); std::map<std::string, std::vector<int32_t>>::iterator it; for (it = geo_groups.begin(); it != geo_groups.end(); ++it) { @@ -438,83 +372,35 @@ template<typename Schema> void AbcGenericMeshWriter::writeFaceSets(struct Mesh * } } -Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree) +void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me) { - /* 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; + if (liquid_sim_modifier_ != nullptr) { + /* We don't need anything more for liquid meshes. */ + return; } - 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. */ + if (frame_has_been_written_ || !args_.export_params->vcolors) { 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); - } + OCompoundProperty arb_geom_params; + if (is_subd_) { + arb_geom_params = abc_subdiv_.getSchema().getArbGeomParams(); } + else { + arb_geom_params = abc_poly_mesh_.getSchema().getArbGeomParams(); + } + write_custom_data(arb_geom_params, m_custom_data_config, &me->ldata, CD_MLOOPCOL); } -void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels) +void ABCGenericMeshWriter::get_velocities(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); + FluidsimModifierData *fmd = reinterpret_cast<FluidsimModifierData *>(liquid_sim_modifier_); FluidsimSettings *fss = fmd->fss; if (fss->meshVelocities) { @@ -530,8 +416,9 @@ void AbcGenericMeshWriter::getVelocities(struct Mesh *mesh, std::vector<Imath::V } } -void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, - std::map<std::string, std::vector<int32_t>> &geo_groups) +void ABCGenericMeshWriter::get_geo_groups(Object *object, + struct Mesh *mesh, + std::map<std::string, std::vector<int32_t>> &geo_groups) { const int num_poly = mesh->totpoly; MPoly *polygons = mesh->mpoly; @@ -540,13 +427,13 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, MPoly ¤t_poly = polygons[i]; short mnr = current_poly.mat_nr; - Material *mat = BKE_object_material_get(m_object, mnr + 1); + Material *mat = BKE_object_material_get(object, mnr + 1); if (!mat) { continue; } - std::string name = get_id_name(&mat->id); + std::string name = args_.hierarchy_iterator->get_id_name(&mat->id); if (geo_groups.find(name) == geo_groups.end()) { std::vector<int32_t> faceArray; @@ -557,9 +444,9 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, } if (geo_groups.size() == 0) { - Material *mat = BKE_object_material_get(m_object, 1); + Material *mat = BKE_object_material_get(object, 1); - std::string name = (mat) ? get_id_name(&mat->id) : "default"; + std::string name = (mat) ? args_.hierarchy_iterator->get_id_name(&mat->id) : "default"; std::vector<int32_t> faceArray; @@ -571,21 +458,116 @@ void AbcGenericMeshWriter::getGeoGroups(struct Mesh *mesh, } } -AbcMeshWriter::AbcMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings) +/* 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); + } } -AbcMeshWriter::~AbcMeshWriter() +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); } -Mesh *AbcMeshWriter::getEvaluatedMesh(Scene *scene_eval, - Object *ob_eval, - bool &UNUSED(r_needsfree)) +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) && + (mesh->flag & ME_AUTOSMOOTH) == 0) { + 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 != nullptr || !"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]); + } + } +} + +ABCMeshWriter::ABCMeshWriter(const ABCWriterConstructorArgs &args) : ABCGenericMeshWriter(args) { - return mesh_get_eval_final(m_settings.depsgraph, scene_eval, ob_eval, &CD_MASK_MESH); } + +Mesh *ABCMeshWriter::get_export_mesh(Object *object_eval, bool & /*r_needsfree*/) +{ + return BKE_object_get_evaluated_mesh(object_eval); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.h b/source/blender/io/alembic/exporter/abc_writer_mesh.h new file mode 100644 index 00000000000..bf4d4e9b9d8 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.h @@ -0,0 +1,95 @@ +/* + * 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. + */ +#pragma once + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_abstract.h" +#include "intern/abc_customdata.h" + +#include <Alembic/AbcGeom/OPolyMesh.h> +#include <Alembic/AbcGeom/OSubD.h> + +struct ModifierData; + +namespace blender { +namespace io { +namespace alembic { + +/* Writer for Alembic geometry. Does not assume the object is a mesh object. */ +class ABCGenericMeshWriter : public ABCAbstractWriter { + private: + /* Either polymesh or subd is used, depending on is_subd_. + * References to the schema must be kept, or Alembic will not properly write. */ + Alembic::AbcGeom::OPolyMesh abc_poly_mesh_; + Alembic::AbcGeom::OPolyMeshSchema abc_poly_mesh_schema_; + + Alembic::AbcGeom::OSubD abc_subdiv_; + Alembic::AbcGeom::OSubDSchema abc_subdiv_schema_; + + /* Determines whether a poly mesh or a subdivision surface is exported. + * The value is set by an export option but only true if there is a subdivision modifier on the + * exported object. */ + bool is_subd_; + ModifierData *subsurf_modifier_; + ModifierData *liquid_sim_modifier_; + + CDStreamConfig m_custom_data_config; + + public: + explicit ABCGenericMeshWriter(const ABCWriterConstructorArgs &args); + virtual ~ABCGenericMeshWriter(); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const; + + protected: + virtual bool is_supported(const HierarchyContext *context) const override; + virtual void do_write(HierarchyContext &context) override; + + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) = 0; + virtual void free_export_mesh(Mesh *mesh); + + virtual bool export_as_subdivision_surface(Object *ob_eval) const; + + private: + void write_mesh(HierarchyContext &context, Mesh *mesh); + void write_subd(HierarchyContext &context, Mesh *mesh); + template<typename Schema> void write_face_sets(Object *object, Mesh *mesh, Schema &schema); + + ModifierData *get_liquid_sim_modifier(Scene *scene_eval, Object *ob_eval); + + void write_arb_geo_params(Mesh *me); + void get_velocities(Mesh *mesh, std::vector<Imath::V3f> &vels); + void get_geo_groups(Object *object, + Mesh *mesh, + std::map<std::string, std::vector<int32_t>> &geo_groups); +}; + +/* Writer for Alembic geometry of Blender Mesh objects. */ +class ABCMeshWriter : public ABCGenericMeshWriter { + public: + ABCMeshWriter(const ABCWriterConstructorArgs &args); + + protected: + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_nurbs.cc b/source/blender/io/alembic/exporter/abc_writer_nurbs.cc index 8b4a1050d33..1fd382214a6 100644 --- a/source/blender/io/alembic/intern/abc_writer_nurbs.cc +++ b/source/blender/io/alembic/exporter/abc_writer_nurbs.cc @@ -19,8 +19,7 @@ */ #include "abc_writer_nurbs.h" -#include "abc_axis_conversion.h" -#include "abc_writer_transform.h" +#include "intern/abc_axis_conversion.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" @@ -29,48 +28,70 @@ #include "BKE_curve.h" +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::OObject; 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) +ABCNurbsWriter::ABCNurbsWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) { - 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); +void ABCNurbsWriter::create_alembic_objects(const HierarchyContext *context) +{ + Curve *curve = static_cast<Curve *>(context->object->data); + size_t num_nurbs = BLI_listbase_count(&curve->nurb); + OObject abc_parent = args_.abc_parent; + const char *abc_parent_path = abc_parent.getFullName().c_str(); - for (size_t i = 0; i < numNurbs; i++) { - std::stringstream str; - str << m_name << '_' << i; + for (size_t i = 0; i < num_nurbs; i++) { + std::stringstream patch_name_stream; + patch_name_stream << args_.abc_name << '_' << i; - while (parent->alembicXform().getChildHeader(str.str())) { - str << "_"; + while (abc_parent.getChildHeader(patch_name_stream.str())) { + patch_name_stream << "_"; } - ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling); - m_nurbs_schema.push_back(nurbs.getSchema()); + std::string patch_name = patch_name_stream.str(); + CLOG_INFO(&LOG, 2, "exporting %s/%s", abc_parent_path, patch_name.c_str()); + + ONuPatch nurbs(abc_parent, patch_name.c_str(), timesample_index_); + abc_nurbs_.push_back(nurbs); + abc_nurbs_schemas_.push_back(nurbs.getSchema()); + } +} + +const OObject ABCNurbsWriter::get_alembic_object() const +{ + if (abc_nurbs_.empty()) { + return OObject(); } + /* For parenting purposes within the Alembic file, all NURBS patches are equal, so just use the + * first one. */ + return abc_nurbs_[0]; } -bool AbcNurbsWriter::isAnimated() const +bool ABCNurbsWriter::check_is_animated(const HierarchyContext &context) const { - /* check if object has shape keys */ - Curve *cu = static_cast<Curve *>(m_object->data); + /* Check if object has shape keys. */ + Curve *cu = static_cast<Curve *>(context.object->data); return (cu->key != NULL); } +bool ABCNurbsWriter::is_supported(const HierarchyContext *context) const +{ + return ELEM(context->object->type, OB_SURF, OB_CURVE); +} + static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots) { if (num_knots <= 1) { @@ -91,22 +112,13 @@ static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_ knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]); } -void AbcNurbsWriter::do_write() +void ABCNurbsWriter::do_write(HierarchyContext &context) { - /* 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); + Curve *curve = static_cast<Curve *>(context.object->data); ListBase *nulb; - if (m_object->runtime.curve_cache->deformed_nurbs.first != NULL) { - nulb = &m_object->runtime.curve_cache->deformed_nurbs; + if (context.object->runtime.curve_cache->deformed_nurbs.first != NULL) { + nulb = &context.object->runtime.curve_cache->deformed_nurbs; } else { nulb = BKE_curve_nurbs_get(curve); @@ -143,7 +155,7 @@ void AbcNurbsWriter::do_write() /* 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(); + OCompoundProperty user_props = abc_nurbs_schemas_[count].getUserProperties(); if ((nu->flagu & CU_NURB_ENDPOINT) != 0) { OBoolProperty prop(user_props, "endpoint_u"); @@ -165,6 +177,10 @@ void AbcNurbsWriter::do_write() prop.set(true); } - m_nurbs_schema[count].set(sample); + abc_nurbs_schemas_[count].set(sample); } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_nurbs.h b/source/blender/io/alembic/exporter/abc_writer_nurbs.h new file mode 100644 index 00000000000..23af4c40556 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_nurbs.h @@ -0,0 +1,57 @@ +/* + * 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. + */ +#pragma once + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_abstract.h" +#include "abc_writer_mesh.h" +#include <vector> + +namespace blender { +namespace io { +namespace alembic { + +class ABCNurbsWriter : public ABCAbstractWriter { + private: + std::vector<Alembic::AbcGeom::ONuPatch> abc_nurbs_; + std::vector<Alembic::AbcGeom::ONuPatchSchema> abc_nurbs_schemas_; + + public: + explicit ABCNurbsWriter(const ABCWriterConstructorArgs &args); + + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; + + protected: + virtual bool is_supported(const HierarchyContext *context) const override; + virtual void do_write(HierarchyContext &context) override; + virtual bool check_is_animated(const HierarchyContext &context) const override; +}; + +class ABCNurbsMeshWriter : public ABCGenericMeshWriter { + public: + explicit ABCNurbsMeshWriter(const ABCWriterConstructorArgs &args); + + protected: + virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; +}; + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_points.cc b/source/blender/io/alembic/exporter/abc_writer_points.cc new file mode 100644 index 00000000000..19870e39a90 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_points.cc @@ -0,0 +1,148 @@ +/* + * 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 "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" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::AbcGeom::kVertexScope; +using Alembic::AbcGeom::OPoints; +using Alembic::AbcGeom::OPointsSchema; + +ABCPointsWriter::ABCPointsWriter(const ABCWriterConstructorArgs &args) : ABCAbstractWriter(args) +{ +} + +void ABCPointsWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting OPoints %s", args_.abc_path.c_str()); + abc_points_ = OPoints(args_.abc_parent, args_.abc_name, timesample_index_); + abc_points_schema_ = abc_points_.getSchema(); +} + +const Alembic::Abc::OObject ABCPointsWriter::get_alembic_object() const +{ + return abc_points_; +} + +bool ABCPointsWriter::is_supported(const HierarchyContext *context) const +{ + return ELEM(context->particle_system->part->type, + PART_EMITTER, + PART_FLUID_FLIP, + PART_FLUID_SPRAY, + PART_FLUID_BUBBLE, + PART_FLUID_FOAM, + PART_FLUID_TRACER, + PART_FLUID_SPRAYFOAM, + PART_FLUID_SPRAYBUBBLE, + PART_FLUID_FOAMBUBBLE, + PART_FLUID_SPRAYFOAMBUBBLE); +} + +bool ABCPointsWriter::check_is_animated(const HierarchyContext & /*context*/) const +{ + /* We assume that particles are always animated. */ + return true; +} + +void ABCPointsWriter::do_write(HierarchyContext &context) +{ + BLI_assert(context.particle_system != nullptr); + + std::vector<Imath::V3f> points; + std::vector<Imath::V3f> velocities; + std::vector<float> widths; + std::vector<uint64_t> ids; + + ParticleSystem *psys = context.particle_system; + ParticleKey state; + ParticleSimulationData sim; + sim.depsgraph = args_.depsgraph; + sim.scene = DEG_get_evaluated_scene(args_.depsgraph); + sim.ob = context.object; + sim.psys = psys; + + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + uint64_t index = 0; + for (int p = 0; p < psys->totpart; p++) { + float pos[3], vel[3]; + + if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { + continue; + } + + state.time = DEG_get_ctime(args_.depsgraph); + if (psys_get_particle_state(&sim, p, &state, 0) == 0) { + continue; + } + + /* location */ + mul_v3_m4v3(pos, context.object->imat, state.co); + + /* velocity */ + sub_v3_v3v3(vel, state.co, 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(psys->particles[p].size); + ids.push_back(index++); + } + + if (psys->lattice_deform_data) { + BKE_lattice_deform_data_destroy(psys->lattice_deform_data); + 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); + + OPointsSchema::Sample sample(psample, idsample, vsample, wsample); + update_bounding_box(context.object); + sample.setSelfBounds(bounding_box_); + abc_points_schema_.set(sample); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_archive.h b/source/blender/io/alembic/exporter/abc_writer_points.h index 737717c1710..03800b80acf 100644 --- a/source/blender/io/alembic/intern/abc_writer_archive.h +++ b/source/blender/io/alembic/exporter/abc_writer_points.h @@ -16,35 +16,37 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_ARCHIVE_H__ -#define __ABC_WRITER_ARCHIVE_H__ +#include "abc_writer_abstract.h" -#include <Alembic/Abc/All.h> -#include <Alembic/AbcCoreOgawa/All.h> +#include <Alembic/AbcGeom/OPoints.h> -#include <fstream> +namespace blender { +namespace io { +namespace alembic { -struct Main; -struct Scene; +class ABCPointsWriter : public ABCAbstractWriter { + Alembic::AbcGeom::OPoints abc_points_; + Alembic::AbcGeom::OPointsSchema abc_points_schema_; -/* 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. - */ + public: + explicit ABCPointsWriter(const ABCWriterConstructorArgs &args); -class ArchiveWriter { - std::ofstream m_outfile; - Alembic::Abc::OArchive m_archive; + virtual void create_alembic_objects(const HierarchyContext *context) override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; - public: - ArchiveWriter(const char *filename, const std::string &abc_scene_name, const Scene *scene); + virtual bool is_supported(const HierarchyContext *context) const override; - Alembic::Abc::OArchive &archive(); + protected: + virtual bool check_is_animated(const HierarchyContext &context) const override; + virtual void do_write(HierarchyContext &context) override; }; -#endif /* __ABC_WRITER_ARCHIVE_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/exporter/abc_writer_transform.cc b/source/blender/io/alembic/exporter/abc_writer_transform.cc new file mode 100644 index 00000000000..65d6b7c5b41 --- /dev/null +++ b/source/blender/io/alembic/exporter/abc_writer_transform.cc @@ -0,0 +1,115 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup balembic + */ + +#include "abc_writer_transform.h" +#include "abc_hierarchy_iterator.h" +#include "intern/abc_axis_conversion.h" +#include "intern/abc_util.h" + +#include "BKE_object.h" + +#include "BLI_math_matrix.h" +#include "BLI_math_rotation.h" + +#include "DNA_layer_types.h" + +#include "CLG_log.h" +static CLG_LogRef LOG = {"io.alembic"}; + +namespace blender { +namespace io { +namespace alembic { + +using Alembic::Abc::OObject; +using Alembic::AbcGeom::OXform; +using Alembic::AbcGeom::OXformSchema; +using Alembic::AbcGeom::XformSample; + +ABCTransformWriter::ABCTransformWriter(const ABCWriterConstructorArgs &args) + : ABCAbstractWriter(args) +{ + timesample_index_ = args_.abc_archive->time_sampling_index_transforms(); +} + +void ABCTransformWriter::create_alembic_objects(const HierarchyContext * /*context*/) +{ + CLOG_INFO(&LOG, 2, "exporting %s", args_.abc_path.c_str()); + abc_xform_ = OXform(args_.abc_parent, args_.abc_name, timesample_index_); + abc_xform_schema_ = abc_xform_.getSchema(); +} + +void ABCTransformWriter::do_write(HierarchyContext &context) +{ + float parent_relative_matrix[4][4]; // The object matrix relative to the parent. + mul_m4_m4m4(parent_relative_matrix, context.parent_matrix_inv_world, context.matrix_world); + + // After this, parent_relative_matrix uses Y=up. + copy_m44_axis_swap(parent_relative_matrix, parent_relative_matrix, ABC_YUP_FROM_ZUP); + + /* If the parent is a camera, undo its to-Maya rotation (see below). */ + bool is_root_object = context.export_parent == nullptr; + if (!is_root_object && context.export_parent->type == OB_CAMERA) { + float rot_mat[4][4]; + axis_angle_to_mat4_single(rot_mat, 'X', M_PI_2); + mul_m4_m4m4(parent_relative_matrix, rot_mat, parent_relative_matrix); + } + + /* If the object is a camera, apply an extra rotation to Maya camera orientation. */ + if (context.object->type == OB_CAMERA) { + float rot_mat[4][4]; + axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); + mul_m4_m4m4(parent_relative_matrix, parent_relative_matrix, rot_mat); + } + + if (is_root_object) { + /* Only apply scaling to root objects, parenting will propagate it. */ + float scale_mat[4][4]; + scale_m4_fl(scale_mat, args_.export_params->global_scale); + scale_mat[3][3] = args_.export_params->global_scale; /* also scale translation */ + mul_m4_m4m4(parent_relative_matrix, parent_relative_matrix, scale_mat); + parent_relative_matrix[3][3] /= + args_.export_params->global_scale; /* normalise the homogeneous component */ + } + + XformSample xform_sample; + xform_sample.setMatrix(convert_matrix_datatype(parent_relative_matrix)); + xform_sample.setInheritsXforms(true); + abc_xform_schema_.set(xform_sample); +} + +const OObject ABCTransformWriter::get_alembic_object() const +{ + return abc_xform_; +} + +bool ABCTransformWriter::check_is_animated(const HierarchyContext &context) const +{ + if (context.duplicator != NULL) { + /* This object is being duplicated, so could be emitted by a particle system and thus + * influenced by forces. TODO(Sybren): Make this more strict. Probably better to get from the + * depsgraph whether this object instance has a time source. */ + return true; + } + return BKE_object_moves_in_time(context.object, context.animation_check_include_parent); +} + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_nurbs.h b/source/blender/io/alembic/exporter/abc_writer_transform.h index c6a3c399b66..950bff39c29 100644 --- a/source/blender/io/alembic/intern/abc_writer_nurbs.h +++ b/source/blender/io/alembic/exporter/abc_writer_transform.h @@ -13,30 +13,35 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_WRITER_NURBS_H__ -#define __ABC_WRITER_NURBS_H__ +#include "abc_writer_abstract.h" -#include "abc_writer_object.h" +#include <Alembic/AbcGeom/OXform.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); +namespace blender { +namespace io { +namespace alembic { +class ABCTransformWriter : public ABCAbstractWriter { private: - virtual void do_write(); + Alembic::AbcGeom::OXform abc_xform_; + Alembic::AbcGeom::OXformSchema abc_xform_schema_; + + public: + explicit ABCTransformWriter(const ABCWriterConstructorArgs &args); + virtual void create_alembic_objects(const HierarchyContext *context) override; - bool isAnimated() const; + protected: + virtual void do_write(HierarchyContext &context) override; + virtual bool check_is_animated(const HierarchyContext &context) const override; + virtual const Alembic::Abc::OObject get_alembic_object() const override; }; -#endif /* __ABC_WRITER_NURBS_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.cc b/source/blender/io/alembic/intern/abc_axis_conversion.cc index 17db5e9c99f..cebab1f2e41 100644 --- a/source/blender/io/alembic/intern/abc_axis_conversion.cc +++ b/source/blender/io/alembic/intern/abc_axis_conversion.cc @@ -20,12 +20,14 @@ #include "abc_axis_conversion.h" -extern "C" { #include "BLI_assert.h" +#include "BLI_math_geom.h" + #include "DNA_object_types.h" -#include "BLI_math_geom.h" -} +namespace blender { +namespace io { +namespace alembic { void create_swapped_rotation_matrix(float rot_x_mat[3][3], float rot_y_mat[3][3], @@ -72,7 +74,8 @@ void create_swapped_rotation_matrix(float rot_x_mat[3][3], rot_z_mat[1][0] = -sin(rz); rot_z_mat[0][1] = sin(rz); rot_z_mat[1][1] = cos(rz); -} +} // namespace + // alembicvoidcreate_swapped_rotation_matrix(floatrot_x_mat[3][3],floatrot_y_mat[3][3],floatrot_z_mat[3][3],constfloateuler[3],AbcAxisSwapModemode) /* Convert matrix from Z=up to Y=up or vice versa. * Use yup_mat = zup_mat for in-place conversion. */ @@ -164,3 +167,7 @@ void create_transform_matrix(Object *obj, copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); } + +} // namespace alembic +} // namespace io +} // namespace blender
\ No newline at end of file diff --git a/source/blender/io/alembic/intern/abc_axis_conversion.h b/source/blender/io/alembic/intern/abc_axis_conversion.h index 7fde0e92ea4..9a19e9116be 100644 --- a/source/blender/io/alembic/intern/abc_axis_conversion.h +++ b/source/blender/io/alembic/intern/abc_axis_conversion.h @@ -22,13 +22,13 @@ * \ingroup Alembic */ +#include "BLI_compiler_compat.h" + struct Object; -#ifdef _MSC_VER -# define ABC_INLINE static __forceinline -#else -# define ABC_INLINE static inline -#endif +namespace blender { +namespace io { +namespace alembic { /* TODO(kevin): for now keeping these transformations hardcoded to make sure * everything works properly, and also because Alembic is almost exclusively @@ -37,7 +37,7 @@ struct Object; /* Copy from Y-up to Z-up. */ -ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) +BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) { const float old_yup1 = yup[1]; /* in case zup == yup */ zup[0] = yup[0]; @@ -45,7 +45,7 @@ ABC_INLINE void copy_zup_from_yup(float zup[3], const float yup[3]) zup[2] = old_yup1; } -ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) +BLI_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) { const short old_yup1 = yup[1]; /* in case zup == yup */ zup[0] = yup[0]; @@ -55,7 +55,7 @@ ABC_INLINE void copy_zup_from_yup(short zup[3], const short yup[3]) /* Copy from Z-up to Y-up. */ -ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) +BLI_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) { const float old_zup1 = zup[1]; /* in case yup == zup */ yup[0] = zup[0]; @@ -63,7 +63,7 @@ ABC_INLINE void copy_yup_from_zup(float yup[3], const float zup[3]) yup[2] = -old_zup1; } -ABC_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) +BLI_INLINE void copy_yup_from_zup(short yup[3], const short zup[3]) { const short old_zup1 = zup[1]; /* in case yup == zup */ yup[0] = zup[0]; @@ -97,3 +97,7 @@ void create_transform_matrix(Object *obj, float r_transform_mat[4][4], AbcMatrixMode mode, Object *proxy_from); + +} // namespace alembic +} // namespace io +} // namespace blender
\ No newline at end of file diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 62f6a52f7cf..f3e2342e844 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -50,6 +50,9 @@ using Alembic::Abc::V2fArraySample; using Alembic::AbcGeom::OC4fGeomParam; using Alembic::AbcGeom::OV2fGeomParam; +namespace blender { +namespace io { +namespace alembic { static void get_uvs(const CDStreamConfig &config, std::vector<Imath::V2f> &uvs, @@ -485,3 +488,7 @@ void read_custom_data(const std::string &iobject_full_name, } } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 96b57b08681..8f4accb70dc 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -16,14 +16,12 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_CUSTOMDATA_H__ -#define __ABC_CUSTOMDATA_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> @@ -38,6 +36,9 @@ struct Mesh; using Alembic::Abc::ICompoundProperty; using Alembic::Abc::OCompoundProperty; +namespace blender { +namespace io { +namespace alembic { struct UVSample { std::vector<Imath::V2f> uvs; @@ -112,4 +113,6 @@ void read_custom_data(const std::string &iobject_full_name, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss); -#endif /* __ABC_CUSTOMDATA_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_exporter.cc b/source/blender/io/alembic/intern/abc_exporter.cc deleted file mode 100644 index 8dad8dff199..00000000000 --- a/source/blender/io/alembic/intern/abc_exporter.cc +++ /dev/null @@ -1,673 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_exporter.h" - -#include <cmath> - -#include "abc_util.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 "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_fluid_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_space_types.h" /* for FILE_MAX */ - -#include "BLI_string.h" - -#ifdef WIN32 -/* needed for MSCV because of snprintf from BLI_string */ -# include "BLI_winstuff.h" -#endif - -#include "BKE_duplilist.h" -#include "BKE_global.h" -#include "BKE_idprop.h" -#include "BKE_layer.h" -#include "BKE_main.h" -#include "BKE_mball.h" -#include "BKE_modifier.h" -#include "BKE_particle.h" -#include "BKE_scene.h" - -#include "DEG_depsgraph_query.h" - -using Alembic::Abc::OBox3dProperty; -using Alembic::Abc::TimeSamplingPtr; - -/* ************************************************************************** */ - -ExportSettings::ExportSettings() - : scene(NULL), - view_layer(NULL), - depsgraph(NULL), - logger(), - selected_only(false), - visible_objects_only(false), - renderable_only(false), - frame_start(1), - frame_end(1), - frame_samples_xform(1), - frame_samples_shape(1), - shutter_open(0.0), - shutter_close(1.0), - global_scale(1.0f), - flatten_hierarchy(false), - export_normals(false), - export_uvs(false), - export_vcols(false), - export_face_sets(false), - export_vweigths(false), - export_hair(true), - export_particles(true), - apply_subdiv(false), - use_subdiv_schema(false), - export_child_hairs(true), - pack_uv(false), - triangulate(false), - quad_method(0), - ngon_method(0) -{ -} - -static bool object_is_smoke_sim(Object *ob) -{ - ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid); - - if (md) { - FluidModifierData *smd = reinterpret_cast<FluidModifierData *>(md); - return (smd->type == MOD_FLUID_TYPE_DOMAIN && smd->domain && - smd->domain->type == FLUID_DOMAIN_TYPE_GAS); - } - - return false; -} - -static bool object_type_is_exportable(Scene *scene, Object *ob) -{ - switch (ob->type) { - case OB_MESH: - if (object_is_smoke_sim(ob)) { - return false; - } - - return true; - case OB_EMPTY: - case OB_CURVE: - case OB_SURF: - case OB_CAMERA: - return true; - case OB_MBALL: - return AbcMBallWriter::isBasisBall(scene, ob); - default: - return false; - } -} - -/** - * Returns whether this object should be exported into the Alembic file. - * - * \param settings: export settings, used for options like 'selected only'. - * \param ob: the object's base in question. - * \param is_duplicated: Normally false; true when the object is instanced - * into the scene by a dupli-object (e.g. part of a dupligroup). - * This ignores selection and layer visibility, - * and assumes that the dupli-object itself (e.g. the group-instantiating empty) is exported. - */ -static bool export_object(const ExportSettings *const settings, - const Base *const base, - bool is_duplicated) -{ - if (!is_duplicated) { - View3D *v3d = NULL; - - /* These two tests only make sense when the object isn't being instanced - * into the scene. When it is, its exportability is determined by - * its dupli-object and the DupliObject::no_draw property. */ - if (settings->selected_only && !BASE_SELECTED(v3d, base)) { - return false; - } - // FIXME Sybren: handle these cleanly (maybe just remove code), - // now using active scene layer instead. - if (settings->visible_objects_only && !BASE_VISIBLE(v3d, base)) { - return false; - } - } - - Object *ob_eval = DEG_get_evaluated_object(settings->depsgraph, base->object); - if ((ob_eval->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) { - /* XXX fix after 2.80: the object was not part of the depsgraph, and thus we cannot get the - * evaluated copy to export. This will be handled more elegantly in the new - * AbstractHierarchyIterator that Sybren is working on. This condition is temporary, and avoids - * a BLI_assert() failure getting the evaluated mesh of this object. */ - return false; - } - - // if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) { - // return false; - // } - - return true; -} - -/* ************************************************************************** */ - -AbcExporter::AbcExporter(Main *bmain, const char *filename, ExportSettings &settings) - : m_bmain(bmain), - m_settings(settings), - m_filename(filename), - m_trans_sampling_index(0), - m_shape_sampling_index(0), - m_writer(NULL) -{ -} - -AbcExporter::~AbcExporter() -{ - /* Free xforms map */ - m_xforms_type::iterator it_x, e_x; - for (it_x = m_xforms.begin(), e_x = m_xforms.end(); it_x != e_x; ++it_x) { - delete it_x->second; - } - - /* Free shapes vector */ - for (int i = 0, e = m_shapes.size(); i != e; i++) { - delete m_shapes[i]; - } - - delete m_writer; -} - -void AbcExporter::getShutterSamples(unsigned int nr_of_samples, - bool time_relative, - std::vector<double> &samples) -{ - Scene *scene = m_settings.scene; /* for use in the FPS macro */ - samples.clear(); - - unsigned int frame_offset = time_relative ? m_settings.frame_start : 0; - double time_factor = time_relative ? FPS : 1.0; - double shutter_open = m_settings.shutter_open; - double shutter_close = m_settings.shutter_close; - double time_inc = (shutter_close - shutter_open) / nr_of_samples; - - /* sample between shutter open & close */ - for (int sample = 0; sample < nr_of_samples; sample++) { - double sample_time = shutter_open + time_inc * sample; - double time = (frame_offset + sample_time) / time_factor; - - samples.push_back(time); - } -} - -Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step) -{ - std::vector<double> samples; - - if (m_settings.frame_start == m_settings.frame_end) { - return TimeSamplingPtr(new Alembic::Abc::TimeSampling()); - } - - getShutterSamples(step, true, samples); - - /* TODO(Sybren): shouldn't we use the FPS macro here? */ - Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), - 1.0 / m_settings.scene->r.frs_sec); - - return TimeSamplingPtr(new Alembic::Abc::TimeSampling(ts, samples)); -} - -void AbcExporter::getFrameSet(unsigned int nr_of_samples, std::set<double> &frames) -{ - frames.clear(); - - std::vector<double> shutter_samples; - - getShutterSamples(nr_of_samples, false, shutter_samples); - - for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) { - for (size_t j = 0; j < nr_of_samples; j++) { - frames.insert(frame + shutter_samples[j]); - } - } -} - -void AbcExporter::operator()(short *do_update, float *progress, bool *was_canceled) -{ - std::string abc_scene_name; - - if (m_bmain->name[0] != '\0') { - char scene_file_name[FILE_MAX]; - BLI_strncpy(scene_file_name, m_bmain->name, FILE_MAX); - abc_scene_name = scene_file_name; - } - else { - abc_scene_name = "untitled"; - } - - m_writer = new ArchiveWriter(m_filename, abc_scene_name, m_settings.scene); - - /* Create time samplings for transforms and shapes. */ - - TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_samples_xform); - - m_trans_sampling_index = m_writer->archive().addTimeSampling(*trans_time); - - TimeSamplingPtr shape_time; - - if ((m_settings.frame_samples_shape == m_settings.frame_samples_xform) || - (m_settings.frame_start == m_settings.frame_end)) { - shape_time = trans_time; - m_shape_sampling_index = m_trans_sampling_index; - } - else { - shape_time = createTimeSampling(m_settings.frame_samples_shape); - m_shape_sampling_index = m_writer->archive().addTimeSampling(*shape_time); - } - - OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds( - m_writer->archive(), m_trans_sampling_index); - - createTransformWritersHierarchy(); - createShapeWriters(); - - /* Make a list of frames to export. */ - - std::set<double> xform_frames; - getFrameSet(m_settings.frame_samples_xform, xform_frames); - - std::set<double> shape_frames; - getFrameSet(m_settings.frame_samples_shape, shape_frames); - - /* Merge all frames needed. */ - std::set<double> frames(xform_frames); - frames.insert(shape_frames.begin(), shape_frames.end()); - - /* Export all frames. */ - - std::set<double>::const_iterator begin = frames.begin(); - std::set<double>::const_iterator end = frames.end(); - - const float size = static_cast<float>(frames.size()); - size_t i = 0; - - for (; begin != end; ++begin) { - *progress = (++i / size); - *do_update = 1; - - if (G.is_break) { - *was_canceled = true; - break; - } - - const double frame = *begin; - - /* 'frame' is offset by start frame, so need to cancel the offset. */ - setCurrentFrame(m_bmain, frame); - - if (shape_frames.count(frame) != 0) { - for (int i = 0, e = m_shapes.size(); i != e; i++) { - m_shapes[i]->write(); - } - } - - if (xform_frames.count(frame) == 0) { - continue; - } - - m_xforms_type::iterator xit, xe; - for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { - xit->second->write(); - } - - /* Save the archive 's bounding box. */ - Imath::Box3d bounds; - - for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) { - Imath::Box3d box = xit->second->bounds(); - bounds.extendBy(box); - } - - archive_bounds_prop.set(bounds); - } -} - -void AbcExporter::createTransformWritersHierarchy() -{ - for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; - base = base->next) { - Object *ob = base->object; - - if (export_object(&m_settings, base, false)) { - switch (ob->type) { - case OB_LAMP: - case OB_LATTICE: - case OB_SPEAKER: - /* We do not export transforms for objects of these classes. */ - break; - default: - exploreTransform(base, ob, ob->parent, NULL); - } - } - } -} - -void AbcExporter::exploreTransform(Base *base, - Object *object, - Object *parent, - Object *dupliObParent) -{ - /* If an object isn't exported itself, its duplilist shouldn't be - * exported either. */ - if (!export_object(&m_settings, base, dupliObParent != NULL)) { - return; - } - - Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); - if (object_type_is_exportable(m_settings.scene, ob)) { - createTransformWriter(ob, parent, dupliObParent); - } - - ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); - - if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - Object *dupli_ob = NULL; - Object *dupli_parent = NULL; - - for (; link; link = link->next) { - /* This skips things like custom bone shapes. */ - if (m_settings.renderable_only && link->no_draw) { - continue; - } - - if (link->type == OB_DUPLICOLLECTION) { - dupli_ob = link->ob; - dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob; - - exploreTransform(base, dupli_ob, dupli_parent, ob); - } - } - - free_object_duplilist(lb); - } -} - -AbcTransformWriter *AbcExporter::createTransformWriter(Object *ob, - Object *parent, - Object *dupliObParent) -{ - /* An object should not be its own parent, or we'll get infinite loops. */ - BLI_assert(ob != parent); - BLI_assert(ob != dupliObParent); - - std::string name; - if (m_settings.flatten_hierarchy) { - name = get_id_name(ob); - } - else { - name = get_object_dag_path_name(ob, dupliObParent); - } - - /* check if we have already created a transform writer for this object */ - AbcTransformWriter *my_writer = getXForm(name); - if (my_writer != NULL) { - return my_writer; - } - - AbcTransformWriter *parent_writer = NULL; - Alembic::Abc::OObject alembic_parent; - - if (m_settings.flatten_hierarchy || parent == NULL) { - /* Parentless objects still have the "top object" as parent - * in Alembic. */ - alembic_parent = m_writer->archive().getTop(); - } - else { - /* Since there are so many different ways to find parents (as evident - * in the number of conditions below), we can't really look up the - * parent by name. We'll just call createTransformWriter(), which will - * return the parent's AbcTransformWriter pointer. */ - if (parent->parent) { - if (parent == dupliObParent) { - parent_writer = createTransformWriter(parent, parent->parent, NULL); - } - else { - parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); - } - } - else if (parent == dupliObParent) { - if (dupliObParent->parent == NULL) { - parent_writer = createTransformWriter(parent, NULL, NULL); - } - else { - parent_writer = createTransformWriter( - parent, dupliObParent->parent, dupliObParent->parent); - } - } - else { - parent_writer = createTransformWriter(parent, dupliObParent, dupliObParent); - } - - BLI_assert(parent_writer); - alembic_parent = parent_writer->alembicXform(); - } - - my_writer = new AbcTransformWriter( - ob, alembic_parent, parent_writer, m_trans_sampling_index, m_settings); - - /* When flattening, the matrix of the dupliobject has to be added. */ - if (m_settings.flatten_hierarchy && dupliObParent) { - my_writer->m_proxy_from = dupliObParent; - } - - m_xforms[name] = my_writer; - return my_writer; -} - -void AbcExporter::createShapeWriters() -{ - for (Base *base = static_cast<Base *>(m_settings.view_layer->object_bases.first); base; - base = base->next) { - exploreObject(base, base->object, NULL); - } -} - -void AbcExporter::exploreObject(Base *base, Object *object, Object *dupliObParent) -{ - /* If an object isn't exported itself, its duplilist shouldn't be - * exported either. */ - if (!export_object(&m_settings, base, dupliObParent != NULL)) { - return; - } - - Object *ob = DEG_get_evaluated_object(m_settings.depsgraph, object); - createShapeWriter(ob, dupliObParent); - - ListBase *lb = object_duplilist(m_settings.depsgraph, m_settings.scene, ob); - - if (lb) { - DupliObject *link = static_cast<DupliObject *>(lb->first); - - for (; link; link = link->next) { - /* This skips things like custom bone shapes. */ - if (m_settings.renderable_only && link->no_draw) { - continue; - } - if (link->type == OB_DUPLICOLLECTION) { - exploreObject(base, link->ob, ob); - } - } - - free_object_duplilist(lb); - } -} - -void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform) -{ - if (!m_settings.export_hair && !m_settings.export_particles) { - return; - } - - ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); - - for (; psys; psys = psys->next) { - if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { - continue; - } - - if (m_settings.export_hair && psys->part->type == PART_HAIR) { - m_settings.export_child_hairs = true; - m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); - } - else if (m_settings.export_particles && - (psys->part->type == PART_EMITTER || psys->part->type == PART_FLUID_FLIP || - psys->part->type == PART_FLUID_SPRAY || psys->part->type == PART_FLUID_BUBBLE || - psys->part->type == PART_FLUID_FOAM || psys->part->type == PART_FLUID_TRACER || - psys->part->type == PART_FLUID_SPRAYFOAM || - psys->part->type == PART_FLUID_SPRAYBUBBLE || - psys->part->type == PART_FLUID_FOAMBUBBLE || - psys->part->type == PART_FLUID_SPRAYFOAMBUBBLE)) { - m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); - } - } -} - -void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) -{ - if (!object_type_is_exportable(m_settings.scene, ob)) { - return; - } - - std::string name; - - if (m_settings.flatten_hierarchy) { - name = get_id_name(ob); - } - else { - name = get_object_dag_path_name(ob, dupliObParent); - } - - AbcTransformWriter *xform = getXForm(name); - - if (!xform) { - ABC_LOG(m_settings.logger) << __func__ << ": xform " << name << " is NULL\n"; - return; - } - - createParticleSystemsWriters(ob, xform); - - switch (ob->type) { - case OB_MESH: { - Mesh *me = static_cast<Mesh *>(ob->data); - - if (!me) { - return; - } - - m_shapes.push_back(new AbcMeshWriter(ob, xform, m_shape_sampling_index, m_settings)); - break; - } - case OB_SURF: { - Curve *cu = static_cast<Curve *>(ob->data); - - if (!cu) { - return; - } - - AbcObjectWriter *writer; - if (m_settings.curves_as_mesh) { - writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); - } - else { - writer = new AbcNurbsWriter(ob, xform, m_shape_sampling_index, m_settings); - } - m_shapes.push_back(writer); - break; - } - case OB_CURVE: { - Curve *cu = static_cast<Curve *>(ob->data); - - if (!cu) { - return; - } - - AbcObjectWriter *writer; - if (m_settings.curves_as_mesh) { - writer = new AbcCurveMeshWriter(ob, xform, m_shape_sampling_index, m_settings); - } - else { - writer = new AbcCurveWriter(ob, xform, m_shape_sampling_index, m_settings); - } - m_shapes.push_back(writer); - break; - } - case OB_CAMERA: { - Camera *cam = static_cast<Camera *>(ob->data); - - if (cam->type == CAM_PERSP) { - m_shapes.push_back(new AbcCameraWriter(ob, xform, m_shape_sampling_index, m_settings)); - } - - break; - } - case OB_MBALL: { - MetaBall *mball = static_cast<MetaBall *>(ob->data); - if (!mball) { - return; - } - - m_shapes.push_back( - new AbcMBallWriter(m_bmain, ob, xform, m_shape_sampling_index, m_settings)); - break; - } - } -} - -AbcTransformWriter *AbcExporter::getXForm(const std::string &name) -{ - std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name); - - if (it == m_xforms.end()) { - return NULL; - } - - return it->second; -} - -void AbcExporter::setCurrentFrame(Main *bmain, double t) -{ - m_settings.scene->r.cfra = static_cast<int>(t); - m_settings.scene->r.subframe = static_cast<float>(t) - m_settings.scene->r.cfra; - BKE_scene_graph_update_for_newframe(m_settings.depsgraph, bmain); -} diff --git a/source/blender/io/alembic/intern/abc_exporter.h b/source/blender/io/alembic/intern/abc_exporter.h deleted file mode 100644 index 049ccb291bd..00000000000 --- a/source/blender/io/alembic/intern/abc_exporter.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_EXPORTER_H__ -#define __ABC_EXPORTER_H__ - -#include <Alembic/Abc/All.h> -#include <map> -#include <set> -#include <vector> - -#include "abc_util.h" - -class AbcObjectWriter; -class AbcTransformWriter; -class ArchiveWriter; - -struct Base; -struct Depsgraph; -struct Main; -struct Object; -struct Scene; -struct ViewLayer; - -struct ExportSettings { - ExportSettings(); - - Scene *scene; - /** Scene layer to export; all its objects will be exported, unless selected_only=true. */ - ViewLayer *view_layer; - Depsgraph *depsgraph; - SimpleLogger logger; - - bool selected_only; - bool visible_objects_only; - bool renderable_only; - - double frame_start, frame_end; - double frame_samples_xform; - double frame_samples_shape; - double shutter_open; - double shutter_close; - float global_scale; - - bool flatten_hierarchy; - - bool export_normals; - bool export_uvs; - bool export_vcols; - bool export_face_sets; - bool export_vweigths; - bool export_hair; - bool export_particles; - - bool apply_subdiv; - bool curves_as_mesh; - bool use_subdiv_schema; - bool export_child_hairs; - bool pack_uv; - bool triangulate; - - int quad_method; - int ngon_method; -}; - -class AbcExporter { - Main *m_bmain; - ExportSettings &m_settings; - - const char *m_filename; - - unsigned int m_trans_sampling_index, m_shape_sampling_index; - - ArchiveWriter *m_writer; - - /* mapping from name to transform writer */ - typedef std::map<std::string, AbcTransformWriter *> m_xforms_type; - m_xforms_type m_xforms; - - std::vector<AbcObjectWriter *> m_shapes; - - public: - AbcExporter(Main *bmain, const char *filename, ExportSettings &settings); - ~AbcExporter(); - - void operator()(short *do_update, float *progress, bool *was_canceled); - - protected: - void getShutterSamples(unsigned int nr_of_samples, - bool time_relative, - std::vector<double> &samples); - void getFrameSet(unsigned int nr_of_samples, std::set<double> &frames); - - private: - Alembic::Abc::TimeSamplingPtr createTimeSampling(double step); - - void createTransformWritersHierarchy(); - AbcTransformWriter *createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); - void exploreTransform(Base *base, Object *object, Object *parent, Object *dupliObParent); - void exploreObject(Base *base, Object *object, Object *dupliObParent); - void createShapeWriters(); - void createShapeWriter(Object *ob, Object *dupliObParent); - void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform); - - AbcTransformWriter *getXForm(const std::string &name); - - void setCurrentFrame(Main *bmain, double t); -}; - -#endif /* __ABC_EXPORTER_H__ */ diff --git a/source/blender/io/alembic/intern/abc_reader_archive.cc b/source/blender/io/alembic/intern/abc_reader_archive.cc index d55736f732a..d7f1095f0fd 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.cc +++ b/source/blender/io/alembic/intern/abc_reader_archive.cc @@ -39,6 +39,10 @@ using Alembic::Abc::Exception; using Alembic::Abc::IArchive; using Alembic::Abc::kWrapExisting; +namespace blender { +namespace io { +namespace alembic { + static IArchive open_archive(const std::string &filename, const std::vector<std::istream *> &input_streams) { @@ -103,3 +107,7 @@ Alembic::Abc::IObject ArchiveReader::getTop() { return m_archive.getTop(); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h index 304c876adce..aea62b46cce 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.h +++ b/source/blender/io/alembic/intern/abc_reader_archive.h @@ -16,14 +16,12 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_ARCHIVE_H__ -#define __ABC_READER_ARCHIVE_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcCoreOgawa/All.h> @@ -32,6 +30,10 @@ struct Main; struct Scene; +namespace blender { +namespace io { +namespace alembic { + /* 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. @@ -50,4 +52,6 @@ class ArchiveReader { Alembic::Abc::IObject getTop(); }; -#endif /* __ABC_READER_ARCHIVE_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_camera.cc b/source/blender/io/alembic/intern/abc_reader_camera.cc index 0752534f8c2..3affb35908d 100644 --- a/source/blender/io/alembic/intern/abc_reader_camera.cc +++ b/source/blender/io/alembic/intern/abc_reader_camera.cc @@ -37,6 +37,10 @@ using Alembic::AbcGeom::IFloatProperty; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::kWrapExisting; +namespace blender { +namespace io { +namespace alembic { + AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -109,3 +113,7 @@ void AbcCameraReader::readObjectData(Main *bmain, const ISampleSelector &sample_ m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object->data = bcam; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_camera.h b/source/blender/io/alembic/intern/abc_reader_camera.h index 1d9763b0454..b733269407b 100644 --- a/source/blender/io/alembic/intern/abc_reader_camera.h +++ b/source/blender/io/alembic/intern/abc_reader_camera.h @@ -13,16 +13,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_CAMERA_H__ -#define __ABC_READER_CAMERA_H__ - #include "abc_reader_object.h" +namespace blender { +namespace io { +namespace alembic { + class AbcCameraReader : public AbcObjectReader { Alembic::AbcGeom::ICameraSchema m_schema; @@ -37,4 +39,6 @@ class AbcCameraReader : public AbcObjectReader { void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); }; -#endif /* __ABC_READER_CAMERA_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc index d5e0b694294..a505dfd654b 100644 --- a/source/blender/io/alembic/intern/abc_reader_curves.cc +++ b/source/blender/io/alembic/intern/abc_reader_curves.cc @@ -54,6 +54,10 @@ using Alembic::AbcGeom::IInt16Property; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::kWrapExisting; +namespace blender { +namespace io { +namespace alembic { + AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -351,3 +355,7 @@ Mesh *AbcCurveReader::read_mesh(Mesh *existing_mesh, return BKE_mesh_new_nomain_from_curve(m_object); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_curves.h b/source/blender/io/alembic/intern/abc_reader_curves.h index eb0538308f8..7488adb9b24 100644 --- a/source/blender/io/alembic/intern/abc_reader_curves.h +++ b/source/blender/io/alembic/intern/abc_reader_curves.h @@ -16,14 +16,12 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_CURVES_H__ -#define __ABC_READER_CURVES_H__ - #include "abc_reader_mesh.h" #include "abc_reader_object.h" @@ -31,6 +29,10 @@ struct Curve; #define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution" +namespace blender { +namespace io { +namespace alembic { + class AbcCurveReader : public AbcObjectReader { Alembic::AbcGeom::ICurvesSchema m_curves_schema; @@ -53,4 +55,6 @@ class AbcCurveReader : public AbcObjectReader { const Alembic::Abc::ISampleSelector &sample_selector); }; -#endif /* __ABC_READER_CURVES_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index 8b79a3a0aa0..756dde3783c 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -32,6 +32,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "BLI_compiler_compat.h" #include "BLI_math_geom.h" #include "BKE_main.h" @@ -59,6 +60,10 @@ using Alembic::AbcGeom::N3fArraySamplePtr; using Alembic::AbcGeom::UInt32ArraySamplePtr; using Alembic::AbcGeom::V2fArraySamplePtr; +namespace blender { +namespace io { +namespace alembic { + /* NOTE: Alembic's polygon winding order is clockwise, to match with Renderman. */ /* Some helpers for mesh generation */ @@ -339,7 +344,7 @@ static void process_normals(CDStreamConfig &config, } } -ABC_INLINE void read_uvs_params(CDStreamConfig &config, +BLI_INLINE void read_uvs_params(CDStreamConfig &config, AbcMeshData &abc_data, const IV2fGeomParam &uv, const ISampleSelector &selector) @@ -714,7 +719,7 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const ISampleSel /* ************************************************************************** */ -ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) +BLI_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) { for (int i = 0, e = totedge; i < e; i++) { MEdge &edge = edges[i]; @@ -930,3 +935,7 @@ Mesh *AbcSubDReader::read_mesh(Mesh *existing_mesh, return config.mesh; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h index bc95c7ec134..363a74b8b5f 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.h +++ b/source/blender/io/alembic/intern/abc_reader_mesh.h @@ -13,19 +13,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_MESH_H__ -#define __ABC_READER_MESH_H__ - #include "abc_customdata.h" #include "abc_reader_object.h" struct Mesh; +namespace blender { +namespace io { +namespace alembic { + class AbcMeshReader : public AbcObjectReader { Alembic::AbcGeom::IPolyMeshSchema m_schema; @@ -83,4 +85,6 @@ void read_mverts(MVert *mverts, CDStreamConfig get_config(struct Mesh *mesh); -#endif /* __ABC_READER_MESH_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_nurbs.cc b/source/blender/io/alembic/intern/abc_reader_nurbs.cc index 5b9954b3ff6..3ca3f6229ab 100644 --- a/source/blender/io/alembic/intern/abc_reader_nurbs.cc +++ b/source/blender/io/alembic/intern/abc_reader_nurbs.cc @@ -44,6 +44,10 @@ using Alembic::AbcGeom::INuPatch; using Alembic::AbcGeom::INuPatchSchema; using Alembic::AbcGeom::IObject; +namespace blender { +namespace io { +namespace alembic { + AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -222,3 +226,7 @@ void AbcNurbsReader::getNurbsPatches(const IObject &obj) getNurbsPatches(child); } } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_nurbs.h b/source/blender/io/alembic/intern/abc_reader_nurbs.h index f4284c136fb..738da82885d 100644 --- a/source/blender/io/alembic/intern/abc_reader_nurbs.h +++ b/source/blender/io/alembic/intern/abc_reader_nurbs.h @@ -13,16 +13,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_NURBS_H__ -#define __ABC_READER_NURBS_H__ - #include "abc_reader_object.h" +namespace blender { +namespace io { +namespace alembic { + class AbcNurbsReader : public AbcObjectReader { std::vector<std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject>> m_schemas; @@ -37,4 +39,6 @@ class AbcNurbsReader : public AbcObjectReader { void getNurbsPatches(const Alembic::Abc::IObject &obj); }; -#endif /* __ABC_READER_NURBS_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc index e5bd0771a42..39b9cd4c161 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.cc +++ b/source/blender/io/alembic/intern/abc_reader_object.cc @@ -41,6 +41,10 @@ using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IXform; using Alembic::AbcGeom::IXformSchema; +namespace blender { +namespace io { +namespace alembic { + AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings) : m_name(""), m_object_name(""), @@ -330,3 +334,7 @@ void AbcObjectReader::decref() m_refcount--; BLI_assert(m_refcount >= 0); } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h index dcc2697e0b5..0bde60b06b5 100644 --- a/source/blender/io/alembic/intern/abc_reader_object.h +++ b/source/blender/io/alembic/intern/abc_reader_object.h @@ -13,14 +13,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_OBJECT_H__ -#define __ABC_READER_OBJECT_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> @@ -33,6 +31,10 @@ struct Object; using Alembic::AbcCoreAbstract::chrono_t; +namespace blender { +namespace io { +namespace alembic { + struct ImportSettings { bool do_convert_mat; float conversion_mat[4][4]; @@ -166,4 +168,6 @@ class AbcObjectReader { Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); -#endif /* __ABC_READER_OBJECT_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc index c5d08693176..b805da4daa3 100644 --- a/source/blender/io/alembic/intern/abc_reader_points.cc +++ b/source/blender/io/alembic/intern/abc_reader_points.cc @@ -43,6 +43,10 @@ using Alembic::AbcGeom::IPoints; using Alembic::AbcGeom::IPointsSchema; using Alembic::AbcGeom::ISampleSelector; +namespace blender { +namespace io { +namespace alembic { + AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -153,3 +157,7 @@ struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh, return new_mesh ? new_mesh : existing_mesh; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_points.h b/source/blender/io/alembic/intern/abc_reader_points.h index 99881e091f9..8a970ac35b3 100644 --- a/source/blender/io/alembic/intern/abc_reader_points.h +++ b/source/blender/io/alembic/intern/abc_reader_points.h @@ -16,17 +16,19 @@ * The Original Code is Copyright (C) 2016 Kévin Dietrich. * All rights reserved. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_POINTS_H__ -#define __ABC_READER_POINTS_H__ - #include "abc_customdata.h" #include "abc_reader_object.h" +namespace blender { +namespace io { +namespace alembic { + class AbcPointsReader : public AbcObjectReader { Alembic::AbcGeom::IPointsSchema m_schema; Alembic::AbcGeom::IPointsSchema::Sample m_sample; @@ -51,4 +53,6 @@ void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, const Alembic::AbcGeom::ISampleSelector &selector, CDStreamConfig &config); -#endif /* __ABC_READER_POINTS_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_transform.cc b/source/blender/io/alembic/intern/abc_reader_transform.cc index 3df391f8432..456d1da2c68 100644 --- a/source/blender/io/alembic/intern/abc_reader_transform.cc +++ b/source/blender/io/alembic/intern/abc_reader_transform.cc @@ -29,6 +29,10 @@ using Alembic::Abc::ISampleSelector; +namespace blender { +namespace io { +namespace alembic { + AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -72,3 +76,7 @@ void AbcEmptyReader::readObjectData(Main *bmain, const ISampleSelector &UNUSED(s m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str()); m_object->data = NULL; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_reader_transform.h b/source/blender/io/alembic/intern/abc_reader_transform.h index 6b4d23c1884..812d3bdfc92 100644 --- a/source/blender/io/alembic/intern/abc_reader_transform.h +++ b/source/blender/io/alembic/intern/abc_reader_transform.h @@ -13,18 +13,20 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_READER_TRANSFORM_H__ -#define __ABC_READER_TRANSFORM_H__ - #include "abc_reader_object.h" #include <Alembic/AbcGeom/All.h> +namespace blender { +namespace io { +namespace alembic { + class AbcEmptyReader : public AbcObjectReader { Alembic::AbcGeom::IXformSchema m_schema; @@ -39,4 +41,6 @@ class AbcEmptyReader : public AbcObjectReader { void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel); }; -#endif /* __ABC_READER_TRANSFORM_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_util.cc b/source/blender/io/alembic/intern/abc_util.cc index 1f3bd2a1aaa..04febd7bfcb 100644 --- a/source/blender/io/alembic/intern/abc_util.cc +++ b/source/blender/io/alembic/intern/abc_util.cc @@ -38,6 +38,10 @@ #include "PIL_time.h" +namespace blender { +namespace io { +namespace alembic { + std::string get_id_name(const Object *const ob) { if (!ob) { @@ -49,12 +53,16 @@ std::string get_id_name(const Object *const ob) std::string get_id_name(const ID *const id) { - std::string name(id->name + 2); - std::replace(name.begin(), name.end(), ' ', '_'); - std::replace(name.begin(), name.end(), '.', '_'); - std::replace(name.begin(), name.end(), ':', '_'); + return get_valid_abc_name(id->name + 2); +} - return name; +std::string get_valid_abc_name(const char *name) +{ + std::string name_string(name); + std::replace(name_string.begin(), name_string.end(), ' ', '_'); + std::replace(name_string.begin(), name_string.end(), '.', '_'); + std::replace(name_string.begin(), name_string.end(), ':', '_'); + return name_string; } /** @@ -252,3 +260,7 @@ std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger) os << logger.str(); return os; } + +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_util.h b/source/blender/io/alembic/intern/abc_util.h index 57b4d9800a5..4689173ab5f 100644 --- a/source/blender/io/alembic/intern/abc_util.h +++ b/source/blender/io/alembic/intern/abc_util.h @@ -13,23 +13,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once /** \file * \ingroup balembic */ -#ifndef __ABC_UTIL_H__ -#define __ABC_UTIL_H__ - #include <Alembic/Abc/All.h> #include <Alembic/AbcGeom/All.h> -#ifdef _MSC_VER -# define ABC_INLINE static __forceinline -#else -# define ABC_INLINE static inline -#endif - /** * \brief The CacheReader struct is only used for anonymous pointers, * to interface between C and C++ code. This library only creates @@ -41,14 +33,19 @@ struct CacheReader { using Alembic::Abc::chrono_t; -class AbcObjectReader; -struct ImportSettings; - struct ID; struct Object; +namespace blender { +namespace io { +namespace alembic { + +class AbcObjectReader; +struct ImportSettings; + std::string get_id_name(const ID *const id); std::string get_id_name(const Object *const ob); +std::string get_valid_abc_name(const char *name); std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent); /* Convert from float to Alembic matrix representations. Does NOT convert from Z-up to Y-up. */ @@ -164,4 +161,6 @@ class SimpleLogger { */ std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger); -#endif /* __ABC_UTIL_H__ */ +} // namespace alembic +} // namespace io +} // namespace blender diff --git a/source/blender/io/alembic/intern/abc_writer_archive.cc b/source/blender/io/alembic/intern/abc_writer_archive.cc deleted file mode 100644 index 40926532f85..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_archive.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_archive.h" - -#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 &scene_name, - double scene_fps) -{ - 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", std::string("v") + BKE_blender_version_string()); - 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; - 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) -{ - /* Use stream to support unicode character paths on Windows. */ -#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, abc_scene_name, FPS); -} - -OArchive &ArchiveWriter::archive() -{ - return m_archive; -} diff --git a/source/blender/io/alembic/intern/abc_writer_camera.cc b/source/blender/io/alembic/intern/abc_writer_camera.cc deleted file mode 100644 index 07ae81e584f..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_camera.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_camera.h" -#include "abc_writer_transform.h" - -#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/io/alembic/intern/abc_writer_mball.cc b/source/blender/io/alembic/intern/abc_writer_mball.cc deleted file mode 100644 index 3593acf18b0..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_mball.cc +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_mball.h" -#include "abc_writer_mesh.h" - -#include "DNA_mesh_types.h" -#include "DNA_meta_types.h" -#include "DNA_object_types.h" - -#include "BKE_displist.h" -#include "BKE_lib_id.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_object.h" - -#include "BLI_utildefines.h" - -AbcMBallWriter::AbcMBallWriter(Main *bmain, - Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings) - : AbcGenericMeshWriter(ob, parent, time_sampling, settings), m_bmain(bmain) -{ - m_is_animated = isAnimated(); -} - -AbcMBallWriter::~AbcMBallWriter() -{ -} - -bool AbcMBallWriter::isAnimated() const -{ - return true; -} - -Mesh *AbcMBallWriter::getEvaluatedMesh(Scene * /*scene_eval*/, Object *ob_eval, bool &r_needsfree) -{ - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); - if (mesh_eval != NULL) { - /* Mesh_eval only exists when generative modifiers are in use. */ - r_needsfree = false; - return mesh_eval; - } - r_needsfree = true; - - /* The approach below is copied from BKE_mesh_new_from_object() */ - Mesh *tmpmesh = BKE_mesh_add(m_bmain, ((ID *)m_object->data)->name + 2); - BLI_assert(tmpmesh != NULL); - - /* BKE_mesh_add gives us a user count we don't need */ - id_us_min(&tmpmesh->id); - - ListBase disp = {NULL, NULL}; - /* TODO(sergey): This is gonna to work for until Depsgraph - * only contains for_render flag. As soon as CoW is - * implemented, this is to be rethought. - */ - BKE_displist_make_mball_forRender(m_settings.depsgraph, m_settings.scene, m_object, &disp); - BKE_mesh_from_metaball(&disp, tmpmesh); - BKE_displist_free(&disp); - - BKE_mesh_texspace_copy_from_object(tmpmesh, m_object); - - return tmpmesh; -} - -void AbcMBallWriter::freeEvaluatedMesh(struct Mesh *mesh) -{ - BKE_id_free(m_bmain, mesh); -} - -bool AbcMBallWriter::isBasisBall(Scene *scene, Object *ob) -{ - Object *basis_ob = BKE_mball_basis_find(scene, ob); - return ob == basis_ob; -} diff --git a/source/blender/io/alembic/intern/abc_writer_mball.h b/source/blender/io/alembic/intern/abc_writer_mball.h deleted file mode 100644 index e3ac1e69cae..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_mball.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_MBALL_H__ -#define __ABC_WRITER_MBALL_H__ - -#include "abc_writer_mesh.h" -#include "abc_writer_object.h" - -struct Main; -struct Object; - -/* AbcMBallWriter converts the metaballs to meshes at every frame, - * and defers to AbcGenericMeshWriter to perform the writing - * to the Alembic file. Only the basis balls are exported, as this - * results in the entire shape as one mesh. */ -class AbcMBallWriter : public AbcGenericMeshWriter { - Main *m_bmain; - - public: - explicit AbcMBallWriter(Main *bmain, - Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcMBallWriter(); - - static bool isBasisBall(Scene *scene, Object *ob); - - protected: - Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; - void freeEvaluatedMesh(struct Mesh *mesh) override; - - private: - bool isAnimated() const override; -}; - -#endif /* __ABC_WRITER_MBALL_H__ */ diff --git a/source/blender/io/alembic/intern/abc_writer_mesh.h b/source/blender/io/alembic/intern/abc_writer_mesh.h deleted file mode 100644 index 9152a370e4f..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_mesh.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_MESH_H__ -#define __ABC_WRITER_MESH_H__ - -#include "abc_customdata.h" -#include "abc_writer_object.h" - -struct Mesh; -struct ModifierData; - -/* Writer for Alembic meshes. Does not assume the object is a mesh object. */ -class AbcGenericMeshWriter : public AbcObjectWriter { - protected: - Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema; - Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample; - - Alembic::AbcGeom::OSubDSchema m_subdiv_schema; - Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample; - - Alembic::Abc::OArrayProperty m_mat_indices; - - bool m_is_animated; - ModifierData *m_subsurf_mod; - - CDStreamConfig m_custom_data_config; - - bool m_is_liquid; - bool m_is_subd; - - public: - AbcGenericMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcGenericMeshWriter(); - void setIsAnimated(bool is_animated); - - protected: - virtual void do_write(); - virtual bool isAnimated() const; - virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) = 0; - virtual void freeEvaluatedMesh(struct Mesh *mesh); - - Mesh *getFinalMesh(bool &r_needsfree); - - void writeMesh(struct Mesh *mesh); - void writeSubD(struct Mesh *mesh); - - void writeArbGeoParams(struct Mesh *mesh); - void getGeoGroups(struct Mesh *mesh, std::map<std::string, std::vector<int32_t>> &geoGroups); - - /* fluid surfaces support */ - void getVelocities(struct Mesh *mesh, std::vector<Imath::V3f> &vels); - - template<typename Schema> void writeFaceSets(struct Mesh *mesh, Schema &schema); -}; - -class AbcMeshWriter : public AbcGenericMeshWriter { - public: - AbcMeshWriter(Object *ob, - AbcTransformWriter *parent, - uint32_t time_sampling, - ExportSettings &settings); - - ~AbcMeshWriter(); - - protected: - virtual Mesh *getEvaluatedMesh(Scene *scene_eval, Object *ob_eval, bool &r_needsfree) override; -}; - -#endif /* __ABC_WRITER_MESH_H__ */ diff --git a/source/blender/io/alembic/intern/abc_writer_object.cc b/source/blender/io/alembic/intern/abc_writer_object.cc deleted file mode 100644 index f4a3587f54d..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_object.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_object.h" - -#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/io/alembic/intern/abc_writer_object.h b/source/blender/io/alembic/intern/abc_writer_object.h deleted file mode 100644 index 830c4aee903..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_object.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_OBJECT_H__ -#define __ABC_WRITER_OBJECT_H__ - -#include <Alembic/Abc/All.h> -#include <Alembic/AbcGeom/All.h> - -#include "abc_exporter.h" - -#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/io/alembic/intern/abc_writer_points.cc b/source/blender/io/alembic/intern/abc_writer_points.cc deleted file mode 100644 index ac663b62693..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_points.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_points.h" -#include "abc_util.h" -#include "abc_writer_mesh.h" -#include "abc_writer_transform.h" - -#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) { - BKE_lattice_deform_data_destroy(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/io/alembic/intern/abc_writer_points.h b/source/blender/io/alembic/intern/abc_writer_points.h deleted file mode 100644 index 184a363ae6b..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_points.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2016 Kévin Dietrich. - * All rights reserved. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_POINTS_H__ -#define __ABC_WRITER_POINTS_H__ - -#include "abc_customdata.h" -#include "abc_writer_object.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/io/alembic/intern/abc_writer_transform.cc b/source/blender/io/alembic/intern/abc_writer_transform.cc deleted file mode 100644 index 1ec7db0a1c6..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_transform.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#include "abc_writer_transform.h" -#include "abc_axis_conversion.h" - -#include <OpenEXR/ImathBoxAlgo.h> - -#include "DNA_object_types.h" - -#include "BLI_math.h" - -#include "DEG_depsgraph_query.h" - -using Alembic::AbcGeom::OObject; -using Alembic::AbcGeom::OXform; - -AbcTransformWriter::AbcTransformWriter(Object *ob, - const OObject &abc_parent, - AbcTransformWriter *parent, - unsigned int time_sampling, - ExportSettings &settings) - : AbcObjectWriter(ob, time_sampling, settings, parent), m_proxy_from(NULL) -{ - m_is_animated = hasAnimation(m_object); - - if (!m_is_animated) { - time_sampling = 0; - } - - m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling); - m_schema = m_xform.getSchema(); - - /* Blender objects can't have a parent without inheriting the transform. */ - m_inherits_xform = parent != NULL; -} - -void AbcTransformWriter::do_write() -{ - Object *ob_eval = DEG_get_evaluated_object(m_settings.depsgraph, m_object); - - if (m_first_frame) { - m_visibility = Alembic::AbcGeom::CreateVisibilityProperty( - m_xform, m_xform.getSchema().getTimeSampling()); - } - - m_visibility.set(!(ob_eval->restrictflag & OB_RESTRICT_VIEWPORT)); - - if (!m_first_frame && !m_is_animated) { - return; - } - - float yup_mat[4][4]; - create_transform_matrix( - ob_eval, yup_mat, m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, m_proxy_from); - - /* If the parent is a camera, undo its to-Maya rotation (see below). */ - bool is_root_object = !m_inherits_xform || ob_eval->parent == nullptr; - if (!is_root_object && ob_eval->parent->type == OB_CAMERA) { - float rot_mat[4][4]; - axis_angle_to_mat4_single(rot_mat, 'X', M_PI_2); - mul_m4_m4m4(yup_mat, rot_mat, yup_mat); - } - - /* If the object is a camera, apply an extra rotation to Maya camera orientation. */ - if (ob_eval->type == OB_CAMERA) { - float rot_mat[4][4]; - axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); - mul_m4_m4m4(yup_mat, yup_mat, rot_mat); - } - - if (is_root_object) { - /* Only apply scaling to root objects, parenting will propagate it. */ - float scale_mat[4][4]; - scale_m4_fl(scale_mat, m_settings.global_scale); - scale_mat[3][3] = m_settings.global_scale; /* also scale translation */ - mul_m4_m4m4(yup_mat, yup_mat, scale_mat); - yup_mat[3][3] /= m_settings.global_scale; /* normalise the homogeneous component */ - } - - m_matrix = convert_matrix_datatype(yup_mat); - m_sample.setMatrix(m_matrix); - m_sample.setInheritsXforms(m_inherits_xform); - m_schema.set(m_sample); -} - -Imath::Box3d AbcTransformWriter::bounds() -{ - Imath::Box3d bounds; - - for (int i = 0; i < m_children.size(); i++) { - Imath::Box3d box(m_children[i]->bounds()); - bounds.extendBy(box); - } - - return Imath::transform(bounds, m_matrix); -} - -bool AbcTransformWriter::hasAnimation(Object * /*ob*/) const -{ - return true; -} diff --git a/source/blender/io/alembic/intern/abc_writer_transform.h b/source/blender/io/alembic/intern/abc_writer_transform.h deleted file mode 100644 index 4397b220761..00000000000 --- a/source/blender/io/alembic/intern/abc_writer_transform.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup balembic - */ - -#ifndef __ABC_WRITER_TRANSFORM_H__ -#define __ABC_WRITER_TRANSFORM_H__ - -#include "abc_writer_object.h" - -#include <Alembic/AbcGeom/All.h> - -class AbcTransformWriter : public AbcObjectWriter { - Alembic::AbcGeom::OXform m_xform; - Alembic::AbcGeom::OXformSchema m_schema; - Alembic::AbcGeom::XformSample m_sample; - Alembic::AbcGeom::OVisibilityProperty m_visibility; - Alembic::Abc::M44d m_matrix; - - bool m_is_animated; - bool m_inherits_xform; - - public: - Object *m_proxy_from; - - public: - AbcTransformWriter(Object *ob, - const Alembic::AbcGeom::OObject &abc_parent, - AbcTransformWriter *parent, - unsigned int time_sampling, - ExportSettings &settings); - - Alembic::AbcGeom::OXform &alembicXform() - { - return m_xform; - } - virtual Imath::Box3d bounds(); - - private: - virtual void do_write(); - - bool hasAnimation(Object *ob) const; -}; - -#endif /* __ABC_WRITER_TRANSFORM_H__ */ diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc index a30b15fee5f..5932791ecf4 100644 --- a/source/blender/io/alembic/intern/alembic_capi.cc +++ b/source/blender/io/alembic/intern/alembic_capi.cc @@ -30,13 +30,6 @@ #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" @@ -58,12 +51,15 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "ED_undo.h" + /* SpaceType struct has a member called 'new' which obviously conflicts with C++ * so temporarily redefining the new keyword to make it compile. */ #define new extern_new #include "BKE_screen.h" #undef new +#include "BLI_compiler_compat.h" #include "BLI_fileops.h" #include "BLI_ghash.h" #include "BLI_listbase.h" @@ -74,48 +70,33 @@ #include "WM_api.h" #include "WM_types.h" -using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::ObjectHeader; - -using Alembic::AbcGeom::kWrapExisting; -using Alembic::AbcGeom::MetaData; -using Alembic::AbcGeom::P3fArraySamplePtr; - using Alembic::AbcGeom::ICamera; -using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::ICurves; -using Alembic::AbcGeom::ICurvesSchema; using Alembic::AbcGeom::IFaceSet; using Alembic::AbcGeom::ILight; -using Alembic::AbcGeom::IN3fArrayProperty; -using Alembic::AbcGeom::IN3fGeomParam; using Alembic::AbcGeom::INuPatch; using Alembic::AbcGeom::IObject; using Alembic::AbcGeom::IPoints; -using Alembic::AbcGeom::IPointsSchema; using Alembic::AbcGeom::IPolyMesh; -using Alembic::AbcGeom::IPolyMeshSchema; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::ISubD; -using Alembic::AbcGeom::IV2fGeomParam; using Alembic::AbcGeom::IXform; -using Alembic::AbcGeom::IXformSchema; -using Alembic::AbcGeom::N3fArraySamplePtr; -using Alembic::AbcGeom::V3fArraySamplePtr; -using Alembic::AbcGeom::XformSample; - +using Alembic::AbcGeom::MetaData; using Alembic::AbcMaterial::IMaterial; +using namespace blender::io::alembic; + struct AbcArchiveHandle { int unused; }; -ABC_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) +BLI_INLINE ArchiveReader *archive_from_handle(AbcArchiveHandle *handle) { return reinterpret_cast<ArchiveReader *>(handle); } -ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) +BLI_INLINE AbcArchiveHandle *handle_from_archive(ArchiveReader *archive) { return reinterpret_cast<AbcArchiveHandle *>(archive); } @@ -225,195 +206,6 @@ static void find_iobject(const IObject &object, IObject &ret, const std::string ret = tmp; } -struct ExportJobData { - ViewLayer *view_layer; - Main *bmain; - wmWindowManager *wm; - - char filename[1024]; - ExportSettings settings; - - short *stop; - short *do_update; - float *progress; - - bool was_canceled; - bool export_ok; -}; - -static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) -{ - ExportJobData *data = static_cast<ExportJobData *>(customdata); - - data->stop = stop; - data->do_update = do_update; - data->progress = progress; - - /* XXX annoying hack: needed to prevent data corruption when changing - * scene frame in separate threads - */ - G.is_rendering = true; - WM_set_locked_interface(data->wm, true); - G.is_break = false; - - DEG_graph_build_from_view_layer( - data->settings.depsgraph, data->bmain, data->settings.scene, data->view_layer); - BKE_scene_graph_update_tagged(data->settings.depsgraph, data->bmain); - - try { - AbcExporter exporter(data->bmain, data->filename, data->settings); - - Scene *scene = data->settings.scene; /* for the CFRA macro */ - const int orig_frame = CFRA; - - data->was_canceled = false; - exporter(do_update, progress, &data->was_canceled); - - if (CFRA != orig_frame) { - CFRA = orig_frame; - - BKE_scene_graph_update_for_newframe(data->settings.depsgraph, data->bmain); - } - - data->export_ok = !data->was_canceled; - } - catch (const std::exception &e) { - ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n'; - } - catch (...) { - ABC_LOG(data->settings.logger) << "Abc Export: unknown error...\n"; - } -} - -static void export_endjob(void *customdata) -{ - ExportJobData *data = static_cast<ExportJobData *>(customdata); - - DEG_graph_free(data->settings.depsgraph); - - if (data->was_canceled && BLI_exists(data->filename)) { - BLI_delete(data->filename, false, false); - } - - std::string log = data->settings.logger.str(); - if (!log.empty()) { - std::cerr << log; - WM_report(RPT_ERROR, "Errors occurred during the export, look in the console to know more..."); - } - - G.is_rendering = false; - WM_set_locked_interface(data->wm, false); -} - -bool ABC_export(Scene *scene, - bContext *C, - const char *filepath, - const struct AlembicExportParams *params, - bool as_background_job) -{ - ExportJobData *job = static_cast<ExportJobData *>( - MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); - - job->view_layer = CTX_data_view_layer(C); - job->bmain = CTX_data_main(C); - job->wm = CTX_wm_manager(C); - job->export_ok = false; - BLI_strncpy(job->filename, filepath, 1024); - - /* Alright, alright, alright.... - * - * ExportJobData contains an ExportSettings containing a SimpleLogger. - * - * Since ExportJobData is a C-style struct dynamically allocated with - * MEM_mallocN (see above), its constructor is never called, therefore the - * ExportSettings constructor is not called which implies that the - * SimpleLogger one is not called either. SimpleLogger in turn does not call - * the constructor of its data members which ultimately means that its - * std::ostringstream member has a NULL pointer. To be able to properly use - * the stream's operator<<, the pointer needs to be set, therefore we have - * to properly construct everything. And this is done using the placement - * new operator as here below. It seems hackish, but I'm too lazy to - * do bigger refactor and maybe there is a better way which does not involve - * hardcore refactoring. */ - new (&job->settings) ExportSettings(); - job->settings.scene = scene; - job->settings.depsgraph = DEG_graph_new(job->bmain, scene, job->view_layer, DAG_EVAL_RENDER); - - /* TODO(Sybren): for now we only export the active scene layer. - * Later in the 2.8 development process this may be replaced by using - * a specific collection for Alembic I/O, which can then be toggled - * between "real" objects and cached Alembic files. */ - job->settings.view_layer = job->view_layer; - - job->settings.frame_start = params->frame_start; - job->settings.frame_end = params->frame_end; - job->settings.frame_samples_xform = params->frame_samples_xform; - job->settings.frame_samples_shape = params->frame_samples_shape; - job->settings.shutter_open = params->shutter_open; - job->settings.shutter_close = params->shutter_close; - - /* TODO(Sybren): For now this is ignored, until we can get selection - * detection working through Base pointers (instead of ob->flags). */ - job->settings.selected_only = params->selected_only; - - job->settings.export_face_sets = params->face_sets; - job->settings.export_normals = params->normals; - job->settings.export_uvs = params->uvs; - job->settings.export_vcols = params->vcolors; - job->settings.export_hair = params->export_hair; - job->settings.export_particles = params->export_particles; - job->settings.apply_subdiv = params->apply_subdiv; - job->settings.curves_as_mesh = params->curves_as_mesh; - job->settings.flatten_hierarchy = params->flatten_hierarchy; - - /* TODO(Sybren): visible_layer & renderable only is ignored for now, - * to be replaced with collections later in the 2.8 dev process - * (also see note above). */ - job->settings.visible_objects_only = params->visible_objects_only; - job->settings.renderable_only = params->renderable_only; - - job->settings.use_subdiv_schema = params->use_subdiv_schema; - job->settings.pack_uv = params->packuv; - job->settings.global_scale = params->global_scale; - job->settings.triangulate = params->triangulate; - job->settings.quad_method = params->quad_method; - job->settings.ngon_method = params->ngon_method; - - if (job->settings.frame_start > job->settings.frame_end) { - std::swap(job->settings.frame_start, job->settings.frame_end); - } - - bool export_ok = false; - if (as_background_job) { - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - job->settings.scene, - "Alembic Export", - WM_JOB_PROGRESS, - WM_JOB_TYPE_ALEMBIC); - - /* setup job */ - WM_jobs_customdata_set(wm_job, job, MEM_freeN); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob); - - WM_jobs_start(CTX_wm_manager(C), wm_job); - } - else { - /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ - short stop = 0, do_update = 0; - float progress = 0.f; - - export_startjob(job, &stop, &do_update, &progress); - export_endjob(job); - export_ok = job->export_ok; - - MEM_freeN(job); - } - - return export_ok; -} - /* ********************** Import file ********************** */ /** @@ -622,6 +414,7 @@ enum { }; struct ImportJobData { + bContext *C; Main *bmain; Scene *scene; ViewLayer *view_layer; @@ -640,6 +433,7 @@ struct ImportJobData { char error_code; bool was_cancelled; bool import_ok; + bool is_background_job; }; static void import_startjob(void *user_data, short *stop, short *do_update, float *progress) @@ -823,6 +617,12 @@ static void import_endjob(void *user_data) DEG_id_tag_update(&data->scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(data->bmain); + + if (data->is_background_job) { + /* Blender already returned from the import operator, so we need to store our own extra undo + * step. */ + ED_undo_push(data->C, "Alembic Import Finished"); + } } for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { @@ -868,6 +668,7 @@ bool ABC_import(bContext *C, { /* Using new here since MEM_* functions do not call constructor to properly initialize data. */ ImportJobData *job = new ImportJobData(); + job->C = C; job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); job->view_layer = CTX_data_view_layer(C); @@ -884,6 +685,7 @@ bool ABC_import(bContext *C, job->error_code = ABC_NO_ERROR; job->was_cancelled = false; job->archive = NULL; + job->is_background_job = as_background_job; G.is_break = false; diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index edac84e2aaa..1de86425521 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -344,9 +344,11 @@ bool AnimationImporter::write_animation_list(const COLLADAFW::AnimationList *ani return true; } -/* \todo refactor read_node_transform to not automatically apply anything, +/** + * \todo refactor read_node_transform to not automatically apply anything, * but rather return the transform matrix, so caller can do with it what is - * necessary. Same for \ref get_node_mat */ + * necessary. Same for \ref get_node_mat + */ void AnimationImporter::read_node_transform(COLLADAFW::Node *node, Object *ob) { float mat[4][4]; diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp index ec9977c1469..e8765fa2bcd 100644 --- a/source/blender/io/collada/BCMath.cpp +++ b/source/blender/io/collada/BCMath.cpp @@ -17,6 +17,8 @@ * All rights reserved. */ +#include "BLI_utildefines.h" + #include "BCMath.h" #include "BlenderContext.h" diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp index 1c897e37a4a..51d753db03f 100644 --- a/source/blender/io/collada/ImageExporter.cpp +++ b/source/blender/io/collada/ImageExporter.cpp @@ -55,7 +55,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) ImBuf *imbuf = BKE_image_acquire_ibuf(image, NULL, NULL); if (!imbuf) { - fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->name); + fprintf(stderr, "Collada export: image does not exist:\n%s\n", image->filepath); return; } @@ -104,7 +104,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) else { /* make absolute source path */ - BLI_strncpy(source_path, image->name, sizeof(source_path)); + BLI_strncpy(source_path, image->filepath, sizeof(source_path)); BLI_path_abs(source_path, ID_BLEND_PATH_FROM_GLOBAL(&image->id)); BLI_path_normalize(NULL, source_path); diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt new file mode 100644 index 00000000000..4ed6f12762e --- /dev/null +++ b/source/blender/io/common/CMakeLists.txt @@ -0,0 +1,45 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2020, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../../blenkernel + ../../blenlib + ../../depsgraph + ../../makesdna +) + +set(INC_SYS +) + +set(SRC + intern/abstract_hierarchy_iterator.cc + + IO_abstract_hierarchy_iterator.h +) + +set(LIB + bf_blenkernel + bf_blenlib +) + +blender_add_lib(bf_io_common "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +target_link_libraries(bf_io_common INTERFACE) diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h index e31d5c91252..5f84fd48b71 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h @@ -48,7 +48,8 @@ struct Object; struct ParticleSystem; struct ViewLayer; -namespace USD { +namespace blender { +namespace io { class AbstractHierarchyWriter; @@ -90,6 +91,14 @@ struct HierarchyContext { * exported objects, in which case this string is empty even though 'duplicator' is set. */ std::string original_export_path; + /* Export path of the higher-up exported data. For transforms, this is the export path of the + * parent object. For object data, this is the export path of that object's transform. + * + * From the exported file's point of view, this is the path to the parent in that file. The term + * "parent" is not used here to avoid confusion with Blender's meaning of the word (which always + * refers to a different object). */ + std::string higher_up_export_path; + bool operator<(const HierarchyContext &other) const; /* Return a HierarchyContext representing the root of the export hierarchy. */ @@ -119,6 +128,39 @@ class AbstractHierarchyWriter { virtual bool check_is_animated(const HierarchyContext &context) const; }; +/* Determines which subset of the writers actually gets to write. */ +struct ExportSubset { + bool transforms : 1; + bool shapes : 1; +}; + +/* EnsuredWriter represents an AbstractHierarchyWriter* combined with information whether it was + * newly created or not. It's returned by AbstractHierarchyIterator::ensure_writer(). */ +class EnsuredWriter { + private: + AbstractHierarchyWriter *writer_; + + /* Is set to truth when ensure_writer() did not find existing writer and created a new one. + * Is set to false when writer has been re-used or when allocation of the new one has failed + * (`writer` will be `nullptr` in that case and bool(ensured_writer) will be false). */ + bool newly_created_; + + EnsuredWriter(AbstractHierarchyWriter *writer, bool newly_created); + + public: + EnsuredWriter(); + + static EnsuredWriter empty(); + static EnsuredWriter existing(AbstractHierarchyWriter *writer); + static EnsuredWriter newly_created(AbstractHierarchyWriter *writer); + + bool is_newly_created() const; + + /* These operators make an EnsuredWriter* act as an AbstractHierarchyWriter* */ + operator bool() const; + AbstractHierarchyWriter *operator->(); +}; + /* AbstractHierarchyIterator iterates over objects in a dependency graph, and constructs export * writers. These writers are then called to perform the actual writing to a USD or Alembic file. * @@ -147,6 +189,7 @@ class AbstractHierarchyIterator { ExportPathMap duplisource_export_path_; Depsgraph *depsgraph_; WriterMap writers_; + ExportSubset export_subset_; public: explicit AbstractHierarchyIterator(Depsgraph *depsgraph); @@ -154,12 +197,21 @@ class AbstractHierarchyIterator { /* Iterate over the depsgraph, create writers, and tell the writers to write. * Main entry point for the AbstractHierarchyIterator, must be called for every to-be-exported - * frame. */ - void iterate_and_write(); + * (sub)frame. */ + virtual void iterate_and_write(); /* Release all writers. Call after all frames have been exported. */ void release_writers(); + /* Determine which subset of writers is used for exporting. + * Set this before calling iterate_and_write(). + * + * Note that writers are created for each iterated object, regardless of this option. When a + * writer is created it will also write the current iteration, to ensure the hierarchy is + * complete. The `export_subset` option is only in effect when the writer already existed from a + * previous iteration. */ + void set_export_subset(ExportSubset export_subset_); + /* Convert the given name to something that is valid for the exported file format. * This base implementation is a no-op; override in a concrete subclass. */ virtual std::string make_valid_name(const std::string &name) const; @@ -187,7 +239,6 @@ class AbstractHierarchyIterator { Object *duplicator, const std::set<Object *> &dupli_set); - ExportChildren &graph_children(const HierarchyContext *parent_context); void context_update_for_graph_index(HierarchyContext *context, const ExportGraph::key_type &graph_index) const; @@ -200,18 +251,21 @@ class AbstractHierarchyIterator { void make_writer_object_data(const HierarchyContext *context); void make_writers_particle_systems(const HierarchyContext *context); + /* Return the appropriate HierarchyContext for the data of the object represented by + * object_context. */ + HierarchyContext context_for_object_data(const HierarchyContext *object_context) const; + /* Convenience wrappers around get_id_name(). */ std::string get_object_name(const Object *object) const; std::string get_object_data_name(const Object *object) const; - AbstractHierarchyWriter *get_writer(const std::string &export_path) const; - typedef AbstractHierarchyWriter *(AbstractHierarchyIterator::*create_writer_func)( const HierarchyContext *); - /* Ensure that a writer exists; if it doesn't, call create_func(context). The create_func - * function should be one of the create_XXXX_writer(context) functions declared below. */ - AbstractHierarchyWriter *ensure_writer(HierarchyContext *context, - create_writer_func create_func); + /* Ensure that a writer exists; if it doesn't, call create_func(context). + * + * The create_func function should be one of the create_XXXX_writer(context) functions declared + * below. */ + EnsuredWriter ensure_writer(HierarchyContext *context, create_writer_func create_func); protected: /* Construct a valid path for the export file format. This class concatenates by using '/' as a @@ -256,8 +310,12 @@ class AbstractHierarchyIterator { /* Called by release_writers() to free what the create_XXX_writer() functions allocated. */ virtual void delete_object_writer(AbstractHierarchyWriter *writer) = 0; + + AbstractHierarchyWriter *get_writer(const std::string &export_path) const; + ExportChildren &graph_children(const HierarchyContext *parent_context); }; -} // namespace USD +} // namespace io +} // namespace blender #endif /* __ABSTRACT_HIERARCHY_ITERATOR_H__ */ diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc index ab83ea2c3c4..9a456bfaf69 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc @@ -16,7 +16,7 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#include "abstract_hierarchy_iterator.h" +#include "IO_abstract_hierarchy_iterator.h" #include <iostream> #include <limits.h> @@ -41,7 +41,8 @@ #include "DEG_depsgraph_query.h" -namespace USD { +namespace blender { +namespace io { const HierarchyContext *HierarchyContext::root() { @@ -74,6 +75,43 @@ void HierarchyContext::mark_as_not_instanced() original_export_path.clear(); } +EnsuredWriter::EnsuredWriter() : writer_(nullptr), newly_created_(false) +{ +} + +EnsuredWriter::EnsuredWriter(AbstractHierarchyWriter *writer, bool newly_created) + : writer_(writer), newly_created_(newly_created) +{ +} + +EnsuredWriter EnsuredWriter::empty() +{ + return EnsuredWriter(nullptr, false); +} +EnsuredWriter EnsuredWriter::existing(AbstractHierarchyWriter *writer) +{ + return EnsuredWriter(writer, false); +} +EnsuredWriter EnsuredWriter::newly_created(AbstractHierarchyWriter *writer) +{ + return EnsuredWriter(writer, true); +} + +bool EnsuredWriter::is_newly_created() const +{ + return newly_created_; +} + +EnsuredWriter::operator bool() const +{ + return writer_ != nullptr; +} + +AbstractHierarchyWriter *EnsuredWriter::operator->() +{ + return writer_; +} + AbstractHierarchyWriter::~AbstractHierarchyWriter() { } @@ -104,7 +142,7 @@ bool AbstractHierarchyWriter::check_is_animated(const HierarchyContext &context) } AbstractHierarchyIterator::AbstractHierarchyIterator(Depsgraph *depsgraph) - : depsgraph_(depsgraph), writers_() + : depsgraph_(depsgraph), writers_(), export_subset_({true, true}) { } @@ -131,6 +169,11 @@ void AbstractHierarchyIterator::release_writers() writers_.clear(); } +void AbstractHierarchyIterator::set_export_subset(ExportSubset export_subset) +{ + export_subset_ = export_subset; +} + std::string AbstractHierarchyIterator::make_valid_name(const std::string &name) const { return name; @@ -341,6 +384,8 @@ void AbstractHierarchyIterator::visit_object(Object *object, context->animation_check_include_parent = false; context->export_path = ""; context->original_export_path = ""; + context->higher_up_export_path = ""; + copy_m4_m4(context->matrix_world, object->obmat); ExportGraph::key_type graph_index = determine_graph_index_object(context); @@ -494,7 +539,6 @@ void AbstractHierarchyIterator::determine_duplication_references( void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_context) { - AbstractHierarchyWriter *transform_writer = nullptr; float parent_matrix_inv_world[4][4]; if (parent_context) { @@ -507,20 +551,27 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont for (HierarchyContext *context : graph_children(parent_context)) { // Update the context so that it is correct for this parent-child relation. copy_m4_m4(context->parent_matrix_inv_world, parent_matrix_inv_world); + if (parent_context != nullptr) { + context->higher_up_export_path = parent_context->export_path; + } // Get or create the transform writer. - transform_writer = ensure_writer(context, &AbstractHierarchyIterator::create_transform_writer); - if (transform_writer == nullptr) { + EnsuredWriter transform_writer = ensure_writer( + context, &AbstractHierarchyIterator::create_transform_writer); + + if (!transform_writer) { // Unable to export, so there is nothing to attach any children to; just abort this entire // branch of the export hierarchy. return; } BLI_assert(DEG_is_evaluated_object(context->object)); - /* XXX This can lead to too many XForms being written. For example, a camera writer can refuse - * to write an orthographic camera. By the time that this is known, the XForm has already been - * written. */ - transform_writer->write(*context); + if (transform_writer.is_newly_created() || export_subset_.transforms) { + /* XXX This can lead to too many XForms being written. For example, a camera writer can + * refuse to write an orthographic camera. By the time that this is known, the XForm has + * already been written. */ + transform_writer->write(*context); + } if (!context->weak_export) { make_writers_particle_systems(context); @@ -534,17 +585,24 @@ void AbstractHierarchyIterator::make_writers(const HierarchyContext *parent_cont // TODO(Sybren): iterate over all unused writers and call unused_during_iteration() or something. } +HierarchyContext AbstractHierarchyIterator::context_for_object_data( + const HierarchyContext *object_context) const +{ + HierarchyContext data_context = *object_context; + data_context.higher_up_export_path = object_context->export_path; + data_context.export_name = get_object_data_name(data_context.object); + data_context.export_path = path_concatenate(data_context.higher_up_export_path, + data_context.export_name); + return data_context; +} + void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext *context) { if (context->object->data == nullptr) { return; } - HierarchyContext data_context = *context; - data_context.export_path = get_object_data_path(context); - - /* data_context.original_export_path is just a copy from the context. It points to the object, - * but needs to point to the object data. */ + HierarchyContext data_context = context_for_object_data(context); if (data_context.is_instance()) { ID *object_data = static_cast<ID *>(context->object->data); data_context.original_export_path = duplisource_export_path_[object_data]; @@ -553,13 +611,16 @@ void AbstractHierarchyIterator::make_writer_object_data(const HierarchyContext * BLI_assert(data_context.is_instance()); } - AbstractHierarchyWriter *data_writer; - data_writer = ensure_writer(&data_context, &AbstractHierarchyIterator::create_data_writer); - if (data_writer == nullptr) { + /* Always write upon creation, otherwise depend on which subset is active. */ + EnsuredWriter data_writer = ensure_writer(&data_context, + &AbstractHierarchyIterator::create_data_writer); + if (!data_writer) { return; } - data_writer->write(data_context); + if (data_writer.is_newly_created() || export_subset_.shapes) { + data_writer->write(data_context); + } } void AbstractHierarchyIterator::make_writers_particle_systems( @@ -573,11 +634,13 @@ void AbstractHierarchyIterator::make_writers_particle_systems( } HierarchyContext hair_context = *transform_context; + hair_context.export_name = make_valid_name(psys->name); hair_context.export_path = path_concatenate(transform_context->export_path, - make_valid_name(psys->name)); + hair_context.export_name); + hair_context.higher_up_export_path = transform_context->export_path; hair_context.particle_system = psys; - AbstractHierarchyWriter *writer = nullptr; + EnsuredWriter writer; switch (psys->part->type) { case PART_HAIR: writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_hair_writer); @@ -586,8 +649,12 @@ void AbstractHierarchyIterator::make_writers_particle_systems( writer = ensure_writer(&hair_context, &AbstractHierarchyIterator::create_particle_writer); break; } + if (!writer) { + continue; + } - if (writer != nullptr) { + /* Always write upon creation, otherwise depend on which subset is active. */ + if (writer.is_newly_created() || export_subset_.shapes) { writer->write(hair_context); } } @@ -615,22 +682,21 @@ AbstractHierarchyWriter *AbstractHierarchyIterator::get_writer( return it->second; } -AbstractHierarchyWriter *AbstractHierarchyIterator::ensure_writer( +EnsuredWriter AbstractHierarchyIterator::ensure_writer( HierarchyContext *context, AbstractHierarchyIterator::create_writer_func create_func) { AbstractHierarchyWriter *writer = get_writer(context->export_path); if (writer != nullptr) { - return writer; + return EnsuredWriter::existing(writer); } writer = (this->*create_func)(context); if (writer == nullptr) { - return nullptr; + return EnsuredWriter::empty(); } writers_[context->export_path] = writer; - - return writer; + return EnsuredWriter::newly_created(writer); } std::string AbstractHierarchyIterator::path_concatenate(const std::string &parent_path, @@ -649,4 +715,5 @@ bool AbstractHierarchyIterator::should_visit_dupli_object(const DupliObject *dup return !dupli_object->no_draw; } -} // namespace USD +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 732a638a255..19e16a5b328 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -32,6 +32,7 @@ add_definitions(-DPXR_STATIC) set(INC . + ../common ../../blenkernel ../../blenlib ../../blenloader @@ -52,7 +53,6 @@ set(INC_SYS ) set(SRC - intern/abstract_hierarchy_iterator.cc intern/usd_capi.cc intern/usd_hierarchy_iterator.cc intern/usd_writer_abstract.cc @@ -64,7 +64,6 @@ set(SRC intern/usd_writer_transform.cc usd.h - intern/abstract_hierarchy_iterator.h intern/usd_exporter_context.h intern/usd_hierarchy_iterator.h intern/usd_writer_abstract.h @@ -79,6 +78,7 @@ set(SRC set(LIB bf_blenkernel bf_blenlib + bf_io_common ) list(APPEND LIB @@ -100,10 +100,10 @@ endif() # Source: https://github.com/PixarAnimationStudios/USD/blob/master/BUILDING.md#linking-whole-archives if(WIN32) target_link_libraries(bf_usd INTERFACE ${USD_LIBRARIES}) -elseif(CMAKE_COMPILER_IS_GNUCXX) - target_link_libraries(bf_usd INTERFACE "-Wl,--whole-archive ${USD_LIBRARIES} -Wl,--no-whole-archive ${TBB_LIBRARIES}") -elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") +elseif(APPLE) target_link_libraries(bf_usd INTERFACE -Wl,-force_load ${USD_LIBRARIES}) +elseif(UNIX) + target_link_libraries(bf_usd INTERFACE "-Wl,--whole-archive ${USD_LIBRARIES} -Wl,--no-whole-archive ${TBB_LIBRARIES}") else() message(FATAL_ERROR "Unknown how to link USD with your compiler ${CMAKE_CXX_COMPILER_ID}") endif() diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc index cf962446d04..2d3972410a4 100644 --- a/source/blender/io/usd/intern/usd_capi.cc +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -44,7 +44,9 @@ #include "WM_api.h" #include "WM_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { struct ExportJobData { Main *bmain; @@ -157,7 +159,9 @@ static void export_endjob(void *customdata) WM_set_locked_interface(data->wm, false); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender bool USD_export(bContext *C, const char *filepath, @@ -167,8 +171,8 @@ bool USD_export(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); Scene *scene = CTX_data_scene(C); - USD::ExportJobData *job = static_cast<USD::ExportJobData *>( - MEM_mallocN(sizeof(USD::ExportJobData), "ExportJobData")); + blender::io::usd::ExportJobData *job = static_cast<blender::io::usd::ExportJobData *>( + MEM_mallocN(sizeof(blender::io::usd::ExportJobData), "ExportJobData")); job->bmain = CTX_data_main(C); job->wm = CTX_wm_manager(C); @@ -186,7 +190,11 @@ bool USD_export(bContext *C, /* setup job */ WM_jobs_customdata_set(wm_job, job, MEM_freeN); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, USD::export_startjob, nullptr, nullptr, USD::export_endjob); + WM_jobs_callbacks(wm_job, + blender::io::usd::export_startjob, + nullptr, + nullptr, + blender::io::usd::export_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -195,8 +203,8 @@ bool USD_export(bContext *C, short stop = 0, do_update = 0; float progress = 0.f; - USD::export_startjob(job, &stop, &do_update, &progress); - USD::export_endjob(job); + blender::io::usd::export_startjob(job, &stop, &do_update, &progress); + blender::io::usd::export_endjob(job); export_ok = job->export_ok; MEM_freeN(job); diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h index 4ae415b3d34..07a9d0fc0c5 100644 --- a/source/blender/io/usd/intern/usd_exporter_context.h +++ b/source/blender/io/usd/intern/usd_exporter_context.h @@ -27,7 +27,9 @@ struct Depsgraph; struct Object; -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDHierarchyIterator; @@ -39,6 +41,8 @@ struct USDExporterContext { const USDExportParams &export_params; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_EXPORTER_CONTEXT_H__ */ diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc index 56e367dd877..388b588b331 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc @@ -41,7 +41,9 @@ #include "DNA_layer_types.h" #include "DNA_object_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDHierarchyIterator::USDHierarchyIterator(Depsgraph *depsgraph, pxr::UsdStageRefPtr stage, @@ -145,4 +147,6 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_particle_writer(const Hier return nullptr; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h index a608012a390..7d750bff0cb 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h @@ -19,7 +19,7 @@ #ifndef __USD_HIERARCHY_ITERATOR_H__ #define __USD_HIERARCHY_ITERATOR_H__ -#include "abstract_hierarchy_iterator.h" +#include "IO_abstract_hierarchy_iterator.h" #include "usd.h" #include "usd_exporter_context.h" @@ -32,7 +32,13 @@ struct Depsgraph; struct ID; struct Object; -namespace USD { +namespace blender { +namespace io { +namespace usd { + +using blender::io::AbstractHierarchyIterator; +using blender::io::AbstractHierarchyWriter; +using blender::io::HierarchyContext; class USDHierarchyIterator : public AbstractHierarchyIterator { private: @@ -66,6 +72,8 @@ class USDHierarchyIterator : public AbstractHierarchyIterator { USDExporterContext create_usd_export_context(const HierarchyContext *context); }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_HIERARCHY_ITERATOR_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_abstract.cc b/source/blender/io/usd/intern/usd_writer_abstract.cc index 76a2436ee92..a416941fb4d 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.cc +++ b/source/blender/io/usd/intern/usd_writer_abstract.cc @@ -32,7 +32,9 @@ static const pxr::TfToken roughness("roughness", pxr::TfToken::Immortal); static const pxr::TfToken surface("surface", pxr::TfToken::Immortal); } // namespace usdtokens -namespace USD { +namespace blender { +namespace io { +namespace usd { USDAbstractWriter::USDAbstractWriter(const USDExporterContext &usd_export_context) : usd_export_context_(usd_export_context), @@ -112,4 +114,6 @@ pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(Material *material) return usd_material; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h index 01b53f4c916..f81cf5197af 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.h +++ b/source/blender/io/usd/intern/usd_writer_abstract.h @@ -19,7 +19,7 @@ #ifndef __USD_WRITER_ABSTRACT_H__ #define __USD_WRITER_ABSTRACT_H__ -#include "abstract_hierarchy_iterator.h" +#include "IO_abstract_hierarchy_iterator.h" #include "usd_exporter_context.h" #include <pxr/usd/sdf/path.h> @@ -36,7 +36,12 @@ struct Material; struct Object; -namespace USD { +namespace blender { +namespace io { +namespace usd { + +using blender::io::AbstractHierarchyWriter; +using blender::io::HierarchyContext; class USDAbstractWriter : public AbstractHierarchyWriter { protected: @@ -70,6 +75,8 @@ class USDAbstractWriter : public AbstractHierarchyWriter { pxr::UsdShadeMaterial ensure_usd_material(Material *material); }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_ABSTRACT_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_camera.cc b/source/blender/io/usd/intern/usd_writer_camera.cc index ea551a43c9f..d51eb32d3fd 100644 --- a/source/blender/io/usd/intern/usd_writer_camera.cc +++ b/source/blender/io/usd/intern/usd_writer_camera.cc @@ -28,7 +28,9 @@ #include "DNA_camera_types.h" #include "DNA_scene_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDCameraWriter::USDCameraWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -106,4 +108,6 @@ void USDCameraWriter::do_write(HierarchyContext &context) } } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_camera.h b/source/blender/io/usd/intern/usd_writer_camera.h index 971264ef11e..8b5795d7d9f 100644 --- a/source/blender/io/usd/intern/usd_writer_camera.h +++ b/source/blender/io/usd/intern/usd_writer_camera.h @@ -21,7 +21,9 @@ #include "usd_writer_abstract.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { /* Writer for writing camera data to UsdGeomCamera. */ class USDCameraWriter : public USDAbstractWriter { @@ -33,6 +35,8 @@ class USDCameraWriter : public USDAbstractWriter { virtual void do_write(HierarchyContext &context) override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_CAMERA_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_hair.cc b/source/blender/io/usd/intern/usd_writer_hair.cc index d38c1032969..0e0256bdb69 100644 --- a/source/blender/io/usd/intern/usd_writer_hair.cc +++ b/source/blender/io/usd/intern/usd_writer_hair.cc @@ -26,7 +26,9 @@ #include "DNA_particle_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDHairWriter::USDHairWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -85,4 +87,6 @@ bool USDHairWriter::check_is_animated(const HierarchyContext &) const return true; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_hair.h b/source/blender/io/usd/intern/usd_writer_hair.h index 1e882fa1654..cecacd0a355 100644 --- a/source/blender/io/usd/intern/usd_writer_hair.h +++ b/source/blender/io/usd/intern/usd_writer_hair.h @@ -21,7 +21,9 @@ #include "usd_writer_abstract.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { /* Writer for writing hair particle data as USD curves. */ class USDHairWriter : public USDAbstractWriter { @@ -33,6 +35,8 @@ class USDHairWriter : public USDAbstractWriter { virtual bool check_is_animated(const HierarchyContext &context) const override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_HAIR_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_light.cc b/source/blender/io/usd/intern/usd_writer_light.cc index 0ce3ee5f8ce..19115dd1a4e 100644 --- a/source/blender/io/usd/intern/usd_writer_light.cc +++ b/source/blender/io/usd/intern/usd_writer_light.cc @@ -30,7 +30,9 @@ #include "DNA_light_types.h" #include "DNA_object_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDLightWriter::USDLightWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -107,4 +109,6 @@ void USDLightWriter::do_write(HierarchyContext &context) usd_light.CreateSpecularAttr().Set(light->spec_fac, timecode); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_light.h b/source/blender/io/usd/intern/usd_writer_light.h index 349c034b6bc..73666622af1 100644 --- a/source/blender/io/usd/intern/usd_writer_light.h +++ b/source/blender/io/usd/intern/usd_writer_light.h @@ -21,7 +21,9 @@ #include "usd_writer_abstract.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDLightWriter : public USDAbstractWriter { public: @@ -32,6 +34,8 @@ class USDLightWriter : public USDAbstractWriter { virtual void do_write(HierarchyContext &context) override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_LIGHT_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 61337beff20..29a9734f876 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -42,7 +42,9 @@ #include "DNA_object_fluidsim_types.h" #include "DNA_particle_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDGenericMeshWriter::USDGenericMeshWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -484,4 +486,6 @@ Mesh *USDMeshWriter::get_export_mesh(Object *object_eval, bool & /*r_needsfree*/ return BKE_object_get_evaluated_mesh(object_eval); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_mesh.h b/source/blender/io/usd/intern/usd_writer_mesh.h index 4175e2b7e27..a14ceecfa53 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.h +++ b/source/blender/io/usd/intern/usd_writer_mesh.h @@ -23,7 +23,9 @@ #include <pxr/usd/usdGeom/mesh.h> -namespace USD { +namespace blender { +namespace io { +namespace usd { struct USDMeshData; @@ -61,6 +63,8 @@ class USDMeshWriter : public USDGenericMeshWriter { virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_MESH_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_metaball.cc b/source/blender/io/usd/intern/usd_writer_metaball.cc index 96bf854d327..f003fba18a4 100644 --- a/source/blender/io/usd/intern/usd_writer_metaball.cc +++ b/source/blender/io/usd/intern/usd_writer_metaball.cc @@ -34,7 +34,9 @@ #include "DNA_mesh_types.h" #include "DNA_meta_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDMetaballWriter::USDMetaballWriter(const USDExporterContext &ctx) : USDGenericMeshWriter(ctx) { @@ -76,4 +78,6 @@ bool USDMetaballWriter::is_basis_ball(Scene *scene, Object *ob) const return ob == basis_ob; } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_metaball.h b/source/blender/io/usd/intern/usd_writer_metaball.h index 1a86daae2ae..9f51a3314a5 100644 --- a/source/blender/io/usd/intern/usd_writer_metaball.h +++ b/source/blender/io/usd/intern/usd_writer_metaball.h @@ -21,7 +21,9 @@ #include "usd_writer_mesh.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDMetaballWriter : public USDGenericMeshWriter { public: @@ -37,6 +39,8 @@ class USDMetaballWriter : public USDGenericMeshWriter { bool is_basis_ball(Scene *scene, Object *ob) const; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_METABALL_H__ */ diff --git a/source/blender/io/usd/intern/usd_writer_transform.cc b/source/blender/io/usd/intern/usd_writer_transform.cc index 0694d873002..643f1a8f4b1 100644 --- a/source/blender/io/usd/intern/usd_writer_transform.cc +++ b/source/blender/io/usd/intern/usd_writer_transform.cc @@ -28,7 +28,9 @@ #include "DNA_layer_types.h" -namespace USD { +namespace blender { +namespace io { +namespace usd { USDTransformWriter::USDTransformWriter(const USDExporterContext &ctx) : USDAbstractWriter(ctx) { @@ -59,4 +61,6 @@ bool USDTransformWriter::check_is_animated(const HierarchyContext &context) cons return BKE_object_moves_in_time(context.object, context.animation_check_include_parent); } -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender diff --git a/source/blender/io/usd/intern/usd_writer_transform.h b/source/blender/io/usd/intern/usd_writer_transform.h index 52c4a657f33..8b4741f1177 100644 --- a/source/blender/io/usd/intern/usd_writer_transform.h +++ b/source/blender/io/usd/intern/usd_writer_transform.h @@ -23,7 +23,9 @@ #include <pxr/usd/usdGeom/xform.h> -namespace USD { +namespace blender { +namespace io { +namespace usd { class USDTransformWriter : public USDAbstractWriter { private: @@ -37,6 +39,8 @@ class USDTransformWriter : public USDAbstractWriter { bool check_is_animated(const HierarchyContext &context) const override; }; -} // namespace USD +} // namespace usd +} // namespace io +} // namespace blender #endif /* __USD_WRITER_TRANSFORM_H__ */ |