Blender V4.3
usd_reader_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 NVIDIA Corporation. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "usd_reader_utils.hh"
6
7#include "BKE_idprop.hh"
8
9#include <pxr/usd/usd/attribute.h>
10
11#include "CLG_log.h"
12static CLG_LogRef LOG = {"io.usd"};
13
14namespace {
15
16template<typename VECT>
17void set_array_prop(IDProperty *idgroup,
18 const char *prop_name,
19 const pxr::UsdAttribute &attr,
20 const pxr::UsdTimeCode motionSampleTime)
21{
22 if (!idgroup || !attr) {
23 return;
24 }
25
26 VECT vec;
27 if (!attr.Get<VECT>(&vec, motionSampleTime)) {
28 return;
29 }
30
31 IDPropertyTemplate val = {0};
32 val.array.len = int(vec.dimension);
33
34 if (val.array.len <= 0) {
35 CLOG_WARN(&LOG, "Invalid array length for prop %s", prop_name);
36 return;
37 }
38
39 if (std::is_same<float, typename VECT::ScalarType>()) {
40 val.array.type = IDP_FLOAT;
41 }
42 else if (std::is_same<pxr::GfHalf, typename VECT::ScalarType>()) {
43 val.array.type = IDP_FLOAT;
44 }
45 else if (std::is_same<double, typename VECT::ScalarType>()) {
46 val.array.type = IDP_DOUBLE;
47 }
48 else if (std::is_same<int, typename VECT::ScalarType>()) {
49 val.array.type = IDP_INT;
50 }
51 else {
52 CLOG_WARN(&LOG, "Couldn't determine array type for prop %s", prop_name);
53 return;
54 }
55
56 IDProperty *prop = IDP_New(IDP_ARRAY, &val, prop_name);
57
58 if (!prop) {
59 CLOG_WARN(&LOG, "Couldn't create array prop %s", prop_name);
60 return;
61 }
62
63 if (std::is_same<pxr::GfHalf, typename VECT::ScalarType>()) {
64 float *prop_data = static_cast<float *>(prop->data.pointer);
65 for (int i = 0; i < val.array.len; ++i) {
66 prop_data[i] = vec[i];
67 }
68 }
69 else {
70 std::memcpy(prop->data.pointer, vec.data(), prop->len * sizeof(typename VECT::ScalarType));
71 }
72
73 IDP_AddToGroup(idgroup, prop);
74}
75
76bool equivalent(const pxr::SdfValueTypeName &type_name1, const pxr::SdfValueTypeName &type_name2)
77{
78 return type_name1.GetType().IsA(type_name2.GetType());
79}
80
81} // anonymous namespace
82
83namespace blender::io::usd {
84
85/* TfToken objects are not cheap to construct, so we do it once. */
86namespace usdtokens {
87static const pxr::TfToken userProperties("userProperties", pxr::TfToken::Immortal);
88} // namespace usdtokens
89
90static void set_string_prop(IDProperty *idgroup, const char *prop_name, const char *str_val)
91{
92 if (!idgroup) {
93 return;
94 }
95
96 IDPropertyTemplate val = {0};
97 val.string.str = str_val;
98 /* Note length includes null terminator. */
99 val.string.len = strlen(str_val) + 1;
101
102 IDProperty *prop = IDP_New(IDP_STRING, &val, prop_name);
103
104 IDP_AddToGroup(idgroup, prop);
105}
106
107static void set_int_prop(IDProperty *idgroup, const char *prop_name, const int ival)
108{
109 if (!idgroup) {
110 return;
111 }
112
113 IDPropertyTemplate val = {0};
114 val.i = ival;
115 IDProperty *prop = IDP_New(IDP_INT, &val, prop_name);
116
117 IDP_AddToGroup(idgroup, prop);
118}
119
120static void set_bool_prop(IDProperty *idgroup, const char *prop_name, const bool bval)
121{
122 if (!idgroup) {
123 return;
124 }
125
126 IDPropertyTemplate val = {0};
127 val.i = bval;
128 IDProperty *prop = IDP_New(IDP_BOOLEAN, &val, prop_name);
129
130 IDP_AddToGroup(idgroup, prop);
131}
132
133static void set_float_prop(IDProperty *idgroup, const char *prop_name, const float fval)
134{
135 if (!idgroup) {
136 return;
137 }
138
139 IDPropertyTemplate val = {0};
140 val.f = fval;
141 IDProperty *prop = IDP_New(IDP_FLOAT, &val, prop_name);
142
143 IDP_AddToGroup(idgroup, prop);
144}
145
146static void set_double_prop(IDProperty *idgroup, const char *prop_name, const double dval)
147{
148 if (!idgroup) {
149 return;
150 }
151
152 IDPropertyTemplate val = {0};
153 val.d = dval;
154 IDProperty *prop = IDP_New(IDP_DOUBLE, &val, prop_name);
155
156 IDP_AddToGroup(idgroup, prop);
157}
158
160 const pxr::UsdPrim &prim,
161 const eUSDAttrImportMode attr_import_mode,
162 const pxr::UsdTimeCode time_code)
163{
164 pxr::UsdAttributeVector attribs = prim.GetAuthoredAttributes();
165 if (attribs.empty()) {
166 return;
167 }
168
169 bool all_custom_attrs = (attr_import_mode == USD_ATTR_IMPORT_ALL);
170
171 for (const pxr::UsdAttribute &attr : attribs) {
172 if (!attr.IsCustom()) {
173 continue;
174 }
175
176 std::vector<std::string> attr_names = attr.SplitName();
177
178 bool is_user_prop = attr_names[0] == "userProperties";
179
180 if (attr_names.size() > 2 && is_user_prop && attr_names[1] == "blender") {
181 continue;
182 }
183
184 if (!all_custom_attrs && !is_user_prop) {
185 continue;
186 }
187
188 IDProperty *idgroup = IDP_EnsureProperties(id);
189
190 /* When importing user properties, strip the namespace. */
191 pxr::TfToken attr_name;
192 if (is_user_prop) {
193 /* We strip the userProperties namespace, but leave others in case
194 * someone's custom attribute namespace is important in their pipeline. */
195 const std::string token = "userProperties:";
196 const std::string name = attr.GetName().GetString();
197 attr_name = pxr::TfToken(name.substr(token.size(), name.size() - token.size()));
198 }
199 else {
200 attr_name = attr.GetName();
201 }
202
203 pxr::SdfValueTypeName type_name = attr.GetTypeName();
204
205 if (type_name == pxr::SdfValueTypeNames->Int) {
206 int ival = 0;
207 if (attr.Get<int>(&ival, time_code)) {
208 set_int_prop(idgroup, attr_name.GetString().c_str(), ival);
209 }
210 }
211 else if (type_name == pxr::SdfValueTypeNames->Float) {
212 float fval = 0.0f;
213 if (attr.Get<float>(&fval, time_code)) {
214 set_float_prop(idgroup, attr_name.GetString().c_str(), fval);
215 }
216 }
217 else if (type_name == pxr::SdfValueTypeNames->Double) {
218 double dval = 0.0;
219 if (attr.Get<double>(&dval, time_code)) {
220 set_double_prop(idgroup, attr_name.GetString().c_str(), dval);
221 }
222 }
223 else if (type_name == pxr::SdfValueTypeNames->Half) {
224 pxr::GfHalf hval = 0.0f;
225 if (attr.Get<pxr::GfHalf>(&hval, time_code)) {
226 set_float_prop(idgroup, attr_name.GetString().c_str(), hval);
227 }
228 }
229 else if (type_name == pxr::SdfValueTypeNames->String) {
230 std::string sval;
231 if (attr.Get<std::string>(&sval, time_code)) {
232 set_string_prop(idgroup, attr_name.GetString().c_str(), sval.c_str());
233 }
234 }
235 else if (type_name == pxr::SdfValueTypeNames->Token) {
236 pxr::TfToken tval;
237 if (attr.Get<pxr::TfToken>(&tval, time_code)) {
238 set_string_prop(idgroup, attr_name.GetString().c_str(), tval.GetString().c_str());
239 }
240 }
241 else if (type_name == pxr::SdfValueTypeNames->Asset) {
242 pxr::SdfAssetPath aval;
243 if (attr.Get<pxr::SdfAssetPath>(&aval, time_code)) {
244 set_string_prop(idgroup, attr_name.GetString().c_str(), aval.GetAssetPath().c_str());
245 }
246 }
247 else if (type_name == pxr::SdfValueTypeNames->Bool) {
248 bool bval = false;
249 if (attr.Get<bool>(&bval, time_code)) {
250 set_bool_prop(idgroup, attr_name.GetString().c_str(), bval);
251 }
252 }
253 else if (equivalent(type_name, pxr::SdfValueTypeNames->Float2)) {
254 set_array_prop<pxr::GfVec2f>(idgroup, attr_name.GetString().c_str(), attr, time_code);
255 }
256 else if (equivalent(type_name, pxr::SdfValueTypeNames->Float3)) {
257 set_array_prop<pxr::GfVec3f>(idgroup, attr_name.GetString().c_str(), attr, time_code);
258 }
259 else if (equivalent(type_name, pxr::SdfValueTypeNames->Float4)) {
260 set_array_prop<pxr::GfVec4f>(idgroup, attr_name.GetString().c_str(), attr, time_code);
261 }
262 else if (equivalent(type_name, pxr::SdfValueTypeNames->Double2)) {
263 set_array_prop<pxr::GfVec2d>(idgroup, attr_name.GetString().c_str(), attr, time_code);
264 }
265 else if (equivalent(type_name, pxr::SdfValueTypeNames->Double3)) {
266 set_array_prop<pxr::GfVec3d>(idgroup, attr_name.GetString().c_str(), attr, time_code);
267 }
268 else if (equivalent(type_name, pxr::SdfValueTypeNames->Double4)) {
269 set_array_prop<pxr::GfVec4d>(idgroup, attr_name.GetString().c_str(), attr, time_code);
270 }
271 else if (equivalent(type_name, pxr::SdfValueTypeNames->Int2)) {
272 set_array_prop<pxr::GfVec2i>(idgroup, attr_name.GetString().c_str(), attr, time_code);
273 }
274 else if (equivalent(type_name, pxr::SdfValueTypeNames->Int3)) {
275 set_array_prop<pxr::GfVec3i>(idgroup, attr_name.GetString().c_str(), attr, time_code);
276 }
277 else if (equivalent(type_name, pxr::SdfValueTypeNames->Int4)) {
278 set_array_prop<pxr::GfVec4i>(idgroup, attr_name.GetString().c_str(), attr, time_code);
279 }
280 else if (equivalent(type_name, pxr::SdfValueTypeNames->Half2)) {
281 set_array_prop<pxr::GfVec2h>(idgroup, attr_name.GetString().c_str(), attr, time_code);
282 }
283 else if (equivalent(type_name, pxr::SdfValueTypeNames->Half3)) {
284 set_array_prop<pxr::GfVec3h>(idgroup, attr_name.GetString().c_str(), attr, time_code);
285 }
286 else if (equivalent(type_name, pxr::SdfValueTypeNames->Half4)) {
287 set_array_prop<pxr::GfVec4h>(idgroup, attr_name.GetString().c_str(), attr, time_code);
288 }
289 }
290}
291
292} // namespace blender::io::usd
IDProperty * IDP_New(char type, const IDPropertyTemplate *val, const char *name, eIDPropertyFlag flags={}) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:989
bool IDP_AddToGroup(IDProperty *group, IDProperty *prop) ATTR_NONNULL()
Definition idprop.cc:722
IDProperty * IDP_EnsureProperties(ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition idprop.cc:880
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
@ IDP_STRING_SUB_UTF8
@ IDP_DOUBLE
@ IDP_FLOAT
@ IDP_STRING
@ IDP_BOOLEAN
@ IDP_INT
@ IDP_ARRAY
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static const pxr::TfToken userProperties("userProperties", pxr::TfToken::Immortal)
static void set_bool_prop(IDProperty *idgroup, const char *prop_name, const bool bval)
static void set_float_prop(IDProperty *idgroup, const char *prop_name, const float fval)
void set_id_props_from_prim(ID *id, const pxr::UsdPrim &prim, const eUSDAttrImportMode attr_import_mode, const pxr::UsdTimeCode time_code)
static void set_double_prop(IDProperty *idgroup, const char *prop_name, const double dval)
static void set_string_prop(IDProperty *idgroup, const char *prop_name, const char *str_val)
@ USD_ATTR_IMPORT_ALL
Definition usd.hh:57
static void set_int_prop(IDProperty *idgroup, const char *prop_name, const int ival)
void * pointer
Definition DNA_ID.h:145
int len
Definition DNA_ID.h:174
IDPropertyData data
Definition DNA_ID.h:168
Definition DNA_ID.h:413
const char * str
Definition BKE_idprop.hh:37
struct IDPropertyTemplate::@30 array
struct IDPropertyTemplate::@29 string
static CLG_LogRef LOG