Loading...
Searching...
No Matches
primData.h
Go to the documentation of this file.
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
28
29#include "pxr/pxr.h"
30#include "pxr/usd/usd/api.h"
31#include "pxr/usd/usd/common.h"
33#include "pxr/usd/usd/primDefinition.h"
34#include "pxr/usd/usd/primTypeInfo.h"
35#include "pxr/usd/sdf/types.h"
36
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/intrusive_ptr.hpp>
44
45#include <atomic>
46#include <cstdint>
47#include <vector>
48
49PXR_NAMESPACE_OPEN_SCOPE
50
52
53// Private class that stores cached prim information and defines the prim tree
54// on a UsdStage.
55//
56// Usd_PrimData objects are arranged in a tree structure, represented as a
57// binary tree. See the _firstChild and _nextSiblingOrParent members.
58//
59// UsdStage builds and manages the tree structure of Usd_PrimData objects. The
60// Usd_PrimData objects lifetimes are governed by an internal reference count
61// (see _refCount). Two objects mutate this reference count: UsdStage owns
62// references to all the Usd_PrimData objects that represent the scene graph,
63// and UsdObject (and by inheritance its subclasses) owns a reference to its
64// prim data object via Usd_PrimDataHandle.
65//
66// Usd_PrimData has a 'dead' flag (see _IsDead and _MarkDead). UsdStage sets
67// this when a prim data object is removed from the scene graph.
68// Usd_PrimDataHandle, which is a smart pointer to Usd_PrimData consults this
69// dead flag to determine prim validity, and to issue informative crash messages
70// on invalid use. See USD_CHECK_ALL_PRIM_ACCESSES.
71//
72class Usd_PrimData
73{
74public:
75
76 // --------------------------------------------------------------------- //
78 // --------------------------------------------------------------------- //
79
86 const SdfPath &GetPath() const { return _path; }
87
88 const TfToken &GetName() const { return GetPath().GetNameToken(); }
89
90 UsdStage *GetStage() const { return _stage; }
91
93 const UsdPrimDefinition &GetPrimDefinition() const {
94 return _primTypeInfo->GetPrimDefinition();
95 }
96
99 const TfToken& GetTypeName() const {
100 return _primTypeInfo->GetTypeName();
101 }
102
104 const UsdPrimTypeInfo &GetPrimTypeInfo() const {
105 return *_primTypeInfo;
106 }
107
109 bool IsPseudoRoot() const { return _flags[Usd_PrimPseudoRootFlag]; }
110
113 bool IsActive() const { return _flags[Usd_PrimActiveFlag]; }
114
118 bool IsLoaded() const { return _flags[Usd_PrimLoadedFlag]; }
119
122 bool IsModel() const { return _flags[Usd_PrimModelFlag]; }
123
127 bool IsGroup() const { return _flags[Usd_PrimGroupFlag]; }
128
129 bool IsComponent() const { return _flags[Usd_PrimComponentFlag]; }
130
131 USD_API
132 bool IsSubComponent() const;
133
135 bool IsAbstract() const { return _flags[Usd_PrimAbstractFlag]; }
136
139 bool IsDefined() const { return _flags[Usd_PrimDefinedFlag]; }
140
143 bool HasDefiningSpecifier() const {
144 return _flags[Usd_PrimHasDefiningSpecifierFlag];
145 }
146
148 bool HasPayload() const { return _flags[Usd_PrimHasPayloadFlag]; }
149
153 bool MayHaveOpinionsInClips() const { return _flags[Usd_PrimClipsFlag]; }
154
156 USD_API
157 SdfSpecifier GetSpecifier() const;
158
159 // --------------------------------------------------------------------- //
161 // --------------------------------------------------------------------- //
162
164 USD_API
165 Usd_PrimDataConstPtr GetParent() const;
166
167 // --------------------------------------------------------------------- //
168 // PrimIndex access.
169 // --------------------------------------------------------------------- //
170
187 USD_API
188 const class PcpPrimIndex &GetPrimIndex() const;
189
196 USD_API
197 const class PcpPrimIndex &GetSourcePrimIndex() const;
198
199 // --------------------------------------------------------------------- //
200 // Tree Structure
201 // --------------------------------------------------------------------- //
202
203 // Return this prim data's first child if it has one, nullptr otherwise.
204 Usd_PrimDataPtr GetFirstChild() const { return _firstChild; }
205
206 // Return this prim data's next sibling if it has one, nullptr otherwise.
207 Usd_PrimDataPtr GetNextSibling() const {
208 return !_nextSiblingOrParent.BitsAs<bool>() ?
209 _nextSiblingOrParent.Get() : nullptr;
210 }
211
212 // Return this prim data's parent if this prim data is the last in its chain
213 // of siblings. That is, if the _nextSiblingOrParent field is pointing to
214 // its parent. Return nullptr otherwise.
215 Usd_PrimDataPtr GetParentLink() const {
216 return _nextSiblingOrParent.BitsAs<bool>() ?
217 _nextSiblingOrParent.Get() : nullptr;
218 }
219
220 // Return the next prim data "to the right" of this one. That is, this
221 // prim's next sibling if it has one, otherwise the next sibling of the
222 // nearest ancestor with a sibling, if there is one, otherwise null.
223 inline Usd_PrimDataPtr GetNextPrim() const {
224 if (Usd_PrimDataPtr sibling = GetNextSibling())
225 return sibling;
226 for (Usd_PrimDataPtr p = GetParentLink(); p; p = p->GetParentLink()) {
227 if (Usd_PrimDataPtr sibling = p->GetNextSibling())
228 return sibling;
229 }
230 return nullptr;
231 }
232
233 // Return the prim data at \p path. If \p path indicates a prim
234 // beneath an instance, return the prim data for the corresponding
235 // prim in the instance's prototype.
236 USD_API Usd_PrimDataConstPtr
237 GetPrimDataAtPathOrInPrototype(const SdfPath &path) const;
238
239 // --------------------------------------------------------------------- //
240 // Instancing
241 // --------------------------------------------------------------------- //
242
245 bool IsInstance() const { return _flags[Usd_PrimInstanceFlag]; }
246
248 bool IsPrototype() const {
249 return IsInPrototype() && GetPath().IsRootPrimPath();
250 }
251
254 bool IsInPrototype() const { return _flags[Usd_PrimPrototypeFlag]; }
255
258 USD_API Usd_PrimDataConstPtr GetPrototype() const;
259
260 // --------------------------------------------------------------------- //
261 // Private Members
262 // --------------------------------------------------------------------- //
263private:
264
265 USD_API
266 Usd_PrimData(UsdStage *stage, const SdfPath& path);
267 USD_API
268 ~Usd_PrimData();
269
270 // Compute and store type info and cached flags.
271 void _ComposeAndCacheFlags(
272 Usd_PrimDataConstPtr parent, bool isPrototypePrim);
273
274 // Flags direct access for Usd_PrimFlagsPredicate.
275 friend class Usd_PrimFlagsPredicate;
276 const Usd_PrimFlagBits &_GetFlags() const {
277 return _flags;
278 }
279
280 // --------------------------------------------------------------------- //
281 // Prim Children
282 // --------------------------------------------------------------------- //
283
284 // Composes the prim children, reporting errors as they occur. Returns true
285 // on success false on failure.
286 bool _ComposePrimChildNames(TfTokenVector* nameOrder);
287
288 void _SetSiblingLink(Usd_PrimDataPtr sibling) {
289 _nextSiblingOrParent.Set(sibling, /* isParent */ false);
290 }
291
292 void _SetParentLink(Usd_PrimDataPtr parent) {
293 _nextSiblingOrParent.Set(parent, /* isParent */ true);
294 }
295
296 // Set the dead bit on this prim data object.
297 void _MarkDead() {
298 _flags[Usd_PrimDeadFlag] = true;
299 _stage = nullptr;
300 _primIndex = nullptr;
301 }
302
303 // Return true if this prim's dead flag is set, false otherwise.
304 bool _IsDead() const { return _flags[Usd_PrimDeadFlag]; }
305
306 // Set whether this prim or any of its namespace ancestors had clips
307 // specified.
308 void _SetMayHaveOpinionsInClips(bool hasClips) {
309 _flags[Usd_PrimClipsFlag] = hasClips;
310 }
311
312 inline class Usd_PrimDataSiblingIterator _ChildrenBegin() const;
313 inline class Usd_PrimDataSiblingIterator _ChildrenEnd() const;
314
315 inline class Usd_PrimDataSubtreeIterator _SubtreeBegin() const;
316 inline class Usd_PrimDataSubtreeIterator _SubtreeEnd() const;
317
318 // Data members.
319 UsdStage *_stage;
320 const PcpPrimIndex *_primIndex;
321 SdfPath _path;
322 const UsdPrimTypeInfo *_primTypeInfo;
323 Usd_PrimData *_firstChild;
324 TfPointerAndBits<Usd_PrimData> _nextSiblingOrParent;
325 mutable std::atomic<int64_t> _refCount;
326 Usd_PrimFlagBits _flags;
327
328 // intrusive_ptr core primitives implementation.
329 friend void intrusive_ptr_add_ref(const Usd_PrimData *prim) {
330 prim->_refCount.fetch_add(1, std::memory_order_relaxed);
331 }
332 friend void intrusive_ptr_release(const Usd_PrimData *prim) {
333 if (prim->_refCount.fetch_sub(1, std::memory_order_release) == 1)
334 delete prim;
335 }
336
337 USD_API
338 friend void Usd_ThrowExpiredPrimAccessError(Usd_PrimData const *p);
339 friend std::string
340 Usd_DescribePrimData(const Usd_PrimData *p, SdfPath const &proxyPrimPath);
341
342 friend inline bool Usd_IsDead(Usd_PrimData const *p) {
343 return p->_IsDead();
344 }
345
346 friend class UsdPrim;
347 friend class UsdStage;
348};
349
350// Sibling iterator class.
351class Usd_PrimDataSiblingIterator {
352 using _UnderylingIterator = Usd_PrimData*;
353public:
354 using iterator_category = std::forward_iterator_tag;
355 using value_type = Usd_PrimData*;
356 using reference = Usd_PrimData*;
357 using pointer = void;
358 using difference_type = std::ptrdiff_t;
359
360 // Default ctor.
361 Usd_PrimDataSiblingIterator() = default;
362
363 reference operator*() const { return _underlyingIterator; }
364
365 // pre-increment
366 Usd_PrimDataSiblingIterator& operator++() {
367 increment();
368 return *this;
369 }
370
371 // post-increment
372 Usd_PrimDataSiblingIterator operator++(int) {
373 Usd_PrimDataSiblingIterator result = *this;
374 increment();
375 return result;
376 }
377
378 bool operator==(const Usd_PrimDataSiblingIterator& other) const {
379 return _underlyingIterator == other._underlyingIterator;
380 }
381
382 bool operator!=(const Usd_PrimDataSiblingIterator& other) const {
383 return _underlyingIterator != other._underlyingIterator;
384 }
385
386private:
387 friend class Usd_PrimData;
388
389 // Constructor used by Prim.
390 Usd_PrimDataSiblingIterator(const _UnderylingIterator &i)
391 : _underlyingIterator(i) {}
392
393 void increment() {
394 _underlyingIterator = _underlyingIterator->GetNextSibling();
395 }
396
397 _UnderylingIterator _underlyingIterator = nullptr;
398};
399
400Usd_PrimDataSiblingIterator
401Usd_PrimData::_ChildrenBegin() const
402{
403 return Usd_PrimDataSiblingIterator(_firstChild);
404}
405
406Usd_PrimDataSiblingIterator
407Usd_PrimData::_ChildrenEnd() const
408{
409 return Usd_PrimDataSiblingIterator(0);
410}
411
412// Tree iterator class.
413class Usd_PrimDataSubtreeIterator {
414 using _UnderlyingIterator = Usd_PrimData*;
415public:
416 using iterator_category = std::forward_iterator_tag;
417 using value_type = Usd_PrimData*;
418 using reference = Usd_PrimData*;
419 using pointer = void;
420 using difference_type = std::ptrdiff_t;
421
422 // Default ctor.
423 Usd_PrimDataSubtreeIterator() = default;
424
425 reference operator*() const { return _underlyingIterator; }
426
427 // pre-increment
428 Usd_PrimDataSubtreeIterator& operator++() {
429 increment();
430 return *this;
431 }
432
433 // post-increment
434 Usd_PrimDataSubtreeIterator operator++(int) {
435 Usd_PrimDataSubtreeIterator result = *this;
436 increment();
437 return result;
438 }
439
440 bool operator==(const Usd_PrimDataSubtreeIterator& other) const {
441 return _underlyingIterator == other._underlyingIterator;
442 }
443
444 bool operator!=(const Usd_PrimDataSubtreeIterator& other) const {
445 return _underlyingIterator != other._underlyingIterator;
446 }
447
448private:
449 friend class Usd_PrimData;
450 friend class UsdPrimSubtreeIterator;
451
452 // Constructor used by Prim.
453 Usd_PrimDataSubtreeIterator(const _UnderlyingIterator &i)
454 : _underlyingIterator(i) {}
455
456 void increment() {
457 _underlyingIterator = _underlyingIterator->GetFirstChild() ?
458 _underlyingIterator->GetFirstChild() :
459 _underlyingIterator->GetNextPrim();
460 }
461
462 _UnderlyingIterator _underlyingIterator = nullptr;
463};
464
465Usd_PrimDataSubtreeIterator
466Usd_PrimData::_SubtreeBegin() const
467{
468 return Usd_PrimDataSubtreeIterator(
469 _firstChild ? _firstChild : GetNextPrim());
470}
471
472Usd_PrimDataSubtreeIterator
473Usd_PrimData::_SubtreeEnd() const
474{
475 return Usd_PrimDataSubtreeIterator(GetNextPrim());
476}
477
478// Helpers for instance proxies.
479
480// Return true if the prim with prim data \p p and proxy prim path
481// \p proxyPrimPath represents an instance proxy.
482template <class PrimDataPtr>
483inline bool
484Usd_IsInstanceProxy(const PrimDataPtr &p, const SdfPath &proxyPrimPath)
485{
486 return !proxyPrimPath.IsEmpty();
487}
488
489// Helpers for subtree traversals.
490
491// Create a predicate based on \p pred for use when traversing the
492// siblings or descendants of the prim with prim data \p p and proxy
493// prim path \p proxyPrimPath. This is used by prim traversal functions
494// like UsdPrim::GetFilteredChildren, UsdPrim::GetFilteredDescendants,
495// UsdPrim::GetFilteredNextSibling, and UsdPrimRange.
496template <class PrimDataPtr>
497inline Usd_PrimFlagsPredicate
498Usd_CreatePredicateForTraversal(const PrimDataPtr &p,
499 const SdfPath &proxyPrimPath,
500 Usd_PrimFlagsPredicate pred)
501{
502 // Don't allow traversals beneath instances unless the client has
503 // explicitly requested it or the starting point is already beneath
504 // an instance (i.e., the starting point is an instance proxy).
505 if (!Usd_IsInstanceProxy(p, proxyPrimPath) &&
506 !pred.IncludeInstanceProxiesInTraversal()) {
507 pred.TraverseInstanceProxies(false);
508 }
509 return pred;
510}
511
512// Move \p p to its parent. If \p proxyPrimPath is not empty, set it to
513// its parent path. If after this \p p is a prototype prim, move \p p to
514// the prim indicated by \p proxyPrimPath. If \p p's path is then equal
515// to \p proxyPrimPath, set \p proxyPrimPath to the empty path.
516template <class PrimDataPtr>
517inline void
518Usd_MoveToParent(PrimDataPtr &p, SdfPath &proxyPrimPath)
519{
520 p = p->GetParent();
521
522 if (!proxyPrimPath.IsEmpty()) {
523 proxyPrimPath = proxyPrimPath.GetParentPath();
524
525 if (p && p->IsPrototype()) {
526 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
527 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
528 p->GetPath() == proxyPrimPath) {
529 proxyPrimPath = SdfPath();
530 }
531 }
532 }
533}
534
535// Search for the next sibling that matches \p pred (up to \p end). If such a
536// sibling exists, move \p p to it and return false. If no such sibling exists
537// then move \p p to its parent and return true. If \p end is reached while
538// looking for siblings, move \p p to \p end and return false.
539//
540// If \p proxyPrimPath is not empty, update it based on the new value of \p p:
541// - If \p p was moved to \p end, set \p proxyPrimPath to the empty path.
542// - If \p p was moved to a sibling, set the prim name for \p proxyPrimPath
543// to the sibling's name.
544// - If \p p was moved to a parent, set \p proxyPrimPath and \p p the same
545// way as Usd_MoveToParent.
546template <class PrimDataPtr>
547inline bool
548Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
549 PrimDataPtr end,
550 const Usd_PrimFlagsPredicate &pred)
551{
552 // Either all siblings are instance proxies or none are. We can just
553 // compute this once and reuse it as we scan for the next sibling.
554 const bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
555
556 PrimDataPtr next = p->GetNextSibling();
557 while (next && next != end &&
558 !Usd_EvalPredicate(pred, next, isInstanceProxy)) {
559 p = next;
560 next = p->GetNextSibling();
561 }
562 p = next ? next : p->GetParentLink();
563
564 if (!proxyPrimPath.IsEmpty()) {
565 if (p == end) {
566 proxyPrimPath = SdfPath();
567 }
568 else if (p == next) {
569 proxyPrimPath =
570 proxyPrimPath.GetParentPath().AppendChild(p->GetName());
571 }
572 else {
573 proxyPrimPath = proxyPrimPath.GetParentPath();
574 if (p && p->IsPrototype()) {
575 p = p->GetPrimDataAtPathOrInPrototype(proxyPrimPath);
576 if (TF_VERIFY(p, "No prim at <%s>", proxyPrimPath.GetText()) &&
577 p->GetPath() == proxyPrimPath) {
578 proxyPrimPath = SdfPath();
579 }
580 }
581 }
582 }
583
584 // Return true if we successfully moved to a parent, otherwise false.
585 return !next && p;
586}
587
588// Convenience method for calling the above with \p end = \c nullptr.
589template <class PrimDataPtr>
590inline bool
591Usd_MoveToNextSiblingOrParent(PrimDataPtr &p, SdfPath &proxyPrimPath,
592 const Usd_PrimFlagsPredicate &pred)
593{
594 return Usd_MoveToNextSiblingOrParent(p, proxyPrimPath,
595 PrimDataPtr(nullptr), pred);
596}
597
598// Search for the first direct child of \p p that matches \p pred (up to
599// \p end). If the given \p p is an instance, search for direct children
600// on the corresponding prototype prim. If such a direct child exists,
601// move \p p to it, and return true. Otherwise leave the iterator
602// unchanged and return false.
603template <class PrimDataPtr>
604inline bool
605Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
606 PrimDataPtr end,
607 const Usd_PrimFlagsPredicate &pred)
608{
609 bool isInstanceProxy = Usd_IsInstanceProxy(p, proxyPrimPath);
610
611 PrimDataPtr src = p;
612 if (src->IsInstance()) {
613 src = src->GetPrototype();
614 isInstanceProxy = true;
615 }
616
617 if (PrimDataPtr child = src->GetFirstChild()) {
618 if (isInstanceProxy) {
619 proxyPrimPath = proxyPrimPath.IsEmpty() ?
620 p->GetPath().AppendChild(child->GetName()) :
621 proxyPrimPath.AppendChild(child->GetName());
622 }
623
624 p = child;
625
626 if (Usd_EvalPredicate(pred, p, isInstanceProxy) ||
627 !Usd_MoveToNextSiblingOrParent(p, proxyPrimPath, end, pred)) {
628 return true;
629 }
630 }
631 return false;
632}
633
634// Convenience method for calling the above with \p end = \c nullptr.
635template <class PrimDataPtr>
636inline bool
637Usd_MoveToChild(PrimDataPtr &p, SdfPath &proxyPrimPath,
638 const Usd_PrimFlagsPredicate &pred)
639{
640 return Usd_MoveToChild(p, proxyPrimPath, PrimDataPtr(nullptr), pred);
641}
642
643PXR_NAMESPACE_CLOSE_SCOPE
644
645#endif // PXR_USD_USD_PRIM_DATA_H
PcpPrimIndex is an index of the all sites of scene description that contribute opinions to a specific...
Definition: primIndex.h:78
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:291
SDF_API SdfPath GetParentPath() const
Return the path that identifies this path's namespace parent.
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:415
SDF_API SdfPath AppendChild(TfToken const &childName) const
Creates a path by appending an element for childName to this path.
This class stores a T * and a small integer in the space of a T *.
Token for efficient comparison, assignment, and hashing of known strings.
Definition: token.h:88
Class representing the builtin definition of a prim given the schemas registered in the schema regist...
UsdPrim is the sole persistent scenegraph object on a UsdStage, and is the embodiment of a "Prim" as ...
Definition: prim.h:134
Forward traversal iterator of sibling UsdPrim s.
Definition: prim.h:2541
Class that holds the full type information for a prim.
Definition: primTypeInfo.h:48
The outermost container for scene description, which owns and presents composed prims as a scenegraph...
Definition: stage.h:151
Standard pointer typedefs.
#define TF_DECLARE_WEAK_PTRS(type)
Define standard weak pointer types.
Definition: declarePtrs.h:62
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:283
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...
std::vector< TfToken > TfTokenVector
Convenience types.
Definition: token.h:457
Basic Sdf data types.
SdfSpecifier
An enum that identifies the possible specifiers for an SdfPrimSpec.
Definition: types.h:116