Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EMSUSD-126 fix finding strongest layer. #3498

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/usdUfe/ufe/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -689,10 +689,16 @@ bool isPropertyMetadataEditAllowed(
= UsdUfe::getStrongerLayer(stage, targetLayer, topAuthoredLayer, true);
bool allowed = (strongestLayer == targetLayer);
if (!allowed && errMsg) {
std::string strongName;
if (strongestLayer)
strongName = strongestLayer->GetDisplayName();
else
strongName = "a layer we could not identify";

*errMsg = TfStringPrintf(
"Cannot edit [%s] attribute because there is a stronger opinion in [%s].",
metadataName.GetText(),
strongestLayer ? strongestLayer->GetDisplayName().c_str() : "some layer");
strongName.c_str());
}
return allowed;
}
Expand Down
16 changes: 9 additions & 7 deletions lib/usdUfe/utils/layers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,15 @@ SdfLayerHandle getStrongerLayer(
return layer2;

for (auto path : root->GetSubLayerPaths()) {
SdfLayerRefPtr subLayer = SdfLayer::FindOrOpen(path);
if (subLayer) {
SdfLayerHandle stronger = getStrongerLayer(subLayer, layer1, layer2);
if (!stronger.IsInvalid()) {
return stronger;
}
}
SdfLayerRefPtr subLayer = SdfLayer::FindRelativeToLayer(root, path);
if (!subLayer)
continue;

SdfLayerHandle stronger = getStrongerLayer(subLayer, layer1, layer2);
if (!stronger)
continue;

return stronger;
}

return SdfLayerHandle();
Expand Down
1 change: 1 addition & 0 deletions test/lib/ufe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ set(TEST_SCRIPT_FILES
testTransform3dTranslate.py
testUIInfoHandler.py
testUfePythonImport.py
testVariant.py
testVisibilityCmd.py
)

Expand Down
170 changes: 170 additions & 0 deletions test/lib/ufe/testVariant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#!/usr/bin/env python

#
# Copyright 2023 Autodesk
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import mayaUsd
import fixturesUtils
import mayaUtils
import usdUtils
import testUtils

from maya import cmds
from maya import standalone

import ufe

from pxr import Usd, Sdf

import unittest


class VariantTestCase(unittest.TestCase):
'''
Verify variants on a USD scene.
'''

pluginsLoaded = False

@classmethod
def setUpClass(cls):
fixturesUtils.readOnlySetUpClass(__file__, loadPlugin=False)

if not cls.pluginsLoaded:
cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded()

@classmethod
def tearDownClass(cls):
cmds.file(new=True, force=True)

standalone.uninitialize()

def setUp(self):
# Load plugins
cmds.file(new=True, force=True)
self.assertTrue(self.pluginsLoaded)

def verifyChildren(self, item, expectedChildrenPaths):
'''
Verify that the list of children UFE paths really are the children
of the given UFE item.
'''
itemHierarchy = ufe.Hierarchy.hierarchy(item)
itemChildren = itemHierarchy.children()
self.assertEqual([ufe.PathString.string(child.path()) for child in itemChildren], expectedChildrenPaths)

def testSwitchVariantMultiLayers(self):
'''
Switch variants in a layer above a layer that already has a variant selection.
'''
import mayaUsd_createStageWithNewLayer
import maya.internal.ufeSupport.ufeCmdWrapper as ufeCmd

# Create a scene with three layers.
proxyShapePathStr = mayaUsd_createStageWithNewLayer.createStageWithNewLayer()
stage = mayaUsd.lib.GetPrim(proxyShapePathStr).GetStage()
rootLayer = stage.GetRootLayer()
subLayers = usdUtils.addNewLayersToLayer(rootLayer, 3)

# Create two variants in the deepest layer.
with Usd.EditContext(stage, subLayers[-1]):
xformPrim = stage.DefinePrim('/Xform1', 'Xform')
variantSet = xformPrim.GetVariantSets().AddVariantSet('modelingVariant')
variantSet.AddVariant('cube')
variantSet.AddVariant('sphere')
variantSet.SetVariantSelection('cube')
with variantSet.GetVariantEditContext():
stage.DefinePrim('/Xform1/Cube', 'Cube')
variantSet.SetVariantSelection('sphere')
with variantSet.GetVariantEditContext():
stage.DefinePrim('/Xform1/Sphere', 'Sphere')

# Paths and item that will be used in the test.
xformPathStr = '%s,/Xform1' % proxyShapePathStr
cubePathStr = '%s/Cube' % xformPathStr
spherePathStr = '%s/Sphere' % xformPathStr

xformItem = ufe.Hierarchy.createItem(ufe.PathString.path(xformPathStr))

# The sphere is the sole child of Xform1.
self.verifyChildren(xformItem, [spherePathStr])

# Switch variants using a command: the cube is now the sole child of
# Xform1.
xformCtxOps = ufe.ContextOps.contextOps(xformItem)
cmd = xformCtxOps.doOpCmd(['Variant Sets', 'modelingVariant', 'cube'])
ufeCmd.execute(cmd)

self.verifyChildren(xformItem, [cubePathStr])

# Undo: sphere is back.
cmds.undo()

self.verifyChildren(xformItem, [spherePathStr])

# Redo: cube is back.
cmds.redo()

self.verifyChildren(xformItem, [cubePathStr])

def testSwitchVariantFromReference(self):
'''
Switch variants declared in a reference.
Make sure the edit restrictions work correctly when the target is a sub-layer
and the top opinion is in the reference and the layers are using relative paths.
'''
import mayaUsd_createStageWithNewLayer
import maya.internal.ufeSupport.ufeCmdWrapper as ufeCmd

# Create a scene with three layers and variants in a reference.
shotFileName = testUtils.getTestScene("variantInRef", "shot.usda")
proxyShapePathStr, stage = mayaUtils.createProxyFromFile(shotFileName)

# Paths and item that will be used in the test.
varyingPathStr = '%s,/assets/varying' % proxyShapePathStr
cubePathStr = '%s/CubePrim' % varyingPathStr
spherePathStr = '%s/SpherePrim' % varyingPathStr

rootItem = ufe.Hierarchy.createItem(ufe.PathString.path(varyingPathStr))

# The sphere is the sole child of Xform1.
self.verifyChildren(rootItem, [spherePathStr])

# Switch variants using a command: the cube is now the sole child of
# Xform1.
rootLayer = stage.GetRootLayer()
subIdentifier = rootLayer.subLayerPaths[0]
subLayer = Sdf.Layer.FindRelativeToLayer(rootLayer, subIdentifier)
with Usd.EditContext(stage, subLayer):
xformCtxOps = ufe.ContextOps.contextOps(rootItem)
cmd = xformCtxOps.doOpCmd(['Variant Sets', 'geo', 'cube'])
ufeCmd.execute(cmd)

self.verifyChildren(rootItem, [cubePathStr])

# Undo: sphere is back.
cmds.undo()

self.verifyChildren(rootItem, [spherePathStr])

# Redo: cube is back.
cmds.redo()

self.verifyChildren(rootItem, [cubePathStr])


if __name__ == '__main__':
unittest.main(verbosity=2)
8 changes: 8 additions & 0 deletions test/testSamples/variantInRef/layout/assets/asset.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#usda 1.0

def Scope "assets" (
prepend references = @geo_variants.usda@
)
{
}

59 changes: 59 additions & 0 deletions test/testSamples/variantInRef/layout/assets/geo_variants.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#usda 1.0
(
defaultPrim = "root"
)

def Xform "root" {
def Xform "varying" (
variants = {
string geo = "sphere"
}
prepend variantSets = "geo"
)
{
variantSet "geo" = {
"cube" {
def Xform "CubePrim"
{
def Mesh "CubeMesh" (
kind = "component"
)
{
uniform bool doubleSided = 1
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)]
color3f[] primvars:displayColor = [(0.13320851, 0.13320851, 0.13320851)]
int[] primvars:st:indices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 9, 8, 1, 10, 11, 3, 12, 0, 2, 13]

double3 xformOp:translate = (2, 0, -2)
uniform token[] xformOpOrder = ["xformOp:translate"]
}
}
}
"sphere" {
def Xform "SpherePrim"
{
def Mesh "SphereMesh" (
kind = "component"
)
{
uniform bool doubleSided = 1
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)]
color3f[] primvars:displayColor = [(0.13320851, 0.13320851, 0.13320851)]
int[] primvars:st:indices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 9, 8, 1, 10, 11, 3, 12, 0, 2, 13]

double3 xformOp:translate = (-2, 0, 2)
uniform token[] xformOpOrder = ["xformOp:translate"]
}
}

}
}
}
}

7 changes: 7 additions & 0 deletions test/testSamples/variantInRef/layout/layout.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#usda 1.0
(
subLayers = [
@assets/asset.usda@,
]
)

8 changes: 8 additions & 0 deletions test/testSamples/variantInRef/shot.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#usda 1.0
(
subLayers = [
@layout/layout.usda@
]
upAxis = "Y"
)