#include "pxr/usd/pcp/layerStackRegistry.h"
#include "pxr/usd/pcp/layerStack.h"
#include "pxr/usd/pcp/layerStackIdentifier.h"
+#include "pxr/usd/pcp/utils.h"
#include "pxr/usd/ar/resolver.h"
#include "pxr/usd/sdf/layerUtils.h"
: rootLayerStackId(rootLayerStackId_)
, fileFormatTarget(fileFormatTarget_)
, isUsd(isUsd)
+ , mutedLayers(fileFormatTarget_)
{ }
typedef SdfLayerHandleVector Layers;
// ------------------------------------------------------------
-namespace
-{
std::string
-_GetCanonicalLayerId(const SdfLayerHandle& anchorLayer,
- const std::string& layerId)
+Pcp_MutedLayers::_GetCanonicalLayerId(const SdfLayerHandle& anchorLayer,
+ const std::string& layerId) const
{
- if (SdfLayer::IsAnonymousLayerIdentifier(layerId)) {
- return layerId;
+ // Split out any file format arguments embedded in layerId so we
+ // can anchor the layer path separately.
+ std::string layerPath;
+ SdfLayer::FileFormatArguments args;
+ if (!SdfLayer::SplitIdentifier(layerId, &layerPath, &args)) {
+ return std::string();
}
-
+
// XXX:
// We may ultimately want to use the resolved path here but that's
// possibly a bigger change and there are questions about what happens if
// the muted path doesn't resolve to an existing asset and how/when to
// invalidate the resolved paths stored in the Pcp_MutedLayers object.
- return ArGetResolver().CreateIdentifier(
- layerId, anchorLayer->GetResolvedPath());
+ const std::string anchoredPath =
+ SdfLayer::IsAnonymousLayerIdentifier(layerPath) ?
+ layerPath :
+ ArGetResolver().CreateIdentifier(
+ layerPath, anchorLayer->GetResolvedPath());
+
+ if (anchoredPath.empty()) {
+ return std::string();
+ }
+
+ // If the layer identifier specified a file format target that matches
+ // our own, we strip it off. This simplifies the matching done in
+ // IsLayerMuted, e.g. in the case where the user specified a muted
+ // layer with a file format target that matches our own, and the
+ // layer identifier being checked has no file format target.
+ Pcp_StripFileFormatTarget(_fileFormatTarget, &args);
+
+ return SdfLayer::CreateIdentifier(anchoredPath, args);
}
+
+Pcp_MutedLayers::Pcp_MutedLayers(const std::string& fileFormatTarget)
+ : _fileFormatTarget(fileFormatTarget)
+{
}
const std::vector<std::string>&
for (const auto& layerToMute : *layersToMute) {
const std::string canonicalId =
_GetCanonicalLayerId(anchorLayer, layerToMute);
+ if (canonicalId.empty()) {
+ continue;
+ }
const auto layerIt = std::lower_bound(
_layers.begin(), _layers.end(), canonicalId);
for (const auto& layerToUnmute : *layersToUnmute) {
const std::string canonicalId =
_GetCanonicalLayerId(anchorLayer, layerToUnmute);
+ if (canonicalId.empty()) {
+ continue;
+ }
const auto layerIt = std::lower_bound(
_layers.begin(), _layers.end(), canonicalId);
}
std::string canonicalId = _GetCanonicalLayerId(anchorLayer, layerId);
+ if (canonicalId.empty()) {
+ return false;
+ }
+
if (std::binary_search(_layers.begin(), _layers.end(), canonicalId)) {
if (canonicalLayerId) {
canonicalLayerId->swap(canonicalId);
def _LoadLayer(self, layerPath):
return Sdf.Layer.FindOrOpen(layerPath)
- def _LoadPcpCache(self, layerPath, sessionLayerPath=None):
+ def _LoadPcpCache(self, layerPath, sessionLayerPath=None,
+ fileFormatTarget=None):
layer = self._LoadLayer(layerPath)
sessionLayer = None if not sessionLayerPath else self._LoadLayer(sessionLayerPath)
- return Pcp.Cache(Pcp.LayerStackIdentifier(layer, sessionLayer))
+ return Pcp.Cache(Pcp.LayerStackIdentifier(layer, sessionLayer),
+ fileFormatTarget=fileFormatTarget or '')
def test_MutingSublayers(self):
"""Tests muting sublayers"""
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp.GetMutedLayers(), [])
self.assertEqual(pi.rootNode.layerStack.mutedLayers, [])
(pi2, err2) = pcp2.ComputePrimIndex('/Root')
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp2.GetMutedLayers(), [])
self.assertEqual(pi2.rootNode.layerStack.mutedLayers, [])
# Muting the cache's root layer is explicitly disallowed.
self.assertEqual(pi.primStack,
[layer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp.GetMutedLayers(), [sublayer.identifier])
self.assertEqual(pi.rootNode.layerStack.mutedLayers,
[sublayer.identifier])
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp2.GetMutedLayers(), [])
self.assertEqual(pi2.rootNode.layerStack.mutedLayers, [])
# Unmute sublayer and verify that it comes back into /Root's
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp.GetMutedLayers(), [])
self.assertEqual(pi.rootNode.layerStack.mutedLayers, [])
(pi2, err2) = pcp2.ComputePrimIndex('/Root')
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp2.GetMutedLayers(), [])
self.assertEqual(pi2.rootNode.layerStack.mutedLayers, [])
# Mute sublayer and verify that change processing has occurred
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root')])
self.assertTrue(anonymousSublayer)
+ self.assertEqual(pcp.GetMutedLayers(), [anonymousSublayer.identifier])
self.assertEqual(pi.rootNode.layerStack.mutedLayers,
[anonymousSublayer.identifier])
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp2.GetMutedLayers(), [])
self.assertEqual(pi2.rootNode.layerStack.mutedLayers, [])
# Unmute sublayer and verify that it comes back into /Root's
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp.GetMutedLayers(), [])
self.assertEqual(pi.rootNode.layerStack.mutedLayers, [])
(pi2, err2) = pcp2.ComputePrimIndex('/Root')
[layer.GetPrimAtPath('/Root'),
sublayer.GetPrimAtPath('/Root'),
anonymousSublayer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp2.GetMutedLayers(), [])
self.assertEqual(pi2.rootNode.layerStack.mutedLayers, [])
def test_MutingSessionLayer(self):
self.assertTrue(not err)
self.assertEqual(pi.primStack,
[layer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp.GetMutedLayers(), [sessionLayer.identifier])
self.assertEqual(pi.rootNode.layerStack.mutedLayers,
[sessionLayer.identifier])
self.assertEqual(pi.primStack,
[sessionLayer.GetPrimAtPath('/Root'),
layer.GetPrimAtPath('/Root')])
+ self.assertEqual(pcp.GetMutedLayers(), [])
self.assertEqual(pi.rootNode.layerStack.mutedLayers, [])
def test_MutingReferencedLayers(self):
# result in change processing, a composition error when recomposing
# /Root, and no reference node on the prim index.
pcp.RequestLayerMuting([refLayer.identifier], [])
+ self.assertEqual(pcp.GetMutedLayers(), [refLayer.identifier])
+
(pi, err) = pcp.ComputePrimIndex('/Root')
self.assertTrue(err)
self.assertEqual(len(pi.rootNode.children), 0)
# Unmute the layer and verify that the composition error is resolved
# and the reference is restored to the prim index.
pcp.RequestLayerMuting([], [refLayer.identifier])
+ self.assertEqual(pcp.GetMutedLayers(), [])
+
(pi, err) = pcp.ComputePrimIndex('/Root')
self.assertTrue(not err)
self.assertEqual(pi.rootNode.children[0].arcType, Pcp.ArcTypeReference)
self.assertEqual(pi2.rootNode.children[0].arcType, Pcp.ArcTypeReference)
self.assertEqual(pi2.rootNode.children[0].layerStack.layers[0], refLayer)
+ def test_MutingWithFileFormatTarget(self):
+ """Tests layer muting for a Pcp.Cache with a file format target."""
+
+ def _HasInvalidSublayerError(errors):
+ return (Pcp.ErrorType_InvalidSublayerPath
+ in (e.errorType for e in errors))
+
+ def _TestMuting(mutedId,
+ expectMutedLayerId=None,
+ expectInvalidSublayerError=False):
+
+ expectMutedLayerId = expectMutedLayerId or mutedId
+
+ # Create a Pcp.Cache with a 'bogus' file format target. This
+ # target will be used for loading layers during composition.
+ pcp = self._LoadPcpCache(
+ 'sublayers/root.sdf', fileFormatTarget='bogus')
+
+ # Normally, we'd be unable to load the sublayer specified in
+ # root.sdf because there is no file format plugin that handles
+ # the 'bogus' file format target. This would cause an invalid
+ # sublayer error during composition.
+ #
+ # To avoid this, we're going to mute the sublayer before we
+ # compose anything.
+ pcp.RequestLayerMuting([mutedId], [])
+ self.assertEqual(pcp.GetMutedLayers(), [expectMutedLayerId])
+
+ # Compute prim index. We should not get an invalid sublayer error
+ # because the sublayer was muted above.
+ (pi, err) = pcp.ComputePrimIndex('/Root')
+
+ if not expectInvalidSublayerError:
+ self.assertFalse(_HasInvalidSublayerError(err))
+
+ sublayerPath = os.path.join(os.getcwd(), 'sublayers/sublayer.sdf')
+
+ # Test using an identifier with no target specified.
+ _TestMuting(sublayerPath, expectMutedLayerId=sublayerPath)
+
+ # Test using an identifier with a target that matches the target
+ # used by the Pcp.Cache.
+ _TestMuting(
+ Sdf.Layer.CreateIdentifier(sublayerPath, {'target':'bogus'}),
+ expectMutedLayerId=sublayerPath)
+
+ # Test using an identifier with a target that does not match the
+ # target used by the Pcp.Cache. In this case, the sublayer will
+ # not be muted, so we expect an invalid sublayer composition error.
+ _TestMuting(
+ Sdf.Layer.CreateIdentifier(sublayerPath, {'target':'bogus2'}),
+ expectInvalidSublayerError=True)
+
if __name__ == "__main__":
unittest.main()