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

LOOKDEVX-571 | Adds support for converting strings with options into #2588

Merged
merged 3 commits into from
Sep 12, 2022
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
81 changes: 71 additions & 10 deletions lib/mayaUsd/ufe/UsdAttribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
#include "Utils.h"
#include "private/Utils.h"

#ifdef UFE_V3_FEATURES_AVAILABLE
#include <mayaUsd/base/tokens.h>
#endif
#include <mayaUsd/ufe/StagesSubject.h>
#include <mayaUsd/ufe/Utils.h>
#include <mayaUsd/undo/UsdUndoBlock.h>
Expand All @@ -37,6 +34,15 @@
#include <unordered_map>
#include <unordered_set>

#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4010)
#include "UsdShaderAttributeDef.h"
#endif
#endif
#ifdef UFE_V3_FEATURES_AVAILABLE
#include <mayaUsd/base/tokens.h>
#endif

// Note: normally we would use this using directive, but here we cannot because
// our class is called UsdAttribute which is exactly the same as the one
// in USD.
Expand Down Expand Up @@ -424,7 +430,21 @@ std::string UsdAttribute::isEditAllowedMsg() const
std::string UsdAttribute::typeName() const
{
if (isValid()) {
return usdTypeToUfe(fUsdAttr.GetTypeName());
#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4010)
UsdShaderAttributeDef::ConstPtr shaderAttrDef
= std::dynamic_pointer_cast<const UsdShaderAttributeDef>(fAttrDef);
if (shaderAttrDef) {
return usdTypeToUfe(shaderAttrDef->shaderProperty());
} else {
#endif
#endif
return usdTypeToUfe(fUsdAttr.GetTypeName());
#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4010)
}
#endif
#endif
}
#ifdef UFE_V4_FEATURES_AVAILABLE
else {
Expand Down Expand Up @@ -864,13 +884,20 @@ Ufe::UndoableCommand::Ptr UsdAttributeFilename::setCmd(const std::string& value)
// UsdAttributeEnumString:
//------------------------------------------------------------------------------

bool UsdAttributeEnumString::isHoldingTfToken() const
{
PXR_NS::VtValue vt;
return UsdAttribute::get(vt, UsdTimeCode::Default()) && vt.IsHolding<TfToken>();
}

#ifdef UFE_V4_FEATURES_AVAILABLE
UsdAttributeEnumString::UsdAttributeEnumString(
const UsdSceneItem::Ptr& item,
const PXR_NS::UsdPrim& prim,
const Ufe::AttributeDef::ConstPtr& attrDef)
: Ufe::AttributeEnumString(item)
, UsdAttribute(prim, attrDef)
, _isHoldingTfToken(isHoldingTfToken())
{
}
#endif
Expand All @@ -880,6 +907,7 @@ UsdAttributeEnumString::UsdAttributeEnumString(
const PXR_NS::UsdAttribute& usdAttr)
: Ufe::AttributeEnumString(item)
, UsdAttribute(usdAttr)
, _isHoldingTfToken(isHoldingTfToken())
{
}

Expand Down Expand Up @@ -910,18 +938,26 @@ UsdAttributeEnumString::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdA
std::string UsdAttributeEnumString::get() const
{
PXR_NS::VtValue vt;
if (UsdAttribute::get(vt, getCurrentTime(sceneItem())) && vt.IsHolding<TfToken>()) {
TfToken tok = vt.UncheckedGet<TfToken>();
return tok.GetString();
if (UsdAttribute::get(vt, getCurrentTime(sceneItem()))) {
if (vt.IsHolding<TfToken>()) {
TfToken tok = vt.UncheckedGet<TfToken>();
return tok.GetString();
} else if (vt.IsHolding<std::string>()) {
return vt.UncheckedGet<std::string>();
}
}

return std::string();
}

void UsdAttributeEnumString::set(const std::string& value)
{
PXR_NS::TfToken tok(value);
setUsdAttr<PXR_NS::TfToken>(*this, tok);
if (_isHoldingTfToken) {
PXR_NS::TfToken tok(value);
setUsdAttr<PXR_NS::TfToken>(*this, tok);
} else {
setUsdAttr<std::string>(*this, value);
}
}

Ufe::UndoableCommand::Ptr UsdAttributeEnumString::setCmd(const std::string& value)
Expand Down Expand Up @@ -949,7 +985,25 @@ Ufe::AttributeEnumString::EnumValues UsdAttributeEnumString::getEnumValues() con
EnumValues tokens = PXR_NS::TfToStringVector(tokenVec);
return tokens;
}

#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4010)
else {
EnumValues result;
UsdShaderAttributeDef::ConstPtr shaderAttrDef
= std::dynamic_pointer_cast<const UsdShaderAttributeDef>(fAttrDef);
if (shaderAttrDef) {
const auto& shaderProperty = shaderAttrDef->shaderProperty();
if (shaderProperty) {
const auto& options = shaderProperty->GetOptions();
for (const auto& option : options) {
result.push_back(option.first.GetString());
}
}
}
return result;
}
#endif
#endif
return EnumValues();
}

Expand Down Expand Up @@ -1024,6 +1078,13 @@ template <> void TypedUsdAttribute<std::string>::set(const std::string& value)
setUsdAttr<std::string>(*this, value);
return;
} else if (typeName == Ufe::Attribute::kEnumString) {
PXR_NS::VtValue vt;
if (UsdAttribute::get(vt, UsdTimeCode::Default())) {
if (vt.IsHolding<std::string>()) {
setUsdAttr<std::string>(*this, value);
return;
}
}
PXR_NS::TfToken tok(value);
setUsdAttr<PXR_NS::TfToken>(*this, tok);
return;
Expand Down
5 changes: 5 additions & 0 deletions lib/mayaUsd/ufe/UsdAttribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ class UsdAttributeEnumString
void set(const std::string& value) override;
Ufe::UndoableCommand::Ptr setCmd(const std::string& value) override;
EnumValues getEnumValues() const override;

private:
bool isHoldingTfToken() const;

const bool _isHoldingTfToken;
}; // UsdAttributeEnumString

