diff --git a/pxr/usd/usd/prim.h b/pxr/usd/usd/prim.h index c47bff6a888..01ba29a677c 100644 --- a/pxr/usd/usd/prim.h +++ b/pxr/usd/usd/prim.h @@ -289,6 +289,12 @@ class UsdPrim : public UsdObject return _Prim()->HasDefiningSpecifier(); } + /// Return true if this prim has a specifier of type SdfSpecifierClass. + /// \sa SdfIsAbstractSpecifier + bool HasAbstractSpecifier() const { + return _Prim()->HasAbstractSpecifier(); + } + /// Return a vector containing the names of API schemas which have /// been applied to this prim. /// diff --git a/pxr/usd/usd/primData.cpp b/pxr/usd/usd/primData.cpp index 92e82829e9f..1c7a15f3677 100644 --- a/pxr/usd/usd/primData.cpp +++ b/pxr/usd/usd/primData.cpp @@ -114,6 +114,7 @@ Usd_PrimData::_ComposeAndCacheFlags(Usd_PrimDataConstPtr parent, _flags[Usd_PrimComponentFlag] = false; _flags[Usd_PrimDefinedFlag] = true; _flags[Usd_PrimHasDefiningSpecifierFlag] = true; + _flags[Usd_PrimHasAbstractSpecifierFlag] = false; _flags[Usd_PrimPrototypeFlag] = isPrototypePrim; _flags[Usd_PrimPseudoRootFlag] = !parent; } @@ -154,14 +155,18 @@ Usd_PrimData::_ComposeAndCacheFlags(Usd_PrimDataConstPtr parent, // Get specifier. const SdfSpecifier specifier = GetSpecifier(); + bool isClassSpecifier = specifier == SdfSpecifierClass; // This prim is abstract if its parent is or if it's a class. _flags[Usd_PrimAbstractFlag] = - parent->IsAbstract() || specifier == SdfSpecifierClass; + parent->IsAbstract() || isClassSpecifier; // Cache whether or not this prim has an authored defining specifier. const bool isDefiningSpec = SdfIsDefiningSpecifier(specifier); _flags[Usd_PrimHasDefiningSpecifierFlag] = isDefiningSpec; + // Cache whether or not this prim has an authored abstract specifier. + _flags[Usd_PrimHasAbstractSpecifierFlag] = isClassSpecifier; + // This prim is defined if its parent is and its specifier is defining. _flags[Usd_PrimDefinedFlag] = isDefiningSpec && parent->IsDefined(); diff --git a/pxr/usd/usd/primData.h b/pxr/usd/usd/primData.h index 04c9591d6a6..9b457f29131 100644 --- a/pxr/usd/usd/primData.h +++ b/pxr/usd/usd/primData.h @@ -125,6 +125,12 @@ class Usd_PrimData return _flags[Usd_PrimHasDefiningSpecifierFlag]; } + /// Return true if this prim has a specifier of type SdfSpecifierClass. + /// \sa SdfIsAbstractSpecifier + bool HasAbstractSpecifier() const { + return _flags[Usd_PrimHasAbstractSpecifierFlag]; + } + /// Return true if this prim has one or more payload composition arcs. bool HasPayload() const { return _flags[Usd_PrimHasPayloadFlag]; } diff --git a/pxr/usd/usd/primFlags.h b/pxr/usd/usd/primFlags.h index efb1b2cd01c..e0d74ea1d55 100644 --- a/pxr/usd/usd/primFlags.h +++ b/pxr/usd/usd/primFlags.h @@ -79,6 +79,7 @@ enum Usd_PrimFlags { Usd_PrimDefinedFlag, Usd_PrimHasDefiningSpecifierFlag, Usd_PrimInstanceFlag, + Usd_PrimHasAbstractSpecifierFlag, // Flags for internal use. Usd_PrimHasPayloadFlag, @@ -489,6 +490,8 @@ extern unspecified UsdPrimIsDefined; extern unspecified UsdPrimIsInstance; /// Tests UsdPrim::HasDefiningSpecifier() extern unspecified UsdPrimHasDefiningSpecifier; +/// Tests UsdPrim::HasAbstractSpecifier() +extern unspecified UsdPrimHasAbstractSpecifier; /// The default predicate used for prim traversals in methods like /// UsdPrim::GetChildren, UsdStage::Traverse, and by UsdPrimRange. @@ -520,6 +523,8 @@ static const Usd_PrimFlags UsdPrimIsDefined = Usd_PrimDefinedFlag; static const Usd_PrimFlags UsdPrimIsInstance = Usd_PrimInstanceFlag; static const Usd_PrimFlags UsdPrimHasDefiningSpecifier = Usd_PrimHasDefiningSpecifierFlag; +static const Usd_PrimFlags UsdPrimHasAbstractSpecifier + = Usd_PrimHasAbstractSpecifierFlag; USD_API extern const Usd_PrimFlagsConjunction UsdPrimDefaultPredicate; USD_API extern const Usd_PrimFlagsPredicate UsdPrimAllPrimsPredicate; diff --git a/pxr/usd/usd/testenv/testUsdPrimRange.py b/pxr/usd/usd/testenv/testUsdPrimRange.py index 24bba2010d5..4277b303eb4 100644 --- a/pxr/usd/usd/testenv/testUsdPrimRange.py +++ b/pxr/usd/usd/testenv/testUsdPrimRange.py @@ -72,6 +72,35 @@ def test_PrimHasDefiningSpecifier(self): ['/c1', '/c1/c2', '/c1/c2/c3']] self.assertEqual(actual, expected) + def test_PrimHasAbstractSpecifier(self): + for fmt in allFormats: + stageFile = 'testHasAbstractSpecifier.' + fmt + stage = Usd.Stage.Open(stageFile) + + root = stage.GetPrimAtPath('/a1') + actual = [] + expected = [stage.GetPrimAtPath(x) for x in ['/a1/a2']] + for prim in Usd.PrimRange.AllPrims(root): + if prim.HasAbstractSpecifier(): + actual.append(prim) + self.assertEqual(actual, expected) + + root = stage.GetPrimAtPath('/b1') + actual = [] + expected = [stage.GetPrimAtPath(x) for x in + ['/b1/b2', '/b1/b2/b3/b4/b5/b6']] + for prim in Usd.PrimRange(root, Usd.PrimIsActive): + if prim.HasAbstractSpecifier(): + actual.append(prim) + self.assertEqual(actual, expected) + + # Note that the over is not included in our traversal. + root = stage.GetPrimAtPath('/c1') + actual = list(Usd.PrimRange(root, Usd.PrimHasAbstractSpecifier)) + expected = [stage.GetPrimAtPath(x) for x in + ['/c1', '/c1/c2', '/c1/c2/c3']] + self.assertEqual(actual, expected) + def test_PrimIsActive(self): for fmt in allFormats: s = Usd.Stage.CreateInMemory('TestPrimIsActive.'+fmt) diff --git a/pxr/usd/usd/testenv/testUsdPrimRange/testHasAbstractSpecifier.usda b/pxr/usd/usd/testenv/testUsdPrimRange/testHasAbstractSpecifier.usda new file mode 100644 index 00000000000..d8ae5ac134c --- /dev/null +++ b/pxr/usd/usd/testenv/testUsdPrimRange/testHasAbstractSpecifier.usda @@ -0,0 +1,43 @@ +#usda 1.0 + +def "a1" +{ + class "a2" + { + over "a3" + { + } + } +} + +over "b1" +{ + class "b2" + { + over "b3" + { + over "b4" + { + over "b5" + { + class "b6" + { + } + } + } + } + } +} + +class "c1" +{ + class "c2" + { + class "c3" + { + over "c4" + { + } + } + } +} diff --git a/pxr/usd/usd/testenv/testUsdPrimRange/testHasAbstractSpecifier.usdc b/pxr/usd/usd/testenv/testUsdPrimRange/testHasAbstractSpecifier.usdc new file mode 100644 index 00000000000..bc54a8fc270 Binary files /dev/null and b/pxr/usd/usd/testenv/testUsdPrimRange/testHasAbstractSpecifier.usdc differ diff --git a/pxr/usd/usd/wrapPrim.cpp b/pxr/usd/usd/wrapPrim.cpp index c217ecc328e..135a508af53 100644 --- a/pxr/usd/usd/wrapPrim.cpp +++ b/pxr/usd/usd/wrapPrim.cpp @@ -271,6 +271,7 @@ void wrapUsdPrim() .def("IsAbstract", &UsdPrim::IsAbstract) .def("IsDefined", &UsdPrim::IsDefined) .def("HasDefiningSpecifier", &UsdPrim::HasDefiningSpecifier) + .def("HasAbstractSpecifier", &UsdPrim::HasAbstractSpecifier) .def("GetPropertyNames", &_WrapGetPropertyNames, (arg("predicate")=pxr_boost::python::object()), diff --git a/pxr/usd/usd/wrapPrimFlags.cpp b/pxr/usd/usd/wrapPrimFlags.cpp index 67ee1d892de..4c18cf61991 100644 --- a/pxr/usd/usd/wrapPrimFlags.cpp +++ b/pxr/usd/usd/wrapPrimFlags.cpp @@ -127,6 +127,8 @@ void wrapUsdPrimFlags() scope().attr("PrimIsInstance") = Usd_Term(UsdPrimIsInstance); scope().attr("PrimHasDefiningSpecifier") = Usd_Term(UsdPrimHasDefiningSpecifier); + scope().attr("PrimHasAbstractSpecifier") + = Usd_Term(UsdPrimHasAbstractSpecifier); scope().attr("PrimDefaultPredicate") = UsdPrimDefaultPredicate; scope().attr("PrimAllPrimsPredicate") = UsdPrimAllPrimsPredicate; diff --git a/pxr/usd/usdGeom/pointInstancer.h b/pxr/usd/usdGeom/pointInstancer.h index 2ce27043de5..f91e1b841e5 100644 --- a/pxr/usd/usdGeom/pointInstancer.h +++ b/pxr/usd/usdGeom/pointInstancer.h @@ -234,11 +234,13 @@ class SdfAssetPath; /// \ref Usd_PrimSpecifiers "specifier" of "def", "over", or "class". The /// default traversals skip over prims that are "pure overs" or classes. So /// to protect prototypes from all generic traversals and processing, place -/// them under a prim that is just an "over". For example, +/// them under a prim that is an "class" or "over". "class" is recommended +/// , while "over" should be used when backwards compatibility with older +/// versions of USD is needed. For example, /// \code /// 01 def PointInstancer "Crowd_Mid" /// 02 { -/// 03 rel prototypes = [ , ] +/// 03 rel prototypes = [ , ] /// 04 /// 05 over "Prototypes" /// 06 { @@ -250,11 +252,14 @@ class SdfAssetPath; /// 12 } /// 13 ) /// 14 { ... } -/// 15 -/// 16 def "MaleThin_Casual" -/// 17 ... -/// 18 } -/// 19 } +/// 15 } +/// 16 +/// 17 class "OtherPrototypes" +/// 18 { +/// 19 def "MaleThin_Casual" +/// 20 ... +/// 21 } +/// 22 } /// \endcode /// /// diff --git a/pxr/usdImaging/usdImaging/delegate.cpp b/pxr/usdImaging/usdImaging/delegate.cpp index 34ed534f93f..e05c3db9f90 100644 --- a/pxr/usdImaging/usdImaging/delegate.cpp +++ b/pxr/usdImaging/usdImaging/delegate.cpp @@ -289,8 +289,8 @@ Usd_PrimFlagsConjunction UsdImagingDelegate::_GetDisplayPredicateForPrototypes() const { return _displayUnloadedPrimsWithBounds ? - UsdPrimIsActive && UsdPrimHasDefiningSpecifier && !UsdPrimIsAbstract : - UsdPrimIsActive && UsdPrimHasDefiningSpecifier && !UsdPrimIsAbstract + UsdPrimIsActive && UsdPrimHasDefiningSpecifier && !UsdPrimHasAbstractSpecifier : + UsdPrimIsActive && UsdPrimHasDefiningSpecifier && !UsdPrimHasAbstractSpecifier && UsdPrimIsLoaded; }