1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/usd/usdGeom/primvarsAPI.h"
25 #include "pxr/usd/usd/schemaRegistry.h"
26 #include "pxr/usd/usd/typed.h"
27 #include "pxr/usd/usd/tokens.h"
28
29 #include "pxr/usd/sdf/types.h"
30 #include "pxr/usd/sdf/assetPath.h"
31
32 PXR_NAMESPACE_OPEN_SCOPE
33
34 // Register the schema with the TfType system.
TF_REGISTRY_FUNCTION(TfType)35 TF_REGISTRY_FUNCTION(TfType)
36 {
37 TfType::Define<UsdGeomPrimvarsAPI,
38 TfType::Bases< UsdAPISchemaBase > >();
39
40 }
41
42 TF_DEFINE_PRIVATE_TOKENS(
43 _schemaTokens,
44 (PrimvarsAPI)
45 );
46
47 /* virtual */
~UsdGeomPrimvarsAPI()48 UsdGeomPrimvarsAPI::~UsdGeomPrimvarsAPI()
49 {
50 }
51
52 /* static */
53 UsdGeomPrimvarsAPI
Get(const UsdStagePtr & stage,const SdfPath & path)54 UsdGeomPrimvarsAPI::Get(const UsdStagePtr &stage, const SdfPath &path)
55 {
56 if (!stage) {
57 TF_CODING_ERROR("Invalid stage");
58 return UsdGeomPrimvarsAPI();
59 }
60 return UsdGeomPrimvarsAPI(stage->GetPrimAtPath(path));
61 }
62
63
64 /* virtual */
_GetSchemaKind() const65 UsdSchemaKind UsdGeomPrimvarsAPI::_GetSchemaKind() const
66 {
67 return UsdGeomPrimvarsAPI::schemaKind;
68 }
69
70 /* static */
71 const TfType &
_GetStaticTfType()72 UsdGeomPrimvarsAPI::_GetStaticTfType()
73 {
74 static TfType tfType = TfType::Find<UsdGeomPrimvarsAPI>();
75 return tfType;
76 }
77
78 /* static */
79 bool
_IsTypedSchema()80 UsdGeomPrimvarsAPI::_IsTypedSchema()
81 {
82 static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
83 return isTyped;
84 }
85
86 /* virtual */
87 const TfType &
_GetTfType() const88 UsdGeomPrimvarsAPI::_GetTfType() const
89 {
90 return _GetStaticTfType();
91 }
92
93 /*static*/
94 const TfTokenVector&
GetSchemaAttributeNames(bool includeInherited)95 UsdGeomPrimvarsAPI::GetSchemaAttributeNames(bool includeInherited)
96 {
97 static TfTokenVector localNames;
98 static TfTokenVector allNames =
99 UsdAPISchemaBase::GetSchemaAttributeNames(true);
100
101 if (includeInherited)
102 return allNames;
103 else
104 return localNames;
105 }
106
107 PXR_NAMESPACE_CLOSE_SCOPE
108
109 // ===================================================================== //
110 // Feel free to add custom code below this line. It will be preserved by
111 // the code generator.
112 //
113 // Just remember to wrap code in the appropriate delimiters:
114 // 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
115 // ===================================================================== //
116 // --(BEGIN CUSTOM CODE)--
117
118 PXR_NAMESPACE_OPEN_SCOPE
119
120 UsdGeomPrimvar
CreatePrimvar(const TfToken & name,const SdfValueTypeName & typeName,const TfToken & interpolation,int elementSize) const121 UsdGeomPrimvarsAPI::CreatePrimvar(const TfToken& name,
122 const SdfValueTypeName &typeName,
123 const TfToken& interpolation,
124 int elementSize) const
125 {
126 const UsdPrim &prim = GetPrim();
127
128 UsdGeomPrimvar primvar(prim, name, typeName);
129
130 if (primvar){
131 if (!interpolation.IsEmpty())
132 primvar.SetInterpolation(interpolation);
133 if (elementSize > 0)
134 primvar.SetElementSize(elementSize);
135 }
136 // otherwise, errors have already been issued
137 return primvar;
138 }
139
140 bool
RemovePrimvar(const TfToken & name)141 UsdGeomPrimvarsAPI::RemovePrimvar(const TfToken& name)
142 {
143 const TfToken& attrName = UsdGeomPrimvar::_MakeNamespaced(name);
144 if (attrName.IsEmpty()) {
145 return false;
146 }
147
148 UsdPrim prim = GetPrim();
149 if (!prim) {
150 TF_CODING_ERROR("RemovePrimvar called on invalid prim: %s",
151 UsdDescribe(prim).c_str());
152 return false;
153 }
154
155 const UsdGeomPrimvar &primvar = UsdGeomPrimvar(prim.GetAttribute(attrName));
156 if (!primvar) {
157 return false;
158 }
159
160 const UsdAttribute& indexAttr = primvar.GetIndicesAttr();
161 bool success = true;
162 // If the Primvar is an indexed primvar, also remove the indexAttr
163 if (indexAttr) {
164 success = prim.RemoveProperty(indexAttr.GetName());
165 }
166 return prim.RemoveProperty(attrName) && success;
167 }
168
169 void
BlockPrimvar(const TfToken & name)170 UsdGeomPrimvarsAPI::BlockPrimvar(const TfToken& name)
171 {
172 const TfToken& attrName = UsdGeomPrimvar::_MakeNamespaced(name);
173 if (attrName.IsEmpty()) {
174 return;
175 }
176
177 const UsdPrim& prim = GetPrim();
178 if (!prim) {
179 TF_CODING_ERROR("RemovePrimvar called on invalid prim: %s",
180 UsdDescribe(prim).c_str());
181 return;
182 }
183
184 const UsdGeomPrimvar &primvar = UsdGeomPrimvar(prim.GetAttribute(name));
185 if (!primvar) {
186 return;
187 }
188
189 // Always block indices attr irrespective of primvar is indexed or not
190 // This prevents leak of indices attr in a composed stage when a stronger
191 // layer has blocked the primvar and at a later time weaker layer adds
192 // indices to the primvar
193 primvar.BlockIndices();
194
195 primvar.GetAttr().Block();
196 }
197
198
199 UsdGeomPrimvar
GetPrimvar(const TfToken & name) const200 UsdGeomPrimvarsAPI::GetPrimvar(const TfToken &name) const
201 {
202 // The getter SHOULD issue an error if 'name' is malformed, which
203 // _MakeNamespaced() will do for us.
204 return UsdGeomPrimvar(GetPrim().GetAttribute
205 (UsdGeomPrimvar::_MakeNamespaced(name)));
206 }
207
208 static
209 std::vector<UsdGeomPrimvar>
_MakePrimvars(std::vector<UsdProperty> const & props,bool (filterPass)(UsdGeomPrimvar const &))210 _MakePrimvars(std::vector<UsdProperty> const &props,
211 bool (filterPass)(UsdGeomPrimvar const &))
212 {
213 std::vector<UsdGeomPrimvar> primvars;
214
215 for (UsdProperty const &prop : props) {
216 // All prefixed properties except the ones that contain extra
217 // namespaces (eg. the ":indices" attributes belonging to indexed
218 // primvars) will be valid primvars.
219 UsdGeomPrimvar primvar = UsdGeomPrimvar(prop.As<UsdAttribute>());
220 if (primvar && filterPass(primvar)){
221 primvars.push_back(std::move(primvar));
222 }
223 }
224 return primvars;
225 }
226
227
228 std::vector<UsdGeomPrimvar>
GetPrimvars() const229 UsdGeomPrimvarsAPI::GetPrimvars() const
230 {
231 TRACE_FUNCTION();
232 const UsdPrim &prim = GetPrim();
233 if (!prim){
234 TF_CODING_ERROR("Called GetPrimvars on invalid prim: %s",
235 UsdDescribe(prim).c_str());
236 return std::vector<UsdGeomPrimvar>();
237 }
238 return _MakePrimvars(prim.GetPropertiesInNamespace(
239 UsdGeomPrimvar::_GetNamespacePrefix()),
240 [](UsdGeomPrimvar const &) { return true; });
241 }
242
243 std::vector<UsdGeomPrimvar>
GetAuthoredPrimvars() const244 UsdGeomPrimvarsAPI::GetAuthoredPrimvars() const
245 {
246 TRACE_FUNCTION();
247 const UsdPrim &prim = GetPrim();
248 if (!prim){
249 TF_CODING_ERROR("Called GetAuthoredPrimvars on invalid prim: %s",
250 UsdDescribe(prim).c_str());
251 return std::vector<UsdGeomPrimvar>();
252 }
253 return _MakePrimvars(prim.GetAuthoredPropertiesInNamespace(
254 UsdGeomPrimvar::_GetNamespacePrefix()),
255 [](UsdGeomPrimvar const &) { return true; });
256 }
257
258
259 std::vector<UsdGeomPrimvar>
GetPrimvarsWithValues() const260 UsdGeomPrimvarsAPI::GetPrimvarsWithValues() const
261 {
262 TRACE_FUNCTION();
263 const UsdPrim &prim = GetPrim();
264 if (!prim){
265 TF_CODING_ERROR("Called GetPrimvarsWithValues on invalid prim: %s",
266 UsdDescribe(prim).c_str());
267 return std::vector<UsdGeomPrimvar>();
268 }
269 return _MakePrimvars(prim.GetAuthoredPropertiesInNamespace(
270 UsdGeomPrimvar::_GetNamespacePrefix()),
271 [](UsdGeomPrimvar const &pv) { return pv.HasValue(); });
272 }
273
274
275 std::vector<UsdGeomPrimvar>
GetPrimvarsWithAuthoredValues() const276 UsdGeomPrimvarsAPI::GetPrimvarsWithAuthoredValues() const
277 {
278 TRACE_FUNCTION();
279 const UsdPrim &prim = GetPrim();
280 if (!prim){
281 TF_CODING_ERROR("Called GetPrimvarsWithAuthoredValues on invalid prim: %s",
282 UsdDescribe(prim).c_str());
283 return std::vector<UsdGeomPrimvar>();
284 }
285 return _MakePrimvars(prim.GetAuthoredPropertiesInNamespace(
286 UsdGeomPrimvar::_GetNamespacePrefix()),
287 [](UsdGeomPrimvar const &pv) {
288 return pv.HasAuthoredValue();
289 });
290 }
291
292
293
294 static
295 void
_AddPrimToInheritedPrimvars(const UsdPrim & prim,const TfToken & pvPrefix,const std::vector<UsdGeomPrimvar> * inputPrimvars,std::vector<UsdGeomPrimvar> * outputPrimvars,bool acceptAll)296 _AddPrimToInheritedPrimvars(const UsdPrim &prim, const TfToken &pvPrefix,
297 const std::vector<UsdGeomPrimvar> *inputPrimvars,
298 std::vector<UsdGeomPrimvar> *outputPrimvars,
299 bool acceptAll)
300 {
301 auto copyPrimvars = [&inputPrimvars,&outputPrimvars]()
302 {
303 if (inputPrimvars != outputPrimvars){
304 *outputPrimvars = *inputPrimvars;
305 inputPrimvars = outputPrimvars;
306 }
307 };
308
309
310 for (UsdProperty const& prop:
311 prim.GetAuthoredPropertiesInNamespace(pvPrefix)) {
312 if (UsdGeomPrimvar pv = UsdGeomPrimvar(prop.As<UsdAttribute>())) {
313 // If the primvar does not provide a value, then it is as if it
314 // does not exist on prim
315 if (!pv.HasAuthoredValue()) {
316 continue;
317 }
318
319 // If pv is constant it will replace an instance already on the list;
320 // if non-constant we'll just remove it.
321 const TfToken &name = pv.GetName();
322 size_t i;
323 bool pvIsConstant = pv.GetInterpolation() == UsdGeomTokens->constant;
324 bool foundMatch = false;
325 for (i=0; i < inputPrimvars->size(); ++i) {
326 if (name == (*inputPrimvars)[i].GetName()) {
327 copyPrimvars();
328 foundMatch = true;
329 if (pvIsConstant || acceptAll){
330 (*outputPrimvars)[i] = std::move(pv);
331 break;
332 }
333 else {
334 // Swap to the end and truncate the vector.
335 // Don't bother to preserve order.
336 std::swap((*outputPrimvars)[i], outputPrimvars->back());
337 outputPrimvars->pop_back();
338 break;
339 }
340 }
341 }
342 if ( !foundMatch && (pvIsConstant || acceptAll)) {
343 copyPrimvars();
344 outputPrimvars->push_back(std::move(pv));
345 }
346 }
347 }
348 }
349
350 static
351 void
_RecurseForInheritablePrimvars(const UsdPrim & prim,const TfToken & pvPrefix,std::vector<UsdGeomPrimvar> * primvars,bool acceptAll=false)352 _RecurseForInheritablePrimvars(const UsdPrim &prim, const TfToken &pvPrefix,
353 std::vector<UsdGeomPrimvar> *primvars,
354 bool acceptAll = false)
355 {
356 if (prim.IsPseudoRoot())
357 return;
358
359 // The `acceptAll` override is only useful for the prim we are actually
360 // querying, i.e. the *first* prim on which this function is called
361 _RecurseForInheritablePrimvars(prim.GetParent(), pvPrefix, primvars);
362 _AddPrimToInheritedPrimvars(prim, pvPrefix, primvars, primvars, acceptAll);
363 }
364
365 std::vector<UsdGeomPrimvar>
FindInheritablePrimvars() const366 UsdGeomPrimvarsAPI::FindInheritablePrimvars() const
367 {
368 TRACE_FUNCTION();
369 // Assume the number of primvars is relatively bounded and
370 // just use a vector to accumulate primvars up to the root prim.
371 std::vector<UsdGeomPrimvar> primvars;
372 const UsdPrim &prim = GetPrim();
373 if (!prim) {
374 TF_CODING_ERROR("FindInheritablePrimvars called on invalid prim: %s",
375 UsdDescribe(prim).c_str());
376 return primvars;
377 }
378
379 TfToken const& prefix = UsdGeomPrimvar::_GetNamespacePrefix();
380 _RecurseForInheritablePrimvars(prim, prefix, &primvars);
381
382 return primvars;
383 }
384
385 std::vector<UsdGeomPrimvar>
FindIncrementallyInheritablePrimvars(const std::vector<UsdGeomPrimvar> & inheritedFromAncestors) const386 UsdGeomPrimvarsAPI::FindIncrementallyInheritablePrimvars(
387 const std::vector<UsdGeomPrimvar> &inheritedFromAncestors) const
388 {
389 TRACE_FUNCTION();
390
391 std::vector<UsdGeomPrimvar> primvars;
392 const UsdPrim &prim = GetPrim();
393 if (!prim) {
394 TF_CODING_ERROR("FindIncrementallyInheritablePrimvars called on invalid prim: %s",
395 UsdDescribe(prim).c_str());
396 return primvars;
397 }
398
399 TfToken const& prefix = UsdGeomPrimvar::_GetNamespacePrefix();
400 _AddPrimToInheritedPrimvars(prim, prefix,
401 &inheritedFromAncestors,
402 &primvars, /* acceptAll = */ false);
403 return primvars;
404 }
405
406 UsdGeomPrimvar
FindPrimvarWithInheritance(const TfToken & name) const407 UsdGeomPrimvarsAPI::FindPrimvarWithInheritance(const TfToken &name) const
408 {
409 TRACE_FUNCTION();
410
411 const TfToken attrName = UsdGeomPrimvar::_MakeNamespaced(name);
412 UsdPrim prim = GetPrim();
413 if (!prim) {
414 TF_CODING_ERROR("FindPrimvarWithInheritance called on invalid prim: %s",
415 UsdDescribe(prim).c_str());
416 return UsdGeomPrimvar();
417 }
418 UsdGeomPrimvar localPv = GetPrimvar(name);
419 if (localPv.HasAuthoredValue()){
420 return localPv;
421 }
422
423 for (prim = prim.GetParent(); prim && !prim.IsPseudoRoot();
424 prim = prim.GetParent()) {
425 UsdAttribute attr = prim.GetAttribute(attrName);
426 if (attr.HasAuthoredValue()) {
427 if (UsdGeomPrimvar pv = UsdGeomPrimvar(attr)) {
428 // Only constant primvars can be inherited.
429 if (pv.GetInterpolation() == UsdGeomTokens->constant) {
430 return pv;
431 } else {
432 // Non-constant interpolation blocks inheritance.
433 return UsdGeomPrimvar();
434 }
435 }
436 }
437 }
438 return localPv;
439 }
440
441 UsdGeomPrimvar
FindPrimvarWithInheritance(const TfToken & name,const std::vector<UsdGeomPrimvar> & inheritedFromAncestors) const442 UsdGeomPrimvarsAPI::FindPrimvarWithInheritance(const TfToken &name,
443 const std::vector<UsdGeomPrimvar>
444 &inheritedFromAncestors) const
445 {
446 TRACE_FUNCTION();
447
448 const UsdPrim &prim = GetPrim();
449 if (!prim) {
450 TF_CODING_ERROR("FindPrimvarWithInheritance called on invalid prim: %s",
451 UsdDescribe(prim).c_str());
452 return UsdGeomPrimvar();
453 }
454 const TfToken attrName = UsdGeomPrimvar::_MakeNamespaced(name);
455 UsdGeomPrimvar pv = GetPrimvar(attrName);
456 if (pv.HasAuthoredValue()){
457 return pv;
458 }
459
460 for (UsdGeomPrimvar const &inherited : inheritedFromAncestors) {
461 if (inherited.GetName() == attrName){
462 return inherited;
463 }
464 }
465
466 return pv;
467 }
468
469 std::vector<UsdGeomPrimvar>
FindPrimvarsWithInheritance() const470 UsdGeomPrimvarsAPI::FindPrimvarsWithInheritance() const
471 {
472 TRACE_FUNCTION();
473 // Assume the number of primvars is relatively bounded and
474 // just use a vector to accumulate primvars up to the root prim.
475 std::vector<UsdGeomPrimvar> primvars;
476 const UsdPrim &prim = GetPrim();
477 if (!prim) {
478 TF_CODING_ERROR("FindPrimvarsWithINheritance called on invalid prim: %s",
479 UsdDescribe(prim).c_str());
480 return primvars;
481 }
482
483 TfToken const& prefix = UsdGeomPrimvar::_GetNamespacePrefix();
484 _RecurseForInheritablePrimvars(prim, prefix, &primvars,
485 /* acceptAll = */ true);
486
487 return primvars;
488 }
489
490 std::vector<UsdGeomPrimvar>
FindPrimvarsWithInheritance(const std::vector<UsdGeomPrimvar> & inheritedFromAncestors) const491 UsdGeomPrimvarsAPI::FindPrimvarsWithInheritance(
492 const std::vector<UsdGeomPrimvar> &inheritedFromAncestors) const
493 {
494 TRACE_FUNCTION();
495
496 std::vector<UsdGeomPrimvar> primvars;
497 const UsdPrim &prim = GetPrim();
498 if (!prim) {
499 TF_CODING_ERROR("FindPrimvarsWithInheritance called on invalid prim: %s",
500 UsdDescribe(prim).c_str());
501 return primvars;
502 }
503
504 TfToken const& prefix = UsdGeomPrimvar::_GetNamespacePrefix();
505 _AddPrimToInheritedPrimvars(prim, prefix,
506 &inheritedFromAncestors,
507 &primvars,
508 /* acceptAll = */ true);
509
510 // If this prim contributed no primvars, then `primvars` won't have
511 // gotten a copy of `inheritedFromAncestors`, so ensure we compensate
512 return primvars.empty() ? inheritedFromAncestors : primvars;
513 }
514
515
516 bool
HasPrimvar(const TfToken & name) const517 UsdGeomPrimvarsAPI::HasPrimvar(const TfToken &name) const
518 {
519 TfToken primvarName = UsdGeomPrimvar::_MakeNamespaced(name, /* quiet */true);
520 const UsdPrim &prim = GetPrim();
521 if (!prim) {
522 TF_CODING_ERROR("HasPrimvar called on invalid prim: %s",
523 UsdDescribe(prim).c_str());
524 return false;
525 }
526 return primvarName.IsEmpty() ? false :
527 UsdGeomPrimvar::IsPrimvar(prim.GetAttribute(primvarName));
528 }
529
530 bool
HasPossiblyInheritedPrimvar(const TfToken & name) const531 UsdGeomPrimvarsAPI::HasPossiblyInheritedPrimvar(const TfToken &name) const
532 {
533 TRACE_FUNCTION();
534
535 UsdPrim prim = GetPrim();
536 if (!prim) {
537 TF_CODING_ERROR("HasPossiblyInheritedPrimvar called on invalid prim: %s",
538 UsdDescribe(prim).c_str());
539 return false;
540 }
541 UsdGeomPrimvar pv = GetPrimvar(name);
542 if (pv.HasAuthoredValue()){
543 return true;
544 }
545
546 const TfToken attrName = UsdGeomPrimvar::_MakeNamespaced(name);
547 if (attrName.IsEmpty()) {
548 return false;
549 }
550 for (prim = prim.GetParent(); prim && !prim.IsPseudoRoot();
551 prim = prim.GetParent()) {
552 UsdAttribute attr = prim.GetAttribute(attrName);
553 if (attr.HasAuthoredValue() && UsdGeomPrimvar::IsPrimvar(attr)) {
554 // Only constant primvars can be inherited.
555 // Non-constant interpolation blocks inheritance.
556 return UsdGeomPrimvar(attr).GetInterpolation()
557 == UsdGeomTokens->constant;
558 }
559 }
560 return false;
561 }
562
563 /* static */
564 bool
CanContainPropertyName(const TfToken & name)565 UsdGeomPrimvarsAPI::CanContainPropertyName(const TfToken& name)
566 {
567 TfToken const& prefix = UsdGeomPrimvar::_GetNamespacePrefix();
568 return TfStringStartsWith(name, prefix);
569 }
570
571 PXR_NAMESPACE_CLOSE_SCOPE
572