Blender  V3.3
abc_archive.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
4 #include "abc_archive.h"
5 
6 #include "BKE_blender_version.h"
7 #include "BKE_main.h"
8 #include "BKE_scene.h"
9 
10 #include "DEG_depsgraph_query.h"
11 
12 #include "DNA_scene_types.h"
13 
14 #include <Alembic/AbcCoreOgawa/All.h>
15 #include <Alembic/AbcGeom/All.h>
16 
17 #ifdef WIN32
18 # include "BLI_path_util.h"
19 # include "BLI_string.h"
20 
21 # include "utfconv.h"
22 #endif
23 
25 
26 using Alembic::Abc::ErrorHandler;
27 using Alembic::Abc::kWrapExisting;
28 using Alembic::Abc::MetaData;
29 using Alembic::Abc::OArchive;
30 using Alembic::Abc::TimeSampling;
31 using Alembic::Abc::TimeSamplingPtr;
32 using Alembic::Abc::TimeSamplingType;
33 
34 static MetaData create_abc_metadata(const Main *bmain, double scene_fps)
35 {
36  MetaData abc_metadata;
37 
38  std::string abc_user_description(bmain->filepath);
39  if (abc_user_description.empty()) {
40  abc_user_description = "unknown";
41  }
42 
43  abc_metadata.set(Alembic::Abc::kApplicationNameKey, "Blender");
44  abc_metadata.set(Alembic::Abc::kUserDescriptionKey, abc_user_description);
45  abc_metadata.set("blender_version", std::string("v") + BKE_blender_version_string());
46  abc_metadata.set("FramesPerTimeUnit", std::to_string(scene_fps));
47 
48  time_t raw_time;
49  time(&raw_time);
50  char buffer[128];
51 
52 #if defined _WIN32 || defined _WIN64
53  ctime_s(buffer, 128, &raw_time);
54 #else
55  ctime_r(&raw_time, buffer);
56 #endif
57 
58  const std::size_t buffer_len = strlen(buffer);
59  if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
60  buffer[buffer_len - 1] = '\0';
61  }
62 
63  abc_metadata.set(Alembic::Abc::kDateWrittenKey, buffer);
64  return abc_metadata;
65 }
66 
67 static OArchive *create_archive(std::ofstream *abc_ostream,
68  const std::string &filename,
69  MetaData &abc_metadata)
70 {
71  /* Use stream to support unicode character paths on Windows. */
72 #ifdef WIN32
73  char filename_cstr[FILE_MAX];
74  BLI_strncpy(filename_cstr, filename.c_str(), FILE_MAX);
75 
76  UTF16_ENCODE(filename_cstr);
77  std::wstring wstr(filename_cstr_16);
78  abc_ostream->open(wstr.c_str(), std::ios::out | std::ios::binary);
79  UTF16_UN_ENCODE(filename_cstr);
80 #else
81  abc_ostream->open(filename, std::ios::out | std::ios::binary);
82 #endif
83 
84  ErrorHandler::Policy policy = ErrorHandler::kThrowPolicy;
85 
86  Alembic::AbcCoreOgawa::WriteArchive archive_writer;
87  return new OArchive(archive_writer(abc_ostream, abc_metadata), kWrapExisting, policy);
88 }
89 
90 /* Construct list of shutter samples.
91  *
92  * These are taken from the interval [shutter open, shutter close),
93  * uniformly sampled with 'nr_of_samples' samples.
94  *
95  * TODO(Sybren): test that the above interval is indeed half-open.
96  *
97  * If 'time_relative' is true, samples are returned as time (in seconds) from params.frame_start.
98  * If 'time_relative' is false, samples are returned as fractional frames from 0.
99  */
100 static void get_shutter_samples(double scene_fps,
102  int nr_of_samples,
103  bool time_relative,
104  std::vector<double> &r_samples)
105 {
106  double frame_offset = time_relative ? params.frame_start : 0.0;
107  double time_factor = time_relative ? scene_fps : 1.0;
108  double shutter_open = params.shutter_open;
109  double shutter_close = params.shutter_close;
110  double time_inc = (shutter_close - shutter_open) / nr_of_samples;
111 
112  /* sample between shutter open & close */
113  for (int sample = 0; sample < nr_of_samples; sample++) {
114  double sample_time = shutter_open + time_inc * sample;
115  double time = (frame_offset + sample_time) / time_factor;
116 
117  r_samples.push_back(time);
118  }
119 }
120 
121 static TimeSamplingPtr create_time_sampling(double scene_fps,
123  int nr_of_samples)
124 {
125  std::vector<double> samples;
126 
127  if (params.frame_start == params.frame_end) {
128  return TimeSamplingPtr(new TimeSampling()); // NOLINT: modernize-make-shared
129  }
130 
131  get_shutter_samples(scene_fps, params, nr_of_samples, true, samples);
132 
133  TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / scene_fps);
134  return TimeSamplingPtr(new TimeSampling(ts, samples)); // NOLINT: modernize-make-shared
135 }
136 
137 static void get_frames(double scene_fps,
139  unsigned int nr_of_samples,
140  std::set<double> &r_frames)
141 {
142  /* Get one set of shutter samples, then add those around each frame to export. */
143  std::vector<double> shutter_samples;
144  get_shutter_samples(scene_fps, params, nr_of_samples, false, shutter_samples);
145 
146  for (double frame = params.frame_start; frame <= params.frame_end; frame += 1.0) {
147  for (size_t j = 0; j < nr_of_samples; j++) {
148  r_frames.insert(frame + shutter_samples[j]);
149  }
150  }
151 }
152 
153 /* ****************************************************************** */
154 
156  const Scene *scene,
158  std::string filename)
159  : archive(nullptr)
160 {
161  double scene_fps = FPS;
162  MetaData abc_metadata = create_abc_metadata(bmain, scene_fps);
163 
164  /* Create the Archive. */
165  archive = create_archive(&abc_ostream_, filename, abc_metadata);
166 
167  /* Create time samples for transforms and shapes. */
168  TimeSamplingPtr ts_xform;
169  TimeSamplingPtr ts_shapes;
170 
171  ts_xform = create_time_sampling(scene_fps, params, params.frame_samples_xform);
172  time_sampling_index_transforms_ = archive->addTimeSampling(*ts_xform);
173 
174  const bool export_animation = params.frame_start != params.frame_end;
175  if (!export_animation || params.frame_samples_shape == params.frame_samples_xform) {
176  ts_shapes = ts_xform;
177  time_sampling_index_shapes_ = time_sampling_index_transforms_;
178  }
179  else {
180  ts_shapes = create_time_sampling(scene_fps, params, params.frame_samples_shape);
181  time_sampling_index_shapes_ = archive->addTimeSampling(*ts_shapes);
182  }
183 
184  /* Construct the frames to export. */
185  get_frames(scene_fps, params, params.frame_samples_xform, xform_frames_);
186  get_frames(scene_fps, params, params.frame_samples_shape, shape_frames_);
187 
188  /* Merge all frames to get the final set of frames to export. */
189  export_frames_.insert(xform_frames_.begin(), xform_frames_.end());
190  export_frames_.insert(shape_frames_.begin(), shape_frames_.end());
191 
192  abc_archive_bbox_ = Alembic::AbcGeom::CreateOArchiveBounds(*archive,
193  time_sampling_index_transforms_);
194 }
195 
197 {
198  delete archive;
199 }
200 
202 {
203  return time_sampling_index_transforms_;
204 }
205 
207 {
208  return time_sampling_index_shapes_;
209 }
210 
211 ABCArchive::Frames::const_iterator ABCArchive::frames_begin() const
212 {
213  return export_frames_.begin();
214 }
215 ABCArchive::Frames::const_iterator ABCArchive::frames_end() const
216 {
217  return export_frames_.end();
218 }
220 {
221  return export_frames_.size();
222 }
223 
224 bool ABCArchive::is_xform_frame(double frame) const
225 {
226  return xform_frames_.find(frame) != xform_frames_.end();
227 }
228 bool ABCArchive::is_shape_frame(double frame) const
229 {
230  return shape_frames_.find(frame) != shape_frames_.end();
231 }
233 {
234  ExportSubset subset;
235  subset.transforms = is_xform_frame(frame);
236  subset.shapes = is_shape_frame(frame);
237  return subset;
238 }
239 
240 void ABCArchive::update_bounding_box(const Imath::Box3d &bounds)
241 {
242  abc_archive_bbox_.set(bounds);
243 }
244 
245 } // namespace blender::io::alembic
const char * BKE_blender_version_string(void)
Definition: blender.c:124
#define FILE_MAX
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
#define FPS
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
Frames::const_iterator frames_end() const
Definition: abc_archive.cc:215
ABCArchive(const Main *bmain, const Scene *scene, AlembicExportParams params, std::string filename)
Definition: abc_archive.cc:155
bool is_xform_frame(double frame) const
Definition: abc_archive.cc:224
ExportSubset export_subset_for_frame(double frame) const
Definition: abc_archive.cc:232
bool is_shape_frame(double frame) const
Definition: abc_archive.cc:228
Frames::const_iterator frames_begin() const
Definition: abc_archive.cc:211
uint32_t time_sampling_index_shapes() const
Definition: abc_archive.cc:206
Alembic::Abc::OArchive * archive
Definition: abc_archive.h:33
void update_bounding_box(const Imath::Box3d &bounds)
Definition: abc_archive.cc:240
uint32_t time_sampling_index_transforms() const
Definition: abc_archive.cc:201
double time
Scene scene
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global float * buffer
static void get_frames(double scene_fps, const AlembicExportParams &params, unsigned int nr_of_samples, std::set< double > &r_frames)
Definition: abc_archive.cc:137
static MetaData create_abc_metadata(const Main *bmain, double scene_fps)
Definition: abc_archive.cc:34
static OArchive * create_archive(std::ofstream *abc_ostream, const std::string &filename, MetaData &abc_metadata)
Definition: abc_archive.cc:67
static TimeSamplingPtr create_time_sampling(double scene_fps, const AlembicExportParams &params, int nr_of_samples)
Definition: abc_archive.cc:121
static void get_shutter_samples(double scene_fps, const AlembicExportParams &params, int nr_of_samples, bool time_relative, std::vector< double > &r_samples)
Definition: abc_archive.cc:100
std::string to_string(const T &n)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
unsigned int uint32_t
Definition: stdint.h:80
Definition: BKE_main.h:121
char filepath[1024]
Definition: BKE_main.h:124
#define UTF16_ENCODE(in8str)
Definition: utfconv.h:83
#define UTF16_UN_ENCODE(in8str)
Definition: utfconv.h:87