//! \brief Internal helper template class to implement the get/set methods from Ufe::TypeAttribute.
Expand Down
29 changes: 18 additions & 11 deletions lib/mayaUsd/ufe/UsdAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <ufe/ufeAssert.h>

#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4010)
#include "UsdShaderAttributeDef.h"
#endif
#if (UFE_PREVIEW_VERSION_NUM >= 4024)
#include <mayaUsd/ufe/UsdUndoAttributesCommands.h>
#endif
Expand Down Expand Up @@ -124,23 +127,27 @@ Ufe::Attribute::Type UsdAttributes::attributeType(const std::string& name)
auto iter = fUsdAttributes.find(name);
if (iter != std::end(fUsdAttributes))
return iter->second->type();

PXR_NS::TfToken tok(name);
PXR_NS::UsdAttribute usdAttr = _GetAttributeType(fPrim, name);
if (usdAttr.IsValid()) {
return getUfeTypeForAttribute(usdAttr);
}
PXR_NS::TfToken tok(name);
#ifdef UFE_V4_FEATURES_AVAILABLE
#if (UFE_PREVIEW_VERSION_NUM >= 4008)
#if (UFE_PREVIEW_VERSION_NUM >= 4010)
Ufe::NodeDef::Ptr nodeDef = UsdAttributes::nodeDef();
if (nodeDef) {
Ufe::AttributeDef::ConstPtr attrDef = nameToAttrDef(tok, nodeDef);
if (attrDef) {
return attrDef->type();
Ufe::AttributeDef::ConstPtr attrDef = nameToAttrDef(tok, nodeDef);
UsdShaderAttributeDef::ConstPtr shaderAttrDef
= std::dynamic_pointer_cast<const UsdShaderAttributeDef>(attrDef);
if (shaderAttrDef) {
const auto& shaderProperty = shaderAttrDef->shaderProperty();
if (shaderProperty) {
return usdTypeToUfe(shaderProperty);
}
}
}
#endif
#endif
PXR_NS::UsdAttribute usdAttr = _GetAttributeType(fPrim, name);
if (usdAttr.IsValid()) {
return getUfeTypeForAttribute(usdAttr);
}
return Ufe::Attribute::kInvalid;
}

