Blender V4.3
abc_util.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "abc_util.h"
10
11#include "abc_reader_camera.h"
12#include "abc_reader_curves.h"
13#include "abc_reader_mesh.h"
14#include "abc_reader_points.h"
16
17#include <Alembic/AbcGeom/ILight.h>
18#include <Alembic/AbcGeom/INuPatch.h>
19#include <Alembic/AbcMaterial/IMaterial.h>
20
21#include <algorithm>
22
23#include "DNA_object_types.h"
24
25#include "BLI_time.h"
26
27using Alembic::Abc::IV3fArrayProperty;
28using Alembic::Abc::PropertyHeader;
29using Alembic::Abc::V3fArraySamplePtr;
30
31namespace blender::io::alembic {
32
33std::string get_id_name(const Object *const ob)
34{
35 if (!ob) {
36 return "";
37 }
38
39 return get_id_name(&ob->id);
40}
41
42std::string get_id_name(const ID *const id)
43{
44 return get_valid_abc_name(id->name + 2);
45}
46
47std::string get_valid_abc_name(const char *name)
48{
49 std::string name_string(name);
50 std::replace(name_string.begin(), name_string.end(), ' ', '_');
51 std::replace(name_string.begin(), name_string.end(), '.', '_');
52 std::replace(name_string.begin(), name_string.end(), ':', '_');
53 return name_string;
54}
55
56std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent)
57{
58 std::string name = get_id_name(ob);
59
60 Object *p = ob->parent;
61
62 while (p) {
63 name = get_id_name(p) + "/" + name;
64 p = p->parent;
65 }
66
67 if (dupli_parent && (ob != dupli_parent)) {
68 name = get_id_name(dupli_parent) + "/" + name;
69 }
70
71 return name;
72}
73
74Imath::M44d convert_matrix_datatype(const float mat[4][4])
75{
76 Imath::M44d m;
77
78 for (int i = 0; i < 4; i++) {
79 for (int j = 0; j < 4; j++) {
80 m[i][j] = double(mat[i][j]);
81 }
82 }
83
84 return m;
85}
86
87void convert_matrix_datatype(const Imath::M44d &xform, float r_mat[4][4])
88{
89 for (int i = 0; i < 4; i++) {
90 for (int j = 0; j < 4; j++) {
91 r_mat[i][j] = float(xform[i][j]);
92 }
93 }
94}
95
96void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
97{
98 tokens.clear();
99
100 std::stringstream ss(s);
101 std::string item;
102
103 while (std::getline(ss, item, delim)) {
104 if (!item.empty()) {
105 tokens.push_back(item);
106 }
107 }
108}
109
110bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
111{
112 if (!prop.valid()) {
113 return false;
114 }
115
116 return prop.getPropertyHeader(name) != nullptr;
117}
118
119V3fArraySamplePtr get_velocity_prop(const Alembic::Abc::ICompoundProperty &schema,
120 const Alembic::AbcGeom::ISampleSelector &selector,
121 const std::string &name)
122{
123 for (size_t i = 0; i < schema.getNumProperties(); i++) {
124 const PropertyHeader &header = schema.getPropertyHeader(i);
125
126 if (header.isCompound()) {
127 const Alembic::Abc::ICompoundProperty &prop = Alembic::Abc::ICompoundProperty(
128 schema, header.getName());
129
130 if (has_property(prop, name)) {
131 /* Header cannot be null here, as its presence is checked via has_property, so it is safe
132 * to dereference. */
133 const PropertyHeader *header = prop.getPropertyHeader(name);
134 if (!IV3fArrayProperty::matches(*header)) {
135 continue;
136 }
137
138 const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
139 if (velocity_prop) {
140 return velocity_prop.getValue(selector);
141 }
142 }
143 }
144 else if (header.isArray()) {
145 if (header.getName() == name && IV3fArrayProperty::matches(header)) {
146 const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
147 return velocity_prop.getValue(selector);
148 }
149 }
150 }
151
152 return V3fArraySamplePtr();
153}
154
155using index_time_pair_t = std::pair<Alembic::AbcCoreAbstract::index_t, Alembic::AbcGeom::chrono_t>;
156
157std::optional<SampleInterpolationSettings> get_sample_interpolation_settings(
158 const Alembic::AbcGeom::ISampleSelector &selector,
159 const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
160 size_t samples_number)
161{
162 const chrono_t time = selector.getRequestedTime();
163 samples_number = std::max(samples_number, size_t(1));
164
165 index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number);
166 Alembic::AbcCoreAbstract::index_t i0 = t0.first;
167
168 if (samples_number == 1 || (fabs(time - t0.second) < 0.0001)) {
169 return {};
170 }
171
172 index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number);
173 Alembic::AbcCoreAbstract::index_t i1 = t1.first;
174
175 if (i0 == i1) {
176 return {};
177 }
178
179 const double bias = (time - t0.second) / (t1.second - t0.second);
180
181 if (fabs(1.0 - bias) < 0.0001) {
182 return {};
183 }
184
185 return SampleInterpolationSettings{i0, i1, bias};
186}
187
188// #define USE_NURBS
189
190AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
191{
192 AbcObjectReader *reader = nullptr;
193
194 const Alembic::AbcGeom::MetaData &md = object.getMetaData();
195
196 if (Alembic::AbcGeom::IXform::matches(md)) {
197 reader = new AbcEmptyReader(object, settings);
198 }
199 else if (Alembic::AbcGeom::IPolyMesh::matches(md)) {
200 reader = new AbcMeshReader(object, settings);
201 }
202 else if (Alembic::AbcGeom::ISubD::matches(md)) {
203 reader = new AbcSubDReader(object, settings);
204 }
205 else if (Alembic::AbcGeom::INuPatch::matches(md)) {
206#ifdef USE_NURBS
207 /* TODO(kevin): importing cyclic NURBS from other software crashes
208 * at the moment. This is due to the fact that NURBS in other
209 * software have duplicated points which causes buffer overflows in
210 * Blender. Need to figure out exactly how these points are
211 * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV).
212 * Until this is fixed, disabling NURBS reading. */
213 reader = new AbcNurbsReader(child, settings);
214#endif
215 }
216 else if (Alembic::AbcGeom::ICamera::matches(md)) {
217 reader = new AbcCameraReader(object, settings);
218 }
219 else if (Alembic::AbcGeom::IPoints::matches(md)) {
220 reader = new AbcPointsReader(object, settings);
221 }
222 else if (Alembic::AbcMaterial::IMaterial::matches(md)) {
223 /* Pass for now. */
224 }
225 else if (Alembic::AbcGeom::ILight::matches(md)) {
226 /* Pass for now. */
227 }
228 else if (Alembic::AbcGeom::IFaceSet::matches(md)) {
229 /* Pass, those are handled in the mesh reader. */
230 }
231 else if (Alembic::AbcGeom::ICurves::matches(md)) {
232 reader = new AbcCurveReader(object, settings);
233 }
234 else {
235 std::cerr << "Alembic: unknown how to handle objects of schema '" << md.get("schemaObjTitle")
236 << "', skipping object '" << object.getFullName() << "'" << std::endl;
237 }
238
239 return reader;
240}
241
242/* ********************** */
243
244ScopeTimer::ScopeTimer(const char *message) : m_message(message), m_start(BLI_time_now_seconds())
245{
246}
247
249{
250 fprintf(stderr, "%s: %fs\n", m_message, BLI_time_now_seconds() - m_start);
251}
252
253/* ********************** */
254
255std::string SimpleLogger::str() const
256{
257 return m_stream.str();
258}
259
261{
262 m_stream.clear();
263 m_stream.str("");
264}
265
266std::ostringstream &SimpleLogger::stream()
267{
268 return m_stream;
269}
270
271std::ostream &operator<<(std::ostream &os, const SimpleLogger &logger)
272{
273 os << logger.str();
274 return os;
275}
276
277} // namespace blender::io::alembic
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
typedef double(DMatrix)[4][4]
Object is a sort of wrapper for general info.
ScopeTimer(const char *message)
Definition abc_util.cc:244
std::ostringstream & stream()
Definition abc_util.cc:266
draw_view in_light_buf[] float
ccl_device_inline float2 fabs(const float2 a)
std::string get_valid_abc_name(const char *name)
Definition abc_util.cc:47
std::ostream & operator<<(std::ostream &os, const SimpleLogger &logger)
Definition abc_util.cc:271
std::string get_object_dag_path_name(const Object *const ob, Object *dupli_parent)
get_object_dag_path_name returns the name under which the object will be exported in the Alembic file...
Definition abc_util.cc:56
V3fArraySamplePtr get_velocity_prop(const Alembic::Abc::ICompoundProperty &schema, const Alembic::AbcGeom::ISampleSelector &selector, const std::string &name)
Definition abc_util.cc:119
std::string get_id_name(const Object *const ob)
Definition abc_util.cc:33
Imath::M44d convert_matrix_datatype(const float mat[4][4])
Definition abc_util.cc:74
std::pair< Alembic::AbcCoreAbstract::index_t, Alembic::AbcGeom::chrono_t > index_time_pair_t
Definition abc_util.cc:155
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
Definition abc_util.cc:110
AbcObjectReader * create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings)
Definition abc_util.cc:190
std::optional< SampleInterpolationSettings > get_sample_interpolation_settings(const Alembic::AbcGeom::ISampleSelector &selector, const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling, size_t samples_number)
Definition abc_util.cc:157
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition abc_util.cc:96
Definition DNA_ID.h:413
struct Object * parent