Skip to content

Commit

Permalink
Merge pull request #3494 from Autodesk/gamaj/LOOKDEVX-2260/third_part…
Browse files Browse the repository at this point in the history
…y_outliner_icons

LOOKDEVX-2260 - Add a third party naming convention for shader outliner icons
  • Loading branch information
seando-adsk authored Dec 6, 2023
2 parents be465cd + dad12d5 commit 3a5d397
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
150 changes: 150 additions & 0 deletions lib/mayaUsd/ufe/MayaUsdUIInfoHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,24 @@
//
#include "MayaUsdUIInfoHandler.h"

#include <pxr/base/arch/fileSystem.h>
#include <pxr/base/tf/getenv.h>
#include <pxr/usd/ar/defaultResolverContext.h>
#include <pxr/usd/ar/resolver.h>
#include <pxr/usd/ar/resolverContextBinder.h>

#include <maya/MDoubleArray.h>
#include <maya/MGlobal.h>

#ifdef UFE_V4_FEATURES_AVAILABLE
#include <maya/MSceneMessage.h>
#include <ufe/nodeDef.h>
#include <ufe/nodeDefHandler.h>
#include <ufe/runTimeMgr.h>
#endif

#include <algorithm>

namespace MAYAUSD_NS_DEF {
namespace ufe {

Expand Down Expand Up @@ -88,5 +103,140 @@ UsdUfe::UsdUIInfoHandler::SupportedTypesMap MayaUsdUIInfoHandler::getSupportedIc
return supportedTypes;
}

#ifdef UFE_V4_FEATURES_AVAILABLE
namespace {
class _MayaIconResolver
{
public:
~_MayaIconResolver() { Terminate(); }

static _MayaIconResolver& Get()
{
static _MayaIconResolver sResolver;
return sResolver;
}

bool FileExists(const std::string& iconName)
{
// Since this will be hitting the filesystem hard, mostly to find nothing, let's cache
// search results. Note that "XBMLANGPATH" is Maya specific, which is why the code is here
// and not in the base class.
auto cachedHit = _searchCache.find(iconName);
if (cachedHit != _searchCache.end()) {
return cachedHit->second;
}

// Would be better using MQtUtil::createPixmap, but this requires linking against
// QtCore.
PXR_NS::ArResolverContextBinder binder(_iconContext);
if (!PXR_NS::ArGetResolver().Resolve(iconName).empty()) {
_searchCache.insert({ iconName, true });
return true;
}

_searchCache.insert({ iconName, false });
return false;
}

void ResetCache()
{
_iconContext = PXR_NS::ArDefaultResolverContext(
PXR_NS::TfStringSplit(PXR_NS::TfGetenv("XBMLANGPATH", ""), ARCH_PATH_LIST_SEP));
_searchCache.clear();
}

static void OnPluginStateChange(const MStringArray& /*strs*/, void* /*clientData*/)
{
_MayaIconResolver::Get().ResetCache();
}

void Terminate()
{
if (_pluginLoadCB) {
MMessage::removeCallback(_pluginLoadCB);
_pluginLoadCB = 0;
}
if (_pluginUnloadCB) {
MMessage::removeCallback(_pluginUnloadCB);
_pluginLoadCB = 0;
}
if (_beforeExitCB) {
MMessage::removeCallback(_beforeExitCB);
_beforeExitCB = 0;
}
}

static void OnTerminateCache(void* /*clientData*/) { _MayaIconResolver::Get().Terminate(); }

private:
_MayaIconResolver()
{
ResetCache();

// Set up callback to notify of plugin load and unload
_pluginLoadCB = MSceneMessage::addStringArrayCallback(
MSceneMessage::kAfterPluginLoad, OnPluginStateChange);
_pluginUnloadCB = MSceneMessage::addStringArrayCallback(
MSceneMessage::kAfterPluginUnload, OnPluginStateChange);
_beforeExitCB = MSceneMessage::addCallback(MSceneMessage::kMayaExiting, OnTerminateCache);
}

PXR_NS::ArDefaultResolverContext _iconContext;
std::unordered_map<std::string, bool> _searchCache;
MCallbackId _pluginLoadCB = 0;
MCallbackId _pluginUnloadCB = 0;
MCallbackId _beforeExitCB = 0;
};
} // namespace
#endif

Ufe::UIInfoHandler::Icon
MayaUsdUIInfoHandler::treeViewIcon(const Ufe::SceneItem::Ptr& mayaItem) const
{
Ufe::UIInfoHandler::Icon icon = Parent::treeViewIcon(mayaItem);

#ifdef UFE_V4_FEATURES_AVAILABLE
if (icon.baseIcon == "out_USD_Shader.png") {
// Naming convention for third party shader outliner icons:
//
// We take the info:id of the shader and make it safe by replacing : with _.
// Then we search the Maya icon paths for a PNG file with that name. If found we will use
// it. Please note that files with _150 and _200 can also be provided for high DPI
// displays.
//
// For example an info:id of:
// MyRenderer:nifty_surface
// On a USD runtime item will have this code search the full Maya icon path for a file
// named:
// out_USD_MyRenderer_nifty_surface.png
// And will use it if found. At resolution 200%, the file:
// out_USD_MyRenderer_nifty_surface_200.png
// Will alternatively be used if found.
//
const auto nodeDefHandler
= Ufe::RunTimeMgr::instance().nodeDefHandler(mayaItem->runTimeId());
if (!nodeDefHandler) {
return icon;
}
const auto nodeDef = nodeDefHandler->definition(mayaItem);
if (!nodeDef || nodeDef->type().empty()) {
return icon;
}

constexpr auto outlinerPrefix = "out_";
const auto runtimeName = Ufe::RunTimeMgr::instance().getName(mayaItem->runTimeId());
std::string iconName = outlinerPrefix + runtimeName + "_" + nodeDef->type();
std::replace(iconName.begin(), iconName.end(), ':', '_');
iconName += ".png";

if (_MayaIconResolver::Get().FileExists(iconName)) {
icon.baseIcon = iconName;
}
}
#endif

return icon;
}

} // namespace ufe
} // namespace MAYAUSD_NS_DEF
1 change: 1 addition & 0 deletions lib/mayaUsd/ufe/MayaUsdUIInfoHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class MAYAUSD_CORE_PUBLIC MayaUsdUIInfoHandler : public UsdUfe::UsdUIInfoHandler
static MayaUsdUIInfoHandler::Ptr create();

UsdUfe::UsdUIInfoHandler::SupportedTypesMap getSupportedIconTypes() const override;
Ufe::UIInfoHandler::Icon treeViewIcon(const Ufe::SceneItem::Ptr& item) const override;

private:
void updateInvisibleColor();
Expand Down

0 comments on commit 3a5d397

Please sign in to comment.