Expand Down Expand Up @@ -173,7 +180,7 @@ Ufe::Attribute::Ptr UsdAttributes::attribute(const std::string& name)
#endif
#endif
bool canCreateAttribute = usdAttr.IsValid();
if (usdAttr.IsValid()) {
if (canCreateAttribute) {
newAttrType = attributeType(name);
}
#ifdef UFE_V4_FEATURES_AVAILABLE
Expand Down
8 changes: 7 additions & 1 deletion lib/mayaUsd/ufe/UsdShaderAttributeDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ namespace ufe {
class MAYAUSD_CORE_PUBLIC UsdShaderAttributeDef : public Ufe::AttributeDef
{
public:
typedef std::shared_ptr<UsdShaderAttributeDef> Ptr;
typedef std::shared_ptr<UsdShaderAttributeDef> Ptr;
typedef std::shared_ptr<const UsdShaderAttributeDef> ConstPtr;

UsdShaderAttributeDef(const PXR_NS::SdrShaderPropertyConstPtr& shaderAttributeDef);
~UsdShaderAttributeDef();
Expand Down Expand Up @@ -61,6 +62,11 @@ class MAYAUSD_CORE_PUBLIC UsdShaderAttributeDef : public Ufe::AttributeDef
//! Returns true if metadata key has a non-empty value.
bool hasMetadata(const std::string& key) const override;

inline const PXR_NS::SdrShaderPropertyConstPtr& shaderProperty() const
{
return fShaderAttributeDef;
}

private:
const PXR_NS::SdrShaderPropertyConstPtr fShaderAttributeDef;

Expand Down
14 changes: 12 additions & 2 deletions lib/mayaUsd/ufe/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,12 @@ Ufe::Attribute::Type usdTypeToUfe(const PXR_NS::SdrShaderPropertyConstPtr& shade
TokenToSdfTypeMap::const_iterator it
= tokenTypeToSdfType.find(shaderProperty->GetTypeAsSdfType().second);
if (it != tokenTypeToSdfType.end()) {
return usdTypeToUfe(it->second);
Ufe::Attribute::Type type = usdTypeToUfe(it->second);
if (type == Ufe::Attribute::kString && !shaderProperty->GetOptions().empty()) {
return Ufe::Attribute::kEnumString;
} else {
return type;
}
} else {
#if PXR_VERSION < 2205
// Pre-22.05 boolean inputs are special:
Expand All @@ -644,7 +649,12 @@ Ufe::Attribute::Type usdTypeToUfe(const PXR_NS::SdrShaderPropertyConstPtr& shade
return usdTypeToUfe(PXR_NS::SdfValueTypeNames->Token);
}
} else {
return usdTypeToUfe(typeName);
Ufe::Attribute::Type type = usdTypeToUfe(typeName);
if (type == Ufe::Attribute::kString && !shaderProperty->GetOptions().empty()) {
return Ufe::Attribute::kEnumString;
} else {
return type;
}
}
}

Expand Down
38 changes: 38 additions & 0 deletions test/lib/ufe/testAttribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import usdUtils

from pxr import Usd, UsdGeom, Vt, Gf
from pxr import UsdShade

from maya import cmds
from maya import standalone
Expand Down Expand Up @@ -419,6 +420,43 @@ def testAttributeEnumString(self):
# Run test using Maya's getAttr command.
self.runMayaGetAttrTest(ufeAttr)

@unittest.skipIf(os.getenv('USD_HAS_MX_METADATA_SUPPORT', 'NOT-FOUND') not in ('1', "TRUE"), 'Test only available if USD can read MaterialX metadata')
@unittest.skipIf(os.getenv('UFE_PREVIEW_VERSION_NUM', '0000') < '4001', 'nodeDefHandler is only available in UFE preview version 0.4.1 and greater')
Comment on lines +423 to +424
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppt-adsk Does using two conditions like this work? I've never seen this before.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decorators can be chained like this. Was used for testCreateUsdPreviewSurfaceAttribute in test\lib\ufe\testAttribute.py.

def testAttributeEnumStringToken(self):
'''Test the EnumString attribute type that stores a token instead of a string.'''

import mayaUsd_createStageWithNewLayer
mayaUsd_createStageWithNewLayer.createStageWithNewLayer()
proxyShapes = cmds.ls(type="mayaUsdProxyShapeBase", long=True)
proxyShapePath = proxyShapes[0]
stage = mayaUsd.lib.GetPrim(proxyShapePath).GetStage()
materialPathStr = '/material1'
UsdShade.Material.Define(stage, materialPathStr)
materialPath = ufe.PathString.path(proxyShapePath + ',' + materialPathStr)
materialSceneItem = ufe.Hierarchy.createItem(materialPath)

runTimeMgr = ufe.RunTimeMgr.instance()
id = runTimeMgr.getId("USD")
nodeDefHandler = runTimeMgr.nodeDefHandler(id)
nodeDef = nodeDefHandler.definition("ND_image_color3")
imageSceneItem = nodeDef.createNode(materialSceneItem, ufe.PathComponent("image1"))
imageAttrs = ufe.Attributes.attributes(imageSceneItem)
uaddressModeAttr = imageAttrs.attribute("inputs:uaddressmode")

# Compare the initial UFE value to that directly from USD.
self.assertEqual(uaddressModeAttr.get(), 'periodic')

# Change to 'constant' and verify the return in UFE.
uaddressModeAttr.set('constant')
self.assertEqual(uaddressModeAttr.get(), 'constant')

uaddressModeEnumValues = uaddressModeAttr.getEnumValues()
self.assertEqual(len(uaddressModeEnumValues), 4)
self.assertTrue('constant' in uaddressModeEnumValues)
self.assertTrue('periodic' in uaddressModeEnumValues)
self.assertTrue('clamp' in uaddressModeEnumValues)
self.assertTrue('mirror' in uaddressModeEnumValues)

def testAttributeBool(self):
'''Test the Bool attribute type.'''

Expand Down
16 changes: 8 additions & 8 deletions test/lib/ufe/testShaderNodeDef.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ def testDefinitionByType(self):
self.assertEqual(inputs[3].type(), "Generic")
self.assertEqual(inputs[3].defaultValue(), "")
self.assertEqual(inputs[4].name(), "uaddressmode")
self.assertEqual(inputs[4].type(), "String")
self.assertEqual(inputs[4].type(), "EnumString")
self.assertEqual(inputs[4].defaultValue(), "periodic")
self.assertEqual(inputs[5].name(), "vaddressmode")
self.assertEqual(inputs[5].name(), "Enumvaddressmode")
self.assertEqual(inputs[5].type(), "String")
self.assertEqual(inputs[5].defaultValue(), "periodic")
self.assertEqual(inputs[6].name(), "filtertype")
self.assertEqual(inputs[6].type(), "String")
self.assertEqual(inputs[6].type(), "EnumString")
self.assertEqual(inputs[6].defaultValue(), "linear")
self.assertEqual(inputs[7].name(), "framerange")
self.assertEqual(inputs[7].type(), "String")
Expand All @@ -132,7 +132,7 @@ def testDefinitionByType(self):
self.assertEqual(inputs[8].type(), "Int")
self.assertEqual(inputs[8].defaultValue(), "0")
self.assertEqual(inputs[9].name(), "frameendaction")
self.assertEqual(inputs[9].type(), "String")
self.assertEqual(inputs[9].type(), "EnumString")
self.assertEqual(inputs[9].defaultValue(), "constant")
self.assertEqual(len(outputs), 1)
self.assertEqual(outputs[0].name(), "out")
Expand Down Expand Up @@ -161,13 +161,13 @@ def testDefinitionByType(self):
self.assertEqual(inputs[3].type(), "Float2")
self.assertEqual(inputs[3].defaultValue(), "")
self.assertEqual(inputs[4].name(), "uaddressmode")
self.assertEqual(inputs[4].type(), "String")
self.assertEqual(inputs[4].type(), "EnumString")
self.assertEqual(inputs[4].defaultValue(), "periodic")
self.assertEqual(inputs[5].name(), "vaddressmode")
self.assertEqual(inputs[5].type(), "String")
self.assertEqual(inputs[5].type(), "EnumString")
self.assertEqual(inputs[5].defaultValue(), "periodic")
self.assertEqual(inputs[6].name(), "filtertype")
self.assertEqual(inputs[6].type(), "String")
self.assertEqual(inputs[6].type(), "EnumString")
self.assertEqual(inputs[6].defaultValue(), "linear")
self.assertEqual(inputs[7].name(), "framerange")
self.assertEqual(inputs[7].type(), "String")
Expand All @@ -176,7 +176,7 @@ def testDefinitionByType(self):
self.assertEqual(inputs[8].type(), "Int")
self.assertEqual(inputs[8].defaultValue(), "0")
self.assertEqual(inputs[9].name(), "frameendaction")
self.assertEqual(inputs[9].type(), "String")
self.assertEqual(inputs[9].type(), "EnumString")
self.assertEqual(inputs[9].defaultValue(), "constant")
self.assertEqual(len(outputs), 1)
self.assertEqual(outputs[0].name(), "out")
Expand Down