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 #ifndef PXR_USD_USD_PRIM_DATA_H 25 #define PXR_USD_USD_PRIM_DATA_H 26 27 /// \file usd/primData.h 28 29 #include "pxr/pxr.h" 30 #include "pxr/usd/usd/api.h" 31 #include "pxr/usd/usd/common.h" 32 #include "pxr/usd/usd/primFlags.h" 33 #include "pxr/usd/usd/primDefinition.h" 34 #include "pxr/usd/usd/primTypeInfo.h" 35 #include "pxr/usd/sdf/types.h" 36 37 #include "pxr/base/tf/declarePtrs.h" 38 #include "pxr/base/tf/pointerAndBits.h" 39 #include "pxr/base/tf/token.h" 40 41 #include "pxr/usd/sdf/path.h" 42 43 #include <boost/range/iterator_range.hpp> 44 #include <boost/iterator/iterator_adaptor.hpp> 45 #include <boost/intrusive_ptr.hpp> 46 47 #include <atomic> 48 #include <cstdint> 49 #include <vector> 50 51 PXR_NAMESPACE_OPEN_SCOPE 52 53 TF_DECLARE_WEAK_PTRS(UsdStage); 54 55 // Private class that stores cached prim information and defines the prim tree 56 // on a UsdStage. 57 // 58 // Usd_PrimData objects are arranged in a tree structure, represented as a 59 // binary tree. See the _firstChild and _nextSiblingOrParent members. 60 // 61 // UsdStage builds and manages the tree structure of Usd_PrimData objects. The 62 // Usd_PrimData objects lifetimes are governed by an internal reference count 63 // (see _refCount). Two objects mutate this reference count: UsdStage owns 64 // references to all the Usd_PrimData objects that represent the scene graph, 65 // and UsdObject (and by inheritance its subclasses) owns a reference to its 66 // prim data object via Usd_PrimDataHandle. 67 // 68 // Usd_PrimData has a 'dead' flag (see _IsDead and _MarkDead). UsdStage sets 69 // this when a prim data object is removed from the scene graph. 70 // Usd_PrimDataHandle, which is a smart pointer to Usd_PrimData consults this 71 // dead flag to determine prim validity, and to issue informative crash messages 72 // on invalid use. See USD_CHECK_ALL_PRIM_ACCESSES. 73 // 74 class Usd_PrimData 75 { 76 public: 77 78 // --------------------------------------------------------------------- // 79 /// \name Prim Data & Behavior 80 // --------------------------------------------------------------------- // 81 82 /// Returns the composed path for the prim. 83 /// 84 /// This path is absolute with respect to the current stage and may require 85 /// translation when used in the context of individual layers of which the 86 /// current stage is composed. 87 /// This always returns a cached result. GetPath()88 const SdfPath &GetPath() const { return _path; } 89 GetName()90 const TfToken &GetName() const { return GetPath().GetNameToken(); } 91 GetStage()92 UsdStage *GetStage() const { return _stage; } 93 94 /// Returns the prim definition for this prim. GetPrimDefinition()95 const UsdPrimDefinition &GetPrimDefinition() const { 96 return _primTypeInfo->GetPrimDefinition(); 97 } 98 99 /// Returns the composed type name for the prim. 100 /// Note that this value is cached and is efficient to query. GetTypeName()101 const TfToken& GetTypeName() const { 102 return _primTypeInfo->GetTypeName(); 103 } 104 105 /// Returns the full type info for the prim. GetPrimTypeInfo()106 const UsdPrimTypeInfo &GetPrimTypeInfo() const { 107 return *_primTypeInfo; 108 } 109 110 /// Returns true if this prim is the pseudoroot. IsPseudoRoot()111 bool IsPseudoRoot() const { return _flags[Usd_PrimPseudoRootFlag]; } 112 113 /// Return true if this prim is active, meaning neither it nor any of its 114 /// ancestors have active=false. Return false otherwise. IsActive()115 bool IsActive() const { return _flags[Usd_PrimActiveFlag]; } 116 117 /// Return true if this prim is active, and \em either it is loadable and 118 /// it is loaded, \em or its nearest loadable ancestor is loaded, \em or it 119 /// has no loadable ancestor; false otherwise. IsLoaded()120 bool IsLoaded() const { return _flags[Usd_PrimLoadedFlag]; } 121 122 /// Return true if this prim is a model based on its kind metadata, false 123 /// otherwise. IsModel()124 bool IsModel() const { return _flags[Usd_PrimModelFlag]; } 125 126 /// Return true if this prim is a model group based on its kind metadata, 127 /// false otherwise. If this prim is a group, it is also necessarily a 128 /// model. IsGroup()129 bool IsGroup() const { return _flags[Usd_PrimGroupFlag]; } 130 131 /// Return true if this prim or any of its ancestors is a class. IsAbstract()132 bool IsAbstract() const { return _flags[Usd_PrimAbstractFlag]; } 133 134 /// Return true if this prim and all its ancestors have defining specifiers, 135 /// false otherwise. \sa SdfIsDefiningSpecifier. IsDefined()136 bool IsDefined() const { return _flags[Usd_PrimDefinedFlag]; } 137 138 /// Return true if this prim has a specifier of type SdfSpecifierDef 139 /// or SdfSpecifierClass. HasDefiningSpecifier()140 bool HasDefiningSpecifier() const { 141 return _flags[Usd_PrimHasDefiningSpecifierFlag]; 142 } 143 144 /// Return true if this prim has one or more payload composition arcs. HasPayload()145 bool HasPayload() const { return _flags[Usd_PrimHasPayloadFlag]; } 146 147 /// Return true if attributes on this prim may have opinions in clips, 148 /// false otherwise. If true, the relevant clips will be examined for 149 /// opinions during value resolution. MayHaveOpinionsInClips()150 bool MayHaveOpinionsInClips() const { return _flags[Usd_PrimClipsFlag]; } 151 152 /// Return this prim's composed specifier. 153 USD_API 154 SdfSpecifier GetSpecifier() const; 155 156 // --------------------------------------------------------------------- // 157 /// \name Parent & Stage 158 // --------------------------------------------------------------------- // 159 160 /// Return this prim's parent prim. Return nullptr if this is a root prim. 161 USD_API 162 Usd_PrimDataConstPtr GetParent() const; 163 164 // --------------------------------------------------------------------- // 165 // PrimIndex access. 166 // --------------------------------------------------------------------- // 167 168 /// Return a const reference to the PcpPrimIndex for this prim. 169 /// 170 /// The prim's PcpPrimIndex can be used to examine the scene description 171 /// sites that contribute to the prim's property and metadata values in 172 /// minute detail. 173 /// 174 /// For prototype prims this prim index will be empty; this ensures 175 /// that these prims do not provide any attribute or metadata 176 /// values. 177 /// 178 /// For all other prims in prototypes, this is the prim index for the 179 /// instance that was chosen to serve as the prototype for all other 180 /// instances. 181 /// 182 /// In either of the above two cases, this prim index will not have the 183 /// same path as the prim's path. 184 USD_API 185 const class PcpPrimIndex &GetPrimIndex() const; 186 187 /// Return a const reference to the source PcpPrimIndex for this prim. 188 /// 189 /// For all prims in prototypes (which includes the prototype prim itself), 190 /// this is the prim index for the instance that was chosen to serve 191 /// as the prototype for all other instances. This prim index will not 192 /// have the same path as the prim's path. 193 USD_API 194 const class PcpPrimIndex &GetSourcePrimIndex() const; 195 196 // --------------------------------------------------------------------- // 197 // Tree Structure 198 // --------------------------------------------------------------------- // 199 200 // Return this prim data's first child if it has one, nullptr otherwise. GetFirstChild()201 Usd_PrimDataPtr GetFirstChild() const { return _firstChild; } 202 203 // Return this prim data's next sibling if it has one, nullptr otherwise. GetNextSibling()204 Usd_PrimDataPtr GetNextSibling() const { 205 return !_nextSiblingOrParent.BitsAs<bool>() ? 206 _nextSiblingOrParent.Get() : nullptr; 207 } 208 209 // Return this prim data's parent if this prim data is the last in its chain 210 // of siblings. That is, if the _nextSiblingOrParent field is pointing to 211 // its parent. Return nullptr otherwise. GetParentLink()212 Usd_PrimDataPtr GetParentLink() const { 213 return _nextSiblingOrParent.BitsAs<bool>() ? 214 _nextSiblingOrParent.Get() : nullptr; 215 } 216 217 // Return the next prim data "to the right" of this one. That is, this 218 // prim's next sibling if it has one, otherwise the next sibling of the 219 // nearest ancestor with a sibling, if there is one, otherwise null. GetNextPrim()220 inline Usd_PrimDataPtr GetNextPrim() const { 221 if (Usd_PrimDataPtr sibling = GetNextSibling()) 222 return sibling; 223 for (Usd_PrimDataPtr p = GetParentLink(); p; p = p->GetParentLink()) { 224 if (Usd_PrimDataPtr sibling = p->GetNextSibling()) 225 return sibling; 226 } 227 return nullptr; 228 } 229 230 // Return the prim data at \p path. If \p path indicates a prim 231 // beneath an instance, return the prim data for the corresponding 232 // prim in the instance's prototype. 233 USD_API Usd_PrimDataConstPtr 234 GetPrimDataAtPathOrInPrototype(const SdfPath &path) const; 235 236 // --------------------------------------------------------------------- // 237 // Instancing 238 // --------------------------------------------------------------------- // 239 240 /// Return true if this prim is an instance of a shared prototype prim, 241 /// false otherwise. IsInstance()242 bool IsInstance() const { return _flags[Usd_PrimInstanceFlag]; } 243 244 /// Return true if this prim is a shared prototype prim, false otherwise. IsPrototype()245 bool IsPrototype() const { 246 return IsInPrototype() && GetPath().IsRootPrimPath(); 247 } 248 249 /// Return true if this prim is a child of a shared prototype prim, 250 /// false otherwise. IsInPrototype()251 bool IsInPrototype() const { return _flags[Usd_PrimPrototypeFlag]; } 252 253 /// If this prim is an instance, return the prim data for the corresponding 254 /// prototype. Otherwise, return nullptr. 255 USD_API Usd_PrimDataConstPtr GetPrototype() const; 256 257 // --------------------------------------------------------------------- // 258 // Private Members 259 // --------------------------------------------------------------------- // 260 private: 261 262 USD_API 263 Usd_PrimData(UsdStage *stage, const SdfPath& path); 264 USD_API 265 ~Usd_PrimData(); 266 267 // Compute and store type info and cached flags. 268 void _ComposeAndCacheFlags( 269 Usd_PrimDataConstPtr parent, bool isPrototypePrim); 270 271 // Flags direct access for Usd_PrimFlagsPredicate. 272 friend class Usd_PrimFlagsPredicate; _GetFlags()273 const Usd_PrimFlagBits &_GetFlags() const { 274 return _flags; 275 } 276 277 // --------------------------------------------------------------------- // 278 // Prim Children 279 // --------------------------------------------------------------------- // 280 281 // Composes the prim children, reporting errors as they occur. Returns true 282 // on success false on failure. 283 bool _ComposePrimChildNames(TfTokenVector* nameOrder); 284 _SetSiblingLink(Usd_PrimDataPtr sibling)285 void _SetSiblingLink(Usd_PrimDataPtr sibling) { 286 _nextSiblingOrParent.Set(sibling, /* isParent */ false); 287 } 288 _SetParentLink(Usd_PrimDataPtr parent)289 void _SetParentLink(Usd_PrimDataPtr parent) { 290 _nextSiblingOrParent.Set(parent, /* isParent */ true); 291 } 292 293 // Set the dead bit on this prim data object. _MarkDead()294 void _MarkDead() { 295 _flags[Usd_PrimDeadFlag] = true; 296 _stage = nullptr; 297 _primIndex = nullptr; 298 } 299 300 // Return true if this prim's dead flag is set, false otherwise. _IsDead()301 bool _IsDead() const { return _flags[Usd_PrimDeadFlag]; } 302 303 // Set whether this prim or any of its namespace ancestors had clips 304 // specified. _SetMayHaveOpinionsInClips(bool hasClips)305 void _SetMayHaveOpinionsInClips(bool hasClips) { 306 _flags[Usd_PrimClipsFlag] = hasClips; 307 } 308 309 typedef boost::iterator_range< 310 class Usd_PrimDataSiblingIterator> SiblingRange; 311 312 inline class Usd_PrimDataSiblingIterator _ChildrenBegin() const; 313 inline class Usd_PrimDataSiblingIterator _ChildrenEnd() const; 314 inline SiblingRange _GetChildrenRange() const; 315 316 typedef boost::iterator_range< 317 class Usd_PrimDataSubtreeIterator> SubtreeRange; 318 319 inline class Usd_PrimDataSubtreeIterator _SubtreeBegin() const; 320 inline class Usd_PrimDataSubtreeIterator _SubtreeEnd() const; 321 inline SubtreeRange _GetSubtreeRange() const; 322 323 // Data members. 324 UsdStage *_stage; 325 const PcpPrimIndex *_primIndex; 326 SdfPath _path; 327 const UsdPrimTypeInfo *_primTypeInfo; 328 Usd_PrimData *_firstChild; 329 TfPointerAndBits<Usd_PrimData> _nextSiblingOrParent; 330 mutable std::atomic<int64_t> _refCount; 331 Usd_PrimFlagBits _flags; 332 333 // intrusive_ptr core primitives implementation. intrusive_ptr_add_ref(const Usd_PrimData * prim)334 friend void intrusive_ptr_add_ref(const Usd_PrimData *prim) { 335 prim->_refCount.fetch_add(1, std::memory_order_relaxed); 336 } intrusive_ptr_release(const Usd_PrimData * prim)337 friend void intrusive_ptr_release(const Usd_PrimData *prim) { 338 if (prim->_refCount.fetch_sub(1, std::memory_order_release) == 1) 339 delete prim; 340 } 341 342 USD_API 343 friend void Usd_ThrowExpiredPrimAccessError(Usd_PrimData const *p); 344 friend std::string 345 Usd_DescribePrimData(const Usd_PrimData *p, SdfPath const &proxyPrimPath); 346 Usd_IsDead(Usd_PrimData const * p)347 friend inline bool Usd_IsDead(Usd_PrimData const *p) { 348 return p->_IsDead(); 349 } 350 351 friend class UsdPrim; 352 friend class UsdStage; 353 }; 354 355 // Sibling iterator class. 356 class Usd_PrimDataSiblingIterator : public boost::iterator_adaptor< 357 Usd_PrimDataSiblingIterator, // crtp. 358 Usd_PrimData *, // base iterator. 359 Usd_PrimData *, // value. 360 boost::forward_traversal_tag, // traversal. 361 Usd_PrimData * // reference. 362 > 363 { 364 public: 365 // Default ctor. Usd_PrimDataSiblingIterator()366 Usd_PrimDataSiblingIterator() {} 367 368 private: 369 friend class Usd_PrimData; 370 371 // Constructor used by Prim. Usd_PrimDataSiblingIterator(const base_type & i)372 Usd_PrimDataSiblingIterator(const base_type &i) 373 : iterator_adaptor_(i) {} 374 375 // Core primitives implementation. 376 friend class boost::iterator_core_access; dereference()377 reference dereference() const { return base(); } increment()378 void increment() { 379 base_reference() = base_reference()->GetNextSibling(); 380 } 381 }; 382 383 // Sibling range. 384 typedef boost::iterator_range< 385 class Usd_PrimDataSiblingIterator> Usd_PrimDataSiblingRange; 386 387 // Inform TfIterator it should feel free to make copies of the range type. 388 template <> 389 struct Tf_ShouldIterateOverCopy< 390 Usd_PrimDataSiblingRange> : boost::true_type {}; 391 template <> 392 struct Tf_ShouldIterateOverCopy< 393 const Usd_PrimDataSiblingRange> : boost::true_type {}; 394 395 Usd_PrimDataSiblingIterator 396 Usd_PrimData::_ChildrenBegin() const 397 { 398 return Usd_PrimDataSiblingIterator(_firstChild); 399 } 400 401 Usd_PrimDataSiblingIterator 402 Usd_PrimData::_ChildrenEnd() const 403 { 404 return Usd_PrimDataSiblingIterator(0); 405 } 406 407 Usd_PrimData::SiblingRange 408 Usd_PrimData::_GetChildrenRange() const 409 { 410 return Usd_PrimData::SiblingRange(_ChildrenBegin(), _ChildrenEnd()); 411 } 412 413 414 // Tree iterator class. 415 class Usd_PrimDataSubtreeIterator : public boost::iterator_adaptor< 416 Usd_PrimDataSubtreeIterator, // crtp. 417 Usd_PrimData *, // base iterator. 418 Usd_PrimData *, // value. 419 boost::forward_traversal_tag, // traversal. 420 Usd_PrimData * // reference. 421 > 422 { 423 public: 424 // Default ctor. 425 Usd_PrimDataSubtreeIterator() {} 426 427 private: 428 friend class Usd_PrimData; 429 friend class UsdPrimSubtreeIterator; 430 431 // Constructor used by Prim. 432 Usd_PrimDataSubtreeIterator(const base_type &i) 433 : iterator_adaptor_(i) {} 434 435 // Core primitives implementation. 436 friend class boost::iterator_core_access; 437 reference dereference() const { return base(); } 438 void increment() { 439 base_type &b = base_reference(); 440 b = b->GetFirstChild() ? b->GetFirstChild() : b->GetNextPrim(); 441 } 442 }; 443 444 // Tree range. 445 typedef boost::iterator_range< 446 class Usd_PrimDataSubtreeIterator> Usd_PrimDataSubtreeRange; 447 448 // Inform TfIterator it should feel free to make copies of the range type. 449 template <> 450 struct Tf_ShouldIterateOverCopy< 451 Usd_PrimDataSubtreeRange> : boost::true_type {}; 452 template <> 453 struct Tf_ShouldIterateOverCopy< 454 const Usd_PrimDataSubtreeRange> : boost::true_type {}; 455 456 Usd_PrimDataSubtreeIterator 457 Usd_PrimData::_SubtreeBegin() const 458 { 459 return Usd_PrimDataSubtreeIterator( 460 _firstChild ? _firstChild : GetNextPrim()); 461 } 462 463 Usd_PrimDataSubtreeIterator 464 Usd_PrimData::_SubtreeEnd() const 465 { 466 return Usd_PrimDataSubtreeIterator(GetNextPrim()); 467 } 468 469 Usd_PrimData::SubtreeRange 470 Usd_PrimData::_GetSubtreeRange() const 471 { 472 return Usd_PrimData::SubtreeRange(_SubtreeBegin(), _SubtreeEnd()); 473 } 474 475 // Helpers for instance proxies. 476 477 // Return true if the prim with prim data \p p and proxy prim path 478 // \p proxyPrimPath represents an instance proxy. 479 template <class PrimDataPtr> 480 inline bool 481 Usd_IsInstanceProxy(const PrimDataPtr &p, const SdfPath &proxyPrimPath) 482 { 483 return !proxyPrimPath.IsEmpty(); 484 } 485 486 // Helpers for subtree traversals. 487 488 // Create a predicate based on \p pred for use when traversing the 489 // siblings or descendants of the prim with prim data \p p and proxy 490 // prim path \p proxyPrimPath. This is used by prim traversal functions 491 // like UsdPrim::GetFilteredChildren, UsdPrim::GetFilteredDescendants, 492 // UsdPrim::GetFilteredNextSibling, and UsdPrimRange. 493 template <class PrimDataPtr> 494 inline Usd_PrimFlagsPredicate 495 Usd_CreatePredicateForTraversal(const PrimDataPtr &p, 496 const SdfPath &proxyPrimPath, 497 Usd_PrimFlagsPredicate pred) 498 { 499 // Don't allow traversals beneath instances unless the client has 500 // explicitly requested it or the starting point is already beneath 501 // an instance (i.e., the starting point is an instance proxy). 502 if (!Usd_IsInstanceProxy(p, proxyPrimPath) && 503 !pred.IncludeInstanceProxiesInTraversal()) { 504 pred.TraverseInstanceProxies(false); 505 } 506 return pred; 507 } 508 509 // Move \p p to its parent. If \p proxyPrimPath is not empty, set it to 510 // its parent path. If after this \p p is a prototype prim, move \p p to 511 // the prim indicated by \p proxyPrimPath. If \p p's path is then equal 512 // to \p proxyPrimPath, set \p proxyPrimPath to the empty path. 513 template <class PrimDataPtr> 514 inline void 515 Usd_MoveToParent(PrimDataPtr &p, SdfPath &proxyPrimPath) 516 { 517 p = p->GetParent(); 518 519 if (!proxyPrimPath.IsEmpty()) { 520 proxyPrimPath = proxyPrimPath.GetParentPath(); 521 522 if (p && p->IsPrototype()) { 523 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath); 524 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) && 525 p->GetPath() == proxyPrimPath) { 526 proxyPrimPath = SdfPath(); 527 } 528 } 529 } 530 } 531 532 // Search for the next sibling that matches \p pred (up to \p end). If such a 533 // sibling exists, move \p p to it and return false. If no such sibling exists 534 // then move \p p to its parent and return true. If \p end is reached while 535 // looking for siblings, move \p p to \p end and return false. 536 // 537 // If \p proxyPrimPath is not empty, update it based on the new value of \p p: 538 // - If \p p was moved to \p end, set \p proxyPrimPath to the empty path. 539 // - If \p p was moved to a sibling, set the prim name for \p proxyPrimPath 540 // to the sibling's name. 541 // - If \p p was moved to a parent, set \p proxyPrimPath and \p p the same 542 // way as Usd_MoveToParent. 543 template <class PrimDataPtr> 544 inline bool 545 Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath, 546 PrimDataPtr end, 547 const Usd_PrimFlagsPredicate &pred) 548 { 549 // Either all siblings are instance proxies or none are. We can just 550 // compute this once and reuse it as we scan for the next sibling. 551 const bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath); 552 553 PrimDataPtr next = p->GetNextSibling(); 554 while (next && next != end && 555 !Usd_EvalPredicate(pred, next, isInstanceProxy)) { 556 p = next; 557 next = p->GetNextSibling(); 558 } 559 p = next ? next : p->GetParentLink(); 560 561 if (!proxyPrimPath.IsEmpty()) { 562 if (p == end) { 563 proxyPrimPath = SdfPath(); 564 } 565 else if (p == next) { 566 proxyPrimPath = 567 proxyPrimPath.GetParentPath().AppendChild(p->GetName()); 568 } 569 else { 570 proxyPrimPath = proxyPrimPath.GetParentPath(); 571 if (p && p->IsPrototype()) { 572 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath); 573 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) && 574 p->GetPath() == proxyPrimPath) { 575 proxyPrimPath = SdfPath(); 576 } 577 } 578 } 579 } 580 581 // Return true if we successfully moved to a parent, otherwise false. 582 return !next && p; 583 } 584 585 // Convenience method for calling the above with \p end = \c nullptr. 586 template <class PrimDataPtr> 587 inline bool 588 Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath, 589 const Usd_PrimFlagsPredicate &pred) 590 { 591 return Usd_MoveToNextSiblingOrParent(p, proxyPrimPath, 592 PrimDataPtr(nullptr), pred); 593 } 594 595 // Search for the first direct child of \p p that matches \p pred (up to 596 // \p end). If the given \p p is an instance, search for direct children 597 // on the corresponding prototype prim. If such a direct child exists, 598 // move \p p to it, and return true. Otherwise leave the iterator 599 // unchanged and return false. 600 template <class PrimDataPtr> 601 inline bool 602 Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath, 603 PrimDataPtr end, 604 const Usd_PrimFlagsPredicate &pred) 605 { 606 bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath); 607 608 PrimDataPtr src = p; 609 if (src->IsInstance()) { 610 src = src->GetPrototype(); 611 isInstanceProxy = true; 612 } 613 614 if (PrimDataPtr child = src->GetFirstChild()) { 615 if (isInstanceProxy) { 616 proxyPrimPath = proxyPrimPath.IsEmpty() ? 617 p->GetPath().AppendChild(child->GetName()) : 618 proxyPrimPath.AppendChild(child->GetName()); 619 } 620 621 p = child; 622 623 if (Usd_EvalPredicate(pred, p, isInstanceProxy) || 624 !Usd_MoveToNextSiblingOrParent(p, proxyPrimPath, end, pred)) { 625 return true; 626 } 627 } 628 return false; 629 } 630 631 // Convenience method for calling the above with \p end = \c nullptr. 632 template <class PrimDataPtr> 633 inline bool 634 Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath, 635 const Usd_PrimFlagsPredicate &pred) 636 { 637 return Usd_MoveToChild(p, proxyPrimPath, PrimDataPtr(nullptr), pred); 638 } 639 640 PXR_NAMESPACE_CLOSE_SCOPE 641 642 #endif // PXR_USD_USD_PRIM_DATA_H 643