diff --git a/.gitignore b/.gitignore index 29b3afc258..62d3261474 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ *.cproject *.pydevproject *.settings/ +*.vs +CMakeSettings.json CMakeCache.txt CMakeLists.txt.user CMakeFiles/cmake.check_cache @@ -13,4 +15,5 @@ CMakeFiles/cmake.check_cache *.DS_Store *.xcuserstate *.pbxuser -*.swp \ No newline at end of file +*.swp +*.pyc \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index d9fcca67e9..e32d9921ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,29 +1,38 @@ -#- +# # ======================================================================= -# Copyright 2019 Autodesk, Inc. All rights reserved. +# Copyright 2019 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. # ======================================================================= -#+ +# cmake_minimum_required(VERSION 3.1.1) +project(maya-usd) + #============================================================================== # Define common build variables #============================================================================== -set(BUILD_PXR_PLUGIN ON CACHE BOOL "Build the Pixar USD plugin and libraries.") -set(BUILD_AL_PLUGIN ON CACHE BOOL "Build the Animal Logic USD plugin and libraries.") - +option(BUILD_MAYAUSD_LIBRARY "Build Core USD libraries." ON) +option(BUILD_ADSK_PLUGIN "Build Autodesk USD plugin." ON) +option(BUILD_PXR_PLUGIN "Build the Pixar USD plugin and libraries." ON) +option(BUILD_AL_PLUGIN "Build the Animal Logic USD plugin and libraries." ON) +option(BUILD_TESTS "Build tests." ON) +option(WANT_USD_RELATIVE_PATH "Use relative rpaths for USD libraries" OFF) +option(CMAKE_WANT_UFE_BUILD "Enable building with UFE (if found)." ON) + +# Avoid noisy install messages +set(CMAKE_INSTALL_MESSAGE "NEVER") #============================================================================== # Modules and Definitions #============================================================================== @@ -32,17 +41,41 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/defaults ) +if (BUILD_MAYAUSD_LIBRARY) + include(cmake/mayausd_version.info) + set(MAYAUSD_VERSION "${MAYAUSD_MAJOR_VERSION}.${MAYAUSD_MINOR_VERSION}.${MAYAUSD_PATCH_LEVEL}") +endif() + if (APPLE) - set(OSX_ARCHITECTURES "x86_64") - add_definitions(-DOSMac_ -DMAC_PLUGIN) - add_definitions(-D_BOOL -DREQUIRE_IOSTREAM) + set(CMAKE_OSX_ARCHITECTURES "x86_64") endif() -include(cmake/python.cmake) +if (DEFINED PYTHON_INCLUDE_DIR AND DEFINED PYTHON_LIBRARIES AND DEFINED PYTHON_EXECUTABLE) + SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") + SET(PYTHONLIBS_FOUND TRUE) + find_package(PythonInterp 2.7 REQUIRED) + if(NOT PYTHONINTERP_FOUND) + set(PYTHONLIBS_FOUND FALSE) + endif() +endif() +if (NOT PYTHONLIBS_FOUND) + include(cmake/python.cmake) +endif() include(cmake/utils.cmake) +find_package(Maya REQUIRED) find_package(USD REQUIRED) include(cmake/usd.cmake) +include(${USD_CONFIG_FILE}) + +if(CMAKE_WANT_UFE_BUILD) + find_package(UFE QUIET) + if(UFE_FOUND) + message(STATUS "Building with UFE ${UFE_VERSION} features enabled.") + else() + message(STATUS "UFE not found. UFE features will be disabled.") + endif() +endif() #============================================================================== # Compiler @@ -51,7 +84,7 @@ include(cmake/usd.cmake) # Consume them here. This is an effort to keep the most common # build files readable. include(CXXDefaults) -add_definitions(${_PXR_CXX_DEFINITIONS}) +add_definitions(${_PXR_CXX_DEFINITIONS} -DBOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE) set(CMAKE_CXX_FLAGS "${_PXR_CXX_FLAGS} ${CMAKE_CXX_FLAGS}") if(NOT WIN32) @@ -63,6 +96,24 @@ endif() string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +#============================================================================== +# Tests +#============================================================================== +if (BUILD_TESTS) + include(cmake/Googletest.cmake) + fetch_googletest() + + enable_testing() + add_subdirectory(test/lib/ufe) +endif() + +#============================================================================== +# CORE +#============================================================================== +if (BUILD_MAYAUSD_LIBRARY) + add_subdirectory(lib) +endif() + #============================================================================== # PLUGINS #============================================================================== @@ -82,6 +133,9 @@ if (BUILD_AL_PLUGIN) endif() endif() +if (BUILD_ADSK_PLUGIN) + add_subdirectory(plugin/adsk) +endif() #============================================================================== # Install mayaUSD.mod @@ -90,3 +144,4 @@ configure_file(mayaUSD.mod.template ${PROJECT_BINARY_DIR}/mayaUSD.mod) install(FILES ${PROJECT_BINARY_DIR}/mayaUSD.mod DESTINATION ${CMAKE_INSTALL_PREFIX} ) + diff --git a/build.py b/build.py index fa73bf20e5..2d4423e9b9 100644 --- a/build.py +++ b/build.py @@ -12,6 +12,7 @@ import shutil import subprocess import sys +import distutils.util ############################################################ # Helpers for printing output @@ -153,7 +154,7 @@ def GetCPUCount(): except NotImplementedError: return 1 -def Run(cmd, logCommandOutput=True): +def Run(context, cmd): """Run the specified command in a subprocess.""" PrintInfo('Running "{cmd}"'.format(cmd=cmd)) @@ -165,7 +166,7 @@ def Run(cmd, logCommandOutput=True): # Let exceptions escape from subprocess calls -- higher level # code will handle them. - if logCommandOutput: + if context.redirectOutstreamFile: p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: @@ -207,6 +208,18 @@ def FormatMultiProcs(numJobs, generator): return "{tag}{procs}".format(tag=tag, procs=numJobs) +def onerror(func, path, exc_info): + """ + If the error is due to an access error (read only file) + add write permission and then retries. + If the error is for another reason it re-raises the error. + """ + import stat + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise ############################################################ # contextmanager @contextlib.contextmanager @@ -231,7 +244,7 @@ def RunCMake(context, extraArgs=None, stages=None): buildDir = context.buildDir if 'clean' in stages and os.path.isdir(buildDir): - shutil.rmtree(buildDir) + shutil.rmtree(buildDir, onerror=onerror) if 'clean' in stages and os.path.isdir(instDir): shutil.rmtree(instDir) @@ -267,7 +280,8 @@ def RunCMake(context, extraArgs=None, stages=None): os.remove(context.logFileLocation) if 'configure' in stages: - Run('cmake ' + Run(context, + 'cmake ' '-DCMAKE_INSTALL_PREFIX="{instDir}" ' '-DCMAKE_BUILD_TYPE={variant} ' '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON' @@ -287,14 +301,31 @@ def RunCMake(context, extraArgs=None, stages=None): installArg = "--target install" if 'build' in stages or 'install' in stages: - Run("cmake --build . --config {variant} {installArg} -- {multiproc}" + Run(context, "cmake --build . --config {variant} {installArg} -- {multiproc}" .format(variant=variant, installArg=installArg, multiproc=FormatMultiProcs(context.numJobs, generator))) -############################################################ -# Maya USD -def InstallMayaUSD(context, buildArgs, stages): +def RunCTest(context, extraArgs=None): + buildDir = context.buildDir + variant = BuildVariant(context) + #TODO we can't currently run tests in parallel, something to revisit. + numJobs = 1 + + with CurrentWorkingDirectory(buildDir): + Run(context, + 'ctest ' + '--output-on-failure ' + '--timeout 300 ' + '-j {numJobs} ' + '-C {variant} ' + '{extraArgs} ' + .format(numJobs=numJobs, + variant=variant, + extraArgs=(" ".join(extraArgs) if extraArgs else ""))) + + +def BuildAndInstall(context, buildArgs, stages): with CurrentWorkingDirectory(context.mayaUsdSrcDir): extraArgs = [] stagesArgs = [] @@ -310,17 +341,33 @@ def InstallMayaUSD(context, buildArgs, stages): extraArgs.append('-DMAYA_DEVKIT_LOCATION="{devkitLocation}"' .format(devkitLocation=context.devkitLocation)) - # Add on any user-specified extra arguments. extraArgs += buildArgs - - # Add on any user-specified stages arguments. stagesArgs += stages RunCMake(context, extraArgs, stagesArgs) + # Ensure directory structure is created and is writable. + for dir in [context.workspaceDir, context.buildDir, context.instDir]: + try: + if os.path.isdir(dir): + testFile = os.path.join(dir, "canwrite") + open(testFile, "w").close() + os.remove(testFile) + else: + os.makedirs(dir) + except Exception as e: + PrintError("Could not write to directory {dir}. Change permissions " + "or choose a different location to install to." + .format(dir=dir)) + sys.exit(1) + Print("""Success MayaUSD build and install !!!!""") + +def RunTests(context,extraArgs): + RunCTest(context,extraArgs) + Print("""Success running MayaUSD tests !!!!""") + ############################################################ # ArgumentParser - parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter) @@ -366,14 +413,20 @@ def InstallMayaUSD(context, buildArgs, stages): parser.add_argument("--build-args", type=str, nargs="*", default=[], help=("Comma-separated list of arguments passed into CMake when building libraries")) +parser.add_argument("--ctest-args", type=str, nargs="*", default=[], + help=("Comma-separated list of arguments passed into CTest.(e.g -VV, --output-on-failure)")) + parser.add_argument("--stages", type=str, nargs="*", default=['clean','configure','build','install'], - help=("Comma-separated list of stages to execute.( possible stages: clean, configure, build, install)")) + help=("Comma-separated list of stages to execute.(possible stages: clean, configure, build, install, test)")) parser.add_argument("-j", "--jobs", type=int, default=GetCPUCount(), help=("Number of build jobs to run in parallel. " "(default: # of processors [{0}])" .format(GetCPUCount()))) +parser.add_argument("--redirect-outstream-file", type=distutils.util.strtobool, dest="redirect_outstream_file", default=True, + help="Redirect output stream to a file. Set this flag to false to redirect output stream to console instead.") + args = parser.parse_args() verbosity = args.verbosity @@ -438,32 +491,49 @@ def __init__(self, args): for argList in args.stages: for arg in argList.split(","): self.stagesArgs.append(arg) + + # CTest arguments + self.ctestArgs = list() + for argList in args.ctest_args: + for arg in argList.split(","): + self.ctestArgs.append(arg) + + # Redirect output stream to file + self.redirectOutstreamFile = args.redirect_outstream_file try: context = InstallContext(args) except Exception as e: PrintError(str(e)) sys.exit(1) -# Summarize -summaryMsg = """ -Building with settings: - Source directory {mayaUsdSrcDir} - Workspace directory {workspaceDir} - Build directory {buildDir} - Install directory {instDir} - Variant {buildVariant} - CMake generator {cmakeGenerator} - Build Log {logFileLocation}""" - -if context.buildArgs: - summaryMsg += """ - Extra Build arguments {buildArgs}""" - -if context.stagesArgs: - summaryMsg += """ - Stages arguments {stagesArgs}""" - -summaryMsg = summaryMsg.format( +if __name__ == "__main__": + # Summarize + summaryMsg = """ + Building with settings: + Source directory {mayaUsdSrcDir} + Workspace directory {workspaceDir} + Build directory {buildDir} + Install directory {instDir} + Variant {buildVariant} + CMake generator {cmakeGenerator}""" + + if context.redirectOutstreamFile: + summaryMsg += """ + Build Log {logFileLocation}""" + + if context.buildArgs: + summaryMsg += """ + Build arguments {buildArgs}""" + + if context.stagesArgs: + summaryMsg += """ + Stages arguments {stagesArgs}""" + + if context.ctestArgs: + summaryMsg += """ + CTest arguments {ctestArgs}""" + + summaryMsg = summaryMsg.format( mayaUsdSrcDir=context.mayaUsdSrcDir, workspaceDir=context.workspaceDir, buildDir=context.buildDir, @@ -471,29 +541,19 @@ def __init__(self, args): logFileLocation=context.logFileLocation, buildArgs=context.buildArgs, stagesArgs=context.stagesArgs, + ctestArgs=context.ctestArgs, buildVariant=BuildVariant(context), cmakeGenerator=("Default" if not context.cmakeGenerator else context.cmakeGenerator) -) + ) -Print(summaryMsg) + Print(summaryMsg) -# Install MayaUSD -InstallMayaUSD(context, context.buildArgs, context.stagesArgs) + # BuildAndInstall + if any(stage in ['clean', 'configure', 'build', 'install'] for stage in context.stagesArgs): + BuildAndInstall(context, context.buildArgs, context.stagesArgs) + + # Run Tests + if 'test' in context.stagesArgs: + RunTests(context, context.ctestArgs) -# Ensure directory structure is created and is writable. -for dir in [context.workspaceDir, context.buildDir, context.instDir]: - try: - if os.path.isdir(dir): - testFile = os.path.join(dir, "canwrite") - open(testFile, "w").close() - os.remove(testFile) - else: - os.makedirs(dir) - except Exception as e: - PrintError("Could not write to directory {dir}. Change permissions " - "or choose a different location to install to." - .format(dir=dir)) - sys.exit(1) - -Print("""Success Maya USD build and install !!!!""") diff --git a/plugin/al/CMakeLists_googletest_download.txt.in b/cmake/CMakeLists_googletest_download.txt.in similarity index 100% rename from plugin/al/CMakeLists_googletest_download.txt.in rename to cmake/CMakeLists_googletest_download.txt.in diff --git a/plugin/al/CMakeLists_googletest_src.txt.in b/cmake/CMakeLists_googletest_src.txt.in similarity index 100% rename from plugin/al/CMakeLists_googletest_src.txt.in rename to cmake/CMakeLists_googletest_src.txt.in diff --git a/cmake/Googletest.cmake b/cmake/Googletest.cmake new file mode 100644 index 0000000000..ae9f4addb6 --- /dev/null +++ b/cmake/Googletest.cmake @@ -0,0 +1,82 @@ +macro(fetch_googletest) + + if (NOT GTEST_FOUND) + # First see if we can find a gtest that was downloaded and built. + if (NOT GOOGLETEST_BUILD_ROOT) + set(GOOGLETEST_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR}) + endif() + if (NOT GTEST_ROOT) + set(GTEST_ROOT "${GOOGLETEST_BUILD_ROOT}/googletest-install") + endif() + find_package(GTest QUIET) + # At this point GTEST_FOUND is set to True in Release but False in Debug. + endif() + + if (NOT GTEST_FOUND) + #====================================================================== + # Download and unpack googletest at configure time. Adapted from + # + # https://github.com/abseil/googletest/blob/master/googletest/README.md + # + # PPT, 22-Nov-2018. + + # Immediately convert CMAKE_MAKE_PROGRAM to forward slashes (if required). + # Attempting to do so in execute_process fails with string invalid escape + # sequence parsing errors. PPT, 22-Nov-2018. + file(TO_CMAKE_PATH ${CMAKE_MAKE_PROGRAM} CMAKE_MAKE_PROGRAM) + if (GOOGLETEST_SRC_DIR) + configure_file(cmake/CMakeLists_googletest_src.txt.in ${GOOGLETEST_BUILD_ROOT}/googletest-config/CMakeLists.txt) + else() + configure_file(cmake/CMakeLists_googletest_download.txt.in ${GOOGLETEST_BUILD_ROOT}/googletest-config/CMakeLists.txt) + endif() + + message(STATUS "========== Installing GoogleTest... ==========") + set(FORCE_SHARED_CRT "") + if(IS_WINDOWS) + set(FORCE_SHARED_CRT -DFORCE_SHARED_CRT=OFF) + endif() + execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} . ${FORCE_SHARED_CRT} + RESULT_VARIABLE result + WORKING_DIRECTORY ${GOOGLETEST_BUILD_ROOT}/googletest-config ) + if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") + endif() + + execute_process(COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} + RESULT_VARIABLE result + WORKING_DIRECTORY ${GOOGLETEST_BUILD_ROOT}/googletest-config ) + if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") + endif() + message(STATUS "========== ... GoogleTest installed. ==========") + + set(GTEST_ROOT ${GOOGLETEST_BUILD_ROOT}/googletest-install CACHE path "GoogleTest installation root") + endif() + + # https://gitlab.kitware.com/cmake/cmake/issues/17799 + # FindGtest is buggy when dealing with Debug build. + if (CMAKE_BUILD_TYPE MATCHES Debug AND GTEST_FOUND MATCHES FALSE) + message("Setting GTest libraries with debug...") + + if (GTEST_LIBRARY_DEBUG MATCHES GTEST_LIBRARY_DEBUG-NOTFOUND) + set(gtest_library "") + set(gtest_main_library "") + if(WIN32) + set(gtest_library lib/gtestd.lib) + set(gtest_main_library lib/gtest_maind.lib) + else() + set(gtest_library lib64/libgtestd.a) + set(gtest_main_library lib64/libgtest_maind.a) + endif() + set(GTEST_INCLUDE_DIRS ${GOOGLETEST_BUILD_ROOT}/googletest-install/include) + set(GTEST_LIBRARY_DEBUG ${GOOGLETEST_BUILD_ROOT}/googletest-install/${gtest_library}) + set(GTEST_MAIN_LIBRARY_DEBUG ${GOOGLETEST_BUILD_ROOT}/googletest-install/${gtest_main_library}) + endif() + + set(GTEST_LIBRARY ${GTEST_LIBRARY_DEBUG}) + set(GTEST_LIBRARIES ${GTEST_LIBRARY}) + set(GTEST_MAIN_LIBRARY ${GTEST_MAIN_LIBRARY_DEBUG}) + set(GTEST_MAIN_LIBRARIES ${GTEST_MAIN_LIBRARY}) + endif() + +endmacro() diff --git a/cmake/defaults/CXXDefaults.cmake b/cmake/defaults/CXXDefaults.cmake index 4d293a0513..755d729407 100644 --- a/cmake/defaults/CXXDefaults.cmake +++ b/cmake/defaults/CXXDefaults.cmake @@ -19,7 +19,7 @@ include(Options) if (CMAKE_COMPILER_IS_GNUCXX) include(gccdefaults) -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") include(clangdefaults) elseif(MSVC) include(msvcdefaults) @@ -32,7 +32,7 @@ _add_define(GLX_GLXEXT_PROTOTYPES) _add_define(BOOST_PYTHON_NO_PY_SIGNATURES) # Maya seems to require this -if (CMAKE_SYSTEM_NAME STREQUAL "Linux") +if (IS_LINUX) _add_define(LINUX) endif() diff --git a/cmake/jinja.cmake b/cmake/jinja.cmake new file mode 100644 index 0000000000..c72af00259 --- /dev/null +++ b/cmake/jinja.cmake @@ -0,0 +1,53 @@ +#- +# ======================================================================= +# Copyright 2018 Autodesk, Inc. All rights reserved. +# +# This computer source code and related instructions and comments are the +# unpublished confidential and proprietary information of Autodesk, Inc. +# and are protected under applicable copyright and trade secret law. They +# may not be disclosed to, copied or used by any third party without the +# prior written consent of Autodesk, Inc. +# ======================================================================= +#+ + +#------------------------------------------------------------------------------ +# +# Gets the Jinja2 and the dependant MarkupSafe python libraries from +# artifactory and set them up. +# +function(init_markupsafe) + + mayaUsd_find_python_module(markupsafe) + + if (NOT MARKUPSAFE_FOUND) + if (NOT MARKUPSAFE_LOCATION) + message(FATAL_ERROR "MARKUPSAFE_LOCATION not set") + endif() + + set(MARKUPSAFE_ROOT "${MARKUPSAFE_LOCATION}/src") + + # Add MarkupSafe to the python path so that Jinja2 can run properly. + mayaUsd_append_path_to_env_var("PYTHONPATH" "${MARKUPSAFE_ROOT}") + endif() + +endfunction() + +function(init_jinja) + + mayaUsd_find_python_module(jinja2) + + if (NOT JINJA2_FOUND) + if (NOT JINJA_LOCATION) + message(FATAL_ERROR "JINJA_LOCATION not set") + endif() + + set(JINJA_ROOT "${JINJA_LOCATION}") + + # Add Jinja2 to the python path so that usdGenSchemas can run properly. + mayaUsd_append_path_to_env_var("PYTHONPATH" "${JINJA_ROOT}") + endif() + +endfunction() + +init_markupsafe() +init_jinja() diff --git a/cmake/mayausd_version.info b/cmake/mayausd_version.info new file mode 100644 index 0000000000..bb330b08ef --- /dev/null +++ b/cmake/mayausd_version.info @@ -0,0 +1,3 @@ +set(MAYAUSD_MAJOR_VERSION 0) +set(MAYAUSD_MINOR_VERSION 1) +set(MAYAUSD_PATCH_LEVEL 0) diff --git a/cmake/modules/FindMaya.cmake b/cmake/modules/FindMaya.cmake index 716201d571..83cab0a6b7 100644 --- a/cmake/modules/FindMaya.cmake +++ b/cmake/modules/FindMaya.cmake @@ -26,7 +26,49 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) -if(APPLE) +#============================================================================= +# Macro for setting up typical plugin properties. These include: +# - OS-specific plugin suffix (.mll, .so, .bundle) +# - Removal of 'lib' prefix on osx/linux +# - OS-specific defines +# - Post-commnad for correcting Qt library linking on osx +# - Windows link flags for exporting initializePlugin/uninitializePlugin +macro(MAYA_SET_PLUGIN_PROPERTIES target) + set_target_properties(${target} PROPERTIES + SUFFIX ${MAYA_PLUGIN_SUFFIX}) + + set(_maya_DEFINES REQUIRE_IOSTREAM _BOOL) + + if(IS_MACOSX) + set(_maya_DEFINES "${_maya_DEFINES}" MAC_PLUGIN OSMac_ OSMac_MachO) + set_target_properties(${target} PROPERTIES + PREFIX "") + elseif(WIN32) + set(_maya_DEFINES "${_maya_DEFINES}" _AFXDLL _MBCS NT_PLUGIN) + set_target_properties( ${target} PROPERTIES + LINK_FLAGS "/export:initializePlugin /export:uninitializePlugin") + else() + set(_maya_DEFINES "${_maya_DEFINES}" LINUX LINUX_64) + set_target_properties( ${target} PROPERTIES + PREFIX "") + endif() + target_compile_definitions(${target} + PRIVATE + ${_maya_DEFINES} + ) + +endmacro(MAYA_SET_PLUGIN_PROPERTIES) +#============================================================================= + +if(IS_MACOSX) + set(MAYA_PLUGIN_SUFFIX ".bundle") +elseif(IS_WINDOWS) + set(MAYA_PLUGIN_SUFFIX ".mll") +else(IS_LINUX) + set(MAYA_PLUGIN_SUFFIX ".so") +endif() + +if(IS_MACOSX) # Note: according to official Autodesk sources (and how it sets up # MAYA_LOCATION itself), MAYA_LOCATION should include Maya.app/Contents # on MacOS - ie: @@ -62,7 +104,7 @@ if(APPLE) DOC "Maya's libraries path" ) -elseif(UNIX) +elseif(IS_LINUX) find_path(MAYA_BASE_DIR include/maya/MFn.h HINTS @@ -87,7 +129,7 @@ elseif(UNIX) DOC "Maya's libraries path" ) -elseif(WIN32) +elseif(IS_WINDOWS) find_path(MAYA_BASE_DIR include/maya/MFn.h HINTS diff --git a/cmake/modules/FindMayaUSD.cmake b/cmake/modules/FindMayaUSD.cmake deleted file mode 100644 index cdbdff6fe5..0000000000 --- a/cmake/modules/FindMayaUSD.cmake +++ /dev/null @@ -1,114 +0,0 @@ -# - MayaUSD finder module -# This module searches for a valid MayaUsd installation. -# It searches for MayaUSD's libraries and include header files -# -# Variables that will be defined: -# MAYAUSD_FOUND Defined if a MAYAUSD installation has been detected -# MAYAUSD_LIBRARY Path to MAYAUSD library -# MAYAUSD_INCLUDE_DIR Path to the MAYAUSD's include directories -# - -if(APPLE) - find_path(MAYAUSD_LIBRARY_DIR - libmayaUsd.dylib - HINTS - "${MAYAUSD_LIB_ROOT}" - "$ENV{MAYAUSD_LIB_ROOT}" - "${MAYA_DEVKIT_LOCATION}" - "${MAYA_LOCATION}" - "$ENV{MAYA_LOCATION}" - "${MAYA_BASE_DIR}" - PATH_SUFFIXES - devkit/mayaUsd/lib - lib/ - DOC - "MayaUSD's libraries path" - ) -elseif(UNIX) - find_path(MAYAUSD_LIBRARY_DIR - libmayaUsd.so - HINTS - "${MAYAUSD_LIB_ROOT}" - "$ENV{MAYAUSD_LIB_ROOT}" - "${MAYA_DEVKIT_LOCATION}" - "${MAYA_LOCATION}" - "$ENV{MAYA_LOCATION}" - "${MAYA_BASE_DIR}" - PATH_SUFFIXES - devkit/mayaUsd/lib - lib/ - DOC - "MayaUSD's libraries path" - ) -elseif(WIN32) - find_path(MAYAUSD_LIBRARY_DIR - mayaUsd.lib - HINTS - "${MAYAUSD_LIB_ROOT}" - "$ENV{MAYAUSD_LIB_ROOT}" - "${MAYA_DEVKIT_LOCATION}" - "${MAYA_LOCATION}" - "$ENV{MAYA_LOCATION}" - "${MAYA_BASE_DIR}" - PATH_SUFFIXES - devkit/mayaUsd/lib - lib/ - DOC - "MayaUSD's libraries path" - ) -endif() - -find_path(MAYAUSD_INCLUDE_DIR - mayaUsd/mayaUsd.h - HINTS - "${MAYAUSD_INCLUDE_ROOT}" - "$ENV{MAYAUSD_INCLUDE_ROOT}" - "${MAYA_DEVKIT_LOCATION}" - "${MAYA_LOCATION}" - "$ENV{MAYA_LOCATION}" - "${MAYA_BASE_DIR}" - PATH_SUFFIXES - devkit/mayaUsd/include - include/ - DOC - "MayaUSD's headers path" -) - -# Use find_library to account for platform-specific library name prefixes -# (e.g. lib) and suffixes (e.g. .lib, .so, .dylib). -foreach(MAYAUSD_LIB mayaUsd) - - find_library(MAYAUSD_LIBRARY - NAMES - ${MAYAUSD_LIB} - PATHS - ${MAYAUSD_LIBRARY_DIR} - NO_DEFAULT_PATH - ) - - if (MAYAUSD_LIBRARY) - list(APPEND MAYAUSD_LIBRARIES ${MAYAUSD_LIBRARY}) - endif() - -endforeach(MAYAUSD_LIB) - -# If we weren't passed in the MayaUsd version info, read it from the header file. -if (NOT DEFINED MAYAUSD_MAJOR_VERSION) - file(READ ${MAYAUSD_INCLUDE_DIR}/mayaUsd/mayaUsd.h MAYAUSD_MAIN_HEADER) - string(REGEX REPLACE ".*\#define MAYAUSD_MAJOR_VERSION[ ]+([0-9]+).*" "\\1" MAYAUSD_MAJOR_VERSION ${MAYAUSD_MAIN_HEADER}) - string(REGEX REPLACE ".*\#define MAYAUSD_MINOR_VERSION[ ]+([0-9]+).*" "\\1" MAYAUSD_MINOR_VERSION ${MAYAUSD_MAIN_HEADER}) - string(REGEX REPLACE ".*\#define MAYAUSD_PATCH_LEVEL[ ]+([0-9]+).*" "\\1" MAYAUSD_PATCH_LEVEL ${MAYAUSD_MAIN_HEADER}) -endif() -set(MAYAUSD_VERSION "${MAYAUSD_MAJOR_VERSION}.${MAYAUSD_MINOR_VERSION}.${MAYAUSD_PATCH_LEVEL}") - -# handle the QUIETLY and REQUIRED arguments and set MAYAUSD_FOUND to TRUE if -# all listed variables are TRUE -include(FindPackageHandleStandardArgs) - -find_package_handle_standard_args(MAYAUSD - REQUIRED_VARS - MAYAUSD_INCLUDE_DIR - MAYAUSD_LIBRARIES - VERSION_VAR - MAYAUSD_VERSION -) diff --git a/cmake/modules/FindUFE.cmake b/cmake/modules/FindUFE.cmake index 3a3ff0d09b..cd92e4ce0e 100644 --- a/cmake/modules/FindUFE.cmake +++ b/cmake/modules/FindUFE.cmake @@ -8,11 +8,13 @@ # UFE_FOUND Defined if a UFE installation has been detected # UFE_LIBRARY Path to UFE library # UFE_INCLUDE_DIR Path to the UFE include directory +# UFE_VERSION UFE version (major.minor.patch) from ufe.h # find_path(UFE_INCLUDE_DIR ufe/versionInfo.h HINTS + $ENV{UFE_INCLUDE_ROOT} ${UFE_INCLUDE_ROOT} ${MAYA_DEVKIT_LOCATION} ${MAYA_LOCATION} @@ -25,30 +27,38 @@ find_path(UFE_INCLUDE_DIR "UFE header path" ) -# get UFE_VERSION from ufe.h +# Get the UFE_VERSION and features from ufe.h if(UFE_INCLUDE_DIR AND EXISTS "${UFE_INCLUDE_DIR}/ufe/ufe.h") - foreach(_ufe_comp MAJOR MINOR) - file(STRINGS - "${UFE_INCLUDE_DIR}/ufe/ufe.h" - _ufe_tmp - REGEX "#define UFE_${_ufe_comp}_VERSION .*$") - string(REGEX MATCHALL "[0-9]+" UFE_${_ufe_comp}_VERSION ${_ufe_tmp}) - endforeach() - foreach(_ufe_comp PATCH) - file(STRINGS - "${UFE_INCLUDE_DIR}/ufe/ufe.h" - _ufe_tmp - REGEX "#define UFE_${_ufe_comp}_LEVEL .*$") - string(REGEX MATCHALL "[0-9]+" UFE_${_ufe_comp}_LEVEL ${_ufe_tmp}) - endforeach() + # Parse the file and get the three lines that have the version info. + file(STRINGS + "${UFE_INCLUDE_DIR}/ufe/ufe.h" + _ufe_vers + REGEX "#define[ ]+(UFE_MAJOR_VERSION|UFE_MINOR_VERSION|UFE_PATCH_LEVEL)[ ]+[0-9]+$") + # Then extract the number from each one. + foreach(_ufe_tmp ${_ufe_vers}) + if(_ufe_tmp MATCHES "#define[ ]+(UFE_MAJOR_VERSION|UFE_MINOR_VERSION|UFE_PATCH_LEVEL)[ ]+([0-9]+)$") + set(${CMAKE_MATCH_1} ${CMAKE_MATCH_2}) + endif() + endforeach() set(UFE_VERSION ${UFE_MAJOR_VERSION}.${UFE_MINOR_VERSION}.${UFE_PATCH_LEVEL}) + + file(STRINGS + "${UFE_INCLUDE_DIR}/ufe/ufe.h" + _ufe_features + REGEX "#define UFE_V[0-9]+_FEATURES_AVAILABLE$") + foreach(_ufe_tmp ${_ufe_features}) + if(_ufe_tmp MATCHES "#define UFE_V([0-9]+)_FEATURES_AVAILABLE$") + set(CMAKE_UFE_V${CMAKE_MATCH_1}_FEATURES_AVAILABLE ON) + endif() + endforeach() endif() find_library(UFE_LIBRARY NAMES ufe_${UFE_MAJOR_VERSION} HINTS + $ENV{UFE_LIB_ROOT} ${UFE_LIB_ROOT} ${MAYA_DEVKIT_LOCATION} ${MAYA_LOCATION} @@ -75,3 +85,9 @@ find_package_handle_standard_args(UFE VERSION_VAR UFE_VERSION ) + +if(UFE_FOUND) + message(STATUS "UFE include dir: ${UFE_INCLUDE_DIR}") + message(STATUS "UFE library: ${UFE_LIBRARY}") + message(STATUS "UFE version: ${UFE_VERSION}") +endif() diff --git a/cmake/modules/FindUSD.cmake b/cmake/modules/FindUSD.cmake index adee9bd56f..e0ca1e21b7 100644 --- a/cmake/modules/FindUSD.cmake +++ b/cmake/modules/FindUSD.cmake @@ -80,15 +80,19 @@ if(USD_INCLUDE_DIR AND EXISTS "${USD_INCLUDE_DIR}/pxr/pxr.h") set(USD_VERSION ${USD_MAJOR_VERSION}.${USD_MINOR_VERSION}.${USD_PATCH_VERSION}) endif() +message(STATUS "USD include dir: ${USD_INCLUDE_DIR}") +message(STATUS "USD library dir: ${USD_LIBRARY_DIR}") +message(STATUS "USD version: ${USD_VERSION}") + include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - USD -REQUIRED_VARS +find_package_handle_standard_args(USD + REQUIRED_VARS PXR_USD_LOCATION USD_INCLUDE_DIR USD_LIBRARY_DIR USD_GENSCHEMA USD_CONFIG_FILE -VERSION_VAR - USD_VERSION) + VERSION_VAR + USD_VERSION +) diff --git a/cmake/usd.cmake b/cmake/usd.cmake index 6d80eda691..8390ac3480 100644 --- a/cmake/usd.cmake +++ b/cmake/usd.cmake @@ -1,6 +1,6 @@ # # ======================================================================= -# Copyright 2019 Autodesk, Inc. All rights reserved. +# Copyright 2019 Autodesk # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,9 +19,9 @@ function(init_usd) # Adjust PYTHONPATH, PATH - append_path_to_env_var("PYTHONPATH" "${PXR_USD_LOCATION}/lib/python") + mayaUsd_append_path_to_env_var("PYTHONPATH" "${PXR_USD_LOCATION}/lib/python") if(WIN32) - append_path_to_env_var("PATH" "${PXR_USD_LOCATION}/bin;${PXR_USD_LOCATION}/lib") + mayaUsd_append_path_to_env_var("PATH" "${PXR_USD_LOCATION}/bin;${PXR_USD_LOCATION}/lib") endif() endfunction() diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 9e7f506e77..4b987d6efe 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -1,6 +1,6 @@ # # ======================================================================= -# Copyright 2019 Autodesk, Inc. All rights reserved. +# Copyright 2019 Autodesk # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,6 +16,17 @@ # ======================================================================= # +include(CMakeParseArguments) + +# The name of the operating system for which CMake is to build +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(IS_WINDOWS TRUE) +elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(IS_LINUX TRUE) +elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(IS_MACOSX TRUE) +endif() + # Appends a path to an environment variable. # Note: if you want to append multiple paths either call this multiple # times, or send in the paths with the proper platform separator. @@ -23,10 +34,10 @@ # envVar The environment variable to modify # pathToAppend The path to append # -function(append_path_to_env_var envVar pathToAppend) +function(mayaUsd_append_path_to_env_var envVar pathToAppend) file(TO_NATIVE_PATH "${pathToAppend}" nativePathToAppend) if(DEFINED ENV{${envVar}}) - if(WIN32) + if(IS_WINDOWS) set(newPath "$ENV{${envVar}};${nativePathToAppend}") else() set(newPath "$ENV{${envVar}}:${nativePathToAppend}") @@ -43,7 +54,7 @@ endfunction() # # module The python module to find # -function(find_python_module module) +function(mayaUsd_find_python_module module) string(TOUPPER ${module} module_upper) set(module_found "${module_upper}_FOUND") if(NOT ${module_found}) @@ -60,4 +71,202 @@ function(find_python_module module) "Location of Python module ${module}") endif(NOT _${module}_status) endif(NOT ${module_found}) -endfunction(find_python_module) +endfunction(mayaUsd_find_python_module) + +# Initialize a variable to accumulate an rpath. The origin is the +# RUNTIME DESTINATION of the target. If not absolute it's appended +# to CMAKE_INSTALL_PREFIX. +function(mayaUsd_init_rpath rpathRef origin) + if(NOT IS_ABSOLUTE ${origin}) + set(origin "${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX}/${origin}") + get_filename_component(origin "${origin}" REALPATH) + endif() + set(${rpathRef} "${origin}" PARENT_SCOPE) +endfunction() + +# Add a relative target path to the rpath. If target is absolute compute +# and add a relative path from the origin to the target. +function(mayaUsd_add_rpath rpathRef target) + if(IS_ABSOLUTE "${target}") + # init_rpath calls get_filename_component([...] REALPATH), which does + # symlink resolution, so we must do the same, otherwise relative path + # determination below will fail. + get_filename_component(target "${target}" REALPATH) + # Make target relative to $ORIGIN (which is the first element in + # rpath when initialized with _pxr_mayaUsd_init_rpath()). + list(GET ${rpathRef} 0 origin) + file(RELATIVE_PATH + target + "${origin}" + "${target}" + ) + if("x${target}" STREQUAL "x") + set(target ".") + endif() + endif() + file(TO_CMAKE_PATH "${target}" target) + set(new_rpath "${${rpathRef}}") + list(APPEND new_rpath "$ORIGIN/${target}") + set(${rpathRef} "${new_rpath}" PARENT_SCOPE) +endfunction() + +function(mayaUsd_install_rpath rpathRef NAME) + # Get and remove the origin. + list(GET ${rpathRef} 0 origin) + set(rpath ${${rpathRef}}) + list(REMOVE_AT rpath 0) + + # Canonicalize and uniquify paths. + set(final "") + foreach(path ${rpath}) + # Replace $ORIGIN with @loader_path + if(IS_MACOSX) + if("${path}/" MATCHES "^[$]ORIGIN/") + # Replace with origin path. + string(REPLACE "$ORIGIN/" "@loader_path/" path "${path}/") + endif() + endif() + + # Strip trailing slashes. + string(REGEX REPLACE "/+$" "" path "${path}") + + # Ignore paths we already have. + if (NOT ";${final};" MATCHES ";${path};") + list(APPEND final "${path}") + endif() + endforeach() + + set_target_properties(${NAME} + PROPERTIES + INSTALL_RPATH_USE_LINK_PATH TRUE + INSTALL_RPATH "${final}" + ) +endfunction() + +function(mayaUsd_promoteMayaUsdHeader) + set(srcFile ${CMAKE_CURRENT_SOURCE_DIR}/base/mayaUsd.h.src) + set(dstFile ${CMAKE_BINARY_DIR}/include/mayaUsd/mayaUsd.h) + if (NOT EXISTS ${dstFile}) + message(STATUS "promoting: " ${srcFile}) + endif() + configure_file(${srcFile} ${dstFile}) +endfunction() + +function(mayaUsd_promoteHeaderList) + foreach(header ${ARGV}) + set(srcFile ${CMAKE_CURRENT_SOURCE_DIR}/${header}) + set(dstFile ${CMAKE_BINARY_DIR}/include/mayaUsd/${header}) + + set(content "#pragma once\n#include \"${srcFile}\"\n") + + if (NOT EXISTS ${dstFile}) + message(STATUS "promoting: " ${srcFile}) + file(WRITE ${dstFile} "${content}") + else() + file(READ ${dstFile} oldContent) + if (NOT "${content}" STREQUAL "${oldContent}") + message(STATUS "Promoting ${srcfile}") + file(WRITE ${dstFile} "${content}") + endif() + endif() + endforeach() +endfunction() + +function(mayaUsd_get_unittest_target unittest_target unittest_basename) + get_filename_component(unittest_name ${unittest_basename} NAME_WE) + set(${unittest_target} "${unittest_name}" PARENT_SCOPE) +endfunction() + +# +# mayaUsd_copyFiles( +# [DESTINATION ] +# [FILES ]) +# +# DESTINATION - destination where files will be copied into. +# FILES - list of files to copy +# +function(mayaUsd_copyFiles target) + cmake_parse_arguments(PREFIX + "TARGET" + "DESTINATION" + "FILES" + ${ARGN} + ) + + if(PREFIX_DESTINATION) + set(destination ${PREFIX_DESTINATION}) + else() + message(FATAL_ERROR "DESTINATION keyword is not specified.") + endif() + + if(PREFIX_FILES) + set(srcFiles ${PREFIX_FILES}) + else() + message(FATAL_ERROR "FILES keyword is not specified.") + endif() + + foreach(file ${srcFiles}) + get_filename_component(input_file "${file}" ABSOLUTE) + get_filename_component(output_file "${destination}/${file}" ABSOLUTE) + + add_custom_command( + TARGET ${target} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${input_file} ${output_file} + DEPENDS "${srcFiles}" + COMMENT "copying file from ${input_file} to ${output_file}" + ) + endforeach() +endfunction() + +# +# mayaUsd_copyDirectory( +# [DESTINATION ] +# [DIRECTORY ]) +# +# DESTINATION - destination where directory will be copied into. +# DIRECTORY - directory to be copied. +# +function(mayaUsd_copyDirectory target) + cmake_parse_arguments(PREFIX + "TARGET" + "DESTINATION" + "DIRECTORY" + ${ARGN} + ) + + if(PREFIX_DESTINATION) + set(destination ${PREFIX_DESTINATION}) + endif() + if(NOT PREFIX_DESTINATION) + message(FATAL_ERROR "DESTINATION keyword is not specified.") + endif() + + if(PREFIX_DIRECTORY) + set(directory ${PREFIX_DIRECTORY}) + get_filename_component(directory "${directory}" ABSOLUTE) + get_filename_component(dir_name "${directory}" NAME) + endif() + if(NOT PREFIX_DIRECTORY) + message(FATAL_ERROR "DIRECTORY keyword is not specified.") + endif() + + # figure out files in directories by traversing all the subdirectories + # relative to directory + file(GLOB_RECURSE srcFiles RELATIVE ${directory} ${directory}/*) + + foreach(file ${srcFiles}) + get_filename_component(input_file "${dir_name}/${file}" ABSOLUTE) + get_filename_component(output_file "${destination}/${dir_name}/${file}" ABSOLUTE) + + add_custom_command( + TARGET ${target} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${input_file} ${output_file} + DEPENDS "${input_file}" + ) + + endforeach() +endfunction() \ No newline at end of file diff --git a/doc/DEVELOPER.md b/doc/DEVELOPER.md index ad39f08056..19b8afd2d4 100644 --- a/doc/DEVELOPER.md +++ b/doc/DEVELOPER.md @@ -3,6 +3,7 @@ | Location | Description | | ------------- | --------------- | | lib | The libraries that all other plugins depend on. Will contain common utilities and features. | +| plugin/adsk | The Autodesk Maya plugin | | plugin/pxr | The Pixar Maya plugin | | plugin/al | The Animal Logic Maya plugin | @@ -13,4 +14,5 @@ | ------------------- | ----------------- | ------------------- | | commit/tag | 1d08054 (>19.07) | 631a2911 (>0.34.0) | + \ No newline at end of file diff --git a/doc/build.md b/doc/build.md index 2af754e588..77b5e9091e 100644 --- a/doc/build.md +++ b/doc/build.md @@ -82,8 +82,11 @@ C:\> python build.py --maya-location "C:\Program Files\Autodesk\maya2019" --pxru Name | Description | Default --- | --- | --- -BUILD_AL_PLUGIN | Builds the Animal Logic USD plugin and libraries. | ON +BUILD_MAYAUSD_LIBRARY | Build Core USD libraries. | ON +BUILD_ADSK_PLUGIN | Build Autodesk USD plugin. | ON BUILD_PXR_PLUGIN | Builds the Pixar USD plugin and libraries. | ON +BUILD_AL_PLUGIN | Builds the Animal Logic USD plugin and libraries. | ON +BUILD_TESTS | Build tests. | ON # Building USD diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000000..df06d2a67f --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,426 @@ +# +# ======================================================================= +# Copyright 2019 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. +# ======================================================================= +# + +cmake_minimum_required(VERSION 3.1.1) +project(mayaUsd) + +if (POLICY CMP0074) + cmake_policy(SET CMP0074 OLD) +endif() + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +#============================================================================== +# Packages +#============================================================================== +set(BOOST_ROOT ${PXR_USD_LOCATION}) +find_package(Boost COMPONENTS + filesystem + REQUIRED +) + +#============================================================================== +# Library +#============================================================================== + +set(LIBRARY_NAME mayaUsd) + +list(APPEND mayaUsd_src + # + base/debugCodes.cpp + # + utils/colorSpace.cpp + utils/query.cpp + utils/util.cpp + utils/utilFileSystem.cpp + utils/stageCache.cpp + # + nodes/usdPrimProvider.cpp + nodes/proxyShapeBase.cpp + nodes/proxyShapePlugin.cpp + nodes/stageData.cpp + # + listeners/stageNoticeListener.cpp + listeners/notice.cpp + listeners/proxyShapeNotice.cpp + # + render/vp2RenderDelegate/debugCodes.cpp + render/vp2RenderDelegate/render_param.cpp + render/vp2RenderDelegate/instancer.cpp + render/vp2RenderDelegate/draw_item.cpp + render/vp2RenderDelegate/material.cpp + render/vp2RenderDelegate/mesh.cpp + render/vp2RenderDelegate/proxyRenderDelegate.cpp + render/vp2RenderDelegate/render_delegate.cpp + render/vp2RenderDelegate/sampler.cpp + # + render/vp2ShaderFragments/shaderFragments.cpp + # +) + +list(APPEND mayaUsdShaderFragments_xmls + # Copied from pxrUsdPreviewSurface with change to support multiple lights + render/vp2ShaderFragments/Float4ToFloatX.xml + render/vp2ShaderFragments/Float4ToFloatY.xml + render/vp2ShaderFragments/Float4ToFloatZ.xml + render/vp2ShaderFragments/Float4ToFloatW.xml + render/vp2ShaderFragments/lightingContributions.xml + render/vp2ShaderFragments/opacityToTransparency.xml + render/vp2ShaderFragments/scaledDiffusePassThrough.xml + render/vp2ShaderFragments/scaledSpecularPassThrough.xml + render/vp2ShaderFragments/usdPreviewSurfaceCombiner.xml + render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml + render/vp2ShaderFragments/UsdPreviewSurface.xml + # New fragments + render/vp2ShaderFragments/FallbackCPVShader.xml + render/vp2ShaderFragments/FallbackShader.xml + render/vp2ShaderFragments/Float4ToFloat3.xml + render/vp2ShaderFragments/Float4ToFloat4.xml + render/vp2ShaderFragments/UsdPrimvarReader_float.xml + render/vp2ShaderFragments/UsdPrimvarReader_float2.xml + render/vp2ShaderFragments/UsdPrimvarReader_float3.xml + render/vp2ShaderFragments/UsdPrimvarReader_float4.xml + render/vp2ShaderFragments/UsdUVTexture.xml + # USD plug info + render/vp2ShaderFragments/plugInfo.json +) + +if(UFE_FOUND) + list(APPEND mayaUsd_src + ufe/Global.cpp + ufe/Utils.cpp + ufe/ProxyShapeHandler.cpp + ufe/ProxyShapeHierarchy.cpp + ufe/ProxyShapeHierarchyHandler.cpp + ufe/StagesSubject.cpp + ufe/UsdHierarchy.cpp + ufe/UsdHierarchyHandler.cpp + ufe/UsdRootChildHierarchy.cpp + ufe/UsdRotatePivotTranslateUndoableCommand.cpp + ufe/UsdRotateUndoableCommand.cpp + ufe/UsdScaleUndoableCommand.cpp + ufe/UsdSceneItem.cpp + ufe/UsdSceneItemOps.cpp + ufe/UsdSceneItemOpsHandler.cpp + ufe/UsdStageMap.cpp + ufe/UsdTransform3d.cpp + ufe/UsdTransform3dHandler.cpp + ufe/UsdTranslateUndoableCommand.cpp + ufe/UsdUndoDeleteCommand.cpp + ufe/UsdUndoDuplicateCommand.cpp + ufe/UsdUndoRenameCommand.cpp + # + ufe/private/Utils.cpp + ) + + if(CMAKE_UFE_V2_FEATURES_AVAILABLE) + list(APPEND mayaUsd_src + ufe/UsdUndoCreateGroupCommand.cpp + ufe/UsdAttribute.cpp + ufe/UsdAttributes.cpp + ufe/UsdAttributesHandler.cpp + ) + endif() +endif() + +list(APPEND mayaUsdBase_headers + base/api.h + base/debugCodes.h +) + +list(APPEND mayaUsdUtils_headers + utils/colorSpace.h + utils/query.h + utils/util.h + utils/utilFileSystem.h + utils/stageCache.h + utils/query.h +) + +list(APPEND mayaUsdNodes_headers + nodes/usdPrimProvider.h + nodes/proxyShapeBase.h + nodes/proxyShapePlugin.h + nodes/stageData.h +) + +list(APPEND mayaUsdListeners_headers + listeners/stageNoticeListener.h + listeners/notice.h + listeners/proxyShapeNotice.h +) + +list(APPEND mayaUsdVP2RenderDelegate_headers + render/vp2RenderDelegate/proxyRenderDelegate.h +) + +if(UFE_FOUND) + list(APPEND mayaUsdUfe_headers + ufe/Global.h + ufe/Utils.h + ufe/ProxyShapeHandler.h + ufe/ProxyShapeHierarchy.h + ufe/ProxyShapeHierarchyHandler.h + ufe/StagesSubject.h + ufe/UsdHierarchy.h + ufe/UsdHierarchyHandler.h + ufe/UsdRootChildHierarchy.h + ufe/UsdRotatePivotTranslateUndoableCommand.h + ufe/UsdRotateUndoableCommand.h + ufe/UsdScaleUndoableCommand.h + ufe/UsdSceneItem.h + ufe/UsdSceneItemOps.h + ufe/UsdSceneItemOpsHandler.h + ufe/UsdStageMap.h + ufe/UsdTransform3d.h + ufe/UsdTransform3dHandler.h + ufe/UsdTranslateUndoableCommand.h + ufe/UsdUndoDeleteCommand.h + ufe/UsdUndoDuplicateCommand.h + ufe/UsdUndoRenameCommand.h + ) + + if(CMAKE_UFE_V2_FEATURES_AVAILABLE) + list(APPEND mayaUsdUfe_headers + ufe/UsdUndoCreateGroupCommand.h + ufe/UsdAttribute.h + ufe/UsdAttributes.h + ufe/UsdAttributesHandler.h + ) + endif() +endif() + +add_library(${LIBRARY_NAME} SHARED + ${mayaUsd_src} +) + +set(compile_definitions_list + MAYAUSD_MACROS_EXPORT + MAYAUSD_CORE_EXPORT + MFB_PACKAGE_NAME="${LIBRARY_NAME}" + MFB_ALT_PACKAGE_NAME="${LIBRARY_NAME}" + MFB_PACKAGE_MODULE=mayaUsd +) + +if(UFE_FOUND) + list(APPEND compile_definitions_list WANT_UFE_BUILD=1) +endif() +if(IS_MACOSX) + list(APPEND compile_definitions_list OSMac_) +endif() + +target_compile_definitions(${LIBRARY_NAME} PRIVATE + ${compile_definitions_list} +) + +# Some of the UFE classes are exporting STL classes which causes this warning. +if(UFE_FOUND AND MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251") + string(REPLACE " " ";" REPLACED_FLAGS ${CMAKE_CXX_FLAGS}) + target_compile_options(${LIBRARY_NAME} INTERFACE ${REPLACED_FLAGS}) +endif() + +set(include_directories_list + ${MAYA_INCLUDE_DIRS} + ${PXR_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR}/include +) + +if(UFE_FOUND) + list(APPEND include_directories_list ${UFE_INCLUDE_DIR}) +endif() + +target_include_directories( ${LIBRARY_NAME} PUBLIC + ${include_directories_list} +) + +target_link_libraries(${LIBRARY_NAME} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${MAYA_Foundation_LIBRARY} + ${MAYA_OpenMayaAnim_LIBRARY} + ${MAYA_OpenMaya_LIBRARY} + ${MAYA_OpenMayaRender_LIBRARY} + ${MAYA_OpenMayaUI_LIBRARY} + ar + gf + hd + hdx + js + kind + plug + sdf + tf + usd + usdGeom + usdImaging + usdImagingGL + usdLux + usdRi + usdShade + usdSkel + usdUtils + vt +) + +if(UFE_FOUND) + target_link_libraries(${LIBRARY_NAME} ${UFE_LIBRARY}) +endif() + +if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "plugin") + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + mayaUsd_install_rpath(rpath ${LIBRARY_NAME}) +endif() + +if (IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../USD/lib64") + endif() +endif() + +install(TARGETS ${LIBRARY_NAME} + LIBRARY + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib + ARCHIVE + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib + RUNTIME + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib +) +if(IS_WINDOWS) + install(FILES $ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) +endif() + +set_property(GLOBAL PROPERTY GLOBAL_LIBRARY_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}${LIBRARY_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}) + +# promote headers +mayaUsd_promoteMayaUsdHeader() +mayaUsd_promoteHeaderList(${mayaUsdBase_headers}) +mayaUsd_promoteHeaderList(${mayaUsdUtils_headers}) +mayaUsd_promoteHeaderList(${mayaUsdNodes_headers}) +mayaUsd_promoteHeaderList(${mayaUsdListeners_headers}) +mayaUsd_promoteHeaderList(${mayaUsdVP2RenderDelegate_headers}) +if(UFE_FOUND) + mayaUsd_promoteHeaderList(${mayaUsdUfe_headers}) +endif() + +# install public headers +install(FILES ${CMAKE_BINARY_DIR}/include/mayaUsd/mayaUsd.h + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/ +) + +install(FILES ${mayaUsdBase_headers} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/base/ +) + +install(FILES ${mayaUsdUtils_headers} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/utils/ +) + +install(FILES ${mayaUsdNodes_headers} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/nodes/ +) + +install(FILES ${mayaUsdListeners_headers} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/listeners/ +) + +install(FILES ${mayaUsdVP2RenderDelegate_headers} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/render/vp2RenderDelegate +) + +if(UFE_FOUND) + install(FILES ${mayaUsdUfe_headers} + DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mayaUsd/ufe + ) +endif() + +install(FILES ${mayaUsdShaderFragments_xmls} + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/usd/mayaUsd_ShaderFragments/resources +) + +#install top level plugInfo.json that includes the configured plugInfo.json +install(CODE + "file(WRITE \"${CMAKE_INSTALL_PREFIX}/lib/usd/plugInfo.json\" \"{\n \\\"Includes\\\": [ \\\"*/resources/\\\" ]\n}\")" +) + +if(UFE_FOUND) + # UFE Python Bindings + set(UFE_PYTHON_LIBRARY_NAME ufe) + + add_library(${UFE_PYTHON_LIBRARY_NAME} + SHARED + ufe/wrapUtils.cpp + ) + + target_compile_definitions(${UFE_PYTHON_LIBRARY_NAME} + PRIVATE + MFB_PACKAGE_NAME=${LIBRARY_NAME} + MFB_ALT_PACKAGE_NAME=${LIBRARY_NAME} + MFB_PACKAGE_MODULE=ufe + ) + set_target_properties(${UFE_PYTHON_LIBRARY_NAME} + PROPERTIES + PREFIX "" + ) + if(IS_WINDOWS) + set_target_properties(${UFE_PYTHON_LIBRARY_NAME} + PROPERTIES + SUFFIX ".pyd" + ) + elseif(IS_MACOSX) + set_target_properties(${UFE_PYTHON_LIBRARY_NAME} + PROPERTIES + SUFFIX ".so" + ) + endif() + + target_link_libraries(${UFE_PYTHON_LIBRARY_NAME} + ${LIBRARY_NAME} + ) + + if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "${PROJECT_NAME}") + mayaUsd_add_rpath(rpath "../..") + mayaUsd_install_rpath(rpath ${UFE_PYTHON_LIBRARY_NAME}) + endif() + + install(TARGETS ${UFE_PYTHON_LIBRARY_NAME} + LIBRARY + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/${PROJECT_NAME} + RUNTIME + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/${PROJECT_NAME} + ) + + if(IS_WINDOWS) + install(FILES $ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/${PROJECT_NAME} OPTIONAL) + endif() + + install(FILES ufe/__init__.py + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/python/${PROJECT_NAME} + ) + +endif() + +if(IS_MACOSX) + set(_macDef OSMac_) +endif() diff --git a/lib/README.md b/lib/README.md index 39f3a912b6..2859cc8769 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,3 +1 @@ -## NOTE - -This folder holds the libraries that all other plugins depend on. It will contain library of building blocks. +# Core library diff --git a/lib/base/api.h b/lib/base/api.h new file mode 100644 index 0000000000..1b7d90198d --- /dev/null +++ b/lib/base/api.h @@ -0,0 +1,78 @@ +// +// Copyright 2019 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. +// + +#include "pxr/base/arch/export.h" + +#if defined _WIN32 || defined __CYGWIN__ + + // The main export symbol used for the core library. + #ifdef MAYAUSD_CORE_EXPORT + #ifdef __GNUC__ + #define MAYAUSD_CORE_PUBLIC __attribute__ ((dllexport)) + #else + #define MAYAUSD_CORE_PUBLIC __declspec(dllexport) + #endif + #else + #ifdef __GNUC__ + #define MAYAUSD_CORE_PUBLIC __attribute__ ((dllimport)) + #else + #define MAYAUSD_CORE_PUBLIC __declspec(dllimport) + #endif + #endif + #define MAYAUSD_CORE_LOCAL + + // We have a separate export symbol used in the helper macros. + #ifdef MAYAUSD_MACROS_EXPORT + #ifdef __GNUC__ + #define MAYAUSD_MACROS_PUBLIC __attribute__ ((dllexport)) + #else + #define MAYAUSD_MACROS_PUBLIC __declspec(dllexport) + #endif + #else + #ifdef __GNUC__ + #define MAYAUSD_MACROS_PUBLIC __attribute__ ((dllimport)) + #else + #define MAYAUSD_MACROS_PUBLIC __declspec(dllimport) + #endif + #endif + #define MAYAUSD_MACROS_LOCAL +#else + #if __GNUC__ >= 4 + #define MAYAUSD_CORE_PUBLIC __attribute__ ((visibility ("default"))) + #define MAYAUSD_CORE_LOCAL __attribute__ ((visibility ("hidden"))) + + #define MAYAUSD_MACROS_PUBLIC __attribute__ ((visibility ("default"))) + #define MAYAUSD_MACROS_LOCAL __attribute__ ((visibility ("hidden"))) +#else + #define MAYAUSD_CORE_PUBLIC + #define MAYAUSD_CORE_LOCAL + + #define MAYAUSD_MACROS_PUBLIC + #define MAYAUSD_MACROS_LOCAL +#endif +#endif + +#ifdef MAYAUSD_CORE_EXPORT + #define MAYAUSD_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) + #define MAYAUSD_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) +#else + #define MAYAUSD_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) + #define MAYAUSD_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) +#endif + +// Convenience symbol versioning include: because api.h is widely +// included, this reduces the need to explicitly include mayaUsd.h. +#include "mayaUsd/mayaUsd.h" diff --git a/plugin/pxr/maya/lib/usdMaya/debugCodes.cpp b/lib/base/debugCodes.cpp similarity index 96% rename from plugin/pxr/maya/lib/usdMaya/debugCodes.cpp rename to lib/base/debugCodes.cpp index ba9d0c57a4..78c67aad67 100644 --- a/plugin/pxr/maya/lib/usdMaya/debugCodes.cpp +++ b/lib/base/debugCodes.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/debugCodes.h" +#include "base/debugCodes.h" #include "pxr/base/tf/registryManager.h" diff --git a/plugin/pxr/maya/lib/usdMaya/debugCodes.h b/lib/base/debugCodes.h similarity index 90% rename from plugin/pxr/maya/lib/usdMaya/debugCodes.h rename to lib/base/debugCodes.h index 66570694bd..12f737713e 100644 --- a/plugin/pxr/maya/lib/usdMaya/debugCodes.h +++ b/lib/base/debugCodes.h @@ -24,7 +24,9 @@ PXR_NAMESPACE_OPEN_SCOPE TF_DEBUG_CODES( PXRUSDMAYA_REGISTRY, - PXRUSDMAYA_DIAGNOSTICS + PXRUSDMAYA_DIAGNOSTICS, + PXRUSDMAYA_TRANSLATORS, + USDMAYA_PROXYSHAPEBASE ); diff --git a/lib/base/mayaUsd.h.src b/lib/base/mayaUsd.h.src new file mode 100644 index 0000000000..5bb026b7a1 --- /dev/null +++ b/lib/base/mayaUsd.h.src @@ -0,0 +1,46 @@ +// +// Copyright 2019 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. +// + +#pragma once + +#define MAYAUSD_MAJOR_VERSION ${MAYAUSD_MAJOR_VERSION} +#define MAYAUSD_MINOR_VERSION ${MAYAUSD_MINOR_VERSION} +#define MAYAUSD_PATCH_LEVEL ${MAYAUSD_PATCH_LEVEL} + +// MayaUsd public namespace string will never change. +#define MAYAUSD_NS MayaUsd +// C preprocessor trickery to expand arguments. +#define MAYAUSD_CONCAT(A, B) MAYAUSD_CONCAT_IMPL(A, B) +#define MAYAUSD_CONCAT_IMPL(A, B) A##B +// Versioned namespace includes the major version number. +#define MAYAUSD_VERSIONED_NS MAYAUSD_CONCAT(MAYAUSD_NS, _v${MAYAUSD_MAJOR_VERSION}) + +namespace MAYAUSD_VERSIONED_NS {} + +// With a using namespace declaration, pull in the versioned namespace into the +// MayaUsd public namespace, to allow client code to use the plain MayaUsd +// namespace, e.g. MayaUsd::Class. +namespace MAYAUSD_NS { + using namespace MAYAUSD_VERSIONED_NS; +} + +// Macros to place the MayaUsd symbols in the versioned namespace, which is how +// they will appear in the shared library, e.g. MayaUsd_v1::Class. +#ifdef DOXYGEN +#define MAYAUSD_NS_DEF namespace MAYAUSD_NS +#else +#define MAYAUSD_NS_DEF namespace MAYAUSD_VERSIONED_NS +#endif diff --git a/plugin/pxr/maya/lib/usdMaya/notice.cpp b/lib/listeners/notice.cpp similarity index 99% rename from plugin/pxr/maya/lib/usdMaya/notice.cpp rename to lib/listeners/notice.cpp index 0b5d946294..badd984b53 100644 --- a/plugin/pxr/maya/lib/usdMaya/notice.cpp +++ b/lib/listeners/notice.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/notice.h" +#include "notice.h" #include "pxr/base/tf/instantiateType.h" diff --git a/plugin/pxr/maya/lib/usdMaya/notice.h b/lib/listeners/notice.h similarity index 91% rename from plugin/pxr/maya/lib/usdMaya/notice.h rename to lib/listeners/notice.h index 6187941293..5fe84749bb 100644 --- a/plugin/pxr/maya/lib/usdMaya/notice.h +++ b/lib/listeners/notice.h @@ -20,7 +20,7 @@ #include "pxr/base/tf/notice.h" -#include "usdMaya/api.h" +#include "../base/api.h" #include #include @@ -34,15 +34,15 @@ PXR_NAMESPACE_OPEN_SCOPE class UsdMayaSceneResetNotice : public TfNotice { public: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC UsdMayaSceneResetNotice(); /// Registers the proper Maya callbacks for recognizing stage resets. - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static void InstallListener(); /// Removes any Maya callbacks for recognizing stage resets. - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static void RemoveListener(); private: @@ -53,17 +53,17 @@ class UsdMayaSceneResetNotice : public TfNotice class UsdMaya_AssemblyInstancerNoticeBase : public TfNotice { public: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC virtual ~UsdMaya_AssemblyInstancerNoticeBase() = default; - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC MObject GetAssembly() const; - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC MObject GetInstancer() const; protected: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC UsdMaya_AssemblyInstancerNoticeBase( const MObject& assembly, const MObject& instancer); @@ -79,7 +79,7 @@ class UsdMayaAssemblyConnectedToInstancerNotice : public UsdMaya_AssemblyInstancerNoticeBase { public: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC UsdMayaAssemblyConnectedToInstancerNotice( const MObject& assembly, const MObject& instancer); @@ -91,7 +91,7 @@ class UsdMayaAssemblyDisconnectedFromInstancerNotice : public UsdMaya_AssemblyInstancerNoticeBase { public: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC UsdMayaAssemblyDisconnectedFromInstancerNotice( const MObject& assembly, const MObject& instancer); diff --git a/lib/listeners/proxyShapeNotice.cpp b/lib/listeners/proxyShapeNotice.cpp new file mode 100644 index 0000000000..db6caa8e20 --- /dev/null +++ b/lib/listeners/proxyShapeNotice.cpp @@ -0,0 +1,38 @@ +// +// Copyright 2018 Pixar +// +// 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. +// +#include "proxyShapeNotice.h" + +#include "pxr/base/tf/instantiateType.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_INSTANTIATE_TYPE(UsdMayaProxyStageSetNotice, + TfType::CONCRETE, TF_1_PARENT(TfNotice)); + +UsdMayaProxyStageSetNotice::UsdMayaProxyStageSetNotice( + const MayaUsdProxyShapeBase& proxy) + : _proxy(proxy) +{ +} + +const MayaUsdProxyShapeBase& +UsdMayaProxyStageSetNotice::GetProxyShape() const +{ + return _proxy; +} + + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/listeners/proxyShapeNotice.h b/lib/listeners/proxyShapeNotice.h new file mode 100644 index 0000000000..b5f6733c59 --- /dev/null +++ b/lib/listeners/proxyShapeNotice.h @@ -0,0 +1,48 @@ +// +// Copyright 2018 Pixar +// +// 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. +// +#ifndef USDMAYA_PROXYSTAGE_NOTICE_H +#define USDMAYA_PROXYSTAGE_NOTICE_H + +/// \file usdMaya/proxyShapeNotice.h + +#include "pxr/base/tf/notice.h" + +#include "../base/api.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class MayaUsdProxyShapeBase; + +/// Notice sent when the ProxyShape loads a new stage +class UsdMayaProxyStageSetNotice : public TfNotice +{ +public: + MAYAUSD_CORE_PUBLIC + UsdMayaProxyStageSetNotice(const MayaUsdProxyShapeBase& proxy); + + /// Get proxy shape which had stage set + MAYAUSD_CORE_PUBLIC + const MayaUsdProxyShapeBase& GetProxyShape() const; + +private: + const MayaUsdProxyShapeBase& _proxy; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/plugin/pxr/maya/lib/usdMaya/stageNoticeListener.cpp b/lib/listeners/stageNoticeListener.cpp similarity index 98% rename from plugin/pxr/maya/lib/usdMaya/stageNoticeListener.cpp rename to lib/listeners/stageNoticeListener.cpp index 11b95c539e..9bbc0d841a 100644 --- a/plugin/pxr/maya/lib/usdMaya/stageNoticeListener.cpp +++ b/lib/listeners/stageNoticeListener.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/stageNoticeListener.h" +#include "stageNoticeListener.h" #include "pxr/base/tf/notice.h" #include "pxr/base/tf/weakBase.h" diff --git a/plugin/pxr/maya/lib/usdMaya/stageNoticeListener.h b/lib/listeners/stageNoticeListener.h similarity index 94% rename from plugin/pxr/maya/lib/usdMaya/stageNoticeListener.h rename to lib/listeners/stageNoticeListener.h index 071b26ed8d..6039715eb9 100644 --- a/plugin/pxr/maya/lib/usdMaya/stageNoticeListener.h +++ b/lib/listeners/stageNoticeListener.h @@ -18,7 +18,7 @@ /// \file usdMaya/stageNoticeListener.h -#include "usdMaya/api.h" +#include "../base/api.h" #include "pxr/pxr.h" @@ -43,14 +43,14 @@ PXR_NAMESPACE_OPEN_SCOPE class UsdMayaStageNoticeListener : public TfWeakBase { public: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC UsdMayaStageNoticeListener(); - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC virtual ~UsdMayaStageNoticeListener(); /// Set the USD stage for which this instance will listen for notices. - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC void SetStage(const UsdStageWeakPtr& stage); /// Callback type for StageContentsChanged notices. @@ -59,7 +59,7 @@ class UsdMayaStageNoticeListener : public TfWeakBase /// Sets the callback to be invoked when the listener receives a /// StageContentsChanged notice. - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC void SetStageContentsChangedCallback( const StageContentsChangedCallback& callback); diff --git a/lib/nodes/proxyShapeBase.cpp b/lib/nodes/proxyShapeBase.cpp new file mode 100644 index 0000000000..194db069f2 --- /dev/null +++ b/lib/nodes/proxyShapeBase.cpp @@ -0,0 +1,1027 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#include "proxyShapeBase.h" + +#include "../base/debugCodes.h" +#include "../listeners/proxyShapeNotice.h" +#include "../utils/query.h" +#include "../utils/stageCache.h" +#include "../utils/utilFileSystem.h" +#include "stageData.h" + +#include "pxr/base/gf/bbox3d.h" +#include "pxr/base/gf/range3d.h" +#include "pxr/base/gf/ray.h" +#include "pxr/base/gf/vec3d.h" +#include "pxr/base/tf/envSetting.h" +#include "pxr/base/tf/fileUtils.h" +#include "pxr/base/tf/hash.h" +#include "pxr/base/tf/pathUtils.h" +#include "pxr/base/tf/staticData.h" +#include "pxr/base/tf/staticTokens.h" +#include "pxr/base/tf/stringUtils.h" +#include "pxr/base/tf/token.h" + +#include "pxr/usd/ar/resolver.h" +#include "pxr/usd/sdf/layer.h" +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/usd/stageCacheContext.h" +#include "pxr/usd/usd/timeCode.h" +#include "pxr/usd/usdGeom/bboxCache.h" +#include "pxr/usd/usdGeom/imageable.h" +#include "pxr/usd/usdGeom/tokens.h" +#include "pxr/usd/usdUtils/stageCache.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(WANT_UFE_BUILD) +#include +#endif + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PUBLIC_TOKENS(MayaUsdProxyShapeBaseTokens, + MAYAUSD_PROXY_SHAPE_BASE_TOKENS); + +MayaUsdProxyShapeBase::ClosestPointDelegate +MayaUsdProxyShapeBase::_sharedClosestPointDelegate = nullptr; + + +// ======================================================== + +// TypeID from the MayaUsd type ID range. +const MTypeId MayaUsdProxyShapeBase::typeId(0x58000094); +const MString MayaUsdProxyShapeBase::typeName( + MayaUsdProxyShapeBaseTokens->MayaTypeName.GetText()); + +const MString MayaUsdProxyShapeBase::displayFilterName( + TfStringPrintf("%sDisplayFilter", + MayaUsdProxyShapeBaseTokens->MayaTypeName.GetText()).c_str()); +const MString MayaUsdProxyShapeBase::displayFilterLabel("USD Proxies"); + +// Attributes +MObject MayaUsdProxyShapeBase::filePathAttr; +MObject MayaUsdProxyShapeBase::primPathAttr; +MObject MayaUsdProxyShapeBase::excludePrimPathsAttr; +MObject MayaUsdProxyShapeBase::timeAttr; +MObject MayaUsdProxyShapeBase::complexityAttr; +MObject MayaUsdProxyShapeBase::inStageDataAttr; +MObject MayaUsdProxyShapeBase::inStageDataCachedAttr; +MObject MayaUsdProxyShapeBase::outStageDataAttr; +MObject MayaUsdProxyShapeBase::drawRenderPurposeAttr; +MObject MayaUsdProxyShapeBase::drawProxyPurposeAttr; +MObject MayaUsdProxyShapeBase::drawGuidePurposeAttr; + + +/* static */ +void* +MayaUsdProxyShapeBase::creator() +{ + return new MayaUsdProxyShapeBase(); +} + +/* static */ +MStatus +MayaUsdProxyShapeBase::initialize() +{ + MStatus retValue = MS::kSuccess; + + // + // create attr factories + // + MFnNumericAttribute numericAttrFn; + MFnTypedAttribute typedAttrFn; + MFnUnitAttribute unitAttrFn; + + filePathAttr = typedAttrFn.create( + "filePath", + "fp", + MFnData::kString, + MObject::kNullObj, + &retValue); + typedAttrFn.setInternal(true); + typedAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(filePathAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + primPathAttr = typedAttrFn.create( + "primPath", + "pp", + MFnData::kString, + MObject::kNullObj, + &retValue); + typedAttrFn.setInternal(true); + typedAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(primPathAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + excludePrimPathsAttr = typedAttrFn.create( + "excludePrimPaths", + "epp", + MFnData::kString, + MObject::kNullObj, + &retValue); + typedAttrFn.setInternal(true); + typedAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(excludePrimPathsAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + timeAttr = unitAttrFn.create( + "time", + "tm", + MFnUnitAttribute::kTime, + 0.0, + &retValue); + unitAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(timeAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + complexityAttr = numericAttrFn.create( + "complexity", + "cplx", + MFnNumericData::kInt, + 0, + &retValue); + numericAttrFn.setMin(0); + numericAttrFn.setSoftMax(4); + numericAttrFn.setMax(8); + numericAttrFn.setChannelBox(true); + numericAttrFn.setStorable(false); + numericAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(complexityAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + inStageDataAttr = typedAttrFn.create( + "inStageData", + "id", + MayaUsdStageData::mayaTypeId, + MObject::kNullObj, + &retValue); + typedAttrFn.setReadable(false); + typedAttrFn.setStorable(false); + typedAttrFn.setDisconnectBehavior(MFnNumericAttribute::kReset); // on disconnect, reset to Null + typedAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(inStageDataAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // inStageData or filepath-> inStageDataCached -> outStageData + inStageDataCachedAttr = typedAttrFn.create( + "inStageDataCached", + "idc", + MayaUsdStageData::mayaTypeId, + MObject::kNullObj, + &retValue); + typedAttrFn.setStorable(false); + typedAttrFn.setWritable(false); + typedAttrFn.setAffectsAppearance(true); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(inStageDataCachedAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + outStageDataAttr = typedAttrFn.create( + "outStageData", + "od", + MayaUsdStageData::mayaTypeId, + MObject::kNullObj, + &retValue); + typedAttrFn.setStorable(false); + typedAttrFn.setWritable(false); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = addAttribute(outStageDataAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + drawRenderPurposeAttr = numericAttrFn.create( + "drawRenderPurpose", + "drp", + MFnNumericData::kBoolean, + 0.0, + &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + numericAttrFn.setKeyable(true); + numericAttrFn.setReadable(false); + numericAttrFn.setAffectsAppearance(true); + retValue = addAttribute(drawRenderPurposeAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + drawProxyPurposeAttr = numericAttrFn.create( + "drawProxyPurpose", + "dpp", + MFnNumericData::kBoolean, + 1.0, + &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + numericAttrFn.setKeyable(true); + numericAttrFn.setReadable(false); + numericAttrFn.setAffectsAppearance(true); + retValue = addAttribute(drawProxyPurposeAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + drawGuidePurposeAttr = numericAttrFn.create( + "drawGuidePurpose", + "dgp", + MFnNumericData::kBoolean, + 0.0, + &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + numericAttrFn.setKeyable(true); + numericAttrFn.setReadable(false); + numericAttrFn.setAffectsAppearance(true); + retValue = addAttribute(drawGuidePurposeAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // + // add attribute dependencies + // + retValue = attributeAffects(filePathAttr, inStageDataCachedAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = attributeAffects(filePathAttr, outStageDataAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + retValue = attributeAffects(primPathAttr, inStageDataCachedAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = attributeAffects(primPathAttr, outStageDataAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + retValue = attributeAffects(inStageDataAttr, inStageDataCachedAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + retValue = attributeAffects(inStageDataAttr, outStageDataAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + retValue = attributeAffects(inStageDataCachedAttr, outStageDataAttr); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + return retValue; +} + +/* static */ +MayaUsdProxyShapeBase* +MayaUsdProxyShapeBase::GetShapeAtDagPath(const MDagPath& dagPath) +{ + MObject mObj = dagPath.node(); + if (mObj.apiType() != MFn::kPluginShape) { + TF_CODING_ERROR( + "Could not get MayaUsdProxyShapeBase for non-plugin shape node " + "at DAG path: %s (apiTypeStr = %s)", + dagPath.fullPathName().asChar(), + mObj.apiTypeStr()); + return nullptr; + } + + const MFnDependencyNode depNodeFn(mObj); + MayaUsdProxyShapeBase* pShape = + static_cast(depNodeFn.userNode()); + if (!pShape) { + TF_CODING_ERROR( + "Could not get MayaUsdProxyShapeBase for node at DAG path: %s", + dagPath.fullPathName().asChar()); + return nullptr; + } + + return pShape; +} + +/* static */ +void +MayaUsdProxyShapeBase::SetClosestPointDelegate(ClosestPointDelegate delegate) +{ + _sharedClosestPointDelegate = delegate; +} + +/* virtual */ +bool +MayaUsdProxyShapeBase::GetObjectSoftSelectEnabled() const +{ + return false; +} + +/* virtual */ +void +MayaUsdProxyShapeBase::postConstructor() +{ + setRenderable(true); +} + +/* virtual */ +MStatus +MayaUsdProxyShapeBase::compute(const MPlug& plug, MDataBlock& dataBlock) +{ + if (plug == excludePrimPathsAttr || + plug == timeAttr || + plug == complexityAttr || + plug == drawRenderPurposeAttr || + plug == drawProxyPurposeAttr || + plug == drawGuidePurposeAttr) { + // If the attribute that needs to be computed is one of these, then it + // does not affect the ouput stage data, but it *does* affect imaging + // the shape. In that case, we notify Maya that the shape needs to be + // redrawn and let it take care of computing the attribute. This covers + // the case where an attribute on the proxy shape may have an incoming + // connection from another node (e.g. "time1.outTime" being connected + // to the proxy shape's "time" attribute). In that case, + // setDependentsDirty() might not get called and only compute() might. + MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); + return MS::kUnknownParameter; + } + else if (plug == inStageDataCachedAttr) { + return computeInStageDataCached(dataBlock); + } + else if (plug == outStageDataAttr) { + return computeOutStageData(dataBlock); + } + + return MS::kUnknownParameter; +} + +/* virtual */ +SdfLayerRefPtr +MayaUsdProxyShapeBase::computeSessionLayer(MDataBlock&) +{ + return nullptr; +} + +MStatus +MayaUsdProxyShapeBase::computeInStageDataCached(MDataBlock& dataBlock) +{ + MStatus retValue = MS::kSuccess; + + MDataHandle inDataHandle = dataBlock.inputValue(inStageDataAttr, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // If inData has an incoming connection, then use it. Otherwise generate stage from the filepath + if (!inDataHandle.data().isNull() ) { + // + // Propagate inData -> inDataCached + // + MDataHandle inDataCachedHandle = dataBlock.outputValue(inStageDataCachedAttr, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + inDataCachedHandle.copy(inDataHandle); + + inDataCachedHandle.setClean(); + return MS::kSuccess; + } + else { + // + // Calculate from USD filepath and primPath and variantKey + // + + // Get input attr values + const MString file = dataBlock.inputValue(filePathAttr, &retValue).asString(); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // + // let the usd stage cache deal with caching the usd stage data + // + std::string fileString = TfStringTrimRight(file.asChar()); + + TF_DEBUG(USDMAYA_PROXYSHAPEBASE).Msg("ProxyShapeBase::reloadStage original USD file path is %s\n", fileString.c_str()); + + boost::filesystem::path filestringPath(fileString); + if(filestringPath.is_absolute()) + { + fileString = UsdMayaUtilFileSystem::resolvePath(fileString); + TF_DEBUG(USDMAYA_PROXYSHAPEBASE).Msg("ProxyShapeBase::reloadStage resolved the USD file path to %s\n", fileString.c_str()); + } + else + { + fileString = UsdMayaUtilFileSystem::resolveRelativePathWithinMayaContext(thisMObject(), fileString); + TF_DEBUG(USDMAYA_PROXYSHAPEBASE).Msg("ProxyShapeBase::reloadStage resolved the relative USD file path to %s\n", fileString.c_str()); + } + + // Fall back on providing the path "as is" to USD + if (fileString.empty()) + { + fileString.assign(file.asChar(), file.length()); + } + + TF_DEBUG(USDMAYA_PROXYSHAPEBASE).Msg("ProxyShapeBase::loadStage called for the usd file: %s\n", fileString.c_str()); + + // == Load the Stage + UsdStageRefPtr usdStage; + SdfPath primPath; + + if (SdfLayerRefPtr rootLayer = SdfLayer::FindOrOpen(fileString)) { + UsdStageCacheContext ctx(UsdMayaStageCache::Get()); + SdfLayerRefPtr sessionLayer = computeSessionLayer(dataBlock); + if (sessionLayer) { + usdStage = UsdStage::Open(rootLayer, + sessionLayer, + ArGetResolver().GetCurrentContext()); + } else { + usdStage = UsdStage::Open(rootLayer, + ArGetResolver().GetCurrentContext()); + } + + usdStage->SetEditTarget(usdStage->GetSessionLayer()); + } + + if (usdStage) { + primPath = usdStage->GetPseudoRoot().GetPath(); + } + + // Create the output outData ======== + MFnPluginData pluginDataFn; + MObject stageDataObj = + pluginDataFn.create(MayaUsdStageData::mayaTypeId, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + MayaUsdStageData* stageData = + reinterpret_cast(pluginDataFn.data(&retValue)); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // Set the outUsdStageData + stageData->stage = usdStage; + stageData->primPath = primPath; + + // + // set the data on the output plug + // + MDataHandle inDataCachedHandle = + dataBlock.outputValue(inStageDataCachedAttr, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + inDataCachedHandle.set(stageData); + inDataCachedHandle.setClean(); + return MS::kSuccess; + } +} + +MStatus +MayaUsdProxyShapeBase::computeOutStageData(MDataBlock& dataBlock) +{ + MStatus retValue = MS::kSuccess; + + TfReset(_boundingBoxCache); + + // Reset the stage listener until we determine that everything is valid. + _stageNoticeListener.SetStage(UsdStageWeakPtr()); + _stageNoticeListener.SetStageContentsChangedCallback(nullptr); + + MDataHandle inDataCachedHandle = + dataBlock.inputValue(inStageDataCachedAttr, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + UsdStageRefPtr usdStage; + + MayaUsdStageData* inData = + dynamic_cast(inDataCachedHandle.asPluginData()); + if(inData) + { + usdStage = inData->stage; + } + + // If failed to get a valid stage, then + // Propagate inDataCached -> outData + // and return + if (!usdStage) { + MDataHandle outDataHandle = dataBlock.outputValue(outStageDataAttr, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + outDataHandle.copy(inDataCachedHandle); + return MS::kSuccess; + } + + // Get the primPath + const MString primPath = dataBlock.inputValue(primPathAttr, &retValue).asString(); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // Get the prim + // If no primPath string specified, then use the pseudo-root. + UsdPrim usdPrim; + std::string primPathStr = primPath.asChar(); + if ( !primPathStr.empty() ) { + SdfPath primPath(primPathStr); + + // Validate assumption: primPath is descendent of passed-in stage primPath + // Make sure that the primPath is a child of the passed in stage's primpath + if ( primPath.HasPrefix(inData->primPath) ) { + usdPrim = usdStage->GetPrimAtPath( primPath ); + } + else { + TF_WARN("%s: Shape primPath <%s> is not a descendant of input " + "stage primPath <%s>", + MPxSurfaceShape::name().asChar(), + primPath.GetText(), + inData->primPath.GetText()); + } + } else { + usdPrim = usdStage->GetPseudoRoot(); + } + + // Create the output outData + MFnPluginData pluginDataFn; + MObject stageDataObj = + pluginDataFn.create(MayaUsdStageData::mayaTypeId, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + MayaUsdStageData* stageData = + reinterpret_cast(pluginDataFn.data(&retValue)); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + // Set the outUsdStageData + stageData->stage = usdStage; + stageData->primPath = usdPrim ? usdPrim.GetPath() : + usdStage->GetPseudoRoot().GetPath(); + + // + // set the data on the output plug + // + MDataHandle outDataHandle = + dataBlock.outputValue(outStageDataAttr, &retValue); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + outDataHandle.set(stageData); + outDataHandle.setClean(); + + // Start listening for notices for the USD stage. + _stageNoticeListener.SetStage(usdStage); + _stageNoticeListener.SetStageContentsChangedCallback( + std::bind(&MayaUsdProxyShapeBase::_OnStageContentsChanged, + this, + std::placeholders::_1)); + + UsdMayaProxyStageSetNotice(*this).Send(); + + return MS::kSuccess; +} + +/* virtual */ +bool +MayaUsdProxyShapeBase::isBounded() const +{ + return isStageValid(); +} + +/* virtual */ +void +MayaUsdProxyShapeBase::CacheEmptyBoundingBox(MBoundingBox&) +{} + +/* virtual */ +UsdTimeCode +MayaUsdProxyShapeBase::GetOutputTime(MDataBlock dataBlock) const +{ + return _GetTime(dataBlock); +} + +/* virtual */ +MBoundingBox +MayaUsdProxyShapeBase::boundingBox() const +{ + MStatus status; + + // Make sure outStage is up to date + MayaUsdProxyShapeBase* nonConstThis = const_cast(this); + MDataBlock dataBlock = nonConstThis->forceCache(); + dataBlock.inputValue(outStageDataAttr, &status); + CHECK_MSTATUS_AND_RETURN(status, MBoundingBox()); + + // XXX: + // If we could cheaply determine whether a stage only has static geometry, + // we could make this value a constant one for that case, avoiding the + // memory overhead of a cache entry per frame + UsdTimeCode currTime = GetOutputTime(dataBlock); + + std::map::const_iterator cacheLookup = + _boundingBoxCache.find(currTime); + + if (cacheLookup != _boundingBoxCache.end()) { + return cacheLookup->second; + } + + UsdPrim prim = _GetUsdPrim(dataBlock); + if (!prim) { + return MBoundingBox(); + } + + const UsdGeomImageable imageablePrim(prim); + + bool drawRenderPurpose = false; + bool drawProxyPurpose = true; + bool drawGuidePurpose = false; + _GetDrawPurposeToggles( + dataBlock, + &drawRenderPurpose, + &drawProxyPurpose, + &drawGuidePurpose); + + const TfToken purpose1 = UsdGeomTokens->default_; + const TfToken purpose2 = + drawRenderPurpose ? UsdGeomTokens->render : TfToken(); + const TfToken purpose3 = + drawProxyPurpose ? UsdGeomTokens->proxy : TfToken(); + const TfToken purpose4 = + drawGuidePurpose ? UsdGeomTokens->guide : TfToken(); + + const GfBBox3d allBox = imageablePrim.ComputeUntransformedBound( + currTime, + purpose1, + purpose2, + purpose3, + purpose4); + + MBoundingBox &retval = nonConstThis->_boundingBoxCache[currTime]; + + const GfRange3d boxRange = allBox.ComputeAlignedBox(); + + // Convert to GfRange3d to MBoundingBox + if ( !boxRange.IsEmpty() ) { + const GfVec3d boxMin = boxRange.GetMin(); + const GfVec3d boxMax = boxRange.GetMax(); + retval = MBoundingBox( + MPoint(boxMin[0], boxMin[1], boxMin[2]), + MPoint(boxMax[0], boxMax[1], boxMax[2])); + } + else { + nonConstThis->CacheEmptyBoundingBox(retval); + } + + return retval; +} + +void +MayaUsdProxyShapeBase::clearBoundingBoxCache() +{ + _boundingBoxCache.clear(); +} + +bool +MayaUsdProxyShapeBase::isStageValid() const +{ + MStatus localStatus; + MayaUsdProxyShapeBase* nonConstThis = const_cast(this); + MDataBlock dataBlock = nonConstThis->forceCache(); + + MDataHandle outDataHandle = dataBlock.inputValue(outStageDataAttr, &localStatus); + CHECK_MSTATUS_AND_RETURN(localStatus, false); + + MayaUsdStageData* outData = + dynamic_cast(outDataHandle.asPluginData()); + if(!outData || !outData->stage) { + return false; + } + + return true; +} + +/* virtual */ +MStatus +MayaUsdProxyShapeBase::setDependentsDirty(const MPlug& plug, MPlugArray& plugArray) +{ + // If/when the MPxDrawOverride for the proxy shape specifies + // isAlwaysDirty=false to improve performance, we must be sure to notify + // the Maya renderer that the geometry is dirty and needs to be redrawn + // when any plug on the proxy shape is dirtied. + MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); + return MPxSurfaceShape::setDependentsDirty(plug, plugArray); +} + +/* virtual */ +bool +MayaUsdProxyShapeBase::setInternalValue(const MPlug& plug, const MDataHandle& dataHandle) +{ + if (plug == excludePrimPathsAttr) { + _IncreaseExcludePrimPathsVersion(); + } + return MPxSurfaceShape::setInternalValue(plug, dataHandle); +} + +UsdPrim +MayaUsdProxyShapeBase::_GetUsdPrim(MDataBlock dataBlock) const +{ + MStatus localStatus; + UsdPrim usdPrim; + + MDataHandle outDataHandle = + dataBlock.inputValue(outStageDataAttr, &localStatus); + CHECK_MSTATUS_AND_RETURN(localStatus, usdPrim); + + MayaUsdStageData* outData = dynamic_cast(outDataHandle.asPluginData()); + if(!outData) { + return usdPrim; // empty UsdPrim + } + + if(!outData->stage) { + return usdPrim; // empty UsdPrim + } + + usdPrim = (outData->primPath.IsEmpty()) ? + outData->stage->GetPseudoRoot() : + outData->stage->GetPrimAtPath(outData->primPath); + + return usdPrim; +} + +int +MayaUsdProxyShapeBase::getComplexity() const +{ + return _GetComplexity( const_cast(this)->forceCache() ); +} + +int +MayaUsdProxyShapeBase::_GetComplexity(MDataBlock dataBlock) const +{ + int complexity = 0; + MStatus status; + + complexity = dataBlock.inputValue(complexityAttr, &status).asInt(); + + return complexity; +} + +UsdTimeCode +MayaUsdProxyShapeBase::getTime() const +{ + return _GetTime( const_cast(this)->forceCache() ); +} + +UsdTimeCode +MayaUsdProxyShapeBase::_GetTime(MDataBlock dataBlock) const +{ + MStatus status; + + return UsdTimeCode(dataBlock.inputValue(timeAttr, &status).asTime().value()); +} + +UsdStageRefPtr +MayaUsdProxyShapeBase::getUsdStage() const +{ + MStatus localStatus; + MayaUsdProxyShapeBase* nonConstThis = const_cast(this); + MDataBlock dataBlock = nonConstThis->forceCache(); + + MDataHandle outDataHandle = dataBlock.inputValue(outStageDataAttr, &localStatus); + CHECK_MSTATUS_AND_RETURN(localStatus, UsdStageRefPtr()); + + MayaUsdStageData* outData = + dynamic_cast(outDataHandle.asPluginData()); + + if (outData && outData->stage) + return outData->stage; + else + return {}; + +} + +SdfPathVector +MayaUsdProxyShapeBase::getExcludePrimPaths() const +{ + return _GetExcludePrimPaths( const_cast(this)->forceCache() ); +} + +size_t +MayaUsdProxyShapeBase::getExcludePrimPathsVersion() const { + return _excludePrimPathsVersion; +} + +SdfPathVector +MayaUsdProxyShapeBase::_GetExcludePrimPaths(MDataBlock dataBlock) const +{ + SdfPathVector ret; + + const MString excludePrimPathsStr = + dataBlock.inputValue(excludePrimPathsAttr).asString(); + std::vector excludePrimPaths = + TfStringTokenize(excludePrimPathsStr.asChar(), ","); + ret.resize(excludePrimPaths.size()); + for (size_t i = 0; i < excludePrimPaths.size(); ++i) { + ret[i] = SdfPath(TfStringTrim(excludePrimPaths[i])); + } + + return ret; +} + +bool +MayaUsdProxyShapeBase::_GetDrawPurposeToggles( + MDataBlock dataBlock, + bool* drawRenderPurpose, + bool* drawProxyPurpose, + bool* drawGuidePurpose) const +{ + MStatus status; + + MDataHandle drawRenderPurposeHandle = + dataBlock.inputValue(drawRenderPurposeAttr, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + MDataHandle drawProxyPurposeHandle = + dataBlock.inputValue(drawProxyPurposeAttr, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + MDataHandle drawGuidePurposeHandle = + dataBlock.inputValue(drawGuidePurposeAttr, &status); + CHECK_MSTATUS_AND_RETURN(status, false); + + if (drawRenderPurpose) { + *drawRenderPurpose = drawRenderPurposeHandle.asBool(); + } + if (drawProxyPurpose) { + *drawProxyPurpose = drawProxyPurposeHandle.asBool(); + } + if (drawGuidePurpose) { + *drawGuidePurpose = drawGuidePurposeHandle.asBool(); + } + + return true; +} + +bool +MayaUsdProxyShapeBase::GetAllRenderAttributes( + UsdPrim* usdPrimOut, + SdfPathVector* excludePrimPathsOut, + int* complexityOut, + UsdTimeCode* timeOut, + bool* drawRenderPurpose, + bool* drawProxyPurpose, + bool* drawGuidePurpose) +{ + MDataBlock dataBlock = forceCache(); + + *usdPrimOut = _GetUsdPrim(dataBlock); + if (!usdPrimOut->IsValid()) { + return false; + } + + *excludePrimPathsOut = _GetExcludePrimPaths(dataBlock); + *complexityOut = _GetComplexity(dataBlock); + *timeOut = _GetTime(dataBlock); + + _GetDrawPurposeToggles( + dataBlock, + drawRenderPurpose, + drawProxyPurpose, + drawGuidePurpose); + + return true; +} + +/* virtual */ +UsdPrim +MayaUsdProxyShapeBase::usdPrim() const +{ + return _GetUsdPrim( const_cast(this)->forceCache() ); +} + +MDagPath +MayaUsdProxyShapeBase::parentTransform() +{ + MFnDagNode fn(thisMObject()); + MDagPath proxyTransformPath; + fn.getPath(proxyTransformPath); + proxyTransformPath.pop(); + return proxyTransformPath; +} + +MayaUsdProxyShapeBase::MayaUsdProxyShapeBase() : + MPxSurfaceShape() +{ + TfRegistryManager::GetInstance().SubscribeTo(); +} + +/* virtual */ +MayaUsdProxyShapeBase::~MayaUsdProxyShapeBase() +{ + // + // empty + // +} + +MSelectionMask +MayaUsdProxyShapeBase::getShapeSelectionMask() const +{ + // The intent of this function is to control whether this object is + // selectable at all in VP2 + + // However, due to a bug / quirk, it could be used to specifically control + // whether the object was SOFT-selectable if you were using + // MAYA_VP2_USE_VP1_SELECTON; in this mode, this setting is NOT querierd + // when doing "normal" selection, but IS queried when doing soft + // selection. + + // Unfortunately, it is queried for both "normal" selection AND soft + // selection if you are using "true" VP2 selection. So in order to + // control soft selection, in both modes, we keep track of whether + // we currently have object soft-select enabled, and then return an empty + // selection mask if it is, but this object is set to be non-soft-selectable + + static const MSelectionMask emptyMask; + static const MSelectionMask normalMask(MSelectionMask::kSelectMeshes); + + if (GetObjectSoftSelectEnabled() && !canBeSoftSelected()) { + // Disable selection, to disable soft-selection + return emptyMask; + } + return normalMask; +} + +bool +MayaUsdProxyShapeBase::canBeSoftSelected() const +{ + return false; +} + +void +MayaUsdProxyShapeBase::_OnStageContentsChanged( + const UsdNotice::StageContentsChanged& notice) +{ + // If the USD stage this proxy represents changes without Maya's knowledge, + // we need to inform Maya that the shape is dirty and needs to be redrawn. + MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); +} + +bool +MayaUsdProxyShapeBase::closestPoint( + const MPoint& raySource, + const MVector& rayDirection, + MPoint& theClosestPoint, + MVector& theClosestNormal, + bool /*findClosestOnMiss*/, + double /*tolerance*/) +{ + if (_sharedClosestPointDelegate) { + GfRay ray( + GfVec3d(raySource.x, raySource.y, raySource.z), + GfVec3d(rayDirection.x, rayDirection.y, rayDirection.z)); + GfVec3d hitPoint; + GfVec3d hitNorm; + if (_sharedClosestPointDelegate(*this, ray, &hitPoint, &hitNorm)) { + theClosestPoint = MPoint(hitPoint[0], hitPoint[1], hitPoint[2]); + theClosestNormal = MVector(hitNorm[0], hitNorm[1], hitNorm[2]); + return true; + } + } + + return false; +} + +bool MayaUsdProxyShapeBase::canMakeLive() const { + return (bool) _sharedClosestPointDelegate; +} + +#if defined(WANT_UFE_BUILD) +Ufe::Path MayaUsdProxyShapeBase::ufePath() const +{ + // Build a path segment to proxyShape + MDagPath thisPath; + MDagPath::getAPathTo(thisMObject(), thisPath); + + // MDagPath does not include |world to its full path name + MString fullpath = "|world" + thisPath.fullPathName(); + + return Ufe::Path(Ufe::PathSegment(fullpath.asChar(), MAYA_UFE_RUNTIME_ID, MAYA_UFE_SEPARATOR)); +} +#endif + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/nodes/proxyShapeBase.h b/lib/nodes/proxyShapeBase.h new file mode 100644 index 0000000000..5013af5418 --- /dev/null +++ b/lib/nodes/proxyShapeBase.h @@ -0,0 +1,294 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#ifndef PXRUSDMAYA_PROXY_SHAPE_BASE_H +#define PXRUSDMAYA_PROXY_SHAPE_BASE_H + +/// \file usdMaya/proxyShapeBase.h + +#include "../base/api.h" +#include "../listeners/stageNoticeListener.h" +#include "usdPrimProvider.h" + +#include "pxr/pxr.h" + +#include "pxr/base/gf/ray.h" +#include "pxr/base/gf/vec3d.h" +#include "pxr/base/tf/staticTokens.h" + +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/notice.h" +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/timeCode.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(WANT_UFE_BUILD) +#include + +UFE_NS_DEF { + class Path; +} + +constexpr int MAYA_UFE_RUNTIME_ID = 1; +constexpr char MAYA_UFE_SEPARATOR = '|'; +constexpr int USD_UFE_RUNTIME_ID = 2; +constexpr char USD_UFE_SEPARATOR = '/'; +#endif + + +PXR_NAMESPACE_OPEN_SCOPE + + +#define MAYAUSD_PROXY_SHAPE_BASE_TOKENS \ + ((MayaTypeName, "mayaUsdProxyShapeBase")) + +TF_DECLARE_PUBLIC_TOKENS(MayaUsdProxyShapeBaseTokens, + MAYAUSD_CORE_PUBLIC, + MAYAUSD_PROXY_SHAPE_BASE_TOKENS); + + +class MayaUsdProxyShapeBase : public MPxSurfaceShape, + public UsdMayaUsdPrimProvider +{ + public: + typedef MayaUsdProxyShapeBase ThisClass; + + MAYAUSD_CORE_PUBLIC + static const MTypeId typeId; + MAYAUSD_CORE_PUBLIC + static const MString typeName; + + MAYAUSD_CORE_PUBLIC + static const MString displayFilterName; + MAYAUSD_CORE_PUBLIC + static const MString displayFilterLabel; + + // Attributes + MAYAUSD_CORE_PUBLIC + static MObject filePathAttr; + MAYAUSD_CORE_PUBLIC + static MObject primPathAttr; + MAYAUSD_CORE_PUBLIC + static MObject excludePrimPathsAttr; + MAYAUSD_CORE_PUBLIC + static MObject timeAttr; + MAYAUSD_CORE_PUBLIC + static MObject complexityAttr; + MAYAUSD_CORE_PUBLIC + static MObject inStageDataAttr; + MAYAUSD_CORE_PUBLIC + static MObject inStageDataCachedAttr; + MAYAUSD_CORE_PUBLIC + static MObject outStageDataAttr; + MAYAUSD_CORE_PUBLIC + static MObject drawRenderPurposeAttr; + MAYAUSD_CORE_PUBLIC + static MObject drawProxyPurposeAttr; + MAYAUSD_CORE_PUBLIC + static MObject drawGuidePurposeAttr; + + /// Delegate function for computing the closest point and surface normal + /// on the proxy shape to a given ray. + /// The input ray, output point, and output normal should be in the + /// proxy shape's local space. + /// Should return true if a point was found, and false otherwise. + /// (You could just treat this as a ray intersection and return true + /// if intersected, false if missed.) + typedef std::function ClosestPointDelegate; + + MAYAUSD_CORE_PUBLIC + static void* creator(); + + MAYAUSD_CORE_PUBLIC + static MStatus initialize(); + + MAYAUSD_CORE_PUBLIC + static MayaUsdProxyShapeBase* GetShapeAtDagPath(const MDagPath& dagPath); + + MAYAUSD_CORE_PUBLIC + static void SetClosestPointDelegate(ClosestPointDelegate delegate); + + // UsdMayaUsdPrimProvider overrides: + /** + * accessor to get the usdprim + * + * This method pulls the usdstage data from outData, and will evaluate + * the dependencies necessary to do so. It should be called instead of + * pulling on the data directly. + */ + MAYAUSD_CORE_PUBLIC + UsdPrim usdPrim() const override; + + // Virtual function overrides + + MAYAUSD_CORE_PUBLIC + void postConstructor() override; + MAYAUSD_CORE_PUBLIC + MStatus compute( + const MPlug& plug, + MDataBlock& dataBlock) override; + MAYAUSD_CORE_PUBLIC + bool isBounded() const override; + MAYAUSD_CORE_PUBLIC + MBoundingBox boundingBox() const override; + MAYAUSD_CORE_PUBLIC + MSelectionMask getShapeSelectionMask() const override; + + MAYAUSD_CORE_PUBLIC + bool closestPoint( + const MPoint& raySource, + const MVector& rayDirection, + MPoint& theClosestPoint, + MVector& theClosestNormal, + bool findClosestOnMiss, + double tolerance) override; + + MAYAUSD_CORE_PUBLIC + bool canMakeLive() const override; + + // Public functions + MAYAUSD_CORE_PUBLIC + virtual SdfPathVector getExcludePrimPaths() const; + MAYAUSD_CORE_PUBLIC + size_t getExcludePrimPathsVersion() const; + + MAYAUSD_CORE_PUBLIC + int getComplexity() const; + MAYAUSD_CORE_PUBLIC + virtual UsdTimeCode getTime() const; + MAYAUSD_CORE_PUBLIC + virtual UsdStageRefPtr getUsdStage() const; + + MAYAUSD_CORE_PUBLIC + bool GetAllRenderAttributes( + UsdPrim* usdPrimOut, + SdfPathVector* excludePrimPathsOut, + int* complexityOut, + UsdTimeCode* timeOut, + bool* drawRenderPurpose, + bool* drawProxyPurpose, + bool* drawGuidePurpose); + + MAYAUSD_CORE_PUBLIC + MStatus setDependentsDirty( + const MPlug& plug, + MPlugArray& plugArray) override; + + /// \brief Clears the bounding box cache of the shape + MAYAUSD_CORE_PUBLIC + void clearBoundingBoxCache(); + + // returns the shape's parent transform + MAYAUSD_CORE_PUBLIC + MDagPath parentTransform(); + + // Is this required if there is parentTransform? +#if defined(WANT_UFE_BUILD) + MAYAUSD_CORE_PUBLIC + Ufe::Path ufePath() const; +#endif + + protected: + MAYAUSD_CORE_PUBLIC + MayaUsdProxyShapeBase(); + + MAYAUSD_CORE_PUBLIC + ~MayaUsdProxyShapeBase() override; + + MAYAUSD_CORE_PUBLIC + bool isStageValid() const; + + // Hook method for derived classes. This class returns a nullptr. + MAYAUSD_CORE_PUBLIC + virtual SdfLayerRefPtr computeSessionLayer(MDataBlock&); + + // Hook method for derived classes: can this object be soft selected? + // This class returns false. + MAYAUSD_CORE_PUBLIC + virtual bool canBeSoftSelected() const; + + // Hook method for derived classes: is soft select enabled? This + // class returns false. + MAYAUSD_CORE_PUBLIC + virtual bool GetObjectSoftSelectEnabled() const; + + MAYAUSD_CORE_PUBLIC + UsdPrim _GetUsdPrim(MDataBlock dataBlock) const; + + // Hook method for derived classes: cache an empty computed bounding + // box. This class does nothing. + MAYAUSD_CORE_PUBLIC + virtual void CacheEmptyBoundingBox(MBoundingBox&); + + // Return the output time. This class returns the value of the + // input time attribute. + MAYAUSD_CORE_PUBLIC + virtual UsdTimeCode GetOutputTime(MDataBlock) const; + + MAYAUSD_CORE_PUBLIC + void _IncreaseExcludePrimPathsVersion() { _excludePrimPathsVersion++; } + + MAYAUSD_CORE_PUBLIC + bool setInternalValue(const MPlug& plug, const MDataHandle& dataHandle) override; + + private: + MayaUsdProxyShapeBase(const MayaUsdProxyShapeBase&); + MayaUsdProxyShapeBase& operator=(const MayaUsdProxyShapeBase&); + + MStatus computeInStageDataCached(MDataBlock& dataBlock); + MStatus computeOutStageData(MDataBlock& dataBlock); + + SdfPathVector _GetExcludePrimPaths(MDataBlock dataBlock) const; + int _GetComplexity(MDataBlock dataBlock) const; + UsdTimeCode _GetTime(MDataBlock dataBlock) const; + + bool _GetDrawPurposeToggles( + MDataBlock dataBlock, + bool* drawRenderPurpose, + bool* drawProxyPurpose, + bool* drawGuidePurpose) const; + + void _OnStageContentsChanged( + const UsdNotice::StageContentsChanged& notice); + + UsdMayaStageNoticeListener _stageNoticeListener; + + std::map _boundingBoxCache; + size_t _excludePrimPathsVersion{ 1 }; + + static ClosestPointDelegate _sharedClosestPointDelegate; +}; + + +PXR_NAMESPACE_CLOSE_SCOPE + + +#endif diff --git a/lib/nodes/proxyShapePlugin.cpp b/lib/nodes/proxyShapePlugin.cpp new file mode 100644 index 0000000000..c3ef612f1b --- /dev/null +++ b/lib/nodes/proxyShapePlugin.cpp @@ -0,0 +1,138 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#include "proxyShapePlugin.h" + +#include "../render/vp2RenderDelegate/proxyRenderDelegate.h" +#include "../render/vp2ShaderFragments/shaderFragments.h" + +#include "stageData.h" +#include "proxyShapeBase.h" + +#include "pxr/base/tf/envSetting.h" + +#include +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace { +const MString _RegistrantId("mayaUsd"); +int _registrationCount = 0; + +// Name of the plugin registering the proxy shape base class. +MString _registrantPluginName; + +bool _useVP2RenderDelegate = false; + +TF_DEFINE_ENV_SETTING(VP2_RENDER_DELEGATE_PROXY, false, + "Switch proxy shape rendering to VP2 render delegate."); +} + +PXR_NAMESPACE_OPEN_SCOPE + +/* static */ +MStatus +MayaUsdProxyShapePlugin::initialize(MFnPlugin& plugin) +{ + // If we're already registered, do nothing. + if (_registrationCount++ > 0) { + return MS::kSuccess; + } + + _registrantPluginName = plugin.name(); + + _useVP2RenderDelegate = TfGetEnvSetting(VP2_RENDER_DELEGATE_PROXY); + + MStatus status; + + // Proxy shape initialization. + status = plugin.registerData( + MayaUsdStageData::typeName, + MayaUsdStageData::mayaTypeId, + MayaUsdStageData::creator); + CHECK_MSTATUS(status); + + status = plugin.registerShape( + MayaUsdProxyShapeBase::typeName, + MayaUsdProxyShapeBase::typeId, + MayaUsdProxyShapeBase::creator, + MayaUsdProxyShapeBase::initialize, + nullptr, + getProxyShapeClassification()); + CHECK_MSTATUS(status); + + status = MHWRender::MDrawRegistry::registerSubSceneOverrideCreator( + ProxyRenderDelegate::drawDbClassification, + _RegistrantId, + ProxyRenderDelegate::Creator); + CHECK_MSTATUS(status); + + status = HdVP2ShaderFragments::registerFragments(); + CHECK_MSTATUS(status); + + return status; +} + +/* static */ +MStatus +MayaUsdProxyShapePlugin::finalize(MFnPlugin& plugin) +{ + // If more than one plugin still has us registered, do nothing. + if (_registrationCount-- > 1) { + return MS::kSuccess; + } + + // Maya requires deregistration to be done by the same plugin that + // performed the registration. If this isn't possible, warn and don't + // deregister. + if (plugin.name() != _registrantPluginName) { + MGlobal::displayWarning( + "USD proxy shape base cannot be deregistered, registering plugin " + + _registrantPluginName + " is unloaded."); + return MS::kSuccess; + } + + MStatus status = HdVP2ShaderFragments::deregisterFragments(); + CHECK_MSTATUS(status); + + status = MHWRender::MDrawRegistry::deregisterSubSceneOverrideCreator( + ProxyRenderDelegate::drawDbClassification, + _RegistrantId); + CHECK_MSTATUS(status); + + status = plugin.deregisterNode(MayaUsdProxyShapeBase::typeId); + CHECK_MSTATUS(status); + + status = plugin.deregisterData(MayaUsdStageData::mayaTypeId); + CHECK_MSTATUS(status); + + return status; +} + +const MString* MayaUsdProxyShapePlugin::getProxyShapeClassification() +{ + return _useVP2RenderDelegate ? &ProxyRenderDelegate::drawDbClassification : + nullptr; +} + +bool MayaUsdProxyShapePlugin::useVP2_NativeUSD_Rendering() +{ + return _useVP2RenderDelegate; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/nodes/proxyShapePlugin.h b/lib/nodes/proxyShapePlugin.h new file mode 100644 index 0000000000..42e7f2cc5c --- /dev/null +++ b/lib/nodes/proxyShapePlugin.h @@ -0,0 +1,58 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#ifndef PXRUSDMAYA_PROXY_SHAPE_PLUGIN_H +#define PXRUSDMAYA_PROXY_SHAPE_PLUGIN_H + +/// \file usdMaya/proxyShapePlugin.h + +#include "../base/api.h" + +#include "pxr/pxr.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class MayaUsdProxyShapePlugin +/// \brief Encapsulates plugin registration and deregistration of proxy shape classes. +/// +/// Proxy shape support requires plugin registration of node classes, node +/// data, and draw support. This class provides this service, including if +/// multiple plugins that use proxy shapes are loaded: using reference +/// counting, only the first registration and the last deregistration will +/// be performed. Note that because of Maya architecture requirements, +/// deregistration will only be done if the deregistering plugin is the same as +/// the registering plugin. Otherwise, a warning is shown. + +class MayaUsdProxyShapePlugin +{ + public: + MAYAUSD_CORE_PUBLIC + static MStatus initialize(MFnPlugin&); + + MAYAUSD_CORE_PUBLIC + static MStatus finalize(MFnPlugin&); + + MAYAUSD_CORE_PUBLIC + static const MString* getProxyShapeClassification(); + + MAYAUSD_CORE_PUBLIC + static bool useVP2_NativeUSD_Rendering(); +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/plugin/pxr/maya/lib/usdMaya/stageData.cpp b/lib/nodes/stageData.cpp similarity index 66% rename from plugin/pxr/maya/lib/usdMaya/stageData.cpp rename to lib/nodes/stageData.cpp index 782c48cf74..caf689113d 100644 --- a/plugin/pxr/maya/lib/usdMaya/stageData.cpp +++ b/lib/nodes/stageData.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/stageData.h" +#include "stageData.h" #include "pxr/base/gf/bbox3d.h" #include "pxr/base/tf/staticTokens.h" @@ -30,43 +30,44 @@ PXR_NAMESPACE_OPEN_SCOPE -TF_DEFINE_PUBLIC_TOKENS(UsdMayaStageDataTokens, - PXRUSDMAYA_STAGE_DATA_TOKENS); +TF_DEFINE_PUBLIC_TOKENS(MayaUsdStageDataTokens, + PXRMAYAUSD_STAGE_DATA_TOKENS); -const MTypeId UsdMayaStageData::mayaTypeId(0x0010A257); -const MString UsdMayaStageData::typeName( - UsdMayaStageDataTokens->MayaTypeName.GetText()); +const MTypeId MayaUsdStageData::mayaTypeId(0x0010A257); +const MString MayaUsdStageData::typeName( + MayaUsdStageDataTokens->MayaTypeName.GetText()); /* This exists solely to make sure that the usdStage instance - * gets discarded when Maya exits, so that an temporary files + * gets discarded when Maya exits, so that any temporary files * that might have been created are unlinked. */ -static +namespace { void _cleanUp(void *gdPtr) { - UsdMayaStageData *gd = (UsdMayaStageData *)gdPtr; + MayaUsdStageData *gd = (MayaUsdStageData *)gdPtr; gd->unregisterExitCallback(); gd->stage = UsdStageRefPtr(); } +} /* static */ void* -UsdMayaStageData::creator() +MayaUsdStageData::creator() { - return new UsdMayaStageData(); + return new MayaUsdStageData(); } /* virtual */ void -UsdMayaStageData::copy(const MPxData& src) +MayaUsdStageData::copy(const MPxData& src) { - const UsdMayaStageData* stageData = - dynamic_cast(&src); + const MayaUsdStageData* stageData = + dynamic_cast(&src); if (stageData) { stage = stageData->stage; @@ -76,25 +77,25 @@ UsdMayaStageData::copy(const MPxData& src) /* virtual */ MTypeId -UsdMayaStageData::typeId() const +MayaUsdStageData::typeId() const { return mayaTypeId; } /* virtual */ MString -UsdMayaStageData::name() const +MayaUsdStageData::name() const { return typeName; } -UsdMayaStageData::UsdMayaStageData() : MPxGeometryData() +MayaUsdStageData::MayaUsdStageData() : MPxGeometryData() { registerExitCallback(); } void -UsdMayaStageData::registerExitCallback() +MayaUsdStageData::registerExitCallback() { _exitCallbackId = MSceneMessage::addCallback(MSceneMessage::kMayaExiting, _cleanUp, @@ -102,13 +103,13 @@ UsdMayaStageData::registerExitCallback() } void -UsdMayaStageData::unregisterExitCallback() +MayaUsdStageData::unregisterExitCallback() { MSceneMessage::removeCallback(_exitCallbackId); } /* virtual */ -UsdMayaStageData::~UsdMayaStageData() { +MayaUsdStageData::~MayaUsdStageData() { unregisterExitCallback(); } diff --git a/lib/nodes/stageData.h b/lib/nodes/stageData.h new file mode 100644 index 0000000000..6891021fd2 --- /dev/null +++ b/lib/nodes/stageData.h @@ -0,0 +1,138 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#ifndef PXRUSDMAYA_STAGE_DATA_H +#define PXRUSDMAYA_STAGE_DATA_H + +/// \file usdMaya/stageData.h + +#include "../base/api.h" + +#include "pxr/pxr.h" + +#include "pxr/base/tf/staticTokens.h" + +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/stage.h" + +#include +#include +#include +#include +#include + + +PXR_NAMESPACE_OPEN_SCOPE + + +#define PXRMAYAUSD_STAGE_DATA_TOKENS \ + ((MayaTypeName, "pxrUsdStageData")) + +TF_DECLARE_PUBLIC_TOKENS(MayaUsdStageDataTokens, + MAYAUSD_CORE_PUBLIC, + PXRMAYAUSD_STAGE_DATA_TOKENS); + + +class MayaUsdStageData : public MPxGeometryData +{ + public: + /// Unlike other Maya node types, MPxData/MPxGeometryData declare + /// typeId() as a pure virtual method that must be overridden in + /// derived classes, so we have to call this static member "mayaTypeId" + /// instead of just "typeId" as we usually would. + MAYAUSD_CORE_PUBLIC + static const MTypeId mayaTypeId; + MAYAUSD_CORE_PUBLIC + static const MString typeName; + + MAYAUSD_CORE_PUBLIC + static void* creator(); + + /** + * \name MPxGeometryData overrides + */ + //@{ + + MAYAUSD_CORE_PUBLIC + void copy(const MPxData& src) override; + + MAYAUSD_CORE_PUBLIC + MTypeId typeId() const override; + + MAYAUSD_CORE_PUBLIC + MString name() const override; + //@} + + void unregisterExitCallback(); + + /** + * \name data + */ + //@{ + + // The original Pixar code was the following: + // + // UsdStageRefPtr stage; + // + // Now using a weak pointer instead of a referencing pointer. The AL + // plugin originally used a referencing pointer, but ran into problems. + // From a Rob Bateman @ AL e-mail, 7-Apr-2019: + // + // "The reason for the weak pointer was that we found that Maya seemed + // to have a memory leak (as in, the MPxData derived objects were being + // created, but never deleted when we expected them to be - possibly by + // design?). We had originally used a direct mirror of the Pixar data + // object, but because the data objects were never freed (even after + // file new), the original stage would be retained. This meant the + // internal SdfLayerCache in USD would keep hold of the previously + // loaded layers. So we found we had this problem: + // + // 1. Import some.usda file into a proxy shape. + // 2. Make some modifications + // 3. File New + // 4. Import the same "some.usda" file into a proxy shape. + // + // At this point, USD would essentially hand you back the stage + // composed of the modified layers, rather than a clean stage composed + // from the files on disk. Switching the type from a shared_ptr to a + // weak_ptr worked around this issue. Basically if we use a shared + // pointer here, the only way to reload a scene, would be to restart + // Maya." + + UsdStageWeakPtr stage; + SdfPath primPath; + + //@} + + protected: + MAYAUSD_CORE_PUBLIC + MayaUsdStageData(); + MAYAUSD_CORE_PUBLIC + ~MayaUsdStageData() override; + + private: + MayaUsdStageData(const MayaUsdStageData&); + MayaUsdStageData& operator=(const MayaUsdStageData&); + + void registerExitCallback(); + + MCallbackId _exitCallbackId; +}; + + +PXR_NAMESPACE_CLOSE_SCOPE + + +#endif diff --git a/plugin/pxr/maya/lib/usdMaya/usdPrimProvider.cpp b/lib/nodes/usdPrimProvider.cpp similarity index 95% rename from plugin/pxr/maya/lib/usdMaya/usdPrimProvider.cpp rename to lib/nodes/usdPrimProvider.cpp index 1ec79b3a36..479b6b4f58 100644 --- a/plugin/pxr/maya/lib/usdMaya/usdPrimProvider.cpp +++ b/lib/nodes/usdPrimProvider.cpp @@ -14,7 +14,7 @@ // limitations under the License. // #include "pxr/pxr.h" -#include "usdMaya/usdPrimProvider.h" +#include "usdPrimProvider.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/plugin/pxr/maya/lib/usdMaya/usdPrimProvider.h b/lib/nodes/usdPrimProvider.h similarity index 95% rename from plugin/pxr/maya/lib/usdMaya/usdPrimProvider.h rename to lib/nodes/usdPrimProvider.h index f8efe46386..2dab51d245 100644 --- a/plugin/pxr/maya/lib/usdMaya/usdPrimProvider.h +++ b/lib/nodes/usdPrimProvider.h @@ -17,7 +17,7 @@ #define PXRUSDMAYA_USD_PRIM_PROVIDER_H #include "pxr/pxr.h" -#include "usdMaya/api.h" +#include "../base/api.h" #include "pxr/usd/usd/prim.h" PXR_NAMESPACE_OPEN_SCOPE @@ -30,7 +30,7 @@ class UsdMayaUsdPrimProvider // returns the prim that this node is holding virtual UsdPrim usdPrim() const = 0; - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC virtual ~UsdMayaUsdPrimProvider(); }; diff --git a/lib/render/vp2RenderDelegate/debugCodes.cpp b/lib/render/vp2RenderDelegate/debugCodes.cpp new file mode 100644 index 0000000000..f0b5ca52db --- /dev/null +++ b/lib/render/vp2RenderDelegate/debugCodes.cpp @@ -0,0 +1,29 @@ +// +// Copyright 2019 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. +// + +#include "debugCodes.h" + +#include "pxr/base/tf/registryManager.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_REGISTRY_FUNCTION(TfDebug) +{ + TF_DEBUG_ENVIRONMENT_SYMBOL(HDVP2_DEBUG_MATERIAL, "Debug material"); + TF_DEBUG_ENVIRONMENT_SYMBOL(HDVP2_DEBUG_MESH, "Debug mesh"); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/debugCodes.h b/lib/render/vp2RenderDelegate/debugCodes.h new file mode 100644 index 0000000000..77aa94e580 --- /dev/null +++ b/lib/render/vp2RenderDelegate/debugCodes.h @@ -0,0 +1,32 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_DEBUGCODES_H +#define HD_VP2_DEBUGCODES_H + +#include "pxr/pxr.h" +#include "pxr/base/tf/debug.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEBUG_CODES( + HDVP2_DEBUG_MATERIAL, + HDVP2_DEBUG_MESH +); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // HD_VP2_DEBUGCODES_H diff --git a/lib/render/vp2RenderDelegate/draw_item.cpp b/lib/render/vp2RenderDelegate/draw_item.cpp new file mode 100644 index 0000000000..11cf334952 --- /dev/null +++ b/lib/render/vp2RenderDelegate/draw_item.cpp @@ -0,0 +1,73 @@ +// +// Copyright 2019 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. +// + +#include "pxr/imaging/hd/mesh.h" + +#include "draw_item.h" +#include "render_delegate.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief Constructor. + +Data holder for its corresponding render item to facilitate parallelized evaluation. + +Position buffer is held by HdVP2Mesh and shared among its render items. +*/ +HdVP2DrawItem::HdVP2DrawItem( + HdVP2RenderDelegate* delegate, + const HdRprimSharedData* sharedData, + const HdMeshReprDesc& desc) +: HdDrawItem(sharedData) +, _delegate(delegate) +, _reprDesc(desc) +{ + // In the case of instancing, the ID of a proto has an attribute at the end, + // we keep this info in _renderItemName so if needed we can extract proto ID + // and use it to figure out Rprim path for each instance. For example: + // + // "/Proxy/TreePatch/Tree_1.proto_leaves_id0" + // + _renderItemName = GetRprimID().GetText(); + _renderItemName += TfStringPrintf("/DrawItem_%p", this).c_str(); + + _mesh._indexBuffer.reset( + new MHWRender::MIndexBuffer(MHWRender::MGeometry::kUnsignedInt32)); + + if (desc.geomStyle == HdMeshGeomStyleHull) { + const MHWRender::MVertexBufferDescriptor desc("", + MHWRender::MGeometry::kNormal, MHWRender::MGeometry::kFloat, 3); + _mesh._normalsBuffer.reset(new MHWRender::MVertexBuffer(desc)); + } +} + +//! \brief Destructor. +HdVP2DrawItem::~HdVP2DrawItem() { + if (_delegate) { + auto* const param = static_cast(_delegate->GetRenderParam()); + MSubSceneContainer* subSceneContainer = param ? param->GetContainer() : nullptr; + if(subSceneContainer) { + subSceneContainer->remove(GetRenderItemName()); + } + } +} + +//! \brief Get access to render item data. +HdVP2DrawItem::RenderItemData& HdVP2DrawItem::GetRenderItemData() { + return _mesh; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/draw_item.h b/lib/render/vp2RenderDelegate/draw_item.h new file mode 100644 index 0000000000..c58ec57858 --- /dev/null +++ b/lib/render/vp2RenderDelegate/draw_item.h @@ -0,0 +1,105 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_DRAW_ITEM +#define HD_VP2_DRAW_ITEM + +#include "pxr/pxr.h" +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/vt/array.h" +#include "pxr/imaging/hd/changeTracker.h" +#include "pxr/imaging/hd/drawItem.h" +#include "pxr/usd/usd/timeCode.h" + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +struct HdMeshReprDesc; +class HdVP2RenderDelegate; + +/*! \brief Draw Item holds information necessary for accessing and updating VP2 render items + \class HdVP2DrawItem +*/ +class HdVP2DrawItem final : public HdDrawItem +{ +public: + //! Helper struct providing storage for per frame cache data + struct CachedData { + MBoundingBox _boundingBox; //!< Bounding box cache + VtArray _normals; //!< Normals cache + }; + + //! A primvar vertex buffer map indexed by primvar name. + using PrimvarBufferMap = std::unordered_map< + TfToken, + std::unique_ptr, + TfToken::HashFunctor + >; + + //! Helper struct providing storage for render item data + struct RenderItemData { + //! Render item color buffer - use when updating data + std::unique_ptr _colorBuffer; + //! Render item normals buffer - use when updating data + std::unique_ptr _normalsBuffer; + //! Render item primvar buffers - use when updating data + PrimvarBufferMap _primvarBuffers; + //! Render item index buffer - use when updating data + std::unique_ptr _indexBuffer; + + //! Number of instances currently allocated for render item + unsigned int _instanceCount{ 0 }; + + //! Per frame cache + std::map _cache; + }; + +public: + HdVP2DrawItem(HdVP2RenderDelegate* delegate, const HdRprimSharedData* sharedData, const HdMeshReprDesc& desc); + + ~HdVP2DrawItem(); + + RenderItemData& GetRenderItemData(); + + /*! \brief Get render item name + */ + const MString& GetRenderItemName() const { return _renderItemName; } + + /*! \brief Whether the draw item is enabled. + */ + bool IsEnabled() const { return _enabled; } + + /*! \brief Enable or disable the draw item. + */ + void Enable(bool v) { _enabled = v; } + + /*! \brief Get the repr desc for which the draw item was created. + */ + const HdMeshReprDesc& GetReprDesc() const { return _reprDesc; } + +private: + HdVP2RenderDelegate* _delegate{ nullptr }; //!< VP2 render delegate for which this draw item was created + const HdMeshReprDesc _reprDesc; //!< The repr desc for which the draw item was created. + RenderItemData _mesh; //!< VP2 render item data + MString _renderItemName; //!< Unique name. Use this when searching for render item in subscene override container + bool _enabled{ true }; //!< Whether the draw item is enabled. +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/instancer.cpp b/lib/render/vp2RenderDelegate/instancer.cpp new file mode 100644 index 0000000000..5e3f5e60dc --- /dev/null +++ b/lib/render/vp2RenderDelegate/instancer.cpp @@ -0,0 +1,238 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +// Modifications copyright (C) 2019 Autodesk +// +#include "pxr/imaging/glf/glew.h" + +#include "instancer.h" +#include "sampler.h" + +#include "pxr/imaging/hd/sceneDelegate.h" + +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/vec4f.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/rotation.h" +#include "pxr/base/gf/quaternion.h" +#include "pxr/base/tf/staticTokens.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// Define local tokens for the names of the primvars the instancer +// consumes. +// XXX: These should be hydra tokens... +TF_DEFINE_PRIVATE_TOKENS( + _tokens, + (instanceTransform) + (rotate) + (scale) + (translate) +); + +/*! \brief Constructor. + + \param delegate The scene delegate backing this instancer's data. + \param id The unique id of this instancer. + \param parentId The unique id of the parent instancer, + or an empty id if not applicable. +*/ +HdVP2Instancer::HdVP2Instancer(HdSceneDelegate* delegate, + SdfPath const& id, + SdfPath const &parentId) + : HdInstancer(delegate, id, parentId) +{ +} + +/*! \brief Destructor. +*/ +HdVP2Instancer::~HdVP2Instancer() +{ + TF_FOR_ALL(it, _primvarMap) { + delete it->second; + } + _primvarMap.clear(); +} + + +/*! \brief Checks the change tracker to determine whether instance primvars are + dirty, and if so pulls them. + + Since primvars can only be pulled once, and are cached, this function is not + re-entrant. However, this function is called by ComputeInstanceTransforms, + which is called by HdVP2Mesh::Sync(), which is dispatched in parallel, so it needs + to be guarded by _instanceLock. +*/ +void HdVP2Instancer::_SyncPrimvars() +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + HdChangeTracker &changeTracker = + GetDelegate()->GetRenderIndex().GetChangeTracker(); + SdfPath const& id = GetId(); + + // Use the double-checked locking pattern to check if this instancer's + // primvars are dirty. + int dirtyBits = changeTracker.GetInstancerDirtyBits(id); + if (HdChangeTracker::IsAnyPrimvarDirty(dirtyBits, id)) { + std::lock_guard lock(_instanceLock); + + // If not dirty, then another thread did the job + dirtyBits = changeTracker.GetInstancerDirtyBits(id); + if (HdChangeTracker::IsAnyPrimvarDirty(dirtyBits, id)) { + + // If this instancer has dirty primvars, get the list of + // primvar names and then cache each one. + + TfTokenVector primvarNames; + HdPrimvarDescriptorVector primvars = GetDelegate() + ->GetPrimvarDescriptors(id, HdInterpolationInstance); + + for (HdPrimvarDescriptor const& pv: primvars) { + if (HdChangeTracker::IsPrimvarDirty(dirtyBits, id, pv.name)) { + VtValue value = GetDelegate()->Get(id, pv.name); + if (!value.IsEmpty()) { + if (_primvarMap.count(pv.name) > 0) { + delete _primvarMap[pv.name]; + } + _primvarMap[pv.name] = + new HdVtBufferSource(pv.name, value); + } + } + } + + // Mark the instancer as clean + changeTracker.MarkInstancerClean(id); + } + } +} + +/*! \brief Computes all instance transforms for the provided prototype id. + + Taking into account the scene delegate's instancerTransform and the + instance primvars "instanceTransform", "translate", "rotate", "scale". + Computes and flattens nested transforms, if necessary. + + \param prototypeId The prototype to compute transforms for. + + \return One transform per instance, to apply when drawing. +*/ +VtMatrix4dArray HdVP2Instancer::ComputeInstanceTransforms(SdfPath const &prototypeId) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + _SyncPrimvars(); + + // The transforms for this level of instancer are computed by: + // foreach(index : indices) { + // instancerTransform * translate(index) * rotate(index) * + // scale(index) * instanceTransform(index) + // } + // If any transform isn't provided, it's assumed to be the identity. + + GfMatrix4d instancerTransform = + GetDelegate()->GetInstancerTransform(GetId()); + VtIntArray instanceIndices = + GetDelegate()->GetInstanceIndices(GetId(), prototypeId); + + VtMatrix4dArray transforms(instanceIndices.size()); + for (size_t i = 0; i < instanceIndices.size(); ++i) { + transforms[i] = instancerTransform; + } + + // "translate" holds a translation vector for each index. + if (_primvarMap.count(_tokens->translate) > 0) { + HdVP2BufferSampler sampler(*_primvarMap[_tokens->translate]); + for (size_t i = 0; i < instanceIndices.size(); ++i) { + GfVec3f translate; + if (sampler.Sample(instanceIndices[i], &translate)) { + GfMatrix4d translateMat(1); + translateMat.SetTranslate(GfVec3d(translate)); + transforms[i] = translateMat * transforms[i]; + } + } + } + + // "rotate" holds a quaternion in format for each index. + if (_primvarMap.count(_tokens->rotate) > 0) { + HdVP2BufferSampler sampler(*_primvarMap[_tokens->rotate]); + for (size_t i = 0; i < instanceIndices.size(); ++i) { + GfVec4f quat; + if (sampler.Sample(instanceIndices[i], &quat)) { + GfMatrix4d rotateMat(1); + rotateMat.SetRotate(GfRotation(GfQuaternion( + quat[0], GfVec3d(quat[1], quat[2], quat[3])))); + transforms[i] = rotateMat * transforms[i]; + } + } + } + + // "scale" holds an axis-aligned scale vector for each index. + if (_primvarMap.count(_tokens->scale) > 0) { + HdVP2BufferSampler sampler(*_primvarMap[_tokens->scale]); + for (size_t i = 0; i < instanceIndices.size(); ++i) { + GfVec3f scale; + if (sampler.Sample(instanceIndices[i], &scale)) { + GfMatrix4d scaleMat(1); + scaleMat.SetScale(GfVec3d(scale)); + transforms[i] = scaleMat * transforms[i]; + } + } + } + + // "instanceTransform" holds a 4x4 transform matrix for each index. + if (_primvarMap.count(_tokens->instanceTransform) > 0) { + HdVP2BufferSampler sampler(*_primvarMap[_tokens->instanceTransform]); + for (size_t i = 0; i < instanceIndices.size(); ++i) { + GfMatrix4d instanceTransform; + if (sampler.Sample(instanceIndices[i], &instanceTransform)) { + transforms[i] = instanceTransform * transforms[i]; + } + } + } + + if (GetParentId().IsEmpty()) { + return transforms; + } + + HdInstancer *parentInstancer = + GetDelegate()->GetRenderIndex().GetInstancer(GetParentId()); + if (!TF_VERIFY(parentInstancer)) { + return transforms; + } + + // The transforms taking nesting into account are computed by: + // parentTransforms = parentInstancer->ComputeInstanceTransforms(GetId()) + // foreach (parentXf : parentTransforms, xf : transforms) { + // parentXf * xf + // } + VtMatrix4dArray parentTransforms = + static_cast(parentInstancer)-> + ComputeInstanceTransforms(GetId()); + + VtMatrix4dArray final(parentTransforms.size() * transforms.size()); + for (size_t i = 0; i < parentTransforms.size(); ++i) { + for (size_t j = 0; j < transforms.size(); ++j) { + final[i * transforms.size() + j] = transforms[j] * + parentTransforms[i]; + } + } + return final; +} + +PXR_NAMESPACE_CLOSE_SCOPE + diff --git a/lib/render/vp2RenderDelegate/instancer.h b/lib/render/vp2RenderDelegate/instancer.h new file mode 100644 index 0000000000..c1807fedf6 --- /dev/null +++ b/lib/render/vp2RenderDelegate/instancer.h @@ -0,0 +1,65 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +// Modifications copyright (C) 2019 Autodesk +// +#ifndef HD_VP2_INSTANCER +#define HD_VP2_INSTANCER + +#include "pxr/pxr.h" + +#include "pxr/imaging/hd/instancer.h" +#include "pxr/imaging/hd/vtBufferSource.h" + +#include "pxr/base/tf/hashmap.h" +#include "pxr/base/tf/token.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief VP2 instancing of prototype geometry with varying transforms + \class HdVP2Instancer + + Nested instancing can be handled by recursion, and by taking the + cartesian product of the transform arrays at each nesting level, to + create a flattened transform array. +*/ +class HdVP2Instancer final : public HdInstancer +{ +public: + HdVP2Instancer(HdSceneDelegate* delegate, SdfPath const& id, + SdfPath const &parentInstancerId); + + ~HdVP2Instancer(); + + VtMatrix4dArray ComputeInstanceTransforms(SdfPath const &prototypeId); + +private: + void _SyncPrimvars(); + + //! Mutex guard for _SyncPrimvars(). + std::mutex _instanceLock; + + /*! Map of the latest primvar data for this instancer, keyed by + primvar name. Primvar values are VtValue, an any-type; they are + interpreted at consumption time (here, in ComputeInstanceTransforms). + */ + TfHashMap _primvarMap; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/material.cpp b/lib/render/vp2RenderDelegate/material.cpp new file mode 100644 index 0000000000..0671eec1ed --- /dev/null +++ b/lib/render/vp2RenderDelegate/material.cpp @@ -0,0 +1,803 @@ +// +// Copyright 2019 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. +// + +#include "debugCodes.h" +#include "material.h" +#include "render_delegate.h" + +#include "pxr/imaging/glf/image.h" +#include "pxr/imaging/hd/sceneDelegate.h" +#include "pxr/usd/ar/packageUtils.h" +#include "pxr/usd/sdf/assetPath.h" +#include "pxr/usd/usdHydra/tokens.h" +#include "pxr/usdImaging/usdImaging/tokens.h" + +#include "pxr/base/gf/vec2f.h" +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/vec4f.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" +#include "pxr/base/tf/diagnostic.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +TF_DEFINE_PRIVATE_TOKENS( + _tokens, + + (file) + (opacity) + (st) + (varname) + + (input) + (output) + + (rgb) + (r) + (g) + (b) + (a) + + (xyz) + (x) + (y) + (z) + (w) + + (Float4ToFloatX) + (Float4ToFloatY) + (Float4ToFloatZ) + (Float4ToFloatW) + (Float4ToFloat3) +); + +//! Helper utility function to test whether a node is a UsdShade primvar reader. +bool _IsUsdPrimvarReader(const HdMaterialNode& node) +{ + const TfToken& id = node.identifier; + return (id == UsdImagingTokens->UsdPrimvarReader_float || + id == UsdImagingTokens->UsdPrimvarReader_float2 || + id == UsdImagingTokens->UsdPrimvarReader_float3 || + id == UsdImagingTokens->UsdPrimvarReader_float4); +} + +//! Helper utility function to test whether a node is a UsdShade UV texture. +inline bool _IsUsdUVTexture(const HdMaterialNode& node) +{ + return (node.identifier == UsdImagingTokens->UsdUVTexture); +} + +//! Helper utility function to print nodes, connections and primvars in the +//! specified material network. +void _PrintMaterialNetwork( + const std::string& label, + const SdfPath& id, + const HdMaterialNetwork& mat) +{ + std::cout << label << " material network for " << id << "\n"; + + std::cout << " --Node--\n"; + for (HdMaterialNode const& node: mat.nodes) { + std::cout << " " << node.path << "\n"; + std::cout << " " << node.identifier << "\n"; + + for (auto const& entry: node.parameters) { + std::cout << " param " << entry.first << ": " + << TfStringify(entry.second) << "\n"; + } + } + + std::cout << " --Connections--\n"; + for (const HdMaterialRelationship& rel: mat.relationships) { + std::cout << " " << rel.inputId << "." << rel.inputName + << "->" << rel.outputId << "." << rel.outputName << "\n"; + } + + std::cout << " --Primvars--\n"; + for (TfToken const& primvar: mat.primvars) { + std::cout << " " << primvar << "\n"; + } +} + +//! Helper utility function to apply VP2-specific fixes to the material network. +//! - Add passthrough nodes to read vector component(s). +//! - Fix UsdImagingMaterialAdapter issue for not producing primvar requirements. +//! - Temporary workaround of missing support for normal map. +void _ApplyVP2Fixes(HdMaterialNetwork& outNet, const HdMaterialNetwork& inNet) +{ + unsigned int numPassThroughNodes = 0; + + for (const HdMaterialNode &node : inNet.nodes) + { + outNet.nodes.push_back(node); + + // Copy outgoing connections and if needed add passthrough node/connection. + for (const HdMaterialRelationship& rel : inNet.relationships) { + if (rel.inputId != node.path) { + continue; + } + + TfToken passThroughId; + if (rel.inputName == _tokens->rgb || rel.inputName == _tokens->xyz) { + passThroughId = _tokens->Float4ToFloat3; + } + else if (rel.inputName == _tokens->r || rel.inputName == _tokens->x) { + passThroughId = _tokens->Float4ToFloatX; + } + else if (rel.inputName == _tokens->g || rel.inputName == _tokens->y) { + passThroughId = _tokens->Float4ToFloatY; + } + else if (rel.inputName == _tokens->b || rel.inputName == _tokens->z) { + passThroughId = _tokens->Float4ToFloatZ; + } + else if (rel.inputName == _tokens->a || rel.inputName == _tokens->w) { + passThroughId = _tokens->Float4ToFloatW; + } + else { + outNet.relationships.push_back(rel); + continue; + } + + const SdfPath passThroughPath = rel.inputId.ReplaceName(TfToken( + TfStringPrintf("HdVP2PassThrough%d", numPassThroughNodes++))); + + const HdMaterialNode passThroughNode = { + passThroughPath, passThroughId, {} + }; + outNet.nodes.push_back(passThroughNode); + + HdMaterialRelationship newRel = { + rel.inputId, _tokens->output, passThroughPath, _tokens->input + }; + outNet.relationships.push_back(newRel); + + newRel = { + passThroughPath, _tokens->output, rel.outputId, rel.outputName + }; + outNet.relationships.push_back(newRel); + } + + // Normal map is not supported yet. For now primvars:normals is used for + // shading, which is also the current behavior of USD/Hydra. + // https://groups.google.com/d/msg/usd-interest/7epU16C3eyY/X9mLW9VFEwAJ + if (node.identifier == UsdImagingTokens->UsdPreviewSurface) { + outNet.primvars.push_back(HdTokens->normals); + } + // UsdImagingMaterialAdapter doesn't create primvar requirements as + // expected. Workaround by manually looking up "varname" parameter. + // https://groups.google.com/forum/#!msg/usd-interest/z-14AgJKOcU/1uJJ1thXBgAJ + else if (_IsUsdPrimvarReader(node)) { + auto it = node.parameters.find(_tokens->varname); + if (it != node.parameters.end()) { + outNet.primvars.push_back(TfToken(TfStringify(it->second))); + } + } + } +} + +//! Helper utility function to convert Hydra texture addressing token to VP2 enum. +MHWRender::MSamplerState::TextureAddress _ConvertToTextureSamplerAddressEnum( + const TfToken& token) +{ + MHWRender::MSamplerState::TextureAddress address; + + if (token == UsdHydraTokens->clamp) { + address = MHWRender::MSamplerState::kTexClamp; + } + else if (token == UsdHydraTokens->mirror) { + address = MHWRender::MSamplerState::kTexMirror; + } + else if (token == UsdHydraTokens->black) { + address = MHWRender::MSamplerState::kTexBorder; + } + else { + address = MHWRender::MSamplerState::kTexWrap; + } + + return address; +} + +//! Get sampler state description as required by the material node. +MHWRender::MSamplerStateDesc _GetSamplerStateDesc(const HdMaterialNode& node) +{ + TF_VERIFY(_IsUsdUVTexture(node)); + + MHWRender::MSamplerStateDesc desc; + desc.filter = MHWRender::MSamplerState::kMinMagMipLinear; + + auto it = node.parameters.find(UsdHydraTokens->wrapS); + if (it != node.parameters.end()) { + const VtValue& value = it->second; + if (value.IsHolding()) { + const TfToken& token = value.UncheckedGet(); + desc.addressU = _ConvertToTextureSamplerAddressEnum(token); + } + } + + it = node.parameters.find(UsdHydraTokens->wrapT); + if (it != node.parameters.end()) { + const VtValue& value = it->second; + if (value.IsHolding()) { + const TfToken& token = value.UncheckedGet(); + desc.addressV = _ConvertToTextureSamplerAddressEnum(token); + } + } + + return desc; +} + +//! Load texture from the specified path +MHWRender::MTexture* _LoadTexture( + const std::string& path, + bool& isColorSpaceSRGB) +{ + isColorSpaceSRGB = false; + + MHWRender::MRenderer* const renderer = MHWRender::MRenderer::theRenderer(); + MHWRender::MTextureManager* const textureMgr = + renderer ? renderer->getTextureManager() : nullptr; + if (!TF_VERIFY(textureMgr)) { + return nullptr; + } + + GlfImageSharedPtr image = GlfImage::OpenForReading(path); + if (!TF_VERIFY(image)) { + return nullptr; + } + + // GlfImage is used for loading pixel data from usdz only and should + // not trigger any OpenGL call. VP2RenderDelegate will transfer the + // texels to GPU memory with VP2 API which is 3D API agnostic. + GlfImage::StorageSpec spec; + spec.width = image->GetWidth(); + spec.height = image->GetHeight(); + spec.depth = 1; + spec.format = image->GetFormat(); + spec.type = image->GetType(); + spec.flipped = false; + + const int bpp = image->GetBytesPerPixel(); + const int bytesPerRow = spec.width * bpp; + const int bytesPerSlice = bytesPerRow * spec.height; + + std::vector storage(bytesPerSlice); + spec.data = storage.data(); + + if (!image->Read(spec)) { + return nullptr; + } + + MHWRender::MTexture* texture = nullptr; + + MHWRender::MTextureDescription desc; + desc.setToDefault2DTexture(); + desc.fWidth = spec.width; + desc.fHeight = spec.height; + desc.fBytesPerRow = bytesPerRow; + desc.fBytesPerSlice = bytesPerSlice; + + switch (spec.format) + { + case GL_RED: + desc.fFormat = (spec.type == GL_FLOAT ? + MHWRender::kR32_FLOAT : MHWRender::kR8_UNORM); + texture = textureMgr->acquireTexture(path.c_str(), desc, spec.data); + break; + case GL_RGB: + if (spec.type == GL_FLOAT) { + desc.fFormat = MHWRender::kR32G32B32_FLOAT; + texture = textureMgr->acquireTexture(path.c_str(), desc, spec.data); + } + else { + // R8G8B8 is not supported by VP2. Converted to R8G8B8A8. + constexpr int bpp_4 = 4; + + desc.fFormat = MHWRender::kR8G8B8A8_UNORM; + desc.fBytesPerRow = spec.width * bpp_4; + desc.fBytesPerSlice = desc.fBytesPerRow * spec.height; + + std::vector texels(desc.fBytesPerSlice); + + for (int y = 0; y < spec.height; y++) { + for (int x = 0; x < spec.width; x++) { + const int t = spec.width * y + x; + texels[t*bpp_4] = storage[t*bpp]; + texels[t*bpp_4 + 1] = storage[t*bpp + 1]; + texels[t*bpp_4 + 2] = storage[t*bpp + 2]; + texels[t*bpp_4 + 3] = 255; + } + } + + texture = textureMgr->acquireTexture(path.c_str(), desc, texels.data()); + isColorSpaceSRGB = image->IsColorSpaceSRGB(); + } + break; + case GL_RGBA: + if (spec.type == GL_FLOAT) { + desc.fFormat = MHWRender::kR32G32B32A32_FLOAT; + } + else { + desc.fFormat = MHWRender::kR8G8B8A8_UNORM; + isColorSpaceSRGB = image->IsColorSpaceSRGB(); + } + texture = textureMgr->acquireTexture(path.c_str(), desc, spec.data); + break; + default: + break; + } + + return texture; +} + +} //anonymous namespace + +/*! \brief Releases the reference to the shader owned by a smart pointer. +*/ +void +HdVP2ShaderDeleter::operator()(MHWRender::MShaderInstance* shader) +{ + MRenderer* const renderer = MRenderer::theRenderer(); + const MShaderManager* const shaderMgr = + renderer ? renderer->getShaderManager() : nullptr; + if (TF_VERIFY(shaderMgr)) { + shaderMgr->releaseShader(shader); + } +} + +/*! \brief Releases the reference to the texture owned by a smart pointer. +*/ +void +HdVP2TextureDeleter::operator()(MHWRender::MTexture* texture) +{ + MRenderer* const renderer = MRenderer::theRenderer(); + MHWRender::MTextureManager* const textureMgr = + renderer ? renderer->getTextureManager() : nullptr; + if (TF_VERIFY(textureMgr)) { + textureMgr->releaseTexture(texture); + } +} + +/*! \brief Constructor +*/ +HdVP2Material::HdVP2Material(HdVP2RenderDelegate* renderDelegate, const SdfPath& id) + : HdMaterial(id) + , _renderDelegate(renderDelegate) +{ +} + +/*! \brief Destructor - will release allocated shader instances. +*/ +HdVP2Material::~HdVP2Material() { +} + +/*! \brief Synchronize VP2 state with scene delegate state based on dirty bits +*/ +void HdVP2Material::Sync( + HdSceneDelegate* sceneDelegate, + HdRenderParam* /*renderParam*/, + HdDirtyBits* dirtyBits) +{ + if (*dirtyBits & (HdMaterial::DirtyResource | HdMaterial::DirtyParams)) { + const SdfPath& id = GetId(); + VtValue vtMatResource = sceneDelegate->GetMaterialResource(id); + + if (vtMatResource.IsHolding()) { + const HdMaterialNetworkMap& networkMap = + vtMatResource.UncheckedGet(); + + HdMaterialNetwork bxdfNet, dispNet; + TfMapLookup(networkMap.map, HdMaterialTerminalTokens->surface, &bxdfNet); + TfMapLookup(networkMap.map, HdMaterialTerminalTokens->displacement, &dispNet); + + if (*dirtyBits & HdMaterial::DirtyResource) { + // Apply VP2 fixes to the material network + HdMaterialNetwork vp2BxdfNet; + _ApplyVP2Fixes(vp2BxdfNet, bxdfNet); + + // Create a shader instance for the material network. + _surfaceShader.reset(_CreateShaderInstance(vp2BxdfNet)); + + if (TfDebug::IsEnabled(HDVP2_DEBUG_MATERIAL)) { + _PrintMaterialNetwork("BXDF", id, bxdfNet); + _PrintMaterialNetwork("BXDF (with VP2 fixes)", id, vp2BxdfNet); + _PrintMaterialNetwork("Displacement", id, dispNet); + + if (_surfaceShader) { + auto tmpDir = boost::filesystem::temp_directory_path(); + tmpDir /= "HdVP2Material_"; + tmpDir += id.GetName(); + tmpDir += ".txt"; + _surfaceShader->writeEffectSourceToFile(tmpDir.c_str()); + + std::cout << "BXDF generated shader code for " << id << ":\n"; + std::cout << " " << tmpDir << "\n"; + } + } + + // Store primvar requirements. + _requiredPrimvars = std::move(vp2BxdfNet.primvars); + } + + _UpdateShaderInstance(bxdfNet); + } + else { + TF_WARN("Expected material resource for <%s> to hold HdMaterialNetworkMap," + "but found %s instead.", + id.GetText(), vtMatResource.GetTypeName().c_str()); + } + } + + *dirtyBits = HdMaterial::Clean; +} + +/*! \brief Reload the shader +*/ +void HdVP2Material::Reload() { +} + +/*! \brief Returns the minimal set of dirty bits to place in the +change tracker for use in the first sync of this prim. +*/ +HdDirtyBits +HdVP2Material::GetInitialDirtyBitsMask() const { + return HdMaterial::AllDirty; +} + +/*! \brief Returns surface shader instance +*/ +MHWRender::MShaderInstance* +HdVP2Material::GetSurfaceShader() const { + return _surfaceShader.get(); +} + +/*! \brief Creates a shader instance for the surface shader. +*/ +MHWRender::MShaderInstance* +HdVP2Material::_CreateShaderInstance(const HdMaterialNetwork& mat) { + MHWRender::MRenderer* const renderer = MHWRender::MRenderer::theRenderer(); + if (!TF_VERIFY(renderer)) { + return nullptr; + } + + const MHWRender::MShaderManager* const shaderMgr = renderer->getShaderManager(); + if (!TF_VERIFY(shaderMgr)) { + return nullptr; + } + + MHWRender::MShaderInstance* shaderInstance = nullptr; + + // Conditional compilation due to Maya API gaps. +#if MAYA_API_VERSION >= 20200000 + + // UsdImagingMaterialAdapter has walked the shader graph and emitted nodes + // and relationships in topological order to avoid forward-references, thus + // we can run a reverse iteration to avoid connecting a fragment before any + // of its downstream fragments. + for (auto rit = mat.nodes.rbegin(); rit != mat.nodes.rend(); rit++) { + const HdMaterialNode& node = *rit; + + const MString nodeId = node.identifier.GetText(); + const MString nodeName = node.path.GetNameToken().GetText(); + + if (shaderInstance == nullptr) { + shaderInstance = shaderMgr->getFragmentShader(nodeId, "outSurfaceFinal", true); + _surfaceShaderId = node.path; + + if (shaderInstance == nullptr) { + TF_WARN("Failed to create shader instance for %s", nodeId.asChar()); + break; + } + + continue; + } + + MStringArray outputNames, inputNames; + + for (const HdMaterialRelationship& rel : mat.relationships) { + if (rel.inputId == node.path) { + MString outputName = rel.inputName.GetText(); + outputNames.append(outputName); + + if (rel.outputId != _surfaceShaderId) { + std::string str = rel.outputId.GetName(); + str += rel.outputName.GetString(); + inputNames.append(str.c_str()); + } + else { + inputNames.append(rel.outputName.GetText()); + + if (rel.outputName == _tokens->opacity) { + shaderInstance->setIsTransparent(true); + } + } + } + } + + if (outputNames.length() > 0) { + MUintArray invalidParamIndices; + MStatus status = shaderInstance->addInputFragmentForMultiParams( + nodeId, nodeName, outputNames, inputNames, &invalidParamIndices); + + if (!status && TfDebug::IsEnabled(HDVP2_DEBUG_MATERIAL)) { + TF_WARN("Error %s happened when connecting shader %s", + status.errorString().asChar(), node.path.GetText()); + + for (unsigned int i = 0; i < invalidParamIndices.length(); i++) { + unsigned int index = invalidParamIndices[i]; + const MString& outputName = outputNames[index]; + const MString& inputName = inputNames[index]; + TF_WARN(" %s -> %s", outputName.asChar(), inputName.asChar()); + } + } + + if (_IsUsdPrimvarReader(node)) { + auto it = node.parameters.find(_tokens->varname); + if (it != node.parameters.end()) { + const MString paramName = HdTokens->primvar.GetText(); + const MString varname = TfStringify(it->second).c_str(); + shaderInstance->renameParameter(paramName, varname); + } + } + } + else { + TF_DEBUG(HDVP2_DEBUG_MATERIAL).Msg("Failed to connect shader %s\n", + node.path.GetText()); + } + } + +#elif MAYA_API_VERSION >= 20190000 + + // UsdImagingMaterialAdapter has walked the shader graph and emitted nodes + // and relationships in topological order to avoid forward-references, thus + // we can run a reverse iteration to avoid connecting a fragment before any + // of its downstream fragments. + for (auto rit = mat.nodes.rbegin(); rit != mat.nodes.rend(); rit++) { + const HdMaterialNode& node = *rit; + + const MString nodeId = node.identifier.GetText(); + const MString nodeName = node.path.GetNameToken().GetText(); + + if (shaderInstance == nullptr) { + shaderInstance = shaderMgr->getFragmentShader(nodeId, "outSurfaceFinal", true); + _surfaceShaderId = node.path; + + if (shaderInstance == nullptr) { + TF_WARN("Failed to create shader instance for %s", nodeId.asChar()); + break; + } + + continue; + } + + MStringArray outputNames, inputNames; + + std::string primvarname; + + for (const HdMaterialRelationship& rel : mat.relationships) { + if (rel.inputId == node.path) { + outputNames.append(rel.inputName.GetText()); + inputNames.append(rel.outputName.GetText()); + + if (rel.outputName == _tokens->opacity) { + shaderInstance->setIsTransparent(true); + } + } + + if (_IsUsdUVTexture(node)) { + if (rel.outputId == node.path && + rel.outputName == _tokens->st) { + for (const HdMaterialNode& n : mat.nodes) { + if (n.path == rel.inputId && _IsUsdPrimvarReader(n)) { + auto it = n.parameters.find(_tokens->varname); + if (it != n.parameters.end()) { + primvarname = TfStringify(it->second); + } + break; + } + } + } + } + } + + // Without multi-connection support for MShaderInstance, this code path + // can only support common patterns of UsdShade material network, i.e. + // a UsdUVTexture is connected to a single input of a USD Preview Surface. + // More generic fix is coming. + if (outputNames.length() == 1) { + MStatus status = shaderInstance->addInputFragment( + nodeId, outputNames[0], inputNames[0]); + + if (!status) { + TF_DEBUG(HDVP2_DEBUG_MATERIAL).Msg( + "Error %s happened when connecting shader %s\n", + status.errorString().asChar(), node.path.GetText()); + } + + if (_IsUsdUVTexture(node)) { + const MString paramNames[] = { + "file", "fileSampler", "isColorSpaceSRGB", "fallback", "scale", "bias" + }; + + for (const MString& paramName : paramNames) { + const MString resolvedName = nodeName + paramName; + shaderInstance->renameParameter(paramName, resolvedName); + } + + const MString paramName = _tokens->st.GetText(); + shaderInstance->setSemantic(paramName, "uvCoord"); + shaderInstance->setAsVarying(paramName, true); + shaderInstance->renameParameter(paramName, primvarname.c_str()); + } + } + else { + TF_DEBUG(HDVP2_DEBUG_MATERIAL).Msg( + "Failed to connect shader %s\n", node.path.GetText()); + } + } + +#endif + + return shaderInstance; +} + +/*! \brief Updates parameters for the surface shader. +*/ +void HdVP2Material::_UpdateShaderInstance(const HdMaterialNetwork& mat) +{ + if (!_surfaceShader) { + return; + } + + for (const HdMaterialNode& node : mat.nodes) { + const MString nodeName = + node.path != _surfaceShaderId ? node.path.GetName().c_str() : ""; + + MStatus samplerStatus = MStatus::kFailure; + + if (_IsUsdUVTexture(node)) { + const MHWRender::MSamplerStateDesc desc = _GetSamplerStateDesc(node); + const MHWRender::MSamplerState* sampler = + _renderDelegate->GetSamplerState(desc); + if (sampler) { + const MString paramName = nodeName + "fileSampler"; + samplerStatus = _surfaceShader->setParameter(paramName, *sampler); + } + } + + for (auto const& entry: node.parameters) { + const TfToken& token = entry.first; + const VtValue& value = entry.second; + + MString paramName = nodeName + token.GetText(); + + MStatus status = MStatus::kFailure; + + if (value.IsHolding()) { + const bool& val = value.UncheckedGet(); + status = _surfaceShader->setParameter(paramName, val); + } + else if (value.IsHolding()) { + const int& val = value.UncheckedGet(); + status = _surfaceShader->setParameter(paramName, val); + } + else if (value.IsHolding()) { + const float& val = value.UncheckedGet(); + status = _surfaceShader->setParameter(paramName, val); + + // The opacity parameter can be found and updated only when it + // has no connection. In this case, transparency of the shader + // is solely determined by the opacity value. + if (nodeName.length() == 0 && token == _tokens->opacity) { + _surfaceShader->setIsTransparent(!status || val < 0.999f); + } + } + else if (value.IsHolding()) { + const float* val = value.UncheckedGet().data(); + status = _surfaceShader->setParameter(paramName, val); + } + else if (value.IsHolding()) { + const float* val = value.UncheckedGet().data(); + status = _surfaceShader->setParameter(paramName, val); + } + else if (value.IsHolding()) { + const float* val = value.UncheckedGet().data(); + status = _surfaceShader->setParameter(paramName, val); + } + else if (value.IsHolding()) { + MMatrix matrix; + value.UncheckedGet().Get(matrix.matrix); + status = _surfaceShader->setParameter(paramName, matrix); + } + else if (value.IsHolding()) { + MFloatMatrix matrix; + value.UncheckedGet().Get(matrix.matrix); + status = _surfaceShader->setParameter(paramName, matrix); + } + else if (value.IsHolding()) { + // The two parameters have been converted to sampler state + // before entering this loop. + if (_IsUsdUVTexture(node) && + (token == UsdHydraTokens->wrapS || + token == UsdHydraTokens->wrapT)) { + status = samplerStatus; + } + } + else if (value.IsHolding()) { + const SdfAssetPath& val = value.UncheckedGet(); + const std::string& resolvedPath = val.GetResolvedPath(); + const std::string& assetPath = val.GetAssetPath(); + if (_IsUsdUVTexture(node) && token == _tokens->file) { + const HdVP2TextureInfo& info = _AcquireTexture( + !resolvedPath.empty() ? resolvedPath : assetPath); + + MHWRender::MTextureAssignment assignment; + assignment.texture = info._texture.get(); + status = _surfaceShader->setParameter(paramName, assignment); + + if (status) { + paramName = nodeName + "isColorSpaceSRGB"; + status = _surfaceShader->setParameter(paramName, + info._isColorSpaceSRGB); + } + } + } + + if (!status) { + TF_DEBUG(HDVP2_DEBUG_MATERIAL).Msg( + "Failed to set shader parameter %s\n", paramName.asChar()); + } + } + } +} + +/*! \brief Acquires a texture for the given image path. +*/ +const HdVP2TextureInfo& +HdVP2Material::_AcquireTexture(const std::string& path) +{ + const auto it = _textureMap.find(path); + if (it != _textureMap.end()) { + return it->second; + } + + bool isSRGB = false; + MHWRender::MTexture* texture = _LoadTexture(path, isSRGB); + + HdVP2TextureInfo& info = _textureMap[path]; + info._texture.reset(texture); + info._isColorSpaceSRGB = isSRGB; + return info; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/material.h b/lib/render/vp2RenderDelegate/material.h new file mode 100644 index 0000000000..e9bfbdc8fb --- /dev/null +++ b/lib/render/vp2RenderDelegate/material.h @@ -0,0 +1,111 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_MATERIAL +#define HD_VP2_MATERIAL + +#include "pxr/pxr.h" +#include "pxr/imaging/hd/material.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class HdSceneDelegate; +class HdVP2RenderDelegate; + +/*! \brief A deleter for MShaderInstance, for use with smart pointers. +*/ +struct HdVP2ShaderDeleter +{ + void operator () (MHWRender::MShaderInstance*); +}; + +/*! \brief A MShaderInstance owned by a std unique pointer. +*/ +using HdVP2ShaderUniquePtr = std::unique_ptr< + MHWRender::MShaderInstance, + HdVP2ShaderDeleter +>; + +/*! \brief A deleter for MTexture, for use with smart pointers. +*/ +struct HdVP2TextureDeleter +{ + void operator () (MHWRender::MTexture*); +}; + +/*! \brief A MTexture owned by a std unique pointer. +*/ +using HdVP2TextureUniquePtr = std::unique_ptr< + MHWRender::MTexture, + HdVP2TextureDeleter +>; + +/*! \brief Information about the texture. +*/ +struct HdVP2TextureInfo +{ + HdVP2TextureUniquePtr _texture; //!< Unique pointer of the texture + bool _isColorSpaceSRGB; //!< Whether sRGB linearization is needed +}; + +/*! \brief An unordered string-indexed map to cache texture information. +*/ +using HdVP2TextureMap = std::unordered_map; + +/*! \brief A VP2-specific implementation for a Hydra material prim. + \class HdVP2Material + + Provides a basic implementation of a Hydra material. +*/ +class HdVP2Material final : public HdMaterial { +public: + HdVP2Material(HdVP2RenderDelegate*, const SdfPath&); + + ~HdVP2Material() override; + + void Sync(HdSceneDelegate*, HdRenderParam*, HdDirtyBits*) override; + + HdDirtyBits GetInitialDirtyBitsMask() const override; + void Reload() override; + + MHWRender::MShaderInstance* GetSurfaceShader() const; + + /*! \brief Get primvar requirements required by this material. + */ + const TfTokenVector& GetRequiredPrimvars() const { + return _requiredPrimvars; + } + +private: + MHWRender::MShaderInstance* _CreateShaderInstance(const HdMaterialNetwork& mat); + void _UpdateShaderInstance(const HdMaterialNetwork& mat); + const HdVP2TextureInfo& _AcquireTexture(const std::string& path); + + HdVP2RenderDelegate* const _renderDelegate; //!< VP2 render delegate for which this material was created + + HdVP2ShaderUniquePtr _surfaceShader; //!< VP2 surface shader instance + SdfPath _surfaceShaderId; //!< Path of the surface shader + HdVP2TextureMap _textureMap; //!< Textures used by this material + TfTokenVector _requiredPrimvars; //!< primvars required by this material +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/mesh.cpp b/lib/render/vp2RenderDelegate/mesh.cpp new file mode 100644 index 0000000000..b9f7e29f25 --- /dev/null +++ b/lib/render/vp2RenderDelegate/mesh.cpp @@ -0,0 +1,1358 @@ +// +// Copyright 2019 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. +// + +#include "mesh.h" +#include "debugCodes.h" +#include "draw_item.h" +#include "material.h" +#include "instancer.h" +#include "proxyRenderDelegate.h" + +#include "pxr/base/gf/matrix4d.h" +#include "pxr/imaging/hd/sceneDelegate.h" +#include "pxr/imaging/hd/meshUtil.h" +#include "pxr/imaging/hd/smoothNormals.h" +#include "pxr/imaging/hd/vertexAdjacency.h" +#include "pxr/imaging/pxOsd/tokens.h" + +#include +#include +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + + //! A primvar vertex buffer data map indexed by primvar name. + using PrimvarBufferDataMap = std::unordered_map< + TfToken, + float*, + TfToken::HashFunctor + >; + + //! \brief Helper struct used to package all the changes into single commit task + //! (such commit task will be executed on main-thread) + struct CommitState { + HdVP2DrawItem::RenderItemData& _drawItemData; + + //! If valid, new position buffer data to commit + float* _positionBufferData{ nullptr }; + //! If valid, new index buffer data to commit + int* _indexBufferData{ nullptr }; + //! If valid, new color buffer data to commit + float* _colorBufferData{ nullptr }; + //! If valid, new normals buffer data to commit + float* _normalsBufferData{ nullptr }; + //! If valid, new primvar buffer data to commit + PrimvarBufferDataMap _primvarBufferDataMap; + + //! If valid, new shader instance to set + MHWRender::MShaderInstance* _surfaceShader{ nullptr }; + + //! Instancing doesn't have dirty bits, every time we do update, we must update instance transforms + MMatrixArray _instanceTransforms; + + //! Is this object transparent + bool _isTransparent{ false }; + + //! Capture of what has changed on this rprim + HdDirtyBits _dirtyBits; + + //! Construct valid commit state + CommitState(HdVP2DrawItem& drawItem, HdDirtyBits& dirtyBits) + : _drawItemData(drawItem.GetRenderItemData()) + , _dirtyBits(dirtyBits) {} + + //! No default constructor, we need draw item and dirty bits. + CommitState() = delete; + }; + + //! Helper utility function to get number of draw items required for given representation + size_t _GetNumDrawItemsForDesc(const HdMeshReprDesc& reprDesc) + { + // By default, each repr desc item maps to 1 draw item + size_t numDrawItems = 1; + + // Different representations may require different number of draw items + // See HdSt for an example. + switch (reprDesc.geomStyle) { + case HdMeshGeomStyleInvalid: + numDrawItems = 0; + break; + default: + break; + } + + return numDrawItems; + } + + //! Helper utility function to fill primvar data to vertex buffer. + template + void _FillPrimvarData(DEST_TYPE* vertexBuffer, + size_t numVertices, + size_t channelOffset, + bool requiresUnsharedVertices, + const SdfPath& meshId, + const HdMeshTopology& topology, + const TfToken& primvarName, + const VtArray& primvarData, + const HdInterpolation& primvarInterp) + { + switch (primvarInterp) { + case HdInterpolationConstant: + for (size_t v = 0; v < numVertices; v++) { + SRC_TYPE* pointer = reinterpret_cast( + reinterpret_cast(&vertexBuffer[v]) + channelOffset); + *pointer = primvarData[0]; + } + break; + case HdInterpolationVarying: + case HdInterpolationVertex: + if (requiresUnsharedVertices) { + const VtIntArray& faceVertexIndices = topology.GetFaceVertexIndices(); + if (numVertices == faceVertexIndices.size()) { + for (size_t v = 0; v < numVertices; v++) { + SRC_TYPE* pointer = reinterpret_cast( + reinterpret_cast(&vertexBuffer[v]) + channelOffset); + *pointer = primvarData[faceVertexIndices[v]]; + } + } + else { + // numVertices must have been assigned with the number of + // face vertices as required by vertex unsharing. + TF_CODING_ERROR("Invalid Hydra prim '%s': primvar %s " + "requires %zu unshared elements, while the number of " + "face vertices is %zu. Skipping primvar update.", + meshId.GetText(), primvarName.GetText(), + numVertices, faceVertexIndices.size()); + } + } + else if (numVertices <= primvarData.size()) { + // The primvar has more data than needed, we issue a warning but + // don't skip update. Truncate the buffer to the expected length. + if (numVertices < primvarData.size()) { + TF_DEBUG(HDVP2_DEBUG_MESH).Msg("Invalid Hydra prim '%s': " + "primvar %s has %zu elements, while its topology " + "references only upto element index %zu.\n", + meshId.GetText(), primvarName.GetText(), + primvarData.size(), numVertices); + } + + if (channelOffset == 0 && sizeof(DEST_TYPE) == sizeof(SRC_TYPE)) { + memcpy(vertexBuffer, primvarData.cdata(), sizeof(DEST_TYPE) * numVertices); + } + else { + for (size_t v = 0; v < numVertices; v++) { + SRC_TYPE* pointer = reinterpret_cast( + reinterpret_cast(&vertexBuffer[v]) + channelOffset); + *pointer = primvarData[v]; + } + } + } + else { + // The primvar has less data than needed. Issue warning and skip + // update like what is done in HdStMesh. + TF_DEBUG(HDVP2_DEBUG_MESH).Msg("Invalid Hydra prim '%s': " + "primvar %s has only %zu elements, while its topology expects " + "at least %zu elements. Skipping primvar update.\n", + meshId.GetText(), primvarName.GetText(), + primvarData.size(), numVertices); + + memset(vertexBuffer, 0, sizeof(DEST_TYPE) * numVertices); + } + break; + case HdInterpolationUniform: + if (requiresUnsharedVertices) { + const VtIntArray& faceVertexCounts = topology.GetFaceVertexCounts(); + const size_t numFaces = faceVertexCounts.size(); + if (numFaces <= primvarData.size()) { + // The primvar has more data than needed, we issue a warning but + // don't skip update. Truncate the buffer to the expected length. + if (numFaces < primvarData.size()) { + TF_DEBUG(HDVP2_DEBUG_MESH).Msg("Invalid Hydra prim '%s': " + "primvar %s has %zu elements, while its topology " + "references only upto element index %zu.\n", + meshId.GetText(), primvarName.GetText(), + primvarData.size(), numFaces); + } + + for (size_t f = 0, v = 0; f < numFaces; f++) { + const size_t faceVertexCount = faceVertexCounts[f]; + const size_t faceVertexEnd = v + faceVertexCount; + for (; v < faceVertexEnd; v++) { + SRC_TYPE* pointer = reinterpret_cast( + reinterpret_cast(&vertexBuffer[v]) + channelOffset); + *pointer = primvarData[f]; + } + } + } + else { + // The primvar has less data than needed. Issue warning and skip + // update like what is done in HdStMesh. + TF_DEBUG(HDVP2_DEBUG_MESH).Msg("Invalid Hydra prim '%s': " + "primvar %s has only %zu elements, while its topology expects " + "at least %zu elements. Skipping primvar update.\n", + meshId.GetText(), primvarName.GetText(), + primvarData.size(), numFaces); + + memset(vertexBuffer, 0, sizeof(DEST_TYPE) * numVertices); + } + } + else { + TF_CODING_ERROR("Invalid Hydra prim '%s': " + "vertex unsharing is required for uniform primvar %s", + meshId.GetText(), primvarName.GetText()); + } + break; + case HdInterpolationFaceVarying: + if (requiresUnsharedVertices) { + if (numVertices <= primvarData.size()) { + // If the primvar has more data than needed, we issue a warning, + // but don't skip the primvar update. Truncate the buffer to the + // expected length. + if (numVertices < primvarData.size()) { + TF_DEBUG(HDVP2_DEBUG_MESH).Msg("Invalid Hydra prim '%s': " + "primvar %s has %zu elements, while its topology references " + "only upto element index %zu.\n", + meshId.GetText(), primvarName.GetText(), + primvarData.size(), numVertices); + } + + if (channelOffset == 0 && sizeof(DEST_TYPE) == sizeof(SRC_TYPE)) { + memcpy(vertexBuffer, primvarData.cdata(), sizeof(DEST_TYPE) * numVertices); + } + else { + for (size_t v = 0; v < numVertices; v++) { + SRC_TYPE* pointer = reinterpret_cast( + reinterpret_cast(&vertexBuffer[v]) + channelOffset); + *pointer = primvarData[v]; + } + } + } + else { + // It is unexpected to have less data than we index into. Issue + // a warning and skip update. + TF_DEBUG(HDVP2_DEBUG_MESH).Msg("Invalid Hydra prim '%s': " + "primvar %s has only %zu elements, while its topology expects " + "at least %zu elements. Skipping primvar update.\n", + meshId.GetText(), primvarName.GetText(), + primvarData.size(), numVertices); + + memset(vertexBuffer, 0, sizeof(DEST_TYPE) * numVertices); + } + } + else { + TF_CODING_ERROR("Invalid Hydra prim '%s': " + "vertex unsharing is required face-varying primvar %s", + meshId.GetText(), primvarName.GetText()); + } + break; + default: + TF_CODING_ERROR("Invalid Hydra prim '%s': " + "unimplemented interpolation %d for primvar %s", + meshId.GetText(), (int)primvarInterp, primvarName.GetText()); + break; + } + } + + //! Helper utility function to get number of edge indices + unsigned int _GetNumOfEdgeIndices(const HdMeshTopology& topology) + { + const VtIntArray &faceVertexCounts = topology.GetFaceVertexCounts(); + + unsigned int numIndex = 0; + for (int i = 0; i < faceVertexCounts.size(); i++) + { + numIndex += faceVertexCounts[i]; + } + numIndex *= 2; // each edge has two ends. + return numIndex; + } + + //! Helper utility function to extract edge indices + void _FillEdgeIndices(int* indices, const HdMeshTopology& topology) + { + const VtIntArray &faceVertexCounts = topology.GetFaceVertexCounts(); + const int* currentFaceStart = topology.GetFaceVertexIndices().cdata(); + for (int faceId = 0; faceId < faceVertexCounts.size(); faceId++) + { + int numVertexIndicesInFace = faceVertexCounts[faceId]; + if (numVertexIndicesInFace >= 2) + { + for (int faceVertexId = 0; faceVertexId < numVertexIndicesInFace; faceVertexId++) + { + bool isLastVertex = faceVertexId == numVertexIndicesInFace - 1; + *(indices++) = *(currentFaceStart + faceVertexId); + *(indices++) = isLastVertex ? *currentFaceStart : *(currentFaceStart + faceVertexId + 1); + } + } + currentFaceStart += numVertexIndicesInFace; + } + } + + //! Helper utility function to adapt Maya API changes. + void setWantConsolidation(MHWRender::MRenderItem& renderItem, bool state) + { +#if MAYA_API_VERSION >= 20190000 + renderItem.setWantConsolidation(state); +#else + renderItem.setWantSubSceneConsolidation(state); +#endif + } +} //namespace + + +//! \brief Constructor +HdVP2Mesh::HdVP2Mesh(HdVP2RenderDelegate* delegate, const SdfPath& id, const SdfPath& instancerId) + : HdMesh(id, instancerId) + , _delegate(delegate) { + const MHWRender::MVertexBufferDescriptor vbDesc( + "", MHWRender::MGeometry::kPosition, MHWRender::MGeometry::kFloat, 3); + _positionsBuffer.reset(new MHWRender::MVertexBuffer(vbDesc)); +} + +//! \brief Destructor +HdVP2Mesh::~HdVP2Mesh() { +} + +//! \brief Synchronize VP2 state with scene delegate state based on dirty bits and representation +void HdVP2Mesh::Sync( + HdSceneDelegate* delegate, HdRenderParam* renderParam, + HdDirtyBits* dirtyBits, const TfToken& reprToken) { + + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L2, GetId().GetText(), "HdVP2Mesh Sync"); + + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { + _SetMaterialId(delegate->GetRenderIndex().GetChangeTracker(), + delegate->GetMaterialId(GetId())); + } + + _UpdateRepr(delegate, reprToken, dirtyBits); + + auto* const param = static_cast(_delegate->GetRenderParam()); + // HdC_TODO: Currently we are running selection highlighting update in a separate execution + // and this execution will update only wire representation. The next execution will update + // remaining representations, but if we clear dirty bits, nothing will get updated. + // We leave the dirty bits unmodified during selection highlighting to workaround the issue, + // but this is not ideal - we shouldn't have to evaluate the same data twice. + if (!param->GetDrawScene().InSelectionHighlightUpdate()) + *dirtyBits &= ~HdChangeTracker::AllSceneDirtyBits; +} + +/*! \brief Returns the minimal set of dirty bits to place in the + change tracker for use in the first sync of this prim. +*/ +HdDirtyBits HdVP2Mesh::GetInitialDirtyBitsMask() const { + return HdChangeTracker::Clean | HdChangeTracker::InitRepr | + HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyTopology | + HdChangeTracker::DirtyTransform | HdChangeTracker::DirtyMaterialId | + HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyVisibility | HdChangeTracker::DirtyInstanceIndex; +} + +/*! \brief Add additional dirty bits + + This callback from Rprim gives the prim an opportunity to set + additional dirty bits based on those already set. This is done + before the dirty bits are passed to the scene delegate, so can be + used to communicate that extra information is needed by the prim to + process the changes. + + The return value is the new set of dirty bits, which replaces the bits + passed in. + + See HdRprim::PropagateRprimDirtyBits() +*/ +HdDirtyBits HdVP2Mesh::_PropagateDirtyBits(HdDirtyBits bits) const { + // If subdiv tags are dirty, topology needs to be recomputed. + // The latter implies we'll need to recompute all primvar data. + // Any data fetched by the scene delegate should be marked dirty here. + if (bits & HdChangeTracker::DirtySubdivTags) { + bits |= (HdChangeTracker::DirtyPoints | + HdChangeTracker::DirtyNormals | + HdChangeTracker::DirtyPrimvar | + HdChangeTracker::DirtyTopology | + HdChangeTracker::DirtyDisplayStyle); + } + else if (bits & HdChangeTracker::DirtyTopology) { + // Unlike basis curves, we always request refineLevel when topology is + // dirty + bits |= HdChangeTracker::DirtySubdivTags | + HdChangeTracker::DirtyDisplayStyle; + } + + // A change of material means that the Quadrangulate state may have + // changed. + if (bits & HdChangeTracker::DirtyMaterialId) { + bits |= (HdChangeTracker::DirtyPoints | + HdChangeTracker::DirtyNormals | + HdChangeTracker::DirtyPrimvar | + HdChangeTracker::DirtyTopology); + } + + // If points, display style, or topology changed, recompute normals. + if (bits & (HdChangeTracker::DirtyPoints | + HdChangeTracker::DirtyDisplayStyle | + HdChangeTracker::DirtyTopology)) { + bits |= _customDirtyBitsInUse & + (DirtySmoothNormals | DirtyFlatNormals); + } + + // If the topology is dirty, recompute custom indices resources. + if (bits & HdChangeTracker::DirtyTopology) { + bits |= _customDirtyBitsInUse & + (DirtyIndices | + DirtyHullIndices | + DirtyPointsIndices); + } + + // If normals are dirty and we are doing CPU normals + // then the normals computation needs the points primvar + // so mark points as dirty, so that the scene delegate will provide + // the data. + if ((bits & (DirtySmoothNormals | DirtyFlatNormals))/* && + !HdStGLUtils::IsGpuComputeEnabled()*/) { + bits |= HdChangeTracker::DirtyPoints; + } + + // Sometimes we don't get dirty extent notification + if (bits & (HdChangeTracker::DirtyPoints)) { + bits |= HdChangeTracker::DirtyExtent; + } + + return bits; +} + +/*! \brief Initialize the given representation of this Rprim. + + This is called prior to syncing the prim, the first time the repr + is used. + + \param reprToken the name of the repr to initalize. HdRprim has already + resolved the reprName to its final value. + + \param dirtyBits an in/out value. It is initialized to the dirty bits + from the change tracker. InitRepr can then set additional + dirty bits if additional data is required from the scene + delegate when this repr is synced. + + InitRepr occurs before dirty bit propagation. + + See HdRprim::InitRepr() +*/ +void HdVP2Mesh::_InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) { + _ReprVector::iterator it = std::find_if(_reprs.begin(), _reprs.end(), _ReprComparator(reprToken)); + + HdReprSharedPtr repr; + + const bool isNew = (it == _reprs.end()); + if (isNew) { + _reprs.emplace_back(reprToken, boost::make_shared()); + repr = _reprs.back().second; + } + else { + repr = it->second; + } + + auto* const param = static_cast(_delegate->GetRenderParam()); + MSubSceneContainer* subSceneContainer = param->GetContainer(); + if (!subSceneContainer) + return; + + // Selection highlight uses the wire repr for now, hoping it will be able + // to share draw items with future implementation of wireframe mode. If + // it won't, we can then define a customized "selectionHighlight" repr. + if (reprToken == HdReprTokens->wire) { + const bool selected = param->GetDrawScene().IsProxySelected() || + (param->GetDrawScene().GetPrimSelectionState(GetId()) != nullptr); + if (_EnableWireDrawItems(repr, dirtyBits, selected)) + return; + } + else if (!isNew) { + return; + } + + // set dirty bit to say we need to sync a new repr (buffer array + // ranges may change) + *dirtyBits |= HdChangeTracker::NewRepr; + + _MeshReprConfig::DescArray descs = _GetReprDesc(reprToken); + + for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { + const HdMeshReprDesc& desc = descs[descIdx]; + + size_t numDrawItems = _GetNumDrawItemsForDesc(desc); + if (numDrawItems == 0) continue; + + for (size_t itemId = 0; itemId < numDrawItems; itemId++) { + auto* drawItem = new HdVP2DrawItem(_delegate, &_sharedData, desc); + repr->AddDrawItem(drawItem); + + const MString& renderItemName = drawItem->GetRenderItemName(); + + MHWRender::MRenderItem* const renderItem = + _CreateRenderItem(renderItemName, desc); + + _delegate->GetVP2ResourceRegistry().EnqueueCommit( + [subSceneContainer, renderItem]() { + subSceneContainer->add(renderItem); + } + ); + } + + if (desc.geomStyle == HdMeshGeomStyleHull) { + if (desc.flatShadingEnabled) { + if (!(_customDirtyBitsInUse & DirtyFlatNormals)) { + _customDirtyBitsInUse |= DirtyFlatNormals; + *dirtyBits |= DirtyFlatNormals; + } + } + else { + if (!(_customDirtyBitsInUse & DirtySmoothNormals)) { + _customDirtyBitsInUse |= DirtySmoothNormals; + *dirtyBits |= DirtySmoothNormals; + } + } + } + else if (desc.geomStyle == HdMeshGeomStyleHullEdgeOnly) { + *dirtyBits |= HdChangeTracker::DirtyTopology; + } + } +} + +/*! \brief Update the named repr object for this Rprim. + + Repr objects are created to support specific reprName tokens, and contain a list of + HdVP2DrawItems and corresponding RenderItems. +*/ +void HdVP2Mesh::_UpdateRepr(HdSceneDelegate *sceneDelegate, const TfToken& reprToken, HdDirtyBits *dirtyBits) { + + HdReprSharedPtr const &curRepr = _GetRepr(reprToken); + if (!curRepr) { + return; + } + + _MeshReprConfig::DescArray reprDescs = _GetReprDesc(reprToken); + + // Iterate through all reprdescs for the current repr to figure out if any + // of them requires smooth normals or flat normals. If either (or both) + // are required, we will calculate them once and clean the bits. + bool requireSmoothNormals = false; + bool requireFlatNormals = false; + for (size_t descIdx = 0; descIdx < reprDescs.size(); ++descIdx) { + const HdMeshReprDesc &desc = reprDescs[descIdx]; + if (desc.geomStyle == HdMeshGeomStyleHull) { + if (desc.flatShadingEnabled) { + requireFlatNormals = true; + } + else { + requireSmoothNormals = true; + } + } + } + + // For each relevant draw item, update dirty buffer sources. + const HdRepr::DrawItems& items = curRepr->GetDrawItems(); + for (HdDrawItem* item : items) { + if (HdChangeTracker::IsDirty(*dirtyBits)) { + if (auto* drawItem = static_cast(item)) { + const HdMeshReprDesc &desc = drawItem->GetReprDesc(); + _UpdateDrawItem(sceneDelegate, drawItem, dirtyBits, desc, + requireSmoothNormals, requireFlatNormals); + } + } + } +} + +/*! \brief Update the draw item + + This call happens on worker threads and results of the change are collected + in CommitState and enqueued for Commit on main-thread using CommitTasks +*/ +void HdVP2Mesh::_UpdateDrawItem( + HdSceneDelegate* sceneDelegate, + HdVP2DrawItem* drawItem, + HdDirtyBits* dirtyBits, + const HdMeshReprDesc &desc, + bool requireSmoothNormals, + bool requireFlatNormals +) { + auto* const param = static_cast(_delegate->GetRenderParam()); + MSubSceneContainer* subSceneContainer = param->GetContainer(); + if (!subSceneContainer) + return; + + CommitState stateToCommit(*drawItem, *dirtyBits); + HdVP2DrawItem::RenderItemData& drawItemData = stateToCommit._drawItemData; + + static constexpr bool writeOnly = true; + + const SdfPath& id = GetId(); + + const bool topologyDirty = + HdChangeTracker::IsTopologyDirty(*dirtyBits, id); + const bool pointsDirty = + HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->points); + const bool normalsDirty = + HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->normals); + const bool primvarDirty = + HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->primvar); + + if (topologyDirty) { + _topology = GetMeshTopology(sceneDelegate); + } + + if (pointsDirty) { + const VtValue value = sceneDelegate->Get(id, HdTokens->points); + _points = value.Get(); + } + + if (normalsDirty || primvarDirty) { + _UpdatePrimvarSources(sceneDelegate, *dirtyBits); + } + + TfTokenVector matPrimvars; + + const HdRenderIndex& renderIndex = sceneDelegate->GetRenderIndex(); + const HdVP2Material* material = static_cast( + renderIndex.GetSprim(HdPrimTypeTokens->material, GetMaterialId())); + if (material && material->GetSurfaceShader()) { + matPrimvars = material->GetRequiredPrimvars(); + } + else { + matPrimvars.push_back(HdTokens->displayColor); + matPrimvars.push_back(HdTokens->displayOpacity); + matPrimvars.push_back(HdTokens->normals); + } + + // If there is uniform or face-varying primvar, we have to expand shared + // vertices in CPU because OpenGL SSBO technique is not widely supported + // on GPUs and 3D APIs. + bool requiresUnsharedVertices = false; + for (const TfToken& pv : matPrimvars) { + const auto it = _primvarSourceMap.find(pv); + if (it != _primvarSourceMap.end()) { + const HdInterpolation interpolation = it->second.interpolation; + if (interpolation == HdInterpolationUniform || + interpolation == HdInterpolationFaceVarying) { + requiresUnsharedVertices = true; + break; + } + } + } + + const size_t numVertices = requiresUnsharedVertices ? + _topology.GetFaceVertexIndices().size() : _topology.GetNumPoints(); + + // Prepare index buffer. + if (topologyDirty) { + const HdMeshTopology* topologyToUse = &_topology; + HdMeshTopology unsharedTopology; + + if (requiresUnsharedVertices) { + // Fill with sequentially increasing values, starting from 0. The + // new face vertex indices will then be implicitly used to assemble + // all primvar vertex buffers. + VtIntArray newFaceVtxIds; + newFaceVtxIds.resize(_topology.GetFaceVertexIndices().size()); + std::iota(newFaceVtxIds.begin(), newFaceVtxIds.end(), 0); + + unsharedTopology = HdMeshTopology( + _topology.GetScheme(), + _topology.GetOrientation(), + _topology.GetFaceVertexCounts(), + newFaceVtxIds, + _topology.GetHoleIndices(), + _topology.GetRefineLevel() + ); + + topologyToUse = &unsharedTopology; + } + + if (desc.geomStyle == HdMeshGeomStyleHull) { + HdMeshUtil meshUtil(topologyToUse, id); + VtVec3iArray trianglesFaceVertexIndices; + VtIntArray primitiveParam; + meshUtil.ComputeTriangleIndices(&trianglesFaceVertexIndices, &primitiveParam, nullptr); + + const int numIndex = trianglesFaceVertexIndices.size() * 3; + + stateToCommit._indexBufferData = static_cast( + drawItemData._indexBuffer->acquire(numIndex, writeOnly)); + + memcpy(stateToCommit._indexBufferData, trianglesFaceVertexIndices.data(), numIndex * sizeof(int)); + } + else if (desc.geomStyle == HdMeshGeomStyleHullEdgeOnly) { + unsigned int numIndex = _GetNumOfEdgeIndices(*topologyToUse); + + stateToCommit._indexBufferData = static_cast( + drawItemData._indexBuffer->acquire(numIndex, writeOnly)); + + _FillEdgeIndices(stateToCommit._indexBufferData, *topologyToUse); + } + else { + // Index buffer data is not required for point representation. + } + } + + // Prepare position buffer. It is shared among all render items of the rprim + // so it should be updated only once when it gets dirty. + if (pointsDirty) { + void* bufferData = _positionsBuffer->acquire(numVertices, writeOnly); + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, HdTokens->points, _points, HdInterpolationVertex); + + stateToCommit._positionBufferData = static_cast(bufferData); + } + } + + // Prepare normal buffer. + if (drawItemData._normalsBuffer) { + VtVec3fArray normals; + HdInterpolation interp = HdInterpolationConstant; + + const auto it = _primvarSourceMap.find(HdTokens->normals); + if (it != _primvarSourceMap.end()) { + const VtValue& value = it->second.data; + if (ARCH_LIKELY(value.IsHolding())) { + normals = value.UncheckedGet(); + interp = it->second.interpolation; + } + } + + bool prepareNormals = false; + + // If there is authored normals, prepare buffer only when it is dirty. + // otherwise, compute smooth normals from points and adjacency and we + // have a custom dirty bit to determine whether update is needed. + if (!normals.empty()) { + prepareNormals = normalsDirty; + } + else if (requireSmoothNormals && (*dirtyBits & DirtySmoothNormals)) { + // note: normals gets dirty when points are marked as dirty, + // at change tracker. + // clear DirtySmoothNormals (this is not a scene dirtybit) + *dirtyBits &= ~DirtySmoothNormals; + + prepareNormals = true; + + Hd_VertexAdjacencySharedPtr adjacency(new Hd_VertexAdjacency()); + HdBufferSourceSharedPtr adjacencyComputation = + adjacency->GetSharedAdjacencyBuilderComputation(&_topology); + adjacencyComputation->Resolve(); // IS the adjacency updated now? + + // The topology doesn't have to reference all of the points, thus + // we compute the number of normals as required by the topology. + normals = Hd_SmoothNormals::ComputeSmoothNormals( + adjacency.get(), _topology.GetNumPoints(), _points.cdata()); + + interp = HdInterpolationVertex; + } + + if (prepareNormals && !normals.empty()) { + void* bufferData = drawItemData._normalsBuffer->acquire(numVertices, writeOnly); + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, HdTokens->normals, normals, interp); + + stateToCommit._normalsBufferData = static_cast(bufferData); + } + } + } + + // Prepare color buffer. + if (desc.geomStyle == HdMeshGeomStyleHull) { + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { + if (material) { + stateToCommit._surfaceShader = material->GetSurfaceShader(); + if (stateToCommit._surfaceShader && + stateToCommit._surfaceShader->isTransparent()) { + stateToCommit._isTransparent = true; + } + } + } + + TfTokenVector::const_iterator begin = matPrimvars.cbegin(); + TfTokenVector::const_iterator end = matPrimvars.cend(); + + if (primvarDirty && + (std::find(begin, end, HdTokens->displayColor) != end || + std::find(begin, end, HdTokens->displayOpacity) != end)) { + // If color/opacity is not found, the 18% gray color will be used + // to match the default color of Hydra Storm. + VtVec3fArray colorArray(1, GfVec3f(0.18f, 0.18f, 0.18f)); + VtFloatArray alphaArray(1, 1.0f); + + HdInterpolation colorInterp = HdInterpolationConstant; + HdInterpolation alphaInterp = HdInterpolationConstant; + + auto it = _primvarSourceMap.find(HdTokens->displayColor); + if (it != _primvarSourceMap.end()) { + const VtValue& value = it->second.data; + if (value.IsHolding() && value.GetArraySize() > 0) { + colorArray = value.UncheckedGet(); + colorInterp = it->second.interpolation; + } + } + + it = _primvarSourceMap.find(HdTokens->displayOpacity); + if (it != _primvarSourceMap.end()) { + const VtValue& value = it->second.data; + if (value.IsHolding() && value.GetArraySize() > 0) { + alphaArray = value.UncheckedGet(); + alphaInterp = it->second.interpolation; + } + } + + if (colorInterp == HdInterpolationConstant && + alphaInterp == HdInterpolationConstant) { + // Use fallback shader if there is no material binding or we + // failed to create a shader instance from the material. + if (!stateToCommit._surfaceShader) { + const GfVec3f& color = colorArray[0]; + stateToCommit._surfaceShader = _delegate->GetFallbackShader( + MColor(color[0], color[1], color[2], alphaArray[0])); + } + } + else { + if (!drawItemData._colorBuffer) { + const MHWRender::MVertexBufferDescriptor desc("", + MHWRender::MGeometry::kColor, + MHWRender::MGeometry::kFloat, + 4); + + drawItemData._colorBuffer.reset( + new MHWRender::MVertexBuffer(desc)); + } + + void* bufferData = + drawItemData._colorBuffer->acquire(numVertices, writeOnly); + + // Fill color and opacity into the float4 color stream. + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, HdTokens->displayColor, colorArray, colorInterp); + + _FillPrimvarData(static_cast(bufferData), + numVertices, 3, requiresUnsharedVertices, + id, _topology, HdTokens->displayOpacity, alphaArray, alphaInterp); + + stateToCommit._colorBufferData = static_cast(bufferData); + } + + // Use fallback CPV shader if there is no material binding or + // we failed to create a shader instance from the material. + if (!stateToCommit._surfaceShader) { + stateToCommit._surfaceShader = _delegate->GetFallbackCPVShader(); + } + } + + // It is possible that all elements in the opacity array are 1. + // Due to the performance indication about transparency, we have to + // traverse the array and enable transparency only when needed. + if (!stateToCommit._isTransparent) { + if (alphaInterp == HdInterpolationConstant) { + stateToCommit._isTransparent = (alphaArray[0] < 0.999f); + } + else { + for (size_t i = 0; i < alphaArray.size(); i++) { + if (alphaArray[i] < 0.999f) { + stateToCommit._isTransparent = true; + break; + } + } + } + } + } + } + + // Prepare primvar buffers required by the material. + if (material) { + for (const TfToken& pv : matPrimvars) { + // Color, opacity and normal have been prepared separately. + if ((pv == HdTokens->displayColor) || + (pv == HdTokens->displayOpacity) || + (pv == HdTokens->normals)) + continue; + + if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, pv)) + continue; + + const auto it = _primvarSourceMap.find(pv); + if (it == _primvarSourceMap.end()) + continue; + + const VtValue& value = it->second.data; + const HdInterpolation& interp = it->second.interpolation; + + if (!value.IsArrayValued() || value.GetArraySize() == 0) + continue; + + MHWRender::MVertexBuffer* buffer = + drawItemData._primvarBuffers[pv].get(); + + void* bufferData = nullptr; + + if (value.IsHolding()) { + if (!buffer) { + const MHWRender::MVertexBufferDescriptor desc("", + MHWRender::MGeometry::kTexture, + MHWRender::MGeometry::kFloat, 1); + + buffer = new MHWRender::MVertexBuffer(desc); + drawItemData._primvarBuffers[pv].reset(buffer); + } + + if (buffer) { + bufferData = buffer->acquire(numVertices, writeOnly); + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, + pv, value.UncheckedGet(), interp); + } + } + } + else if (value.IsHolding()) { + if (!buffer) { + const MHWRender::MVertexBufferDescriptor desc("", + MHWRender::MGeometry::kTexture, + MHWRender::MGeometry::kFloat, 2); + + buffer = new MHWRender::MVertexBuffer(desc); + drawItemData._primvarBuffers[pv].reset(buffer); + } + + if (buffer) { + bufferData = buffer->acquire(numVertices, writeOnly); + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, + pv, value.UncheckedGet(), interp); + } + } + } + else if (value.IsHolding()) { + if (!buffer) { + const MHWRender::MVertexBufferDescriptor desc("", + MHWRender::MGeometry::kTexture, + MHWRender::MGeometry::kFloat, 3); + + buffer = new MHWRender::MVertexBuffer(desc); + drawItemData._primvarBuffers[pv].reset(buffer); + } + + if (buffer) { + bufferData = buffer->acquire(numVertices, writeOnly); + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, + pv, value.UncheckedGet(), interp); + } + } + } + else if (value.IsHolding()) { + if (!buffer) { + const MHWRender::MVertexBufferDescriptor desc("", + MHWRender::MGeometry::kTexture, + MHWRender::MGeometry::kFloat, 4); + + buffer = new MHWRender::MVertexBuffer(desc); + drawItemData._primvarBuffers[pv].reset(buffer); + } + + if (buffer) { + bufferData = buffer->acquire(numVertices, writeOnly); + if (bufferData) { + _FillPrimvarData(static_cast(bufferData), + numVertices, 0, requiresUnsharedVertices, + id, _topology, + pv, value.UncheckedGet(), interp); + } + } + } + else { + TF_WARN("Unsupported primvar array"); + } + + stateToCommit._primvarBufferDataMap[pv] = static_cast(bufferData); + } + } + + // Bounding box is per-prim shared data. + GfRange3d range; + + if (HdChangeTracker::IsExtentDirty(*dirtyBits, id)) { + range = GetExtent(sceneDelegate); + if (!range.IsEmpty()) { + _sharedData.bounds.SetRange(range); + } + + *dirtyBits &= ~HdChangeTracker::DirtyExtent; + } + else { + range = _sharedData.bounds.GetRange(); + } + + const GfVec3d& min = range.GetMin(); + const GfVec3d& max = range.GetMax(); + const MBoundingBox bounds(MPoint(min[0], min[1], min[2]), MPoint(max[0], max[1], max[2])); + + // World matrix is per-prim shared data. + GfMatrix4d transform; + + if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { + transform = sceneDelegate->GetTransform(id); + _sharedData.bounds.SetMatrix(transform); + + *dirtyBits &= ~HdChangeTracker::DirtyTransform; + } + else { + transform = _sharedData.bounds.GetMatrix(); + } + + MMatrix worldMatrix; + transform.Get(worldMatrix.matrix); + + if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) { + _UpdateVisibility(sceneDelegate, dirtyBits); + } + + // If the mesh is instanced, create one new instance per transform. + // The current instancer invalidation tracking makes it hard for + // us to tell whether transforms will be dirty, so this code + // pulls them every time something changes. + if (!GetInstancerId().IsEmpty()) { + + // Retrieve instance transforms from the instancer. + HdInstancer *instancer = renderIndex.GetInstancer(GetInstancerId()); + VtMatrix4dArray transforms = + static_cast(instancer)-> + ComputeInstanceTransforms(id); + + MMatrix instanceMatrix; + + if ((desc.geomStyle == HdMeshGeomStyleHullEdgeOnly) && + !param->GetDrawScene().IsProxySelected()) { + if (auto state = param->GetDrawScene().GetPrimSelectionState(id)) { + for (const auto& indexArray : state->instanceIndices) { + for (const auto index : indexArray) { + transforms[index].Get(instanceMatrix.matrix); + instanceMatrix = worldMatrix * instanceMatrix; + stateToCommit._instanceTransforms.append(instanceMatrix); + } + } + } + } + else { + for (size_t i = 0; i < transforms.size(); ++i) { + transforms[i].Get(instanceMatrix.matrix); + instanceMatrix = worldMatrix * instanceMatrix; + stateToCommit._instanceTransforms.append(instanceMatrix); + } + } + } + + // Capture class member for lambda + MHWRender::MVertexBuffer* const positionsBuffer = _positionsBuffer.get(); + + _delegate->GetVP2ResourceRegistry().EnqueueCommit( + [drawItem, stateToCommit, param, positionsBuffer, bounds, worldMatrix]() + { + const MString& renderItemName = drawItem->GetRenderItemName(); + + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L2, renderItemName.asChar(), "HdVP2Mesh Commit Buffers"); + + MHWRender::MRenderItem* renderItem = param->GetContainer()->find(renderItemName); + if(!renderItem) { + TF_CODING_ERROR("Invalid render item: %s\n", renderItemName.asChar()); + return; + } + + MHWRender::MVertexBuffer* colorBuffer = stateToCommit._drawItemData._colorBuffer.get(); + MHWRender::MVertexBuffer* normalsBuffer = stateToCommit._drawItemData._normalsBuffer.get(); + MHWRender::MIndexBuffer* indexBuffer = stateToCommit._drawItemData._indexBuffer.get(); + + HdVP2DrawItem::PrimvarBufferMap& primvarBuffers = stateToCommit._drawItemData._primvarBuffers; + + MHWRender::MVertexBufferArray vertexBuffers; + vertexBuffers.addBuffer("positions", positionsBuffer); + + if (colorBuffer) + vertexBuffers.addBuffer("diffuseColor", colorBuffer); + + if (normalsBuffer) + vertexBuffers.addBuffer("normals", normalsBuffer); + + for (auto& entry : primvarBuffers) { + const TfToken& primvarName = entry.first; + MHWRender::MVertexBuffer* primvarBuffer = entry.second.get(); + if (primvarBuffer) { + vertexBuffers.addBuffer(primvarName.GetText(), primvarBuffer); + } + } + + // If available, something changed + if(stateToCommit._positionBufferData) + positionsBuffer->commit(stateToCommit._positionBufferData); + + // If available, something changed + if (stateToCommit._colorBufferData && colorBuffer) + colorBuffer->commit(stateToCommit._colorBufferData); + + // If available, something changed + if (stateToCommit._normalsBufferData && normalsBuffer) + normalsBuffer->commit(stateToCommit._normalsBufferData); + + // If available, something changed + for (const auto& entry : stateToCommit._primvarBufferDataMap) { + const TfToken& primvarName = entry.first; + float* primvarBufferData = entry.second; + + const auto it = primvarBuffers.find(primvarName); + if (it != primvarBuffers.end()) { + MHWRender::MVertexBuffer* primvarBuffer = it->second.get(); + if (primvarBuffer && primvarBufferData) { + primvarBuffer->commit(primvarBufferData); + } + } + } + + // If available, something changed + if (stateToCommit._indexBufferData && indexBuffer) + indexBuffer->commit(stateToCommit._indexBufferData); + + // If available, something changed + if (stateToCommit._surfaceShader != nullptr && + stateToCommit._surfaceShader != renderItem->getShader()) { + renderItem->setShader(stateToCommit._surfaceShader); + renderItem->setTreatAsTransparent(stateToCommit._isTransparent); + } + + if ((stateToCommit._dirtyBits & HdChangeTracker::DirtyVisibility) != 0) { + renderItem->enable(drawItem->IsEnabled() && drawItem->GetVisible()); + } + + ProxyRenderDelegate& drawScene = param->GetDrawScene(); + drawScene.setGeometryForRenderItem(*renderItem, vertexBuffers, *indexBuffer, &bounds); + + // Important, update instance transforms after setting geometry on render items! + auto& oldInstanceCount = stateToCommit._drawItemData._instanceCount; + auto newInstanceCount = stateToCommit._instanceTransforms.length(); + + if (oldInstanceCount > 1) { + // GPU instancing has been enabled. We cannot switch to consolidation + // without recreating render item, so we keep using GPU instancing. + if (oldInstanceCount == newInstanceCount) { + for (unsigned int i = 0; i < newInstanceCount; i++) { + // VP2 defines instance ID of the first instance to be 1. + drawScene.updateInstanceTransform(*renderItem, + i+1, stateToCommit._instanceTransforms[i]); + } + } else { + drawScene.setInstanceTransformArray(*renderItem, + stateToCommit._instanceTransforms); + } + } + else if (newInstanceCount > 1) { + // Turn off consolidation to allow GPU instancing to be used for + // multiple instances. + setWantConsolidation(*renderItem, false); + drawScene.setInstanceTransformArray(*renderItem, + stateToCommit._instanceTransforms); + } + else if (newInstanceCount == 1) { + // Special case for single instance prims. We will keep the original + // render item to allow consolidation. + renderItem->setMatrix(&stateToCommit._instanceTransforms[0]); + } + else { + // Regular non-instanced prims. Consolidation has been turned on by + // default and will be kept enabled on this case. + renderItem->setMatrix(&worldMatrix); + } + + oldInstanceCount = newInstanceCount; + }); +} + +void HdVP2Mesh::_UpdatePrimvarSources( + HdSceneDelegate* sceneDelegate, + HdDirtyBits dirtyBits) +{ + const SdfPath& id = GetId(); + + // Update _primvarSourceMap, our local cache of raw primvar data. + // This function pulls data from the scene delegate, but defers processing. + // + // While iterating primvars, we skip "points" (vertex positions) because + // the points primvar is processed separately for direct access later. We + // only call GetPrimvar on primvars that have been marked dirty. + // + // Currently, hydra doesn't have a good way of communicating changes in + // the set of primvars, so we only ever add and update to the primvar set. + + for (size_t i = 0; i < HdInterpolationCount; i++) { + const HdInterpolation interp = static_cast(i); + const HdPrimvarDescriptorVector primvars = + GetPrimvarDescriptors(sceneDelegate, interp); + + for (const HdPrimvarDescriptor& pv: primvars) { + if (HdChangeTracker::IsPrimvarDirty(dirtyBits, id, pv.name) && + pv.name != HdTokens->points) { + const VtValue value = GetPrimvar(sceneDelegate, pv.name); + _primvarSourceMap[pv.name] = { value, interp }; + } + } + } +} + +/*! \brief Create render item for points repr. +*/ +MHWRender::MRenderItem* HdVP2Mesh::_CreatePointsRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::DecorationItem, + MHWRender::MGeometry::kPoints + ); + + renderItem->setDrawMode(MHWRender::MGeometry::kSelectionOnly); + renderItem->castsShadows(false); + renderItem->receivesShadows(false); + renderItem->setShader(_delegate->Get3dFatPointShader()); + + MSelectionMask selectionMask(MSelectionMask::kSelectPointsForGravity); + selectionMask.addMask(MSelectionMask::kSelectMeshVerts); + renderItem->setSelectionMask(selectionMask); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + +/*! \brief Create render item for wireframe repr. +*/ +MHWRender::MRenderItem* HdVP2Mesh::_CreateWireframeRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::DecorationItem, + MHWRender::MGeometry::kLines + ); + + renderItem->depthPriority(MHWRender::MRenderItem::sActiveWireDepthPriority); + renderItem->castsShadows(false); + renderItem->receivesShadows(false); + renderItem->setShader(_delegate->Get3dSolidShader()); + + renderItem->setSelectionMask(MSelectionMask()); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + +/*! \brief Create render item for smoothHull repr. +*/ +MHWRender::MRenderItem* HdVP2Mesh::_CreateSmoothHullRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::MaterialSceneItem, + MHWRender::MGeometry::kTriangles + ); + + renderItem->setExcludedFromPostEffects(false); + renderItem->castsShadows(true); + renderItem->receivesShadows(true); + renderItem->setShader(_delegate->GetFallbackShader()); + + renderItem->setSelectionMask(MSelectionMask::kSelectMeshes); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + +/*! \brief Create render item for the specified desc. +*/ +MHWRender::MRenderItem* HdVP2Mesh::_CreateRenderItem( + const MString& name, + const HdMeshReprDesc& desc) const +{ + MHWRender::MRenderItem* renderItem = nullptr; + + switch (desc.geomStyle) { + case HdMeshGeomStyleHull: + renderItem = _CreateSmoothHullRenderItem(name); + break; + case HdMeshGeomStyleHullEdgeOnly: + renderItem = _CreateWireframeRenderItem(name); + break; + case HdMeshGeomStylePoints: + renderItem = _CreatePointsRenderItem(name); + break; + default: + TF_WARN("Unexpected geomStyle"); + break; + } + + return renderItem; +} + +/*! \brief Enable or disable the wireframe draw item. + + \return True if no draw items should be created for the repr. +*/ +bool HdVP2Mesh::_EnableWireDrawItems( + const HdReprSharedPtr& repr, + HdDirtyBits* dirtyBits, + bool enable) +{ + if (_wireItemsEnabled == enable) { + return true; + } + + _wireItemsEnabled = enable; + + if (repr) { + const HdRepr::DrawItems& items = repr->GetDrawItems(); + for (HdDrawItem* item : items) { + if (auto drawItem = static_cast(item)) { + const HdMeshReprDesc& reprDesc = drawItem->GetReprDesc(); + if (reprDesc.geomStyle == HdMeshGeomStyleHullEdgeOnly) { + drawItem->Enable(enable); + *dirtyBits |= HdChangeTracker::DirtyVisibility; + return true; + } + } + } + } + + return false; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/mesh.h b/lib/render/vp2RenderDelegate/mesh.h new file mode 100644 index 0000000000..38c34810eb --- /dev/null +++ b/lib/render/vp2RenderDelegate/mesh.h @@ -0,0 +1,114 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_MESH +#define HD_VP2_MESH + +#include "pxr/pxr.h" +#include "pxr/imaging/hd/mesh.h" + +#include "render_delegate.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class HdSceneDelegate; +class HdVP2DrawItem; +struct HdMeshReprDesc; + +/*! \brief VP2 representation of poly-mesh object. + \class HdVP2Mesh + + The prim object's main function is to bridge the scene description and the + renderable representation. The Hydra image generation algorithm will call + HdRenderIndex::SyncAll() before any drawing; this, in turn, will call + Sync() for each mesh with new data. + + Sync() is passed a set of dirtyBits, indicating which scene buffers are + dirty. It uses these to pull all of the new scene data and constructs + updated embree geometry objects. Commit of changed buffers to GPU happens + in HdVP2RenderDelegate::CommitResources(), which runs on main-thread after + all prims have been updated. +*/ +class HdVP2Mesh final : public HdMesh { +public: + HdVP2Mesh(HdVP2RenderDelegate*, const SdfPath&, const SdfPath& instancerId = SdfPath()); + + ~HdVP2Mesh() override; + + void Sync( + HdSceneDelegate*, HdRenderParam*, + HdDirtyBits*, const TfToken& reprToken) override; + + HdDirtyBits GetInitialDirtyBitsMask() const override; + +private: + HdDirtyBits _PropagateDirtyBits(HdDirtyBits) const override; + + void _InitRepr(const TfToken&, HdDirtyBits*) override; + + void _UpdateRepr(HdSceneDelegate*, const TfToken&, HdDirtyBits*); + + void _UpdateDrawItem( + HdSceneDelegate*, HdVP2DrawItem*, HdDirtyBits*, + const HdMeshReprDesc&, bool requireSmoothNormals, bool requireFlatNormals); + + bool _EnableWireDrawItems(const HdReprSharedPtr& repr, HdDirtyBits* dirtyBits, bool enable); + + void _UpdatePrimvarSources(HdSceneDelegate* sceneDelegate, HdDirtyBits dirtyBits); + + MHWRender::MRenderItem* _CreateRenderItem(const MString& name, const HdMeshReprDesc& desc) const; + MHWRender::MRenderItem* _CreateSmoothHullRenderItem(const MString& name) const; + MHWRender::MRenderItem* _CreateWireframeRenderItem(const MString& name) const; + MHWRender::MRenderItem* _CreatePointsRenderItem(const MString& name) const; + + //! Custom dirty bits used by this mesh + enum DirtyBits : HdDirtyBits { + DirtySmoothNormals = HdChangeTracker::CustomBitsBegin, + DirtyFlatNormals = (DirtySmoothNormals << 1), + DirtyIndices = (DirtyFlatNormals << 1), + DirtyHullIndices = (DirtyIndices << 1), + DirtyPointsIndices = (DirtyHullIndices << 1), + DirtyBoundingBox = (DirtyPointsIndices << 1) + }; + + HdVP2RenderDelegate* _delegate{ nullptr }; //!< VP2 render delegate for which this mesh was created + HdDirtyBits _customDirtyBitsInUse{ 0 }; //!< Storage for custom dirty bits. See _PropagateDirtyBits for details. + + // TODO: Define HdVP2MeshSharedData to hold extra shared data specific to VP2? + std::unique_ptr _positionsBuffer; //!< Per-Rprim position buffer to be shared among render items + bool _wireItemsEnabled{ false }; //!< Whether draw items for the wire repr are enabled + + //! Cached scene data. VtArrays are reference counted, so as long as we + //! only call const accessors keeping them around doesn't incur a buffer + //! copy. + HdMeshTopology _topology; + VtVec3fArray _points; + + //! A local cache of primvar scene data. "data" is a copy-on-write handle to + //! the actual primvar buffer, and "interpolation" is the interpolation mode + //! to be used. + struct PrimvarSource { + VtValue data; + HdInterpolation interpolation; + }; + TfHashMap _primvarSourceMap; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp b/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp new file mode 100644 index 0000000000..041cb1a308 --- /dev/null +++ b/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp @@ -0,0 +1,563 @@ +// +// Copyright 2019 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. +// + +#include "proxyRenderDelegate.h" +#include "render_delegate.h" + +#include "pxr/base/tf/diagnostic.h" +#include "pxr/usdImaging/usdImaging/delegate.h" +#include "pxr/imaging/hdx/renderTask.h" +#include "pxr/imaging/hdx/selectionTracker.h" +#include "pxr/imaging/hdx/taskController.h" +#include "pxr/imaging/hd/enums.h" +#include "pxr/imaging/hd/mesh.h" +#include "pxr/imaging/hd/repr.h" +#include "pxr/imaging/hd/rprimCollection.h" + +#include "../../nodes/proxyShapeBase.h" +#include "../../nodes/stageData.h" +#include "../../utils/util.h" + +#include +#include +#include +#include +#include + +#if defined(WANT_UFE_BUILD) +#include "ufe/sceneItem.h" +#include "ufe/runTimeMgr.h" +#include "ufe/globalSelection.h" +#include "ufe/observableSelection.h" +#include "ufe/selectionNotification.h" +#endif + +PXR_NAMESPACE_OPEN_SCOPE + +namespace +{ + MGlobal::ListAdjustment GetListAdjustment() + { + // Keyboard modifiers can be queried from QApplication::keyboardModifiers() + // in case running MEL command leads to performance hit. On the other hand + // the advantage of using MEL command is the platform-agnostic state of the + // CONTROL key that it provides for aligning to Maya's implementation. + int modifiers = 0; + MGlobal::executeCommand("getModifiers", modifiers); + + const bool shiftHeld = (modifiers % 2); + const bool ctrlHeld = (modifiers / 4 % 2); + + MGlobal::ListAdjustment listAdjustment = MGlobal::kReplaceList; + + if (shiftHeld && ctrlHeld) + { + listAdjustment = MGlobal::kAddToList; + } + else if (ctrlHeld) + { + listAdjustment = MGlobal::kRemoveFromList; + } + else if (shiftHeld) + { + listAdjustment = MGlobal::kXORWithList; + } + + return listAdjustment; + } + +#if defined(WANT_UFE_BUILD) + class UfeSelectionObserver : public Ufe::Observer + { + public: + UfeSelectionObserver(ProxyRenderDelegate& proxyRenderDelegate) + : Ufe::Observer() + , _proxyRenderDelegate(proxyRenderDelegate) + { + } + + void operator()(const Ufe::Notification& notification) override + { + // During Maya file read, each node will be selected in turn, so we get + // notified for each node in the scene. Prune this out. + if (MFileIO::isOpeningFile()) { + return; + } + + auto selectionChanged = + dynamic_cast(¬ification); + if (selectionChanged != nullptr) { + _proxyRenderDelegate.SelectionChanged(); + } + } + + private: + ProxyRenderDelegate& _proxyRenderDelegate; + }; +#endif + +} // namespace + +//! \brief Draw classification used during plugin load to register in VP2 +const MString ProxyRenderDelegate::drawDbClassification( + TfStringPrintf("drawdb/subscene/vp2RenderDelegate/%s", + MayaUsdProxyShapeBaseTokens->MayaTypeName.GetText()).c_str()); + +//! \brief Factory method registered at plugin load +MHWRender::MPxSubSceneOverride* ProxyRenderDelegate::Creator(const MObject& obj) { + return new ProxyRenderDelegate(obj); +} + +//! \brief Constructor +ProxyRenderDelegate::ProxyRenderDelegate(const MObject& obj) + : MHWRender::MPxSubSceneOverride(obj) + , _mObject(obj) { +} + +//! \brief Destructor +ProxyRenderDelegate::~ProxyRenderDelegate() { + delete _sceneDelegate; + delete _taskController; + delete _renderIndex; + delete _renderDelegate; +} + +//! \brief This drawing routine supports all devices (DirectX and OpenGL) +MHWRender::DrawAPI ProxyRenderDelegate::supportedDrawAPIs() const { + return MHWRender::kAllDevices; +} + +#if defined(MAYA_ENABLE_UPDATE_FOR_SELECTION) +//! \brief Enable subscene update in selection passes for deferred update of selection render items. +bool ProxyRenderDelegate::enableUpdateForSelection() const { + return true; +} +#endif + +//! \brief Always requires update since changes are tracked by Hydraw change tracker and it will guarantee minimal update +bool ProxyRenderDelegate::requiresUpdate(const MSubSceneContainer& container, const MFrameContext& frameContext) const { + return true; +} + +//! \brief Return pointer to DG proxy shape node +MayaUsdProxyShapeBase* ProxyRenderDelegate::getProxyShape() const { + const MFnDependencyNode depNodeFn(_mObject); + MayaUsdProxyShapeBase* usdSubSceneShape = static_cast(depNodeFn.userNode()); + return usdSubSceneShape; +} + +//! \brief One time initialization of this drawing routine +void ProxyRenderDelegate::_InitRenderDelegate() { + // No need to run all the checks if we got till the end + if (_isInitialized()) + return; + + MStatus status; + MayaUsdProxyShapeBase* usdSubSceneShape = getProxyShape(); + if (!usdSubSceneShape) + return; + + if (!_usdStage) { + _usdStage = usdSubSceneShape->getUsdStage(); + } + + if (!_renderDelegate) { + MProfilingScope subProfilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorD_L1, "Allocate VP2RenderDelegate"); + _renderDelegate = new HdVP2RenderDelegate(*this); + } + + if (!_renderIndex) { + MProfilingScope subProfilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorD_L1, "Allocate RenderIndex"); + _renderIndex = HdRenderIndex::New(_renderDelegate); + } + + if (!_sceneDelegate) { + MProfilingScope subProfilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorD_L1, "Allocate SceneDelegate"); + + SdfPath delegateID = SdfPath::AbsoluteRootPath().AppendChild(TfToken(TfStringPrintf( + "Proxy_%s_%p", usdSubSceneShape->name().asChar(), usdSubSceneShape))); + + _sceneDelegate = new UsdImagingDelegate(_renderIndex, delegateID); + + _taskController = new HdxTaskController(_renderIndex, + delegateID.AppendChild(TfToken(TfStringPrintf("_UsdImaging_VP2_%p", this))) ); + + // Assign a collection of active representations, then each Rprim will + // initialize and update draw data for these active repr(s). If update + // for selection is enabled, the draw data for the "points" repr won't + // be prepared until point snapping is activated; otherwise they have + // to be early prepared for potential activation of point snapping. + _defaultCollection.reset(new HdRprimCollection(HdTokens->geometry, +#if defined(MAYA_ENABLE_UPDATE_FOR_SELECTION) + HdReprSelector(HdReprTokens->smoothHull) +#else + HdReprSelector(HdReprTokens->smoothHull, TfToken(), HdReprTokens->points) +#endif + )); + + _taskController->SetCollection(*_defaultCollection); + + _selectionHighlightCollection.reset(new HdRprimCollection(HdTokens->geometry, + HdReprSelector(HdReprTokens->wire) + )); + + _selection.reset(new HdSelection); + +#if defined(WANT_UFE_BUILD) + if (!_ufeSelectionObserver) { + auto globalSelection = Ufe::GlobalSelection::get(); + if (globalSelection) { + _ufeSelectionObserver = std::make_shared(*this); + globalSelection->addObserver(_ufeSelectionObserver); + } + } +#endif + + // We don't really need any HdTask because VP2RenderDelegate uses Hydra + // engine for data preparation only, but we have to add a dummy render + // task to bootstrap data preparation. + const HdTaskSharedPtrVector tasks = _taskController->GetRenderingTasks(); + for (const HdTaskSharedPtr& task : tasks) { + if (dynamic_cast(task.get())) { + _dummyTasks.push_back(task); + break; + } + } + } +} + +//! \brief Populate render index with prims coming from scene delegate. +//! \return True when delegate is ready to draw +bool ProxyRenderDelegate::_Populate() { + if (!_isInitialized()) + return false; + + auto* proxyShape = getProxyShape(); + if (_usdStage && (!_isPopulated || proxyShape->getExcludePrimPathsVersion() != _excludePrimPathsVersion) ) { + MProfilingScope subProfilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorD_L1, "Populate"); + + // It might have been already populated, clear it if so. + SdfPathVector excludePrimPaths = proxyShape->getExcludePrimPaths(); + for (auto& excludePrim : excludePrimPaths) { + SdfPath indexPath = _sceneDelegate->ConvertCachePathToIndexPath(excludePrim); + if (_renderIndex->HasRprim(indexPath)) { + _renderIndex->RemoveRprim(indexPath); + } + } + + _sceneDelegate->Populate(_usdStage->GetPseudoRoot(),excludePrimPaths); + + _isPopulated = true; + _excludePrimPathsVersion = proxyShape->getExcludePrimPathsVersion(); + } + + return _isPopulated; +} + +//! \brief Synchronize USD scene delegate time with Maya's scene time. +void ProxyRenderDelegate::_UpdateTime() { + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L1, "Update Time"); + + MayaUsdProxyShapeBase* usdSubSceneShape = getProxyShape(); + if(usdSubSceneShape && _sceneDelegate) { + UsdTimeCode timeCode = usdSubSceneShape->getTime(); + _sceneDelegate->SetTime(timeCode); + } +} + +//! \brief Execute Hydra engine which will performe minimal update VP2 state update based on change tracker. +void ProxyRenderDelegate::_Execute(const MHWRender::MFrameContext& frameContext) { + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L1, "Execute"); + +#if defined(MAYA_ENABLE_UPDATE_FOR_SELECTION) + // Since Maya 2020, subscene update can be invoked in a selection pass. + const bool inSelectionPass = (frameContext.getSelectionInfo() != nullptr); + const bool inPointSnapping = pointSnappingActive(); + + // Query selection adjustment mode only if the update is triggered in a selection pass. + _globalListAdjustment = (inSelectionPass && !inPointSnapping) ? GetListAdjustment() : MGlobal::kReplaceList; +#else + // Before Maya 2020, subscene update would never be invoked in a selection pass. + constexpr bool inSelectionPass = false; + constexpr bool inPointSnapping = false; +#endif + + // HdC_TODO: we need to figure out how to use Hydra repr more effectively + // when more reprs are coming. + if (inSelectionPass) { + if (inPointSnapping) { + // Update display reprs at the first frame where point snapping is activated. + if (!_defaultCollection->GetReprSelector().Contains(HdReprTokens->points)) { + const HdReprSelector under(TfToken(), TfToken(), HdReprTokens->points); + const HdReprSelector reprSelector = + _defaultCollection->GetReprSelector().CompositeOver(under); + _defaultCollection->SetReprSelector(reprSelector); + _taskController->SetCollection(*_defaultCollection); + } + } + } + else if (_selectionChanged) { + _selectionChanged = false; + + if (_UpdateSelectionHighlight()) { + // Update display reprs at the first frame where selection highlight is activated. + if (!_defaultCollection->GetReprSelector().Contains(HdReprTokens->wire)) { + const HdReprSelector under(TfToken(), HdReprTokens->wire, TfToken()); + const HdReprSelector reprSelector = + _defaultCollection->GetReprSelector().CompositeOver(under); + _defaultCollection->SetReprSelector(reprSelector); + _taskController->SetCollection(*_defaultCollection); + } + } + } + + _engine.Execute(_renderIndex, &_dummyTasks); +} + +//! \brief Main update entry from subscene override. +void ProxyRenderDelegate::update(MSubSceneContainer& container, const MFrameContext& frameContext) { + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorD_L1, "ProxyRenderDelegate::update"); + + _InitRenderDelegate(); + + // Give access to current time and subscene container to the rest of render delegate world via render param's. + auto* param = reinterpret_cast(_renderDelegate->GetRenderParam()); + param->BeginUpdate(container, _sceneDelegate->GetTime()); + + if (_Populate()) { + _UpdateTime(); + _Execute(frameContext); + } + param->EndUpdate(); +} + +//! \brief Switch to component-level selection for point snapping. +void ProxyRenderDelegate::updateSelectionGranularity( + const MDagPath& path, + MHWRender::MSelectionContext& selectionContext) +{ + if (pointSnappingActive()) + { + selectionContext.setSelectionLevel(MHWRender::MSelectionContext::kComponent); + } +} + +//! \brief UFE-based selection for both instanced and non-instanced cases. +bool ProxyRenderDelegate::getInstancedSelectionPath( + const MHWRender::MRenderItem& renderItem, + const MHWRender::MIntersection& intersection, + MDagPath& dagPath) const +{ +#if defined(WANT_UFE_BUILD) + // When point snapping, only the point position matters, so return false + // to use the DAG path from the default implementation and avoid the UFE + // global selection list to be updated. + if (pointSnappingActive()) + return false; + + auto handler = Ufe::RunTimeMgr::instance().hierarchyHandler(USD_UFE_RUNTIME_ID); + if (handler == nullptr) + return false; + + MayaUsdProxyShapeBase* proxyShape = getProxyShape(); + if (proxyShape == nullptr) + return false; + + // Extract id of the owner Rprim. A SdfPath directly created from the render + // item name could be ill-formed if the render item represents instancing: + // "/TreePatch/Tree_1.proto_leaves_id0/DrawItem_xxxxxxxx". Thus std::string + // is used instead to extract Rprim id. + const std::string renderItemName = renderItem.name().asChar(); + const auto pos = renderItemName.find_last_of(USD_UFE_SEPARATOR); + SdfPath rprimId(renderItemName.substr(0, pos)); + + // If the selection hit comes from an instanced render item, its instance + // transform matrices should have been sorted according to USD instance ID, + // therefore drawInstID is usdInstID plus 1 considering VP2 defines the + // instance ID of the first instance as 1. + const int drawInstID = intersection.instanceID(); + if (drawInstID > 0) { + const int usdInstID = drawInstID - 1; + rprimId = _sceneDelegate->GetPathForInstanceIndex(rprimId, usdInstID, nullptr); + } + + const SdfPath usdPath(_sceneDelegate->ConvertIndexPathToCachePath(rprimId)); + + const Ufe::PathSegment pathSegment(usdPath.GetText(), USD_UFE_RUNTIME_ID, USD_UFE_SEPARATOR); + const Ufe::SceneItem::Ptr& si = handler->createItem(proxyShape->ufePath() + pathSegment); + if (!si) { + TF_WARN("UFE runtime is not updated for the USD stage. Please save scene and reopen."); + return false; + } + + auto globalSelection = Ufe::GlobalSelection::get(); + + // If update for selection is enabled, we can query selection list adjustment + // mode once per selection update to avoid any potential performance hit due + // to MEL command execution. +#if defined(MAYA_ENABLE_UPDATE_FOR_SELECTION) + switch (_globalListAdjustment) +#else + switch (GetListAdjustment()) +#endif + { + case MGlobal::kReplaceList: + // The list has been cleared before viewport selection runs, so we + // can add the new hits directly. UFE selection list is a superset + // of Maya selection list, calling clear()/replaceWith() on UFE + // selection list would clear Maya selection list. + globalSelection->append(si); + break; + case MGlobal::kAddToList: + globalSelection->append(si); + break; + case MGlobal::kRemoveFromList: + globalSelection->remove(si); + break; + case MGlobal::kXORWithList: + if (!globalSelection->remove(si)) + { + globalSelection->append(si); + } + break; + default: + TF_WARN("Unexpected MGlobal::ListAdjustment enum for selection."); + break; + } + + return true; +#else + return false; +#endif +} + +//! \brief Notify of selection change. +void ProxyRenderDelegate::SelectionChanged() +{ + _selectionChanged = true; +} + +//! \brief Filter selection for Rprims under the proxy shape. +void ProxyRenderDelegate::_FilterSelection() +{ +#if defined(WANT_UFE_BUILD) + MayaUsdProxyShapeBase* proxyShape = getProxyShape(); + if (proxyShape == nullptr) { + return; + } + + _selection.reset(new HdSelection); + + const auto proxyPath = proxyShape->ufePath(); + const auto globalSelection = Ufe::GlobalSelection::get(); + + for (const Ufe::SceneItem::Ptr& item : *globalSelection) { + if (item->runTimeId() != USD_UFE_RUNTIME_ID) { + continue; + } + + const Ufe::Path::Segments& segments = item->path().getSegments(); + if ((segments.size() != 2) || (proxyPath != segments[0])) { + continue; + } + + const SdfPath usdPath(segments[1].string()); + const SdfPath idxPath(_sceneDelegate->ConvertCachePathToIndexPath(usdPath)); + + _sceneDelegate->PopulateSelection(HdSelection::HighlightModeSelect, + idxPath, UsdImagingDelegate::ALL_INSTANCES, _selection); + } +#endif +} + +/*! \brief Update for selection highlight + + \return True if selection highlight needs to be shown. +*/ +bool ProxyRenderDelegate::_UpdateSelectionHighlight() +{ + bool retVal = false; + + const bool wasProxySelected = _isProxySelected; + + MDagPath proxyDagPath; + MDagPath::getAPathTo(_mObject, proxyDagPath); + auto status = MHWRender::MGeometryUtilities::displayStatus(proxyDagPath); + _isProxySelected = ((status == MHWRender::kHilite) || (status == MHWRender::kLead)); + + constexpr HdSelection::HighlightMode mode = HdSelection::HighlightModeSelect; + + SdfPathVector rootPaths; + + if (_isProxySelected) { + rootPaths.push_back(SdfPath::AbsoluteRootPath()); + retVal = true; + } + else if (wasProxySelected) { + rootPaths.push_back(SdfPath::AbsoluteRootPath()); + _FilterSelection(); + retVal = !_selection->GetSelectedPrimPaths(mode).empty(); + } + else { + SdfPathVector oldPaths = _selection->GetSelectedPrimPaths(mode); + _FilterSelection(); + SdfPathVector newPaths = _selection->GetSelectedPrimPaths(mode); + + if (!oldPaths.empty() || !newPaths.empty()) { + rootPaths = std::move(oldPaths); + rootPaths.reserve(rootPaths.size() + newPaths.size()); + rootPaths.insert(rootPaths.end(), newPaths.begin(), newPaths.end()); + } + + retVal = !newPaths.empty(); + } + + if (!rootPaths.empty()) { + _inSelectionHighlightUpdate = true; + + _selectionHighlightCollection->SetRootPaths(rootPaths); + _taskController->SetCollection(*_selectionHighlightCollection); + _engine.Execute(_renderIndex, &_dummyTasks); + _taskController->SetCollection(*_defaultCollection); + + _inSelectionHighlightUpdate = false; + } + + return retVal; +} + +//! \brief Query whether the proxy is selected. +bool ProxyRenderDelegate::IsProxySelected() const +{ + return _isProxySelected; +} + +//! \brief Query the selection state of a given prim. +const HdSelection::PrimSelectionState* +ProxyRenderDelegate::GetPrimSelectionState(const SdfPath& path) const +{ + return (_selection == nullptr) ? nullptr : + _selection->GetPrimSelectionState(HdSelection::HighlightModeSelect, path); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/proxyRenderDelegate.h b/lib/render/vp2RenderDelegate/proxyRenderDelegate.h new file mode 100644 index 0000000000..3ed998cf8b --- /dev/null +++ b/lib/render/vp2RenderDelegate/proxyRenderDelegate.h @@ -0,0 +1,181 @@ +// +// Copyright 2019 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. +// + +#ifndef PROXY_RENDER_DELEGATE +#define PROXY_RENDER_DELEGATE + +#include "pxr/pxr.h" + +#include "pxr/imaging/hd/engine.h" +#include "pxr/imaging/hd/selection.h" +#include "pxr/imaging/hd/task.h" +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/prim.h" + +#include "../../base/api.h" + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(WANT_UFE_BUILD) +#include "ufe/observer.h" +#endif + +// Conditional compilation due to Maya API gap. +#if MAYA_API_VERSION >= 20200000 +#define MAYA_ENABLE_UPDATE_FOR_SELECTION +#endif + +PXR_NAMESPACE_OPEN_SCOPE + +class HdRenderDelegate; +class HdRenderIndex; +class HdRprimCollection; +class UsdImagingDelegate; +class MayaUsdProxyShapeBase; +class HdxTaskController; + +/*! \brief USD Proxy rendering routine via VP2 MPxSubSceneOverride + + This drawing routine leverages HdVP2RenderDelegate for synchronization + of data between scene delegate and VP2. Final rendering is done by VP2 + as part of subscene override mechanism. + + USD Proxy can be rendered in a number of ways, to enable this drawing + path set VP2_RENDER_DELEGATE_PROXY env variable before loading USD + plugin. +*/ +class ProxyRenderDelegate : public MHWRender::MPxSubSceneOverride +{ + ProxyRenderDelegate(const MObject& obj); + +public: + MAYAUSD_CORE_PUBLIC + ~ProxyRenderDelegate() override; + + MAYAUSD_CORE_PUBLIC + static const MString drawDbClassification; + + MAYAUSD_CORE_PUBLIC + static MHWRender::MPxSubSceneOverride* Creator(const MObject& obj); + + MAYAUSD_CORE_PUBLIC + MHWRender::DrawAPI supportedDrawAPIs() const override; + +#if defined(MAYA_ENABLE_UPDATE_FOR_SELECTION) + MAYAUSD_CORE_PUBLIC + bool enableUpdateForSelection() const override; +#endif + + MAYAUSD_CORE_PUBLIC + bool requiresUpdate(const MSubSceneContainer& container, const MFrameContext& frameContext) const override; + + MAYAUSD_CORE_PUBLIC + void update(MSubSceneContainer& container, const MFrameContext& frameContext) override; + + MAYAUSD_CORE_PUBLIC + void updateSelectionGranularity( + const MDagPath& path, + MSelectionContext& selectionContext) override; + + MAYAUSD_CORE_PUBLIC + bool getInstancedSelectionPath( + const MRenderItem& renderItem, + const MIntersection& intersection, + MDagPath& dagPath) const override; + + MAYAUSD_CORE_PUBLIC + MayaUsdProxyShapeBase* getProxyShape() const; + + MAYAUSD_CORE_PUBLIC + void SelectionChanged(); + + MAYAUSD_CORE_PUBLIC + bool IsProxySelected() const; + + MAYAUSD_CORE_PUBLIC + bool InSelectionHighlightUpdate() const { return _inSelectionHighlightUpdate; } + + MAYAUSD_CORE_PUBLIC + const HdSelection::PrimSelectionState* GetPrimSelectionState(const SdfPath& path) const; + +private: + ProxyRenderDelegate(const ProxyRenderDelegate&) = delete; + ProxyRenderDelegate& operator=(const ProxyRenderDelegate&) = delete; + + void _InitRenderDelegate(); + bool _Populate(); + void _UpdateTime(); + void _Execute(const MHWRender::MFrameContext& frameContext); + + bool _isInitialized(); + + void _FilterSelection(); + bool _UpdateSelectionHighlight(); + + MObject _mObject; //!< Proxy shape MObject + + // USD & Hydra Objects + HdEngine _engine; //!< Hydra engine responsible for running synchronization between scene delegate and VP2RenderDelegate + HdTaskSharedPtrVector _dummyTasks; //!< Dummy task to bootstrap data preparation inside Hydra engine + UsdStageRefPtr _usdStage; //!< USD stage pointer + HdRenderDelegate* _renderDelegate{ nullptr }; //!< VP2RenderDelegate + HdRenderIndex* _renderIndex{ nullptr }; //!< Flattened representation of client scene graph + HdxTaskController* _taskController{ nullptr }; //!< Task controller necessary for execution with hydra engine (we don't really need it, but there doesn't seem to be a way to get synchronization running without it) + UsdImagingDelegate* _sceneDelegate{ nullptr }; //!< USD scene delegate + + size_t _excludePrimPathsVersion{ 0 }; //!< Last version of exluded prims used during render index populate + + bool _isPopulated{ false }; //!< If false, scene delegate wasn't populated yet within render index + bool _selectionChanged{ false }; //!< Whether there is any selection change or not + bool _isProxySelected{ false }; //!< Whether the proxy shape is selected + bool _inSelectionHighlightUpdate{ false };//!< Set to true when selection highlight update is executing + + //! A collection of Rprims to prepare render data for specified reprs + std::unique_ptr _defaultCollection; + + //! A collection of Rprims to update selection highlight + std::unique_ptr _selectionHighlightCollection; + + //! A collection of Rprims being selected + HdSelectionSharedPtr _selection; + +#if defined(WANT_UFE_BUILD) + //! Observer for UFE global selection change + Ufe::Observer::Ptr _ufeSelectionObserver; +#endif + +#if defined(MAYA_ENABLE_UPDATE_FOR_SELECTION) + //! Adjustment mode for global selection list: ADD, REMOVE, REPLACE, XOR + MGlobal::ListAdjustment _globalListAdjustment; +#endif +}; + +/*! \brief Is this object properly initialized and can start receiving updates. Once this is done, render index needs to be populated and then we rely on change tracker. +*/ +inline bool ProxyRenderDelegate::_isInitialized() { + return (_sceneDelegate != nullptr); +} + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/render_delegate.cpp b/lib/render/vp2RenderDelegate/render_delegate.cpp new file mode 100644 index 0000000000..a31be5ac88 --- /dev/null +++ b/lib/render/vp2RenderDelegate/render_delegate.cpp @@ -0,0 +1,661 @@ +// +// Copyright 2019 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. +// + +#include "render_delegate.h" + +#include "material.h" +#include "mesh.h" + +#include "render_pass.h" +#include "instancer.h" + +#include "pxr/imaging/hd/bprim.h" +#include "pxr/imaging/hd/camera.h" +#include "pxr/imaging/hd/instancer.h" +#include "pxr/imaging/hd/resourceRegistry.h" +#include "pxr/imaging/hd/rprim.h" +#include "pxr/imaging/hd/tokens.h" + +#include + +#include + +#include "tbb/spin_rw_mutex.h" +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +namespace +{ + /*! \brief List of supported Rprims by VP2 render delegate + */ + inline const TfTokenVector& _SupportedRprimTypes() { + static const TfTokenVector r{ HdPrimTypeTokens->mesh }; + return r; + } + + /*! \brief List of supported Sprims by VP2 render delegate + */ + inline const TfTokenVector& _SupportedSprimTypes() { + static const TfTokenVector r{ + HdPrimTypeTokens->material, HdPrimTypeTokens->camera }; + return r; + } + + /*! \brief List of supported Bprims by VP2 render delegate + */ + inline const TfTokenVector& _SupportedBprimTypes() { + static const TfTokenVector r{ HdPrimTypeTokens->texture }; + return r; + } + + const MString _diffuseColorParameterName = "diffuseColor"; //!< Shader parameter name + const MString _solidColorParameterName = "solidColor"; //!< Shader parameter name + const MString _pointSizeParameterName = "pointSize"; //!< Shader parameter name + const MString _fallbackShaderName = "FallbackShader"; //!< Name of the fallback shader + const MString _structOutputName = "outSurfaceFinal"; //!< Output struct name of the fallback shader + + /*! \brief Color hash helper class, used by shader registry + */ + struct MColorHash + { + std::size_t operator()(const MColor& color) const + { + std::size_t seed = 0; + boost::hash_combine(seed, color.r); + boost::hash_combine(seed, color.g); + boost::hash_combine(seed, color.b); + boost::hash_combine(seed, color.a); + return seed; + } + }; + + /*! \brief Color-indexed shader map. + */ + using MShaderMap = std::unordered_map< + MColor, + MHWRender::MShaderInstance*, + MColorHash + >; + + /*! \brief Shader cache. + */ + class MShaderCache final + { + public: + /*! \brief Initialize shaders. + */ + void Initialize() + { + if (_isInitialized) + return; + + MHWRender::MRenderer* renderer = MHWRender::MRenderer::theRenderer(); + const MHWRender::MShaderManager* shaderMgr = + renderer ? renderer->getShaderManager() : nullptr; + if (!TF_VERIFY(shaderMgr)) + return; + + _fallbackCPVShader = shaderMgr->getFragmentShader( + "FallbackCPVShader", _structOutputName, true); + + TF_VERIFY(_fallbackCPVShader); + + _3dSolidShader = shaderMgr->getStockShader( + MHWRender::MShaderManager::k3dSolidShader); + + if (TF_VERIFY(_3dSolidShader)) { + constexpr float color[] = { 0.056f, 1.0f, 0.366f, 1.0f }; + _3dSolidShader->setParameter(_solidColorParameterName, color); + } + + _3dFatPointShader = shaderMgr->getStockShader( + MHWRender::MShaderManager::k3dFatPointShader); + + if (TF_VERIFY(_3dFatPointShader)) { + constexpr float white[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + constexpr float size[] = { 5.0, 5.0 }; + + _3dFatPointShader->setParameter(_solidColorParameterName, white); + _3dFatPointShader->setParameter(_pointSizeParameterName, size); + } + + _isInitialized = true; + } + + /*! \brief Returns a fallback CPV shader instance when no material is bound. + */ + MHWRender::MShaderInstance* GetFallbackCPVShader() const { + return _fallbackCPVShader; + } + + /*! \brief Returns a 3d green shader that can be used for selection highlight. + */ + MHWRender::MShaderInstance* Get3dSolidShader() const { + return _3dSolidShader; + } + + /*! \brief Returns a white 3d fat point shader. + */ + MHWRender::MShaderInstance* Get3dFatPointShader() const { + return _3dFatPointShader; + } + + /*! \brief Returns a fallback shader instance when no material is bound. + + This method is keeping registry of all fallback shaders generated, + allowing only one instance per color which enables consolidation of + draw calls with same shader instance. + + \param color Color to set on given shader instance + + \return A new or existing copy of shader instance with given color + */ + MHWRender::MShaderInstance* GetFallbackShader(const MColor& color) + { + // Look for it first with reader lock + { + tbb::reader_writer_lock::scoped_lock_read lockToRead(_fallbackShaderMutex); + + auto it = _fallbackShaders.find(color); + if (it != _fallbackShaders.end()) { + return it->second; + } + } + + MHWRender::MRenderer* renderer = MHWRender::MRenderer::theRenderer(); + const MHWRender::MShaderManager* shaderMgr = + renderer ? renderer->getShaderManager() : nullptr; + if (!TF_VERIFY(shaderMgr)) + return nullptr; + + MHWRender::MShaderInstance* shader = shaderMgr->getFragmentShader( + _fallbackShaderName, _structOutputName, true); + + if (TF_VERIFY(shader)) { + float diffuseColor[] = { color.r, color.g, color.b, color.a }; + shader->setParameter(_diffuseColorParameterName, diffuseColor); + + tbb::reader_writer_lock::scoped_lock lockToWrite(_fallbackShaderMutex); + + // Double check that it wasn't inserted by another thread + auto it = _fallbackShaders.find(color); + if (it != _fallbackShaders.end()) { + return it->second; + } + + // Insert instance we just created + _fallbackShaders[color] = shader; + } + + return shader; + } + + private: + bool _isInitialized { false }; //!< Whether the shader cache is initialized + + tbb::reader_writer_lock _fallbackShaderMutex; //!< Synchronization used to protect concurrent read from serial writes + MShaderMap _fallbackShaders; //!< Shader registry used by fallback shaders + + MHWRender::MShaderInstance* _fallbackCPVShader { nullptr }; //!< Fallback shader with CPV support + MHWRender::MShaderInstance* _3dSolidShader { nullptr }; //!< 3d shader for solid color + MHWRender::MShaderInstance* _3dFatPointShader { nullptr }; //!< 3d shader for points + }; + + MShaderCache sShaderCache; //!< Global shader cache to minimize the number of unique shaders. + + /*! \brief Sampler state desc hash helper class, used by sampler state cache. + */ + struct MSamplerStateDescHash + { + std::size_t operator()(const MHWRender::MSamplerStateDesc& desc) const + { + std::size_t seed = 0; + boost::hash_combine(seed, desc.filter); + boost::hash_combine(seed, desc.comparisonFn); + boost::hash_combine(seed, desc.addressU); + boost::hash_combine(seed, desc.addressV); + boost::hash_combine(seed, desc.addressW); + boost::hash_combine(seed, desc.borderColor[0]); + boost::hash_combine(seed, desc.borderColor[1]); + boost::hash_combine(seed, desc.borderColor[2]); + boost::hash_combine(seed, desc.borderColor[3]); + boost::hash_combine(seed, desc.mipLODBias); + boost::hash_combine(seed, desc.minLOD); + boost::hash_combine(seed, desc.maxLOD); + boost::hash_combine(seed, desc.maxAnisotropy); + boost::hash_combine(seed, desc.coordCount); + boost::hash_combine(seed, desc.elementIndex); + return seed; + } + }; + + /*! Sampler state desc equality helper class, used by sampler state cache. + */ + struct MSamplerStateDescEquality + { + bool operator() ( + const MHWRender::MSamplerStateDesc& a, + const MHWRender::MSamplerStateDesc& b) const + { + return ( + a.filter == b.filter && + a.comparisonFn == b.comparisonFn && + a.addressU == b.addressU && + a.addressV == b.addressV && + a.addressW == b.addressW && + a.borderColor[0] == b.borderColor[0] && + a.borderColor[1] == b.borderColor[1] && + a.borderColor[2] == b.borderColor[2] && + a.borderColor[3] == b.borderColor[3] && + a.mipLODBias == b.mipLODBias && + a.minLOD == b.minLOD && + a.maxLOD == b.maxLOD && + a.maxAnisotropy == b.maxAnisotropy && + a.coordCount == b.coordCount && + a.elementIndex == b.elementIndex + ); + } + }; + + using MSamplerStateCache = std::unordered_map< + MHWRender::MSamplerStateDesc, + const MHWRender::MSamplerState*, + MSamplerStateDescHash, + MSamplerStateDescEquality + >; + + MSamplerStateCache sSamplerStates; //!< Sampler state cache + tbb::spin_rw_mutex sSamplerRWMutex; //!< Synchronization used to protect concurrent read from serial writes + +} // namespace + +const int HdVP2RenderDelegate::sProfilerCategory = MProfiler::addCategory( +#if MAYA_API_VERSION >= 20190000 + "HdVP2RenderDelegate", "HdVP2RenderDelegate" +#else + "HdVP2RenderDelegate" +#endif +); + +std::mutex HdVP2RenderDelegate::_mutexResourceRegistry; +std::atomic_int HdVP2RenderDelegate::_counterResourceRegistry; +HdResourceRegistrySharedPtr HdVP2RenderDelegate::_resourceRegistry; + +/*! \brief Constructor. +*/ +HdVP2RenderDelegate::HdVP2RenderDelegate(ProxyRenderDelegate& drawScene) { + _id = SdfPath(TfToken(TfStringPrintf("/HdVP2RenderDelegate_%p", this))); + + std::lock_guard guard(_mutexResourceRegistry); + if (_counterResourceRegistry.fetch_add(1) == 0) { + _resourceRegistry.reset(new HdResourceRegistry()); + } + + _renderParam.reset(new HdVP2RenderParam(drawScene)); + + // The shader cache should be initialized after mayaUsd loads shader fragments. + sShaderCache.Initialize(); +} + +/*! \brief Destructor. +*/ +HdVP2RenderDelegate::~HdVP2RenderDelegate() { + std::lock_guard guard(_mutexResourceRegistry); + + if (_counterResourceRegistry.fetch_sub(1) == 1) { + _resourceRegistry.reset(); + } +} + +/*! \brief Return delegate's HdVP2RenderParam, giving access to things like MPxSubSceneOverride. +*/ +HdRenderParam* HdVP2RenderDelegate::GetRenderParam() const { + return _renderParam.get(); +} + +/*! \brief Notification to commit resources to GPU & compute before rendering + + This notification sent by HdEngine happens after parallel synchronization of data, + prim's via VP2 resource registry are inserting work to commit. Now is the time + on main thread to commit resources and compute missing streams. + + In future we will better leverage evaluation time to perform synchronization + of data and allow main-thread task execution during the compute as it's done + for the rest of VP2 synchronization with DG data. +*/ +void HdVP2RenderDelegate::CommitResources(HdChangeTracker* tracker) { + TF_UNUSED(tracker); + + MProfilingScope profilingScope(sProfilerCategory, MProfiler::kColorC_L2, "Commit resources"); + + // --------------------------------------------------------------------- // + // RESOLVE, COMPUTE & COMMIT PHASE + // --------------------------------------------------------------------- // + // All the required input data is now resident in memory, next we must: + // + // 1) Execute compute as needed for normals, tessellation, etc. + // 2) Commit resources to the GPU. + // 3) Update any scene-level acceleration structures. + + _resourceRegistryVP2.Commit(); +} + +/*! \brief Return a list of which Rprim types can be created by this class's. +*/ +const TfTokenVector& HdVP2RenderDelegate::GetSupportedRprimTypes() const { + return _SupportedRprimTypes(); +} + +/*! \brief Return a list of which Sprim types can be created by this class's. +*/ +const TfTokenVector& HdVP2RenderDelegate::GetSupportedSprimTypes() const { + return _SupportedSprimTypes(); +} + +/*! \brief Return a list of which Bprim types can be created by this class's. +*/ +const TfTokenVector& HdVP2RenderDelegate::GetSupportedBprimTypes() const { + return _SupportedBprimTypes(); +} + +/*! \brief Return unused global resource registry. +*/ +HdResourceRegistrySharedPtr HdVP2RenderDelegate::GetResourceRegistry() const { + return _resourceRegistry; +} + +/*! \brief Return VP2 resource registry, holding access to commit execution enqueue. +*/ +HdVP2ResourceRegistry& HdVP2RenderDelegate::GetVP2ResourceRegistry() { + return _resourceRegistryVP2; +} + +/*! \brief Create a renderpass for rendering a given collection. +*/ +HdRenderPassSharedPtr HdVP2RenderDelegate::CreateRenderPass(HdRenderIndex* index, const HdRprimCollection& collection) { + return HdRenderPassSharedPtr(new HdVP2RenderPass(this, index, collection)); +} + +/*! \brief Request to create a new VP2 instancer. + + \param id The unique identifier of this instancer. + \param instancerId The unique identifier for the parent instancer that + uses this instancer as a prototype (may be empty). + + \return A pointer to the new instancer or nullptr on error. +*/ +HdInstancer* HdVP2RenderDelegate::CreateInstancer( + HdSceneDelegate* delegate, const SdfPath& id, const SdfPath& instancerId) { + + return new HdVP2Instancer(delegate, id, instancerId); +} + +/*! \brief Destroy instancer instance +*/ +void HdVP2RenderDelegate::DestroyInstancer(HdInstancer* instancer) { + delete instancer; +} + +/*! \brief Request to Allocate and Construct a new, VP2 specialized Rprim. + + \param typeId the type identifier of the prim to allocate + \param rprimId a unique identifier for the prim + \param instancerId the unique identifier for the instancer that uses + the prim (optional: May be empty). + + \return A pointer to the new prim or nullptr on error. +*/ +HdRprim* HdVP2RenderDelegate::CreateRprim( + const TfToken& typeId, const SdfPath& rprimId, const SdfPath& instancerId) { + if (typeId == HdPrimTypeTokens->mesh) { + return new HdVP2Mesh(this, rprimId, instancerId); + } + //if (typeId == HdPrimTypeTokens->volume) { + // return new HdVP2Volume(this, rprimId, instancerId); + //} + TF_CODING_ERROR("Unknown Rprim Type %s", typeId.GetText()); + return nullptr; +} + +/*! \brief Destroy & deallocate Rprim instance +*/ +void HdVP2RenderDelegate::DestroyRprim(HdRprim* rPrim) { + delete rPrim; +} + +/*! \brief Request to Allocate and Construct a new, VP2 specialized Sprim. + + \param typeId the type identifier of the prim to allocate + \param sprimId a unique identifier for the prim + + \return A pointer to the new prim or nullptr on error. +*/ +HdSprim* HdVP2RenderDelegate::CreateSprim( + const TfToken& typeId, const SdfPath& sprimId) { + if (typeId == HdPrimTypeTokens->material) { + return new HdVP2Material(this, sprimId); + } + if (typeId == HdPrimTypeTokens->camera) { + return new HdCamera(sprimId); + } + /* + if (typeId == HdPrimTypeTokens->sphereLight) { + return HdVP2Light::CreatePointLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->distantLight) { + return HdVP2Light::CreateDistantLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->diskLight) { + return HdVP2Light::CreateDiskLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->rectLight) { + return HdVP2Light::CreateRectLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->cylinderLight) { + return HdVP2Light::CreateCylinderLight(this, sprimId); + } + if (typeId == HdPrimTypeTokens->domeLight) { + return HdVP2Light::CreateDomeLight(this, sprimId); + } + */ + TF_CODING_ERROR("Unknown Sprim Type %s", typeId.GetText()); + return nullptr; +} + +/*! \brief Request to Allocate and Construct an Sprim to use as a standin, if there + if an error with another another Sprim of the same type.For example, + if another prim references a non - exisiting Sprim, the fallback could + be used. + + \param typeId the type identifier of the prim to allocate + + \return A pointer to the new prim or nullptr on error. +*/ +HdSprim* HdVP2RenderDelegate::CreateFallbackSprim(const TfToken& typeId) { + if (typeId == HdPrimTypeTokens->material) { + return new HdVP2Material(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->camera) { + return new HdCamera(SdfPath::EmptyPath()); + } + /* + if (typeId == HdPrimTypeTokens->sphereLight) { + return HdVP2Light::CreatePointLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->distantLight) { + return HdVP2Light::CreateDistantLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->diskLight) { + return HdVP2Light::CreateDiskLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->rectLight) { + return HdVP2Light::CreateRectLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->cylinderLight) { + return HdVP2Light::CreateCylinderLight(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->domeLight) { + return HdVP2Light::CreateDomeLight(this, SdfPath::EmptyPath()); + } + */ + TF_CODING_ERROR("Unknown Sprim Type %s", typeId.GetText()); + return nullptr; +} + +/*! \brief Destroy & deallocate Sprim instance +*/ +void HdVP2RenderDelegate::DestroySprim(HdSprim* sPrim) { + delete sPrim; +} + +/*! \brief Request to Allocate and Construct a new, VP2 specialized Bprim. + + \param typeId the type identifier of the prim to allocate + \param sprimId a unique identifier for the prim + + \return A pointer to the new prim or nullptr on error. +*/ +HdBprim* HdVP2RenderDelegate::CreateBprim( + const TfToken& typeId, const SdfPath& bprimId) { + /* + if (typeId == HdPrimTypeTokens->texture) { + return new HdVP2Texture(this, bprimId); + } + if (typeId == HdPrimTypeTokens->renderBuffer) { + return new HdVP2RenderBuffer(bprimId); + } + if (typeId == _tokens->openvdbAsset) { + return new HdVP2OpenvdbAsset(this, bprimId); + } + TF_CODING_ERROR("Unknown Bprim Type %s", typeId.GetText()); + */ + return nullptr; +} + +/*! \brief Request to Allocate and Construct a Bprim to use as a standin, if there + if an error with another another Bprim of the same type. For example, + if another prim references a non-exisiting Bprim, the fallback could + be used. + + \param typeId the type identifier of the prim to allocate + + \return A pointer to the new prim or nullptr on error. +*/ +HdBprim* HdVP2RenderDelegate::CreateFallbackBprim(const TfToken& typeId) { + /* + if (typeId == HdPrimTypeTokens->texture) { + return new HdVP2Texture(this, SdfPath::EmptyPath()); + } + if (typeId == HdPrimTypeTokens->renderBuffer) { + return new HdVP2RenderBuffer(SdfPath::EmptyPath()); + } + if (typeId == _tokens->openvdbAsset) { + return new HdVP2OpenvdbAsset(this, SdfPath::EmptyPath()); + } + TF_CODING_ERROR("Unknown Bprim Type %s", typeId.GetText()); + */ + return nullptr; +} + +/*! \brief Destroy & deallocate Bprim instance +*/ +void HdVP2RenderDelegate::DestroyBprim(HdBprim* bPrim) { + delete bPrim; +} + +/*! \brief Returns a token that indicates material bindings purpose. + + The full material purpose is suggested according to + https://github.com/PixarAnimationStudios/USD/pull/853 +*/ +TfToken HdVP2RenderDelegate::GetMaterialBindingPurpose() const { + return HdTokens->full; +} + +/*! \brief Returns a node name made as a child of delegate's id. +*/ +MString HdVP2RenderDelegate::GetLocalNodeName(const MString& name) const { + return MString(_id.AppendChild(TfToken(name.asChar())).GetText()); +} + +/*! \brief Returns a fallback shader instance when no material is bound. + + This method is keeping registry of all fallback shaders generated, allowing only + one instance per color which enables consolidation of render calls with same shader + instance. + + \param color Color to set on given shader instance + + \return A new or existing copy of shader instance with given color parameter set +*/ +MHWRender::MShaderInstance* HdVP2RenderDelegate::GetFallbackShader(MColor color) const +{ + return sShaderCache.GetFallbackShader(color); +} + +/*! \brief Returns a fallback CPV shader instance when no material is bound. +*/ +MHWRender::MShaderInstance* HdVP2RenderDelegate::GetFallbackCPVShader() const +{ + return sShaderCache.GetFallbackCPVShader(); +} + +/*! \brief Returns a 3d green shader that can be used for selection highlight. +*/ +MHWRender::MShaderInstance* HdVP2RenderDelegate::Get3dSolidShader() const +{ + return sShaderCache.Get3dSolidShader(); +} + +/*! \brief Returns a white 3d fat point shader. +*/ +MHWRender::MShaderInstance* HdVP2RenderDelegate::Get3dFatPointShader() const +{ + return sShaderCache.Get3dFatPointShader(); +} + +/*! \brief Returns a sampler state as specified by the description. +*/ +const MHWRender::MSamplerState* HdVP2RenderDelegate::GetSamplerState( + const MHWRender::MSamplerStateDesc& desc) const +{ + // Look for it first with reader lock + tbb::spin_rw_mutex::scoped_lock lock(sSamplerRWMutex, false/*write*/); + + auto it = sSamplerStates.find(desc); + if (it != sSamplerStates.end()) { + return it->second; + } + + // Upgrade to writer lock. + lock.upgrade_to_writer(); + + // Double check that it wasn't inserted by another thread + it = sSamplerStates.find(desc); + if (it != sSamplerStates.end()) { + return it->second; + } + + // Create and cache. + const MHWRender::MSamplerState* samplerState = + MHWRender::MStateManager::acquireSamplerState(desc); + sSamplerStates[desc] = samplerState; + return samplerState; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/render_delegate.h b/lib/render/vp2RenderDelegate/render_delegate.h new file mode 100644 index 0000000000..73479518cf --- /dev/null +++ b/lib/render/vp2RenderDelegate/render_delegate.h @@ -0,0 +1,133 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_RENDER_DELEGATE +#define HD_VP2_RENDER_DELEGATE + +#include "pxr/pxr.h" +#include "pxr/imaging/hd/renderDelegate.h" +#include "pxr/imaging/hd/resourceRegistry.h" + +#include "render_param.h" +#include "resource_registry.h" + +#include +#include + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class ProxyRenderDelegate; + +/*! \brief VP2 render delegate + \class HdVP2RenderDelegate + + Render delegates provide renderer-specific functionality to the render + index, the main hydra state management structure. The render index uses + the render delegate to create and delete scene primitives, which include + geometry and also non-drawable objects. + + Primitives in Hydra are split into Rprims (drawables), Sprims (state + objects like cameras and materials), and Bprims (buffer objects like + textures). The minimum set of primitives a renderer needs to support is + one Rprim (so the scene's not empty) and the "camera" Sprim, which is + required by HdxRenderTask, the task implementing basic hydra drawing. + + VP2 render delegate reports which prim types it supports via + GetSupportedRprimTypes() (and Sprim, Bprim). + + VP2 Rprims create MRenderItem geometry objects in the MPxSubSceneOverride. + Render delegate renderpasses are not utilized, since subscene is only + a subset of what's being draw in the viewport and overall control is left + to the application. + + The render delegate also has a hook for the main hydra execution algorithm + (HdEngine::Execute()): between HdRenderIndex::SyncAll(), which pulls new + scene data, and execution of tasks, the engine calls back to + CommitResources(). This commit is perfoming execution which must happen + on the main-thread. In the future we will further split engine execution, + levering evaluation time to do HdRenderIndex::SyncAll together with + parallel DG computation and perform commit from reserved thread + via main-thread tasks. +*/ +class HdVP2RenderDelegate final : public HdRenderDelegate { +public: + HdVP2RenderDelegate(ProxyRenderDelegate& proxyDraw); + + ~HdVP2RenderDelegate() override; + + HdRenderParam* GetRenderParam() const override; + + const TfTokenVector& GetSupportedRprimTypes() const override; + + const TfTokenVector& GetSupportedSprimTypes() const override; + + const TfTokenVector& GetSupportedBprimTypes() const override; + + HdResourceRegistrySharedPtr GetResourceRegistry() const override; + + HdVP2ResourceRegistry& GetVP2ResourceRegistry(); + + HdRenderPassSharedPtr CreateRenderPass(HdRenderIndex* index, HdRprimCollection const& collection) override; + + HdInstancer* CreateInstancer(HdSceneDelegate* delegate, SdfPath const& id, SdfPath const& instancerId) override; + void DestroyInstancer(HdInstancer* instancer) override; + + HdRprim* CreateRprim(TfToken const& typeId, SdfPath const& rprimId, SdfPath const& instancerId) override; + void DestroyRprim(HdRprim* rPrim) override; + + HdSprim* CreateSprim(TfToken const& typeId, SdfPath const& sprimId) override; + HdSprim* CreateFallbackSprim(TfToken const& typeId) override; + void DestroySprim(HdSprim* sPrim) override; + + HdBprim* CreateBprim(TfToken const& typeId, SdfPath const& bprimId) override; + HdBprim* CreateFallbackBprim(TfToken const& typeId) override; + void DestroyBprim(HdBprim* bPrim) override; + + void CommitResources(HdChangeTracker* tracker) override; + + TfToken GetMaterialBindingPurpose() const override; + + MString GetLocalNodeName(const MString& name) const; + + MHWRender::MShaderInstance* GetFallbackShader(MColor color=MColor(0.18f,0.18f,0.18f,1.0f)) const; + MHWRender::MShaderInstance* GetFallbackCPVShader() const; + MHWRender::MShaderInstance* Get3dSolidShader() const; + MHWRender::MShaderInstance* Get3dFatPointShader() const; + + const MHWRender::MSamplerState* GetSamplerState( + const MHWRender::MSamplerStateDesc& desc) const; + + static const int sProfilerCategory; //!< Profiler category + +private: + HdVP2RenderDelegate(const HdVP2RenderDelegate&) = delete; + HdVP2RenderDelegate& operator=(const HdVP2RenderDelegate&) = delete; + + static std::mutex _mutexResourceRegistry; //!< Mutex protecting construction/destruction of resource registry + static std::atomic_int _counterResourceRegistry; //!< Number of render delegates sharing this resource registry. Last one deletes the instance. + static HdResourceRegistrySharedPtr _resourceRegistry; //!< Shared and unused by VP2 resource registry + + std::unique_ptr _renderParam; //!< Render param used to provided access to VP2 during prim synchronization + SdfPath _id; //!< Render delegate IDs + HdVP2ResourceRegistry _resourceRegistryVP2; //!< VP2 resource registry used for enqueue and execution of commits +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/render_param.cpp b/lib/render/vp2RenderDelegate/render_param.cpp new file mode 100644 index 0000000000..3aa1f99ded --- /dev/null +++ b/lib/render/vp2RenderDelegate/render_param.cpp @@ -0,0 +1,36 @@ +// +// Copyright 2019 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. +// + +#include "render_param.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief Begin update before rendering of VP2 starts. +*/ +void HdVP2RenderParam::BeginUpdate(MSubSceneContainer& container, UsdTimeCode frame) { + _container = &container; + _frame = frame; +} + +/*! \brief End update & clear access to render item container which pass this point won't be valid. +*/ +void HdVP2RenderParam::EndUpdate() { + _container = nullptr; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/render_param.h b/lib/render/vp2RenderDelegate/render_param.h new file mode 100644 index 0000000000..47cc8413c7 --- /dev/null +++ b/lib/render/vp2RenderDelegate/render_param.h @@ -0,0 +1,69 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_RENDER_PARAM +#define HD_VP2_RENDER_PARAM + +#include "pxr/pxr.h" + +#include "pxr/imaging/hd/renderDelegate.h" +#include "pxr/usd/usd/timeCode.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class ProxyRenderDelegate; + +/*! \brief The HdRenderParam is an opaque(to core Hydra) handle, passed to each prim + during Sync processing and providing access to VP2. + \class HdVP2RenderParam +*/ +class HdVP2RenderParam final : public HdRenderParam { +public: + /*! \brief Constructor + */ + HdVP2RenderParam(ProxyRenderDelegate& drawScene) + : _drawScene(drawScene) {} + + /*! \brief Destructor + */ + ~HdVP2RenderParam() override = default; + + void BeginUpdate(MSubSceneContainer& container, UsdTimeCode frame); + void EndUpdate(); + + /*! \brief Get access to subscene override used to draw the scene + */ + ProxyRenderDelegate& GetDrawScene() const { return _drawScene; } + + /*! \brief Get access to render item container - only valid during draw update + */ + MSubSceneContainer* GetContainer() const { return _container; } + + /*! \brief Refreshed during each update, provides info about currently refreshed frame + */ + UsdTimeCode GetFrame() const { return _frame; } + +protected: + ProxyRenderDelegate& _drawScene; //!< Subscene override used as integration interface for HdVP2RenderDelegate + MSubSceneContainer* _container{ nullptr }; //!< Container to all render items, only valid between begin and end update of subscene override. + UsdTimeCode _frame{ UsdTimeCode::Default() }; //!< Rendered frame (useful for caching of data) +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/lib/render/vp2RenderDelegate/render_pass.h b/lib/render/vp2RenderDelegate/render_pass.h new file mode 100644 index 0000000000..4bd5d2b044 --- /dev/null +++ b/lib/render/vp2RenderDelegate/render_pass.h @@ -0,0 +1,51 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_RENDER_PASS +#define HD_VP2_RENDER_PASS + +#include "pxr/pxr.h" +#include "pxr/imaging/hd/renderPass.h" + +PXR_NAMESPACE_OPEN_SCOPE + +class HdVP2RenderDelegate; + +/*! \brief Empty render pass class. Unused for rendering with VP2 but required by HdEngine & HdRenderDelegate. + \class HdVP2RenderPass +*/ +class HdVP2RenderPass final : public HdRenderPass +{ +public: + //! \brief Constructor + HdVP2RenderPass(HdVP2RenderDelegate* delegate, HdRenderIndex *index, HdRprimCollection const &collection) + : HdRenderPass(index, collection), _delegate(delegate) + {} + + //! \brief Destructor + virtual ~HdVP2RenderPass() {} + + //! \brief Empty execute + void _Execute(HdRenderPassStateSharedPtr const &renderPassState, TfTokenVector const &renderTags) override {} + +private: + HdVP2RenderDelegate* _delegate{ nullptr }; // !< VP2 render delegate for which this render pass was created + +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif \ No newline at end of file diff --git a/lib/render/vp2RenderDelegate/resource_registry.h b/lib/render/vp2RenderDelegate/resource_registry.h new file mode 100644 index 0000000000..afc52e59aa --- /dev/null +++ b/lib/render/vp2RenderDelegate/resource_registry.h @@ -0,0 +1,59 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_RESOURCE_REGISTRY +#define HD_VP2_RESOURCE_REGISTRY + +#include "task_commit.h" + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief Central place to manage GPU resources commits and any resources not managed by VP2 directly + \class HdVP2ResourceRegistry +*/ +class HdVP2ResourceRegistry +{ +public: + //! \brief Default constructor + HdVP2ResourceRegistry() = default; + //! \brief Default destructor + ~HdVP2ResourceRegistry() = default; + + //! \brief Execute commit tasks (called by render delegate) + void Commit() { + HdVP2TaskCommit* commitTask; + while (_commitTasks.try_pop(commitTask)) { + (*commitTask)(); + commitTask->destroy(); + } + } + + //! \brief Enqueue commit task. Call is thread safe. + template + void EnqueueCommit(Body taskBody) { + _commitTasks.push(HdVP2TaskCommitBody::construct(taskBody)); + } +private: + //! Concurrent queue for commit tasks + tbb::concurrent_queue> _commitTasks; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif \ No newline at end of file diff --git a/lib/render/vp2RenderDelegate/sampler.cpp b/lib/render/vp2RenderDelegate/sampler.cpp new file mode 100644 index 0000000000..a9e5d60475 --- /dev/null +++ b/lib/render/vp2RenderDelegate/sampler.cpp @@ -0,0 +1,149 @@ +// +// Copyright 2017 Pixar +// +// 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. +// +// Modifications copyright (C) 2019 Autodesk +// +#include "sampler.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief The constructor takes a reference to a buffer source. The data is + owned externally; + + The caller is responsible for ensuring the buffer is alive while Sample() is being called. + + \param buffer The buffer being sampled. +*/ +HdVP2BufferSampler::HdVP2BufferSampler(HdVtBufferSource const& buffer) + : _buffer(buffer) {} + +/*! \brief Sample the buffer at given element index + + Sample the buffer at element index \p index, and write the sample to + \p value.Interpret \p value as having arity \p numComponents, each of + type \p componentType.These parameters may not match the datatype + declaration of the underlying buffer, in which case Sample returns + false.Sample also returns false if \p index is out of bounds. + + For example, to sample data as GfVec3, \p dataType would be + HdTupleType{ HdTypeFloatVec3, 1 }. + + \param index The element index to sample. + \param value The memory to write the value to(only written on success). + \param dataType The HdTupleType describing element values. + + \return True if the value was successfully sampled. +*/ +bool HdVP2BufferSampler::Sample(int index, void* value, + HdTupleType dataType) const +{ + // Sanity checks: index is within the bounds of buffer, + // and the sample type and buffer type (defined by the dataType) + // are the same. + if (_buffer.GetNumElements() <= (size_t)index || + _buffer.GetTupleType() != dataType) { + return false; + } + + // Calculate the element's byte offset in the array. + size_t elemSize = HdDataSizeOfTupleType(dataType); + size_t offset = elemSize * index; + + // Equivalent to: + // *static_cast(value) = + // static_cast(_buffer.GetData())[index]; + memcpy(value, + static_cast(_buffer.GetData()) + offset, elemSize); + + return true; +} + +template +static void +_InterpolateImpl(void* out, void** samples, float* weights, + size_t sampleCount, short numComponents) { + // This is an implementation of a general blend of samples: + // out = sum_j { sample[j] * weights[j] }. + // Since the vector length comes in as a parameter, and not part + // of the type, the blend is implemented per component. + for (short i = 0; i < numComponents; ++i) { + static_cast(out)[i] = 0; + for (size_t j = 0; j < sampleCount; ++j) { + static_cast(out)[i] += + static_cast(samples[j])[i] * weights[j]; + } + } +} + +/*! \brief Utility function for derived classes: combine multiple samples with + blend weights: \p out = sum_i { \p samples[i] * \p weights[i] }. + + \param out The memory to write the output to (only written on success). + \param samples The array of sample pointers (length \p sampleCount). + \param weights The array of sample weights (length \p sampleCount). + \param sampleCount The number of samples to combine. + \param dataType The HdTupleType describing element values. + + \return True if the samples were successfully combined. +*/ +bool HdVP2PrimvarSampler::_Interpolate(void* out, void** samples, float* weights, + size_t sampleCount, HdTupleType dataType) { + // Combine maps from component type tag to C++ type, and delegates to + // the templated _InterpolateImpl. + + // Combine number of components in the underlying type and tuple arity. + short numComponents = HdGetComponentCount(dataType.type) * dataType.count; + + HdType componentType = HdGetComponentType(dataType.type); + + switch(componentType) { + case HdTypeBool: + /* This function isn't meaningful on boolean types. */ + return false; + case HdTypeInt8: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + case HdTypeInt16: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + return true; + case HdTypeUInt16: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + return true; + case HdTypeInt32: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + return true; + case HdTypeUInt32: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + return true; + case HdTypeFloat: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + return true; + case HdTypeDouble: + _InterpolateImpl(out, samples, weights, sampleCount, + numComponents); + return true; + default: + TF_CODING_ERROR("Unsupported type '%s' passed to _Interpolate", + TfEnum::GetName(componentType).c_str()); + return false; + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/sampler.h b/lib/render/vp2RenderDelegate/sampler.h new file mode 100644 index 0000000000..342a1e2737 --- /dev/null +++ b/lib/render/vp2RenderDelegate/sampler.h @@ -0,0 +1,160 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +// Modifications copyright (C) 2019 Autodesk +// +#ifndef HD_VP2_SAMPLER_H +#define HD_VP2_SAMPLER_H + +#include "pxr/pxr.h" +#include + +#include "pxr/imaging/glf/glew.h" + +#include "pxr/imaging/hd/enums.h" +#include "pxr/imaging/hd/vtBufferSource.h" + +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" +#include "pxr/base/gf/vec2d.h" +#include "pxr/base/gf/vec2f.h" +#include "pxr/base/gf/vec2i.h" +#include "pxr/base/gf/vec3d.h" +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/vec3i.h" +#include "pxr/base/gf/vec4d.h" +#include "pxr/base/gf/vec4f.h" +#include "pxr/base/gf/vec4i.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief A utility class that helps map between C++ types and Hd type tags. + \class HdVP2TypeHelper +*/ +class HdVP2TypeHelper { +public: + //! Define a type that can hold one sample of any primvar. + using PrimvarTypeContainer = char[sizeof(GfMatrix4d)]; + + /*! \brief Return the HdTupleType corresponding to the given C++ type. + */ + template + static HdTupleType GetTupleType(); +}; + +// Define template specializations of HdVP2TypeHelper methods for +// all our supported types... +#define TYPE_HELPER(T,type)\ +template<> inline HdTupleType \ +HdVP2TypeHelper::GetTupleType() { return HdTupleType{type, 1}; } + + TYPE_HELPER(bool, HdTypeBool) + TYPE_HELPER(char, HdTypeInt8) + TYPE_HELPER(short, HdTypeInt16) + TYPE_HELPER(unsigned short, HdTypeUInt16) + TYPE_HELPER(int, HdTypeInt32) + TYPE_HELPER(GfVec2i, HdTypeInt32Vec2) + TYPE_HELPER(GfVec3i, HdTypeInt32Vec3) + TYPE_HELPER(GfVec4i, HdTypeInt32Vec4) + TYPE_HELPER(unsigned int, HdTypeUInt32) + TYPE_HELPER(float, HdTypeFloat) + TYPE_HELPER(GfVec2f, HdTypeFloatVec2) + TYPE_HELPER(GfVec3f, HdTypeFloatVec3) + TYPE_HELPER(GfVec4f, HdTypeFloatVec4) + TYPE_HELPER(double, HdTypeDouble) + TYPE_HELPER(GfVec2d, HdTypeDoubleVec2) + TYPE_HELPER(GfVec3d, HdTypeDoubleVec3) + TYPE_HELPER(GfVec4d, HdTypeDoubleVec4) + TYPE_HELPER(GfMatrix4f, HdTypeFloatMat4) + TYPE_HELPER(GfMatrix4d, HdTypeDoubleMat4) +#undef TYPE_HELPER + + +/*! \brief A utility class that knows how to sample an element from a type-tagged + buffer (like HdVtBufferSource). + \class HdVP2BufferSampler + + This class provides templated accessors to let the caller directly get the + final sample type; it also does bounds checks and type checks. +*/ +class HdVP2BufferSampler { +public: + HdVP2BufferSampler(HdVtBufferSource const& buffer); + + bool Sample(int index, void* value, HdTupleType dataType) const; + + // Convenient, templated frontend for Sample(). + template bool Sample(int index, T* value) const { + return Sample(index, static_cast(value), + HdVP2TypeHelper::GetTupleType()); + } + +private: + HdVtBufferSource const& _buffer; //!< Buffer source to sample +}; + +/*! \brief An abstract base class that knows how to sample a primvar. + \class HdVP2PrimvarSampler + + An abstract base class that knows how to sample a primvar signal given + a ray hit coordinate: an tuple. It provides templated + accessors, but derived classes are responsible for implementing appropriate + sampling or interpolation modes. +*/ +class HdVP2PrimvarSampler { +public: + //! Default constructor. + HdVP2PrimvarSampler() = default; + //! Default destructor. + virtual ~HdVP2PrimvarSampler() = default; + + /*! \brief Sample the primvar at element index and local basis coordinates. + + Sample the primvar at element index \p index and local basis coordinates + \p u and \p v, writing the sample to \p value. Interpret \p value as + having arity \p numComponents, each of type \p componentType. These + parameters may not match the datatype declaration of the underlying + buffer. + + Derived classes are responsible for implementing sampling logic for + their particular interpolation modes. Sample returns true if a value + was successfully retrieved. + + \param element The element index to sample. + \param u The u coordinate to sample. + \param v The v coordinate to sample. + \param value The memory to write the value to (only written on success). + \param dataType The HdTupleType describing element values. + + \return True if the value was successfully sampled. + */ + virtual bool Sample(unsigned int element, float u, float v, void* value, + HdTupleType dataType) const = 0; + + //! Convenient, templated frontend for Sample(). + template bool Sample(unsigned int element, float u, float v, + T* value) const { + return Sample(element, u, v, static_cast(value), + HdVP2TypeHelper::GetTupleType()); + } + +protected: + static bool _Interpolate(void* out, void** samples, float* weights, + size_t sampleCount, HdTupleType dataType); +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // HD_VP2_SAMPLER_H diff --git a/lib/render/vp2RenderDelegate/task_commit.h b/lib/render/vp2RenderDelegate/task_commit.h new file mode 100644 index 0000000000..88d8a5310e --- /dev/null +++ b/lib/render/vp2RenderDelegate/task_commit.h @@ -0,0 +1,80 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_TASK_COMMIT +#define HD_VP2_TASK_COMMIT + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief Base commit task class + \class HdVP2TaskCommit +*/ +class HdVP2TaskCommit +{ +public: + virtual ~HdVP2TaskCommit() = default; + + //! Execute the task + virtual void operator()() = 0; + + //! Destroy & deallocated this task + virtual void destroy() = 0; +}; + +/*! \brief Wrapper of a task body into commit task. + \class HdVP2TaskCommit +*/ +template +class HdVP2TaskCommitBody final : public HdVP2TaskCommit { + //! Use scalable allocator to prevent heap contention + using my_allocator_type = tbb::tbb_allocator>; + + //! Private constructor to force usage of construct method & allocation with + //! scalable allocator. + HdVP2TaskCommitBody(const Body& body) : fBody(body) {} + +public: + ~HdVP2TaskCommitBody() override = default; + + //! Execute body task. + void operator()() override { + fBody(); + } + + //! Objects of this type are allocated with tbb_allocator. + //! Release the memory using same allocator by calling destroy method. + void destroy() override { + my_allocator_type().destroy(this); + my_allocator_type().deallocate(this, 1); + } + + /*! Allocate a new object of type Body using scalable allocator. + Always free this object by calling destroy method! + */ + static HdVP2TaskCommitBody* construct(const Body& body) { + void* mem = my_allocator_type().allocate(1); + return new (mem) HdVP2TaskCommitBody(body); + } + +private: + Body fBody; //!< Function object providing execution "body" for this task +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif \ No newline at end of file diff --git a/lib/render/vp2ShaderFragments/FallbackCPVShader.xml b/lib/render/vp2ShaderFragments/FallbackCPVShader.xml new file mode 100644 index 0000000000..6c3e59b467 --- /dev/null +++ b/lib/render/vp2ShaderFragments/FallbackCPVShader.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/FallbackShader.xml b/lib/render/vp2ShaderFragments/FallbackShader.xml new file mode 100644 index 0000000000..c3173cd742 --- /dev/null +++ b/lib/render/vp2ShaderFragments/FallbackShader.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/Float4ToFloat3.xml b/lib/render/vp2ShaderFragments/Float4ToFloat3.xml new file mode 100644 index 0000000000..c839a11c00 --- /dev/null +++ b/lib/render/vp2ShaderFragments/Float4ToFloat3.xml @@ -0,0 +1,47 @@ + + + Extracts the XYZ component of a 4D float vector. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/render/vp2ShaderFragments/Float4ToFloat4.xml b/lib/render/vp2ShaderFragments/Float4ToFloat4.xml new file mode 100644 index 0000000000..7279f9caa9 --- /dev/null +++ b/lib/render/vp2ShaderFragments/Float4ToFloat4.xml @@ -0,0 +1,47 @@ + + + Passthrough of a 4D float vector. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/Float4ToFloatW.xml b/lib/render/vp2ShaderFragments/Float4ToFloatW.xml new file mode 100644 index 0000000000..22a2a2307e --- /dev/null +++ b/lib/render/vp2ShaderFragments/Float4ToFloatW.xml @@ -0,0 +1,47 @@ + + + Extracts the W component of a 4D float vector. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/Float4ToFloatX.xml b/lib/render/vp2ShaderFragments/Float4ToFloatX.xml new file mode 100644 index 0000000000..2ad55df63e --- /dev/null +++ b/lib/render/vp2ShaderFragments/Float4ToFloatX.xml @@ -0,0 +1,47 @@ + + + Extracts the X component of a 4D float vector. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/Float4ToFloatY.xml b/lib/render/vp2ShaderFragments/Float4ToFloatY.xml new file mode 100644 index 0000000000..d9895ff573 --- /dev/null +++ b/lib/render/vp2ShaderFragments/Float4ToFloatY.xml @@ -0,0 +1,47 @@ + + + Extracts the Y component of a 4D float vector. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/Float4ToFloatZ.xml b/lib/render/vp2ShaderFragments/Float4ToFloatZ.xml new file mode 100644 index 0000000000..eff719b783 --- /dev/null +++ b/lib/render/vp2ShaderFragments/Float4ToFloatZ.xml @@ -0,0 +1,47 @@ + + + Extracts the Z component of a 4D float vector. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml b/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml new file mode 100644 index 0000000000..68c6b2f228 --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPrimvarReader_float.xml b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float.xml new file mode 100644 index 0000000000..59ce5474ef --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPrimvarReader_float2.xml b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float2.xml new file mode 100644 index 0000000000..55a404c58b --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float2.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPrimvarReader_float3.xml b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float3.xml new file mode 100644 index 0000000000..5d19d53735 --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float3.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPrimvarReader_float4.xml b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float4.xml new file mode 100644 index 0000000000..55ba06bc35 --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPrimvarReader_float4.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdUVTexture.xml b/lib/render/vp2ShaderFragments/UsdUVTexture.xml new file mode 100644 index 0000000000..9c1f43e472 --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdUVTexture.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + breakPnt) ? float4(1., 1., 1., 1.) : float4(0., 0., 0., 0.)); + float4 linSeg = outColor * slope; + float4 powSeg = pow( max( float4(0., 0., 0., 0.), scale * outColor + offset), gamma); + outColor = isAboveBreak * powSeg + ( float4(1., 1., 1., 1.) - isAboveBreak ) * linSeg; + } + return outColor * scale + bias; +} + ]]> + + + + + + breakPnt) ? float4(1., 1., 1., 1.) : float4(0., 0., 0., 0.)); + float4 linSeg = outColor * slope; + float4 powSeg = pow( max( float4(0., 0., 0., 0.), scale * outColor + offset), gamma); + outColor = isAboveBreak * powSeg + ( float4(1., 1., 1., 1.) - isAboveBreak ) * linSeg; + } + return outColor * scale + bias; +} + ]]> + + + + diff --git a/lib/render/vp2ShaderFragments/lightingContributions.xml b/lib/render/vp2ShaderFragments/lightingContributions.xml new file mode 100644 index 0000000000..6ce6eb6247 --- /dev/null +++ b/lib/render/vp2ShaderFragments/lightingContributions.xml @@ -0,0 +1,109 @@ + + + + Structure to hold computed diffuse and specular lighting contributions for a light. + + + + + + + + + + + + + + + = 110) +#define float3 vec3 +#endif + +// line 101 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +struct LightingContributions +{ + float3 diffuse; + float3 specular; +}; + + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +// line 101 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +struct LightingContributions +{ + float3 diffuse; + float3 specular; +}; + + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +// line 101 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +struct LightingContributions +{ + float3 diffuse; + float3 specular; +}; + + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +// line 101 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +struct LightingContributions +{ + float3 diffuse; + float3 specular; +}; + + +]]> + + + + \ No newline at end of file diff --git a/lib/render/vp2ShaderFragments/opacityToTransparency.xml b/lib/render/vp2ShaderFragments/opacityToTransparency.xml new file mode 100644 index 0000000000..dd01a39c85 --- /dev/null +++ b/lib/render/vp2ShaderFragments/opacityToTransparency.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/plugInfo.json b/lib/render/vp2ShaderFragments/plugInfo.json new file mode 100644 index 0000000000..e1889662d0 --- /dev/null +++ b/lib/render/vp2ShaderFragments/plugInfo.json @@ -0,0 +1,12 @@ +{ + "Plugins": [ + { + "Name": "mayaUsd_ShaderFragments", + "Info": {}, + "LibraryPath": "../../usd/mayaUsd_ShaderFragments", + "ResourcePath": "../../usd/mayaUsd_ShaderFragments/resources", + "Root": "..", + "Type": "library" + } + ] +} diff --git a/lib/render/vp2ShaderFragments/scaledDiffusePassThrough.xml b/lib/render/vp2ShaderFragments/scaledDiffusePassThrough.xml new file mode 100644 index 0000000000..4c53656225 --- /dev/null +++ b/lib/render/vp2ShaderFragments/scaledDiffusePassThrough.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/scaledSpecularPassThrough.xml b/lib/render/vp2ShaderFragments/scaledSpecularPassThrough.xml new file mode 100644 index 0000000000..6fb0f086cb --- /dev/null +++ b/lib/render/vp2ShaderFragments/scaledSpecularPassThrough.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/shaderFragments.cpp b/lib/render/vp2ShaderFragments/shaderFragments.cpp new file mode 100644 index 0000000000..1c70e14f0b --- /dev/null +++ b/lib/render/vp2ShaderFragments/shaderFragments.cpp @@ -0,0 +1,232 @@ +// +// Copyright 2019 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. +// + +#include "shaderFragments.h" + +#include "pxr/base/plug/plugin.h" +#include "pxr/base/plug/thisPlugin.h" +#include "pxr/base/tf/stringUtils.h" + +#include "pxr/usdImaging/usdImaging/tokens.h" + +#include +#include +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS( + _tokens, + + (FallbackCPVShader) + (FallbackShader) + + (Float4ToFloatX) + (Float4ToFloatY) + (Float4ToFloatZ) + (Float4ToFloatW) + (Float4ToFloat3) + (Float4ToFloat4) + + (lightingContributions) + (scaledDiffusePassThrough) + (scaledSpecularPassThrough) + (opacityToTransparency) + (usdPreviewSurfaceLighting) + (usdPreviewSurfaceCombiner) + + (UsdUVTexture) + + (UsdPrimvarReader_float) + (UsdPrimvarReader_float2) + (UsdPrimvarReader_float3) + (UsdPrimvarReader_float4) + + (UsdPreviewSurface) +); + +static const TfTokenVector _FragmentNames = { + _tokens->UsdUVTexture, + + _tokens->UsdPrimvarReader_float, + _tokens->UsdPrimvarReader_float2, + _tokens->UsdPrimvarReader_float3, + _tokens->UsdPrimvarReader_float4, + + _tokens->Float4ToFloatX, + _tokens->Float4ToFloatY, + _tokens->Float4ToFloatZ, + _tokens->Float4ToFloatW, + _tokens->Float4ToFloat3, + _tokens->Float4ToFloat4, + + _tokens->lightingContributions, + _tokens->scaledDiffusePassThrough, + _tokens->scaledSpecularPassThrough, + _tokens->opacityToTransparency, + _tokens->usdPreviewSurfaceLighting, + _tokens->usdPreviewSurfaceCombiner +}; + +static const TfTokenVector _FragmentGraphNames = { + _tokens->FallbackCPVShader, + _tokens->FallbackShader, + _tokens->UsdPreviewSurface +}; + + +// Helper methods +namespace +{ + std::string _GetResourcePath(const std::string& resource) + { + static PlugPluginPtr plugin = + PlugRegistry::GetInstance().GetPluginWithName("mayaUsd_ShaderFragments"); + if (!TF_VERIFY(plugin, "Could not get plugin\n")) { + return std::string(); + } + + const std::string path = PlugFindPluginResource(plugin, resource); + TF_VERIFY(!path.empty(), "Could not find resource: %s\n", resource.c_str()); + + return path; + } +} + +// Fragment registration +MStatus HdVP2ShaderFragments::registerFragments() +{ + MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer(); + if (!theRenderer) { + return MS::kFailure; + } + + MHWRender::MFragmentManager* fragmentManager = + theRenderer->getFragmentManager(); + if (!fragmentManager) { + return MS::kFailure; + } + + // Register all fragments. + for (const TfToken& fragNameToken : _FragmentNames) { + const MString fragName(fragNameToken.GetText()); + + if (fragmentManager->hasFragment(fragName)) { + continue; + } + + const std::string fragXmlFile = + TfStringPrintf("%s.xml", fragName.asChar()); + const std::string fragXmlPath = _GetResourcePath(fragXmlFile); + + const MString addedName = + fragmentManager->addShadeFragmentFromFile( + fragXmlPath.c_str(), + false); + + if (addedName != fragName) { + MGlobal::displayError( + TfStringPrintf("Failed to register fragment '%s' from file: %s", + fragName.asChar(), + fragXmlPath.c_str()).c_str()); + return MS::kFailure; + } + } + + // Register all fragment graphs. + for (const TfToken& fragGraphNameToken : _FragmentGraphNames) { + const MString fragGraphName(fragGraphNameToken.GetText()); + + if (fragmentManager->hasFragment(fragGraphName)) { + continue; + } + + const std::string fragGraphXmlFile = + TfStringPrintf("%s.xml", fragGraphName.asChar()); + const std::string fragGraphXmlPath = _GetResourcePath(fragGraphXmlFile); + + const MString addedName = + fragmentManager->addFragmentGraphFromFile(fragGraphXmlPath.c_str()); + if (addedName != fragGraphName) { + MGlobal::displayError( + TfStringPrintf("Failed to register fragment graph '%s' from file: %s", + fragGraphName.asChar(), + fragGraphXmlPath.c_str()).c_str()); + return MS::kFailure; + } + } + + return MS::kSuccess; +} + +// Fragment deregistration +MStatus HdVP2ShaderFragments::deregisterFragments() +{ + MHWRender::MRenderer* theRenderer = MHWRender::MRenderer::theRenderer(); + if (!theRenderer) { + return MS::kFailure; + } + + MHWRender::MFragmentManager* fragmentManager = + theRenderer->getFragmentManager(); + if (!fragmentManager) { + return MS::kFailure; + } + + // De-register all fragment graphs. + for (const TfToken& fragGraphNameToken : _FragmentGraphNames) { + const MString fragGraphName(fragGraphNameToken.GetText()); + + if (!fragmentManager->removeFragment(fragGraphName)) { + MGlobal::displayWarning( + TfStringPrintf("Failed to remove fragment graph: %s", + fragGraphName.asChar()).c_str()); + return MS::kFailure; + } + } + + // De-register all fragments. + for (const TfToken& fragNameToken : _FragmentNames) { + const MString fragName(fragNameToken.GetText()); + + if (!fragmentManager->removeFragment(fragName)) { + MGlobal::displayWarning( + TfStringPrintf("Failed to remove fragment: %s", + fragName.asChar()).c_str()); + return MS::kFailure; + } + } + +#if MAYA_API_VERSION >= 201700 + // Clear the shader manager's effect cache as well so that any changes to + // the fragments will get picked up if they are re-registered. + const MHWRender::MShaderManager* shaderMgr = theRenderer->getShaderManager(); + if (!shaderMgr) { + return MS::kFailure; + } + + MStatus status = shaderMgr->clearEffectCache(); + if (status != MS::kSuccess) { + MGlobal::displayWarning("Failed to clear shader manager effect cache"); + return status; + } +#endif + + return MS::kSuccess; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2ShaderFragments/shaderFragments.h b/lib/render/vp2ShaderFragments/shaderFragments.h new file mode 100644 index 0000000000..7c4db7a285 --- /dev/null +++ b/lib/render/vp2ShaderFragments/shaderFragments.h @@ -0,0 +1,41 @@ +// +// Copyright 2019 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. +// + +#ifndef HD_VP2_SHADER_FRAGMENTS +#define HD_VP2_SHADER_FRAGMENTS + +#include "pxr/pxr.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/*! \brief + \class HdVP2ShaderFragments +*/ +class HdVP2ShaderFragments +{ +public: + // Loads all fragments into VP2 + static MStatus registerFragments(); + + // Unload all fragments from VP2 + static MStatus deregisterFragments(); +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // HD_VP2_SHADER_FRAGMENTS diff --git a/lib/render/vp2ShaderFragments/usdPreviewSurfaceCombiner.xml b/lib/render/vp2ShaderFragments/usdPreviewSurfaceCombiner.xml new file mode 100644 index 0000000000..35bf943e81 --- /dev/null +++ b/lib/render/vp2ShaderFragments/usdPreviewSurfaceCombiner.xml @@ -0,0 +1,259 @@ + + + + Combines material and lighting components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + = 110) +#define float3 vec3 +#endif + +mayaSurfaceShaderOutput +usdPreviewSurfaceCombiner( + float3 diffuseIrradianceIn, + float3 specularIrradianceIn, + float3 ambientIn, + float3 irradianceEnv, + float3 specularEnv, + float3 diffuseColor, + float3 specularColor, + float3 emissiveColor, + float3 transparency) +{ + mayaSurfaceShaderOutput result; + + // Ambient + result.outColor = ambientIn * diffuseColor; + + // Diffuse + result.outColor += diffuseIrradianceIn; + result.outColor += diffuseColor * irradianceEnv; + + if (!mayaAlphaCut) { + result.outColor *= saturate(1.0 - transparency); + } + + // Specular + result.outColor += specularIrradianceIn; + result.outColor += specularColor * specularEnv; + + // Emissive + result.outColor += emissiveColor; + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = (1.0 - transparency); + + return result; +} + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +mayaSurfaceShaderOutput +usdPreviewSurfaceCombiner( + float3 diffuseIrradianceIn, + float3 specularIrradianceIn, + float3 ambientIn, + float3 irradianceEnv, + float3 specularEnv, + float3 diffuseColor, + float3 specularColor, + float3 emissiveColor, + float3 transparency) +{ + mayaSurfaceShaderOutput result; + + // Ambient + result.outColor = ambientIn * diffuseColor; + + // Diffuse + result.outColor += diffuseIrradianceIn; + result.outColor += diffuseColor * irradianceEnv; + + if (!mayaAlphaCut) { + result.outColor *= saturate(1.0 - transparency); + } + + // Specular + result.outColor += specularIrradianceIn; + result.outColor += specularColor * specularEnv; + + // Emissive + result.outColor += emissiveColor; + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = (1.0 - transparency); + + return result; +} + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +mayaSurfaceShaderOutput +usdPreviewSurfaceCombiner( + float3 diffuseIrradianceIn, + float3 specularIrradianceIn, + float3 ambientIn, + float3 irradianceEnv, + float3 specularEnv, + float3 diffuseColor, + float3 specularColor, + float3 emissiveColor, + float3 transparency) +{ + mayaSurfaceShaderOutput result; + + // Ambient + result.outColor = ambientIn * diffuseColor; + + // Diffuse + result.outColor += diffuseIrradianceIn; + result.outColor += diffuseColor * irradianceEnv; + + if (!mayaAlphaCut) { + result.outColor *= saturate(1.0 - transparency); + } + + // Specular + result.outColor += specularIrradianceIn; + result.outColor += specularColor * specularEnv; + + // Emissive + result.outColor += emissiveColor; + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = (1.0 - transparency); + + return result; +} + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +mayaSurfaceShaderOutput +usdPreviewSurfaceCombiner( + float3 diffuseIrradianceIn, + float3 specularIrradianceIn, + float3 ambientIn, + float3 irradianceEnv, + float3 specularEnv, + float3 diffuseColor, + float3 specularColor, + float3 emissiveColor, + float3 transparency) +{ + mayaSurfaceShaderOutput result; + + // Ambient + result.outColor = ambientIn * diffuseColor; + + // Diffuse + result.outColor += diffuseIrradianceIn; + result.outColor += diffuseColor * irradianceEnv; + + if (!mayaAlphaCut) { + result.outColor *= saturate(1.0 - transparency); + } + + // Specular + result.outColor += specularIrradianceIn; + result.outColor += specularColor * specularEnv; + + // Emissive + result.outColor += emissiveColor; + + // Transparency + result.outTransparency = transparency; + + result.outGlowColor = float3(0.0, 0.0, 0.0); + result.outMatteOpacity = (1.0 - transparency); + + return result; +} + +]]> + + + + \ No newline at end of file diff --git a/lib/render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml b/lib/render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml new file mode 100644 index 0000000000..6c0e09ab3a --- /dev/null +++ b/lib/render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml @@ -0,0 +1,687 @@ + + + + Computes the diffuse and specular lighting contributions for a light. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + = 110) +#define float3 vec3 +#endif + +// line 110 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +#define PI 3.1415 +#define EPSILON 0.001 + + +float +SchlickFresnel(float EdotH) +{ + return pow(max(0.0, 1.0 - EdotH), 5.0); +} + +float +NormalDistribution(float specularRoughness, float NdotH) +{ + float alpha = specularRoughness * specularRoughness; + float alpha2 = alpha * alpha; + float NdotH2 = NdotH * NdotH; + float DDenom = (NdotH2 * (alpha2 - 1.0)) + 1.0; + DDenom *= DDenom; + DDenom *= PI; + float D = (alpha2 + EPSILON) / DDenom; + return D; +} + +float +Geometric( + float specularRoughness, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float alpha = specularRoughness * specularRoughness; + float k = alpha * 0.5; + float G = NdotE / (NdotE * (1.0 - k) + k); + G *= NdotL / (NdotL * (1.0 - k) + k); + return G; +} + +float +evaluateDirectDiffuse() +{ + return 1.0 / PI; +} + +float3 +evaluateDirectSpecular( + float3 specularColorF0, + float3 specularColorF90, + float specularRoughness, + float fresnel, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float3 F = mix(specularColorF0, specularColorF90, fresnel); + float D = NormalDistribution(specularRoughness, NdotH); + float G = Geometric(specularRoughness, NdotL, NdotE, NdotH, EdotH); + float3 RNum = F * G * D; + float RDenom = 4.0f * NdotL * NdotE + EPSILON; + return RNum / RDenom; +} + +LightingContributions +usdPreviewSurfaceLighting( + float3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + float3 specularColor, + float specularRoughness, + float clearcoatAmount, + float3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + float NdotL, + float NdotE, + float NdotH, + float EdotH, + float3 lightDiffuseIrradiance, + float3 lightSpecularIrradiance) +{ + specularRoughness = max(0.001, specularRoughness); + clearcoatRoughness = max(0.001, clearcoatRoughness); + + float fresnel = SchlickFresnel(EdotH); + + // Evaluate diffuse + float3 d = diffuseColor * evaluateDirectDiffuse(); + + // Evaluate specular first lobe + float3 s1 = float3(0.0, 0.0, 0.0); + if (specularAmount > 0.0) { + float3 F0 = specularColor; + float3 F90 = float3(1.0, 1.0, 1.0); + + if (!useSpecularWorkflow) { + float R = (1.0 - ior) / (1.0 + ior); + float3 specColor = mix(float3(1.0, 1.0, 1.0), diffuseColor, metallic); + F0 = R * R * specColor; + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - mix(F0, F90, fresnel)); + } + + // Evaluate clearcoat + float3 s2 = float3(0.0, 0.0, 0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +// line 110 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +#define PI 3.1415 +#define EPSILON 0.001 + + +float +SchlickFresnel(float EdotH) +{ + return pow(max(0.0, 1.0 - EdotH), 5.0); +} + +float +NormalDistribution(float specularRoughness, float NdotH) +{ + float alpha = specularRoughness * specularRoughness; + float alpha2 = alpha * alpha; + float NdotH2 = NdotH * NdotH; + float DDenom = (NdotH2 * (alpha2 - 1.0)) + 1.0; + DDenom *= DDenom; + DDenom *= PI; + float D = (alpha2 + EPSILON) / DDenom; + return D; +} + +float +Geometric( + float specularRoughness, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float alpha = specularRoughness * specularRoughness; + float k = alpha * 0.5; + float G = NdotE / (NdotE * (1.0 - k) + k); + G *= NdotL / (NdotL * (1.0 - k) + k); + return G; +} + +float +evaluateDirectDiffuse() +{ + return 1.0 / PI; +} + +float3 +evaluateDirectSpecular( + float3 specularColorF0, + float3 specularColorF90, + float specularRoughness, + float fresnel, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float3 F = mix(specularColorF0, specularColorF90, fresnel); + float D = NormalDistribution(specularRoughness, NdotH); + float G = Geometric(specularRoughness, NdotL, NdotE, NdotH, EdotH); + float3 RNum = F * G * D; + float RDenom = 4.0f * NdotL * NdotE + EPSILON; + return RNum / RDenom; +} + +LightingContributions +usdPreviewSurfaceLighting( + float3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + float3 specularColor, + float specularRoughness, + float clearcoatAmount, + float3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + float NdotL, + float NdotE, + float NdotH, + float EdotH, + float3 lightDiffuseIrradiance, + float3 lightSpecularIrradiance) +{ + specularRoughness = max(0.001, specularRoughness); + clearcoatRoughness = max(0.001, clearcoatRoughness); + + float fresnel = SchlickFresnel(EdotH); + + // Evaluate diffuse + float3 d = diffuseColor * evaluateDirectDiffuse(); + + // Evaluate specular first lobe + float3 s1 = float3(0.0, 0.0, 0.0); + if (specularAmount > 0.0) { + float3 F0 = specularColor; + float3 F90 = float3(1.0, 1.0, 1.0); + + if (!useSpecularWorkflow) { + float R = (1.0 - ior) / (1.0 + ior); + float3 specColor = mix(float3(1.0, 1.0, 1.0), diffuseColor, metallic); + F0 = R * R * specColor; + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - mix(F0, F90, fresnel)); + } + + // Evaluate clearcoat + float3 s2 = float3(0.0, 0.0, 0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +// line 110 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +#define PI 3.1415 +#define EPSILON 0.001 + + +float +SchlickFresnel(float EdotH) +{ + return pow(max(0.0, 1.0 - EdotH), 5.0); +} + +float +NormalDistribution(float specularRoughness, float NdotH) +{ + float alpha = specularRoughness * specularRoughness; + float alpha2 = alpha * alpha; + float NdotH2 = NdotH * NdotH; + float DDenom = (NdotH2 * (alpha2 - 1.0)) + 1.0; + DDenom *= DDenom; + DDenom *= PI; + float D = (alpha2 + EPSILON) / DDenom; + return D; +} + +float +Geometric( + float specularRoughness, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float alpha = specularRoughness * specularRoughness; + float k = alpha * 0.5; + float G = NdotE / (NdotE * (1.0 - k) + k); + G *= NdotL / (NdotL * (1.0 - k) + k); + return G; +} + +float +evaluateDirectDiffuse() +{ + return 1.0 / PI; +} + +float3 +evaluateDirectSpecular( + float3 specularColorF0, + float3 specularColorF90, + float specularRoughness, + float fresnel, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float3 F = lerp(specularColorF0, specularColorF90, fresnel); + float D = NormalDistribution(specularRoughness, NdotH); + float G = Geometric(specularRoughness, NdotL, NdotE, NdotH, EdotH); + float3 RNum = F * G * D; + float RDenom = 4.0f * NdotL * NdotE + EPSILON; + return RNum / RDenom; +} + +LightingContributions +usdPreviewSurfaceLighting( + float3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + float3 specularColor, + float specularRoughness, + float clearcoatAmount, + float3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + float NdotL, + float NdotE, + float NdotH, + float EdotH, + float3 lightDiffuseIrradiance, + float3 lightSpecularIrradiance) +{ + specularRoughness = max(0.001, specularRoughness); + clearcoatRoughness = max(0.001, clearcoatRoughness); + + float fresnel = SchlickFresnel(EdotH); + + // Evaluate diffuse + float3 d = diffuseColor * evaluateDirectDiffuse(); + + // Evaluate specular first lobe + float3 s1 = float3(0.0, 0.0, 0.0); + if (specularAmount > 0.0) { + float3 F0 = specularColor; + float3 F90 = float3(1.0, 1.0, 1.0); + + if (!useSpecularWorkflow) { + float R = (1.0 - ior) / (1.0 + ior); + float3 specColor = lerp(float3(1.0, 1.0, 1.0), diffuseColor, metallic); + F0 = R * R * specColor; + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - lerp(F0, F90, fresnel)); + } + + // Evaluate clearcoat + float3 s2 = float3(0.0, 0.0, 0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +]]> + + + + + + = 110) +#define float3 vec3 +#endif + +// line 110 of "../../../../pxr/usdImaging/lib/usdShaders/shaders/previewSurface.glslfx" + +#define PI 3.1415 +#define EPSILON 0.001 + + +float +SchlickFresnel(float EdotH) +{ + return pow(max(0.0, 1.0 - EdotH), 5.0); +} + +float +NormalDistribution(float specularRoughness, float NdotH) +{ + float alpha = specularRoughness * specularRoughness; + float alpha2 = alpha * alpha; + float NdotH2 = NdotH * NdotH; + float DDenom = (NdotH2 * (alpha2 - 1.0)) + 1.0; + DDenom *= DDenom; + DDenom *= PI; + float D = (alpha2 + EPSILON) / DDenom; + return D; +} + +float +Geometric( + float specularRoughness, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float alpha = specularRoughness * specularRoughness; + float k = alpha * 0.5; + float G = NdotE / (NdotE * (1.0 - k) + k); + G *= NdotL / (NdotL * (1.0 - k) + k); + return G; +} + +float +evaluateDirectDiffuse() +{ + return 1.0 / PI; +} + +float3 +evaluateDirectSpecular( + float3 specularColorF0, + float3 specularColorF90, + float specularRoughness, + float fresnel, + float NdotL, + float NdotE, + float NdotH, + float EdotH) +{ + float3 F = lerp(specularColorF0, specularColorF90, fresnel); + float D = NormalDistribution(specularRoughness, NdotH); + float G = Geometric(specularRoughness, NdotL, NdotE, NdotH, EdotH); + float3 RNum = F * G * D; + float RDenom = 4.0f * NdotL * NdotE + EPSILON; + return RNum / RDenom; +} + +LightingContributions +usdPreviewSurfaceLighting( + float3 diffuseColor, + bool useSpecularWorkflow, + float ior, + float metallic, + float specularAmount, + float3 specularColor, + float specularRoughness, + float clearcoatAmount, + float3 clearcoatColor, + float clearcoatRoughness, + float occlusion, + float NdotL, + float NdotE, + float NdotH, + float EdotH, + float3 lightDiffuseIrradiance, + float3 lightSpecularIrradiance) +{ + specularRoughness = max(0.001, specularRoughness); + clearcoatRoughness = max(0.001, clearcoatRoughness); + + float fresnel = SchlickFresnel(EdotH); + + // Evaluate diffuse + float3 d = diffuseColor * evaluateDirectDiffuse(); + + // Evaluate specular first lobe + float3 s1 = float3(0.0, 0.0, 0.0); + if (specularAmount > 0.0) { + float3 F0 = specularColor; + float3 F90 = float3(1.0, 1.0, 1.0); + + if (!useSpecularWorkflow) { + float R = (1.0 - ior) / (1.0 + ior); + float3 specColor = lerp(float3(1.0, 1.0, 1.0), diffuseColor, metallic); + F0 = R * R * specColor; + F90 = specColor; + + // For metallic workflows, pure metals have no diffuse + d *= 1.0 - metallic; + } + + s1 = specularAmount * evaluateDirectSpecular( + F0, // Specular color 0 + F90, // Specular color 90 + specularRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + + // Adjust the diffuse so glazing angles have less diffuse + d *= (1.0 - lerp(F0, F90, fresnel)); + } + + // Evaluate clearcoat + float3 s2 = float3(0.0, 0.0, 0.0); + if (clearcoatAmount > 0.0) { + s2 = clearcoatAmount * evaluateDirectSpecular( + clearcoatColor, // Clearcoat color 0 + clearcoatColor, // Clearcoat color 90 + clearcoatRoughness, // Roughness + fresnel, // Fresnel + NdotL, NdotE, NdotH, EdotH); // Dot products needed for lights + } + + LightingContributions lightingContrib; + + lightingContrib.diffuse = + occlusion * NdotL * d * lightDiffuseIrradiance; + + lightingContrib.specular = + occlusion * NdotL * (s1 + s2) * lightSpecularIrradiance; + + return lightingContrib; +} + + +]]> + + + + \ No newline at end of file diff --git a/lib/ufe/Global.cpp b/lib/ufe/Global.cpp new file mode 100644 index 0000000000..865b142278 --- /dev/null +++ b/lib/ufe/Global.cpp @@ -0,0 +1,132 @@ +// +// Copyright 2019 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. +// + +#include "Global.h" +#include "ProxyShapeHandler.h" +#include "StagesSubject.h" +#include "private/InPathChange.h" +#include "UsdHierarchyHandler.h" +#include "UsdTransform3dHandler.h" +#include "UsdSceneItemOpsHandler.h" + +#include "ufe/rtid.h" +#include "ufe/runTimeMgr.h" +#include "ufe/hierarchyHandler.h" +#include "ufe/ProxyShapeHierarchyHandler.h" + +#ifdef UFE_V2_FEATURES_AVAILABLE +// Note: must come after include of ufe files so we have the define. +#include "UsdAttributesHandler.h" +#endif + +#include +#include + +namespace { + int gRegistrationCount = 0; +} + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ + +// Maya's UFE run-time name and ID. +static const std::string kMayaRunTimeName("Maya-DG"); +Ufe::Rtid g_MayaRtid = 0; + +// Register this run-time with UFE under the following name. +static const std::string kUSDRunTimeName("USD"); + +// Our run-time ID, allocated by UFE at registration time. Initialize it +// with illegal 0 value. +Ufe::Rtid g_USDRtid = 0; + +// The normal Maya hierarchy handler, which we decorate for ProxyShape support. +// Keep a reference to it to restore on finalization. +Ufe::HierarchyHandler::Ptr g_MayaHierarchyHandler; + +// Subject singleton for observation of all USD stages. +StagesSubject::Ptr g_StagesSubject; + +bool InPathChange::fInPathChange = false; + +//------------------------------------------------------------------------------ +// Functions +//------------------------------------------------------------------------------ + +// Only intended to be called by the plugin initialization, to +// initialize the stage model. +MStatus initialize() +{ + // If we're already registered, do nothing. + if (gRegistrationCount++ > 0) + return MS::kSuccess; + + // Replace the Maya hierarchy handler with ours. + g_MayaRtid = Ufe::RunTimeMgr::instance().getId(kMayaRunTimeName); +#if !defined(NDEBUG) + assert(g_MayaRtid != 0); +#endif + if (g_MayaRtid == 0) + return MS::kFailure; + + g_MayaHierarchyHandler = Ufe::RunTimeMgr::instance().hierarchyHandler(g_MayaRtid); + auto proxyShapeHandler = ProxyShapeHierarchyHandler::create(g_MayaHierarchyHandler); + Ufe::RunTimeMgr::instance().setHierarchyHandler(g_MayaRtid, proxyShapeHandler); + + auto usdHierHandler = UsdHierarchyHandler::create(); + auto usdTrans3dHandler = UsdTransform3dHandler::create(); + auto usdSceneItemOpsHandler = UsdSceneItemOpsHandler::create(); +#ifdef UFE_V2_FEATURES_AVAILABLE + auto usdAttributesHandler = UsdAttributesHandler::create(); + g_USDRtid = Ufe::RunTimeMgr::instance().register_( + kUSDRunTimeName, usdHierHandler, usdTrans3dHandler, usdSceneItemOpsHandler, usdAttributesHandler); +#else + g_USDRtid = Ufe::RunTimeMgr::instance().register_( + kUSDRunTimeName, usdHierHandler, usdTrans3dHandler, usdSceneItemOpsHandler); +#endif +#if !defined(NDEBUG) + assert(g_USDRtid != 0); +#endif + if (g_USDRtid == 0) + return MS::kFailure; + + g_StagesSubject = StagesSubject::create(); + + return MS::kSuccess; +} + +MStatus finalize() +{ + // If more than one plugin still has us registered, do nothing. + if (gRegistrationCount-- > 1) + return MS::kSuccess; + + // Restore the normal Maya hierarchy handler, and unregister. + Ufe::RunTimeMgr::instance().setHierarchyHandler(g_MayaRtid, g_MayaHierarchyHandler); + Ufe::RunTimeMgr::instance().unregister(g_USDRtid); + g_MayaHierarchyHandler.reset(); + + g_StagesSubject.Reset(); + + return MS::kSuccess; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/Global.h b/lib/ufe/Global.h new file mode 100644 index 0000000000..b38dcd5d3e --- /dev/null +++ b/lib/ufe/Global.h @@ -0,0 +1,36 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "maya/MStatus.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +// Only intended to be called by the plugin initialization, to +// initialize the handlers and stage model. +MAYAUSD_CORE_PUBLIC +MStatus initialize(); + +//! Only intended to be called by the plugin finalization, to +//! finalize the handlers stage model. +MAYAUSD_CORE_PUBLIC +MStatus finalize(); + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/ProxyShapeHandler.cpp b/lib/ufe/ProxyShapeHandler.cpp new file mode 100644 index 0000000000..a4272e23d3 --- /dev/null +++ b/lib/ufe/ProxyShapeHandler.cpp @@ -0,0 +1,95 @@ +// +// Copyright 2019 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. +// + +#include "ProxyShapeHandler.h" + +#include "../utils/query.h" + +#include "maya/MGlobal.h" +#include "maya/MString.h" +#include "maya/MStringArray.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ +const std::string ProxyShapeHandler::fMayaUsdGatewayNodeType = "mayaUsdProxyShapeBase"; + +//------------------------------------------------------------------------------ +// ProxyShapeHandler +//------------------------------------------------------------------------------ + +/*static*/ +const std::string& ProxyShapeHandler::gatewayNodeType() +{ + return fMayaUsdGatewayNodeType; +} + +/*static*/ +std::vector ProxyShapeHandler::getAllNames() +{ + std::vector names; + MString cmd; + MStringArray result; + cmd.format("ls -type ^1s -long", fMayaUsdGatewayNodeType.c_str()); + if (MS::kSuccess == MGlobal::executeCommand(cmd, result)) + { + for (MString& name : result) + { + names.push_back(name.asChar()); + } + } + return names; +} + +/*static*/ +UsdStageWeakPtr ProxyShapeHandler::dagPathToStage(const std::string& dagPath) +{ + UsdStageWeakPtr stagePtr; + + if (UsdPrim usdPrim = UsdMayaQuery::GetPrim(dagPath)) + stagePtr = usdPrim.GetStage(); + + return stagePtr; +} + +/*static*/ +std::vector ProxyShapeHandler::getAllStages() +{ + // According to Pixar, the following should work: + // return UsdMayaStageCache::Get().GetAllStages(); + // but after a file open of a scene with one or more Pixar proxy shapes, + // returns an empty list. To be investigated, PPT, 28-Feb-2019. + + // When using an unmodified AL plugin, the following line crashes + // Maya, so it requires the AL proxy shape inheritance from + // MayaUsdProxyShapeBase. PPT, 12-Apr-2019. + std::vector stages; + for (const auto& name : getAllNames()) + { + UsdStageWeakPtr stage = dagPathToStage(name); + if (stage) + { + stages.push_back(stage); + } + } + return stages; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/ProxyShapeHandler.h b/lib/ufe/ProxyShapeHandler.h new file mode 100644 index 0000000000..553e6eea8d --- /dev/null +++ b/lib/ufe/ProxyShapeHandler.h @@ -0,0 +1,62 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "pxr/pxr.h" +#include "pxr/usd/usd/prim.h" + +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +/*! + Proxy shape abstraction, to support use of USD proxy shape with any plugin + that has a proxy shape derived from MayaUsdProxyShapeBase. + */ +class MAYAUSD_CORE_PUBLIC ProxyShapeHandler +{ +public: + ProxyShapeHandler() = default; + ~ProxyShapeHandler() = default; + + // Delete the copy/move constructors assignment operators. + ProxyShapeHandler(const ProxyShapeHandler&) = delete; + ProxyShapeHandler& operator=(const ProxyShapeHandler&) = delete; + ProxyShapeHandler(ProxyShapeHandler&&) = delete; + ProxyShapeHandler& operator=(ProxyShapeHandler&&) = delete; + + //! \return Type of the Maya shape node at the root of a USD hierarchy. + static const std::string& gatewayNodeType(); + + static std::vector getAllNames(); + + static UsdStageWeakPtr dagPathToStage(const std::string& dagPath); + + static std::vector getAllStages(); + +private: + static const std::string fMayaUsdGatewayNodeType; + +}; // ProxyShapeHandler + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/ProxyShapeHierarchy.cpp b/lib/ufe/ProxyShapeHierarchy.cpp new file mode 100644 index 0000000000..6f302af007 --- /dev/null +++ b/lib/ufe/ProxyShapeHierarchy.cpp @@ -0,0 +1,148 @@ +// +// Copyright 2019 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. +// + +#include "ProxyShapeHierarchy.h" +#include "Utils.h" + +#include "ufe/pathComponent.h" +#include "ufe/pathSegment.h" +#include "ufe/rtid.h" + +#include "pxr/usd/usd/stage.h" + +#include + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ +extern Ufe::Rtid g_USDRtid; + +//------------------------------------------------------------------------------ +// ProxyShapeHierarchy +//------------------------------------------------------------------------------ + +ProxyShapeHierarchy::ProxyShapeHierarchy(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler) + : Ufe::Hierarchy() + , fMayaHierarchyHandler(mayaHierarchyHandler) +{ +} + +ProxyShapeHierarchy::~ProxyShapeHierarchy() +{ +} + +/*static*/ +ProxyShapeHierarchy::Ptr ProxyShapeHierarchy::create(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler) +{ + return std::make_shared(mayaHierarchyHandler); +} + +void ProxyShapeHierarchy::setItem(const Ufe::SceneItem::Ptr& item) +{ + // Our USD root prim is from the stage, which is from the item. So if we are + // changing the item, it's possible that we won't have the same stage (and + // thus the same root prim). To be safe, clear our stored root prim. + if (fItem != item) + { + fUsdRootPrim = UsdPrim(); + } + fItem = item; + fMayaHierarchy = fMayaHierarchyHandler->hierarchy(item); +} + +const UsdPrim& ProxyShapeHierarchy::getUsdRootPrim() const +{ + if (!fUsdRootPrim.IsValid()) + { + // FIXME During AL_usdmaya_ProxyShapeImport, nodes (both Maya + // and USD) are being added (e.g. the proxy shape itself), but + // there is no stage yet, and there is no way to detect that a + // proxy shape import command is under way. PPT, 28-Sep-2018. + UsdStageWeakPtr stage = getStage(fItem->path()); + if (stage) + { + fUsdRootPrim = stage->GetPrimAtPath(SdfPath("/")); + } + } + return fUsdRootPrim; +} + +//------------------------------------------------------------------------------ +// Ufe::Hierarchy overrides +//------------------------------------------------------------------------------ + +Ufe::SceneItem::Ptr ProxyShapeHierarchy::sceneItem() const +{ + return fItem; +} + +bool ProxyShapeHierarchy::hasChildren() const +{ + const UsdPrim& rootPrim = getUsdRootPrim(); + if (!rootPrim.IsValid()) + return false; + return !rootPrim.GetChildren().empty(); +} + +Ufe::SceneItemList ProxyShapeHierarchy::children() const +{ + // Return children of the USD root. + const UsdPrim& rootPrim = getUsdRootPrim(); + if (!rootPrim.IsValid()) + return Ufe::SceneItemList(); + + auto usdChildren = rootPrim.GetChildren(); + auto parentPath = fItem->path(); + + // We must create selection items for our children. These will have as + // path the path of the proxy shape, with a single path segment of a + // single component appended to it. + Ufe::SceneItemList children; + for (const auto& child : usdChildren) + { + children.push_back(UsdSceneItem::create(parentPath + Ufe::PathSegment( + Ufe::PathComponent(child.GetName().GetString()), g_USDRtid, '/'), child)); + } + return children; +} + +Ufe::SceneItem::Ptr ProxyShapeHierarchy::parent() const +{ + return fMayaHierarchy->parent(); +} + +Ufe::AppendedChild ProxyShapeHierarchy::appendChild(const Ufe::SceneItem::Ptr& child) +{ + throw std::runtime_error("ProxyShapeHierarchy::appendChild() not implemented"); +} + +#ifdef UFE_V2_FEATURES_AVAILABLE +Ufe::SceneItem::Ptr ProxyShapeHierarchy::createGroup(const Ufe::PathComponent& name) const +{ + throw std::runtime_error("ProxyShapeHierarchy::createGroup() not implemented"); +} + +Ufe::Group ProxyShapeHierarchy::createGroupCmd(const Ufe::PathComponent& name) const +{ + throw std::runtime_error("ProxyShapeHierarchy::createGroupCmd not implemented"); +} +#endif + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/ProxyShapeHierarchy.h b/lib/ufe/ProxyShapeHierarchy.h new file mode 100644 index 0000000000..9f0a2ef061 --- /dev/null +++ b/lib/ufe/ProxyShapeHierarchy.h @@ -0,0 +1,80 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/hierarchy.h" +#include "ufe/hierarchyHandler.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief USD gateway node hierarchy interface. +/*! + This class defines a hierarchy interface for a single kind of Maya node, + the USD gateway node. This node is special in that its parent is a Maya + node, but its children are children of the USD root prim. + */ +class MAYAUSD_CORE_PUBLIC ProxyShapeHierarchy : public Ufe::Hierarchy +{ +public: + typedef std::shared_ptr Ptr; + + ProxyShapeHierarchy(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler); + ~ProxyShapeHierarchy() override; + + // Delete the copy/move constructors assignment operators. + ProxyShapeHierarchy(const ProxyShapeHierarchy&) = delete; + ProxyShapeHierarchy& operator=(const ProxyShapeHierarchy&) = delete; + ProxyShapeHierarchy(ProxyShapeHierarchy&&) = delete; + ProxyShapeHierarchy& operator=(ProxyShapeHierarchy&&) = delete; + + //! Create a ProxyShapeHierarchy from a UFE hierarchy handler. + static ProxyShapeHierarchy::Ptr create(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler); + + void setItem(const Ufe::SceneItem::Ptr& item); + + // Ufe::Hierarchy overrides + Ufe::SceneItem::Ptr sceneItem() const override; + bool hasChildren() const override; + Ufe::SceneItemList children() const override; + Ufe::SceneItem::Ptr parent() const override; + Ufe::AppendedChild appendChild(const Ufe::SceneItem::Ptr& child) override; + +#ifdef UFE_V2_FEATURES_AVAILABLE + Ufe::SceneItem::Ptr createGroup(const Ufe::PathComponent& name) const override; + Ufe::Group createGroupCmd(const Ufe::PathComponent& name) const override; +#endif + +private: + const UsdPrim& getUsdRootPrim() const; + +private: + Ufe::SceneItem::Ptr fItem; + Hierarchy::Ptr fMayaHierarchy; + Ufe::HierarchyHandler::Ptr fMayaHierarchyHandler; + + // The root prim is initialized on first use and therefore mutable. + mutable UsdPrim fUsdRootPrim; +}; // ProxyShapeHierarchy + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/ProxyShapeHierarchyHandler.cpp b/lib/ufe/ProxyShapeHierarchyHandler.cpp new file mode 100644 index 0000000000..2728396f43 --- /dev/null +++ b/lib/ufe/ProxyShapeHierarchyHandler.cpp @@ -0,0 +1,63 @@ +// +// Copyright 2019 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. +// + +#include "ProxyShapeHierarchyHandler.h" +#include "Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +ProxyShapeHierarchyHandler::ProxyShapeHierarchyHandler(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler) + : Ufe::HierarchyHandler() + , fMayaHierarchyHandler(mayaHierarchyHandler) +{ + fProxyShapeHierarchy = ProxyShapeHierarchy::create(mayaHierarchyHandler); +} + +ProxyShapeHierarchyHandler::~ProxyShapeHierarchyHandler() +{ +} + +/*static*/ +ProxyShapeHierarchyHandler::Ptr ProxyShapeHierarchyHandler::create(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler) +{ + return std::make_shared(mayaHierarchyHandler); +} + +//------------------------------------------------------------------------------ +// Ufe::HierarchyHandler overrides +//------------------------------------------------------------------------------ + +Ufe::Hierarchy::Ptr ProxyShapeHierarchyHandler::hierarchy(const Ufe::SceneItem::Ptr& item) const +{ + if (isAGatewayType(item->nodeType())) + { + fProxyShapeHierarchy->setItem(item); + return fProxyShapeHierarchy; + } + else + { + return fMayaHierarchyHandler->hierarchy(item); + } +} + +Ufe::SceneItem::Ptr ProxyShapeHierarchyHandler::createItem(const Ufe::Path& path) const +{ + return fMayaHierarchyHandler->createItem(path); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/ProxyShapeHierarchyHandler.h b/lib/ufe/ProxyShapeHierarchyHandler.h new file mode 100644 index 0000000000..47689ae95b --- /dev/null +++ b/lib/ufe/ProxyShapeHierarchyHandler.h @@ -0,0 +1,69 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/hierarchyHandler.h" +#include "ufe/ProxyShapeHierarchy.h" + +//PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Maya run-time hierarchy handler with support for USD gateway node. +/*! + This hierarchy handler is NOT a USD run-time hierarchy handler: it is a + Maya run-time hierarchy handler. It decorates the standard Maya run-time + hierarchy handler and replaces it, providing special behavior only if the + requested hierarchy interface is for the Maya to USD gateway node. In that + case, it returns a special ProxyShapeHierarchy interface object, which + knows how to handle USD children of the Maya ProxyShapeHierarchy node. + + For all other Maya nodes, this hierarchy handler simply delegates the work + to the standard Maya hierarchy handler it decorates, which returns a + standard Maya hierarchy interface object. + */ +class MAYAUSD_CORE_PUBLIC ProxyShapeHierarchyHandler : public Ufe::HierarchyHandler +{ +public: + typedef std::shared_ptr Ptr; + + ProxyShapeHierarchyHandler(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler); + ~ProxyShapeHierarchyHandler() override; + + // Delete the copy/move constructors assignment operators. + ProxyShapeHierarchyHandler(const ProxyShapeHierarchyHandler&) = delete; + ProxyShapeHierarchyHandler& operator=(const ProxyShapeHierarchyHandler&) = delete; + ProxyShapeHierarchyHandler(ProxyShapeHierarchyHandler&&) = delete; + ProxyShapeHierarchyHandler& operator=(ProxyShapeHierarchyHandler&&) = delete; + + //! Create a ProxyShapeHierarchyHandler from a UFE hierarchy handler. + static ProxyShapeHierarchyHandler::Ptr create(Ufe::HierarchyHandler::Ptr mayaHierarchyHandler); + + // Ufe::HierarchyHandler overrides + Ufe::Hierarchy::Ptr hierarchy(const Ufe::SceneItem::Ptr& item) const override; + Ufe::SceneItem::Ptr createItem(const Ufe::Path& path) const override; + +private: + Ufe::HierarchyHandler::Ptr fMayaHierarchyHandler; + ProxyShapeHierarchy::Ptr fProxyShapeHierarchy; + +}; // ProxyShapeHierarchyHandler + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/StagesSubject.cpp b/lib/ufe/StagesSubject.cpp new file mode 100644 index 0000000000..12de877c64 --- /dev/null +++ b/lib/ufe/StagesSubject.cpp @@ -0,0 +1,227 @@ +// +// Copyright 2019 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. +// + +#include "StagesSubject.h" +#include "Utils.h" +#include "UsdStageMap.h" +#include "ProxyShapeHandler.h" +#include "private/InPathChange.h" + +#include "ufe/path.h" +#include "ufe/hierarchy.h" +#include "ufe/scene.h" +#include "ufe/sceneNotification.h" +#include "ufe/transform3d.h" + +#include "maya/MSceneMessage.h" +#include "maya/MMessage.h" + +#include + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables & macros +//------------------------------------------------------------------------------ +extern UsdStageMap g_StageMap; +extern Ufe::Rtid g_USDRtid; + +//------------------------------------------------------------------------------ +// StagesSubject +//------------------------------------------------------------------------------ + +StagesSubject::StagesSubject() +{ + // Workaround to MAYA-65920: at startup, MSceneMessage.kAfterNew file + // callback is incorrectly called by Maya before the + // MSceneMessage.kBeforeNew file callback, which should be illegal. + // Detect this and ignore illegal calls to after new file callbacks. + // PPT, 19-Jan-16. + fBeforeNewCallback = false; + + MStatus res; + fCbIds.append(MSceneMessage::addCallback( + MSceneMessage::kBeforeNew, beforeNewCallback, this, &res)); + CHECK_MSTATUS(res); + fCbIds.append(MSceneMessage::addCallback( + MSceneMessage::kBeforeOpen, beforeOpenCallback, this, &res)); + CHECK_MSTATUS(res); + fCbIds.append(MSceneMessage::addCallback( + MSceneMessage::kAfterOpen, afterOpenCallback, this, &res)); + CHECK_MSTATUS(res); + fCbIds.append(MSceneMessage::addCallback( + MSceneMessage::kAfterNew, afterNewCallback, this, &res)); + CHECK_MSTATUS(res); + + TfWeakPtr me(this); + TfNotice::Register(me, &StagesSubject::onStageSet); +} + +StagesSubject::~StagesSubject() +{ + MMessage::removeCallbacks(fCbIds); + fCbIds.clear(); +} + +/*static*/ +StagesSubject::Ptr StagesSubject::create() +{ + return TfCreateWeakPtr(new StagesSubject); +} + +bool StagesSubject::beforeNewCallback() const +{ + return fBeforeNewCallback; +} + +void StagesSubject::beforeNewCallback(bool b) +{ + fBeforeNewCallback = b; +} + +/*static*/ +void StagesSubject::beforeNewCallback(void* clientData) +{ + StagesSubject* ss = static_cast(clientData); + ss->beforeNewCallback(true); +} + +/*static*/ +void StagesSubject::beforeOpenCallback(void* clientData) +{ + //StagesSubject* ss = static_cast(clientData); + StagesSubject::beforeNewCallback(clientData); +} + +/*static*/ +void StagesSubject::afterNewCallback(void* clientData) +{ + StagesSubject* ss = static_cast(clientData); + + // Workaround to MAYA-65920: detect and avoid illegal callback sequence. + if (!ss->beforeNewCallback()) + return; + + ss->beforeNewCallback(false); + StagesSubject::afterOpenCallback(clientData); +} + +/*static*/ +void StagesSubject::afterOpenCallback(void* clientData) +{ + StagesSubject* ss = static_cast(clientData); + ss->afterOpen(); +} + +void StagesSubject::afterOpen() +{ + // Observe stage changes, for all stages. Return listener object can + // optionally be used to call Revoke() to remove observation, but must + // keep reference to it, otherwise its reference count is immediately + // decremented, falls to zero, and no observation occurs. + + // Ideally, we would observe the data model only if there are observers, + // to minimize cost of observation. However, since observation is + // frequent, we won't implement this for now. PPT, 22-Dec-2017. + std::for_each(std::begin(fStageListeners), std::end(fStageListeners), + [](StageListenerMap::value_type element) { TfNotice::Revoke(element.second); } ); + + StagesSubject::Ptr me(this); + for (auto stage : ProxyShapeHandler::getAllStages()) + { + fStageListeners[stage] = TfNotice::Register( + me, &StagesSubject::stageChanged, stage); + } + + // Set up our stage to AL_usdmaya_ProxyShape UFE path (and reverse) + // mapping. We do this with the following steps: + // - get all proxyShape nodes in the scene. + // - get their AL Python wrapper + // - get their Dag paths + // - convert the Dag paths to UFE paths. + g_StageMap.clear(); + auto proxyShapeNames = ProxyShapeHandler::getAllNames(); + for (const auto& psn : proxyShapeNames) + { + MDagPath dag = nameToDagPath(psn); + Ufe::Path ufePath = dagPathToUfe(dag); + auto stage = ProxyShapeHandler::dagPathToStage(psn); + g_StageMap.addItem(ufePath, stage); + } +} + +void StagesSubject::stageChanged(UsdNotice::ObjectsChanged const& notice, UsdStageWeakPtr const& sender) +{ + // If the stage path has not been initialized yet, do nothing + if (stagePath(sender).empty()) + return; + + auto stage = notice.GetStage(); + for (const auto& changedPath : notice.GetResyncedPaths()) + { + const std::string& usdPrimPathStr = changedPath.GetPrimPath().GetString(); + Ufe::Path ufePath = stagePath(sender) + Ufe::PathSegment(usdPrimPathStr, g_USDRtid, '/'); + auto prim = stage->GetPrimAtPath(changedPath); + // Changed paths could be xformOps. + // These are considered as invalid null prims + if (prim.IsValid() && !InPathChange::inPathChange()) + { + auto sceneItem = Ufe::Hierarchy::createItem(ufePath); + + // AL LayerCommands.addSubLayer test will cause Maya to crash + // if we don't filter invalid sceneItems. This patch is provided + // to prevent crashes, but more investigation will have to be + // done to understand why ufePath in case of sub layer + // creation causes Ufe::Hierarchy::createItem to fail. + if (!sceneItem) + continue; + + if (prim.IsActive()) + { + auto notification = Ufe::ObjectAdd(sceneItem); + Ufe::Scene::notifyObjectAdd(notification); + } + else + { + auto notification = Ufe::ObjectPostDelete(sceneItem); + Ufe::Scene::notifyObjectDelete(notification); + } + } + } + + for (const auto& changedPath : notice.GetChangedInfoOnlyPaths()) + { + auto usdPrimPathStr = changedPath.GetPrimPath().GetString(); + auto ufePath = stagePath(sender) + Ufe::PathSegment(usdPrimPathStr, g_USDRtid, '/'); + // We need to determine if the change is a Transform3d change. + // We must at least pick up xformOp:translate, xformOp:rotateXYZ, + // and xformOp:scale. + static std::string xformOp(".xformOp:"); + if (changedPath.GetElementString().substr(0, xformOp.length()) == xformOp) + { + Ufe::Transform3d::notify(ufePath); + } + } +} + +void StagesSubject::onStageSet(const UsdMayaProxyStageSetNotice& notice) +{ + afterOpen(); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/StagesSubject.h b/lib/ufe/StagesSubject.h new file mode 100644 index 0000000000..42da829f5b --- /dev/null +++ b/lib/ufe/StagesSubject.h @@ -0,0 +1,90 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" +#include "../listeners/proxyShapeNotice.h" + +#include "pxr/base/tf/weakBase.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/base/tf/hash.h" +#include "pxr/base/tf/notice.h" +#include "pxr/usd/usd/notice.h" + +#include "maya/MCallbackIdArray.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Subject class to observe Maya scene. +/*! + This class observes Maya file open, to register a USD observer on each + stage the Maya scene contains. This USD observer translates USD + notifications into UFE notifications. + */ +class MAYAUSD_CORE_PUBLIC StagesSubject : public TfWeakBase +{ +public: + typedef TfWeakPtr Ptr; + + //! Constructor + StagesSubject(); + + //! Destructor + ~StagesSubject(); + + //! Create the StagesSubject. + static StagesSubject::Ptr create(); + + // Delete the copy/move constructors assignment operators. + StagesSubject(const StagesSubject&) = delete; + StagesSubject& operator=(const StagesSubject&) = delete; + StagesSubject(StagesSubject&&) = delete; + StagesSubject& operator=(StagesSubject&&) = delete; + + bool beforeNewCallback() const; + void beforeNewCallback(bool b); + + void afterOpen(); + +private: + // Maya scene message callbacks + static void beforeNewCallback(void* clientData); + static void beforeOpenCallback(void* clientData); + static void afterNewCallback(void* clientData); + static void afterOpenCallback(void* clientData); + + //! Call the stageChanged() methods on stage observers. + void stageChanged(UsdNotice::ObjectsChanged const& notice, UsdStageWeakPtr const& sender); + +private: + // Notice listener method for proxy stage set + void onStageSet(const UsdMayaProxyStageSetNotice& notice); + + // Map of per-stage listeners, indexed by stage. + typedef TfHashMap StageListenerMap; + StageListenerMap fStageListeners; + + bool fBeforeNewCallback = false; + + MCallbackIdArray fCbIds; + +}; // StagesSubject + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdAttribute.cpp b/lib/ufe/UsdAttribute.cpp new file mode 100644 index 0000000000..c41566ce41 --- /dev/null +++ b/lib/ufe/UsdAttribute.cpp @@ -0,0 +1,489 @@ +// +// Copyright 2019 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. +// + +#include "UsdAttribute.h" + +#include "pxr/base/tf/token.h" +#include "pxr/base/vt/value.h" +#include "pxr/usd/usd/schemaRegistry.h" +#include "pxr/usd/sdf/attributeSpec.h" + +// We unconditionally want the UFE asserts here (even in release builds). +// The UFE_ASSERT_MSG has a built-in throw which we want to use for error handling. +#define UFE_ENABLE_ASSERTS +#include + +#include +#include +#include + +// 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. +// PXR_NAMESPACE_USING_DIRECTIVE + +static constexpr char kErrorMsgFailedSet[] = "Failed to set USD attribute with new value"; +static constexpr char kErrorMsgFailedConvertToString[] = "Could not convert the attribute to a string"; +static constexpr char kErrorMsgInvalidType[] = "USD attribute does not match created attribute class type"; +static constexpr char kErrorMsgEnumNoValue[] = "Enum string attribute has no value"; + +//------------------------------------------------------------------------------ +// Helper functions +//------------------------------------------------------------------------------ + +namespace +{ + +std::string getUsdAttributeValueAsString(const PXR_NS::UsdAttribute& attr) +{ + if (!attr.HasValue()) return ""; + + PXR_NS::VtValue v; + if (attr.Get(&v)) + { + if (v.CanCast()) + { + PXR_NS::VtValue v_str = v.Cast(); + return v_str.Get(); + } + + std::ostringstream os; + os << v; + return os.str(); + } + + UFE_ASSERT_MSG(false, kErrorMsgFailedConvertToString); + return ""; +} + +template +U getUsdAttributeVectorAsUfe(const PXR_NS::UsdAttribute& attr) +{ + if (!attr.HasValue()) return U(); + + PXR_NS::VtValue vt; + if (attr.Get(&vt) && vt.IsHolding()) + { + T gfVec = vt.UncheckedGet(); + U ret(gfVec[0], gfVec[1], gfVec[2]); + return ret; + } + + UFE_ASSERT_MSG(false, kErrorMsgInvalidType); + return U(); +} + +template +void setUsdAttributeVectorFromUfe(PXR_NS::UsdAttribute& attr, const U& value) +{ + T vec; + UFE_ASSERT_MSG(attr.Get(&vec), kErrorMsgInvalidType); + vec.Set(value.x(), value.y(), value.z()); + bool b = attr.Set(vec); + UFE_ASSERT_MSG(b, kErrorMsgFailedSet); +} + +} // end namespace + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// UsdAttribute: +//------------------------------------------------------------------------------ + +UsdAttribute::UsdAttribute(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) + : fUsdAttr(usdAttr) +{ + fPrim = item->prim(); +} + +UsdAttribute::~UsdAttribute() +{ +} + +bool UsdAttribute::hasValue() const +{ + return fUsdAttr.HasValue(); +} + +std::string UsdAttribute::name() const +{ + // Should be the same as the name we were created with. + return fUsdAttr.GetName().GetString(); +} + +std::string UsdAttribute::documentation() const +{ + return fUsdAttr.GetDocumentation(); +} + +std::string UsdAttribute::string() const +{ + return getUsdAttributeValueAsString(fUsdAttr); +} + +//------------------------------------------------------------------------------ +// UsdAttributeGeneric: +//------------------------------------------------------------------------------ + +UsdAttributeGeneric::UsdAttributeGeneric(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) + : Ufe::AttributeGeneric(item) + , UsdAttribute(item, usdAttr) +{ +} + +/*static*/ +UsdAttributeGeneric::Ptr UsdAttributeGeneric::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeGeneric - Ufe::AttributeGeneric overrides +//------------------------------------------------------------------------------ + +std::string UsdAttributeGeneric::nativeType() const +{ + return fUsdAttr.GetTypeName().GetType().GetTypeName(); +} + +//------------------------------------------------------------------------------ +// UsdAttributeEnumString: +//------------------------------------------------------------------------------ + +UsdAttributeEnumString::UsdAttributeEnumString(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) + : Ufe::AttributeEnumString(item) + , UsdAttribute(item, usdAttr) +{ +} + +/*static*/ +UsdAttributeEnumString::Ptr UsdAttributeEnumString::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeEnumString - Ufe::AttributeEnumString overrides +//------------------------------------------------------------------------------ + +std::string UsdAttributeEnumString::get() const +{ + UFE_ASSERT_MSG(hasValue(), kErrorMsgEnumNoValue); + PXR_NS::VtValue vt; + if (fUsdAttr.Get(&vt) && vt.IsHolding()) + { + TfToken tok = vt.UncheckedGet(); + return tok.GetString(); + } + + UFE_ASSERT_MSG(false, kErrorMsgInvalidType); + return ""; +} + +void UsdAttributeEnumString::set(const std::string& value) +{ + PXR_NS::TfToken dummy; + UFE_ASSERT_MSG(fUsdAttr.Get(&dummy), kErrorMsgInvalidType); + PXR_NS::TfToken tok(value); + bool b = fUsdAttr.Set(tok); + UFE_ASSERT_MSG(b, kErrorMsgFailedSet); +} + +Ufe::AttributeEnumString::EnumValues UsdAttributeEnumString::getEnumValues() const +{ + PXR_NS::TfToken tk(name()); + auto attrDefn = PXR_NS::UsdSchemaRegistry::GetAttributeDefinition(fPrim.GetTypeName(), tk); + if (attrDefn && attrDefn->HasAllowedTokens()) + { + auto tokenArray = attrDefn->GetAllowedTokens(); + std::vector tokenVec(tokenArray.begin(), tokenArray.end()); + EnumValues tokens = PXR_NS::TfToStringVector(tokenVec); + return tokens; + } + + return EnumValues(); +} + +//------------------------------------------------------------------------------ +// TypedUsdAttribute: +//------------------------------------------------------------------------------ + +template +TypedUsdAttribute::TypedUsdAttribute(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) + : Ufe::TypedAttribute(item) + , UsdAttribute(item, usdAttr) +{ +} + +//------------------------------------------------------------------------------ +// TypedUsdAttribute - Ufe::TypedAttribute overrides +//------------------------------------------------------------------------------ + +template<> +std::string TypedUsdAttribute::get() const +{ + if (!hasValue()) return ""; + + PXR_NS::VtValue vt; + if (fUsdAttr.Get(&vt)) + { + // The USDAttribute can be holding either TfToken or string. + if (vt.IsHolding()) + { + TfToken tok = vt.UncheckedGet(); + return tok.GetString(); + } + else if (vt.IsHolding()) + { + return vt.UncheckedGet(); + } + } + + UFE_ASSERT_MSG(false, kErrorMsgInvalidType); + return ""; +} + +template <> +void TypedUsdAttribute::set(const std::string& value) +{ + // We need to figure out if the USDAttribute is holding a TfToken or string. + const PXR_NS::SdfValueTypeName typeName = fUsdAttr.GetTypeName(); + if (typeName.GetHash() == SdfValueTypeNames->String.GetHash()) + { + std::string dummy; + UFE_ASSERT_MSG(fUsdAttr.Get(&dummy), kErrorMsgInvalidType); + bool b = fUsdAttr.Set(value); + UFE_ASSERT_MSG(b, kErrorMsgFailedSet); + return; + } + else if (typeName.GetHash() == SdfValueTypeNames->Token.GetHash()) + { + PXR_NS::TfToken dummy; + UFE_ASSERT_MSG(fUsdAttr.Get(&dummy), kErrorMsgInvalidType); + PXR_NS::TfToken tok(value); + bool b = fUsdAttr.Set(tok); + UFE_ASSERT_MSG(b, kErrorMsgFailedSet); + return; + } + + // If we get here it means the USDAttribute type wasn't TfToken or string. + UFE_ASSERT_MSG(false, kErrorMsgInvalidType); +} + +template<> +Ufe::Color3f TypedUsdAttribute::get() const +{ + return getUsdAttributeVectorAsUfe(fUsdAttr); +} + +// Note: cannot use setUsdAttributeVectorFromUfe since it relies on x/y/z +template<> +void TypedUsdAttribute::set(const Ufe::Color3f& value) +{ + GfVec3f vec; + UFE_ASSERT_MSG(fUsdAttr.Get(&vec), kErrorMsgInvalidType); + vec.Set(value.r(), value.g(), value.b()); + bool b = fUsdAttr.Set(vec); + UFE_ASSERT_MSG(b, kErrorMsgFailedSet); +} + +template<> +Ufe::Vector3i TypedUsdAttribute::get() const +{ + return getUsdAttributeVectorAsUfe(fUsdAttr); +} + +template<> +void TypedUsdAttribute::set(const Ufe::Vector3i& value) +{ + setUsdAttributeVectorFromUfe(fUsdAttr, value); +} + +template<> +Ufe::Vector3f TypedUsdAttribute::get() const +{ + return getUsdAttributeVectorAsUfe(fUsdAttr); +} + +template<> +void TypedUsdAttribute::set(const Ufe::Vector3f& value) +{ + setUsdAttributeVectorFromUfe(fUsdAttr, value); +} + +template<> +Ufe::Vector3d TypedUsdAttribute::get() const +{ + return getUsdAttributeVectorAsUfe(fUsdAttr); +} + +template<> +void TypedUsdAttribute::set(const Ufe::Vector3d& value) +{ + setUsdAttributeVectorFromUfe(fUsdAttr, value); +} + +template +T TypedUsdAttribute::get() const +{ + if (!hasValue()) return T(); + + PXR_NS::VtValue vt; + if (fUsdAttr.Get(&vt) && vt.IsHolding()) + { + return vt.UncheckedGet(); + } + + UFE_ASSERT_MSG(false, kErrorMsgInvalidType); + return T(); +} + +template +void TypedUsdAttribute::set(const T& value) +{ + T dummy; + UFE_ASSERT_MSG(fUsdAttr.Get(&dummy), kErrorMsgInvalidType); + bool b = fUsdAttr.Set(value); + UFE_ASSERT_MSG(b, kErrorMsgFailedSet); +} + +//------------------------------------------------------------------------------ +// UsdAttributeBool: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeBool::Ptr UsdAttributeBool::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeInt: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeInt::Ptr UsdAttributeInt::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeFloat: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeFloat::Ptr UsdAttributeFloat::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeDouble: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeDouble::Ptr UsdAttributeDouble::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeString: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeString::Ptr UsdAttributeString::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeColorFloat3: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeColorFloat3::Ptr UsdAttributeColorFloat3::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeInt3: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeInt3::Ptr UsdAttributeInt3::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeFloat3: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeFloat3::Ptr UsdAttributeFloat3::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +//------------------------------------------------------------------------------ +// UsdAttributeDouble3: +//------------------------------------------------------------------------------ + +/*static*/ +UsdAttributeDouble3::Ptr UsdAttributeDouble3::create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr) +{ + auto attr = std::make_shared(item, usdAttr); + return attr; +} + +#if 0 +// Note: if we were to implement generic attribute setting (via string) this +// would be the way it could be done. +bool UsdAttribute::setValue(const std::string& value) +{ + // Put the input string into a VtValue so we can cast it to the proper type. + PXR_NS::VtValue val(value.c_str()); + + // Attempt to cast the value to what we want. Get a default value for this + // attribute's type name. + PXR_NS::VtValue defVal = fUsdAttr.GetTypeName().GetDefaultValue(); + + // Attempt to cast the given string to the default value's type. + // If casting fails, attempt to continue with the given value. + PXR_NS::VtValue cast = PXR_NS::VtValue::CastToTypeOf(val, defVal); + if (!cast.IsEmpty()) + cast.Swap(val); + + return fUsdAttr.Set(val); +} +#endif + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdAttribute.h b/lib/ufe/UsdAttribute.h new file mode 100644 index 0000000000..005a226338 --- /dev/null +++ b/lib/ufe/UsdAttribute.h @@ -0,0 +1,215 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "UsdSceneItem.h" + +#include "ufe/attribute.h" + +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/attribute.h" + +// Ufe::Attribute overrides (minus the type method) +#define UFE_ATTRIBUTE_OVERRIDES \ + bool hasValue() const override { return UsdAttribute::hasValue(); } \ + std::string name() const override { return UsdAttribute::name(); } \ + std::string documentation() const override { return UsdAttribute::documentation(); } \ + std::string string() const override { return UsdAttribute::string(); } + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Internal helper class to implement the pure virtual methods from Ufe::Attribute. +class UsdAttribute +{ +public: + UsdAttribute(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); + ~UsdAttribute(); + + // Ufe::Attribute override methods that we've mimic'd here. + bool hasValue() const; + std::string name() const; + std::string documentation() const; + std::string string() const; + +public: + PXR_NS::UsdPrim fPrim; + PXR_NS::UsdAttribute fUsdAttr; +}; // UsdAttribute + +//! \brief Interface for USD attributes which don't match any defined type. +class UsdAttributeGeneric : public Ufe::AttributeGeneric, private UsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + UsdAttributeGeneric(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); + + //! Create a UsdAttributeGeneric. + static UsdAttributeGeneric::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); + + // Ufe::Attribute overrides + UFE_ATTRIBUTE_OVERRIDES + + // Ufe::AttributeGeneric overrides + std::string nativeType() const override; +}; // UsdAttributeGeneric + +//! \brief Interface for USD token attributes. +class UsdAttributeEnumString : public Ufe::AttributeEnumString, private UsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + UsdAttributeEnumString(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); + + //! Create a UsdAttributeEnumString. + static UsdAttributeEnumString::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); + + // Ufe::Attribute overrides + UFE_ATTRIBUTE_OVERRIDES + + // Ufe::AttributeEnumString overrides + std::string get() const override; + void set(const std::string& value) override; + EnumValues getEnumValues() const override; +}; // UsdAttributeEnumString + +//! \brief Internal helper template class to implement the get/set methods from Ufe::TypeAttribute. +template +class TypedUsdAttribute : public Ufe::TypedAttribute, private UsdAttribute +{ +public: + TypedUsdAttribute(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); + + // Ufe::Attribute overrides + UFE_ATTRIBUTE_OVERRIDES + + // Ufe::TypedAttribute overrides + T get() const override; + void set(const T& value) override; +}; // TypedUsdAttribute + +//! \brief Interface for USD bool attributes. +class UsdAttributeBool : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeBool. + static UsdAttributeBool::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeBool + +//! \brief Interface for USD int attributes. +class UsdAttributeInt : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeInt. + static UsdAttributeInt::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeInt + +//! \brief Interface for USD float attributes. +class UsdAttributeFloat : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeFloat. + static UsdAttributeFloat::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeFloat + +//! \brief Interface for USD double attributes. +class UsdAttributeDouble : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeDouble. + static UsdAttributeDouble::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeDouble + +//! \brief Interface for USD string/token attributes. +class UsdAttributeString : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeString. + static UsdAttributeString::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeString + +//! \brief Interface for USD RGB color (float) attributes. +class UsdAttributeColorFloat3 : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeColorFloat3. + static UsdAttributeColorFloat3::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeColorFloat3 + +//! \brief Interface for USD Vector3i (int) attributes. +class UsdAttributeInt3 : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeInt3. + static UsdAttributeInt3::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeInt3 + +//! \brief Interface for USD Vector3f (float) attributes. +class UsdAttributeFloat3 : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeFloat3. + static UsdAttributeFloat3::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeFloat3 + +//! \brief Interface for USD Vector3d (double) attributes. +class UsdAttributeDouble3 : public TypedUsdAttribute +{ +public: + typedef std::shared_ptr Ptr; + + using TypedUsdAttribute::TypedUsdAttribute; + + //! Create a UsdAttributeDouble3. + static UsdAttributeDouble3::Ptr create(const UsdSceneItem::Ptr& item, const PXR_NS::UsdAttribute& usdAttr); +}; // UsdAttributeDouble3 + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdAttributes.cpp b/lib/ufe/UsdAttributes.cpp new file mode 100644 index 0000000000..fd9e817fb1 --- /dev/null +++ b/lib/ufe/UsdAttributes.cpp @@ -0,0 +1,249 @@ +// +// Copyright 2019 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. +// + +#include "UsdAttributes.h" + +#include + +#include "pxr/base/tf/token.h" +#include "pxr/usd/usd/schemaRegistry.h" +#include "pxr/usd/sdf/attributeSpec.h" + +// Note: normally we would use this using directive, but here we cannot because +// one of our classes is called UsdAttribute which is exactly the same as +// the one in USD. +// PXR_NAMESPACE_USING_DIRECTIVE + +static constexpr char kErrorMsgUnknown[] = "Unknown UFE attribute type encountered"; +static constexpr char kErrorMsgInvalidAttribute[] = "Invalid USDAttribute!"; + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdAttributes::UsdAttributes(const UsdSceneItem::Ptr& item) + : Ufe::Attributes() + , fItem(item) +{ + fPrim = item->prim(); +} + +UsdAttributes::~UsdAttributes() +{ +} + +/*static*/ +UsdAttributes::Ptr UsdAttributes::create(const UsdSceneItem::Ptr& item) +{ + auto attrs = std::make_shared(item); + return attrs; +} + +//------------------------------------------------------------------------------ +// Ufe::Attributes overrides +//------------------------------------------------------------------------------ + +Ufe::SceneItem::Ptr UsdAttributes::sceneItem() const +{ + return fItem; +} + +Ufe::Attribute::Type UsdAttributes::attributeType(const std::string& name) +{ + PXR_NS::TfToken tok(name); + PXR_NS::UsdAttribute usdAttr = fPrim.GetAttribute(tok); + return getUfeTypeForAttribute(usdAttr); +} + +Ufe::Attribute::Ptr UsdAttributes::attribute(const std::string& name) +{ + // If we've already created an attribute for this name, just return it. + auto iter = fAttributes.find(name); + if (iter != std::end(fAttributes)) + return iter->second; + + // No attribute for the input name was found -> create one. + PXR_NS::TfToken tok(name); + PXR_NS::UsdAttribute usdAttr = fPrim.GetAttribute(tok); + Ufe::Attribute::Type newAttrType = getUfeTypeForAttribute(usdAttr); + Ufe::Attribute::Ptr newAttr; + + if (newAttrType == Ufe::Attribute::kBool) { + newAttr = UsdAttributeBool::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kInt) { + newAttr = UsdAttributeInt::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kFloat) { + newAttr = UsdAttributeFloat::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kDouble) { + newAttr = UsdAttributeDouble::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kString) { + newAttr = UsdAttributeString::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kColorFloat3) { + newAttr = UsdAttributeColorFloat3::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kEnumString) { + newAttr = UsdAttributeEnumString::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kInt3) { + newAttr = UsdAttributeInt3::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kFloat3) { + newAttr = UsdAttributeFloat3::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kDouble3) { + newAttr = UsdAttributeDouble3::create(fItem, usdAttr); + } + else if (newAttrType == Ufe::Attribute::kGeneric) { + newAttr = UsdAttributeGeneric::create(fItem, usdAttr); + } + else { + UFE_ASSERT_MSG(false, kErrorMsgUnknown); + } + fAttributes[name] = newAttr; + return newAttr; +} + +std::vector UsdAttributes::attributeNames() const +{ + std::vector names; + for (const auto& attr : fPrim.GetAttributes()) + { + names.push_back(attr.GetName()); + } + return names; +} + +bool UsdAttributes::hasAttribute(const std::string& name) const +{ + TfToken tkName(name); + return fPrim.HasAttribute(tkName); +} + +Ufe::Attribute::Type UsdAttributes::getUfeTypeForAttribute(const PXR_NS::UsdAttribute& usdAttr) const +{ + // Map the USD type into UFE type. + static const std::unordered_map sUsdTypeToUfe + { + {SdfValueTypeNames->Bool.GetHash(), Ufe::Attribute::kBool}, // bool +// {SdfValueTypeNames->UChar.GetHash(), Ufe::Attribute::kUnknown}, // uint8_t + {SdfValueTypeNames->Int.GetHash(), Ufe::Attribute::kInt}, // int32_t +// {SdfValueTypeNames->UInt.GetHash(), Ufe::Attribute::kUnknown}, // uint32_t +// {SdfValueTypeNames->Int64.GetHash(), Ufe::Attribute::kInt}, // int64_t +// {SdfValueTypeNames->UInt64.GetHash(), Ufe::Attribute::kUnknown}, // uint64_t +// {SdfValueTypeNames->Half.GetHash(), Ufe::Attribute::kUnknown}, // GfHalf + {SdfValueTypeNames->Float.GetHash(), Ufe::Attribute::kFloat}, // float + {SdfValueTypeNames->Double.GetHash(), Ufe::Attribute::kDouble}, // double + {SdfValueTypeNames->String.GetHash(), Ufe::Attribute::kString}, // std::string + {SdfValueTypeNames->Token.GetHash(), Ufe::Attribute::kEnumString}, // TfToken +// {SdfValueTypeNames->Asset.GetHash(), Ufe::Attribute::kUnknown}, // SdfAssetPath +// {SdfValueTypeNames->Int2.GetHash(), Ufe::Attribute::kInt2}, // GfVec2i +// {SdfValueTypeNames->Half2.GetHash(), Ufe::Attribute::kUnknown}, // GfVec2h +// {SdfValueTypeNames->Float2.GetHash(), Ufe::Attribute::kFloat2}, // GfVec2f +// {SdfValueTypeNames->Double2.GetHash(), Ufe::Attribute::kDouble2}, // GfVec2d + {SdfValueTypeNames->Int3.GetHash(), Ufe::Attribute::kInt3}, // GfVec3i +// {SdfValueTypeNames->Half3.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3h + {SdfValueTypeNames->Float3.GetHash(), Ufe::Attribute::kFloat3}, // GfVec3f + {SdfValueTypeNames->Double3.GetHash(), Ufe::Attribute::kDouble3}, // GfVec3d +// {SdfValueTypeNames->Int4.GetHash(), Ufe::Attribute::kInt4}, // GfVec4i +// {SdfValueTypeNames->Half4.GetHash(), Ufe::Attribute::kUnknown}, // GfVec4h +// {SdfValueTypeNames->Float4.GetHash(), Ufe::Attribute::kFloat4}, // GfVec4f +// {SdfValueTypeNames->Double4.GetHash(), Ufe::Attribute::kDouble4}, // GfVec4d +// {SdfValueTypeNames->Point3h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3h +// {SdfValueTypeNames->Point3f.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3f +// {SdfValueTypeNames->Point3d.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3d +// {SdfValueTypeNames->Vector3h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3h +// {SdfValueTypeNames->Vector3f.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3f +// {SdfValueTypeNames->Vector3d.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3d +// {SdfValueTypeNames->Normal3h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3h +// {SdfValueTypeNames->Normal3f.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3f +// {SdfValueTypeNames->Normal3d.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3d +// {SdfValueTypeNames->Color3h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3h + {SdfValueTypeNames->Color3f.GetHash(), Ufe::Attribute::kColorFloat3}, // GfVec3f + {SdfValueTypeNames->Color3d.GetHash(), Ufe::Attribute::kColorFloat3}, // GfVec3d +// {SdfValueTypeNames->Color4h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec4h +// {SdfValueTypeNames->Color4f.GetHash(), Ufe::Attribute::kUnknown}, // GfVec4f +// {SdfValueTypeNames->Color4d.GetHash(), Ufe::Attribute::kUnknown}, // GfVec4d +// {SdfValueTypeNames->Quath.GetHash(), Ufe::Attribute::kUnknown}, // GfQuath +// {SdfValueTypeNames->Quatf.GetHash(), Ufe::Attribute::kUnknown}, // GfQuatf +// {SdfValueTypeNames->Quatd.GetHash(), Ufe::Attribute::kUnknown}, // GfQuatd +// {SdfValueTypeNames->Matrix2d.GetHash(), Ufe::Attribute::kUnknown}, // GfMatrix2d +// {SdfValueTypeNames->Matrix3d.GetHash(), Ufe::Attribute::kUnknown}, // GfMatrix3d +// {SdfValueTypeNames->Matrix4d.GetHash(), Ufe::Attribute::kUnknown}, // GfMatrix4d +// {SdfValueTypeNames->Frame4d.GetHash(), Ufe::Attribute::kUnknown}, // GfMatrix4d +// {SdfValueTypeNames->TexCoord2f.GetHash(), Ufe::Attribute::kUnknown}, // GfVec2f +// {SdfValueTypeNames->TexCoord2d.GetHash(), Ufe::Attribute::kUnknown}, // GfVec2d +// {SdfValueTypeNames->TexCoord2h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec2h +// {SdfValueTypeNames->TexCoord3f.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3f +// {SdfValueTypeNames->TexCoord3d.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3d +// {SdfValueTypeNames->TexCoord3h.GetHash(), Ufe::Attribute::kUnknown}, // GfVec3h +// To add? +// SdfValueTypeName BoolArray; +// SdfValueTypeName UCharArray, IntArray, UIntArray, Int64Array, UInt64Array; +// SdfValueTypeName HalfArray, FloatArray, DoubleArray; +// SdfValueTypeName StringArray, TokenArray, AssetArray; +// SdfValueTypeName Int2Array, Int3Array, Int4Array; +// SdfValueTypeName Half2Array, Half3Array, Half4Array; +// SdfValueTypeName Float2Array, Float3Array, Float4Array; +// SdfValueTypeName Double2Array, Double3Array, Double4Array; +// SdfValueTypeName Point3hArray, Point3fArray, Point3dArray; +// SdfValueTypeName Vector3hArray, Vector3fArray, Vector3dArray; +// SdfValueTypeName Normal3hArray, Normal3fArray, Normal3dArray; +// SdfValueTypeName Color3hArray, Color3fArray, Color3dArray; +// SdfValueTypeName Color4hArray, Color4fArray, Color4dArray; +// SdfValueTypeName QuathArray, QuatfArray, QuatdArray; +// SdfValueTypeName Matrix2dArray, Matrix3dArray, Matrix4dArray; +// SdfValueTypeName Frame4dArray; +// SdfValueTypeName TexCoord2hArray, TexCoord2fArray, TexCoord2dArray; +// SdfValueTypeName TexCoord3hArray, TexCoord3fArray, TexCoord3dArray; + }; + + if (usdAttr.IsValid()) + { + const PXR_NS::SdfValueTypeName typeName = usdAttr.GetTypeName(); + const auto iter = sUsdTypeToUfe.find(typeName.GetHash()); + + // ** TEMP - for debugging purposes only + // std::string cppName = typeName.GetCPPTypeName(); + + if (iter != sUsdTypeToUfe.end()) + { + // Special case for TfToken -> Enum. If it doesn't have any allowed + // tokens, then use String instead. + if (iter->second == Ufe::Attribute::kEnumString) + { + auto attrDefn = PXR_NS::UsdSchemaRegistry::GetAttributeDefinition(fPrim.GetTypeName(), usdAttr.GetName()); + if (!attrDefn || !attrDefn->HasAllowedTokens()) + return Ufe::Attribute::kString; + } + + return iter->second; + } + + // We use the generic type to show a Usd attribute's value and native type. + return Ufe::Attribute::kGeneric; + } + + UFE_ASSERT_MSG(false, kErrorMsgInvalidAttribute); + return Ufe::Attribute::kInvalid; +} + + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdAttributes.h b/lib/ufe/UsdAttributes.h new file mode 100644 index 0000000000..c16cefb827 --- /dev/null +++ b/lib/ufe/UsdAttributes.h @@ -0,0 +1,70 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" +#include "UsdAttribute.h" + +#include "ufe/attributes.h" + +#include "pxr/usd/usd/prim.h" + +#include + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface for USD Attributes. +class UsdAttributes : public Ufe::Attributes +{ +public: + typedef std::shared_ptr Ptr; + + UsdAttributes(const UsdSceneItem::Ptr& item); + ~UsdAttributes() override; + + // Delete the copy/move constructors assignment operators. + UsdAttributes(const UsdAttributes&) = delete; + UsdAttributes& operator=(const UsdAttributes&) = delete; + UsdAttributes(UsdAttributes&&) = delete; + UsdAttributes& operator=(UsdAttributes&&) = delete; + + //! Create a UsdAttributes. + static UsdAttributes::Ptr create(const UsdSceneItem::Ptr& item); + + // Ufe::Attributes overrides + Ufe::SceneItem::Ptr sceneItem() const override; + Ufe::Attribute::Type attributeType(const std::string& name) override; + Ufe::Attribute::Ptr attribute(const std::string& name) override; + std::vector attributeNames() const override; + bool hasAttribute(const std::string& name) const override; + +private: + Ufe::Attribute::Type getUfeTypeForAttribute(const PXR_NS::UsdAttribute& usdAttr) const; + +private: + UsdSceneItem::Ptr fItem; + PXR_NS::UsdPrim fPrim; + + typedef std::unordered_map AttributeMap; + AttributeMap fAttributes; + +}; // UsdAttributes + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdAttributesHandler.cpp b/lib/ufe/UsdAttributesHandler.cpp new file mode 100644 index 0000000000..0366ba1971 --- /dev/null +++ b/lib/ufe/UsdAttributesHandler.cpp @@ -0,0 +1,53 @@ +// +// Copyright 2019 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. +// + +#include "UsdAttributesHandler.h" +#include "UsdSceneItem.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdAttributesHandler::UsdAttributesHandler() + : Ufe::AttributesHandler() +{ +} + +UsdAttributesHandler::~UsdAttributesHandler() +{ +} + +/*static*/ +UsdAttributesHandler::Ptr UsdAttributesHandler::create() +{ + return std::make_shared(); +} + +//------------------------------------------------------------------------------ +// Ufe::AttributesHandler overrides +//------------------------------------------------------------------------------ + +Ufe::Attributes::Ptr UsdAttributesHandler::attributes(const Ufe::SceneItem::Ptr& item) const +{ + UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast(item); +#if !defined(NDEBUG) + assert(usdItem); +#endif + auto usdAttributes = UsdAttributes::create(usdItem); + return usdAttributes; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdAttributesHandler.h b/lib/ufe/UsdAttributesHandler.h new file mode 100644 index 0000000000..36fc2961a5 --- /dev/null +++ b/lib/ufe/UsdAttributesHandler.h @@ -0,0 +1,53 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdAttributes.h" + +#include "ufe/attributesHandler.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface to create the USD Attributes interface objects. +class UsdAttributesHandler : public Ufe::AttributesHandler +{ +public: + typedef std::shared_ptr Ptr; + + UsdAttributesHandler(); + ~UsdAttributesHandler(); + + // Delete the copy/move constructors assignment operators. + UsdAttributesHandler(const UsdAttributesHandler&) = delete; + UsdAttributesHandler& operator=(const UsdAttributesHandler&) = delete; + UsdAttributesHandler(UsdAttributesHandler&&) = delete; + UsdAttributesHandler& operator=(UsdAttributesHandler&&) = delete; + + //! Create a UsdAttributesHandler. + static UsdAttributesHandler::Ptr create(); + + // Ufe::AttributesHandler overrides + Ufe::Attributes::Ptr attributes(const Ufe::SceneItem::Ptr& item) const override; + +private: + +}; // UsdAttributesHandler + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdHierarchy.cpp b/lib/ufe/UsdHierarchy.cpp new file mode 100644 index 0000000000..243fb7a065 --- /dev/null +++ b/lib/ufe/UsdHierarchy.cpp @@ -0,0 +1,183 @@ +// +// Copyright 2019 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. +// + +#include "UsdHierarchy.h" +#include "UsdUndoCreateGroupCommand.h" +#include "private/Utils.h" +#include "Utils.h" +#include "private/InPathChange.h" + +#include "ufe/sceneNotification.h" +#include "ufe/scene.h" + +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/sdf/layer.h" +#include "pxr/usd/sdf/copyUtils.h" +#include "pxr/usd/usdGeom/xform.h" +#include "pxr/base/tf/stringUtils.h" + +#include +#include + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdHierarchy::UsdHierarchy() + : Ufe::Hierarchy() +{ +} + +UsdHierarchy::~UsdHierarchy() +{ +} + +/*static*/ +UsdHierarchy::Ptr UsdHierarchy::create() +{ + return std::make_shared(); +} + +void UsdHierarchy::setItem(UsdSceneItem::Ptr item) +{ + fPrim = item->prim(); + fItem = item; +} + +const Ufe::Path& UsdHierarchy::path() const +{ + return fItem->path(); +} + +UsdSceneItem::Ptr UsdHierarchy::usdSceneItem() const +{ + return fItem; +} + +//------------------------------------------------------------------------------ +// Ufe::Hierarchy overrides +//------------------------------------------------------------------------------ + +Ufe::SceneItem::Ptr UsdHierarchy::sceneItem() const +{ + return fItem; +} + +bool UsdHierarchy::hasChildren() const +{ + return !fPrim.GetChildren().empty(); +} + +Ufe::SceneItemList UsdHierarchy::children() const +{ + // Return USD children only, i.e. children within this run-time. + Ufe::SceneItemList children; + for (auto child : fPrim.GetChildren()) + { + children.push_back(UsdSceneItem::create(fItem->path() + child.GetName(), child)); + } + return children; +} + +Ufe::SceneItem::Ptr UsdHierarchy::parent() const +{ + return UsdSceneItem::create(fItem->path().pop(), fPrim.GetParent()); +} + +Ufe::AppendedChild UsdHierarchy::appendChild(const Ufe::SceneItem::Ptr& child) +{ + auto usdChild = std::dynamic_pointer_cast(child); +#if !defined(NDEBUG) + assert(usdChild); +#endif + + // First, check if we need to rename the child. + std::string childName = uniqueChildName(sceneItem(), child->path()); + + // Set up all paths to perform the reparent. + auto prim = usdChild->prim(); + auto stage = prim.GetStage(); + auto ufeSrcPath = usdChild->path(); + auto usdSrcPath = prim.GetPath(); + auto ufeDstPath = fItem->path() + childName; + auto usdDstPath = fPrim.GetPath().AppendChild(TfToken(childName)); + SdfLayerHandle layer = defPrimSpecLayer(prim); + if (!layer) { + std::string err = TfStringPrintf("No prim found at %s", usdSrcPath.GetString().c_str()); + throw std::runtime_error(err.c_str()); + } + + // In USD, reparent is implemented like rename, using copy to + // destination, then remove from source. + // See UsdUndoRenameCommand._rename comments for details. + InPathChange pc; + + auto status = SdfCopySpec(layer, usdSrcPath, layer, usdDstPath); + if (!status) { + std::string err = TfStringPrintf("Appending child %s to parent %s failed.", + ufeSrcPath.string().c_str(), fItem->path().string().c_str()); + throw std::runtime_error(err.c_str()); + } + + stage->RemovePrim(usdSrcPath); + auto ufeDstItem = UsdSceneItem::create(ufeDstPath, ufePathToPrim(ufeDstPath)); + auto notification = Ufe::ObjectReparent(ufeDstItem, ufeSrcPath); + Ufe::Scene::notifyObjectPathChange(notification); + + // FIXME No idea how to get the child prim index yet. PPT, 16-Aug-2018. + return Ufe::AppendedChild(ufeDstItem, ufeSrcPath, 0); +} + +#ifdef UFE_V2_FEATURES_AVAILABLE +// Create a transform. +Ufe::SceneItem::Ptr UsdHierarchy::createGroup(const Ufe::PathComponent& name) const +{ + // According to Pixar, the following is more efficient when creating + // multiple transforms, because of the use of ChangeBlock(): + // with Sdf.ChangeBlock(): + // primSpec = Sdf.CreatePrimInLayer(layer, usdPath) + // primSpec.specifier = Sdf.SpecifierDef + // primSpec.typeName = 'Xform' + + // Rename the new group for uniqueness, if needed. + Ufe::Path newPath = fItem->path() + name; + auto childName = uniqueChildName(sceneItem(), newPath); + + // Next, get the stage corresponding to the new path. + auto segments = newPath.getSegments(); + TEST_USD_PATH(segments, newPath); + auto dagSegment = segments[0]; + auto stage = getStage(Ufe::Path(dagSegment)); + + // Build the corresponding USD path and create the USD group prim. + auto usdPath = fItem->prim().GetPath().AppendChild(TfToken(childName)); + auto prim = UsdGeomXform::Define(stage, usdPath).GetPrim(); + + // Create a UFE scene item from the prim. + auto ufeChildPath = fItem->path() + childName; + return UsdSceneItem::create(ufeChildPath, prim); +} + +Ufe::Group UsdHierarchy::createGroupCmd(const Ufe::PathComponent& name) const +{ + auto createGroupCmd = UsdUndoCreateGroupCommand::create(fItem, name); + createGroupCmd->execute(); + return Ufe::Group(createGroupCmd->group(), createGroupCmd); +} +#endif + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdHierarchy.h b/lib/ufe/UsdHierarchy.h new file mode 100644 index 0000000000..8b6ff1c6fe --- /dev/null +++ b/lib/ufe/UsdHierarchy.h @@ -0,0 +1,73 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" +#include "UsdSceneItem.h" + +#include "ufe/hierarchy.h" +#include "ufe/path.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief USD run-time hierarchy interface +/*! + This class implements the hierarchy interface for normal USD prims, using + standard USD calls to obtain a prim's parent and children. +*/ +class MAYAUSD_CORE_PUBLIC UsdHierarchy : public Ufe::Hierarchy +{ +public: + typedef std::shared_ptr Ptr; + + UsdHierarchy(); + ~UsdHierarchy() override; + + // Delete the copy/move constructors assignment operators. + UsdHierarchy(const UsdHierarchy&) = delete; + UsdHierarchy& operator=(const UsdHierarchy&) = delete; + UsdHierarchy(UsdHierarchy&&) = delete; + UsdHierarchy& operator=(UsdHierarchy&&) = delete; + + //! Create a UsdHierarchy. + static UsdHierarchy::Ptr create(); + + void setItem(UsdSceneItem::Ptr item); + const Ufe::Path& path() const; + + UsdSceneItem::Ptr usdSceneItem() const; + + // Ufe::Hierarchy overrides + Ufe::SceneItem::Ptr sceneItem() const override; + bool hasChildren() const override; + Ufe::SceneItemList children() const override; + Ufe::SceneItem::Ptr parent() const override; + Ufe::AppendedChild appendChild(const Ufe::SceneItem::Ptr& child) override; + +#ifdef UFE_V2_FEATURES_AVAILABLE + Ufe::SceneItem::Ptr createGroup(const Ufe::PathComponent& name) const override; + Ufe::Group createGroupCmd(const Ufe::PathComponent& name) const override; +#endif + +private: + UsdSceneItem::Ptr fItem; + UsdPrim fPrim; + +}; // UsdHierarchy + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdHierarchyHandler.cpp b/lib/ufe/UsdHierarchyHandler.cpp new file mode 100644 index 0000000000..240ed3ff94 --- /dev/null +++ b/lib/ufe/UsdHierarchyHandler.cpp @@ -0,0 +1,67 @@ +// +// Copyright 2019 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. +// + +#include "UsdHierarchyHandler.h" +#include "UsdSceneItem.h" +#include "Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdHierarchyHandler::UsdHierarchyHandler() + : Ufe::HierarchyHandler() +{ + fUsdRootChildHierarchy = UsdRootChildHierarchy::create(); + fUsdHierarchy = UsdHierarchy::create(); +} + +UsdHierarchyHandler::~UsdHierarchyHandler() +{ +} + +/*static*/ +UsdHierarchyHandler::Ptr UsdHierarchyHandler::create() +{ + return std::make_shared(); +} + +//------------------------------------------------------------------------------ +// UsdHierarchyHandler overrides +//------------------------------------------------------------------------------ + +Ufe::Hierarchy::Ptr UsdHierarchyHandler::hierarchy(const Ufe::SceneItem::Ptr& item) const +{ + UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast(item); + if(isRootChild(usdItem->path())) + { + fUsdRootChildHierarchy->setItem(usdItem); + return fUsdRootChildHierarchy; + } + else + { + fUsdHierarchy->setItem(usdItem); + return fUsdHierarchy; + } +} + +Ufe::SceneItem::Ptr UsdHierarchyHandler::createItem(const Ufe::Path& path) const +{ + const UsdPrim prim = ufePathToPrim(path); + return prim.IsValid() ? UsdSceneItem::create(path, prim) : nullptr; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdHierarchyHandler.h b/lib/ufe/UsdHierarchyHandler.h new file mode 100644 index 0000000000..3850417b2b --- /dev/null +++ b/lib/ufe/UsdHierarchyHandler.h @@ -0,0 +1,66 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdHierarchy.h" +#include "UsdRootChildHierarchy.h" + +#include "ufe/hierarchyHandler.h" + +//PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief USD run-time hierarchy handler. +/*! + This hierarchy handler is the standard USD run-time hierarchy handler. Its + only special behavior is to return a UsdRootChildHierarchy interface object + if it is asked for a hierarchy interface for a child of the USD root prim. + These prims are special because we define their parent to be the Maya USD + gateway node, which the UsdRootChildHierarchy interface implements. + */ +class MAYAUSD_CORE_PUBLIC UsdHierarchyHandler : public Ufe::HierarchyHandler +{ +public: + typedef std::shared_ptr Ptr; + + UsdHierarchyHandler(); + ~UsdHierarchyHandler() override; + + // Delete the copy/move constructors assignment operators. + UsdHierarchyHandler(const UsdHierarchyHandler&) = delete; + UsdHierarchyHandler& operator=(const UsdHierarchyHandler&) = delete; + UsdHierarchyHandler(UsdHierarchyHandler&&) = delete; + UsdHierarchyHandler& operator=(UsdHierarchyHandler&&) = delete; + + //! Create a UsdHierarchyHandler. + static UsdHierarchyHandler::Ptr create(); + + // UsdHierarchyHandler overrides + Ufe::Hierarchy::Ptr hierarchy(const Ufe::SceneItem::Ptr& item) const override; + Ufe::SceneItem::Ptr createItem(const Ufe::Path& path) const override; + +private: + UsdRootChildHierarchy::Ptr fUsdRootChildHierarchy; + UsdHierarchy::Ptr fUsdHierarchy; + +}; // UsdHierarchyHandler + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdRootChildHierarchy.cpp b/lib/ufe/UsdRootChildHierarchy.cpp new file mode 100644 index 0000000000..ef4c260ecb --- /dev/null +++ b/lib/ufe/UsdRootChildHierarchy.cpp @@ -0,0 +1,68 @@ +// +// Copyright 2019 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. +// + +#include "UsdRootChildHierarchy.h" + +#include "ufe/runTimeMgr.h" + +#include + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ +extern Ufe::Rtid g_MayaRtid; +const std::string kNotGatewayNodePath = "Tail of path %s is not a gateway node."; + +UsdRootChildHierarchy::UsdRootChildHierarchy() + : UsdHierarchy() +{ +} + +UsdRootChildHierarchy::~UsdRootChildHierarchy() +{ +} + +/*static*/ +UsdRootChildHierarchy::Ptr UsdRootChildHierarchy::create() +{ + return std::make_shared(); +} + +//------------------------------------------------------------------------------ +// Ufe::Hierarchy overrides +//------------------------------------------------------------------------------ + +Ufe::SceneItem::Ptr UsdRootChildHierarchy::parent() const +{ + // If we're a child of the root, our parent node in the path is a Maya + // node. Ask the Maya hierarchy interface to create a selection item + // for that path. + auto parentPath = path().pop(); +#if !defined(NDEBUG) + assert(parentPath.runTimeId() == g_MayaRtid); +#endif + if (parentPath.runTimeId() != g_MayaRtid) + TF_WARN(kNotGatewayNodePath.c_str(), path().string().c_str()); + + auto mayaHierarchyHandler = Ufe::RunTimeMgr::instance().hierarchyHandler(g_MayaRtid); + return mayaHierarchyHandler->createItem(parentPath); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdRootChildHierarchy.h b/lib/ufe/UsdRootChildHierarchy.h new file mode 100644 index 0000000000..ab63f2215c --- /dev/null +++ b/lib/ufe/UsdRootChildHierarchy.h @@ -0,0 +1,55 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdHierarchy.h" + +//PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief USD run-time hierarchy interface for children of the USD root prim. +/*! + This class modifies its base class implementation to return the Maya USD + gateway node as parent of USD prims that are children of the USD root prim. + */ +class MAYAUSD_CORE_PUBLIC UsdRootChildHierarchy : public UsdHierarchy +{ +public: + typedef std::shared_ptr Ptr; + + UsdRootChildHierarchy(); + ~UsdRootChildHierarchy() override; + + // Delete the copy/move constructors assignment operators. + UsdRootChildHierarchy(const UsdRootChildHierarchy&) = delete; + UsdRootChildHierarchy& operator=(const UsdRootChildHierarchy&) = delete; + UsdRootChildHierarchy(UsdRootChildHierarchy&&) = delete; + UsdRootChildHierarchy& operator=(UsdRootChildHierarchy&&) = delete; + + //! Create a UsdRootChildHierarchy. + static UsdRootChildHierarchy::Ptr create(); + + // Ufe::Hierarchy overrides + Ufe::SceneItem::Ptr parent() const override; + +}; // UsdRootChildHierarchy + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdRotatePivotTranslateUndoableCommand.cpp b/lib/ufe/UsdRotatePivotTranslateUndoableCommand.cpp new file mode 100644 index 0000000000..68eb56bb72 --- /dev/null +++ b/lib/ufe/UsdRotatePivotTranslateUndoableCommand.cpp @@ -0,0 +1,77 @@ +// +// Copyright 2019 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. +// + +#include "UsdRotatePivotTranslateUndoableCommand.h" +#include "private/Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdRotatePivotTranslateUndoableCommand::UsdRotatePivotTranslateUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) + : Ufe::TranslateUndoableCommand(item) + , fPrim(prim) + , fPath(ufePath) + , fNoPivotOp(false) +{ + // Prim does not have a pivot translate attribute + const TfToken xpivot("xformOp:translate:pivot"); + if (!fPrim.HasAttribute(xpivot)) + { + fNoPivotOp = true; + // Add an empty pivot translate. + rotatePivotTranslateOp(fPrim, fPath, 0, 0, 0); + } + + fPivotAttrib = fPrim.GetAttribute(xpivot); + fPivotAttrib.Get(&fPrevPivotValue); +} + +UsdRotatePivotTranslateUndoableCommand::~UsdRotatePivotTranslateUndoableCommand() +{ +} + +/*static*/ +UsdRotatePivotTranslateUndoableCommand::Ptr UsdRotatePivotTranslateUndoableCommand::create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) +{ + return std::make_shared(prim, ufePath, item); +} + +void UsdRotatePivotTranslateUndoableCommand::undo() +{ + fPivotAttrib.Set(fPrevPivotValue); + // Todo : We would want to remove the xformOp + // (SD-06/07/2018) Haven't found a clean way to do it - would need to investigate +} + +void UsdRotatePivotTranslateUndoableCommand::redo() +{ + // No-op, use move to translate the rotate pivot of the object. + // The Maya move command directly invokes our translate() method in its + // redoIt(), which is invoked both for the inital move and the redo. +} + +//------------------------------------------------------------------------------ +// Ufe::TranslateUndoableCommand overrides +//------------------------------------------------------------------------------ + +bool UsdRotatePivotTranslateUndoableCommand::translate(double x, double y, double z) +{ + rotatePivotTranslateOp(fPrim, fPath, x, y, z); + return true; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdRotatePivotTranslateUndoableCommand.h b/lib/ufe/UsdRotatePivotTranslateUndoableCommand.h new file mode 100644 index 0000000000..0c323848ef --- /dev/null +++ b/lib/ufe/UsdRotatePivotTranslateUndoableCommand.h @@ -0,0 +1,65 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/transform3dUndoableCommands.h" + +#include "pxr/usd/usd/attribute.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Absolute translation command of the given prim's rotate pivot. +/*! + Ability to perform undo to restore the original pivot value. + */ +class MAYAUSD_CORE_PUBLIC UsdRotatePivotTranslateUndoableCommand : public Ufe::TranslateUndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdRotatePivotTranslateUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + ~UsdRotatePivotTranslateUndoableCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdRotatePivotTranslateUndoableCommand(const UsdRotatePivotTranslateUndoableCommand&) = delete; + UsdRotatePivotTranslateUndoableCommand& operator=(const UsdRotatePivotTranslateUndoableCommand&) = delete; + UsdRotatePivotTranslateUndoableCommand(UsdRotatePivotTranslateUndoableCommand&&) = delete; + UsdRotatePivotTranslateUndoableCommand& operator=(UsdRotatePivotTranslateUndoableCommand&&) = delete; + + //! Create a UsdRotatePivotTranslateUndoableCommand from a USD prim, UFE path and UFE scene item. + static UsdRotatePivotTranslateUndoableCommand::Ptr create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + + // Ufe::TranslateUndoableCommand overrides + void undo() override; + void redo() override; + bool translate(double x, double y, double z) override; + +private: + UsdPrim fPrim; + UsdAttribute fPivotAttrib; + GfVec3f fPrevPivotValue; + Ufe::Path fPath; + bool fNoPivotOp; + +}; // UsdRotatePivotTranslateUndoableCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdRotateUndoableCommand.cpp b/lib/ufe/UsdRotateUndoableCommand.cpp new file mode 100644 index 0000000000..ea5663d074 --- /dev/null +++ b/lib/ufe/UsdRotateUndoableCommand.cpp @@ -0,0 +1,102 @@ +// +// Copyright 2019 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. +// + +#include "UsdRotateUndoableCommand.h" +#include "private/Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdRotateUndoableCommand::UsdRotateUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) + : Ufe::RotateUndoableCommand(item) + , fPrim(prim) + , fPath(ufePath) + , fNoRotateOp(false) +{ + // Since we want to change xformOp:rotateXYZ, and we need to store the prevRotate for + // undo purpose, we need to make sure we convert it to common API xformOps (In case we have + // rotateX, rotateY or rotateZ ops) + try { + convertToCompatibleCommonAPI(prim); + } + catch (...) { + // Since Maya cannot catch this error at this moment, store it until we actually rotate + fFailedInit = std::current_exception(); // capture + return; + } + + // Prim does not have a rotateXYZ attribute + const TfToken xrot("xformOp:rotateXYZ"); + if (!fPrim.HasAttribute(xrot)) + { + rotateOp(fPrim, fPath, 0, 0, 0); // Add an empty rotate + fNoRotateOp = true; + } + + fRotateAttrib = fPrim.GetAttribute(xrot); + fRotateAttrib.Get(&fPrevRotateValue); +} + +UsdRotateUndoableCommand::~UsdRotateUndoableCommand() +{ +} + +/*static*/ +UsdRotateUndoableCommand::Ptr UsdRotateUndoableCommand::create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) +{ + return std::make_shared(prim, ufePath, item); +} + +void UsdRotateUndoableCommand::undo() +{ + // Check if initialization went ok. + if (!fFailedInit) + { + fRotateAttrib.Set(fPrevRotateValue); + } + // Todo : We would want to remove the xformOp + // (SD-06/07/2018) Haven't found a clean way to do it - would need to investigate +} + +void UsdRotateUndoableCommand::redo() +{ + perform(); +} + +void UsdRotateUndoableCommand::perform() +{ + // No-op, use rotate to move the object + // The Maya rotate command directly invokes our rotate() method in its + // redoIt(), which is invoked both for the inital rotate and the redo. +} + +//------------------------------------------------------------------------------ +// Ufe::RotateUndoableCommand overrides +//------------------------------------------------------------------------------ + +bool UsdRotateUndoableCommand::rotate(double x, double y, double z) +{ + // Fail early - Initialization did not go as expected. + if (fFailedInit) + { + std::rethrow_exception(fFailedInit); + } + rotateOp(fPrim, fPath, x, y, z); + return true; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdRotateUndoableCommand.h b/lib/ufe/UsdRotateUndoableCommand.h new file mode 100644 index 0000000000..90c32cbd1c --- /dev/null +++ b/lib/ufe/UsdRotateUndoableCommand.h @@ -0,0 +1,71 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/transform3dUndoableCommands.h" + +#include "pxr/usd/usd/attribute.h" + +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Absolute rotation command of the given prim. +/*! + Ability to perform undo to restore the original rotation value. + As of 06/07/2018, redo is a no op as Maya re-does the operation for redo + */ +class MAYAUSD_CORE_PUBLIC UsdRotateUndoableCommand : public Ufe::RotateUndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdRotateUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + ~UsdRotateUndoableCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdRotateUndoableCommand(const UsdRotateUndoableCommand&) = delete; + UsdRotateUndoableCommand& operator=(const UsdRotateUndoableCommand&) = delete; + UsdRotateUndoableCommand(UsdRotateUndoableCommand&&) = delete; + UsdRotateUndoableCommand& operator=(UsdRotateUndoableCommand&&) = delete; + + //! Create a UsdRotateUndoableCommand from a USD prim, UFE path and UFE scene item. + static UsdRotateUndoableCommand::Ptr create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + + // Ufe::RotateUndoableCommand overrides + void undo() override; + void redo() override; + bool rotate(double x, double y, double z) override; + +private: + void perform(); + +private: + UsdPrim fPrim; + Ufe::Path fPath; + UsdAttribute fRotateAttrib; + GfVec3f fPrevRotateValue; + std::exception_ptr fFailedInit; + bool fNoRotateOp; +}; // UsdRotateUndoableCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdScaleUndoableCommand.cpp b/lib/ufe/UsdScaleUndoableCommand.cpp new file mode 100644 index 0000000000..ee4f93156f --- /dev/null +++ b/lib/ufe/UsdScaleUndoableCommand.cpp @@ -0,0 +1,82 @@ +// +// Copyright 2019 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. +// + +#include "UsdScaleUndoableCommand.h" +#include "private/Utils.h" +#include "Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdScaleUndoableCommand::UsdScaleUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) + : Ufe::ScaleUndoableCommand(item) + , fPrim(prim) + , fPath(ufePath) + , fNoScaleOp(false) +{ + // Prim does not have a scale attribute + const TfToken xscale("xformOp:scale"); + if (!fPrim.HasAttribute(xscale)) + { + fNoScaleOp = true; + scaleOp(fPrim, fPath, 1, 1, 1); // Add a neutral scale xformOp. + } + + fScaleAttrib = fPrim.GetAttribute(xscale); + fScaleAttrib.Get(&fPrevScaleValue); +} + +UsdScaleUndoableCommand::~UsdScaleUndoableCommand() +{ +} + +/*static*/ +UsdScaleUndoableCommand::Ptr UsdScaleUndoableCommand::create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) +{ + return std::make_shared(prim, ufePath, item); +} + +void UsdScaleUndoableCommand::undo() +{ + fScaleAttrib.Set(fPrevScaleValue); + // Todo : We would want to remove the xformOp + // (SD-06/07/2018) Haven't found a clean way to do it - would need to investigate +} + +void UsdScaleUndoableCommand::redo() +{ + perform(); +} + +void UsdScaleUndoableCommand::perform() +{ + // No-op, use scale to scale the object. + // The Maya scale command directly invokes our scale() method in its + // redoIt(), which is invoked both for the inital scale and the redo. +} + +//------------------------------------------------------------------------------ +// Ufe::ScaleUndoableCommand overrides +//------------------------------------------------------------------------------ + +bool UsdScaleUndoableCommand::scale(double x, double y, double z) +{ + scaleOp(fPrim, fPath, x, y, z); + return true; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdScaleUndoableCommand.h b/lib/ufe/UsdScaleUndoableCommand.h new file mode 100644 index 0000000000..d24f430fd0 --- /dev/null +++ b/lib/ufe/UsdScaleUndoableCommand.h @@ -0,0 +1,68 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/transform3dUndoableCommands.h" + +#include "pxr/usd/usd/attribute.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Absolute scale command of the given prim. +/*! + Ability to perform undo to restore the original scale value. + As of 06/07/2018, redo is a no op as Maya re-does the operation for redo + */ +class MAYAUSD_CORE_PUBLIC UsdScaleUndoableCommand : public Ufe::ScaleUndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdScaleUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + ~UsdScaleUndoableCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdScaleUndoableCommand(const UsdScaleUndoableCommand&) = delete; + UsdScaleUndoableCommand& operator=(const UsdScaleUndoableCommand&) = delete; + UsdScaleUndoableCommand(UsdScaleUndoableCommand&&) = delete; + UsdScaleUndoableCommand& operator=(UsdScaleUndoableCommand&&) = delete; + + //! Create a UsdScaleUndoableCommand from a USD prim, UFE path and UFE scene item. + static UsdScaleUndoableCommand::Ptr create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + + // Ufe::ScaleUndoableCommand overrides + void undo() override; + void redo() override; + bool scale(double x, double y, double z) override; + +private: + void perform(); + +private: + UsdPrim fPrim; + UsdAttribute fScaleAttrib; + GfVec3f fPrevScaleValue; + Ufe::Path fPath; + bool fNoScaleOp; +}; // UsdScaleUndoableCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdSceneItem.cpp b/lib/ufe/UsdSceneItem.cpp new file mode 100644 index 0000000000..a75bbf1658 --- /dev/null +++ b/lib/ufe/UsdSceneItem.cpp @@ -0,0 +1,53 @@ +// +// Copyright 2019 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. +// + +#include "UsdSceneItem.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdSceneItem::UsdSceneItem(const Ufe::Path& path, const UsdPrim& prim) + : Ufe::SceneItem(path) + , fPrim(prim) +{ +} + +UsdSceneItem::~UsdSceneItem() +{ +} + +/*static*/ +UsdSceneItem::Ptr UsdSceneItem::create(const Ufe::Path& path, const UsdPrim& prim) +{ + return std::make_shared(path, prim); +} + +const UsdPrim& UsdSceneItem::prim() const +{ + return fPrim; +} + +//------------------------------------------------------------------------------ +// Ufe::SceneItem overrides +//------------------------------------------------------------------------------ + +std::string UsdSceneItem::nodeType() const +{ + return fPrim.GetTypeName(); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdSceneItem.h b/lib/ufe/UsdSceneItem.h new file mode 100644 index 0000000000..3730373993 --- /dev/null +++ b/lib/ufe/UsdSceneItem.h @@ -0,0 +1,57 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/sceneItem.h" + +#include "pxr/usd/usd/prim.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief USD run-time scene item interface +class MAYAUSD_CORE_PUBLIC UsdSceneItem : public Ufe::SceneItem +{ +public: + typedef std::shared_ptr Ptr; + + UsdSceneItem(const Ufe::Path& path, const UsdPrim& prim); + ~UsdSceneItem() override; + + // Delete the copy/move constructors assignment operators. + UsdSceneItem(const UsdSceneItem&) = delete; + UsdSceneItem& operator=(const UsdSceneItem&) = delete; + UsdSceneItem(UsdSceneItem&&) = delete; + UsdSceneItem& operator=(UsdSceneItem&&) = delete; + + //! Create a UsdSceneItem from a UFE path and a USD prim. + static UsdSceneItem::Ptr create(const Ufe::Path& path, const UsdPrim& prim); + + const UsdPrim& prim() const; + + // Ufe::SceneItem overrides + std::string nodeType() const override; + +private: + UsdPrim fPrim; +}; // UsdSceneItem + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdSceneItemOps.cpp b/lib/ufe/UsdSceneItemOps.cpp new file mode 100644 index 0000000000..60b7895f47 --- /dev/null +++ b/lib/ufe/UsdSceneItemOps.cpp @@ -0,0 +1,110 @@ +// +// Copyright 2019 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. +// + +#include "UsdSceneItemOps.h" +#include "UsdUndoDeleteCommand.h" +#include "UsdUndoDuplicateCommand.h" +#include "UsdUndoRenameCommand.h" +#include "Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdSceneItemOps::UsdSceneItemOps() + : Ufe::SceneItemOps() +{ +} + +UsdSceneItemOps::~UsdSceneItemOps() +{ +} + +/*static*/ +UsdSceneItemOps::Ptr UsdSceneItemOps::create() +{ + return std::make_shared(); +} + +void UsdSceneItemOps::setItem(const UsdSceneItem::Ptr& item) +{ + fPrim = item->prim(); + fItem = item; +} + +const Ufe::Path& UsdSceneItemOps::path() const +{ + return fItem->path(); +} + +//------------------------------------------------------------------------------ +// Ufe::SceneItemOps overrides +//------------------------------------------------------------------------------ + +Ufe::SceneItem::Ptr UsdSceneItemOps::sceneItem() const +{ + return fItem; +} + +Ufe::UndoableCommand::Ptr UsdSceneItemOps::deleteItemCmd() +{ + auto deleteCmd = UsdUndoDeleteCommand::create(fPrim); + deleteCmd->execute(); + return deleteCmd; +} + +bool UsdSceneItemOps::deleteItem() +{ + return fPrim.SetActive(false); +} + +Ufe::Duplicate UsdSceneItemOps::duplicateItemCmd() +{ + auto duplicateCmd = UsdUndoDuplicateCommand::create(fPrim, fItem->path()); + duplicateCmd->execute(); + auto item = createSiblingSceneItem(path(), duplicateCmd->usdDstPath().GetElementString()); + return Ufe::Duplicate(item, duplicateCmd); +} + +Ufe::SceneItem::Ptr UsdSceneItemOps::duplicateItem() +{ + SdfPath usdDstPath; + SdfLayerHandle layer; + UsdUndoDuplicateCommand::primInfo(fPrim, usdDstPath, layer); + bool status = UsdUndoDuplicateCommand::duplicate(layer, fPrim.GetPath(), usdDstPath); + + // The duplicate is a sibling of the source. + if (status) + return createSiblingSceneItem(path(), usdDstPath.GetElementString()); + + return nullptr; +} + +Ufe::SceneItem::Ptr UsdSceneItemOps::renameItem(const Ufe::PathComponent& newName) +{ + auto renameCmd = UsdUndoRenameCommand::create(fItem, newName); + renameCmd->execute(); + return renameCmd->renamedItem(); +} + +Ufe::Rename UsdSceneItemOps::renameItemCmd(const Ufe::PathComponent& newName) +{ + auto renameCmd = UsdUndoRenameCommand::create(fItem, newName); + renameCmd->execute(); + return Ufe::Rename(renameCmd->renamedItem(), renameCmd); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdSceneItemOps.h b/lib/ufe/UsdSceneItemOps.h new file mode 100644 index 0000000000..cc22dd8177 --- /dev/null +++ b/lib/ufe/UsdSceneItemOps.h @@ -0,0 +1,69 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/path.h" +#include "ufe/sceneItemOps.h" + +#include "pxr/usd/usd/prim.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface for scene item operations. +class MAYAUSD_CORE_PUBLIC UsdSceneItemOps : public Ufe::SceneItemOps +{ +public: + typedef std::shared_ptr Ptr; + + UsdSceneItemOps(); + ~UsdSceneItemOps() override; + + // Delete the copy/move constructors assignment operators. + UsdSceneItemOps(const UsdSceneItemOps&) = delete; + UsdSceneItemOps& operator=(const UsdSceneItemOps&) = delete; + UsdSceneItemOps(UsdSceneItemOps&&) = delete; + UsdSceneItemOps& operator=(UsdSceneItemOps&&) = delete; + + //! Create a UsdSceneItemOps. + static UsdSceneItemOps::Ptr create(); + + void setItem(const UsdSceneItem::Ptr& item); + const Ufe::Path& path() const; + + // Ufe::SceneItemOps overrides + Ufe::SceneItem::Ptr sceneItem() const override; + Ufe::UndoableCommand::Ptr deleteItemCmd() override; + bool deleteItem() override; + Ufe::Duplicate duplicateItemCmd() override; + Ufe::SceneItem::Ptr duplicateItem() override; + Ufe::Rename renameItemCmd(const Ufe::PathComponent& newName) override; + Ufe::SceneItem::Ptr renameItem(const Ufe::PathComponent& newName) override; + +private: + UsdSceneItem::Ptr fItem; + UsdPrim fPrim; + +}; // UsdSceneItemOps + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdSceneItemOpsHandler.cpp b/lib/ufe/UsdSceneItemOpsHandler.cpp new file mode 100644 index 0000000000..f305034fd8 --- /dev/null +++ b/lib/ufe/UsdSceneItemOpsHandler.cpp @@ -0,0 +1,53 @@ +// +// Copyright 2019 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. +// + +#include "UsdSceneItemOpsHandler.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdSceneItemOpsHandler::UsdSceneItemOpsHandler() + : Ufe::SceneItemOpsHandler() +{ + fUsdSceneItemOps = UsdSceneItemOps::create(); +} + +UsdSceneItemOpsHandler::~UsdSceneItemOpsHandler() +{ +} + +/*static*/ +UsdSceneItemOpsHandler::Ptr UsdSceneItemOpsHandler::create() +{ + return std::make_shared(); +} + +//------------------------------------------------------------------------------ +// Ufe::SceneItemOpsHandler overrides +//------------------------------------------------------------------------------ + +Ufe::SceneItemOps::Ptr UsdSceneItemOpsHandler::sceneItemOps(const Ufe::SceneItem::Ptr& item) const +{ + UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast(item); +#if !defined(NDEBUG) + assert(usdItem); +#endif + fUsdSceneItemOps->setItem(usdItem); + return fUsdSceneItemOps; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdSceneItemOpsHandler.h b/lib/ufe/UsdSceneItemOpsHandler.h new file mode 100644 index 0000000000..53ffaec2c4 --- /dev/null +++ b/lib/ufe/UsdSceneItemOpsHandler.h @@ -0,0 +1,56 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItemOps.h" + +#include "ufe/sceneItemOpsHandler.h" + +//PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface to create a UsdSceneItemOps interface object. +class MAYAUSD_CORE_PUBLIC UsdSceneItemOpsHandler : public Ufe::SceneItemOpsHandler +{ +public: + typedef std::shared_ptr Ptr; + + UsdSceneItemOpsHandler(); + ~UsdSceneItemOpsHandler() override; + + // Delete the copy/move constructors assignment operators. + UsdSceneItemOpsHandler(const UsdSceneItemOpsHandler&) = delete; + UsdSceneItemOpsHandler& operator=(const UsdSceneItemOpsHandler&) = delete; + UsdSceneItemOpsHandler(UsdSceneItemOpsHandler&&) = delete; + UsdSceneItemOpsHandler& operator=(UsdSceneItemOpsHandler&&) = delete; + + //! Create a UsdSceneItemOpsHandler. + static UsdSceneItemOpsHandler::Ptr create(); + + // Ufe::SceneItemOpsHandler overrides + Ufe::SceneItemOps::Ptr sceneItemOps(const Ufe::SceneItem::Ptr& item) const override; + +private: + UsdSceneItemOps::Ptr fUsdSceneItemOps; + +}; // UsdSceneItemOpsHandler + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdStageMap.cpp b/lib/ufe/UsdStageMap.cpp new file mode 100644 index 0000000000..91a0ff14f7 --- /dev/null +++ b/lib/ufe/UsdStageMap.cpp @@ -0,0 +1,63 @@ +// +// Copyright 2019 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. +// + +#include "UsdStageMap.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables +//------------------------------------------------------------------------------ + +UsdStageMap g_StageMap; + +//------------------------------------------------------------------------------ +// UsdStageMap +//------------------------------------------------------------------------------ + +void UsdStageMap::addItem(const Ufe::Path& path, UsdStageWeakPtr stage) +{ + fPathToStage[path] = stage; + fStageToPath[stage] = path; +} + +UsdStageWeakPtr UsdStageMap::stage(const Ufe::Path& path) const +{ + // A stage is bound to a single Dag proxy shape. + auto iter = fPathToStage.find(path); + if (iter != std::end(fPathToStage)) + return iter->second; + return nullptr; +} + +Ufe::Path UsdStageMap::path(UsdStageWeakPtr stage) const +{ + // A stage is bound to a single Dag proxy shape. + auto iter = fStageToPath.find(stage); + if (iter != std::end(fStageToPath)) + return iter->second; + return Ufe::Path(); +} + +void UsdStageMap::clear() +{ + fPathToStage.clear(); + fStageToPath.clear(); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdStageMap.h b/lib/ufe/UsdStageMap.h new file mode 100644 index 0000000000..0688da448c --- /dev/null +++ b/lib/ufe/UsdStageMap.h @@ -0,0 +1,73 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/path.h" + +#include "pxr/usd/usd/stage.h" +#include "pxr/base/tf/hash.h" + +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief USD Stage Map +/*! + Map of AL_usdmaya_ProxyShape UFE path to corresponding stage. + + Map of stage to corresponding AL_usdmaya_ProxyShape UFE path. Ideally, we + would support dynamically computing the path for the AL_usdmaya_ProxyShape + node, but we assume here it will not be reparented. We will also assume that + a USD stage will not be instanced (even though nothing in the data model + prevents it). +*/ +class MAYAUSD_CORE_PUBLIC UsdStageMap +{ +public: + UsdStageMap() = default; + ~UsdStageMap() = default; + + // Delete the copy/move constructors assignment operators. + UsdStageMap(const UsdStageMap&) = delete; + UsdStageMap& operator=(const UsdStageMap&) = delete; + UsdStageMap(UsdStageMap&&) = delete; + UsdStageMap& operator=(UsdStageMap&&) = delete; + + //!Add the input Ufe path and USD Stage to the map. + void addItem(const Ufe::Path& path, UsdStageWeakPtr stage); + + //! Get USD stage corresponding to argument Maya Dag path. + UsdStageWeakPtr stage(const Ufe::Path& path) const; + + //! Return the ProxyShape node UFE path for the argument stage. + Ufe::Path path(UsdStageWeakPtr stage) const; + + void clear(); + +private: + // We keep two maps for fast lookup when there are many proxy shapes. + std::unordered_map fPathToStage; + TfHashMap fStageToPath; + +}; // UsdStageMap + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdTransform3d.cpp b/lib/ufe/UsdTransform3d.cpp new file mode 100644 index 0000000000..1f96ebd332 --- /dev/null +++ b/lib/ufe/UsdTransform3d.cpp @@ -0,0 +1,196 @@ +// +// Copyright 2019 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. +// + +#include "UsdTransform3d.h" +#include "UsdTranslateUndoableCommand.h" +#include "UsdRotateUndoableCommand.h" +#include "UsdScaleUndoableCommand.h" +#include "UsdRotatePivotTranslateUndoableCommand.h" +#include "private/Utils.h" + +#include "pxr/usd/usdGeom/xformCache.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +namespace { + Ufe::Matrix4d convertFromUsd(const GfMatrix4d& matrix) + { + double m[4][4]; + matrix.Get(m); + Ufe::Matrix4d uMat; + uMat.matrix = {{ {{m[0][0], m[0][1], m[0][2], m[0][3]}}, + {{m[1][0], m[1][1], m[1][2], m[1][3]}}, + {{m[2][0], m[2][1], m[2][2], m[2][3]}}, + {{m[3][0], m[3][1], m[3][2], m[3][3]}} }}; + return uMat; + } + + Ufe::Matrix4d primToUfeXform(const UsdPrim& prim) + { + UsdGeomXformCache xformCache; + GfMatrix4d usdMatrix = xformCache.GetLocalToWorldTransform(prim); + Ufe::Matrix4d xform = convertFromUsd(usdMatrix); + return xform; + } + + Ufe::Matrix4d primToUfeExclusiveXform(const UsdPrim& prim) + { + UsdGeomXformCache xformCache; + GfMatrix4d usdMatrix = xformCache.GetParentToWorldTransform(prim); + Ufe::Matrix4d xform = convertFromUsd(usdMatrix); + return xform; + } +} + +UsdTransform3d::UsdTransform3d() + : Transform3d() +{ +} + +UsdTransform3d::~UsdTransform3d() +{ +} + +/*static*/ +UsdTransform3d::Ptr UsdTransform3d::create() +{ + return std::make_shared(); +} + +void UsdTransform3d::setItem(const UsdSceneItem::Ptr& item) +{ + fPrim = item->prim(); + fItem = item; +} + +//------------------------------------------------------------------------------ +// Ufe::Transform3d overrides +//------------------------------------------------------------------------------ + +const Ufe::Path& UsdTransform3d::path() const +{ + return fItem->path(); +} + +Ufe::SceneItem::Ptr UsdTransform3d::sceneItem() const +{ + return fItem; +} + +Ufe::TranslateUndoableCommand::Ptr UsdTransform3d::translateCmd() +{ + auto translateCmd = UsdTranslateUndoableCommand::create(fPrim, fItem->path(), fItem); + return translateCmd; +} + +void UsdTransform3d::translate(double x, double y, double z) +{ + translateOp(fPrim, fItem->path(), x, y, z); +} + +Ufe::Vector3d UsdTransform3d::translation() const +{ + double x{0}, y{0}, z{0}; + const TfToken xlate("xformOp:translate"); + if (fPrim.HasAttribute(xlate)) + { + // Initially, attribute can be created, but have no value. + GfVec3d v; + if (fPrim.GetAttribute(xlate).Get(&v)) + { + x = v[0]; y = v[1]; z = v[2]; + } + } + return Ufe::Vector3d(x, y, z); +} + +Ufe::RotateUndoableCommand::Ptr UsdTransform3d::rotateCmd() +{ + auto rotateCmd = UsdRotateUndoableCommand::create(fPrim, fItem->path(), fItem); + return rotateCmd; +} + +void UsdTransform3d::rotate(double x, double y, double z) +{ + rotateOp(fPrim, fItem->path(), x, y, z); +} + +Ufe::ScaleUndoableCommand::Ptr UsdTransform3d::scaleCmd() +{ + auto scaleCmd = UsdScaleUndoableCommand::create(fPrim, fItem->path(), fItem); + return scaleCmd; +} + +void UsdTransform3d::scale(double x, double y, double z) +{ + scaleOp(fPrim, fItem->path(), x, y, z); +} + +Ufe::TranslateUndoableCommand::Ptr UsdTransform3d::rotatePivotTranslateCmd() +{ + auto translateCmd = UsdRotatePivotTranslateUndoableCommand::create(fPrim, fItem->path(), fItem); + return translateCmd; +} + +void UsdTransform3d::rotatePivotTranslate(double x, double y, double z) +{ + rotatePivotTranslateOp(fPrim, fItem->path(), x, y, z); +} + +Ufe::Vector3d UsdTransform3d::rotatePivot() const +{ + double x{0}, y{0}, z{0}; + const TfToken xpivot("xformOp:translate:pivot"); + if (fPrim.HasAttribute(xpivot)) + { + // Initially, attribute can be created, but have no value. + GfVec3f v; + if (fPrim.GetAttribute(xpivot).Get(&v)) + { + x = v[0]; y = v[1]; z = v[2]; + } + } + return Ufe::Vector3d(x, y, z); +} + +Ufe::TranslateUndoableCommand::Ptr UsdTransform3d::scalePivotTranslateCmd() +{ + throw std::runtime_error("UsdTransform3d::scalePivotTranslateCmd() not implemented"); +} + +void UsdTransform3d::scalePivotTranslate(double x, double y, double z) +{ + return rotatePivotTranslate(x, y, z); +} + +Ufe::Vector3d UsdTransform3d::scalePivot() const +{ + return rotatePivot(); +} + +Ufe::Matrix4d UsdTransform3d::segmentInclusiveMatrix() const +{ + return primToUfeXform(fPrim); +} + +Ufe::Matrix4d UsdTransform3d::segmentExclusiveMatrix() const +{ + return primToUfeExclusiveXform(fPrim); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdTransform3d.h b/lib/ufe/UsdTransform3d.h new file mode 100644 index 0000000000..928891c55c --- /dev/null +++ b/lib/ufe/UsdTransform3d.h @@ -0,0 +1,78 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/path.h" +#include "ufe/transform3d.h" + +#include "pxr/usd/usd/prim.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface to transform objects in 3D. +class MAYAUSD_CORE_PUBLIC UsdTransform3d : public Ufe::Transform3d +{ +public: + typedef std::shared_ptr Ptr; + + UsdTransform3d(); + ~UsdTransform3d() override; + + // Delete the copy/move constructors assignment operators. + UsdTransform3d(const UsdTransform3d&) = delete; + UsdTransform3d& operator=(const UsdTransform3d&) = delete; + UsdTransform3d(UsdTransform3d&&) = delete; + UsdTransform3d& operator=(UsdTransform3d&&) = delete; + + //! Create a UsdTransform3d. + static UsdTransform3d::Ptr create(); + + void setItem(const UsdSceneItem::Ptr& item); + + // Ufe::Transform3d overrides + const Ufe::Path& path() const override; + Ufe::SceneItem::Ptr sceneItem() const override; + Ufe::TranslateUndoableCommand::Ptr translateCmd() override; + void translate(double x, double y, double z) override; + Ufe::Vector3d translation() const override; + Ufe::RotateUndoableCommand::Ptr rotateCmd() override; + void rotate(double x, double y, double z) override; + Ufe::ScaleUndoableCommand::Ptr scaleCmd() override; + void scale(double x, double y, double z) override; + Ufe::TranslateUndoableCommand::Ptr rotatePivotTranslateCmd() override; + void rotatePivotTranslate(double x, double y, double z) override; + Ufe::Vector3d rotatePivot() const override; + Ufe::TranslateUndoableCommand::Ptr scalePivotTranslateCmd() override; + void scalePivotTranslate(double x, double y, double z) override; + Ufe::Vector3d scalePivot() const override; + Ufe::Matrix4d segmentInclusiveMatrix() const override; + Ufe::Matrix4d segmentExclusiveMatrix() const override; + +private: + UsdSceneItem::Ptr fItem; + UsdPrim fPrim; + +}; // UsdTransform3d + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdTransform3dHandler.cpp b/lib/ufe/UsdTransform3dHandler.cpp new file mode 100644 index 0000000000..a47957f456 --- /dev/null +++ b/lib/ufe/UsdTransform3dHandler.cpp @@ -0,0 +1,54 @@ +// +// Copyright 2019 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. +// + +#include "UsdTransform3dHandler.h" +#include "UsdSceneItem.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdTransform3dHandler::UsdTransform3dHandler() + : Ufe::Transform3dHandler() +{ + fUsdTransform3d = UsdTransform3d::create(); +} + +UsdTransform3dHandler::~UsdTransform3dHandler() +{ +} + +/*static*/ +UsdTransform3dHandler::Ptr UsdTransform3dHandler::create() +{ + return std::make_shared(); +} + +//------------------------------------------------------------------------------ +// Ufe::Transform3dHandler overrides +//------------------------------------------------------------------------------ + +Ufe::Transform3d::Ptr UsdTransform3dHandler::transform3d(const Ufe::SceneItem::Ptr& item) const +{ + UsdSceneItem::Ptr usdItem = std::dynamic_pointer_cast(item); +#if !defined(NDEBUG) + assert(usdItem); +#endif + fUsdTransform3d->setItem(usdItem); + return fUsdTransform3d; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdTransform3dHandler.h b/lib/ufe/UsdTransform3dHandler.h new file mode 100644 index 0000000000..de5a6b5152 --- /dev/null +++ b/lib/ufe/UsdTransform3dHandler.h @@ -0,0 +1,56 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdTransform3d.h" + +#include "ufe/transform3dHandler.h" + +//PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Interface to create a UsdTransform3d interface object. +class MAYAUSD_CORE_PUBLIC UsdTransform3dHandler : public Ufe::Transform3dHandler +{ +public: + typedef std::shared_ptr Ptr; + + UsdTransform3dHandler(); + ~UsdTransform3dHandler(); + + // Delete the copy/move constructors assignment operators. + UsdTransform3dHandler(const UsdTransform3dHandler&) = delete; + UsdTransform3dHandler& operator=(const UsdTransform3dHandler&) = delete; + UsdTransform3dHandler(UsdTransform3dHandler&&) = delete; + UsdTransform3dHandler& operator=(UsdTransform3dHandler&&) = delete; + + //! Create a UsdTransform3dHandler. + static UsdTransform3dHandler::Ptr create(); + + // Ufe::Transform3dHandler overrides + Ufe::Transform3d::Ptr transform3d(const Ufe::SceneItem::Ptr& item) const override; + +private: + UsdTransform3d::Ptr fUsdTransform3d; + +}; // UsdTransform3dHandler + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdTranslateUndoableCommand.cpp b/lib/ufe/UsdTranslateUndoableCommand.cpp new file mode 100644 index 0000000000..7ba15e63ce --- /dev/null +++ b/lib/ufe/UsdTranslateUndoableCommand.cpp @@ -0,0 +1,82 @@ +// +// Copyright 2019 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. +// + +#include "UsdTranslateUndoableCommand.h" +#include "private/Utils.h" +#include "Utils.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdTranslateUndoableCommand::UsdTranslateUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) + : Ufe::TranslateUndoableCommand(item) + , fPrim(prim) + , fPath(ufePath) + , fNoTranslateOp(false) +{ + // Prim does not have a translate attribute + const TfToken xlate("xformOp:translate"); + if (!fPrim.HasAttribute(xlate)) + { + fNoTranslateOp = true; + translateOp(fPrim, fPath, 0, 0, 0); // Add an empty translate + } + + fTranslateAttrib = fPrim.GetAttribute(xlate); + fTranslateAttrib.Get(&fPrevTranslateValue); +} + +UsdTranslateUndoableCommand::~UsdTranslateUndoableCommand() +{ +} + +/*static*/ +UsdTranslateUndoableCommand::Ptr UsdTranslateUndoableCommand::create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item) +{ + return std::make_shared(prim, ufePath, item); +} + +void UsdTranslateUndoableCommand::undo() +{ + fTranslateAttrib.Set(fPrevTranslateValue); + // Todo : We would want to remove the xformOp + // (SD-06/07/2018) Haven't found a clean way to do it - would need to investigate +} + +void UsdTranslateUndoableCommand::redo() +{ + perform(); +} + +void UsdTranslateUndoableCommand::perform() +{ + // No-op, use translate to move the object. + // The Maya move command directly invokes our translate() method in its + // redoIt(), which is invoked both for the inital move and the redo. +} + +//------------------------------------------------------------------------------ +// Ufe::TranslateUndoableCommand overrides +//------------------------------------------------------------------------------ + +bool UsdTranslateUndoableCommand::translate(double x, double y, double z) +{ + translateOp(fPrim, fPath, x, y, z); + return true; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdTranslateUndoableCommand.h b/lib/ufe/UsdTranslateUndoableCommand.h new file mode 100644 index 0000000000..6d311d832f --- /dev/null +++ b/lib/ufe/UsdTranslateUndoableCommand.h @@ -0,0 +1,68 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "ufe/transform3dUndoableCommands.h" + +#include "pxr/usd/usd/attribute.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Translation command of the given prim. +/*! + Ability to perform undo to restore the original translate value. + As of 06/07/2018, redo is a no op as Maya re-does the operation for redo + */ +class MAYAUSD_CORE_PUBLIC UsdTranslateUndoableCommand : public Ufe::TranslateUndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdTranslateUndoableCommand(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + ~UsdTranslateUndoableCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdTranslateUndoableCommand(const UsdTranslateUndoableCommand&) = delete; + UsdTranslateUndoableCommand& operator=(const UsdTranslateUndoableCommand&) = delete; + UsdTranslateUndoableCommand(UsdTranslateUndoableCommand&&) = delete; + UsdTranslateUndoableCommand& operator=(UsdTranslateUndoableCommand&&) = delete; + + //! Create a UsdTranslateUndoableCommand from a USD prim, UFE path and UFE scene item. + static UsdTranslateUndoableCommand::Ptr create(const UsdPrim& prim, const Ufe::Path& ufePath, const Ufe::SceneItem::Ptr& item); + + // Ufe::TranslateUndoableCommand overrides + void undo() override; + void redo() override; + bool translate(double x, double y, double z) override; + +private: + void perform(); + +private: + UsdPrim fPrim; + UsdAttribute fTranslateAttrib; + GfVec3d fPrevTranslateValue; + Ufe::Path fPath; + bool fNoTranslateOp; +}; // UsdTranslateUndoableCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoCreateGroupCommand.cpp b/lib/ufe/UsdUndoCreateGroupCommand.cpp new file mode 100644 index 0000000000..edc611e98b --- /dev/null +++ b/lib/ufe/UsdUndoCreateGroupCommand.cpp @@ -0,0 +1,80 @@ +// +// Copyright 2019 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. +// + +#include "UsdUndoCreateGroupCommand.h" + +#include "ufe/scene.h" +#include "ufe/hierarchy.h" +#include "ufe/sceneNotification.h" + +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/stage.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdUndoCreateGroupCommand::UsdUndoCreateGroupCommand(const UsdSceneItem::Ptr& parentItem, const Ufe::PathComponent& name) + : Ufe::UndoableCommand() + , fParentItem(parentItem) + , fName(name) +{ +} + +UsdUndoCreateGroupCommand::~UsdUndoCreateGroupCommand() +{ +} + +/*static*/ +UsdUndoCreateGroupCommand::Ptr UsdUndoCreateGroupCommand::create(const UsdSceneItem::Ptr& parentItem, const Ufe::PathComponent& name) +{ + return std::make_shared(parentItem, name); +} + +Ufe::SceneItem::Ptr UsdUndoCreateGroupCommand::group() const +{ + return fGroup; +} + +//------------------------------------------------------------------------------ +// UsdUndoCreateGroupCommand overrides +//------------------------------------------------------------------------------ + +void UsdUndoCreateGroupCommand::undo() +{ + if (!fGroup) return; + + // See UsdUndoDuplicateCommand.undo() comments. + auto notification = Ufe::ObjectPreDelete(fGroup); + Ufe::Scene::notifyObjectDelete(notification); + + auto prim = fGroup->prim(); + auto stage = prim.GetStage(); + auto usdPath = prim.GetPath(); + stage->RemovePrim(usdPath); + + fGroup.reset(); +} + +void UsdUndoCreateGroupCommand::redo() +{ + auto hierarchy = Ufe::Hierarchy::hierarchy(fParentItem); + // See MAYA-92264: redo doesn't work. PPT, 19-Nov-2018. + Ufe::SceneItem::Ptr group = hierarchy->createGroup(fName); + fGroup = std::dynamic_pointer_cast(group); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoCreateGroupCommand.h b/lib/ufe/UsdUndoCreateGroupCommand.h new file mode 100644 index 0000000000..e0499a8d54 --- /dev/null +++ b/lib/ufe/UsdUndoCreateGroupCommand.h @@ -0,0 +1,62 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/undoableCommand.h" +#include "ufe/pathComponent.h" + +//PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief UsdUndoCreateGroupCommand +class MAYAUSD_CORE_PUBLIC UsdUndoCreateGroupCommand : public Ufe::UndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdUndoCreateGroupCommand(const UsdSceneItem::Ptr& parentItem, const Ufe::PathComponent& name); + ~UsdUndoCreateGroupCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdUndoCreateGroupCommand(const UsdUndoCreateGroupCommand&) = delete; + UsdUndoCreateGroupCommand& operator=(const UsdUndoCreateGroupCommand&) = delete; + UsdUndoCreateGroupCommand(UsdUndoCreateGroupCommand&&) = delete; + UsdUndoCreateGroupCommand& operator=(UsdUndoCreateGroupCommand&&) = delete; + + //! Create a UsdUndoCreateGroupCommand from a USD scene item and a UFE path component. + static UsdUndoCreateGroupCommand::Ptr create(const UsdSceneItem::Ptr& parentItem, const Ufe::PathComponent& name); + + Ufe::SceneItem::Ptr group() const; + + // UsdUndoCreateGroupCommand overrides + void undo() override; + void redo() override; + +private: + UsdSceneItem::Ptr fParentItem; + Ufe::PathComponent fName; + UsdSceneItem::Ptr fGroup; + +}; // UsdUndoCreateGroupCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoDeleteCommand.cpp b/lib/ufe/UsdUndoDeleteCommand.cpp new file mode 100644 index 0000000000..f8835070dc --- /dev/null +++ b/lib/ufe/UsdUndoDeleteCommand.cpp @@ -0,0 +1,58 @@ +// +// Copyright 2019 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. +// + +#include "UsdUndoDeleteCommand.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdUndoDeleteCommand::UsdUndoDeleteCommand(const UsdPrim& prim) + : Ufe::UndoableCommand() + , fPrim(prim) +{ +} + +UsdUndoDeleteCommand::~UsdUndoDeleteCommand() +{ +} + +/*static*/ +UsdUndoDeleteCommand::Ptr UsdUndoDeleteCommand::create(const UsdPrim& prim) +{ + return std::make_shared(prim); +} + +void UsdUndoDeleteCommand::perform(bool state) +{ + fPrim.SetActive(state); +} + +//------------------------------------------------------------------------------ +// UsdUndoDeleteCommand overrides +//------------------------------------------------------------------------------ + +void UsdUndoDeleteCommand::undo() +{ + perform(true); +} + +void UsdUndoDeleteCommand::redo() +{ + perform(false); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoDeleteCommand.h b/lib/ufe/UsdUndoDeleteCommand.h new file mode 100644 index 0000000000..a81dc1f580 --- /dev/null +++ b/lib/ufe/UsdUndoDeleteCommand.h @@ -0,0 +1,62 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/undoableCommand.h" + +#include "pxr/usd/usd/prim.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief UsdUndoDeleteCommand +class MAYAUSD_CORE_PUBLIC UsdUndoDeleteCommand : public Ufe::UndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdUndoDeleteCommand(const UsdPrim& prim); + ~UsdUndoDeleteCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdUndoDeleteCommand(const UsdUndoDeleteCommand&) = delete; + UsdUndoDeleteCommand& operator=(const UsdUndoDeleteCommand&) = delete; + UsdUndoDeleteCommand(UsdUndoDeleteCommand&&) = delete; + UsdUndoDeleteCommand& operator=(UsdUndoDeleteCommand&&) = delete; + + //! Create a UsdUndoDeleteCommand from a USD prim. + static UsdUndoDeleteCommand::Ptr create(const UsdPrim& prim); + + // UsdUndoDeleteCommand overrides + void undo() override; + void redo() override; + +private: + void perform(bool state); + +private: + UsdPrim fPrim; + +}; // UsdUndoDeleteCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoDuplicateCommand.cpp b/lib/ufe/UsdUndoDuplicateCommand.cpp new file mode 100644 index 0000000000..5e141969dd --- /dev/null +++ b/lib/ufe/UsdUndoDuplicateCommand.cpp @@ -0,0 +1,124 @@ +// +// Copyright 2019 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. +// + +#include "UsdUndoDuplicateCommand.h" +#include "Utils.h" + +#include "ufe/scene.h" +#include "ufe/sceneNotification.h" +#include "ufe/log.h" + +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/sdf/copyUtils.h" +#include "pxr/base/tf/token.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdUndoDuplicateCommand::UsdUndoDuplicateCommand(const UsdPrim& srcPrim, const Ufe::Path& ufeSrcPath) + : Ufe::UndoableCommand() + , fSrcPrim(srcPrim) + , fUfeSrcPath(ufeSrcPath) +{ + fStage = fSrcPrim.GetStage(); + primInfo(srcPrim, fUsdDstPath, fLayer); +} + +UsdUndoDuplicateCommand::~UsdUndoDuplicateCommand() +{ +} + +/*static*/ +UsdUndoDuplicateCommand::Ptr UsdUndoDuplicateCommand::create(const UsdPrim& srcPrim, const Ufe::Path& ufeSrcPath) +{ + return std::make_shared(srcPrim, ufeSrcPath); +} + +const SdfPath& UsdUndoDuplicateCommand::usdDstPath() const +{ + return fUsdDstPath; +} + +/*static*/ +void UsdUndoDuplicateCommand::primInfo(const UsdPrim& srcPrim, SdfPath& usdDstPath, SdfLayerHandle& srcLayer) +{ + auto parent = srcPrim.GetParent(); + TfToken::HashSet childrenNames; + for(auto child : parent.GetChildren()) + { + childrenNames.insert(child.GetName()); + } + + // Find a unique name for the destination. If the source name already + // has a numerical suffix, increment it, otherwise append "1" to it. + auto dstName = uniqueName(childrenNames, srcPrim.GetName()); + usdDstPath = parent.GetPath().AppendChild(TfToken(dstName)); + + // Iterate over the layer stack, starting at the highest-priority layer. + // The source layer is the one in which there exists a def primSpec, not + // an over. An alternative would have beeen to call Sdf.CopySpec for + // each layer in which there is an over or a def, until we reach the + // layer with a def primSpec. This would preserve the visual appearance + // of the duplicate. PPT, 12-Jun-2018. + srcLayer = defPrimSpecLayer(srcPrim); + if (!srcLayer) { + std::string err = TfStringPrintf("No prim found at %s", srcPrim.GetPath().GetString().c_str()); + throw std::runtime_error(err.c_str()); + } +} + +/*static*/ +bool UsdUndoDuplicateCommand::duplicate(const SdfLayerHandle& layer, const SdfPath& usdSrcPath, const SdfPath& usdDstPath) +{ + // We use the source layer as the destination. An alternate workflow + // would be the edit target layer be the destination: + // layer = self._stage.GetEditTarget().GetLayer() + return SdfCopySpec(layer, usdSrcPath, layer, usdDstPath); +} + +//------------------------------------------------------------------------------ +// UsdUndoDuplicateCommand overrides +//------------------------------------------------------------------------------ + +void UsdUndoDuplicateCommand::undo() +{ + // USD sends a ResyncedPaths notification after the prim is removed, but + // at that point the prim is no longer valid, and thus a UFE post delete + // notification is no longer possible. To respect UFE object delete + // notification semantics, which require the object to be alive when + // the notification is sent, we send a pre delete notification here. + Ufe::ObjectPreDelete notification(createSiblingSceneItem( + fUfeSrcPath, fUsdDstPath.GetElementString())); + Ufe::Scene::notifyObjectDelete(notification); + + fStage->RemovePrim(fUsdDstPath); +} + +void UsdUndoDuplicateCommand::redo() +{ + // MAYA-92264: Pixar bug prevents redo from working. Try again with USD + // version 0.8.5 or later. PPT, 28-May-2018. + try { + duplicate(fLayer, fSrcPrim.GetPath(), fUsdDstPath); + } + catch (const std::exception& e) { + UFE_LOG(e.what()); + throw; // re-throw the same exception + } +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoDuplicateCommand.h b/lib/ufe/UsdUndoDuplicateCommand.h new file mode 100644 index 0000000000..fb0ac02593 --- /dev/null +++ b/lib/ufe/UsdUndoDuplicateCommand.h @@ -0,0 +1,77 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/path.h" +#include "ufe/undoableCommand.h" + +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/prim.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief UsdUndoDuplicateCommand +class MAYAUSD_CORE_PUBLIC UsdUndoDuplicateCommand : public Ufe::UndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdUndoDuplicateCommand(const UsdPrim& srcPrim, const Ufe::Path& ufeSrcPath); + ~UsdUndoDuplicateCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdUndoDuplicateCommand(const UsdUndoDuplicateCommand&) = delete; + UsdUndoDuplicateCommand& operator=(const UsdUndoDuplicateCommand&) = delete; + UsdUndoDuplicateCommand(UsdUndoDuplicateCommand&&) = delete; + UsdUndoDuplicateCommand& operator=(UsdUndoDuplicateCommand&&) = delete; + + //! Create a UsdUndoDuplicateCommand from a USD prim and UFE path. + static UsdUndoDuplicateCommand::Ptr create(const UsdPrim& srcPrim, const Ufe::Path& ufeSrcPath); + + const SdfPath& usdDstPath() const; + + //! Return the USD destination path and layer. + static void primInfo(const UsdPrim& srcPrim, SdfPath& usdDstPath, SdfLayerHandle& srcLayer); + + //! Duplicate the prim hierarchy at usdSrcPath. + //! \return True for success. + static bool duplicate(const SdfLayerHandle& layer, const SdfPath& usdSrcPath, const SdfPath& usdDstPath); + + //! Return the USD destination path and layer. + static void primInfo(); + + // UsdUndoDuplicateCommand overrides + void undo() override; + void redo() override; + +private: + UsdPrim fSrcPrim; + UsdStageWeakPtr fStage; + SdfLayerHandle fLayer; + Ufe::Path fUfeSrcPath; + SdfPath fUsdDstPath; + +}; // UsdUndoDuplicateCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoRenameCommand.cpp b/lib/ufe/UsdUndoRenameCommand.cpp new file mode 100644 index 0000000000..b7791732cb --- /dev/null +++ b/lib/ufe/UsdUndoRenameCommand.cpp @@ -0,0 +1,118 @@ +// +// Copyright 2019 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. +// + +#include "UsdUndoRenameCommand.h" +#include "Utils.h" +#include "private/InPathChange.h" + +#include "ufe/scene.h" +#include "ufe/sceneNotification.h" +#include "ufe/log.h" + +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/sdf/copyUtils.h" +#include "pxr/base/tf/token.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +UsdUndoRenameCommand::UsdUndoRenameCommand(const UsdSceneItem::Ptr& srcItem, const Ufe::PathComponent& newName) + : Ufe::UndoableCommand() +{ + const UsdPrim& prim = srcItem->prim(); + fStage = prim.GetStage(); + fUfeSrcPath = srcItem->path(); + fUsdSrcPath = prim.GetPath(); + // Every call to rename() (through execute(), undo() or redo()) removes + // a prim, which becomes expired. Since USD UFE scene items contain a + // prim, we must recreate them after every call to rename. + fUsdDstPath = prim.GetParent().GetPath().AppendChild(TfToken(newName.string())); + fLayer = defPrimSpecLayer(prim); + if (fLayer) { + std::string err = TfStringPrintf("No prim found at %s", prim.GetPath().GetString().c_str()); + throw std::runtime_error(err.c_str()); + } +} + +UsdUndoRenameCommand::~UsdUndoRenameCommand() +{ +} + +/*static*/ +UsdUndoRenameCommand::Ptr UsdUndoRenameCommand::create(const UsdSceneItem::Ptr& srcItem, const Ufe::PathComponent& newName) +{ + return std::make_shared(srcItem, newName); +} + +UsdSceneItem::Ptr UsdUndoRenameCommand::renamedItem() const +{ + return fUfeDstItem; +} + +bool UsdUndoRenameCommand::rename(SdfLayerHandle layer, const Ufe::Path& ufeSrcPath, const SdfPath& usdSrcPath, const SdfPath& usdDstPath) +{ + InPathChange pc; + return internalRename(layer, ufeSrcPath, usdSrcPath, usdDstPath); +} + +bool UsdUndoRenameCommand::internalRename(SdfLayerHandle layer, const Ufe::Path& ufeSrcPath, const SdfPath& usdSrcPath, const SdfPath& usdDstPath) +{ + // We use the source layer as the destination. An alternate workflow + // would be the edit target layer be the destination: + // layer = self._stage.GetEditTarget().GetLayer() + bool status = SdfCopySpec(layer, usdSrcPath, layer, usdDstPath); + if (status) + { + fStage->RemovePrim(usdSrcPath); + // The renamed scene item is a "sibling" of its original name. + fUfeDstItem = createSiblingSceneItem( + ufeSrcPath, usdDstPath.GetElementString()); + // USD sends two ResyncedPaths() notifications, one for the CopySpec + // call, the other for the RemovePrim call (new name added, old name + // removed). Unfortunately, the rename semantics are lost: there is + // no notion that the two notifications belong to the same atomic + // change. Provide a single Rename notification ourselves here. + Ufe::ObjectRename notification(fUfeDstItem, ufeSrcPath); + Ufe::Scene::notifyObjectPathChange(notification); + } + + return status; +} + +//------------------------------------------------------------------------------ +// UsdUndoRenameCommand overrides +//------------------------------------------------------------------------------ + +void UsdUndoRenameCommand::undo() +{ + // MAYA-92264: Pixar bug prevents undo from working. Try again with USD + // version 0.8.5 or later. PPT, 7-Jul-2018. + try { + rename(fLayer, fUfeDstItem->path(), fUsdDstPath, fUsdSrcPath); + } + catch (const std::exception& e) { + UFE_LOG(e.what()); + throw; // re-throw the same exception + } +} + +void UsdUndoRenameCommand::redo() +{ + rename(fLayer, fUfeSrcPath, fUsdSrcPath, fUsdDstPath); +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/UsdUndoRenameCommand.h b/lib/ufe/UsdUndoRenameCommand.h new file mode 100644 index 0000000000..652ae19aba --- /dev/null +++ b/lib/ufe/UsdUndoRenameCommand.h @@ -0,0 +1,75 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/path.h" +#include "ufe/pathComponent.h" +#include "ufe/undoableCommand.h" + +#include "pxr/usd/sdf/path.h" +#include "pxr/usd/usd/prim.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief UsdUndoRenameCommand +class MAYAUSD_CORE_PUBLIC UsdUndoRenameCommand : public Ufe::UndoableCommand +{ +public: + typedef std::shared_ptr Ptr; + + UsdUndoRenameCommand(const UsdSceneItem::Ptr& srcItem, const Ufe::PathComponent& newName); + ~UsdUndoRenameCommand() override; + + // Delete the copy/move constructors assignment operators. + UsdUndoRenameCommand(const UsdUndoRenameCommand&) = delete; + UsdUndoRenameCommand& operator=(const UsdUndoRenameCommand&) = delete; + UsdUndoRenameCommand(UsdUndoRenameCommand&&) = delete; + UsdUndoRenameCommand& operator=(UsdUndoRenameCommand&&) = delete; + + //! Create a UsdUndoRenameCommand from a USD scene item and UFE pathcomponent. + static UsdUndoRenameCommand::Ptr create(const UsdSceneItem::Ptr& srcItem, const Ufe::PathComponent& newName); + + UsdSceneItem::Ptr renamedItem() const; + + //! Rename the prim hierarchy at usdSrcPath to usdDstPath. + bool rename(SdfLayerHandle layer, const Ufe::Path& ufeSrcPath, const SdfPath& usdSrcPath, const SdfPath& usdDstPath); + + // UsdUndoRenameCommand overrides + void undo() override; + void redo() override; + +private: + bool internalRename(SdfLayerHandle layer, const Ufe::Path& ufeSrcPath, const SdfPath& usdSrcPath, const SdfPath& usdDstPath); + +private: + UsdStageWeakPtr fStage; + SdfLayerHandle fLayer; + Ufe::Path fUfeSrcPath; + SdfPath fUsdSrcPath; + UsdSceneItem::Ptr fUfeDstItem; + SdfPath fUsdDstPath; + +}; // UsdUndoRenameCommand + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/Utils.cpp b/lib/ufe/Utils.cpp new file mode 100644 index 0000000000..95e800a03e --- /dev/null +++ b/lib/ufe/Utils.cpp @@ -0,0 +1,222 @@ +// +// Copyright 2019 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. +// + +#include "Utils.h" +#include "private/Utils.h" +#include "UsdStageMap.h" +#include "ProxyShapeHandler.h" + +#include "pxr/base/tf/hashset.h" +#include "pxr/usd/usd/stage.h" + +#include "maya/MGlobal.h" +#include "maya/MSelectionList.h" + +#include +#include +#include +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +#ifndef MAYA_MSTRINGARRAY_ITERATOR_CATEGORY +// MStringArray::Iterator is not standard-compliant in Maya 2019, needs the +// following workaround. Fixed in Maya 2020. PPT, 20-Jun-2019. +namespace std +{ + template<> + struct iterator_traits { + typedef std::bidirectional_iterator_tag iterator_category; + }; +} +#endif + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Global variables & macros +//------------------------------------------------------------------------------ + +extern UsdStageMap g_StageMap; +extern Ufe::Rtid g_MayaRtid; + +// Cache of Maya node types we've queried before for inheritance from the +// gateway node type. +std::unordered_map g_GatewayType; + +//------------------------------------------------------------------------------ +// Utility Functions +//------------------------------------------------------------------------------ + +UsdStageWeakPtr getStage(const Ufe::Path& path) +{ + return g_StageMap.stage(path); +} + +Ufe::Path stagePath(UsdStageWeakPtr stage) +{ + return g_StageMap.path(stage); +} + +UsdPrim ufePathToPrim(const Ufe::Path& path) +{ + // Assume that there are only two segments in the path, the first a Maya + // Dag path segment to the proxy shape, which identifies the stage, and + // the second the USD segment. + const Ufe::Path::Segments& segments = path.getSegments(); + TEST_USD_PATH(segments, path); + + UsdPrim prim; + if (auto stage = getStage(Ufe::Path(segments[0]))) + { + prim = stage->GetPrimAtPath(SdfPath(segments[1].string())); + } + return prim; +} + +bool isRootChild(const Ufe::Path& path) +{ + auto segments = path.getSegments(); + TEST_USD_PATH(segments, path); + return(segments[1].size() == 1); +} + +SdfLayerHandle defPrimSpecLayer(const UsdPrim& prim) +{ + // Iterate over the layer stack, starting at the highest-priority layer. + // The source layer is the one in which there exists a def primSpec, not + // an over. + + SdfLayerHandle defLayer; + auto layerStack = prim.GetStage()->GetLayerStack(); + for (auto layer : layerStack) + { + auto primSpec = layer->GetPrimAtPath(prim.GetPath()); + if (primSpec && (primSpec->GetSpecifier() == SdfSpecifierDef)) + { + defLayer = layer; + break; + } + } + return defLayer; +} + +UsdSceneItem::Ptr createSiblingSceneItem(const Ufe::Path& ufeSrcPath, const std::string& siblingName) +{ + auto ufeSiblingPath = ufeSrcPath.sibling(Ufe::PathComponent(siblingName)); + return UsdSceneItem::create(ufeSiblingPath, ufePathToPrim(ufeSiblingPath)); +} + +std::string uniqueName(const TfToken::HashSet& existingNames, std::string srcName) +{ + // Compiled regular expression to find a numerical suffix to a path component. + // It searches for any number of characters followed by a single non-numeric, + // then one or more digits at end of string. + std::regex re("(.*)([^0-9])([0-9]+)$"); + std::string base{srcName}; + int suffix{1}; + std::smatch match; + if (std::regex_match(srcName, match, re)) + { + base = match[1].str() + match[2].str(); + suffix = std::stoi(match[3].str()) + 1; + } + std::string dstName = base + std::to_string(suffix); + while (existingNames.count(TfToken(dstName)) > 0) + { + dstName = base + std::to_string(++suffix); + } + return dstName; +} + +std::string uniqueChildName(const Ufe::SceneItem::Ptr& parent, const Ufe::Path& childPath) +{ + auto usdParent = std::dynamic_pointer_cast(parent); +#if !defined(NDEBUG) + assert(usdParent); +#endif + if (!usdParent) return ""; + + TfToken::HashSet childrenNames; + for (auto child : usdParent->prim().GetChildren()) + { + childrenNames.insert(child.GetName()); + } + std::string childName = childPath.back().string(); + if (childrenNames.find(TfToken(childName)) != childrenNames.end()) + { + childName = uniqueName(childrenNames, childName); + } + return childName; +} + +bool isAGatewayType(const std::string& mayaNodeType) +{ + // If we've seen this node type before, return the cached value. + auto iter = g_GatewayType.find(mayaNodeType); + if (iter != std::end(g_GatewayType)) + { + return iter->second; + } + + // Note: we are calling the MEL interpreter to determine the inherited types, + // but we are then caching the result. So MEL will only be called once + // for each node type. + // Not seen before, so ask Maya. + // When the inherited flag is used, the command returns a string array containing + // the names of all the base node types inherited by the the given node. + MString cmd; + MStringArray inherited; + bool isInherited = false; + cmd.format("nodeType -inherited -isTypeName ^1s", mayaNodeType.c_str()); + if (MS::kSuccess == MGlobal::executeCommand(cmd, inherited)) + { + MString gatewayNodeType(ProxyShapeHandler::gatewayNodeType().c_str()); + auto iter2 = std::find(inherited.begin(), inherited.end(), gatewayNodeType); + isInherited = (iter2 != inherited.end()); + g_GatewayType[mayaNodeType] = isInherited; + } + return isInherited; +} + +Ufe::Path dagPathToUfe(const MDagPath& dagPath) +{ + // This function can only create UFE Maya scene items with a single + // segment, as it is only given a Dag path as input. + return Ufe::Path(dagPathToPathSegment(dagPath)); +} + +Ufe::PathSegment dagPathToPathSegment(const MDagPath& dagPath) +{ + std::string fullPathName = dagPath.fullPathName().asChar(); + return Ufe::PathSegment("world" + fullPathName, g_MayaRtid, '|'); +} + +MDagPath nameToDagPath(const std::string& name) +{ + MSelectionList selection; + selection.add(MString(name.c_str())); + MDagPath dag; + MStatus status = selection.getDagPath(0, dag); + CHECK_MSTATUS(status); + return dag; +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/Utils.h b/lib/ufe/Utils.h new file mode 100644 index 0000000000..e55bbce04c --- /dev/null +++ b/lib/ufe/Utils.h @@ -0,0 +1,85 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../base/api.h" + +#include "UsdSceneItem.h" + +#include "ufe/path.h" +#include "ufe/pathSegment.h" + +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/sdf/layer.h" +#include "pxr/base/tf/token.h" + +#include "maya/MDagPath.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Helper functions +//------------------------------------------------------------------------------ + +//! Get USD stage corresponding to argument Maya Dag path. +MAYAUSD_CORE_PUBLIC +UsdStageWeakPtr getStage(const Ufe::Path& path); + +//! Return the ProxyShape node UFE path for the argument stage. +MAYAUSD_CORE_PUBLIC +Ufe::Path stagePath(UsdStageWeakPtr stage); + +//! Return the USD prim corresponding to the argument UFE path. +MAYAUSD_CORE_PUBLIC +UsdPrim ufePathToPrim(const Ufe::Path& path); + +MAYAUSD_CORE_PUBLIC +bool isRootChild(const Ufe::Path& path); + +//! Return the highest-priority layer where the prim has a def primSpec. +MAYAUSD_CORE_PUBLIC +SdfLayerHandle defPrimSpecLayer(const UsdPrim& prim); + +MAYAUSD_CORE_PUBLIC +UsdSceneItem::Ptr createSiblingSceneItem(const Ufe::Path& ufeSrcPath, const std::string& siblingName); + +//! Split the source name into a base name and a numerical suffix (set to +//! 1 if absent). Increment the numerical suffix until name is unique. +MAYAUSD_CORE_PUBLIC +std::string uniqueName(const TfToken::HashSet& existingNames, std::string srcName); + +//! Return a unique child name. Parent must be a UsdSceneItem. +MAYAUSD_CORE_PUBLIC +std::string uniqueChildName(const Ufe::SceneItem::Ptr& parent, const Ufe::Path& childPath); + +//! Return if a Maya node type is derived from the gateway node type. +MAYAUSD_CORE_PUBLIC +bool isAGatewayType(const std::string& mayaNodeType); + +MAYAUSD_CORE_PUBLIC +Ufe::Path dagPathToUfe(const MDagPath& dagPath); + +MAYAUSD_CORE_PUBLIC +Ufe::PathSegment dagPathToPathSegment(const MDagPath& dagPath); + +MAYAUSD_CORE_PUBLIC +MDagPath nameToDagPath(const std::string& name); + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/__init__.py b/lib/ufe/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/ufe/private/InPathChange.h b/lib/ufe/private/InPathChange.h new file mode 100644 index 0000000000..bd9e1d173f --- /dev/null +++ b/lib/ufe/private/InPathChange.h @@ -0,0 +1,43 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../../base/api.h" + +MAYAUSD_NS_DEF { +namespace ufe { + +//! \brief Helper class to scope when we are in a path change operation. +class InPathChange +{ +public: + InPathChange() { fInPathChange = true; } + ~InPathChange() { fInPathChange = false; } + + // Delete the copy/move constructors assignment operators. + InPathChange(const InPathChange&) = delete; + InPathChange& operator=(const InPathChange&) = delete; + InPathChange(InPathChange&&) = delete; + InPathChange& operator=(InPathChange&&) = delete; + + static bool inPathChange() { return fInPathChange; } + +private: + static bool fInPathChange; +}; + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/private/Utils.cpp b/lib/ufe/private/Utils.cpp new file mode 100644 index 0000000000..cc75e87bde --- /dev/null +++ b/lib/ufe/private/Utils.cpp @@ -0,0 +1,214 @@ +// +// Copyright 2019 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. +// + +#include "Utils.h" + +#include "ufe/log.h" + +#include "pxr/base/tf/stringUtils.h" +#include "pxr/usd/usdGeom/xformable.h" + +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Private helper functions +//------------------------------------------------------------------------------ + +UsdGeomXformCommonAPI convertToCompatibleCommonAPI(const UsdPrim& prim) +{ + // As we are using USD's XformCommonAPI which supports only the following xformOps : + // ["xformOp:translate", "xformOp:translate:pivot", "xformOp:rotateXYZ", "xformOp:scale", "!invert!xformOp:translate:pivot"] + // We are extending the supported xform Operations with : + // ["xformOp:rotateX", "xformOp:rotateY", "xformOp:rotateZ"] + // Where we convert these into xformOp:rotateXYZ. + + static TfToken rotX("xformOp:rotateX"); + static TfToken rotY("xformOp:rotateY"); + static TfToken rotZ("xformOp:rotateZ"); + static TfToken rotXYZ("xformOp:rotateXYZ"); + static TfToken scale("xformOp:scale"); + static TfToken trans("xformOp:translate"); + static TfToken pivot("xformOp:translate:pivot"); + static TfToken notPivot("!invert!xformOp:translate:pivot"); + + auto xformable = UsdGeomXformable(prim); + bool resetsXformStack; + auto xformOps = xformable.GetOrderedXformOps(&resetsXformStack); + xformable.ClearXformOpOrder(); + auto primXform = UsdGeomXformCommonAPI(prim); + for (const auto& op : xformOps) + { + auto opName = op.GetOpName(); + + // RotateX, RotateY, RotateZ + if ((opName == rotX) || (opName == rotY) || (opName == rotZ)) + { + float retValue; + if (op.Get(&retValue)) + { + if (opName == rotX) + primXform.SetRotate(GfVec3f(retValue, 0, 0)); + else if (opName == rotY) + primXform.SetRotate(GfVec3f(0, retValue, 0)); + else if (opName == rotZ) + primXform.SetRotate(GfVec3f(0, 0, retValue)); + } + } + // RotateXYZ + else if (opName == rotXYZ) + { + GfVec3f retValue; + if (op.Get(&retValue)) + { + primXform.SetRotate(retValue); + } + } + // Scale + else if (opName == scale) + { + GfVec3f retValue; + if (op.Get(&retValue)) + { + primXform.SetScale(retValue); + } + } + // Translate + else if (opName == trans) + { + GfVec3d retValue; + if (op.Get(&retValue)) + { + primXform.SetTranslate(retValue); + } + } + // Scale / rotate pivot + else if (opName == pivot) + { + GfVec3f retValue; + if (op.Get(&retValue)) + { + primXform.SetPivot(retValue); + } + } + // Scale / rotate pivot inverse + else if (opName == notPivot) + { + // automatically added, nothing to do. + } + // Not compatible + else + { + // Restore old + xformable.SetXformOpOrder(xformOps); + std::string err = TfStringPrintf("Incompatible xform op %s:", op.GetOpName().GetString().c_str()); + throw std::runtime_error(err.c_str()); + } + } + return primXform; +} + +//------------------------------------------------------------------------------ +// Operations: translate, rotate, scale, pivot +//------------------------------------------------------------------------------ + +void translateOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z) +{ + auto primXform = UsdGeomXformCommonAPI(prim); + if (!primXform.SetTranslate(GfVec3d(x, y, z))) + { + // This could mean that we have an incompatible xformOp in the stack + try { + primXform = convertToCompatibleCommonAPI(prim); + if (!primXform.SetTranslate(GfVec3d(x,y,z))) + throw std::runtime_error("Unable to SetTranslate after conversion to CommonAPI."); + } + catch (const std::exception& e) { + std::string err = TfStringPrintf("Failed to translate prim %s - %s", + path.string().c_str(), e.what()); + UFE_LOG(err.c_str()); + throw; + } + } +} + +void rotateOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z) +{ + auto primXform = UsdGeomXformCommonAPI(prim); + if (!primXform.SetRotate(GfVec3f(x, y, z))) + { + // This could mean that we have an incompatible xformOp in the stack + try { + primXform = convertToCompatibleCommonAPI(prim); + if (!primXform.SetRotate(GfVec3f(x, y, z))) + throw std::runtime_error("Unable to SetRotate after conversion to CommonAPI."); + } + catch (const std::exception& e) { + std::string err = TfStringPrintf("Failed to rotate prim %s - %s", + path.string().c_str(), e.what()); + UFE_LOG(err.c_str()); + throw; + } + } +} + +void scaleOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z) +{ + auto primXform = UsdGeomXformCommonAPI(prim); + if (!primXform.SetScale(GfVec3f(x, y, z))) + { + // This could mean that we have an incompatible xformOp in the stack + try { + primXform = convertToCompatibleCommonAPI(prim); + if (!primXform.SetScale(GfVec3f(x, y, z))) + throw std::runtime_error("Unable to SetScale after conversion to CommonAPI."); + } + catch (const std::exception& e) { + std::string err = TfStringPrintf("Failed to scale prim %s - %s", + path.string().c_str(), e.what()); + UFE_LOG(err.c_str()); + throw; + } + } +} + +void rotatePivotTranslateOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z) +{ + auto primXform = UsdGeomXformCommonAPI(prim); + if (!primXform.SetPivot(GfVec3f(x, y, z))) + { + // This could mean that we have an incompatible xformOp in the stack + try { + primXform = convertToCompatibleCommonAPI(prim); + if (!primXform.SetPivot(GfVec3f(x, y, z))) + throw std::runtime_error("Unable to SetPivot after conversion to CommonAPI."); + } + catch (const std::exception& e) { + std::string err = TfStringPrintf("Failed to set pivot for prim %s - %s", + path.string().c_str(), e.what()); + UFE_LOG(err.c_str()); + throw; + } + } +} + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/private/Utils.h b/lib/ufe/private/Utils.h new file mode 100644 index 0000000000..65b1f6c5db --- /dev/null +++ b/lib/ufe/private/Utils.h @@ -0,0 +1,71 @@ +// +// Copyright 2019 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. +// +#pragma once + +#include "../../base/api.h" + +#include "ufe/path.h" + +#include "pxr/usd/usd/prim.h" +#include "pxr/base/tf/token.h" +#include "pxr/usd/usdGeom/xformCommonAPI.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { +namespace ufe { + +//------------------------------------------------------------------------------ +// Private globals and macros +//------------------------------------------------------------------------------ +const std::string kIllegalUSDPath = "Illegal USD run-time path %s."; + +#if !defined(NDEBUG) + #define TEST_USD_PATH(SEG, PATH) \ + assert(SEG.size() == 2); \ + if (SEG.size() != 2) \ + TF_WARN(kIllegalUSDPath.c_str(), PATH.string().c_str()); +#else + #define TEST_USD_PATH(SEG, PATH) \ + if (SEG.size() != 2) \ + TF_WARN(kIllegalUSDPath.c_str(), PATH.string().c_str()); +#endif + +//------------------------------------------------------------------------------ +// Private helper functions +//------------------------------------------------------------------------------ + +//! Extended support for the xform operations. +UsdGeomXformCommonAPI convertToCompatibleCommonAPI(const UsdPrim& prim); + +//------------------------------------------------------------------------------ +// Operations: translate, rotate, scale, pivot +//------------------------------------------------------------------------------ + +//! Absolute translation of the given prim. +void translateOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z); + +//! Absolute rotation (degrees) of the given prim. +void rotateOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z); + +//! Absolute scale of the given prim. +void scaleOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z); + +//! Absolute translation of the given prim's pivot point. +void rotatePivotTranslateOp(const UsdPrim& prim, const Ufe::Path& path, double x, double y, double z); + +} // namespace ufe +} // namespace MayaUsd diff --git a/lib/ufe/wrapUtils.cpp b/lib/ufe/wrapUtils.cpp new file mode 100644 index 0000000000..bd04e9b7c9 --- /dev/null +++ b/lib/ufe/wrapUtils.cpp @@ -0,0 +1,71 @@ +// +// Copyright 2019 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. +// + +#include + +#include "UsdSceneItem.h" +#include "Utils.h" + +#include "ufe/runTimeMgr.h" +#include "ufe/rtid.h" + +using namespace MayaUsd; +using namespace boost::python; + +UsdPrim getPrimFromRawItem(uint64_t rawItem) +{ + Ufe::SceneItem* item = reinterpret_cast(rawItem); + ufe::UsdSceneItem* usdItem = dynamic_cast(item); + if (nullptr != usdItem) + { + return usdItem->prim(); + } + return UsdPrim(); +} + +#ifdef UFE_V2_FEATURES_AVAILABLE +std::string getNodeNameFromRawItem(uint64_t rawItem) +{ + std::string name; + Ufe::SceneItem* item = reinterpret_cast(rawItem); + if (nullptr != item) + name = item->nodeName(); + return name; +} +#endif + +std::string getNodeTypeFromRawItem(uint64_t rawItem) +{ + std::string type; + Ufe::SceneItem* item = reinterpret_cast(rawItem); + if (nullptr != item) + { + // Prepend the name of the runtime manager of this item to the type. + type = Ufe::RunTimeMgr::instance().getName(item->runTimeId()) + item->nodeType(); + } + return type; +} + +BOOST_PYTHON_MODULE(ufe) +{ + def("getPrimFromRawItem", getPrimFromRawItem); + + #ifdef UFE_V2_FEATURES_AVAILABLE + def("getNodeNameFromRawItem", getNodeNameFromRawItem); + #endif + + def("getNodeTypeFromRawItem", getNodeTypeFromRawItem); +} diff --git a/plugin/pxr/maya/lib/usdMaya/colorSpace.cpp b/lib/utils/colorSpace.cpp similarity index 97% rename from plugin/pxr/maya/lib/usdMaya/colorSpace.cpp rename to lib/utils/colorSpace.cpp index 3cd18de21c..4d19f915a6 100644 --- a/plugin/pxr/maya/lib/usdMaya/colorSpace.cpp +++ b/lib/utils/colorSpace.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/colorSpace.h" +#include "colorSpace.h" #include "pxr/base/tf/envSetting.h" diff --git a/plugin/pxr/maya/lib/usdMaya/colorSpace.h b/lib/utils/colorSpace.h similarity index 98% rename from plugin/pxr/maya/lib/usdMaya/colorSpace.h rename to lib/utils/colorSpace.h index c582d29dab..eb3b6f9772 100644 --- a/plugin/pxr/maya/lib/usdMaya/colorSpace.h +++ b/lib/utils/colorSpace.h @@ -18,7 +18,7 @@ /// \file usdMaya/colorSpace.h -#include "usdMaya/api.h" +#include "../base/api.h" #include "pxr/pxr.h" @@ -50,7 +50,7 @@ namespace UsdMayaColorSpace /// You should only be setting that if you've more or less fully switched to /// Viewport 2.0 (as proper color management is only supported there). /// -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool IsColorManaged(); diff --git a/plugin/pxr/maya/lib/usdMaya/query.cpp b/lib/utils/query.cpp similarity index 95% rename from plugin/pxr/maya/lib/usdMaya/query.cpp rename to lib/utils/query.cpp index 452f330d05..2afefa934e 100644 --- a/plugin/pxr/maya/lib/usdMaya/query.cpp +++ b/lib/utils/query.cpp @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/query.h" +#include "query.h" -#include "usdMaya/usdPrimProvider.h" -#include "usdMaya/util.h" +#include "../nodes/usdPrimProvider.h" +#include "util.h" #include "pxr/base/arch/systemInfo.h" diff --git a/plugin/pxr/maya/lib/usdMaya/query.h b/lib/utils/query.h similarity index 93% rename from plugin/pxr/maya/lib/usdMaya/query.h rename to lib/utils/query.h index 47f8cc4b70..6916cf65a0 100644 --- a/plugin/pxr/maya/lib/usdMaya/query.h +++ b/lib/utils/query.h @@ -18,7 +18,7 @@ /// \file usdMaya/query.h -#include "usdMaya/api.h" +#include "../base/api.h" #include "pxr/pxr.h" @@ -35,9 +35,9 @@ struct UsdMayaQuery { /*! \brief converts a dagPath of a usdStageShapeNode into a usdprim */ - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static UsdPrim GetPrim(const std::string& shapeName); - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static void ReloadStage(const std::string& shapeName); }; diff --git a/plugin/pxr/maya/lib/usdMaya/stageCache.cpp b/lib/utils/stageCache.cpp similarity index 98% rename from plugin/pxr/maya/lib/usdMaya/stageCache.cpp rename to lib/utils/stageCache.cpp index a41c39a379..f0b13c07b6 100644 --- a/plugin/pxr/maya/lib/usdMaya/stageCache.cpp +++ b/lib/utils/stageCache.cpp @@ -13,9 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/stageCache.h" +#include "stageCache.h" -#include "usdMaya/notice.h" +#include "../listeners/notice.h" #include "pxr/usd/sdf/attributeSpec.h" #include "pxr/usd/sdf/layer.h" diff --git a/plugin/pxr/maya/lib/usdMaya/stageCache.h b/lib/utils/stageCache.h similarity index 94% rename from plugin/pxr/maya/lib/usdMaya/stageCache.h rename to lib/utils/stageCache.h index 99cd23e0f3..61d59141d6 100644 --- a/plugin/pxr/maya/lib/usdMaya/stageCache.h +++ b/lib/utils/stageCache.h @@ -18,7 +18,7 @@ /// \file usdMaya/stageCache.h -#include "usdMaya/api.h" +#include "../base/api.h" #include "pxr/pxr.h" @@ -38,24 +38,25 @@ class UsdMayaStageCache /// Return the singleton stage cache for use by all USD clients within Maya. /// 2 stage caches are maintained; 1 for stages that have been /// force-populated, and 1 for stages that have not been force-populated. - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static UsdStageCache& Get(const bool forcePopulate=true); /// Clear the cache - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static void Clear(); /// Erase all stages from the stage caches whose root layer path is /// \p layerPath. /// /// The number of stages erased from the caches is returned. - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static size_t EraseAllStagesWithRootLayerPath( const std::string& layerPath); /// Gets (or creates) a shared session layer tied with the given variant /// selections and draw mode on the given root path. /// The stage is cached for the lifetime of the current Maya scene. + MAYAUSD_CORE_PUBLIC static SdfLayerRefPtr GetSharedSessionLayer( const SdfPath& rootPath, const std::map& variantSelections, diff --git a/plugin/pxr/maya/lib/usdMaya/util.cpp b/lib/utils/util.cpp similarity index 99% rename from plugin/pxr/maya/lib/usdMaya/util.cpp rename to lib/utils/util.cpp index 450ad4e3c5..7e3fd68c7b 100644 --- a/plugin/pxr/maya/lib/usdMaya/util.cpp +++ b/lib/utils/util.cpp @@ -13,10 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "pxr/pxr.h" -#include "usdMaya/colorSpace.h" -#include "usdMaya/util.h" +#include "util.h" + +#include "colorSpace.h" #include "pxr/base/gf/gamma.h" #include "pxr/base/gf/vec2f.h" @@ -738,7 +738,7 @@ _getAttachedMayaShaderObjects( for (unsigned int i=0; i < setObjs.length(); ++i) { // Get associated Set and Shading Group MFnSet setFn(setObjs[i], &status); - MPlug seSurfaceShaderPlg = setFn.findPlug("surfaceShader", &status); + MPlug seSurfaceShaderPlg = setFn.findPlug("surfaceShader", true, &status); // Find connection shader->shadingGroup MPlugArray plgCons; @@ -811,11 +811,11 @@ _GetColorAndTransparencyFromDepNode( { MStatus status; MFnDependencyNode d(shaderObj); - MPlug colorPlug = d.findPlug("color", &status); + MPlug colorPlug = d.findPlug("color", true, &status); if (!status) { return false; } - MPlug transparencyPlug = d.findPlug("transparency", &status); + MPlug transparencyPlug = d.findPlug("transparency", true, &status); if (!status) { return false; } @@ -1358,12 +1358,12 @@ UsdMayaUtil::getPlugMatrix( MMatrix* outVal) { MStatus status; - MPlug plug = depNode.findPlug(attr, &status); + MPlug plug = depNode.findPlug(attr, true, &status); if (!status) { return false; } - MObject plugObj = plug.asMObject(MDGContext::fsNormal, &status); + MObject plugObj = plug.asMObject(&status); if (!status) { return false; } @@ -1384,7 +1384,7 @@ UsdMayaUtil::setPlugMatrix( const GfMatrix4d& mx) { MStatus status; - MPlug plug = depNode.findPlug(attr, &status); + MPlug plug = depNode.findPlug(attr, true, &status); CHECK_MSTATUS_AND_RETURN(status, false); return setPlugMatrix(mx, plug); } diff --git a/plugin/pxr/maya/lib/usdMaya/util.h b/lib/utils/util.h similarity index 94% rename from plugin/pxr/maya/lib/usdMaya/util.h rename to lib/utils/util.h index 8c13e58030..961c81fdb2 100644 --- a/plugin/pxr/maya/lib/usdMaya/util.h +++ b/lib/utils/util.h @@ -19,7 +19,7 @@ /// \file usdMaya/util.h #include "pxr/pxr.h" -#include "usdMaya/api.h" +#include "../base/api.h" #include "pxr/base/gf/vec2f.h" #include "pxr/base/gf/vec3f.h" @@ -113,9 +113,9 @@ class MDataHandleHolder : public TfRefBase MDataHandle _dataHandle; public: - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC static TfRefPtr New(const MPlug& plug); - PXRUSDMAYA_API + MAYAUSD_CORE_PUBLIC MDataHandle GetDataHandle() { return _dataHandle; } private: @@ -165,13 +165,13 @@ ConvertCMToMM(const double cm) /// Converts the given value \p mdistance in Maya's MDistance units to the /// equivalent value in USD's metersPerUnit. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC double ConvertMDistanceUnitToUsdGeomLinearUnit( const MDistance::Unit mdistanceUnit); /// Coverts the given value \p linearUnit in USD's metersPerUnit to the /// equivalent value in Maya's MDistance units. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MDistance::Unit ConvertUsdGeomLinearUnitToMDistanceUnit( const double linearUnit); @@ -185,21 +185,21 @@ MDistance::Unit ConvertUsdGeomLinearUnitToMDistanceUnit( /// /// If \p mayaNode is not one of these or if an error is encountered, an /// empty string will be returned. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC std::string GetMayaNodeName(const MObject& mayaNode); /// Gets the Maya MObject for the node named \p nodeName. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MStatus GetMObjectByName(const std::string& nodeName, MObject& mObj); /// Gets the Maya MDagPath for the node named \p nodeName. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MStatus GetDagPathByName(const std::string& nodeName, MDagPath& dagPath); /// Gets the Maya MPlug for the given \p attrPath. /// The attribute path should be specified as "nodeName.attrName" (the format /// used by MEL). -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MStatus GetPlugByName(const std::string& attrPath, MPlug& plug); /// Get the MPlug for the output time attribute of Maya's global time object @@ -214,36 +214,36 @@ MStatus GetPlugByName(const std::string& attrPath, MPlug& plug); /// all MFn::kTime function set objects in the scene and returning the one whose /// outTime attribute matches the current time. If no such object can be found, /// an invalid plug is returned. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MPlug GetMayaTimePlug(); /// Get the MPlug for the shaders attribute of Maya's defaultShaderList /// /// This is an accessor for the "defaultShaderList1.shaders" plug. Similar to /// GetMayaTimePlug(), it will traverse through MFn::kShaderList objects. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MPlug GetMayaShaderListPlug(); /// Get the MObject for the DefaultLightSet, which should add any light nodes /// as members for them to take effect in the scene -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MObject GetDefaultLightSetObject(); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool isAncestorDescendentRelationship( const MDagPath& path1, const MDagPath& path2); // returns 0 if static, 1 if sampled, and 2 if a curve -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC int getSampledType(const MPlug& iPlug, const bool includeConnectedChildren); /// Determine if the Maya object \p mayaObject is animated or not -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool isAnimated(const MObject& mayaObject, const bool checkParent = false); // Determine if a specific Maya plug is animated or not. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool isPlugAnimated(const MPlug& plug); /// Determine if a Maya object is an intermediate object. @@ -251,11 +251,11 @@ bool isPlugAnimated(const MPlug& plug); /// Only objects with the MFnDagNode function set can be intermediate objects. /// Objects whose intermediate object status cannot be determined are assumed /// not to be intermediate objects. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool isIntermediate(const MObject& object); // returns true for visible and lod invisible and not templated objects -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool isRenderable(const MObject& object); /// Determine whether a Maya object can be saved to or exported from the Maya @@ -263,7 +263,7 @@ bool isRenderable(const MObject& object); /// /// Objects whose "default node" or "do not write" status cannot be determined /// using the MFnDependencyNode function set are assumed to be writable. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool isWritable(const MObject& object); /// This is the delimiter that Maya uses to identify levels of hierarchy in the @@ -279,16 +279,16 @@ const std::string MayaNamespaceDelimiter(":"); /// This will turn "taco:foo:bar" into "foo:bar" for \p nsDepth == 1, or /// "taco:foo:bar" into "bar" for \p nsDepth > 1. /// If \p nsDepth is -1, all namespaces are stripped. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC std::string stripNamespaces( const std::string& nodeName, const int nsDepth = -1); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC std::string SanitizeName(const std::string& name); // This to allow various pipeline to sanitize the colorset name for output -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC std::string SanitizeColorSetName(const std::string& name); /// Get the base colors and opacities from the shader(s) bound to \p node. @@ -297,7 +297,7 @@ std::string SanitizeColorSetName(const std::string& name); /// A single value for each of color and alpha will be returned, /// interpolation will be constant, and assignmentIndices will be empty. /// -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool GetLinearShaderColor( const MFnDagNode& node, PXR_NS::VtVec3fArray* RGBData, @@ -318,7 +318,7 @@ bool GetLinearShaderColor( /// representing per-face assignments. Faces with no assigned shader will have /// a value of -1 in \p assignmentIndices. \p interpolation will be uniform. /// -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool GetLinearShaderColor( const MFnMesh& mesh, PXR_NS::VtVec3fArray* RGBData, @@ -328,28 +328,28 @@ bool GetLinearShaderColor( /// Combine distinct indices that point to the same values to all point to the /// same index for that value. This will potentially shrink the data array. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC void MergeEquivalentIndexedValues( PXR_NS::VtFloatArray* valueData, PXR_NS::VtIntArray* assignmentIndices); /// Combine distinct indices that point to the same values to all point to the /// same index for that value. This will potentially shrink the data array. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC void MergeEquivalentIndexedValues( PXR_NS::VtVec2fArray* valueData, PXR_NS::VtIntArray* assignmentIndices); /// Combine distinct indices that point to the same values to all point to the /// same index for that value. This will potentially shrink the data array. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC void MergeEquivalentIndexedValues( PXR_NS::VtVec3fArray* valueData, PXR_NS::VtIntArray* assignmentIndices); /// Combine distinct indices that point to the same values to all point to the /// same index for that value. This will potentially shrink the data array. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC void MergeEquivalentIndexedValues( PXR_NS::VtVec4fArray* valueData, PXR_NS::VtIntArray* assignmentIndices); @@ -358,7 +358,7 @@ void MergeEquivalentIndexedValues( /// constant interpolation if possible. This will potentially shrink the /// indices array and will update the interpolation if any compression was /// possible. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC void CompressFaceVaryingPrimvarIndices( const MFnMesh& mesh, PXR_NS::TfToken* interpolation, @@ -370,20 +370,20 @@ void CompressFaceVaryingPrimvarIndices( /// default (or since being brought in from a reference for plugs on nodes from /// referenced files), or if the plug is the destination of a connection. /// Otherwise, it is considered unauthored. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool IsAuthored(const MPlug& plug); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MPlug GetConnected(const MPlug& plug); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC void Connect( const MPlug& srcPlug, const MPlug& dstPlug, const bool clearDstPlug); /// Get a named child plug of \p plug by name. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MPlug FindChildPlugByName(const MPlug& plug, const MString& name); /// Converts the given Maya node name \p nodeName into an SdfPath. @@ -391,8 +391,8 @@ MPlug FindChildPlugByName(const MPlug& plug, const MString& name); /// Elements of the path will be sanitized such that it is a valid SdfPath. /// This means it will replace Maya's namespace delimiter (':') with /// underscores ('_'). -PXRUSDMAYA_API -PXR_NS::SdfPath MayaNodeNameToSdfPath( +MAYAUSD_CORE_PUBLIC +SdfPath MayaNodeNameToSdfPath( const std::string& nodeName, const bool stripNamespaces); @@ -405,14 +405,14 @@ PXR_NS::SdfPath MayaNodeNameToSdfPath( /// Elements of the path will be sanitized such that it is a valid SdfPath. /// This means it will replace Maya's namespace delimiter (':') with /// underscores ('_'). -PXRUSDMAYA_API -PXR_NS::SdfPath MDagPathToUsdPath( +MAYAUSD_CORE_PUBLIC +SdfPath MDagPathToUsdPath( const MDagPath& dagPath, const bool mergeTransformAndShape, const bool stripNamespaces); /// Convenience function to retrieve custom data -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool GetBoolCustomData( const PXR_NS::UsdAttribute& obj, const PXR_NS::TfToken& key, @@ -439,13 +439,13 @@ bool getPlugValue( } /// Convert a Gf matrix to an MMatrix. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MMatrix GfMatrixToMMatrix(const GfMatrix4d& mx); // Like getPlugValue, but gets the matrix stored inside the MFnMatrixData on a // plug. // Returns true upon success, placing the matrix in the outVal parameter. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool getPlugMatrix( const MFnDependencyNode& depNode, const MString& attr, @@ -453,13 +453,13 @@ bool getPlugMatrix( /// Set a matrix value on plug name \p attr, of \p depNode. /// Returns true if the value was set on the plug successfully, false otherwise. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool setPlugMatrix( const MFnDependencyNode& depNode, const MString& attr, const GfMatrix4d& mx); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool setPlugMatrix(const GfMatrix4d& mx, MPlug& plug); /// Given an \p usdAttr , extract the value at the default timecode and write @@ -467,7 +467,7 @@ bool setPlugMatrix(const GfMatrix4d& mx, MPlug& plug); /// This will make sure that color values (which are linear in usd) get /// gamma corrected (display in maya). /// Returns true if the value was set on the plug successfully, false otherwise. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool setPlugValue(const PXR_NS::UsdAttribute& attr, MPlug& attrPlug); /// Given an \p usdAttr , extract the value at timecode \p time and write it @@ -475,7 +475,7 @@ bool setPlugValue(const PXR_NS::UsdAttribute& attr, MPlug& attrPlug); /// This will make sure that color values (which are linear in usd) get /// gamma corrected (display in maya). /// Returns true if the value was set on the plug successfully, false otherwise. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool setPlugValue( const PXR_NS::UsdAttribute& attr, const PXR_NS::UsdTimeCode time, @@ -501,20 +501,20 @@ bool setPlugValue( /// plug. When the helper object goes out of scope, the data handle will be /// destructed. /// If the plug's data handle could not be obtained, returns nullptr. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC TfRefPtr GetPlugDataHandle(const MPlug& plug); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool SetNotes(MFnDependencyNode& depNode, const std::string& notes); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool SetHiddenInOutliner(MFnDependencyNode& depNode, const bool hidden); /// Reads values from the given \p argData into a VtDictionary, using the /// \p guideDict to figure out which keys and what type of values should be read /// from \p argData. /// Mainly useful for parsing arguments in commands all at once. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC VtDictionary GetDictionaryFromArgDatabase( const MArgDatabase& argData, const VtDictionary& guideDict); @@ -525,7 +525,7 @@ VtDictionary GetDictionaryFromArgDatabase( /// Mainly useful for parsing arguments one-by-one in translators' option /// strings. If you have an MArgList/MArgParser/MArgDatabase, it's going to be /// way simpler to use GetDictionaryFromArgDatabase() instead. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC VtValue ParseArgumentValue( const std::string& key, const std::string& value, @@ -537,18 +537,18 @@ VtValue ParseArgumentValue( /// The returned list is sorted from furthest to closest ancestor. The returned /// list will always have the given type \p ty as the last item. /// Note that this calls out to MEL. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC std::vector GetAllAncestorMayaNodeTypes(const std::string& ty); /// If dagPath is a scene assembly node or is the descendant of one, populates /// the \p *assemblyPath with the assembly path and returns \c true. /// Otherwise, returns \c false. -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC bool FindAncestorSceneAssembly( const MDagPath& dagPath, MDagPath* assemblyPath = nullptr); -PXRUSDMAYA_API +MAYAUSD_CORE_PUBLIC MBoundingBox GetInfiniteBoundingBox(); } // namespace UsdMayaUtil diff --git a/lib/utils/utilFileSystem.cpp b/lib/utils/utilFileSystem.cpp new file mode 100644 index 0000000000..57be2519c6 --- /dev/null +++ b/lib/utils/utilFileSystem.cpp @@ -0,0 +1,99 @@ + +#include "utilFileSystem.h" +#include "../base/debugCodes.h" + +#include +#include +#include + +#include "pxr/usd/ar/resolver.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +std::string +UsdMayaUtilFileSystem::resolvePath(const std::string& filePath) +{ + ArResolver& resolver = ArGetResolver(); + return resolver.Resolve(filePath); +} + +std::string +UsdMayaUtilFileSystem::getDir(const std::string &fullFilePath) +{ + return boost::filesystem::path(fullFilePath).parent_path().string(); +} + +std::string +UsdMayaUtilFileSystem::getMayaReferencedFileDir(const MObject &proxyShapeNode) +{ + // Can not use MFnDependencyNode(proxyShapeNode).isFromReferencedFile() to test if it is reference node or not, + // which always return false even the proxyShape node is referenced... + + MStatus stat; + MFnReference refFn; + MItDependencyNodes dgIter(MFn::kReference, &stat); + for (; !dgIter.isDone(); dgIter.next()) + { + MObject cRefNode = dgIter.thisNode(); + refFn.setObject(cRefNode); + if(refFn.containsNodeExactly(proxyShapeNode, &stat)) + { + // According to Maya API document, the second argument is 'includePath' and set it to true to include the file path. + // However, I have to set it to false to return the full file path otherwise I get a file name only... + MString refFilePath = refFn.fileName(true, false, false, &stat); + if(!refFilePath.length()) + return std::string(); + + std::string referencedFilePath = refFilePath.asChar(); + TF_DEBUG(USDMAYA_PROXYSHAPEBASE).Msg("getMayaReferencedFileDir: The reference file that contains the proxyShape node is : %s\n", referencedFilePath.c_str()); + + return getDir(referencedFilePath); + } + } + + return std::string(); +} + +std::string +UsdMayaUtilFileSystem::getMayaSceneFileDir() +{ + std::string currentFile = std::string(MFileIO::currentFile().asChar(), MFileIO::currentFile().length()); + size_t filePathSize = currentFile.size(); + if(filePathSize < 4) + return std::string(); + + // If scene is untitled, the maya file will be MayaWorkspaceDir/untitled : + constexpr char ma_ext[] = ".ma"; + constexpr char mb_ext[] = ".mb"; + auto ext_start = currentFile.end() - 3; + if(std::equal(ma_ext, ma_ext + 3, ext_start) || std::equal(mb_ext, mb_ext + 3, ext_start)) + return getDir(currentFile); + + return std::string(); +} + +std::string +UsdMayaUtilFileSystem::resolveRelativePathWithinMayaContext(const MObject &proxyShape, const std::string& relativeFilePath) +{ + if (relativeFilePath.length() < 3) + return relativeFilePath; + + std::string currentFileDir = getMayaReferencedFileDir(proxyShape); + + if(currentFileDir.empty()) + currentFileDir = getMayaSceneFileDir(); + + if(currentFileDir.empty()) + return relativeFilePath; + + boost::system::error_code errorCode; + auto path = boost::filesystem::canonical(relativeFilePath, currentFileDir, errorCode); + if (errorCode) + { + // file does not exist + return std::string(); + } + + return path.string(); +} + diff --git a/lib/utils/utilFileSystem.h b/lib/utils/utilFileSystem.h new file mode 100644 index 0000000000..9241c1c224 --- /dev/null +++ b/lib/utils/utilFileSystem.h @@ -0,0 +1,42 @@ +#include "pxr/pxr.h" + +#include "../base/api.h" + +#include +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +namespace UsdMayaUtilFileSystem +{ + /*! \brief returns the resolved filesystem path for the file identified by the given path + */ + MAYAUSD_CORE_PUBLIC + std::string resolvePath(const std::string& filePath); + + /*! \brief returns the path to the + */ + MAYAUSD_CORE_PUBLIC + std::string getDir(const std::string &fullFilePath); + + /*! \brief returns parent directory of a maya scene file opened by reference + */ + MAYAUSD_CORE_PUBLIC + std::string getMayaReferencedFileDir(const MObject& proxyShapeNode); + + /*! \brief returns parent directory of opened maya scene file + */ + MAYAUSD_CORE_PUBLIC + std::string getMayaSceneFileDir(); + + /*! \brief returns the aboluste path relative to the maya file + */ + MAYAUSD_CORE_PUBLIC + std::string resolveRelativePathWithinMayaContext(const MObject& proxyShape, + const std::string& relativeFilePath); + +} // namespace UsdMayaUtilFileSystem + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/mayaUSD.mod.template b/mayaUSD.mod.template index 2efc2e1b59..e356af9ef8 100644 --- a/mayaUSD.mod.template +++ b/mayaUSD.mod.template @@ -11,8 +11,16 @@ MAYA_SCRIPT_PATH+:=maya/lib/usd/usdMaya/resources MAYA_PLUG_IN_PATH+:=maya/plugin PXR_PLUGINPATH_NAME+:=lib/usd ++ MayaUSD_LIB ${MAYAUSD_VERSION} ${CMAKE_INSTALL_PREFIX} +PATH+:=lib +PYTHONPATH+:=lib/python +PXR_PLUGINPATH_NAME+:=lib/usd +VP2_RENDER_DELEGATE_PROXY=1 + + AL_USDMaya ${AL_USDMAYA_VERSION} ${CMAKE_INSTALL_PREFIX}/plugin/al PYTHONPATH+:=lib/python PATH+:=lib MAYA_PLUG_IN_PATH+:=plugin -PXR_PLUGINPATH_NAME+:=lib/usd \ No newline at end of file +PXR_PLUGINPATH_NAME+:=lib/usd +PXR_PLUGINPATH_NAME+:=plugin +MAYA_WANT_UFE_SELECTION=1 diff --git a/plugin/adsk/CMakeLists.txt b/plugin/adsk/CMakeLists.txt new file mode 100644 index 0000000000..63fa811c9d --- /dev/null +++ b/plugin/adsk/CMakeLists.txt @@ -0,0 +1,9 @@ +message("========== ADSK USD Plugin ==========") + +set(INSTALL_DIR_SUFFIX plugin/adsk) + +#============================================================================== +# Packages +#============================================================================== +add_subdirectory(plugin) + diff --git a/plugin/adsk/plugin/CMakeLists.txt b/plugin/adsk/plugin/CMakeLists.txt new file mode 100644 index 0000000000..e3a79fd92d --- /dev/null +++ b/plugin/adsk/plugin/CMakeLists.txt @@ -0,0 +1,76 @@ +set(PLUGIN_PACKAGE mayaUsdPlugin) + +if(CMAKE_WANT_UFE_BUILD) + find_package(UFE QUIET) + if(UFE_FOUND) + message(STATUS "Building with UFE ${UFE_VERSION} features enabled.") + include_directories(${UFE_INCLUDE_DIR}) + add_definitions(-DWANT_UFE_BUILD) + else() + message(STATUS "UFE not found. UFE features will be disabled.") + endif() +endif() + +add_library(${PLUGIN_PACKAGE} MODULE + plugin.cpp + ProxyShape.cpp +) + +target_compile_definitions(${PLUGIN_PACKAGE} + PRIVATE + MAYAUSD_PLUGIN_EXPORT +) + +target_include_directories(${PLUGIN_PACKAGE} + PRIVATE + ${MAYAUSD_INCLUDE_DIR} + ${PXR_INCLUDE_DIRS} +) + +target_link_libraries(${PLUGIN_PACKAGE} + PRIVATE + ${MAYA_LIBRARIES} + mayaUsd + ar + gf + kind + plug + sdf + tf + usd + usdGeom + usdUtils +) + +MAYA_SET_PLUGIN_PROPERTIES(${PLUGIN_PACKAGE}) + +# rpath setup +if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "plugin") + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_install_rpath(rpath ${PLUGIN_PACKAGE}) +endif() + +if(IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib64") + endif() +endif() + +install(TARGETS + ${PLUGIN_PACKAGE} + LIBRARY + DESTINATION ${INSTALL_DIR_SUFFIX}/plugin + RUNTIME + DESTINATION ${INSTALL_DIR_SUFFIX}/plugin +) + +if(IS_WINDOWS) + install(FILES $ DESTINATION ${INSTALL_DIR_SUFFIX}/plugin OPTIONAL) +endif() + diff --git a/plugin/adsk/plugin/ProxyShape.cpp b/plugin/adsk/plugin/ProxyShape.cpp new file mode 100644 index 0000000000..bb1ec6489d --- /dev/null +++ b/plugin/adsk/plugin/ProxyShape.cpp @@ -0,0 +1,64 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#include "ProxyShape.h" + +#include + +MAYAUSD_NS_DEF { + +// ======================================================== + +const MTypeId MAYAUSD_PROXYSHAPE_ID (0x58000095); + +const MTypeId ProxyShape::typeId(MayaUsd::MAYAUSD_PROXYSHAPE_ID); +const MString ProxyShape::typeName("mayaUsdProxyShape"); + +/* static */ +void* +ProxyShape::creator() +{ + return new ProxyShape(); +} + +/* static */ +MStatus +ProxyShape::initialize() +{ + MStatus retValue = inheritAttributesFrom(MayaUsdProxyShapeBase::typeName); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + + return retValue; +} + +ProxyShape::ProxyShape() : MayaUsdProxyShapeBase() +{ + TfRegistryManager::GetInstance().SubscribeTo(); +} + +/* virtual */ +ProxyShape::~ProxyShape() +{ + // + // empty + // +} + +void ProxyShape::postConstructor() +{ + ParentClass::postConstructor(); +} + +} // MayaUsd diff --git a/plugin/adsk/plugin/ProxyShape.h b/plugin/adsk/plugin/ProxyShape.h new file mode 100644 index 0000000000..e4d58925dc --- /dev/null +++ b/plugin/adsk/plugin/ProxyShape.h @@ -0,0 +1,54 @@ +// +// Copyright 2016 Pixar +// +// 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. +// +#pragma once + +#include "base/api.h" + +#include "mayaUsd/nodes/proxyShapeBase.h" + +#include "pxr/pxr.h" + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_NS_DEF { + +class ProxyShape : public MayaUsdProxyShapeBase +{ + public: + typedef MayaUsdProxyShapeBase ParentClass; + + MAYAUSD_PLUGIN_PUBLIC + static const MTypeId typeId; + MAYAUSD_PLUGIN_PUBLIC + static const MString typeName; + + MAYAUSD_PLUGIN_PUBLIC + static void* creator(); + + MAYAUSD_PLUGIN_PUBLIC + static MStatus initialize(); + + void postConstructor() override; + + private: + ProxyShape(); + + ProxyShape(const ProxyShape&); + ~ProxyShape() override; + ProxyShape& operator=(const ProxyShape&); +}; + +} // MayaUsd diff --git a/plugin/adsk/plugin/base/api.h b/plugin/adsk/plugin/base/api.h new file mode 100644 index 0000000000..dc445c2cc1 --- /dev/null +++ b/plugin/adsk/plugin/base/api.h @@ -0,0 +1,48 @@ +// +// Copyright 2019 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. +// + +#if defined _WIN32 || defined __CYGWIN__ + + // We need a different export symbol for the plugin because when we are building + // the actual Maya plugin we must 'export' the two functions for plugin load/unload. + // And then we won't set the core export because we need to 'import' the symbols. + #ifdef MAYAUSD_PLUGIN_EXPORT + #ifdef __GNUC__ + #define MAYAUSD_PLUGIN_PUBLIC __attribute__ ((dllexport)) + #else + #define MAYAUSD_PLUGIN_PUBLIC __declspec(dllexport) + #endif + #else + #ifdef __GNUC__ + #define MAYAUSD_PLUGIN_PUBLIC __attribute__ ((dllimport)) + #else + #define MAYAUSD_PLUGIN_PUBLIC __declspec(dllimport) + #endif + #endif + #define MAYAUSD_PLUGIN_LOCAL +#else + #if __GNUC__ >= 4 + #define MAYAUSD_PLUGIN_PUBLIC __attribute__ ((visibility ("default"))) + #define MAYAUSD_PLUGIN_LOCAL __attribute__ ((visibility ("hidden"))) +#else + #define MAYAUSD_PLUGIN_PUBLIC + #define MAYAUSD_PLUGIN_LOCAL +#endif +#endif + +// Convenience symbol versioning include: because api.h is widely +// included, this reduces the need to explicitly include mayaUsd.h. +#include "mayaUsd/mayaUsd.h" diff --git a/plugin/adsk/plugin/plugin.cpp b/plugin/adsk/plugin/plugin.cpp new file mode 100644 index 0000000000..675bfb78fa --- /dev/null +++ b/plugin/adsk/plugin/plugin.cpp @@ -0,0 +1,87 @@ +// +// Copyright 2019 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. +// + +#include "base/api.h" +#include "ProxyShape.h" + +#include +#include +#include +#include + +#if defined(WANT_UFE_BUILD) +#include +#endif + +#include +#include +#include + +#include "pxr/base/tf/envSetting.h" +#include "pxr/base/plug/plugin.h" +#include "pxr/base/plug/registry.h" + +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +MAYAUSD_PLUGIN_PUBLIC +MStatus initializePlugin(MObject obj) +{ + MStatus status; + MFnPlugin plugin(obj, "Autodesk", "1.0", "Any"); + + status = MayaUsdProxyShapePlugin::initialize(plugin); + CHECK_MSTATUS(status); + +#if defined(WANT_UFE_BUILD) + status = MayaUsd::ufe::initialize(); + if (!status) { + status.perror("mayaUsdPlugin: unable to initialize ufe."); + } +#endif + + status = plugin.registerShape( + MayaUsd::ProxyShape::typeName, + MayaUsd::ProxyShape::typeId, + MayaUsd::ProxyShape::creator, + MayaUsd::ProxyShape::initialize, + nullptr, + MayaUsdProxyShapePlugin::getProxyShapeClassification()); + CHECK_MSTATUS(status); + + return status; +} + +MAYAUSD_PLUGIN_PUBLIC +MStatus uninitializePlugin(MObject obj) +{ + MFnPlugin plugin(obj); + MStatus status; + + status = plugin.deregisterNode(MayaUsd::ProxyShape::typeId); + CHECK_MSTATUS(status); + + status = MayaUsdProxyShapePlugin::finalize(plugin); + CHECK_MSTATUS(status); + +#if defined(WANT_UFE_BUILD) + status = MayaUsd::ufe::finalize(); + CHECK_MSTATUS(status); +#endif + + return status; +} diff --git a/plugin/al/CMakeLists.txt b/plugin/al/CMakeLists.txt index 00c9b05ef8..aff32e13f2 100644 --- a/plugin/al/CMakeLists.txt +++ b/plugin/al/CMakeLists.txt @@ -17,29 +17,18 @@ option(BUILD_USDMAYA_SCHEMAS "Build optional schemas." ON) option(BUILD_USDMAYA_TRANSLATORS "Build optional translators." ON) option(SKIP_USDMAYA_TESTS "Build tests" OFF) -if ("${MAYA_DEVKIT_LOCATION}" STREQUAL "") - set(CMAKE_WANT_UFE_BUILD OFF) -else() - set(CMAKE_WANT_UFE_BUILD ON) -endif() - -include(${USD_CONFIG_FILE}) - -find_package(Maya REQUIRED) - # to get PYTHON_EXECUTABLE find_package(PythonInterp) -# find_package(MayaUSD REQUIRED) - if(CMAKE_WANT_UFE_BUILD) - add_definitions(-DWANT_UFE_BUILD) - - find_package(UFE REQUIRED) - include_directories(${UFE_INCLUDE_DIR}) - - message("UFE Build Enabled") - message("Using UFE version : ${UFE_VERSION}") + find_package(UFE QUIET) + if(UFE_FOUND) + message(STATUS "Building with UFE ${UFE_VERSION} features enabled.") + include_directories(${UFE_INCLUDE_DIR}) + add_definitions(-DWANT_UFE_BUILD) + else() + message(STATUS "UFE not found. UFE features will be disabled.") + endif() endif() # FindBoost is particularly buggy, and doesn't like custom boost locations. @@ -61,90 +50,6 @@ find_package(Boost COMPONENTS REQUIRED ) -if(NOT SKIP_USDMAYA_TESTS) - if (NOT GTEST_FOUND) - # First see if we can find a gtest that was downloaded and built. - if (NOT GOOGLETEST_BUILD_ROOT) - set(GOOGLETEST_BUILD_ROOT ${CMAKE_CURRENT_BINARY_DIR}) - endif() - if (NOT GTEST_ROOT) - set(GTEST_ROOT "${GOOGLETEST_BUILD_ROOT}/googletest-install") - endif() - find_package(GTest QUIET) - # At this point GTEST_FOUND is set to True in Release but False in Debug. - endif() - - enable_testing() - if (NOT GTEST_FOUND) - #====================================================================== - # Download and unpack googletest at configure time. Adapted from - # - # https://github.com/abseil/googletest/blob/master/googletest/README.md - # - # PPT, 22-Nov-2018. - - # Immediately convert CMAKE_MAKE_PROGRAM to forward slashes (if required). - # Attempting to do so in execute_process fails with string invalid escape - # sequence parsing errors. PPT, 22-Nov-2018. - file(TO_CMAKE_PATH ${CMAKE_MAKE_PROGRAM} CMAKE_MAKE_PROGRAM) - - if (GOOGLETEST_SRC_DIR) - configure_file(CMakeLists_googletest_src.txt.in ${GOOGLETEST_BUILD_ROOT}/googletest-config/CMakeLists.txt) - else() - configure_file(CMakeLists_googletest_download.txt.in ${GOOGLETEST_BUILD_ROOT}/googletest-config/CMakeLists.txt) - endif() - - message(STATUS "========== Installing GoogleTest... ==========") - set(FORCE_SHARED_CRT "") - if(MSVC) - set(FORCE_SHARED_CRT -DFORCE_SHARED_CRT=OFF) - endif() - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} . ${FORCE_SHARED_CRT} - RESULT_VARIABLE result - WORKING_DIRECTORY ${GOOGLETEST_BUILD_ROOT}/googletest-config ) - if(result) - message(FATAL_ERROR "CMake step for googletest failed: ${result}") - endif() - - execute_process(COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} - RESULT_VARIABLE result - WORKING_DIRECTORY ${GOOGLETEST_BUILD_ROOT}/googletest-config ) - if(result) - message(FATAL_ERROR "Build step for googletest failed: ${result}") - endif() - message(STATUS "========== ... GoogleTest installed. ==========") - - set(GTEST_ROOT ${GOOGLETEST_BUILD_ROOT}/googletest-install CACHE path "GoogleTest installation root") - #====================================================================== - endif() - - # https://gitlab.kitware.com/cmake/cmake/issues/17799 - # FindGtest is buggy when dealing with Debug build. - if (CMAKE_BUILD_TYPE MATCHES Debug AND GTEST_FOUND MATCHES FALSE) - message("Setting GTest libraries with debug...") - - if (GTEST_LIBRARY_DEBUG MATCHES GTEST_LIBRARY_DEBUG-NOTFOUND) - set(gtest_library "") - set(gtest_main_library "") - if(WIN32) - set(gtest_library lib/gtestd.lib) - set(gtest_main_library lib/gtest_maind.lib) - else() - set(gtest_library lib64/libgtestd.a) - set(gtest_main_library lib64/libgtest_maind.a) - endif() - set(GTEST_INCLUDE_DIRS ${GOOGLETEST_BUILD_ROOT}/googletest-install/include) - set(GTEST_LIBRARY_DEBUG ${GOOGLETEST_BUILD_ROOT}/googletest-install/${gtest_library}) - set(GTEST_MAIN_LIBRARY_DEBUG ${GOOGLETEST_BUILD_ROOT}/googletest-install/${gtest_main_library}) - endif() - - set(GTEST_LIBRARY ${GTEST_LIBRARY_DEBUG}) - set(GTEST_LIBRARIES ${GTEST_LIBRARY}) - set(GTEST_MAIN_LIBRARY ${GTEST_MAIN_LIBRARY_DEBUG}) - set(GTEST_MAIN_LIBRARIES ${GTEST_MAIN_LIBRARY}) - endif() -endif() - set(AL_USDMAYA_LOCATION_NAME "AL_USDMAYA_LOCATION" CACHE @@ -152,6 +57,8 @@ set(AL_USDMAYA_LOCATION_NAME "Name of the environment variable used to store AL_USDMaya installation location" ) +set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) + # Build all the utils set(EVENTS_INCLUDE_LOCATION ${CMAKE_CURRENT_LIST_DIR}/utils) set(USDUTILS_INCLUDE_LOCATION ${CMAKE_CURRENT_LIST_DIR}/usdutils) @@ -188,4 +95,4 @@ get_property(PYTHON_LIBRARY_LOCATION GLOBAL PROPERTY GLOBAL_PYTHON_LIBRARY_LOCAT configure_file(ALUsdMayaConfig.cmake.in ${PROJECT_BINARY_DIR}/ALUsdMayaConfig.cmake @ONLY) install(CODE "message(STATUS \"POST INSTALL: Compiling python/pyc for ${CMAKE_INSTALL_PREFIX} ... \")") -install(CODE "execute_process(COMMAND python -m compileall ${CMAKE_INSTALL_PREFIX} )") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m compileall ${CMAKE_INSTALL_PREFIX} )") diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/ForwardDeclares.h b/plugin/al/lib/AL_USDMaya/AL/usdmaya/ForwardDeclares.h index fbc8ee32d6..48542d3692 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/ForwardDeclares.h +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/ForwardDeclares.h @@ -24,7 +24,6 @@ namespace usdmaya { struct guid; class Global; struct MObjectMap; -class StageData; class StageCache; namespace cmds { diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/PluginRegister.h b/plugin/al/lib/AL_USDMaya/AL/usdmaya/PluginRegister.h index f44e12fa62..07b6893169 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/PluginRegister.h +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/PluginRegister.h @@ -22,7 +22,6 @@ #include "AL/maya/utils/CommandGuiHelper.h" #include "AL/maya/utils/MenuBuilder.h" #include "AL/usdmaya/Global.h" -#include "AL/usdmaya/StageData.h" #include "AL/usdmaya/cmds/CreateUsdPrim.h" #include "AL/usdmaya/cmds/DebugCommands.h" #include "AL/usdmaya/cmds/EventCommand.h" @@ -60,6 +59,12 @@ #include "maya/MGlobal.h" #include "maya/MStatus.h" +#include + +#if defined(WANT_UFE_BUILD) +#include +#endif + PXR_NAMESPACE_USING_DIRECTIVE namespace AL { @@ -232,7 +237,6 @@ MStatus registerPlugin(AFnPlugin& plugin) } } - AL_REGISTER_DATA(plugin, AL::usdmaya::StageData); AL_REGISTER_COMMAND(plugin, AL::maya::utils::CommandGuiListGen); AL_REGISTER_COMMAND(plugin, AL::usdmaya::cmds::CreateUsdPrim); AL_REGISTER_COMMAND(plugin, AL::usdmaya::cmds::LayerCreateLayer); @@ -272,7 +276,32 @@ MStatus registerPlugin(AFnPlugin& plugin) AL_REGISTER_TRANSLATOR(plugin, AL::usdmaya::fileio::ImportTranslator); AL_REGISTER_TRANSLATOR(plugin, AL::usdmaya::fileio::ExportTranslator); AL_REGISTER_DRAW_OVERRIDE(plugin, AL::usdmaya::nodes::ProxyDrawOverride); - AL_REGISTER_SHAPE_NODE(plugin, AL::usdmaya::nodes::ProxyShape, AL::usdmaya::nodes::ProxyShapeUI, AL::usdmaya::nodes::ProxyDrawOverride); + + status = MayaUsdProxyShapePlugin::initialize(plugin); + CHECK_MSTATUS(status); + + if (MayaUsdProxyShapePlugin::useVP2_NativeUSD_Rendering()) { + status = plugin.registerShape( + AL::usdmaya::nodes::ProxyShape::kTypeName, + AL::usdmaya::nodes::ProxyShape::kTypeId, + AL::usdmaya::nodes::ProxyShape::creator, + AL::usdmaya::nodes::ProxyShape::initialise, + AL::usdmaya::nodes::ProxyShapeUI::creator, + MayaUsdProxyShapePlugin::getProxyShapeClassification() + ); + CHECK_MSTATUS(status); + } + else { + AL_REGISTER_SHAPE_NODE(plugin, AL::usdmaya::nodes::ProxyShape, AL::usdmaya::nodes::ProxyShapeUI, AL::usdmaya::nodes::ProxyDrawOverride); + } + +#if defined(WANT_UFE_BUILD) + status = MayaUsd::ufe::initialize(); + if (!status) { + status.perror("Unable to initialize ufe."); + } +#endif + AL_REGISTER_TRANSFORM_NODE(plugin, AL::usdmaya::nodes::Transform, AL::usdmaya::nodes::TransformationMatrix); AL_REGISTER_DEPEND_NODE(plugin, AL::usdmaya::nodes::RendererManager); AL_REGISTER_DEPEND_NODE(plugin, AL::usdmaya::nodes::Layer); @@ -335,6 +364,11 @@ MStatus unregisterPlugin(AFnPlugin& plugin) { MStatus status; +#if defined(WANT_UFE_BUILD) + status = MayaUsd::ufe::finalize(); + CHECK_MSTATUS(status); +#endif + // gpuCachePluginMain used as an example. if (MGlobal::kInteractive == MGlobal::mayaState()) { MString cmd = "deleteSelectTypeItem(\"Surface\",\""; @@ -395,11 +429,14 @@ MStatus unregisterPlugin(AFnPlugin& plugin) AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::MeshAnimDeformer); AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::MeshAnimCreator); AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::ProxyShape); + + status = MayaUsdProxyShapePlugin::finalize(plugin); + CHECK_MSTATUS(status); + AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::Transform); AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::RendererManager); AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::Layer); AL_UNREGISTER_NODE(plugin, AL::usdmaya::nodes::LayerManager); - AL_UNREGISTER_DATA(plugin, AL::usdmaya::StageData); AL::usdmaya::Global::onPluginUnload(); return status; diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/StageData.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/StageData.cpp deleted file mode 100644 index b4149f9cf2..0000000000 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/StageData.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// -// Copyright 2017 Animal Logic -// -// 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. -// -#include "AL/usdmaya/StageData.h" -#include "AL/usdmaya/TypeIDs.h" -#include "AL/usdmaya/DebugCodes.h" -#include "AL/maya/event/MayaEventManager.h" - -namespace AL { -namespace usdmaya { - -const MTypeId StageData::kTypeId(AL_USDMAYA_STAGEDATA); -const MString StageData::kName("AL_usdmaya_StageData"); - - -//---------------------------------------------------------------------------------------------------------------------- -static void _cleanUp(void* gdPtr) -{ - StageData *gd = (StageData*)gdPtr; - gd->stage = UsdStageRefPtr(); -} - -//---------------------------------------------------------------------------------------------------------------------- -void* StageData::creator() -{ - return new StageData; -} - -//---------------------------------------------------------------------------------------------------------------------- -void StageData::copy(const MPxData& data) -{ - const StageData* stageData = dynamic_cast(&data); - if(stageData) - { - stage = stageData->stage; - primPath = stageData->primPath; - } -} - -//---------------------------------------------------------------------------------------------------------------------- -StageData::StageData() -{ - m_exitCallbackId = AL::maya::event::MayaEventManager::instance().registerCallback(_cleanUp, "MayaExiting", "DestroyStageDataOnExit", 0x10000, this); - TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("StageData::StageData() created: %p\n", this); -} - -//---------------------------------------------------------------------------------------------------------------------- -StageData::~StageData() -{ - AL::maya::event::MayaEventManager::instance().unregisterCallback(m_exitCallbackId); - TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("StageData::StageData() deleted: %p\n", this); -} - - -//---------------------------------------------------------------------------------------------------------------------- -MTypeId StageData::typeId() const -{ - return kTypeId; -} - -//---------------------------------------------------------------------------------------------------------------------- -MString StageData::name() const -{ - return kName; -} -} -//---------------------------------------------------------------------------------------------------------------------- -} // al -//---------------------------------------------------------------------------------------------------------------------- diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/StageData.h b/plugin/al/lib/AL_USDMaya/AL/usdmaya/StageData.h deleted file mode 100644 index 337c0a421f..0000000000 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/StageData.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright 2017 Animal Logic -// -// 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. -// -#pragma once - -#include "AL/usdmaya/Api.h" - -#include "AL/event/EventHandler.h" - -#include "maya/MPxGeometryData.h" - -#include "pxr/usd/usd/stage.h" - -PXR_NAMESPACE_USING_DIRECTIVE - -namespace AL { -namespace usdmaya { - -//---------------------------------------------------------------------------------------------------------------------- -/// \brief This code is effectively copied from the pixar plugin. It's just used to pass the usd stage through the DG -/// \ingroup usdmaya -//---------------------------------------------------------------------------------------------------------------------- -class StageData - : public MPxGeometryData -{ -public: - - /// \brief ctor - StageData(); - - /// \brief dtor - ~StageData(); - - /// \brief creates an instance of this data object - AL_USDMAYA_PUBLIC - static void* creator(); - - /// \brief copy the input stage data into this node - /// \param aDatum the data to copy - void copy(const MPxData& aDatum) override; - - /// the type id of the stage data - AL_USDMAYA_PUBLIC - static const MTypeId kTypeId; - - /// the type name of the stage data - AL_USDMAYA_PUBLIC - static const MString kName; - - /// the stage passed through the DG - UsdStageWeakPtr stage; - - /// the prim path root - SdfPath primPath; - -private: - MTypeId typeId() const override; - MString name() const override; - AL::event::CallbackId m_exitCallbackId; -}; - -//---------------------------------------------------------------------------------------------------------------------- -} // usdmaya -} // AL -//---------------------------------------------------------------------------------------------------------------------- diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimCreator.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimCreator.cpp index f68c40248a..9257a38e90 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimCreator.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimCreator.cpp @@ -19,7 +19,6 @@ #include "AL/usdmaya/DebugCodes.h" #include "AL/usdmaya/nodes/MeshAnimCreator.h" #include "AL/usdmaya/nodes/ProxyShape.h" -#include "AL/usdmaya/StageData.h" #include "AL/usdmaya/utils/Utils.h" #include "AL/usdmaya/utils/MeshUtils.h" @@ -28,6 +27,8 @@ #include "pxr/usd/usdGeom/mesh.h" +#include + namespace AL { namespace usdmaya { namespace nodes { @@ -52,7 +53,7 @@ MStatus MeshAnimCreator::initialise() // do not write these nodes to the file. They will be created automagically by the proxy shape m_primPath = addStringAttr("primPath", "pp", kReadable | kWritable); m_inTime = addTimeAttr("inTime", "it", MTime(), kReadable | kWritable | kStorable | kConnectable); - m_inStageData = addDataAttr("inStageData", "isd", StageData::kTypeId, kWritable | kStorable | kConnectable); + m_inStageData = addDataAttr("inStageData", "isd", MayaUsdStageData::mayaTypeId, kWritable | kStorable | kConnectable); m_outMesh = addMeshAttr("outMesh", "out", kReadable | kStorable | kConnectable); attributeAffects(m_primPath, m_outMesh); attributeAffects(m_inTime, m_outMesh); diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimDeformer.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimDeformer.cpp index 560167273e..dbab7178ed 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimDeformer.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/MeshAnimDeformer.cpp @@ -19,7 +19,6 @@ #include "AL/usdmaya/DebugCodes.h" #include "AL/usdmaya/nodes/MeshAnimDeformer.h" #include "AL/usdmaya/nodes/ProxyShape.h" -#include "AL/usdmaya/StageData.h" #include "AL/usdmaya/utils/Utils.h" #include "maya/MFnMesh.h" @@ -27,6 +26,8 @@ #include "pxr/usd/usdGeom/mesh.h" +#include + namespace AL { namespace usdmaya { namespace nodes { @@ -52,7 +53,7 @@ MStatus MeshAnimDeformer::initialise() // do not write these nodes to the file. They will be created automagically by the proxy shape m_primPath = addStringAttr("primPath", "pp", kReadable | kWritable); m_inTime = addTimeAttr("inTime", "it", MTime(), kReadable | kWritable | kStorable | kConnectable); - m_inStageData = addDataAttr("inStageData", "isd", StageData::kTypeId, kWritable | kStorable | kConnectable); + m_inStageData = addDataAttr("inStageData", "isd", MayaUsdStageData::mayaTypeId, kWritable | kStorable | kConnectable); m_outMesh = addMeshAttr("outMesh", "out", kReadable | kStorable | kConnectable); m_inMesh = addMeshAttr("inMesh", "in", kWritable | kStorable | kConnectable); attributeAffects(m_primPath, m_outMesh); diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.cpp index 1f85f8bb94..00d10220fd 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.cpp @@ -19,21 +19,7 @@ #include "pxr/usdImaging/usdImagingGL/engine.h" */ -#if (__cplusplus >= 201703L) -# include -#else -# include -#endif -namespace AL { -namespace filesystem { -#if (__cplusplus >= 201703L) -typedef std::filesystem::path path; -#else -typedef boost::filesystem::path path; -#endif -} -} #include "maya/MEvaluationNode.h" #include "maya/MEventMessage.h" #include "maya/MFileIO.h" @@ -61,7 +47,6 @@ typedef boost::filesystem::path path; #include "AL/usdmaya/nodes/Transform.h" #include "AL/usdmaya/nodes/TransformationMatrix.h" #include "AL/usdmaya/StageCache.h" -#include "AL/usdmaya/StageData.h" #include "AL/usdmaya/TypeIDs.h" #include "AL/usdmaya/Version.h" #include "AL/usdmaya/utils/Utils.h" @@ -77,6 +62,10 @@ typedef boost::filesystem::path path; #include "pxr/usd/usdUtils/stageCache.h" #include "pxr/usdImaging/usdImaging/delegate.h" +#include +#include +#include + #if defined(WANT_UFE_BUILD) #include "ufe/path.h" #endif @@ -88,15 +77,6 @@ typedef void (*proxy_function_prototype)(void* userData, AL::usdmaya::nodes::Pro const char* ProxyShape::s_selectionMaskName = "al_ProxyShape"; -MDagPath ProxyShape::parentTransform() -{ - MFnDagNode fn(thisMObject()); - MDagPath proxyTransformPath; - fn.getPath(proxyTransformPath); - proxyTransformPath.pop(); - return proxyTransformPath; -} - //---------------------------------------------------------------------------------------------------------------------- void ProxyShape::serialiseTranslatorContext() { @@ -119,104 +99,14 @@ void ProxyShape::deserialiseTranslatorContext() triggerEvent("PostDeserialiseContext"); } -//---------------------------------------------------------------------------------------------------------------------- -static std::string resolvePath(const std::string& filePath) -{ - ArResolver& resolver = ArGetResolver(); - - return resolver.Resolve(filePath); -} - -static std::string getDir(const std::string &fullFilePath) -{ - return AL::filesystem::path(fullFilePath).parent_path().string(); -} - -static std::string getMayaReferencedFileDir(const MObject &proxyShapeNode) -{ - // Can not use MFnDependencyNode(proxyShapeNode).isFromReferencedFile() to test if it is reference node or not, - // which always return false even the proxyShape node is referenced... - - MStatus stat; - MFnReference refFn; - MItDependencyNodes dgIter(MFn::kReference, &stat); - for (; !dgIter.isDone(); dgIter.next()) - { - MObject cRefNode = dgIter.thisNode(); - refFn.setObject(cRefNode); - if(refFn.containsNodeExactly(proxyShapeNode, &stat)) - { - // According to Maya API document, the second argument is 'includePath' and set it to true to include the file path. - // However, I have to set it to false to return the full file path otherwise I get a file name only... - MString refFilePath = refFn.fileName(true, false, false, &stat); - if(!refFilePath.length()) - return std::string(); - - std::string referencedFilePath = refFilePath.asChar(); - TF_DEBUG(ALUSDMAYA_TRANSLATORS).Msg("getMayaReferencedFileDir: The reference file that contains the proxyShape node is : %s\n", referencedFilePath.c_str()); - - return getDir(referencedFilePath); - } - } - - return std::string(); -} - -static std::string getMayaSceneFileDir() -{ - std::string currentFile = AL::maya::utils::convert(MFileIO::currentFile()); - size_t filePathSize = currentFile.size(); - if(filePathSize < 4) - return std::string(); - - // If scene is untitled, the maya file will be MayaWorkspaceDir/untitled : - constexpr char ma_ext[] = ".ma"; - constexpr char mb_ext[] = ".mb"; - auto ext_start = currentFile.end() - 3; - if(std::equal(ma_ext, ma_ext + 3, ext_start) || - std::equal(mb_ext, mb_ext + 3, ext_start)) - return getDir(currentFile); - - return std::string(); -} - -static std::string resolveRelativePathWithinMayaContext(const MObject &proxyShape, const std::string& relativeFilePath) -{ - if (relativeFilePath.length() < 3) - return relativeFilePath; - - std::string currentFileDir = getMayaReferencedFileDir(proxyShape); - if(currentFileDir.empty()) - currentFileDir = getMayaSceneFileDir(); - - if(currentFileDir.empty()) - return relativeFilePath; - - boost::system::error_code errorCode; - AL::filesystem::path path = boost::filesystem::canonical(relativeFilePath, currentFileDir, errorCode); - if (errorCode){ - // file does not exist - return std::string(); - } - return path.string(); -} - //---------------------------------------------------------------------------------------------------------------------- AL_MAYA_DEFINE_NODE(ProxyShape, AL_USDMAYA_PROXYSHAPE, AL_usdmaya); -MObject ProxyShape::m_filePath = MObject::kNullObj; -MObject ProxyShape::m_primPath = MObject::kNullObj; -MObject ProxyShape::m_excludePrimPaths = MObject::kNullObj; MObject ProxyShape::m_populationMaskIncludePaths = MObject::kNullObj; MObject ProxyShape::m_excludedTranslatedGeometry = MObject::kNullObj; -MObject ProxyShape::m_time = MObject::kNullObj; MObject ProxyShape::m_timeOffset = MObject::kNullObj; MObject ProxyShape::m_timeScalar = MObject::kNullObj; MObject ProxyShape::m_outTime = MObject::kNullObj; -MObject ProxyShape::m_complexity = MObject::kNullObj; -MObject ProxyShape::m_outStageData = MObject::kNullObj; -MObject ProxyShape::m_displayGuides = MObject::kNullObj; -MObject ProxyShape::m_displayRenderGuides = MObject::kNullObj; MObject ProxyShape::m_layers = MObject::kNullObj; MObject ProxyShape::m_serializedSessionLayer = MObject::kNullObj; MObject ProxyShape::m_sessionLayerName = MObject::kNullObj; @@ -245,18 +135,7 @@ int m_stageCacheId; UsdPrim ProxyShape::getUsdPrim(MDataBlock& dataBlock) const { TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape::getUsdPrim\n"); - UsdPrim usdPrim; - StageData* outData = inputDataValue(dataBlock, m_outStageData); - if(outData) - { - if(outData->stage) - { - usdPrim = (outData->primPath.IsEmpty()) ? - outData->stage->GetPseudoRoot() : - outData->stage->GetPrimAtPath(outData->primPath); - } - } - return usdPrim; + return _GetUsdPrim(dataBlock); } //---------------------------------------------------------------------------------------------------------------------- @@ -267,7 +146,20 @@ SdfPathVector ProxyShape::getExcludePrimPaths() const SdfPathVector paths = getPrimPathsFromCommaJoinedString(excludePrimPathsPlug().asString()); SdfPathVector temp = getPrimPathsFromCommaJoinedString(excludedTranslatedGeometryPlug().asString()); paths.insert(paths.end(), temp.begin(), temp.end()); - return paths; + + const auto& translatedGeo = m_context->excludedGeometry(); + + // combine the excluded paths + SdfPathVector excludedGeometryPaths; + excludedGeometryPaths.reserve(m_excludedTaggedGeometry.size() + paths.size() + translatedGeo.size()); + excludedGeometryPaths.assign(m_excludedTaggedGeometry.begin(), m_excludedTaggedGeometry.end()); + excludedGeometryPaths.insert(excludedGeometryPaths.end(), m_excludedGeometry.begin(), m_excludedGeometry.end()); + for (auto& it : translatedGeo) + { + excludedGeometryPaths.push_back(it.second); + } + + return excludedGeometryPaths; } //---------------------------------------------------------------------------------------------------------------------- @@ -399,7 +291,7 @@ void ProxyShape::translatePrimsIntoMaya( if(context()->isExcludedGeometryDirty()) { TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape:translatePrimsIntoMaya excluded geometry has been modified, reconstructing imaging engine \n"); - constructGLImagingEngine(); + constructExcludedPrims(); //if excluded prims changed, this will call constructGLImagingEngine } } //---------------------------------------------------------------------------------------------------------------------- @@ -461,19 +353,7 @@ void ProxyShape::constructGLImagingEngine() // delete previous instance destroyGLImagingEngine(); - const auto& translatedGeo = m_context->excludedGeometry(); - - // combine the excluded paths - SdfPathVector excludedGeometryPaths; - excludedGeometryPaths.reserve(m_excludedTaggedGeometry.size() + m_excludedGeometry.size() + translatedGeo.size()); - excludedGeometryPaths.assign(m_excludedTaggedGeometry.begin(), m_excludedTaggedGeometry.end()); - excludedGeometryPaths.insert(excludedGeometryPaths.end(), m_excludedGeometry.begin(), m_excludedGeometry.end()); - for(auto& it : translatedGeo) - { - excludedGeometryPaths.push_back(it.second); - } - - m_engine = new Engine(m_path, excludedGeometryPaths); + m_engine = new Engine(m_path, m_excludedGeometry); // set renderer plugin based on RendererManager setting RendererManager* manager = RendererManager::findManager(); if(manager && m_engine) @@ -520,12 +400,12 @@ MStatus ProxyShape::setDependentsDirty(const MPlug& plugBeingDirtied, MPlugArray } } - if(plugBeingDirtied == m_time || plugBeingDirtied == m_timeOffset || plugBeingDirtied == m_timeScalar) + if(plugBeingDirtied == time() || plugBeingDirtied == m_timeOffset || plugBeingDirtied == m_timeScalar) { plugs.append(outTimePlug()); return MS::kSuccess; } - if(plugBeingDirtied == m_filePath) + if(plugBeingDirtied == filePath()) { MHWRender::MRenderer::setGeometryDrawDirty(thisMObject(), true); } @@ -605,14 +485,14 @@ bool ProxyShape::getRenderAttris(UsdImagingGLRenderParams& attribs, const MHWRen const float complexities[] = {1.05f, 1.15f, 1.25f, 1.35f, 1.45f, 1.55f, 1.65f, 1.75f, 1.9f}; attribs.complexity = complexities[complexityPlug().asInt()]; - attribs.showGuides = displayGuidesPlug().asBool(); - attribs.showRender = displayRenderGuidesPlug().asBool(); + attribs.showGuides = drawGuidePurposePlug().asBool(); + attribs.showRender = drawRenderPurposePlug().asBool(); return true; } //---------------------------------------------------------------------------------------------------------------------- ProxyShape::ProxyShape() - : MPxSurfaceShape(), AL::maya::utils::NodeHelper(), AL::event::NodeEvents(&AL::event::EventScheduler::getScheduler()), + : MayaUsdProxyShapeBase(), AL::maya::utils::NodeHelper(), AL::event::NodeEvents(&AL::event::EventScheduler::getScheduler()), m_context(fileio::translators::TranslatorContext::create(this)), m_translatorManufacture(context()) { @@ -769,6 +649,9 @@ MStatus ProxyShape::initialise() { TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape::initialise\n"); + MStatus retValue = inheritAttributesFrom(MayaUsdProxyShapeBase::typeName); + CHECK_MSTATUS_AND_RETURN_IT(retValue); + const char* errorString = "ProxyShape::initialize"; try { @@ -780,23 +663,22 @@ MStatus ProxyShape::initialise() //for backward compatibility (or at least to stop maya spewing out errors on scene open). This attribute was removed in 0.32.17 addStringAttr("serializedArCtx", "arcd", kReadable|kWritable|kHidden); // m_filePath / m_primPath / m_excludePrimPaths are internal just so we get notification on change - m_filePath = addFilePathAttr("filePath", "fp", kCached | kReadable | kWritable | kStorable | kAffectsAppearance | kInternal, kLoad, "USD Files (*.usd*) (*.usd*);;Alembic Files (*.abc)"); + inheritFilePathAttr("filePath", kCached | kReadable | kWritable | kStorable | kAffectsAppearance | kInternal, kLoad, "USD Files (*.usd*) (*.usd*);;Alembic Files (*.abc)"); - m_primPath = addStringAttr("primPath", "pp", kCached | kReadable | kWritable | kStorable | kAffectsAppearance | kInternal); - m_excludePrimPaths = addStringAttr("excludePrimPaths", "epp", kCached | kReadable | kWritable | kStorable | kAffectsAppearance | kInternal); + inheritStringAttr("primPath", kCached | kReadable | kWritable | kStorable | kAffectsAppearance | kInternal); + inheritStringAttr("excludePrimPaths", kCached | kReadable | kWritable | kStorable | kAffectsAppearance | kInternal); m_populationMaskIncludePaths = addStringAttr("populationMaskIncludePaths", "pmi", kCached | kReadable | kWritable | kStorable | kAffectsAppearance); m_excludedTranslatedGeometry = addStringAttr("excludedTranslatedGeometry", "etg", kCached | kReadable | kWritable | kStorable | kAffectsAppearance); - m_complexity = addInt32Attr("complexity", "cplx", 0, kCached | kConnectable | kReadable | kWritable | kAffectsAppearance | kKeyable | kStorable); - setMinMax(m_complexity, 0, 8, 0, 4); - m_outStageData = addDataAttr("outStageData", "od", StageData::kTypeId, kConnectable | kReadable | kWritable | kAffectsAppearance); - m_displayGuides = addBoolAttr("displayGuides", "dg", false, kCached | kKeyable | kWritable | kAffectsAppearance | kStorable); - m_displayRenderGuides = addBoolAttr("displayRenderGuides", "drg", false, kCached | kKeyable | kWritable | kAffectsAppearance | kStorable); + inheritInt32Attr("complexity", kCached | kConnectable | kReadable | kWritable | kAffectsAppearance | kKeyable | kStorable); + // outStageData attribute already added in base class. + inheritBoolAttr("displayGuides", kCached | kKeyable | kWritable | kAffectsAppearance | kStorable); + inheritBoolAttr("displayRenderGuides", kCached | kKeyable | kWritable | kAffectsAppearance | kStorable); m_unloaded = addBoolAttr("unloaded", "ul", false, kCached | kKeyable | kWritable | kAffectsAppearance | kStorable); m_serializedTrCtx = addStringAttr("serializedTrCtx", "srtc", kReadable|kWritable|kStorable|kHidden); addFrame("USD Timing Information"); - m_time = addTimeAttr("time", "tm", MTime(0.0), kCached | kConnectable | kReadable | kWritable | kStorable | kAffectsAppearance); + inheritTimeAttr("time", kCached | kConnectable | kReadable | kWritable | kStorable | kAffectsAppearance); m_timeOffset = addTimeAttr("timeOffset", "tmo", MTime(0.0), kCached | kConnectable | kReadable | kWritable | kStorable | kAffectsAppearance); m_timeScalar = addDoubleAttr("timeScalar", "tms", 1.0, kCached | kConnectable | kReadable | kWritable | kStorable | kAffectsAppearance); m_outTime = addTimeAttr("outTime", "otm", MTime(0.0), kCached | kConnectable | kReadable | kAffectsAppearance); @@ -830,14 +712,14 @@ MStatus ProxyShape::initialise() m_assetResolverConfig = addStringAttr("assetResolverConfig", "arc", kReadable | kWritable | kConnectable | kStorable | kAffectsAppearance | kInternal); - AL_MAYA_CHECK_ERROR(attributeAffects(m_time, m_outTime), errorString); + AL_MAYA_CHECK_ERROR(attributeAffects(time(), m_outTime), errorString); AL_MAYA_CHECK_ERROR(attributeAffects(m_timeOffset, m_outTime), errorString); AL_MAYA_CHECK_ERROR(attributeAffects(m_timeScalar, m_outTime), errorString); - AL_MAYA_CHECK_ERROR(attributeAffects(m_filePath, m_outStageData), errorString); - AL_MAYA_CHECK_ERROR(attributeAffects(m_primPath, m_outStageData), errorString); - AL_MAYA_CHECK_ERROR(attributeAffects(m_populationMaskIncludePaths, m_outStageData), errorString); - AL_MAYA_CHECK_ERROR(attributeAffects(m_stageDataDirty, m_outStageData), errorString); - AL_MAYA_CHECK_ERROR(attributeAffects(m_assetResolverConfig, m_outStageData), errorString); + // file path and prim path affects on out stage data already done in base + // class. + AL_MAYA_CHECK_ERROR(attributeAffects(m_populationMaskIncludePaths, outStageData()), errorString); + AL_MAYA_CHECK_ERROR(attributeAffects(m_stageDataDirty, outStageData()), errorString); + AL_MAYA_CHECK_ERROR(attributeAffects(m_assetResolverConfig, outStageData()), errorString); } catch (const MStatus& status) { @@ -1063,7 +945,7 @@ void ProxyShape::serializeAll() //---------------------------------------------------------------------------------------------------------------------- void ProxyShape::onObjectsChanged(UsdNotice::ObjectsChanged const& notice, UsdStageWeakPtr const& sender) { - if(MFileIO::isReadingFile()) + if(MFileIO::isReadingFile() || AL::usdmaya::utils::BlockNotifications::isBlockingNotifications()) return; if (!sender || sender != m_stage) @@ -1120,7 +1002,7 @@ void ProxyShape::onObjectsChanged(UsdNotice::ObjectsChanged const& notice, UsdSt // do we need to clear the bounding box cache? if(shouldCleanBBoxCache) { - m_boundingBoxCache.clear(); + clearBoundingBoxCache(); // Ideally we want to have a way to force maya to call ProxyShape::boundingBox() again to update the bbox attributes. // This may lead to a delay in the bbox updates (e.g. usually you need to reselect the proxy before the bounds will @@ -1426,7 +1308,7 @@ void ProxyShape::loadStage() const int stageIdVal = inputInt32Value(dataBlock, m_stageCacheId); UsdStageCache::Id stageId = UsdStageCache::Id().FromLongInt(stageIdVal); - MString file = inputStringValue(dataBlock, m_filePath); + MString file = inputStringValue(dataBlock, filePath()); if (m_stage) { @@ -1456,7 +1338,7 @@ void ProxyShape::loadStage() // Save the initial edit target and all dirty layers. trackAllDirtyLayers(); file.set(m_stage->GetRootLayer()->GetIdentifier().c_str()); - outputStringValue(dataBlock, m_filePath, file); + outputStringValue(dataBlock, filePath(), file); } else { @@ -1481,16 +1363,16 @@ void ProxyShape::loadStage() TF_DEBUG(ALUSDMAYA_TRANSLATORS).Msg("ProxyShape::reloadStage original USD file path is %s\n", fileString.c_str()); - AL::filesystem::path filestringPath(fileString); + boost::filesystem::path filestringPath(fileString); if (filestringPath.is_absolute()) { - fileString = resolvePath(fileString); + fileString = UsdMayaUtilFileSystem::resolvePath(fileString); TF_DEBUG(ALUSDMAYA_TRANSLATORS).Msg("ProxyShape::reloadStage resolved the USD file path to %s\n", fileString.c_str()); } else { - fileString = resolveRelativePathWithinMayaContext(thisMObject(), fileString); + fileString = UsdMayaUtilFileSystem::resolveRelativePathWithinMayaContext(thisMObject(), fileString); TF_DEBUG(ALUSDMAYA_TRANSLATORS).Msg("ProxyShape::reloadStage resolved the relative USD file path to %s\n", fileString.c_str()); } @@ -1605,7 +1487,7 @@ void ProxyShape::loadStage() // Get the prim // If no primPath string specified, then use the pseudo-root. const SdfPath rootPath(std::string("/")); - MString primPathStr = inputStringValue(dataBlock, m_primPath); + MString primPathStr = inputStringValue(dataBlock, primPath()); if (primPathStr.length()) { m_path = SdfPath(AL::maya::utils::convert(primPathStr)); @@ -1680,6 +1562,8 @@ void ProxyShape::constructExcludedPrims() auto excludedPaths = getExcludePrimPaths(); if (m_excludedGeometry != excludedPaths) { + _IncreaseExcludePrimPathsVersion(); + std::swap(m_excludedGeometry, excludedPaths); constructGLImagingEngine(); } @@ -1801,8 +1685,9 @@ void ProxyShape::postConstructor() { TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape::postConstructor\n"); + ParentClass::postConstructor(); + // Apply render defaults - setRenderable(true); MPlug(thisMObject(), m_visibleInReflections).setValue(true); MPlug(thisMObject(), m_visibleInRefractions).setValue(true); } @@ -1941,7 +1826,7 @@ MStatus ProxyShape::computeOutStageData(const MPlug& plug, MDataBlock& dataBlock { // create new stage data MObject data; - StageData* usdStageData = createData(StageData::kTypeId, data); + MayaUsdStageData* usdStageData = createData(MayaUsdStageData::mayaTypeId, data); if(!usdStageData) { return MS::kFailure; @@ -1958,11 +1843,14 @@ MStatus ProxyShape::computeOutStageData(const MPlug& plug, MDataBlock& dataBlock usdStageData->primPath = m_path; // set the cached output value, and flush - MStatus status = outputDataValue(dataBlock, m_outStageData, usdStageData); + MStatus status = outputDataValue(dataBlock, outStageData(), usdStageData); if(!status) { return MS::kFailure; } + + UsdMayaProxyStageSetNotice(*this).Send(); + return status; } @@ -1972,7 +1860,7 @@ bool ProxyShape::isStageValid() const TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape::isStageValid\n"); MDataBlock dataBlock = const_cast(this)->forceCache(); - StageData* outData = inputDataValue(dataBlock, m_outStageData); + MayaUsdStageData* outData = inputDataValue(dataBlock, outStageData()); if(outData && outData->stage) return true; @@ -1984,11 +1872,11 @@ UsdStageRefPtr ProxyShape::getUsdStage() const { TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape::getUsdStage\n"); - MPlug plug(thisMObject(), m_outStageData); + MPlug plug(thisMObject(), outStageData()); MObject data; plug.getValue(data); MFnPluginData fnData(data); - StageData* outData = static_cast(fnData.data()); + MayaUsdStageData* outData = static_cast(fnData.data()); if(outData) { return outData->stage; @@ -1996,10 +1884,15 @@ UsdStageRefPtr ProxyShape::getUsdStage() const return UsdStageRefPtr(); } +UsdTimeCode ProxyShape::getTime() const +{ + return UsdTimeCode(outTimePlug().asMTime().as(MTime::uiUnit())); +} + //---------------------------------------------------------------------------------------------------------------------- MStatus ProxyShape::computeOutputTime(const MPlug& plug, MDataBlock& dataBlock, MTime& currentTime) { - MTime inTime = inputTimeValue(dataBlock, m_time); + MTime inTime = inputTimeValue(dataBlock, time()); MTime inTimeOffset = inputTimeValue(dataBlock, m_timeOffset); double inTimeScalar = inputDoubleValue(dataBlock, m_timeScalar); currentTime.setValue((inTime.as(MTime::uiUnit()) - inTimeOffset.as(MTime::uiUnit())) * inTimeScalar); @@ -2018,11 +1911,13 @@ MStatus ProxyShape::compute(const MPlug& plug, MDataBlock& dataBlock) return computeOutputTime(plug, dataBlock, currentTime); } else - if(plug == m_outStageData) + if(plug == outStageData()) { MStatus status = computeOutputTime(MPlug(plug.node(), m_outTime), dataBlock, currentTime); return status == MS::kSuccess ? computeOutStageData(plug, dataBlock) : status; } + // Completely skip over parent class compute(), because it has inStageData + // and inStageDataCached attributes we don't use. return MPxSurfaceShape::compute(plug, dataBlock); } @@ -2036,13 +1931,14 @@ bool ProxyShape::setInternalValue(const MPlug& plug, const MDataHandle& dataHand // the datablock for us, but this would be too late for these subfunctions TF_DEBUG(ALUSDMAYA_EVALUATION).Msg("ProxyShape::setInternalValue %s\n", plug.name().asChar()); - if(plug == m_filePath || plug == m_assetResolverConfig || plug == m_stageCacheId) + if(plug == filePath() || plug == m_assetResolverConfig || plug == m_stageCacheId) { m_filePathDirty = true; // can't use dataHandle.datablock(), as this is a temporary datahandle MDataBlock datablock = forceCache(); - if (plug == m_filePath || plug == m_assetResolverConfig) + + if (plug == filePath() || plug == m_assetResolverConfig) { AL_MAYA_CHECK_ERROR_RETURN_VAL(outputStringValue(datablock, plug, dataHandle.asString()), false, @@ -2066,11 +1962,11 @@ bool ProxyShape::setInternalValue(const MPlug& plug, const MDataHandle& dataHand return true; } else - if(plug == m_primPath) + if(plug == primPath()) { // can't use dataHandle.datablock(), as this is a temporary datahandle MDataBlock datablock = forceCache(); - AL_MAYA_CHECK_ERROR_RETURN_VAL(outputStringValue(datablock, m_primPath, dataHandle.asString()), + AL_MAYA_CHECK_ERROR_RETURN_VAL(outputStringValue(datablock, primPath(), dataHandle.asString()), false, "ProxyShape::setInternalValue - error setting primPath"); if(m_stage) @@ -2096,7 +1992,7 @@ bool ProxyShape::setInternalValue(const MPlug& plug, const MDataHandle& dataHand return true; } else - if(plug == m_excludePrimPaths || plug == m_excludedTranslatedGeometry) + if(plug == excludePrimPaths() || plug == m_excludedTranslatedGeometry) { // can't use dataHandle.datablock(), as this is a temporary datahandle MDataBlock datablock = forceCache(); @@ -2126,98 +2022,17 @@ bool ProxyShape::isBounded() const } //---------------------------------------------------------------------------------------------------------------------- -MBoundingBox ProxyShape::boundingBox() const +void ProxyShape::CacheEmptyBoundingBox(MBoundingBox& cachedBBox) { - MStatus status; - - // Make sure outStage is up to date - MDataBlock dataBlock = const_cast(this)->forceCache(); - - // This would seem to be superfluous? unless it is actually forcing a DG pull? - MDataHandle outDataHandle = dataBlock.inputValue(m_outStageData, &status); - (void)outDataHandle; - CHECK_MSTATUS_AND_RETURN(status, MBoundingBox() ); - - // XXX:aluk - // If we could cheaply determine whether a stage only has static geometry, - // we could make this value a constant one for that case, avoiding the - // memory overhead of a cache entry per frame - UsdTimeCode currTime = UsdTimeCode(inputTimeValue(dataBlock, m_outTime).as(MTime::uiUnit())); - - // RB: There must be a nicer way of doing this that avoids the map? - // The time codes are likely to be ranged, so an ordered array + binary search would surely work? - std::map::const_iterator cacheLookup = m_boundingBoxCache.find(currTime); - if (cacheLookup != m_boundingBoxCache.end()) - { - return cacheLookup->second; - } - - GfBBox3d allBox; - UsdPrim prim = getUsdPrim(dataBlock); - if (prim) - { - UsdGeomImageable imageablePrim(prim); - bool showGuides = inputBoolValue(dataBlock, m_displayGuides); - bool showRenderGuides = inputBoolValue(dataBlock, m_displayRenderGuides); - if (showGuides && showRenderGuides) - { - allBox = imageablePrim.ComputeUntransformedBound( - currTime, - UsdGeomTokens->default_, - UsdGeomTokens->proxy, - UsdGeomTokens->guide, - UsdGeomTokens->render); - } - else - if (showGuides && !showRenderGuides) - { - allBox = imageablePrim.ComputeUntransformedBound( - currTime, - UsdGeomTokens->default_, - UsdGeomTokens->proxy, - UsdGeomTokens->guide); - } - else if (!showGuides && showRenderGuides) - { - allBox = imageablePrim.ComputeUntransformedBound( - currTime, - UsdGeomTokens->default_, - UsdGeomTokens->proxy, - UsdGeomTokens->render); - } - else - { - allBox = imageablePrim.ComputeUntransformedBound( - currTime, - UsdGeomTokens->default_, - UsdGeomTokens->proxy); - } - } - else - { - return MBoundingBox(); - } - - // insert new cache entry - MBoundingBox& retval = m_boundingBoxCache[currTime]; - - // Convert to GfRange3d to MBoundingBox - GfRange3d boxRange = allBox.ComputeAlignedBox(); - if (!boxRange.IsEmpty()) - { - retval = MBoundingBox(MPoint(boxRange.GetMin()[0], - boxRange.GetMin()[1], - boxRange.GetMin()[2]), - MPoint(boxRange.GetMax()[0], - boxRange.GetMax()[1], - boxRange.GetMax()[2])); - } - else - { - retval = MBoundingBox(MPoint(-100000.0f, -100000.0f, -100000.0f), MPoint(100000.0f, 100000.0f, 100000.0f)); - } + cachedBBox = MBoundingBox( + MPoint(-100000.0f, -100000.0f, -100000.0f), + MPoint( 100000.0f, 100000.0f, 100000.0f)); +} - return retval; +//---------------------------------------------------------------------------------------------------------------------- +UsdTimeCode ProxyShape::GetOutputTime(MDataBlock dataBlock) const +{ + return UsdTimeCode(inputDoubleValue(dataBlock, m_outTime)); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h index 105acc2ef8..a322d37405 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShape.h @@ -47,6 +47,8 @@ #include "pxr/usd/usd/stage.h" #include "pxr/usdImaging/usdImagingGL/renderParams.h" +#include + #if defined(WANT_UFE_BUILD) #include "ufe/ufe.h" @@ -250,7 +252,7 @@ extern AL::event::EventId kPostClearStageCache; /// \ingroup nodes //---------------------------------------------------------------------------------------------------------------------- class ProxyShape - : public MPxSurfaceShape, + : public MayaUsdProxyShapeBase, public AL::maya::utils::NodeHelper, public proxy::PrimFilterInterface, public AL::event::NodeEvents, @@ -260,10 +262,9 @@ class ProxyShape friend class ProxyShapeUI; friend class StageReloadGuard; friend class ProxyDrawOverride; -public: - // returns the shape's parent transform - MDagPath parentTransform(); + typedef MayaUsdProxyShapeBase ParentClass; +public: /// a method that registers all of the events in the ProxyShape AL_USDMAYA_PUBLIC @@ -295,17 +296,25 @@ class ProxyShape /// \name Input Attributes //-------------------------------------------------------------------------------------------------------------------- + // Convenience declarations for attributes inherited from proxy shape + // base class. +#define AL_INHERIT_ATTRIBUTE(XX) \ + AL_USDMAYA_PUBLIC \ + static const MObject& XX() { return XX##Attr; } \ + AL_USDMAYA_PUBLIC \ + MPlug XX##Plug() const { return MPlug( thisMObject(), XX##Attr ); } + /// the input USD file path for this proxy - AL_DECL_ATTRIBUTE(filePath); + AL_INHERIT_ATTRIBUTE(filePath); /// a path to a prim you want to view with this shape - AL_DECL_ATTRIBUTE(primPath); + AL_INHERIT_ATTRIBUTE(primPath); /// a comma seperated list of prims you *don't* want to see. - AL_DECL_ATTRIBUTE(excludePrimPaths); + AL_INHERIT_ATTRIBUTE(excludePrimPaths); /// the input time value (probably connected to time1.outTime) - AL_DECL_ATTRIBUTE(time); + AL_INHERIT_ATTRIBUTE(time); /// an offset, in GUI time units, where the animation should start playback AL_DECL_ATTRIBUTE(timeOffset); @@ -315,13 +324,13 @@ class ProxyShape AL_DECL_ATTRIBUTE(timeScalar); /// the subdiv complexity used - AL_DECL_ATTRIBUTE(complexity); + AL_INHERIT_ATTRIBUTE(complexity); /// display guide - sets shape to display geometry of purpose "guide". See imageable.h - AL_DECL_ATTRIBUTE(displayGuides); + AL_INHERIT_ATTRIBUTE(drawGuidePurpose); - /// display render guide - sets hape to display geometry of purpose "render". See imageable.h - AL_DECL_ATTRIBUTE(displayRenderGuides); + /// display render guide - sets shape to display geometry of purpose "render". See imageable.h + AL_INHERIT_ATTRIBUTE(drawRenderPurpose); /// Connection to any layer DG nodes AL_DECL_ATTRIBUTE(layers); @@ -381,8 +390,8 @@ class ProxyShape /// outTime = (time - timeOffset) * timeScalar AL_DECL_ATTRIBUTE(outTime); - /// inStageData ---> inStageDataCached ---> outStageData - AL_DECL_ATTRIBUTE(outStageData); + /// Inject m_stage and m_path members into DG as a data attribute. + AL_INHERIT_ATTRIBUTE(outStageData); //-------------------------------------------------------------------------------------------------------------------- @@ -393,8 +402,11 @@ class ProxyShape /// on the output stage. /// \return the proxy shape AL_USDMAYA_PUBLIC - UsdStageRefPtr getUsdStage() const; + UsdStageRefPtr getUsdStage() const override; + AL_USDMAYA_PUBLIC + UsdTimeCode getTime() const override; + /// \brief provides access to the UsdStage that this proxy shape is currently representing /// \return the proxy shape UsdStageRefPtr usdStage() const @@ -407,10 +419,6 @@ class ProxyShape /// \return true if the attribs could be retrieved (i.e. is the stage is valid) bool getRenderAttris(UsdImagingGLRenderParams& attribs, const MHWRender::MFrameContext& frameContext, const MDagPath& dagPath); - /// \brief compute bounds - AL_USDMAYA_PUBLIC - MBoundingBox boundingBox() const override; - //-------------------------------------------------------------------------------------------------------------------- /// \name AL_usdmaya_Transform utils /// \brief A set of commands to manipulate the chains of transforms that map to the usd prims found in a stage. @@ -860,10 +868,6 @@ class ProxyShape AL_USDMAYA_PUBLIC MSelectionMask getShapeSelectionMask() const override; - /// \brief Clears the bounding box cache of the shape - inline void clearBoundingBoxCache() - { m_boundingBoxCache.clear(); } - private: /// \brief constructs the USD imaging engine for this shape void constructGLImagingEngine(); @@ -999,6 +1003,8 @@ class ProxyShape MPxNode::SchedulingType schedulingType() const override { return kSerial; } #endif MStatus preEvaluation(const MDGContext & context, const MEvaluationNode& evaluationNode) override; + void CacheEmptyBoundingBox(MBoundingBox&) override; + UsdTimeCode GetOutputTime(MDataBlock) const override; //-------------------------------------------------------------------------------------------------------------------- /// \name Compute methods @@ -1014,7 +1020,7 @@ class ProxyShape //-------------------------------------------------------------------------------------------------------------------- UsdPrim getUsdPrim(MDataBlock& dataBlock) const; - SdfPathVector getExcludePrimPaths() const; + SdfPathVector getExcludePrimPaths() const override; UsdStagePopulationMask constructStagePopulationMask(const MString &paths) const; bool isStageValid() const; @@ -1072,7 +1078,6 @@ class ProxyShape TfNotice::Key m_editTargetChanged; TfNotice::Key m_transactionNoticeKey; - mutable std::map m_boundingBoxCache; MCallbackId m_onSelectionChanged = 0; SdfPathVector m_excludedGeometry; SdfPathVector m_excludedTaggedGeometry; diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShapeUI.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShapeUI.cpp index b2f05488be..c31ffa87ed 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShapeUI.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyShapeUI.cpp @@ -20,6 +20,9 @@ #include "AL/usdmaya/nodes/ProxyShape.h" #include "AL/usdmaya/nodes/ProxyShapeUI.h" +#include "maya/MFnDagNode.h" +#include "maya/MMatrix.h" +#include "maya/MTime.h" #include "maya/MDrawInfo.h" #include "maya/MDrawRequest.h" #include "maya/MDrawRequestQueue.h" @@ -138,8 +141,8 @@ void ProxyShapeUI::draw(const MDrawRequest& request, M3dView& view) const auto stage = shape->getUsdStage(); UsdImagingGLRenderParams params; - params.showGuides = shape->displayGuidesPlug().asBool(); - params.showRender = shape->displayRenderGuidesPlug().asBool(); + params.showGuides = shape->drawGuidePurposePlug().asBool(); + params.showRender = shape->drawRenderPurposePlug().asBool(); params.frame = UsdTimeCode(shape->outTimePlug().asMTime().as(MTime::uiUnit())); params.complexity = 1.0f; @@ -345,8 +348,8 @@ bool ProxyShapeUI::select(MSelectInfo& selectInfo, MSelectionList& selectionList proxyShape->m_pleaseIgnoreSelection = true; UsdImagingGLRenderParams params; - params.showGuides = proxyShape->displayGuidesPlug().asBool(); - params.showRender = proxyShape->displayRenderGuidesPlug().asBool(); + params.showGuides = proxyShape->drawGuidePurposePlug().asBool(); + params.showRender = proxyShape->drawRenderPurposePlug().asBool(); UsdPrim root = proxyShape->getUsdStage()->GetPseudoRoot(); diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyUsdGeomCamera.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyUsdGeomCamera.cpp index 52b700a4e2..18afad6e0d 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyUsdGeomCamera.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/ProxyUsdGeomCamera.cpp @@ -31,9 +31,10 @@ #include #include "AL/usdmaya/TypeIDs.h" -#include #include +#include + namespace AL { namespace usdmaya { namespace nodes { @@ -81,8 +82,8 @@ UsdGeomCamera ProxyUsdGeomCamera::getCamera() const { // Pull in stage data MFnPluginData fnData(stageObject); - AL::usdmaya::StageData* stageData = static_cast(fnData.data()); + auto* stageData = static_cast(fnData.data()); if (stageData != nullptr) { // Get prim path @@ -514,7 +515,7 @@ MStatus ProxyUsdGeomCamera::initialise() m_path = addStringAttr("path", "p", "", kStorable | kWritable); - m_stage = addDataAttr("stage", "s", AL::usdmaya::StageData::kTypeId, kWritable | kHidden | kConnectable, MFnNumericAttribute::kReset); + m_stage = addDataAttr("stage", "s", MayaUsdStageData::mayaTypeId, kWritable | kHidden | kConnectable, MFnNumericAttribute::kReset); m_time = addTimeAttr("time", "tm", MTime(0.0), kCached | kConnectable | kReadable | kWritable | kHidden | kStorable | kAffectsAppearance); diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/Transform.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/Transform.cpp index 0a3d6c1c14..4b260f817e 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/Transform.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/Transform.cpp @@ -15,11 +15,12 @@ // #include "AL/usdmaya/TypeIDs.h" #include "AL/usdmaya/DebugCodes.h" -#include "AL/usdmaya/StageData.h" #include "AL/usdmaya/nodes/ProxyShape.h" #include "AL/usdmaya/nodes/Transform.h" #include "AL/usdmaya/nodes/TransformationMatrix.h" +#include + #include "maya/MBoundingBox.h" #include "maya/MGlobal.h" #include "maya/MTime.h" @@ -107,7 +108,7 @@ MStatus Transform::initialise() addFrame("USD Prim Information"); m_primPath = addStringAttr("primPath", "pp", kReadable | kWritable | kStorable | kConnectable | kAffectsWorldSpace, true); - m_inStageData = addDataAttr("inStageData", "isd", StageData::kTypeId, kWritable | kStorable | kConnectable | kHidden | kAffectsWorldSpace); + m_inStageData = addDataAttr("inStageData", "isd", MayaUsdStageData::mayaTypeId, kWritable | kStorable | kConnectable | kHidden | kAffectsWorldSpace); addFrame("USD Timing Information"); m_time = addTimeAttr("time", "tm", MTime(0.0), kKeyable | kConnectable | kReadable | kWritable | kStorable | kAffectsWorldSpace); @@ -187,7 +188,7 @@ MStatus Transform::compute(const MPlug& plug, MDataBlock& dataBlock) // This should only be computed if there's no connection, so set it to an empty stage // create new stage data MObject data; - StageData* usdStageData = createData(StageData::kTypeId, data); + auto* usdStageData = createData(MayaUsdStageData::mayaTypeId, data); if(!usdStageData) { return MS::kFailure; @@ -446,7 +447,7 @@ MStatus Transform::validateAndSetValue(const MPlug& plug, const MDataHandle& han if(plug == m_inStageData) { MDataBlock dataBlock = forceCache(*(MDGContext *)&context); - StageData* data = inputDataValue(dataBlock, m_inStageData); + auto* data = inputDataValue(dataBlock, m_inStageData); if (data && data->stage) { MString path = inputStringValue(dataBlock, m_primPath); @@ -472,7 +473,7 @@ MStatus Transform::validateAndSetValue(const MPlug& plug, const MDataHandle& han MString path = handle.asString(); outputStringValue(dataBlock, m_primPath, path); - StageData* data = inputDataValue(dataBlock, m_inStageData); + auto* data = inputDataValue(dataBlock, m_inStageData); if (data && data->stage) { SdfPath primPath; diff --git a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/wrapProxyShape.cpp b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/wrapProxyShape.cpp index ebaca9ac5b..4ff4f0d0af 100644 --- a/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/wrapProxyShape.cpp +++ b/plugin/al/lib/AL_USDMaya/AL/usdmaya/nodes/wrapProxyShape.cpp @@ -16,9 +16,10 @@ #include "AL/usdmaya/nodes/ProxyShape.h" #include "AL/usdmaya/nodes/Transform.h" #include "AL/maya/utils/MayaHelperMacros.h" -#include "AL/usdmaya/StageData.h" #include "AL/maya/utils/Utils.h" +#include + #include #include #include @@ -140,7 +141,7 @@ namespace { MObject stageObject; status = stageDataPlug.getValue(stageObject); MFnPluginData fnData(stageObject); - auto stageData = static_cast(fnData.data()); + auto* stageData = static_cast(fnData.data()); // Validate stage if (stageData && stageData->stage) diff --git a/plugin/al/lib/AL_USDMaya/CMakeLists.txt b/plugin/al/lib/AL_USDMaya/CMakeLists.txt index 4b3d7e7810..3f98bdf2f8 100644 --- a/plugin/al/lib/AL_USDMaya/CMakeLists.txt +++ b/plugin/al/lib/AL_USDMaya/CMakeLists.txt @@ -1,7 +1,5 @@ set(arDirPath AL/usdmaya) -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set(LIBRARY_NAME AL_USDMaya) list(APPEND AL_usdmaya_headers @@ -11,7 +9,6 @@ list(APPEND AL_usdmaya_headers AL/usdmaya/PluginRegister.h AL/usdmaya/SelectabilityDB.h AL/usdmaya/StageCache.h - AL/usdmaya/StageData.h AL/usdmaya/TransformOperation.h AL/usdmaya/TypeIDs.h AL/usdmaya/ForwardDeclares.h @@ -25,7 +22,6 @@ list(APPEND AL_usdmaya_source AL/usdmaya/Metadata.cpp AL/usdmaya/SelectabilityDB.cpp AL/usdmaya/StageCache.cpp - AL/usdmaya/StageData.cpp AL/usdmaya/TransformOperation.cpp AL/usdmaya/CodeTimings.cpp AL/usdmaya/moduleDeps.cpp @@ -157,13 +153,15 @@ add_library(${LIBRARY_NAME} ${AL_usdmaya_nodes_source} ) +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + target_compile_definitions(${LIBRARY_NAME} PRIVATE + ${_macDef} AL_MAYA_MACROS_EXPORT AL_USDMAYA_EXPORT - MFB_PACKAGE_NAME="${LIBRARY_NAME}" - MFB_ALT_PACKAGE_NAME="${LIBRARY_NAME}" - MFB_PACKAGE_MODULE=usdmaya AL_USDMAYA_LOCATION_NAME="${AL_USDMAYA_LOCATION_NAME}" ) @@ -212,9 +210,13 @@ target_link_libraries(${LIBRARY_NAME} ${MAYA_OpenMayaUI_LIBRARY} ${MAYA_OpenMaya_LIBRARY} ${MAYA_OpenMayaRender_LIBRARY} - ${UFE_LIBRARY} + mayaUsd ) +if(UFE_FOUND) + target_link_libraries(${LIBRARY_NAME} ${UFE_LIBRARY}) +endif() + if(NEED_BOOST_FILESYSTEM) target_link_libraries(${LIBRARY_NAME} ${Boost_FILESYSTEM_LIBRARY} @@ -227,7 +229,7 @@ install(TARGETS ${LIBRARY_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) endif() @@ -246,8 +248,13 @@ add_library(${PYTHON_LIBRARY_NAME} AL/usdmaya/fileio/translators/wrapTranslatorContext.cpp ) +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + target_compile_definitions(${PYTHON_LIBRARY_NAME} PRIVATE + ${_macDef} MFB_PACKAGE_NAME=${LIBRARY_NAME} MFB_ALT_PACKAGE_NAME=${LIBRARY_NAME} MFB_PACKAGE_MODULE=usdmaya @@ -256,7 +263,7 @@ set_target_properties(${PYTHON_LIBRARY_NAME} PROPERTIES PREFIX "" ) -if(MSVC) +if(IS_WINDOWS) set_target_properties(${PYTHON_LIBRARY_NAME} PROPERTIES SUFFIX ".pyd" diff --git a/plugin/al/mayatest/AL/maya/test/CMakeLists.txt b/plugin/al/mayatest/AL/maya/test/CMakeLists.txt index 6f3378252c..9e7a4bfc21 100755 --- a/plugin/al/mayatest/AL/maya/test/CMakeLists.txt +++ b/plugin/al/mayatest/AL/maya/test/CMakeLists.txt @@ -4,8 +4,6 @@ #################################################################################################### find_package(GTest REQUIRED) -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set(MAYA_TEST_LIBRARY_NAME "AL_MayaTest") set(MAYA_TEST_LIBRARY_LOCATION ${CMAKE_INSTALL_PREFIX}/lib) @@ -29,8 +27,13 @@ add_library(${MAYA_TEST_LIBRARY_NAME} ${maya_test_source} ) +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + target_compile_definitions(${MAYA_TEST_LIBRARY_NAME} PRIVATE + ${_macDef} AL_MAYA_TEST_EXPORT ) @@ -44,8 +47,8 @@ target_link_libraries(${MAYA_TEST_LIBRARY_NAME} target_include_directories(${MAYA_TEST_LIBRARY_NAME} PRIVATE ${MAYATEST_INCLUDE_LOCATION} - ${MAYA_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} + ${MAYA_INCLUDE_DIRS} ${USD_INCLUDE_DIR} ) diff --git a/plugin/al/mayautils/AL/maya/CMakeLists.txt b/plugin/al/mayautils/AL/maya/CMakeLists.txt index 804ab77cba..ddb3326018 100755 --- a/plugin/al/mayautils/AL/maya/CMakeLists.txt +++ b/plugin/al/mayautils/AL/maya/CMakeLists.txt @@ -3,8 +3,6 @@ # Setup #################################################################################################### -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set(MAYAUTILS_LIBRARY_NAME "AL_MayaUtils") set(MAYAUTILS_LIBRARY_LOCATION ${CMAKE_INSTALL_PREFIX}/lib) @@ -47,8 +45,13 @@ add_library(${MAYAUTILS_LIBRARY_NAME} ${maya_source} ) +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + target_compile_definitions(${MAYAUTILS_LIBRARY_NAME} PRIVATE + ${_macDef} AL_MAYA_EVENTS_EXPORT AL_MAYA_UTILS_EXPORT AL_MAYA_MACROS_EXPORT @@ -88,7 +91,7 @@ install(TARGETS ${MAYAUTILS_LIBRARY_NAME} RUNTIME DESTINATION ${MAYAUTILS_LIBRARY_LOCATION} ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${MAYAUTILS_LIBRARY_LOCATION} OPTIONAL) endif() diff --git a/plugin/al/mayautils/AL/maya/tests/mayaplugintest/CMakeLists.txt b/plugin/al/mayautils/AL/maya/tests/mayaplugintest/CMakeLists.txt index e16a952559..3691221786 100644 --- a/plugin/al/mayautils/AL/maya/tests/mayaplugintest/CMakeLists.txt +++ b/plugin/al/mayautils/AL/maya/tests/mayaplugintest/CMakeLists.txt @@ -22,6 +22,15 @@ add_library(${MAYAUTILS_TEST_LIBRARY_NAME} # Remove the lib prefix else Maya can't load the library SET_TARGET_PROPERTIES(${MAYAUTILS_TEST_LIBRARY_NAME} PROPERTIES PREFIX "") +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + +target_compile_definitions(${MAYAUTILS_TEST_LIBRARY_NAME} + PRIVATE + ${_macDef} +) + target_link_libraries(${MAYAUTILS_TEST_LIBRARY_NAME} PRIVATE ${GTEST_LIBRARIES} diff --git a/plugin/al/mayautils/AL/maya/utils/NodeHelper.cpp b/plugin/al/mayautils/AL/maya/utils/NodeHelper.cpp index dc88ab7715..c94220a39b 100644 --- a/plugin/al/mayautils/AL/maya/utils/NodeHelper.cpp +++ b/plugin/al/mayautils/AL/maya/utils/NodeHelper.cpp @@ -194,7 +194,7 @@ MObject NodeHelper::addStringAttr(const char* longName, const char* shortName, u } //---------------------------------------------------------------------------------------------------------------------- -MObject NodeHelper::addStringAttr(const char* longName, const char* shortName, const char* defaultValue, uint32_t flags, bool forceShow) +void NodeHelper::inheritStringAttr(const char* longName, uint32_t flags, bool forceShow) { if(m_internal) { @@ -205,6 +205,11 @@ MObject NodeHelper::addStringAttr(const char* longName, const char* shortName, c frame.m_attributeTypes.push_back(Frame::kNormal); } } +} +//---------------------------------------------------------------------------------------------------------------------- +MObject NodeHelper::addStringAttr(const char* longName, const char* shortName, const char* defaultValue, uint32_t flags, bool forceShow) +{ + inheritStringAttr(longName, flags, forceShow); MFnTypedAttribute fn; MFnStringData stringData; @@ -217,7 +222,7 @@ MObject NodeHelper::addStringAttr(const char* longName, const char* shortName, c } //---------------------------------------------------------------------------------------------------------------------- -MObject NodeHelper::addFilePathAttr(const char* longName, const char* shortName, uint32_t flags, FileMode fileMode, const char* fileFilter) +void NodeHelper::inheritFilePathAttr(const char* longName, uint32_t flags, FileMode fileMode, const char* fileFilter) { if(m_internal) { @@ -229,6 +234,12 @@ MObject NodeHelper::addFilePathAttr(const char* longName, const char* shortName, frame.m_attributeTypes.push_back((Frame::AttributeUiType)fileMode); } } +} + +//---------------------------------------------------------------------------------------------------------------------- +MObject NodeHelper::addFilePathAttr(const char* longName, const char* shortName, uint32_t flags, FileMode fileMode, const char* fileFilter) +{ + inheritFilePathAttr(longName, flags, fileMode, fileFilter); MFnTypedAttribute fn; MObject attribute = fn.create(longName, shortName, MFnData::kString); MStatus status = applyAttributeFlags(fn, flags); @@ -278,7 +289,7 @@ MObject NodeHelper::addInt16Attr(const char* longName, const char* shortName, in } //---------------------------------------------------------------------------------------------------------------------- -MObject NodeHelper::addInt32Attr(const char* longName, const char* shortName, int32_t defaultValue, uint32_t flags) +void NodeHelper::inheritInt32Attr(const char* longName, uint32_t flags) { if(m_internal) { @@ -289,6 +300,13 @@ MObject NodeHelper::addInt32Attr(const char* longName, const char* shortName, in frame.m_attributeTypes.push_back(Frame::kNormal); } } +} + +//---------------------------------------------------------------------------------------------------------------------- +MObject NodeHelper::addInt32Attr(const char* longName, const char* shortName, int32_t defaultValue, uint32_t flags) +{ + inheritInt32Attr(longName, flags); + MFnNumericAttribute fn; MObject attribute = fn.create(longName, shortName, MFnNumericData::kInt, defaultValue); MStatus status = applyAttributeFlags(fn, flags); @@ -338,7 +356,7 @@ MObject NodeHelper::addFloatAttr(const char* longName, const char* shortName, fl } //---------------------------------------------------------------------------------------------------------------------- -MObject NodeHelper::addTimeAttr(const char* longName, const char* shortName, const MTime& defaultValue, uint32_t flags) +void NodeHelper::inheritTimeAttr(const char* longName, uint32_t flags) { if(m_internal) { @@ -349,6 +367,13 @@ MObject NodeHelper::addTimeAttr(const char* longName, const char* shortName, con frame.m_attributeTypes.push_back(Frame::kNormal); } } +} + +//---------------------------------------------------------------------------------------------------------------------- +MObject NodeHelper::addTimeAttr(const char* longName, const char* shortName, const MTime& defaultValue, uint32_t flags) +{ + inheritTimeAttr(longName, flags); + MFnUnitAttribute fn; MObject attribute = fn.create(longName, shortName, defaultValue); MStatus status = applyAttributeFlags(fn, flags); @@ -457,7 +482,7 @@ MObject NodeHelper::addDoubleAttr(const char* longName, const char* shortName, d } //---------------------------------------------------------------------------------------------------------------------- -MObject NodeHelper::addBoolAttr(const char* longName, const char* shortName, bool defaultValue, uint32_t flags) +void NodeHelper::inheritBoolAttr(const char* longName, uint32_t flags) { if(m_internal) { @@ -468,6 +493,13 @@ MObject NodeHelper::addBoolAttr(const char* longName, const char* shortName, boo frame.m_attributeTypes.push_back(Frame::kNormal); } } +} + +//---------------------------------------------------------------------------------------------------------------------- +MObject NodeHelper::addBoolAttr(const char* longName, const char* shortName, bool defaultValue, uint32_t flags) +{ + inheritBoolAttr(longName, flags); + MFnNumericAttribute fn; MObject attribute = fn.create(longName, shortName, MFnNumericData::kBoolean, defaultValue); MStatus status = applyAttributeFlags(fn, flags); diff --git a/plugin/al/mayautils/AL/maya/utils/NodeHelper.h b/plugin/al/mayautils/AL/maya/utils/NodeHelper.h index fa66b57b5d..4c16ecc0ff 100644 --- a/plugin/al/mayautils/AL/maya/utils/NodeHelper.h +++ b/plugin/al/mayautils/AL/maya/utils/NodeHelper.h @@ -651,6 +651,13 @@ class NodeHelper AL_MAYA_UTILS_PUBLIC static MObject addStringAttr(const char* longName, const char* shortName, uint32_t flags, bool forceShow = false); + /// \brief inherit in this node type a string attribute from a base node type. + /// \param longName long name for the attribute + /// \param flags a bitfield containing a mask of the AttributeFlags enumeration. Describes if the attribute is an input/output/etc + /// \param forceShow force attribute to be shown. Used in case attribute is not writable but needs to be shown i.e. read-only. + AL_MAYA_UTILS_PUBLIC + static void inheritStringAttr(const char* longName, uint32_t flags, bool forceShow = false); + /// \brief add a new string attribute to this node type. /// \param longName long name for the attribute /// \param shortName short name for the attribute @@ -672,6 +679,15 @@ class NodeHelper AL_MAYA_UTILS_PUBLIC static MObject addFilePathAttr(const char* longName, const char* shortName, uint32_t flags, FileMode fileMode, const char* fileFilter = ""); + /// \brief inherit in this node type a file path attribute from a base node type. + /// \param longName long name for the attribute + /// \param flags a bitfield containing a mask of the AttributeFlags enumeration. Describes if the attribute is an input/output/etc + /// \param fileMode an enum that determines whether the GUI should display a file open dialog, file save, or directory dialog. + /// \param fileFilter a file filter of the form: + /// "USD Files (*.usd*) (*.usd*);;Alembic Files (*.abc) (*.abc);;All files (*.*) (*.*)" + AL_MAYA_UTILS_PUBLIC + static void inheritFilePathAttr(const char* longName, uint32_t flags, FileMode fileMode, const char* fileFilter = ""); + /// \brief add a new integer attribute to this node type. /// \param longName long name for the attribute /// \param shortName short name for the attribute @@ -699,6 +715,12 @@ class NodeHelper AL_MAYA_UTILS_PUBLIC static MObject addInt32Attr(const char* longName, const char* shortName, int32_t defaultValue, uint32_t flags); + /// \brief inherit in this node type an integer attribute from a base node type. + /// \param longName long name for the attribute + /// \param flags a bitfield containing a mask of the AttributeFlags enumeration. Describes if the attribute is an input/output/etc + AL_MAYA_UTILS_PUBLIC + static void inheritInt32Attr(const char* longName, uint32_t flags); + /// \brief add a new integer attribute to this node type. /// \param longName long name for the attribute /// \param shortName short name for the attribute @@ -735,6 +757,12 @@ class NodeHelper AL_MAYA_UTILS_PUBLIC static MObject addTimeAttr(const char* longName, const char* shortName, const MTime& defaultValue, uint32_t flags); + /// \brief inherit in this node type a time attribute from a base node type. + /// \param longName long name for the attribute + /// \param flags a bitfield containing a mask of the AttributeFlags enumeration. Describes if the attribute is an input/output/etc + AL_MAYA_UTILS_PUBLIC + static void inheritTimeAttr(const char* longName, uint32_t flags); + /// \brief add a new time attribute to this node type. /// \param longName long name for the attribute /// \param shortName short name for the attribute @@ -763,6 +791,12 @@ class NodeHelper AL_MAYA_UTILS_PUBLIC static MObject addBoolAttr(const char* longName, const char* shortName, bool defaultValue, uint32_t flags); + /// \brief inherit in this node type a boolean attribute from a base node type. + /// \param longName long name for the attribute + /// \param flags a bitfield containing a mask of the AttributeFlags enumeration. Describes if the attribute is an input/output/etc + AL_MAYA_UTILS_PUBLIC + static void inheritBoolAttr(const char* longName, uint32_t flags); + /// \brief add a new float3 attribute to this node type. /// \param longName long name for the attribute /// \param shortName short name for the attribute diff --git a/plugin/al/plugin/AL_USDMayaPlugin/CMakeLists.txt b/plugin/al/plugin/AL_USDMayaPlugin/CMakeLists.txt index 60e3e8fc03..b743d6ecaf 100644 --- a/plugin/al/plugin/AL_USDMayaPlugin/CMakeLists.txt +++ b/plugin/al/plugin/AL_USDMayaPlugin/CMakeLists.txt @@ -30,38 +30,36 @@ target_include_directories(${PXR_PACKAGE} "../../lib/AL_USDMaya" ) -if(MSVC) - set_target_properties(${PXR_PACKAGE} PROPERTIES SUFFIX ".mll") -elseif(APPLE) - set_target_properties(${PXR_PACKAGE} - PROPERTIES - PREFIX "" - SUFFIX ".bundle" - MACOSX_RPATH TRUE - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "@loader_path/../lib;@loader_path/../../pxr/lib;@loader_path/../../pxr/maya/lib;${PXR_USD_LOCATION}/lib" - ) -else() - # This puts the paths into RUNPATH instead of RPATH. - # They are the same except that RPATH is searched before LD_LIBRARY_PATH whereas RUNPATH is searched after. - # Using RUNPATH will give users the ability to override a shared library. - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--enable-new-dtags") +MAYA_SET_PLUGIN_PROPERTIES(${PXR_PACKAGE}) - set_target_properties(${PXR_PACKAGE} - PROPERTIES - PREFIX "" - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/../../pxr/lib:$ORIGIN/../../pxr/maya/lib:${PXR_USD_LOCATION}/lib:${PXR_USD_LOCATION}/lib64" - ) +# rpath setup +if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "plugin") + mayaUsd_add_rpath(rpath "../lib") + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib") + mayaUsd_install_rpath(rpath ${PXR_PACKAGE}) +endif() + +if(IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib64") + endif() endif() install(TARGETS ${PXR_PACKAGE} LIBRARY - DESTINATION ${INSTALL_DIR_SUFFIX}/plugin + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugin RUNTIME - DESTINATION ${INSTALL_DIR_SUFFIX}/plugin + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugin ) -if(MSVC) - install(FILES $ DESTINATION ${INSTALL_DIR_SUFFIX}/plugin OPTIONAL) +if(IS_WINDOWS) + install(FILES $ DESTINATION ${CMAKE_INSTALL_PREFIX}/plugin OPTIONAL) endif() diff --git a/plugin/al/plugin/AL_USDMayaTestPlugin/AL/usdmaya/nodes/test_ProxyUsdGeomCamera.cpp b/plugin/al/plugin/AL_USDMayaTestPlugin/AL/usdmaya/nodes/test_ProxyUsdGeomCamera.cpp index 82a9387e52..2644d3dc67 100644 --- a/plugin/al/plugin/AL_USDMayaTestPlugin/AL/usdmaya/nodes/test_ProxyUsdGeomCamera.cpp +++ b/plugin/al/plugin/AL_USDMayaTestPlugin/AL/usdmaya/nodes/test_ProxyUsdGeomCamera.cpp @@ -37,7 +37,7 @@ #include "pxr/usd/usdGeom/xform.h" #include "AL/usdmaya/TypeIDs.h" -#include +#include #include using AL::usdmaya::nodes::ProxyShape; diff --git a/plugin/al/plugin/AL_USDMayaTestPlugin/CMakeLists.txt b/plugin/al/plugin/AL_USDMayaTestPlugin/CMakeLists.txt index 9c419be7fb..2bd7cd7843 100644 --- a/plugin/al/plugin/AL_USDMayaTestPlugin/CMakeLists.txt +++ b/plugin/al/plugin/AL_USDMayaTestPlugin/CMakeLists.txt @@ -85,32 +85,35 @@ PRIVATE ${MAYATEST_INCLUDE_LOCATION} ) -if(MSVC) - set_target_properties(${PXR_PACKAGE} PROPERTIES SUFFIX ".mll") -elseif(APPLE) - set_target_properties(${PXR_PACKAGE} - PROPERTIES - PREFIX "" - SUFFIX ".bundle" - MACOSX_RPATH TRUE - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "@loader_path/../lib;@loader_path/../../pxr/lib;@loader_path/../../pxr/maya/lib;${PXR_USD_LOCATION}/lib" - ) -else() - set_target_properties(${PXR_PACKAGE} - PROPERTIES - PREFIX "" - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/../../pxr/lib:$ORIGIN/../../pxr/maya/lib:${PXR_USD_LOCATION}/lib:${PXR_USD_LOCATION}/lib64" - ) +MAYA_SET_PLUGIN_PROPERTIES(${PXR_PACKAGE}) + +# rpath setup +if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "plugin") + mayaUsd_add_rpath(rpath "../lib") + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib") + mayaUsd_install_rpath(rpath ${PXR_PACKAGE}) +endif() + +if(IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib64") + endif() endif() install(TARGETS ${PXR_PACKAGE} LIBRARY - DESTINATION ${INSTALL_DIR_SUFFIX}/plugin + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugin RUNTIME - DESTINATION ${INSTALL_DIR_SUFFIX}/plugin + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugin ) add_test( diff --git a/plugin/al/plugin/AL_USDMayaTestPlugin/test_translators_Translator.cpp b/plugin/al/plugin/AL_USDMayaTestPlugin/test_translators_Translator.cpp index 69fc1122a3..bf3fe239c1 100644 --- a/plugin/al/plugin/AL_USDMayaTestPlugin/test_translators_Translator.cpp +++ b/plugin/al/plugin/AL_USDMayaTestPlugin/test_translators_Translator.cpp @@ -18,9 +18,10 @@ #include "AL/usdmaya/fileio/translators/TranslatorBase.h" #include "AL/usdmaya/fileio/translators/TranslatorContext.h" #include "AL/usdmaya/fileio/translators/TranslatorTestType.h" -#include "AL/usdmaya/StageData.h" #include "AL/usdmaya/nodes/ProxyShape.h" +#include + #include "maya/MDagModifier.h" #include "pxr/base/tf/refPtr.h" diff --git a/plugin/al/schemas/AL/usd/schemas/maya/CMakeLists.txt b/plugin/al/schemas/AL/usd/schemas/maya/CMakeLists.txt index 7455ac1124..4012ae0618 100644 --- a/plugin/al/schemas/AL/usd/schemas/maya/CMakeLists.txt +++ b/plugin/al/schemas/AL/usd/schemas/maya/CMakeLists.txt @@ -1,6 +1,3 @@ - -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set( resources_install_path ${CMAKE_INSTALL_PREFIX}/lib/usd/AL_USDMayaSchemas/resources @@ -39,7 +36,7 @@ configure_file ( execute_process( COMMAND - python + ${PYTHON_EXECUTABLE} ${USD_GENSCHEMA} ${CMAKE_CURRENT_BINARY_DIR}/schema.usda . @@ -67,9 +64,6 @@ add_library(AL_USDMayaSchemas target_compile_definitions(AL_USDMayaSchemas PRIVATE - MFB_PACKAGE_NAME=AL_USDMayaSchemas - MFB_ALT_PACKAGE_NAME=AL_USDMayaSchemas - MFB_PACKAGE_MODULE=AL.usd.schemas.maya AL_USDMAYASCHEMAS_EXPORTS ) @@ -81,7 +75,7 @@ target_include_directories(AL_USDMayaSchemas # Hamed 2019 # https://stackoverflow.com/questions/25617839/undefined-reference-to-symbol-pthread-key-deleteglibc-2-2-5 set(PTHREAD_LINK "") -if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if(IS_LINUX) set(PTHREAD_LINK -lpthread -lm) endif() @@ -94,7 +88,7 @@ install( RUNTIME DESTINATION ${library_install_path} ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${library_install_path} OPTIONAL) endif() @@ -123,7 +117,7 @@ set_target_properties(_AL_USDMayaSchemas PREFIX "" ) -if(MSVC) +if(IS_WINDOWS) set_target_properties(_AL_USDMayaSchemas PROPERTIES SUFFIX ".pyd" @@ -145,7 +139,7 @@ install(TARGETS _AL_USDMayaSchemas # configure_file has a nice feature where it will copy the __init__ file over when it gets modified, unlike file(COPY ...) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CMAKE_BINARY_DIR}/AL/usd/schemas/maya/__init__.py COPYONLY) -install(CODE "execute_process(COMMAND python -m compileall ${CMAKE_BINARY_DIR}/AL/usd/schemas/maya/__init__.py )") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m compileall ${CMAKE_BINARY_DIR}/AL/usd/schemas/maya/__init__.py )") string(REPLACE "/" ";" folderHierarchy "AL/usd/schemas/maya") @@ -180,7 +174,7 @@ install( ) install(CODE "message(STATUS \"POST INSTALL: Compiling python/pyc for ${CMAKE_INSTALL_PREFIX}/lib/python ... \")") -install(CODE "execute_process(COMMAND python -m compileall ${CMAKE_INSTALL_PREFIX}/lib/python )") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m compileall ${CMAKE_INSTALL_PREFIX}/lib/python )") #################################################################################################### # Install public headers diff --git a/plugin/al/schemas/AL/usd/schemas/mayatest/CMakeLists.txt b/plugin/al/schemas/AL/usd/schemas/mayatest/CMakeLists.txt index 14753885cc..6870198691 100644 --- a/plugin/al/schemas/AL/usd/schemas/mayatest/CMakeLists.txt +++ b/plugin/al/schemas/AL/usd/schemas/mayatest/CMakeLists.txt @@ -1,5 +1,3 @@ -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set( resources_install_path ${CMAKE_INSTALL_PREFIX}/lib/usd/AL_USDMayaSchemasTest/resources @@ -64,9 +62,6 @@ add_library(AL_USDMayaSchemasTest target_compile_definitions(AL_USDMayaSchemasTest PRIVATE - MFB_PACKAGE_NAME=AL_USDMayaSchemasTest - MFB_ALT_PACKAGE_NAME=AL_USDMayaSchemasTest - MFB_PACKAGE_MODULE=AL.usd.schemas.mayatest AL_USDMAYASCHEMASTEST_EXPORTS ) diff --git a/plugin/al/translators/CMakeLists.txt b/plugin/al/translators/CMakeLists.txt index ec5b998a16..7adea48356 100644 --- a/plugin/al/translators/CMakeLists.txt +++ b/plugin/al/translators/CMakeLists.txt @@ -1,6 +1,4 @@ -list(APPEND DEPENDANT_LIBRARIES AL_USDMaya AL_USDMayaSchemas gf plug tf) - -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) +list(APPEND DEPENDANT_LIBRARIES AL_USDMaya AL_USDMayaSchemas mayaUsd gf plug tf) set(DIRECTORY_PATH AL/usdmaya/fileio/translators) @@ -22,15 +20,23 @@ add_library(${TRANSLATORS_PACKAGE} DirectionalLight.cpp ) +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + +# HS OCT 2019, do we really need to define +# AL_MAYA_MACROS_EXPORT for this target? +if(NOT IS_WINDOWS) + set_target_properties(${TRANSLATORS_PACKAGE} + PROPERTIES COMPILE_DEFINITIONS + "AL_MAYA_MACROS_EXPORT;${_macDef}" + ) +endif() + set(arg_PUBLIC_HEADER_FILES Camera.h ) -target_compile_definitions(${TRANSLATORS_PACKAGE} - PRIVATE - AL_MAYA_MACROS_EXPORT -) - # Copy the plugin metadata file in a hierarchy replicating the install hierarchy. # The file will be used by the unittests. get_target_property(LIBRARY_LOCATION @@ -62,15 +68,26 @@ target_include_directories( ../lib/AL_USDMaya ) -set_target_properties(${TRANSLATORS_PACKAGE} - PROPERTIES COMPILE_DEFINITIONS - "MFB_TRANSLATORS_PACKAGE=${TRANSLATORS_PACKAGE};MFB_ALT_TRANSLATORS_PACKAGE=${TRANSLATORS_PACKAGE}" -) +# rpath setup +if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "plugin") + mayaUsd_add_rpath(rpath "../lib") + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_install_rpath(rpath ${TRANSLATORS_PACKAGE}) +endif() -set_target_properties(${TRANSLATORS_PACKAGE} - PROPERTIES COMPILE_DEFINITIONS - "MFB_TRANSLATORS_PACKAGE=${TRANSLATORS_PACKAGE};MFB_ALT_TRANSLATORS_PACKAGE=${TRANSLATORS_PACKAGE}" - ) +if (IS_LINUX) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--enable-new-dtags" PARENT_SCOPE) + + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib64") + endif() +endif() target_link_libraries(${TRANSLATORS_PACKAGE} ${DEPENDANT_LIBRARIES}) @@ -80,7 +97,7 @@ install(TARGETS ${TRANSLATORS_PACKAGE} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/lib ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib OPTIONAL) endif() diff --git a/plugin/al/translators/Mesh.cpp b/plugin/al/translators/Mesh.cpp index 31d5a15954..34754e3951 100644 --- a/plugin/al/translators/Mesh.cpp +++ b/plugin/al/translators/Mesh.cpp @@ -28,6 +28,7 @@ #include "AL/usdmaya/utils/DiffPrimVar.h" #include "AL/usdmaya/utils/MeshUtils.h" +#include "AL/usdmaya/utils/Utils.h" #include "AL/usdmaya/DebugCodes.h" #include "AL/usdmaya/fileio/translators/DagNodeTranslator.h" @@ -217,7 +218,7 @@ MStatus Mesh::preTearDown(UsdPrim& prim) * This crash and error seems to be happening mainly when switching out a variant that contains a Mesh, and that Mesh has been * force translated into Maya. */ - TfNotice::Block block; + AL::usdmaya::utils::BlockNotifications blockNow; //don't use TfNotice::Block, render delegates need to know about the change // Write the overrides back to the path it was imported at MObjectHandle obj; context()->getMObject(prim, obj, MFn::kInvalid); diff --git a/plugin/al/translators/pxrUsdTranslators/CMakeLists.txt b/plugin/al/translators/pxrUsdTranslators/CMakeLists.txt index 64808d967e..67d49cd1f4 100644 --- a/plugin/al/translators/pxrUsdTranslators/CMakeLists.txt +++ b/plugin/al/translators/pxrUsdTranslators/CMakeLists.txt @@ -30,24 +30,29 @@ add_library(${PXR_TRANSLATORS_PACKAGE} plugin.cpp ) -if(MSVC) - set_target_properties(${PXR_TRANSLATORS_PACKAGE} PROPERTIES SUFFIX ".mll") -elseif(APPLE) - set_target_properties(${PXR_TRANSLATORS_PACKAGE} - PROPERTIES - PREFIX "" - SUFFIX ".bundle" - MACOSX_RPATH TRUE - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "@loader_path/../lib;@loader_path/../../pxr/lib;@loader_path/../../pxr/maya/lib;${PXR_USD_LOCATION}/lib" - ) -else() - set_target_properties(${PXR_TRANSLATORS_PACKAGE} - PROPERTIES - PREFIX "" - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/../../pxr/lib:$ORIGIN/../../pxr/maya/lib:${PXR_USD_LOCATION}/lib:${PXR_USD_LOCATION}/lib64" - ) +MAYA_SET_PLUGIN_PROPERTIES(${PXR_TRANSLATORS_PACKAGE}) + +# rpath setup +if(IS_MACOSX OR IS_LINUX) + mayaUsd_init_rpath(rpath "plugin") + mayaUsd_add_rpath(rpath "../lib") + + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib") + mayaUsd_install_rpath(rpath ${PXR_TRANSLATORS_PACKAGE}) +endif() + +if (IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../USD/lib64") + endif() endif() target_include_directories( @@ -65,7 +70,7 @@ install(TARGETS ${PXR_TRANSLATORS_PACKAGE} RUNTIME DESTINATION ${INSTALL_DIR_SUFFIX}/plugin ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${INSTALL_DIR_SUFFIX}/plugin OPTIONAL) endif() diff --git a/plugin/al/translators/pxrUsdTranslators/ProxyShapeTranslator.cpp b/plugin/al/translators/pxrUsdTranslators/ProxyShapeTranslator.cpp index f2d6712ea2..16daf0bd8e 100644 --- a/plugin/al/translators/pxrUsdTranslators/ProxyShapeTranslator.cpp +++ b/plugin/al/translators/pxrUsdTranslators/ProxyShapeTranslator.cpp @@ -27,7 +27,7 @@ #include "usdMaya/primWriterArgs.h" #include "usdMaya/primWriterContext.h" #include "usdMaya/primWriterRegistry.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/token.h" #include "pxr/usd/kind/registry.h" diff --git a/plugin/al/usdmayautils/AL/usdmaya/utils/CMakeLists.txt b/plugin/al/usdmayautils/AL/usdmaya/utils/CMakeLists.txt index 03acec8157..1455a6ba7a 100755 --- a/plugin/al/usdmayautils/AL/usdmaya/utils/CMakeLists.txt +++ b/plugin/al/usdmayautils/AL/usdmaya/utils/CMakeLists.txt @@ -3,8 +3,6 @@ # Setup #################################################################################################### -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set(USDMAYA_UTILS_LIBRARY_NAME "AL_USDMayaUtils") set(MAYA_UTILS_LIBRARY_LOCATION ${CMAKE_INSTALL_PREFIX}/lib) @@ -37,8 +35,13 @@ add_library(${USDMAYA_UTILS_LIBRARY_NAME} ${usdmaya_utils_source} ) +if(IS_MACOSX) + set(_macDef OSMac_) +endif() + target_compile_definitions(${USDMAYA_UTILS_LIBRARY_NAME} PRIVATE + ${_macDef} AL_USDMAYA_UTILS_EXPORT ) @@ -79,6 +82,6 @@ install(TARGETS ${USDMAYA_UTILS_LIBRARY_NAME} RUNTIME DESTINATION ${MAYA_UTILS_LIBRARY_LOCATION} ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${MAYA_UTILS_LIBRARY_LOCATION} OPTIONAL) endif() diff --git a/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.cpp b/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.cpp index af0669e940..c9434a0091 100644 --- a/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.cpp +++ b/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.cpp @@ -24,10 +24,31 @@ #include "maya/MMatrix.h" #include "maya/MVector.h" +#include + +namespace { + std::atomic _blockingCount; +} + namespace AL { namespace usdmaya { namespace utils { +//---------------------------------------------------------------------------------------------------------------------- +BlockNotifications::BlockNotifications() { + _blockingCount++; +} + +//---------------------------------------------------------------------------------------------------------------------- +BlockNotifications::~BlockNotifications() { + _blockingCount--; +} + +//---------------------------------------------------------------------------------------------------------------------- +bool BlockNotifications::isBlockingNotifications() { + return _blockingCount.load() > 0; +} + //---------------------------------------------------------------------------------------------------------------------- void matrixToSRT(const GfMatrix4d& value, double S[3], MEulerRotation& R, double T[3]) { diff --git a/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.h b/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.h index 1a15867fb1..073b17232c 100644 --- a/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.h +++ b/plugin/al/usdmayautils/AL/usdmaya/utils/Utils.h @@ -29,6 +29,21 @@ namespace AL { namespace usdmaya { namespace utils { +//---------------------------------------------------------------------------------------------------------------------- +/// \brief Helper class used to stop proxy shape from processing any USD notifications (this affects all threads) +/// \ingroup usdmaya +class BlockNotifications { +public: + AL_USDMAYA_UTILS_PUBLIC + BlockNotifications(); + + AL_USDMAYA_UTILS_PUBLIC + ~BlockNotifications(); + + AL_USDMAYA_UTILS_PUBLIC + static bool isBlockingNotifications(); +}; + //---------------------------------------------------------------------------------------------------------------------- /// \brief Returns the dagPath result of mapping UsdPrim -> Maya Object. /// proxyShapeNode is an optional argument, if it is passed and the passed in mayaObject's path couldn't be determined, diff --git a/plugin/al/usdtransaction/CMakeLists.txt b/plugin/al/usdtransaction/CMakeLists.txt index 3ce0e4f049..dd753f9e20 100755 --- a/plugin/al/usdtransaction/CMakeLists.txt +++ b/plugin/al/usdtransaction/CMakeLists.txt @@ -1,5 +1,3 @@ -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - add_subdirectory(AL/usd/transaction) set(LIBRARY_NAME AL_USDTransaction) diff --git a/plugin/al/usdutils/AL/usd/utils/CMakeLists.txt b/plugin/al/usdutils/AL/usd/utils/CMakeLists.txt index e83427f29a..ee78fcbfaa 100755 --- a/plugin/al/usdutils/AL/usd/utils/CMakeLists.txt +++ b/plugin/al/usdutils/AL/usd/utils/CMakeLists.txt @@ -3,8 +3,6 @@ # Setup #################################################################################################### -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set(USDUTILS_LIBRARY_NAME "AL_USDUtils") set(USDUTILS_LIBRARY_LOCATION ${CMAKE_INSTALL_PREFIX}/lib) @@ -67,6 +65,6 @@ install(TARGETS ${USDUTILS_LIBRARY_NAME} RUNTIME DESTINATION ${USDUTILS_LIBRARY_LOCATION} ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${USDUTILS_LIBRARY_LOCATION} OPTIONAL) endif() diff --git a/plugin/al/utils/AL/CMakeLists.txt b/plugin/al/utils/AL/CMakeLists.txt index d51a0690e5..6f0236ee8f 100755 --- a/plugin/al/utils/AL/CMakeLists.txt +++ b/plugin/al/utils/AL/CMakeLists.txt @@ -2,8 +2,6 @@ # Setup #################################################################################################### -set(CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX} ) - set(EVENTS_LIBRARY_NAME "AL_EventSystem") set(EVENTS_LIBRARY_LOCATION ${CMAKE_INSTALL_PREFIX}/lib) @@ -44,6 +42,6 @@ install(TARGETS ${EVENTS_LIBRARY_NAME} RUNTIME DESTINATION ${EVENTS_LIBRARY_LOCATION} ) -if(MSVC) +if(IS_WINDOWS) install(FILES $ DESTINATION ${EVENTS_LIBRARY_LOCATION} OPTIONAL) endif() diff --git a/plugin/pxr/CMakeLists.txt b/plugin/pxr/CMakeLists.txt index 948aacd7f0..df21e3ec03 100644 --- a/plugin/pxr/CMakeLists.txt +++ b/plugin/pxr/CMakeLists.txt @@ -18,10 +18,6 @@ pxr_setup_python() #============================================================================== # Packages #============================================================================== -find_package(Maya REQUIRED) - -include(${USD_CONFIG_FILE}) - pxr_toplevel_prologue() add_subdirectory(maya) pxr_toplevel_epilogue() diff --git a/plugin/pxr/cmake/macros/Private.cmake b/plugin/pxr/cmake/macros/Private.cmake index 1567325c51..05e2d6db5d 100644 --- a/plugin/pxr/cmake/macros/Private.cmake +++ b/plugin/pxr/cmake/macros/Private.cmake @@ -438,7 +438,7 @@ function(_pxr_enable_precompiled_header TARGET_NAME) # Additional compile flags to use precompiled header. This will be set(compile_flags "") - if(MSVC) + if(IS_WINDOWS) # Build with precompiled header (/Yu, /Fp) and automatically # include the header (/FI). set(compile_flags "/Yu\"${rel_output_header_path}\" /FI\"${rel_output_header_path}\" /Fp\"${abs_precompiled_path}\"") @@ -450,7 +450,7 @@ function(_pxr_enable_precompiled_header TARGET_NAME) # Use FALSE if we have an external precompiled header we can use. if(TRUE) - if(MSVC) + if(IS_WINDOWS) # Copy the header to precompile. add_custom_command( OUTPUT "${abs_output_header_path}" @@ -570,72 +570,6 @@ function(_pxr_enable_precompiled_header TARGET_NAME) endforeach() endfunction() -# Initialize a variable to accumulate an rpath. The origin is the -# RUNTIME DESTINATION of the target. If not absolute it's appended -# to CMAKE_INSTALL_PREFIX. -function(_pxr_init_rpath rpathRef origin) - if(NOT IS_ABSOLUTE ${origin}) - set(origin "${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX}/${origin}") - get_filename_component(origin "${origin}" REALPATH) - endif() - set(${rpathRef} "${origin}" PARENT_SCOPE) -endfunction() - -# Add a relative target path to the rpath. If target is absolute compute -# and add a relative path from the origin to the target. -function(_pxr_add_rpath rpathRef target) - if(IS_ABSOLUTE "${target}") - # Make target relative to $ORIGIN (which is the first element in - # rpath when initialized with _pxr_init_rpath()). - list(GET ${rpathRef} 0 origin) - file(RELATIVE_PATH - target - "${origin}" - "${target}" - ) - if("x${target}" STREQUAL "x") - set(target ".") - endif() - endif() - file(TO_CMAKE_PATH "${target}" target) - set(new_rpath "${${rpathRef}}") - list(APPEND new_rpath "$ORIGIN/${target}") - set(${rpathRef} "${new_rpath}" PARENT_SCOPE) -endfunction() - -function(_pxr_install_rpath rpathRef NAME) - # Get and remove the origin. - list(GET ${rpathRef} 0 origin) - set(rpath ${${rpathRef}}) - list(REMOVE_AT rpath 0) - - # Canonicalize and uniquify paths. - set(final "") - foreach(path ${rpath}) - # Replace $ORIGIN with @loader_path - if(APPLE) - if("${path}/" MATCHES "^[$]ORIGIN/") - # Replace with origin path. - string(REPLACE "$ORIGIN/" "@loader_path/" path "${path}/") - endif() - endif() - - # Strip trailing slashes. - string(REGEX REPLACE "/+$" "" path "${path}") - - # Ignore paths we already have. - if (NOT ";${final};" MATCHES ";${path};") - list(APPEND final "${path}") - endif() - endforeach() - - set_target_properties(${NAME} - PROPERTIES - INSTALL_RPATH_USE_LINK_PATH TRUE - INSTALL_RPATH "${final}" - ) -endfunction() - # Split the library (target) names in libs into internal-to-the-monolithic- # library and external-of-it lists. function(_pxr_split_libraries libs internal_result external_result) @@ -817,7 +751,7 @@ function(_pxr_target_link_libraries NAME) if(";${PXR_STATIC_LIBS};" MATCHES ";${lib};") # The library is explicitly static. list(APPEND final ${lib}) - elseif(MSVC) + elseif(IS_WINDOWS) # The syntax here is -WHOLEARCHIVE[:lib] but CMake will # treat that as a link flag and not "see" the library. # As a result it won't replace a target with the path @@ -939,12 +873,32 @@ function(_pxr_python_module NAME) set(libInstallPrefix "lib/python/pxr/${pyModuleName}") # Python modules need to be able to access their corresponding - # wrapped library and the install lib directory. - _pxr_init_rpath(rpath "${libInstallPrefix}") - _pxr_add_rpath(rpath + # wrapped library and the install lib directory. The wrapped library + # is the C++ library (e.g. libusdMaya.so on Linux) for which we're + # providing Python wrappers (e.g. _usdMaya.so on Linux). + # Do not prepend INSTALL_DIR_SUFFIX, init_rpath does this for relative + # paths. + mayaUsd_init_rpath(rpath "${libInstallPrefix}") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${args_WRAPPED_LIB_INSTALL_PREFIX}") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") - _pxr_install_rpath(rpath ${LIBRARY_NAME}) + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + + # Add path for usd core + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + + if(IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../../USD/lib64") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib64") + endif() + endif() + + mayaUsd_install_rpath(rpath ${LIBRARY_NAME}) _get_folder("_python" folder) set_target_properties(${LIBRARY_NAME} @@ -958,16 +912,18 @@ function(_pxr_python_module NAME) PROPERTIES SUFFIX ".pyd" ) - elseif(APPLE) + elseif(IS_MACOSX) # Python modules must be suffixed with .so on Mac. set_target_properties(${LIBRARY_NAME} PROPERTIES SUFFIX ".so" ) + set(_macDef OSMac_) endif() target_compile_definitions(${LIBRARY_NAME} PRIVATE + ${_macDef} MFB_PACKAGE_NAME=${PXR_PACKAGE} MFB_ALT_PACKAGE_NAME=${PXR_PACKAGE} MFB_PACKAGE_MODULE=${pyModuleName} @@ -1213,11 +1169,15 @@ function(_pxr_library NAME) if(TARGET shared_libs) set(pythonModulesEnabled "PXR_PYTHON_MODULES_ENABLED=1") endif() + if(IS_MACOSX) + set(_macDef OSMac_) + endif() target_compile_definitions(${NAME} PUBLIC ${pythonEnabled} ${apiPublic} PRIVATE + ${_macDef} MFB_PACKAGE_NAME=${PXR_PACKAGE} MFB_ALT_PACKAGE_NAME=${PXR_PACKAGE} MFB_PACKAGE_MODULE=${pythonModuleName} @@ -1264,13 +1224,29 @@ function(_pxr_library NAME) # XXX -- May want some plugins to be baked into monolithic. _pxr_target_link_libraries(${NAME} ${args_LIBRARIES}) - # Rpath has libraries under the USD/third party prefix and the install prefix. - # The former is for helper libraries for a third party application and - # the latter for core USD libraries. - _pxr_init_rpath(rpath "${libInstallPrefix}") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX}/${PXR_INSTALL_SUBDIR}/lib") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX}/lib") - _pxr_install_rpath(rpath ${NAME}) + mayaUsd_init_rpath(rpath "${libInstallPrefix}") + # Add path for Pixar-specific Maya shared libraries. As of 1-Aug-2019, + # this is only the usdMaya shared library. + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${INSTALL_DIR_SUFFIX}/${PXR_INSTALL_SUBDIR}/lib") + # Add path for common mayaUsd shared libraries. As of 1-Aug-2019, this is + # only the mayaUsd shared library. + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../../USD/lib") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib") + endif() + + if(IS_LINUX) + if(WANT_USD_RELATIVE_PATH) + mayaUsd_add_rpath(rpath "../../../../../USD/lib64") + elseif(DEFINED PXR_USD_LOCATION) + mayaUsd_add_rpath(rpath "${PXR_USD_LOCATION}/lib64") + endif() + endif() + + mayaUsd_install_rpath(rpath ${NAME}) # # Set up the install. diff --git a/plugin/pxr/cmake/macros/Public.cmake b/plugin/pxr/cmake/macros/Public.cmake index b5414bd25a..adf32b44c3 100644 --- a/plugin/pxr/cmake/macros/Public.cmake +++ b/plugin/pxr/cmake/macros/Public.cmake @@ -108,7 +108,7 @@ function(pxr_library NAME) if(args_MAYA_PLUGIN) if (WIN32) set(suffix ".mll") - elseif(APPLE) + elseif(IS_MACOSX) set(suffix ".bundle") endif() endif() @@ -157,7 +157,7 @@ function(pxr_library NAME) if(PXR_ENABLE_PYTHON_SUPPORT AND (args_PYMODULE_CPPFILES OR args_PYMODULE_FILES OR args_PYSIDE_UI_FILES)) _pxr_python_module( ${NAME} - WRAPPED_LIB_INSTALL_PREFIX "${libInstallPrefix}" + WRAPPED_LIB_INSTALL_PREFIX "plugin/pxr/${libInstallPrefix}" PYTHON_FILES ${args_PYMODULE_FILES} PYSIDE_UI_FILES ${args_PYSIDE_UI_FILES} CPPFILES ${args_PYMODULE_CPPFILES} @@ -261,9 +261,9 @@ function(pxr_build_test_shared_lib LIBRARY_NAME) # Find libraries under the install prefix, which has the core USD # libraries. - _pxr_init_rpath(rpath "tests/lib") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") - _pxr_install_rpath(rpath ${LIBRARY_NAME}) + mayaUsd_init_rpath(rpath "tests/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_install_rpath(rpath ${LIBRARY_NAME}) if (NOT bt_SOURCE_DIR) set(bt_SOURCE_DIR testenv) @@ -341,9 +341,9 @@ function(pxr_build_test TEST_NAME) # Find libraries under the install prefix, which has the core USD # libraries. - _pxr_init_rpath(rpath "tests") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") - _pxr_install_rpath(rpath ${TEST_NAME}) + mayaUsd_init_rpath(rpath "tests") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_install_rpath(rpath ${TEST_NAME}) # XXX -- We shouldn't have to install to run tests. install(TARGETS ${TEST_NAME} @@ -425,7 +425,7 @@ function(pxr_register_test TEST_NAME) # This harness is a filter which allows us to manipulate the test run, # e.g. by changing the environment, changing the expected return code, etc. - set(testWrapperCmd ${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros/testWrapper.py --verbose) + set(testWrapperCmd ${PROJECT_SOURCE_DIR}/plugin/pxr/cmake/macros/testWrapper.py --verbose) if (bt_STDOUT_REDIRECT) set(testWrapperCmd ${testWrapperCmd} --stdout-redirect=${bt_STDOUT_REDIRECT}) @@ -456,9 +456,9 @@ function(pxr_register_test TEST_NAME) # assume the testenv has the same name as the test but allow it to be # overridden by specifying TESTENV. if (bt_TESTENV) - set(testenvDir ${CMAKE_INSTALL_PREFIX}/tests/ctest/${bt_TESTENV}) + set(testenvDir ${CMAKE_INSTALL_PREFIX}/plugin/pxr/tests/ctest/${bt_TESTENV}) else() - set(testenvDir ${CMAKE_INSTALL_PREFIX}/tests/ctest/${TEST_NAME}) + set(testenvDir ${CMAKE_INSTALL_PREFIX}/plugin/pxr/tests/ctest/${TEST_NAME}) endif() set(testWrapperCmd ${testWrapperCmd} --testenv-dir=${testenvDir}) @@ -515,31 +515,32 @@ function(pxr_register_test TEST_NAME) endforeach() endif() - # If we're building static libraries, the C++ tests that link against - # these libraries will look for resource files in the "usd" subdirectory - # relative to where the tests are installed. However, the build installs - # these files in the "lib" directory where the libraries are installed. + # Look for resource files in the "usd" subdirectory relative to the + # "lib" directory where the libraries are installed. # # We don't want to copy these resource files for each test, so instead # we set the PXR_PLUGINPATH_NAME env var to point to the "lib/usd" # directory where these files are installed. - if (NOT TARGET shared_libs) - set(_plugSearchPathEnvName "PXR_PLUGINPATH_NAME") - if (PXR_OVERRIDE_PLUGINPATH_NAME) - set(_plugSearchPathEnvName ${PXR_OVERRIDE_PLUGINPATH_NAME}) - endif() - - set(testWrapperCmd ${testWrapperCmd} --env-var=${_plugSearchPathEnvName}=${CMAKE_INSTALL_PREFIX}/lib/usd) + set(_plugSearchPathEnvName "PXR_PLUGINPATH_NAME") + if (PXR_OVERRIDE_PLUGINPATH_NAME) + set(_plugSearchPathEnvName ${PXR_OVERRIDE_PLUGINPATH_NAME}) endif() + set(_testPluginPath "${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin;${CMAKE_INSTALL_PREFIX}/lib/usd") + set(_testPrePath "$ENV{PATH};${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib;${CMAKE_INSTALL_PREFIX}/lib") + # Ensure that Python imports the Python files built by this build. # On Windows convert backslash to slash and don't change semicolons # to colons. - set(_testPythonPath "${CMAKE_INSTALL_PREFIX}/lib/python;$ENV{PYTHONPATH}") + set(_testPythonPath "${CMAKE_INSTALL_PREFIX}/lib/python;${CMAKE_INSTALL_PREFIX}/plugin/pxr/lib/python;$ENV{PYTHONPATH}") if(WIN32) string(REGEX REPLACE "\\\\" "/" _testPythonPath "${_testPythonPath}") + string(REGEX REPLACE "\\\\" "/" _testPluginPath "${_testPluginPath}") + string(REGEX REPLACE "\\\\" "/" _testPrePath "${_testPrePath}") else() string(REPLACE ";" ":" _testPythonPath "${_testPythonPath}") + string(REPLACE ";" ":" _testPluginPath "${_testPluginPath}") + string(REPLACE ";" ":" _testPrePath "${_testPrePath}") endif() # Ensure we run with the appropriate python executable. @@ -554,7 +555,9 @@ function(pxr_register_test TEST_NAME) add_test( NAME ${TEST_NAME} COMMAND ${PYTHON_EXECUTABLE} ${testWrapperCmd} - "--env-var=PYTHONPATH=${_testPythonPath}" ${testCmd} + "--env-var=PYTHONPATH=${_testPythonPath}" + "--env-var=${_plugSearchPathEnvName}=${_testPluginPath}" + "--pre-path=${_testPrePath}" ${testCmd} ) # But in some cases, we need to pass cmake properties directly to cmake @@ -732,7 +735,7 @@ function(pxr_toplevel_epilogue) # that we carefully avoid adding the usd_m target itself by using # TARGET_FILE. Linking the usd_m target would link usd_m and # everything it links to. - if(MSVC) + if(IS_WINDOWS) target_link_libraries(usd_ms PRIVATE -WHOLEARCHIVE:$ @@ -777,10 +780,10 @@ function(pxr_toplevel_epilogue) ${PXR_THREAD_LIBS} ) - _pxr_init_rpath(rpath "${libInstallPrefix}") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${PXR_INSTALL_SUBDIR}/lib") - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") - _pxr_install_rpath(rpath usd_ms) + mayaUsd_init_rpath(rpath "${libInstallPrefix}") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/${PXR_INSTALL_SUBDIR}/lib") + mayaUsd_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") + mayaUsd_install_rpath(rpath usd_ms) endif() # Setup the plugins in the top epilogue to ensure that everybody has had a diff --git a/plugin/pxr/cmake/macros/testWrapper.py b/plugin/pxr/cmake/macros/testWrapper.py index ae8100beaa..2936383a1d 100644 --- a/plugin/pxr/cmake/macros/testWrapper.py +++ b/plugin/pxr/cmake/macros/testWrapper.py @@ -233,11 +233,11 @@ def _runCommand(raw_command, stdout_redir, stderr_redir, env, # Add any envvars specified with --env-var options into the environment env = os.environ.copy() for varStr in args.envVars: - if varStr == 'PATH': - sys.stderr.write("Error: use --pre-path or --post-path to edit PATH.") - sys.exit(1) try: k, v = varStr.split('=', 1) + if k == 'PATH': + sys.stderr.write("Error: use --pre-path or --post-path to edit PATH.") + sys.exit(1) v = v.replace('', testDir) env[k] = v except IndexError: diff --git a/plugin/pxr/maya/CMakeLists.txt b/plugin/pxr/maya/CMakeLists.txt index 0834a07c9b..b805f2379c 100644 --- a/plugin/pxr/maya/CMakeLists.txt +++ b/plugin/pxr/maya/CMakeLists.txt @@ -1,5 +1,5 @@ set(PXR_INSTALL_SUBDIR "maya") - + pxr_add_extra_plugins(plugin) add_subdirectory(lib) diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/batchRenderer.h b/plugin/pxr/maya/lib/pxrUsdMayaGL/batchRenderer.h index 09470e09c1..2dd285241b 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/batchRenderer.h +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/batchRenderer.h @@ -25,8 +25,8 @@ #include "pxrUsdMayaGL/shapeAdapter.h" #include "pxrUsdMayaGL/softSelectHelper.h" #include "usdMaya/diagnosticDelegate.h" -#include "usdMaya/notice.h" -#include "usdMaya/util.h" +#include +#include #include "pxr/base/gf/matrix4d.h" #include "pxr/base/gf/vec2i.h" diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerImager.h b/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerImager.h index 908d705533..d244179240 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerImager.h +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerImager.h @@ -24,8 +24,8 @@ #include "pxr/base/tf/singleton.h" #include "pxr/base/tf/weakBase.h" -#include "usdMaya/notice.h" -#include "usdMaya/util.h" +#include +#include #include #include diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerShapeAdapter.cpp b/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerShapeAdapter.cpp index 6f1db1008b..c9592508df 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerShapeAdapter.cpp +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/instancerShapeAdapter.cpp @@ -21,7 +21,7 @@ #include "pxrUsdMayaGL/shapeAdapter.h" #include "usdMaya/referenceAssembly.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeUtil.h" #include "pxr/base/gf/vec4f.h" diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyDrawOverride.cpp b/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyDrawOverride.cpp index dce98e79e1..4238986b21 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyDrawOverride.cpp +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyDrawOverride.cpp @@ -122,7 +122,7 @@ UsdMayaProxyDrawOverride::boundingBox( return MBoundingBox(); } - UsdMayaProxyShape* pShape = UsdMayaProxyShape::GetShapeAtDagPath(objPath); + MayaUsdProxyShapeBase* pShape = MayaUsdProxyShapeBase::GetShapeAtDagPath(objPath); if (!pShape) { return MBoundingBox(); } @@ -156,7 +156,7 @@ UsdMayaProxyDrawOverride::isBounded( // remove PIXMAYA_ENABLE_BOUNDING_BOX_MODE. return true; - // UsdMayaProxyShape* pShape = UsdMayaProxyShape::GetShapeAtDagPath(objPath); + // MayaUsdProxyShapeBase* pShape = MayaUsdProxyShapeBase::GetShapeAtDagPath(objPath); // if (!pShape) { // return false; // } @@ -190,7 +190,7 @@ UsdMayaProxyDrawOverride::prepareForDraw( return nullptr; } - UsdMayaProxyShape* shape = UsdMayaProxyShape::GetShapeAtDagPath(objPath); + MayaUsdProxyShapeBase* shape = MayaUsdProxyShapeBase::GetShapeAtDagPath(objPath); if (!shape) { return nullptr; } diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeDelegate.cpp b/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeDelegate.cpp index 24a4f50330..e7ed73052a 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeDelegate.cpp +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeDelegate.cpp @@ -48,7 +48,7 @@ static PxrMayaHdPrimFilter _sharedPrimFilter = { /// rendering using Hydra via the UsdMayaGLBatchRenderer. bool UsdMayaGL_ClosestPointOnProxyShape( - const UsdMayaProxyShape& shape, + const MayaUsdProxyShapeBase& shape, const GfRay& ray, GfVec3d* outClosestPoint, GfVec3d* outClosestNormal) @@ -137,7 +137,7 @@ UsdMayaGL_ObjectSoftSelectEnabled() TF_REGISTRY_FUNCTION(UsdMayaProxyShape) { - UsdMayaProxyShape::SetClosestPointDelegate( + MayaUsdProxyShapeBase::SetClosestPointDelegate( UsdMayaGL_ClosestPointOnProxyShape); UsdMayaProxyShape::SetObjectSoftSelectEnabledDelegate( UsdMayaGL_ObjectSoftSelectEnabled); diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeUI.cpp b/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeUI.cpp index 03932d1268..840f0442a0 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeUI.cpp +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/proxyShapeUI.cpp @@ -64,8 +64,8 @@ UsdMayaProxyShapeUI::getDrawRequests( MDrawRequestQueue& requests) { const MDagPath shapeDagPath = drawInfo.multiPath(); - UsdMayaProxyShape* shape = - UsdMayaProxyShape::GetShapeAtDagPath(shapeDagPath); + MayaUsdProxyShapeBase* shape = + MayaUsdProxyShapeBase::GetShapeAtDagPath(shapeDagPath); if (!shape) { return; } @@ -142,7 +142,7 @@ UsdMayaProxyShapeUI::select( return false; } - // Note that we cannot use UsdMayaProxyShape::GetShapeAtDagPath() here. + // Note that we cannot use MayaUsdProxyShapeBase::GetShapeAtDagPath() here. // selectInfo.selectPath() returns the dag path to the assembly node, not // the shape node, so we don't have the shape node's path readily available. UsdMayaProxyShape* shape = static_cast(surfaceShape()); diff --git a/plugin/pxr/maya/lib/pxrUsdMayaGL/usdProxyShapeAdapter.cpp b/plugin/pxr/maya/lib/pxrUsdMayaGL/usdProxyShapeAdapter.cpp index 75f5ce09e8..318122cb0e 100644 --- a/plugin/pxr/maya/lib/pxrUsdMayaGL/usdProxyShapeAdapter.cpp +++ b/plugin/pxr/maya/lib/pxrUsdMayaGL/usdProxyShapeAdapter.cpp @@ -123,8 +123,8 @@ PxrMayaHdUsdProxyShapeAdapter::_Sync( const unsigned int displayStyle, const MHWRender::DisplayStatus displayStatus) { - UsdMayaProxyShape* usdProxyShape = - UsdMayaProxyShape::GetShapeAtDagPath(shapeDagPath); + MayaUsdProxyShapeBase* usdProxyShape = + MayaUsdProxyShapeBase::GetShapeAtDagPath(shapeDagPath); if (!usdProxyShape) { TF_DEBUG(PXRUSDMAYAGL_SHAPE_ADAPTER_LIFECYCLE).Msg( "Failed to get UsdMayaProxyShape for '%s'\n", diff --git a/plugin/pxr/maya/lib/usdMaya/CMakeLists.txt b/plugin/pxr/maya/lib/usdMaya/CMakeLists.txt index 03b080e32f..773a2c3d51 100644 --- a/plugin/pxr/maya/lib/usdMaya/CMakeLists.txt +++ b/plugin/pxr/maya/lib/usdMaya/CMakeLists.txt @@ -22,6 +22,7 @@ pxr_shared_library(${PXR_PACKAGE} ${MAYA_OpenMaya_LIBRARY} ${MAYA_OpenMayaAnim_LIBRARY} ${MAYA_OpenMayaRender_LIBRARY} + mayaUsd INCLUDE_DIRS ${Boost_INCLUDE_DIRS} @@ -33,13 +34,11 @@ pxr_shared_library(${PXR_PACKAGE} PUBLIC_CLASSES adaptor blockSceneModificationContext - colorSpace diagnosticDelegate editUtil hdImagingShape jobArgs meshUtil - notice pointBasedDeformerNode primReader primReaderArgs @@ -49,7 +48,6 @@ pxr_shared_library(${PXR_PACKAGE} primWriterArgs primWriterContext primWriterRegistry - query readUtil roundTripUtil shaderWriter @@ -58,10 +56,7 @@ pxr_shared_library(${PXR_PACKAGE} shadingModeImporter shadingModeRegistry shadingUtil - stageCache - stageData stageNode - stageNoticeListener transformWriter translatorCamera translatorCurves @@ -75,8 +70,6 @@ pxr_shared_library(${PXR_PACKAGE} translatorSkel translatorUtil translatorXformable - util - usdPrimProvider writeJobContext writeUtil xformStack @@ -96,7 +89,6 @@ pxr_shared_library(${PXR_PACKAGE} userTaggedAttribute PRIVATE_CLASSES - debugCodes fallbackPrimReader functorPrimReader functorPrimWriter @@ -232,14 +224,22 @@ pxr_install_test_dir( SRC testenv/PointBasedDeformerNodeTest DEST testPointBasedDeformerNode ) +set(TEST_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/plugin/pxr") + +# MAYA-96273 (closed as by design) says that to obtain correct mayapy exit +# codes starting with Maya 2018.4, the MAYA_NO_STANDALONE_ATEXIT environment +# variable must be defined. Otherwise, mayapy unconditionally exits with 0 +# (success), which completely masks test failures. + pxr_register_test(testPointBasedDeformerNode CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testPointBasedDeformerNode" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testPointBasedDeformerNode" TESTENV testPointBasedDeformerNode ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -249,12 +249,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportAsClip CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportAsClip" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportAsClip" TESTENV testUsdExportAsClip ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -264,12 +265,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportAssembly CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportAssembly" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportAssembly" TESTENV testUsdExportAssembly ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -279,12 +281,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportAssemblyEdits CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportAssemblyEdits" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportAssemblyEdits" TESTENV testUsdExportAssemblyEdits ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -294,12 +297,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportCamera CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportCamera" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportCamera" TESTENV testUsdExportCamera ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -309,12 +313,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportColorSets CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportColorSets" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportColorSets" TESTENV testUsdExportColorSets ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -324,12 +329,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportConnected CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportConnected" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportConnected" TESTENV testUsdExportConnected ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -340,12 +346,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportDisplayColor CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportDisplayColor" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportDisplayColor" TESTENV testUsdExportDisplayColor ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -355,12 +362,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportEulerFilter CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportEulerFilter" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportEulerFilter" TESTENV testUsdExportEulerFilter ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -370,12 +378,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportFilterTypes CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportFilterTypes" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportFilterTypes" TESTENV testUsdExportFilterTypes ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -385,12 +394,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportFrameOffset CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportFrameOffset" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportFrameOffset" TESTENV testUsdExportFrameOffset ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -400,12 +410,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportInstances CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportInstances" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportInstances" TESTENV testUsdExportInstances ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -415,12 +426,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportLocator CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportLocator" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportLocator" TESTENV testUsdExportLocator ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -430,12 +442,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportMesh CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportMesh" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportMesh" TESTENV testUsdExportMesh ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -445,22 +458,24 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportNurbsCurve CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportNurbsCurve" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportNurbsCurve" TESTENV testUsdExportNurbsCurve ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) pxr_register_test(testUsdExportOpenLayer CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportOpenLayer" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportOpenLayer" ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -470,12 +485,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportOverImport CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportOverImport" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportOverImport" TESTENV testUsdExportOverImport ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -485,12 +501,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportPackage CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportPackage" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportPackage" TESTENV testUsdExportPackage ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -500,12 +517,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportParentScope CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportParentScope" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportParentScope" TESTENV testUsdExportParentScope ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -515,12 +533,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportParticles CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportParticles" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportParticles" TESTENV testUsdExportParticles ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -530,12 +549,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportPointInstancer CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportPointInstancer" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportPointInstancer" TESTENV testUsdExportPointInstancer ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -545,12 +565,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportPref CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportPref" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportPref" TESTENV testUsdExportPref ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -560,12 +581,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportRenderLayerMode CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportRenderLayerMode" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportRenderLayerMode" TESTENV testUsdExportRenderLayerMode ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile MAYA_ENABLE_LEGACY_RENDER_LAYERS=1 ) @@ -578,12 +600,13 @@ pxr_register_test(testUsdExportRenderLayerMode # ) # pxr_register_test(testUsdExportRfMLight # CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} -# COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportRfMLight" +# COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportRfMLight" # TESTENV testUsdExportRfMLight # ENV -# MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin -# MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources +# MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin +# MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources # MAYA_DISABLE_CIP=1 +# MAYA_NO_STANDALONE_ATEXIT=1 # MAYA_APP_DIR=/maya_profile # ) @@ -593,12 +616,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportSelection CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportSelection" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportSelection" TESTENV testUsdExportSelection ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -608,12 +632,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportShadingInstanced CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportShadingInstanced" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportShadingInstanced" TESTENV testUsdExportShadingInstanced ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -623,12 +648,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportShadingModeDisplayColor CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportShadingModeDisplayColor" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportShadingModeDisplayColor" TESTENV testUsdExportShadingModeDisplayColor ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -638,12 +664,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportShadingModePxrRis CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportShadingModePxrRis" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportShadingModePxrRis" TESTENV testUsdExportShadingModePxrRis ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -653,23 +680,25 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportSkeleton CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportSkeleton" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportSkeleton" TESTENV testUsdExportSkeleton ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) pxr_register_test(testUsdExportStripNamespaces CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportStripNamespaces" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportStripNamespaces" TESTENV testUsdExportStripNamespaces ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -679,13 +708,14 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportUVSets CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportUVSets" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportUVSets" TESTENV testUsdExportUVSets ENV PIXMAYA_WRITE_UV_AS_FLOAT2=0 - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -695,13 +725,14 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportUVSetsFloat CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportUVSets" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportUVSets" TESTENV testUsdExportUVSetsFloat ENV PIXMAYA_WRITE_UV_AS_FLOAT2=1 - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -711,13 +742,14 @@ pxr_install_test_dir( ) pxr_register_test(testUsdExportVisibilityDefault CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdExportVisibilityDefault" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdExportVisibilityDefault" TESTENV testUsdExportVisibilityDefault ENV PIXMAYA_WRITE_UV_AS_FLOAT2=1 - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -727,12 +759,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportAsAssemblies CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportAsAssemblies" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportAsAssemblies" TESTENV testUsdImportAsAssemblies ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -742,12 +775,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportCamera CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportCamera" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportCamera" TESTENV testUsdImportCamera ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -757,12 +791,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportColorSets CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportColorSets" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportColorSets" TESTENV testUsdImportColorSets ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -772,12 +807,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportFrameRange CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportFrameRange" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportFrameRange" TESTENV testUsdImportFrameRange ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -787,12 +823,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportMesh CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportMesh" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportMesh" TESTENV testUsdImportMesh ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -802,12 +839,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportNestedAssemblyAnimation CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportNestedAssemblyAnimation" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportNestedAssemblyAnimation" TESTENV testUsdImportNestedAssemblyAnimation ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -819,12 +857,13 @@ pxr_register_test(testUsdImportNestedAssemblyAnimation # ) # pxr_register_test(testUsdImportRfMLight # CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} -# COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportRfMLight" +# COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportRfMLight" # TESTENV testUsdImportRfMLight # ENV -# MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin -# MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources +# MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin +# MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources # MAYA_DISABLE_CIP=1 +# MAYA_NO_STANDALONE_ATEXIT=1 # MAYA_APP_DIR=/maya_profile # ) @@ -834,12 +873,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportSessionLayer CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportSessionLayer" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportSessionLayer" TESTENV testUsdImportSessionLayer ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -849,12 +889,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportShadingModeDisplayColor CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportShadingModeDisplayColor" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportShadingModeDisplayColor" TESTENV testUsdImportShadingModeDisplayColor ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -864,12 +905,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportShadingModePxrRis CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportShadingModePxrRis" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportShadingModePxrRis" TESTENV testUsdImportShadingModePxrRis ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -879,12 +921,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportSkeleton CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportSkeleton" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportSkeleton" TESTENV testUsdImportSkeleton ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -894,12 +937,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdTranslateTypelessDefs CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdTranslateTypelessDefs" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdTranslateTypelessDefs" TESTENV testUsdTranslateTypelessDefs ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -909,13 +953,14 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportUVSets CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportUVSets" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportUVSets" TESTENV testUsdImportUVSets ENV PIXMAYA_READ_FLOAT2_AS_UV=0 - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -925,13 +970,14 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportUVSetsFloat CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportUVSets" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportUVSets" TESTENV testUsdImportUVSetsFloat ENV PIXMAYA_READ_FLOAT2_AS_UV=1 - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -941,12 +987,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdImportXforms CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImportXforms" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdImportXforms" TESTENV testUsdImportXforms ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -956,32 +1003,35 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaAppDir CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaAppDir" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaAppDir" TESTENV testUsdMayaAppDir ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) pxr_register_test(testUsdMayaBlockSceneModificationContext CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaBlockSceneModificationContext" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaBlockSceneModificationContext" ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) pxr_register_test(testUsdMayaDiagnosticDelegate CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaDiagnosticDelegate" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaDiagnosticDelegate" ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -991,12 +1041,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaGetVariantSetSelections CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaGetVariantSetSelections" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaGetVariantSetSelections" TESTENV testUsdMayaGetVariantSetSelections ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1006,12 +1057,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaModelKindProcessor CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaModelKindProcessor" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaModelKindProcessor" TESTENV testUsdMayaModelKindProcessor ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1021,12 +1073,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaProxyShape CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaProxyShape" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaProxyShape" TESTENV testUsdMayaProxyShape ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1036,12 +1089,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaReferenceAssemblyEdits CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaReferenceAssemblyEdits" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaReferenceAssemblyEdits" TESTENV testUsdMayaReferenceAssemblyEdits ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1051,12 +1105,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaUserExportedAttributes CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaUserExportedAttributes" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaUserExportedAttributes" TESTENV testUsdMayaUserExportedAttributes ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1066,12 +1121,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaAdaptorGeom CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaAdaptorGeom" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaAdaptorGeom" TESTENV testUsdMayaAdaptorGeom ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1081,12 +1137,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdMayaAdaptorMetadata CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaAdaptorMetadata" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaAdaptorMetadata" TESTENV testUsdMayaAdaptorMetadata ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1096,12 +1153,13 @@ pxr_install_test_dir( ) pxr_register_test(testUsdReferenceAssemblyChangeRepresentations CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdReferenceAssemblyChangeRepresentations" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdReferenceAssemblyChangeRepresentations" TESTENV testUsdReferenceAssemblyChangeRepresentations ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -1111,22 +1169,24 @@ pxr_install_test_dir( ) pxr_register_test(testUsdReferenceAssemblySelection CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdReferenceAssemblySelection" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdReferenceAssemblySelection" TESTENV testUsdReferenceAssemblySelection ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) pxr_register_test(testUsdMayaXformStack CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdMayaXformStack" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testUsdMayaXformStack" TESTENV testUsdMayaXformStack ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) diff --git a/plugin/pxr/maya/lib/usdMaya/adaptor.cpp b/plugin/pxr/maya/lib/usdMaya/adaptor.cpp index 2836269e0c..f7e42c8d1b 100644 --- a/plugin/pxr/maya/lib/usdMaya/adaptor.cpp +++ b/plugin/pxr/maya/lib/usdMaya/adaptor.cpp @@ -18,7 +18,7 @@ #include "usdMaya/primWriterRegistry.h" #include "usdMaya/readUtil.h" #include "usdMaya/registryHelper.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeUtil.h" #include "pxr/usd/sdf/schema.h" diff --git a/plugin/pxr/maya/lib/usdMaya/chaserRegistry.cpp b/plugin/pxr/maya/lib/usdMaya/chaserRegistry.cpp index f43da67ce4..b9714cce00 100644 --- a/plugin/pxr/maya/lib/usdMaya/chaserRegistry.cpp +++ b/plugin/pxr/maya/lib/usdMaya/chaserRegistry.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/chaserRegistry.h" -#include "usdMaya/debugCodes.h" +#include #include "usdMaya/registryHelper.h" #include "pxr/base/tf/instantiateSingleton.h" diff --git a/plugin/pxr/maya/lib/usdMaya/chaserRegistry.h b/plugin/pxr/maya/lib/usdMaya/chaserRegistry.h index 593f3eaa52..1819cfaeff 100644 --- a/plugin/pxr/maya/lib/usdMaya/chaserRegistry.h +++ b/plugin/pxr/maya/lib/usdMaya/chaserRegistry.h @@ -21,7 +21,7 @@ #include "usdMaya/api.h" #include "usdMaya/chaser.h" #include "usdMaya/jobArgs.h" -#include "usdMaya/util.h" +#include #include "pxr/pxr.h" diff --git a/plugin/pxr/maya/lib/usdMaya/diagnosticDelegate.cpp b/plugin/pxr/maya/lib/usdMaya/diagnosticDelegate.cpp index 49b4b71ed5..f659071454 100644 --- a/plugin/pxr/maya/lib/usdMaya/diagnosticDelegate.cpp +++ b/plugin/pxr/maya/lib/usdMaya/diagnosticDelegate.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/diagnosticDelegate.h" -#include "usdMaya/debugCodes.h" +#include #include "pxr/base/arch/threads.h" #include "pxr/base/tf/envSetting.h" diff --git a/plugin/pxr/maya/lib/usdMaya/editUtil.cpp b/plugin/pxr/maya/lib/usdMaya/editUtil.cpp index 6dbb114dbb..2710aec5c8 100644 --- a/plugin/pxr/maya/lib/usdMaya/editUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/editUtil.cpp @@ -16,7 +16,7 @@ #include "usdMaya/editUtil.h" #include "usdMaya/referenceAssembly.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/stringUtils.h" diff --git a/plugin/pxr/maya/lib/usdMaya/exportCommand.cpp b/plugin/pxr/maya/lib/usdMaya/exportCommand.cpp index c4ebf0c2ba..8f9d50f6fd 100644 --- a/plugin/pxr/maya/lib/usdMaya/exportCommand.cpp +++ b/plugin/pxr/maya/lib/usdMaya/exportCommand.cpp @@ -16,7 +16,7 @@ #include "usdMaya/exportCommand.h" #include "usdMaya/shadingModeRegistry.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJob.h" #include "usdMaya/writeUtil.h" diff --git a/plugin/pxr/maya/lib/usdMaya/hdImagingShape.cpp b/plugin/pxr/maya/lib/usdMaya/hdImagingShape.cpp index a2179efa08..c4100f1dd6 100644 --- a/plugin/pxr/maya/lib/usdMaya/hdImagingShape.cpp +++ b/plugin/pxr/maya/lib/usdMaya/hdImagingShape.cpp @@ -18,7 +18,7 @@ #include "usdMaya/blockSceneModificationContext.h" #include "usdMaya/translatorUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/envSetting.h" diff --git a/plugin/pxr/maya/lib/usdMaya/hdImagingShape.h b/plugin/pxr/maya/lib/usdMaya/hdImagingShape.h index dc407cd668..bf1da84820 100644 --- a/plugin/pxr/maya/lib/usdMaya/hdImagingShape.h +++ b/plugin/pxr/maya/lib/usdMaya/hdImagingShape.h @@ -21,7 +21,7 @@ #include "pxr/pxr.h" #include "usdMaya/api.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/staticTokens.h" diff --git a/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.cpp b/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.cpp index 3b6a8617b2..32830a7077 100644 --- a/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.cpp +++ b/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.cpp @@ -17,7 +17,7 @@ #include "usdMaya/instancedNodeWriter.h" #include "usdMaya/primWriter.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/usd/sdf/path.h" diff --git a/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.h b/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.h index b5e84ee275..e42b43f339 100644 --- a/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.h +++ b/plugin/pxr/maya/lib/usdMaya/instancedNodeWriter.h @@ -21,7 +21,7 @@ #include "pxr/pxr.h" #include "usdMaya/primWriter.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/usd/sdf/path.h" diff --git a/plugin/pxr/maya/lib/usdMaya/jobArgs.h b/plugin/pxr/maya/lib/usdMaya/jobArgs.h index 4688726b62..f50bbc3e33 100644 --- a/plugin/pxr/maya/lib/usdMaya/jobArgs.h +++ b/plugin/pxr/maya/lib/usdMaya/jobArgs.h @@ -19,7 +19,7 @@ /// \file usdMaya/jobArgs.h #include "usdMaya/api.h" -#include "usdMaya/util.h" +#include #include "pxr/pxr.h" diff --git a/plugin/pxr/maya/lib/usdMaya/pointBasedDeformerNode.cpp b/plugin/pxr/maya/lib/usdMaya/pointBasedDeformerNode.cpp index c96b50a08b..f1c5e40b57 100644 --- a/plugin/pxr/maya/lib/usdMaya/pointBasedDeformerNode.cpp +++ b/plugin/pxr/maya/lib/usdMaya/pointBasedDeformerNode.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/pointBasedDeformerNode.h" -#include "usdMaya/stageData.h" +#include #include "pxr/base/gf/math.h" #include "pxr/base/gf/vec3f.h" @@ -88,7 +88,7 @@ UsdMayaPointBasedDeformerNode::initialize() inUsdStageAttr = typedAttrFn.create("inUsdStage", "is", - UsdMayaStageData::mayaTypeId, + MayaUsdStageData::mayaTypeId, MObject::kNullObj, &status); CHECK_MSTATUS_AND_RETURN_IT(status); @@ -149,8 +149,8 @@ UsdMayaPointBasedDeformerNode::deform( block.inputValue(inUsdStageAttr, &status); CHECK_MSTATUS_AND_RETURN_IT(status); - UsdMayaStageData* stageData = - dynamic_cast(inUsdStageHandle.asPluginData()); + MayaUsdStageData* stageData = + dynamic_cast(inUsdStageHandle.asPluginData()); if (!stageData || !stageData->stage) { return MS::kFailure; } diff --git a/plugin/pxr/maya/lib/usdMaya/primReaderRegistry.cpp b/plugin/pxr/maya/lib/usdMaya/primReaderRegistry.cpp index 1e6e216247..343591e2f1 100644 --- a/plugin/pxr/maya/lib/usdMaya/primReaderRegistry.cpp +++ b/plugin/pxr/maya/lib/usdMaya/primReaderRegistry.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/primReaderRegistry.h" -#include "usdMaya/debugCodes.h" +#include #include "usdMaya/fallbackPrimReader.h" #include "usdMaya/functorPrimReader.h" #include "usdMaya/registryHelper.h" diff --git a/plugin/pxr/maya/lib/usdMaya/primWriter.cpp b/plugin/pxr/maya/lib/usdMaya/primWriter.cpp index da1e12ae09..818855db96 100644 --- a/plugin/pxr/maya/lib/usdMaya/primWriter.cpp +++ b/plugin/pxr/maya/lib/usdMaya/primWriter.cpp @@ -19,7 +19,7 @@ #include "usdMaya/adaptor.h" #include "usdMaya/jobArgs.h" #include "usdMaya/translatorGprim.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "usdMaya/writeUtil.h" diff --git a/plugin/pxr/maya/lib/usdMaya/primWriter.h b/plugin/pxr/maya/lib/usdMaya/primWriter.h index 37a573f936..8fdc9ba893 100644 --- a/plugin/pxr/maya/lib/usdMaya/primWriter.h +++ b/plugin/pxr/maya/lib/usdMaya/primWriter.h @@ -22,7 +22,7 @@ #include "usdMaya/api.h" #include "usdMaya/jobArgs.h" -#include "usdMaya/util.h" +#include #include "pxr/base/vt/value.h" #include "pxr/usd/sdf/path.h" diff --git a/plugin/pxr/maya/lib/usdMaya/primWriterRegistry.cpp b/plugin/pxr/maya/lib/usdMaya/primWriterRegistry.cpp index fc0b8a1a8d..e2fd8c52ef 100644 --- a/plugin/pxr/maya/lib/usdMaya/primWriterRegistry.cpp +++ b/plugin/pxr/maya/lib/usdMaya/primWriterRegistry.cpp @@ -16,7 +16,7 @@ #include "pxr/pxr.h" #include "usdMaya/primWriterRegistry.h" -#include "usdMaya/debugCodes.h" +#include #include "usdMaya/functorPrimWriter.h" #include "usdMaya/registryHelper.h" diff --git a/plugin/pxr/maya/lib/usdMaya/proxyShape.cpp b/plugin/pxr/maya/lib/usdMaya/proxyShape.cpp index 788697248c..b6f19e5b75 100644 --- a/plugin/pxr/maya/lib/usdMaya/proxyShape.cpp +++ b/plugin/pxr/maya/lib/usdMaya/proxyShape.cpp @@ -16,10 +16,11 @@ #include "usdMaya/proxyShape.h" #include "usdMaya/hdImagingShape.h" -#include "usdMaya/query.h" -#include "usdMaya/stageCache.h" -#include "usdMaya/stageData.h" -#include "usdMaya/util.h" +#include +#include +#include +#include +#include #include "pxr/base/gf/bbox3d.h" #include "pxr/base/gf/range3d.h" @@ -76,7 +77,6 @@ #include #include - PXR_NAMESPACE_OPEN_SCOPE @@ -91,11 +91,8 @@ TF_DEFINE_PUBLIC_TOKENS(UsdMayaProxyShapeTokens, TF_DEFINE_ENV_SETTING(PIXMAYA_ENABLE_BOUNDING_BOX_MODE, false, "Enable bounding box rendering (slows refresh rate)"); -UsdMayaProxyShape::ClosestPointDelegate -UsdMayaProxyShape::_sharedClosestPointDelegate = nullptr; - -UsdMayaProxyShape::ObjectSoftSelectEnabledDelgate -UsdMayaProxyShape::_sharedObjectSoftSelectEnabledDelgate = nullptr; +UsdMayaProxyShape::ObjectSoftSelectEnabledDelegate +UsdMayaProxyShape::_sharedObjectSoftSelectEnabledDelegate = nullptr; // ======================================================== @@ -104,25 +101,9 @@ const MTypeId UsdMayaProxyShape::typeId(0x0010A259); const MString UsdMayaProxyShape::typeName( UsdMayaProxyShapeTokens->MayaTypeName.GetText()); -const MString UsdMayaProxyShape::displayFilterName( - TfStringPrintf("%sDisplayFilter", - UsdMayaProxyShapeTokens->MayaTypeName.GetText()).c_str()); -const MString UsdMayaProxyShape::displayFilterLabel("USD Proxies"); - // Attributes -MObject UsdMayaProxyShape::filePathAttr; -MObject UsdMayaProxyShape::primPathAttr; -MObject UsdMayaProxyShape::excludePrimPathsAttr; -MObject UsdMayaProxyShape::timeAttr; MObject UsdMayaProxyShape::variantKeyAttr; -MObject UsdMayaProxyShape::complexityAttr; -MObject UsdMayaProxyShape::inStageDataAttr; -MObject UsdMayaProxyShape::inStageDataCachedAttr; MObject UsdMayaProxyShape::fastPlaybackAttr; -MObject UsdMayaProxyShape::outStageDataAttr; -MObject UsdMayaProxyShape::drawRenderPurposeAttr; -MObject UsdMayaProxyShape::drawProxyPurposeAttr; -MObject UsdMayaProxyShape::drawGuidePurposeAttr; MObject UsdMayaProxyShape::softSelectableAttr; @@ -137,61 +118,14 @@ UsdMayaProxyShape::creator() MStatus UsdMayaProxyShape::initialize() { - MStatus retValue = MS::kSuccess; + MStatus retValue = inheritAttributesFrom(MayaUsdProxyShapeBase::typeName); + CHECK_MSTATUS_AND_RETURN_IT(retValue); // // create attr factories // - MFnCompoundAttribute compoundAttrFn; - MFnEnumAttribute enumAttrFn; MFnNumericAttribute numericAttrFn; MFnTypedAttribute typedAttrFn; - MFnUnitAttribute unitAttrFn; - - filePathAttr = typedAttrFn.create( - "filePath", - "fp", - MFnData::kString, - MObject::kNullObj, - &retValue); - typedAttrFn.setReadable(false); - typedAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(filePathAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - primPathAttr = typedAttrFn.create( - "primPath", - "pp", - MFnData::kString, - MObject::kNullObj, - &retValue); - typedAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(primPathAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - excludePrimPathsAttr = typedAttrFn.create( - "excludePrimPaths", - "epp", - MFnData::kString, - MObject::kNullObj, - &retValue); - typedAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(excludePrimPathsAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - timeAttr = unitAttrFn.create( - "time", - "tm", - MFnUnitAttribute::kTime, - 0.0, - &retValue); - unitAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(timeAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); variantKeyAttr = typedAttrFn.create( "variantKey", @@ -205,50 +139,6 @@ UsdMayaProxyShape::initialize() retValue = addAttribute(variantKeyAttr); CHECK_MSTATUS_AND_RETURN_IT(retValue); - complexityAttr = numericAttrFn.create( - "complexity", - "cplx", - MFnNumericData::kInt, - 0, - &retValue); - numericAttrFn.setMin(0); - numericAttrFn.setSoftMax(4); - numericAttrFn.setMax(8); - numericAttrFn.setChannelBox(true); - numericAttrFn.setStorable(false); - numericAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(complexityAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - inStageDataAttr = typedAttrFn.create( - "inStageData", - "id", - UsdMayaStageData::mayaTypeId, - MObject::kNullObj, - &retValue); - typedAttrFn.setReadable(false); - typedAttrFn.setStorable(false); - typedAttrFn.setDisconnectBehavior(MFnNumericAttribute::kReset); // on disconnect, reset to Null - typedAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(inStageDataAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - // inStageData or filepath-> inStageDataCached -> outStageData - inStageDataCachedAttr = typedAttrFn.create( - "inStageDataCached", - "idc", - UsdMayaStageData::mayaTypeId, - MObject::kNullObj, - &retValue); - typedAttrFn.setStorable(false); - typedAttrFn.setWritable(false); - typedAttrFn.setAffectsAppearance(true); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(inStageDataCachedAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - fastPlaybackAttr = numericAttrFn.create( "fastPlayback", "fs", @@ -261,57 +151,6 @@ UsdMayaProxyShape::initialize() retValue = addAttribute(fastPlaybackAttr); CHECK_MSTATUS_AND_RETURN_IT(retValue); - outStageDataAttr = typedAttrFn.create( - "outStageData", - "od", - UsdMayaStageData::mayaTypeId, - MObject::kNullObj, - &retValue); - typedAttrFn.setStorable(false); - typedAttrFn.setWritable(false); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - retValue = addAttribute(outStageDataAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - drawRenderPurposeAttr = numericAttrFn.create( - "drawRenderPurpose", - "drp", - MFnNumericData::kBoolean, - 0.0, - &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - numericAttrFn.setKeyable(true); - numericAttrFn.setReadable(false); - numericAttrFn.setAffectsAppearance(true); - retValue = addAttribute(drawRenderPurposeAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - drawProxyPurposeAttr = numericAttrFn.create( - "drawProxyPurpose", - "dpp", - MFnNumericData::kBoolean, - 1.0, - &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - numericAttrFn.setKeyable(true); - numericAttrFn.setReadable(false); - numericAttrFn.setAffectsAppearance(true); - retValue = addAttribute(drawProxyPurposeAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - drawGuidePurposeAttr = numericAttrFn.create( - "drawGuidePurpose", - "dgp", - MFnNumericData::kBoolean, - 0.0, - &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - numericAttrFn.setKeyable(true); - numericAttrFn.setReadable(false); - numericAttrFn.setAffectsAppearance(true); - retValue = addAttribute(drawGuidePurposeAttr); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - softSelectableAttr = numericAttrFn.create( "softSelectable", "softSelectable", @@ -326,162 +165,43 @@ UsdMayaProxyShape::initialize() // // add attribute dependencies // - retValue = attributeAffects(filePathAttr, inStageDataCachedAttr); - retValue = attributeAffects(filePathAttr, outStageDataAttr); - - retValue = attributeAffects(primPathAttr, inStageDataCachedAttr); - retValue = attributeAffects(primPathAttr, outStageDataAttr); - retValue = attributeAffects(variantKeyAttr, inStageDataCachedAttr); retValue = attributeAffects(variantKeyAttr, outStageDataAttr); - retValue = attributeAffects(inStageDataAttr, inStageDataCachedAttr); - retValue = attributeAffects(inStageDataAttr, outStageDataAttr); - - retValue = attributeAffects(inStageDataCachedAttr, outStageDataAttr); - return retValue; } -/* static */ -UsdMayaProxyShape* -UsdMayaProxyShape::GetShapeAtDagPath(const MDagPath& dagPath) -{ - MObject mObj = dagPath.node(); - if (mObj.apiType() != MFn::kPluginShape) { - TF_CODING_ERROR( - "Could not get UsdMayaProxyShape for non-plugin shape node " - "at DAG path: %s (apiTypeStr = %s)", - dagPath.fullPathName().asChar(), - mObj.apiTypeStr()); - return nullptr; - } - - const MFnDependencyNode depNodeFn(mObj); - UsdMayaProxyShape* pShape = - static_cast(depNodeFn.userNode()); - if (!pShape) { - TF_CODING_ERROR( - "Could not get UsdMayaProxyShape for node at DAG path: %s", - dagPath.fullPathName().asChar()); - return nullptr; - } - - return pShape; -} - -/* static */ -void -UsdMayaProxyShape::SetClosestPointDelegate(ClosestPointDelegate delegate) -{ - _sharedClosestPointDelegate = delegate; -} - /* static */ void UsdMayaProxyShape::SetObjectSoftSelectEnabledDelegate( - ObjectSoftSelectEnabledDelgate delegate) + ObjectSoftSelectEnabledDelegate delegate) { - _sharedObjectSoftSelectEnabledDelgate = delegate; + _sharedObjectSoftSelectEnabledDelegate = delegate; } -/* static */ +/* virtual */ bool -UsdMayaProxyShape::GetObjectSoftSelectEnabled() +UsdMayaProxyShape::GetObjectSoftSelectEnabled() const { // If the delegate isn't set, we just assume soft select isn't currently // enabled - this will mean that the object is selectable in VP2, by default - if (!_sharedObjectSoftSelectEnabledDelgate) { + if (!_sharedObjectSoftSelectEnabledDelegate) { return false; } - return _sharedObjectSoftSelectEnabledDelgate(); -} - -/* virtual */ -void -UsdMayaProxyShape::postConstructor() -{ - setRenderable(true); - - // This shape uses Hydra for imaging, so make sure that the - // pxrHdImagingShape is setup. - PxrMayaHdImagingShape::GetOrCreateInstance(); + return _sharedObjectSoftSelectEnabledDelegate(); } -/* virtual */ -MStatus -UsdMayaProxyShape::compute(const MPlug& plug, MDataBlock& dataBlock) -{ - if (plug == excludePrimPathsAttr || - plug == timeAttr || - plug == complexityAttr || - plug == drawRenderPurposeAttr || - plug == drawProxyPurposeAttr || - plug == drawGuidePurposeAttr) { - // If the attribute that needs to be computed is one of these, then it - // does not affect the ouput stage data, but it *does* affect imaging - // the shape. In that case, we notify Maya that the shape needs to be - // redrawn and let it take care of computing the attribute. This covers - // the case where an attribute on the proxy shape may have an incoming - // connection from another node (e.g. "time1.outTime" being connected - // to the proxy shape's "time" attribute). In that case, - // setDependentsDirty() might not get called and only compute() might. - MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); - return MS::kUnknownParameter; - } - else if (plug == inStageDataCachedAttr) { - return computeInStageDataCached(dataBlock); - } - else if (plug == outStageDataAttr) { - return computeOutStageData(dataBlock); - } - - return MS::kUnknownParameter; -} - -MStatus -UsdMayaProxyShape::computeInStageDataCached(MDataBlock& dataBlock) +SdfLayerRefPtr +UsdMayaProxyShape::computeSessionLayer(MDataBlock& dataBlock) { MStatus retValue = MS::kSuccess; - MDataHandle inDataHandle = dataBlock.inputValue(inStageDataAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - // If inData has an incoming connection, then use it. Otherwise generate stage from the filepath - if (!inDataHandle.data().isNull() ) { - // - // Propagate inData -> inDataCached - // - MDataHandle inDataCachedHandle = dataBlock.outputValue(inStageDataCachedAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - inDataCachedHandle.copy(inDataHandle); - - inDataCachedHandle.setClean(); - return MS::kSuccess; - } - else { - // - // Calculate from USD filepath and primPath and variantKey - // - - // Get input attr values - const MString file = dataBlock.inputValue(filePathAttr, &retValue).asString(); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - // - // let the usd stage cache deal with caching the usd stage data - // - std::string fileString = TfStringTrimRight(file.asChar()); - - // == Load the Stage - UsdStageRefPtr usdStage; - SdfPath primPath; - // get the variantKey MDataHandle variantKeyHandle = dataBlock.inputValue(variantKeyAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); + if (retValue != MS::kSuccess) { + return nullptr; + } const MString variantKey = variantKeyHandle.asString(); SdfLayerRefPtr sessionLayer; @@ -494,7 +214,9 @@ UsdMayaProxyShape::computeInStageDataCached(MDataBlock& dataBlock) // Get the primPath const MString primPathMString = dataBlock.inputValue(primPathAttr, &retValue).asString(); - CHECK_MSTATUS_AND_RETURN_IT(retValue); + if (retValue != MS::kSuccess) { + return nullptr; + } std::vector primPathEltStrs = TfStringTokenize(primPathMString.asChar(),"/"); @@ -505,145 +227,7 @@ UsdMayaProxyShape::computeInStageDataCached(MDataBlock& dataBlock) } } - if (SdfLayerRefPtr rootLayer = SdfLayer::FindOrOpen(fileString)) { - UsdStageCacheContext ctx(UsdMayaStageCache::Get()); - if (sessionLayer) { - usdStage = UsdStage::Open(rootLayer, - sessionLayer, - ArGetResolver().GetCurrentContext()); - } else { - usdStage = UsdStage::Open(rootLayer, - ArGetResolver().GetCurrentContext()); - } - - usdStage->SetEditTarget(usdStage->GetSessionLayer()); - } - - if (usdStage) { - primPath = usdStage->GetPseudoRoot().GetPath(); - } - - // Create the output outData ======== - MFnPluginData pluginDataFn; - MObject stageDataObj = - pluginDataFn.create(UsdMayaStageData::mayaTypeId, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - UsdMayaStageData* stageData = - reinterpret_cast(pluginDataFn.data(&retValue)); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - // Set the outUsdStageData - stageData->stage = usdStage; - stageData->primPath = primPath; - - // - // set the data on the output plug - // - MDataHandle inDataCachedHandle = - dataBlock.outputValue(inStageDataCachedAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - inDataCachedHandle.set(stageData); - inDataCachedHandle.setClean(); - return MS::kSuccess; - } -} - -MStatus -UsdMayaProxyShape::computeOutStageData(MDataBlock& dataBlock) -{ - MStatus retValue = MS::kSuccess; - - TfReset(_boundingBoxCache); - - // Reset the stage listener until we determine that everything is valid. - _stageNoticeListener.SetStage(UsdStageWeakPtr()); - _stageNoticeListener.SetStageContentsChangedCallback(nullptr); - - MDataHandle inDataCachedHandle = - dataBlock.inputValue(inStageDataCachedAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - UsdStageRefPtr usdStage; - - UsdMayaStageData* inData = - dynamic_cast(inDataCachedHandle.asPluginData()); - if(inData) - { - usdStage = inData->stage; - } - - // If failed to get a valid stage, then - // Propagate inDataCached -> outData - // and return - if (!usdStage) { - MDataHandle outDataHandle = dataBlock.outputValue(outStageDataAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - outDataHandle.copy(inDataCachedHandle); - return MS::kSuccess; - } - - // Get the primPath - const MString primPath = dataBlock.inputValue(primPathAttr, &retValue).asString(); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - // Get the prim - // If no primPath string specified, then use the pseudo-root. - UsdPrim usdPrim; - std::string primPathStr = primPath.asChar(); - if ( !primPathStr.empty() ) { - SdfPath primPath(primPathStr); - - // Validate assumption: primPath is descendent of passed-in stage primPath - // Make sure that the primPath is a child of the passed in stage's primpath - if ( primPath.HasPrefix(inData->primPath) ) { - usdPrim = usdStage->GetPrimAtPath( primPath ); - } - else { - TF_WARN("%s: Shape primPath <%s> is not a descendant of input " - "stage primPath <%s>", - MPxSurfaceShape::name().asChar(), - primPath.GetText(), - inData->primPath.GetText()); - } - } else { - usdPrim = usdStage->GetPseudoRoot(); - } - - // Create the output outData - MFnPluginData pluginDataFn; - MObject stageDataObj = - pluginDataFn.create(UsdMayaStageData::mayaTypeId, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - UsdMayaStageData* stageData = - reinterpret_cast(pluginDataFn.data(&retValue)); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - // Set the outUsdStageData - stageData->stage = usdStage; - stageData->primPath = usdPrim ? usdPrim.GetPath() : - usdStage->GetPseudoRoot().GetPath(); - - // - // set the data on the output plug - // - MDataHandle outDataHandle = - dataBlock.outputValue(outStageDataAttr, &retValue); - CHECK_MSTATUS_AND_RETURN_IT(retValue); - - outDataHandle.set(stageData); - outDataHandle.setClean(); - - // Start listening for notices for the USD stage. - _stageNoticeListener.SetStage(usdStage); - _stageNoticeListener.SetStageContentsChangedCallback( - std::bind(&UsdMayaProxyShape::_OnStageContentsChanged, - this, - std::placeholders::_1)); - - return MS::kSuccess; + return sessionLayer; } /* virtual */ @@ -651,7 +235,8 @@ bool UsdMayaProxyShape::isBounded() const { return !_useFastPlayback && - TfGetEnvSetting(PIXMAYA_ENABLE_BOUNDING_BOX_MODE)&& isStageValid(); + TfGetEnvSetting(PIXMAYA_ENABLE_BOUNDING_BOX_MODE) && + ParentClass::isBounded(); } /* virtual */ @@ -662,102 +247,7 @@ UsdMayaProxyShape::boundingBox() const return UsdMayaUtil::GetInfiniteBoundingBox(); } - MStatus status; - - // Make sure outStage is up to date - UsdMayaProxyShape* nonConstThis = const_cast(this); - MDataBlock dataBlock = nonConstThis->forceCache(); - dataBlock.inputValue(outStageDataAttr, &status); - CHECK_MSTATUS_AND_RETURN(status, MBoundingBox()); - - // XXX: - // If we could cheaply determine whether a stage only has static geometry, - // we could make this value a constant one for that case, avoiding the - // memory overhead of a cache entry per frame - MDataHandle timeHandle = dataBlock.inputValue(timeAttr, &status); - UsdTimeCode currTime = UsdTimeCode(timeHandle.asTime().value()); - - std::map::const_iterator cacheLookup = - _boundingBoxCache.find(currTime); - - if (cacheLookup != _boundingBoxCache.end()) { - return cacheLookup->second; - } - - UsdPrim prim = usdPrim(); - if (!prim) { - return MBoundingBox(); - } - - const UsdGeomImageable imageablePrim(prim); - - bool drawRenderPurpose = false; - bool drawProxyPurpose = true; - bool drawGuidePurpose = false; - _GetDrawPurposeToggles( - dataBlock, - &drawRenderPurpose, - &drawProxyPurpose, - &drawGuidePurpose); - - const TfToken purpose1 = UsdGeomTokens->default_; - const TfToken purpose2 = - drawRenderPurpose ? UsdGeomTokens->render : TfToken(); - const TfToken purpose3 = - drawProxyPurpose ? UsdGeomTokens->proxy : TfToken(); - const TfToken purpose4 = - drawGuidePurpose ? UsdGeomTokens->guide : TfToken(); - - const GfBBox3d allBox = imageablePrim.ComputeUntransformedBound( - currTime, - purpose1, - purpose2, - purpose3, - purpose4); - - MBoundingBox& retval = nonConstThis->_boundingBoxCache[currTime]; - - const GfRange3d boxRange = allBox.ComputeAlignedBox(); - if (!boxRange.IsEmpty()) { - const GfVec3d boxMin = boxRange.GetMin(); - const GfVec3d boxMax = boxRange.GetMax(); - retval = MBoundingBox( - MPoint(boxMin[0], boxMin[1], boxMin[2]), - MPoint(boxMax[0], boxMax[1], boxMax[2])); - } - - return retval; -} - -bool -UsdMayaProxyShape::isStageValid() const -{ - MStatus localStatus; - UsdMayaProxyShape* nonConstThis = const_cast(this); - MDataBlock dataBlock = nonConstThis->forceCache(); - - MDataHandle outDataHandle = dataBlock.inputValue(outStageDataAttr, &localStatus); - CHECK_MSTATUS_AND_RETURN(localStatus, false); - - UsdMayaStageData* outData = - dynamic_cast(outDataHandle.asPluginData()); - if(!outData || !outData->stage) { - return false; - } - - return true; -} - -/* virtual */ -MStatus -UsdMayaProxyShape::setDependentsDirty(const MPlug& plug, MPlugArray& plugArray) -{ - // If/when the MPxDrawOverride for the proxy shape specifies - // isAlwaysDirty=false to improve performance, we must be sure to notify - // the Maya renderer that the geometry is dirty and needs to be redrawn - // when any plug on the proxy shape is dirtied. - MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); - return MPxSurfaceShape::setDependentsDirty(plug, plugArray); + return ParentClass::boundingBox(); } /* virtual */ @@ -790,159 +280,8 @@ UsdMayaProxyShape::getInternalValueInContext( return MPxSurfaceShape::getInternalValueInContext(plug, dataHandle, ctx); } -/* virtual */ -UsdPrim -UsdMayaProxyShape::usdPrim() const -{ - return _GetUsdPrim( const_cast(this)->forceCache() ); -} - -UsdPrim -UsdMayaProxyShape::_GetUsdPrim(MDataBlock dataBlock) const -{ - MStatus localStatus; - UsdPrim usdPrim; - - MDataHandle outDataHandle = - dataBlock.inputValue(outStageDataAttr, &localStatus); - CHECK_MSTATUS_AND_RETURN(localStatus, usdPrim); - - UsdMayaStageData* outData = dynamic_cast(outDataHandle.asPluginData()); - if(!outData) { - return usdPrim; // empty UsdPrim - } - - if(!outData->stage) { - return usdPrim; // empty UsdPrim - } - - usdPrim = (outData->primPath.IsEmpty()) ? - outData->stage->GetPseudoRoot() : - outData->stage->GetPrimAtPath(outData->primPath); - - return usdPrim; -} - -int -UsdMayaProxyShape::getComplexity() const -{ - return _GetComplexity( const_cast(this)->forceCache() ); -} - -int -UsdMayaProxyShape::_GetComplexity(MDataBlock dataBlock) const -{ - int complexity = 0; - MStatus status; - - complexity = dataBlock.inputValue(complexityAttr, &status).asInt(); - - return complexity; -} - -UsdTimeCode -UsdMayaProxyShape::getTime() const -{ - return _GetTime( const_cast(this)->forceCache() ); -} - -UsdTimeCode -UsdMayaProxyShape::_GetTime(MDataBlock dataBlock) const -{ - MStatus status; - - return UsdTimeCode(dataBlock.inputValue(timeAttr, &status).asTime().value()); -} - -SdfPathVector -UsdMayaProxyShape::getExcludePrimPaths() const -{ - return _GetExcludePrimPaths( const_cast(this)->forceCache() ); -} - -SdfPathVector -UsdMayaProxyShape::_GetExcludePrimPaths(MDataBlock dataBlock) const -{ - SdfPathVector ret; - - const MString excludePrimPathsStr = - dataBlock.inputValue(excludePrimPathsAttr).asString(); - std::vector excludePrimPaths = - TfStringTokenize(excludePrimPathsStr.asChar(), ","); - ret.resize(excludePrimPaths.size()); - for (size_t i = 0; i < excludePrimPaths.size(); ++i) { - ret[i] = SdfPath(TfStringTrim(excludePrimPaths[i])); - } - - return ret; -} - -bool -UsdMayaProxyShape::_GetDrawPurposeToggles( - MDataBlock dataBlock, - bool* drawRenderPurpose, - bool* drawProxyPurpose, - bool* drawGuidePurpose) const -{ - MStatus status; - - MDataHandle drawRenderPurposeHandle = - dataBlock.inputValue(drawRenderPurposeAttr, &status); - CHECK_MSTATUS_AND_RETURN(status, false); - - MDataHandle drawProxyPurposeHandle = - dataBlock.inputValue(drawProxyPurposeAttr, &status); - CHECK_MSTATUS_AND_RETURN(status, false); - - MDataHandle drawGuidePurposeHandle = - dataBlock.inputValue(drawGuidePurposeAttr, &status); - CHECK_MSTATUS_AND_RETURN(status, false); - - if (drawRenderPurpose) { - *drawRenderPurpose = drawRenderPurposeHandle.asBool(); - } - if (drawProxyPurpose) { - *drawProxyPurpose = drawProxyPurposeHandle.asBool(); - } - if (drawGuidePurpose) { - *drawGuidePurpose = drawGuidePurposeHandle.asBool(); - } - - return true; -} - -bool -UsdMayaProxyShape::GetAllRenderAttributes( - UsdPrim* usdPrimOut, - SdfPathVector* excludePrimPathsOut, - int* complexityOut, - UsdTimeCode* timeOut, - bool* drawRenderPurpose, - bool* drawProxyPurpose, - bool* drawGuidePurpose) -{ - MDataBlock dataBlock = forceCache(); - - *usdPrimOut = _GetUsdPrim(dataBlock); - if (!usdPrimOut->IsValid()) { - return false; - } - - *excludePrimPathsOut = _GetExcludePrimPaths(dataBlock); - *complexityOut = _GetComplexity(dataBlock); - *timeOut = _GetTime(dataBlock); - - _GetDrawPurposeToggles( - dataBlock, - drawRenderPurpose, - drawProxyPurpose, - drawGuidePurpose); - - return true; -} - UsdMayaProxyShape::UsdMayaProxyShape() : - MPxSurfaceShape(), + MayaUsdProxyShapeBase(), _useFastPlayback(false) { TfRegistryManager::GetInstance().SubscribeTo(); @@ -956,36 +295,8 @@ UsdMayaProxyShape::~UsdMayaProxyShape() // } -MSelectionMask -UsdMayaProxyShape::getShapeSelectionMask() const -{ - // The intent of this function is to control whether this object is - // selectable at all in VP2 - - // However, due to a bug / quirk, it could be used to specifically control - // whether the object was SOFT-selectable if you were using - // MAYA_VP2_USE_VP1_SELECTON; in this mode, this setting is NOT querierd - // when doing "normal" selection, but IS queried when doing soft - // selection. - - // Unfortunately, it is queried for both "normal" selection AND soft - // selection if you are using "true" VP2 selection. So in order to - // control soft selection, in both modes, we keep track of whether - // we currently have object soft-select enabled, and then return an empty - // selection mask if it is, but this object is set to be non-soft-selectable - - static const MSelectionMask emptyMask; - static const MSelectionMask normalMask(MSelectionMask::kSelectMeshes); - - if (GetObjectSoftSelectEnabled() && !_CanBeSoftSelected()) { - // Disable selection, to disable soft-selection - return emptyMask; - } - return normalMask; -} - bool -UsdMayaProxyShape::_CanBeSoftSelected() const +UsdMayaProxyShape::canBeSoftSelected() const { UsdMayaProxyShape* nonConstThis = const_cast(this); MDataBlock dataBlock = nonConstThis->forceCache(); @@ -999,42 +310,16 @@ UsdMayaProxyShape::_CanBeSoftSelected() const return softSelHandle.asBool(); } -void -UsdMayaProxyShape::_OnStageContentsChanged( - const UsdNotice::StageContentsChanged& notice) +void UsdMayaProxyShape::postConstructor() { - // If the USD stage this proxy represents changes without Maya's knowledge, - // we need to inform Maya that the shape is dirty and needs to be redrawn. - MHWRender::MRenderer::setGeometryDrawDirty(thisMObject()); -} + ParentClass::postConstructor(); -bool -UsdMayaProxyShape::closestPoint( - const MPoint& raySource, - const MVector& rayDirection, - MPoint& theClosestPoint, - MVector& theClosestNormal, - bool /*findClosestOnMiss*/, - double /*tolerance*/) -{ - if (_sharedClosestPointDelegate) { - GfRay ray( - GfVec3d(raySource.x, raySource.y, raySource.z), - GfVec3d(rayDirection.x, rayDirection.y, rayDirection.z)); - GfVec3d hitPoint; - GfVec3d hitNorm; - if (_sharedClosestPointDelegate(*this, ray, &hitPoint, &hitNorm)) { - theClosestPoint = MPoint(hitPoint[0], hitPoint[1], hitPoint[2]); - theClosestNormal = MVector(hitNorm[0], hitNorm[1], hitNorm[2]); - return true; - } + if (!MayaUsdProxyShapePlugin::useVP2_NativeUSD_Rendering()) + { + // This shape uses Hydra for imaging, so make sure that the + // pxrHdImagingShape is setup. + PxrMayaHdImagingShape::GetOrCreateInstance(); } - - return false; -} - -bool UsdMayaProxyShape::canMakeLive() const { - return (bool) _sharedClosestPointDelegate; } diff --git a/plugin/pxr/maya/lib/usdMaya/proxyShape.h b/plugin/pxr/maya/lib/usdMaya/proxyShape.h index 47f0142001..27910b4eab 100644 --- a/plugin/pxr/maya/lib/usdMaya/proxyShape.h +++ b/plugin/pxr/maya/lib/usdMaya/proxyShape.h @@ -19,12 +19,10 @@ /// \file usdMaya/proxyShape.h #include "usdMaya/api.h" -#include "usdMaya/stageNoticeListener.h" -#include "usdMaya/usdPrimProvider.h" +#include #include "pxr/pxr.h" -#include "pxr/base/gf/ray.h" #include "pxr/base/gf/vec3d.h" #include "pxr/base/tf/staticTokens.h" @@ -61,64 +59,26 @@ TF_DECLARE_PUBLIC_TOKENS(UsdMayaProxyShapeTokens, PXRUSDMAYA_PROXY_SHAPE_TOKENS); -class UsdMayaProxyShape : public MPxSurfaceShape, - public UsdMayaUsdPrimProvider +class UsdMayaProxyShape : public MayaUsdProxyShapeBase { public: + typedef MayaUsdProxyShapeBase ParentClass; + PXRUSDMAYA_API static const MTypeId typeId; PXRUSDMAYA_API static const MString typeName; - PXRUSDMAYA_API - static const MString displayFilterName; - PXRUSDMAYA_API - static const MString displayFilterLabel; - - // Attributes - PXRUSDMAYA_API - static MObject filePathAttr; - PXRUSDMAYA_API - static MObject primPathAttr; - PXRUSDMAYA_API - static MObject excludePrimPathsAttr; - PXRUSDMAYA_API - static MObject timeAttr; PXRUSDMAYA_API static MObject variantKeyAttr; PXRUSDMAYA_API - static MObject complexityAttr; - PXRUSDMAYA_API - static MObject inStageDataAttr; - PXRUSDMAYA_API - static MObject inStageDataCachedAttr; - PXRUSDMAYA_API static MObject fastPlaybackAttr; - PXRUSDMAYA_API - static MObject outStageDataAttr; - PXRUSDMAYA_API - static MObject drawRenderPurposeAttr; - PXRUSDMAYA_API - static MObject drawProxyPurposeAttr; - PXRUSDMAYA_API - static MObject drawGuidePurposeAttr; - PXRUSDMAYA_API static MObject softSelectableAttr; - /// Delegate function for computing the closest point and surface normal - /// on the proxy shape to a given ray. - /// The input ray, output point, and output normal should be in the - /// proxy shape's local space. - /// Should return true if a point was found, and false otherwise. - /// (You could just treat this as a ray intersection and return true - /// if intersected, false if missed.) - typedef std::function ClosestPointDelegate; - /// Delegate function for returning whether object soft select mode is /// currently on - typedef std::function ObjectSoftSelectEnabledDelgate; + typedef std::function ObjectSoftSelectEnabledDelegate; PXRUSDMAYA_API static void* creator(); @@ -126,81 +86,18 @@ class UsdMayaProxyShape : public MPxSurfaceShape, PXRUSDMAYA_API static MStatus initialize(); - PXRUSDMAYA_API - static UsdMayaProxyShape* GetShapeAtDagPath(const MDagPath& dagPath); - - PXRUSDMAYA_API - static void SetClosestPointDelegate(ClosestPointDelegate delegate); - PXRUSDMAYA_API static void SetObjectSoftSelectEnabledDelegate( - ObjectSoftSelectEnabledDelgate delegate); - - PXRUSDMAYA_API - static bool GetObjectSoftSelectEnabled(); + ObjectSoftSelectEnabledDelegate delegate); // Virtual function overrides - PXRUSDMAYA_API - void postConstructor() override; - PXRUSDMAYA_API - MStatus compute( - const MPlug& plug, - MDataBlock& dataBlock) override; + PXRUSDMAYA_API bool isBounded() const override; PXRUSDMAYA_API MBoundingBox boundingBox() const override; - PXRUSDMAYA_API - MSelectionMask getShapeSelectionMask() const override; - - PXRUSDMAYA_API - bool closestPoint( - const MPoint& raySource, - const MVector& rayDirection, - MPoint& theClosestPoint, - MVector& theClosestNormal, - bool findClosestOnMiss, - double tolerance) override; - - PXRUSDMAYA_API - bool canMakeLive() const override; - - // UsdMayaUsdPrimProvider overrides: - /** - * accessor to get the usdprim - * - * This method pulls the usdstage data from outData, and will evaluate - * the dependencies necessary to do so. It should be called instead of - * pulling on the data directly. - */ - PXRUSDMAYA_API - UsdPrim usdPrim() const override; // Public functions - PXRUSDMAYA_API - SdfPathVector getExcludePrimPaths() const; - - PXRUSDMAYA_API - int getComplexity() const; - - PXRUSDMAYA_API - UsdTimeCode getTime() const; - - PXRUSDMAYA_API - bool GetAllRenderAttributes( - UsdPrim* usdPrimOut, - SdfPathVector* excludePrimPathsOut, - int* complexityOut, - UsdTimeCode* timeOut, - bool* drawRenderPurpose, - bool* drawProxyPurpose, - bool* drawGuidePurpose); - - PXRUSDMAYA_API - MStatus setDependentsDirty( - const MPlug& plug, - MPlugArray& plugArray) override; - PXRUSDMAYA_API bool setInternalValueInContext( const MPlug& plug, @@ -213,9 +110,18 @@ class UsdMayaProxyShape : public MPxSurfaceShape, MDataHandle& dataHandle, MDGContext& ctx) override; + void postConstructor() override; + protected: + // Use the variant key to get the session layer from the prim path. + PXRUSDMAYA_API + SdfLayerRefPtr computeSessionLayer(MDataBlock&) override; + + PXRUSDMAYA_API + bool canBeSoftSelected() const override; + PXRUSDMAYA_API - bool isStageValid() const; + bool GetObjectSoftSelectEnabled() const override; private: UsdMayaProxyShape(); @@ -224,34 +130,10 @@ class UsdMayaProxyShape : public MPxSurfaceShape, ~UsdMayaProxyShape() override; UsdMayaProxyShape& operator=(const UsdMayaProxyShape&); - MStatus computeInStageDataCached(MDataBlock& dataBlock); - MStatus computeOutStageData(MDataBlock& dataBlock); - - UsdPrim _GetUsdPrim(MDataBlock dataBlock) const; - SdfPathVector _GetExcludePrimPaths(MDataBlock dataBlock) const; - int _GetComplexity(MDataBlock dataBlock) const; - UsdTimeCode _GetTime(MDataBlock dataBlock) const; - - bool _GetDrawPurposeToggles( - MDataBlock dataBlock, - bool* drawRenderPurpose, - bool* drawProxyPurpose, - bool* drawGuidePurpose) const; - - bool _CanBeSoftSelected() const; - - void _OnStageContentsChanged( - const UsdNotice::StageContentsChanged& notice); - - UsdMayaStageNoticeListener _stageNoticeListener; - - std::map _boundingBoxCache; - bool _useFastPlayback; - static ClosestPointDelegate _sharedClosestPointDelegate; - static ObjectSoftSelectEnabledDelgate - _sharedObjectSoftSelectEnabledDelgate; + static ObjectSoftSelectEnabledDelegate + _sharedObjectSoftSelectEnabledDelegate; }; diff --git a/plugin/pxr/maya/lib/usdMaya/readJob.cpp b/plugin/pxr/maya/lib/usdMaya/readJob.cpp index e4734178cc..3504267a70 100644 --- a/plugin/pxr/maya/lib/usdMaya/readJob.cpp +++ b/plugin/pxr/maya/lib/usdMaya/readJob.cpp @@ -17,12 +17,12 @@ #include "usdMaya/primReaderRegistry.h" #include "usdMaya/shadingModeRegistry.h" -#include "usdMaya/stageCache.h" +#include #include "usdMaya/stageNode.h" #include "usdMaya/translatorMaterial.h" #include "usdMaya/translatorModelAssembly.h" #include "usdMaya/translatorXformable.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/token.h" diff --git a/plugin/pxr/maya/lib/usdMaya/readJob_ImportWithProxies.cpp b/plugin/pxr/maya/lib/usdMaya/readJob_ImportWithProxies.cpp index 81c3df2699..fbe3ab1185 100644 --- a/plugin/pxr/maya/lib/usdMaya/readJob_ImportWithProxies.cpp +++ b/plugin/pxr/maya/lib/usdMaya/readJob_ImportWithProxies.cpp @@ -18,7 +18,7 @@ #include "usdMaya/primReaderArgs.h" #include "usdMaya/primReaderContext.h" #include "usdMaya/primReaderRegistry.h" -#include "usdMaya/stageCache.h" +#include #include "usdMaya/translatorModelAssembly.h" #include "usdMaya/translatorUtil.h" diff --git a/plugin/pxr/maya/lib/usdMaya/readUtil.cpp b/plugin/pxr/maya/lib/usdMaya/readUtil.cpp index 67159e968e..fcb879e85f 100644 --- a/plugin/pxr/maya/lib/usdMaya/readUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/readUtil.cpp @@ -16,8 +16,8 @@ #include "usdMaya/readUtil.h" #include "usdMaya/adaptor.h" -#include "usdMaya/colorSpace.h" -#include "usdMaya/util.h" +#include +#include #include "pxr/base/gf/gamma.h" #include "pxr/base/gf/matrix4d.h" diff --git a/plugin/pxr/maya/lib/usdMaya/referenceAssembly.cpp b/plugin/pxr/maya/lib/usdMaya/referenceAssembly.cpp index 07de263900..950e686f50 100644 --- a/plugin/pxr/maya/lib/usdMaya/referenceAssembly.cpp +++ b/plugin/pxr/maya/lib/usdMaya/referenceAssembly.cpp @@ -17,12 +17,12 @@ #include "usdMaya/editUtil.h" #include "usdMaya/jobArgs.h" -#include "usdMaya/notice.h" +#include #include "usdMaya/proxyShape.h" -#include "usdMaya/query.h" +#include #include "usdMaya/readJob.h" -#include "usdMaya/stageCache.h" -#include "usdMaya/stageData.h" +#include +#include #include "pxr/base/tf/fileUtils.h" #include "pxr/base/tf/registryManager.h" @@ -176,7 +176,7 @@ UsdMayaReferenceAssembly::initialize() inStageDataAttr = typedAttrFn.create( "inStageData", "id", - UsdMayaStageData::mayaTypeId, + MayaUsdStageData::mayaTypeId, MObject::kNullObj, &status); CHECK_MSTATUS_AND_RETURN_IT(status); @@ -220,7 +220,7 @@ UsdMayaReferenceAssembly::initialize() inStageDataCachedAttr = typedAttrFn.create( "inStageDataCached", "idc", - UsdMayaStageData::mayaTypeId, + MayaUsdStageData::mayaTypeId, MObject::kNullObj, &status); CHECK_MSTATUS_AND_RETURN_IT(status); @@ -232,7 +232,7 @@ UsdMayaReferenceAssembly::initialize() outStageDataAttr = typedAttrFn.create( "outStageData", "od", - UsdMayaStageData::mayaTypeId, + MayaUsdStageData::mayaTypeId, MObject::kNullObj, &status); CHECK_MSTATUS_AND_RETURN_IT(status); @@ -749,7 +749,7 @@ UsdMayaReferenceAssembly::computeInStageDataCached(MDataBlock& dataBlock) // issue an error. (If fileString is empty, it just means that the // reference assembly hasn't been set up yet.) // We'll still return a success code from this function because we can - // provide Maya with a sane result (an empty UsdMayaStageData). + // provide Maya with a sane result (an empty MayaUsdStageData). if (!fileString.empty() && !usdStage) { TF_RUNTIME_ERROR( "Could not open USD stage with root layer '%s' for assembly %s", @@ -760,11 +760,11 @@ UsdMayaReferenceAssembly::computeInStageDataCached(MDataBlock& dataBlock) // Create the output outData ======== MFnPluginData pluginDataFn; MObject stageDataObj = - pluginDataFn.create(UsdMayaStageData::mayaTypeId, &retValue); + pluginDataFn.create(MayaUsdStageData::mayaTypeId, &retValue); CHECK_MSTATUS_AND_RETURN_IT(retValue); - UsdMayaStageData* stageData = - reinterpret_cast(pluginDataFn.data(&retValue)); + MayaUsdStageData* stageData = + reinterpret_cast(pluginDataFn.data(&retValue)); CHECK_MSTATUS_AND_RETURN_IT(retValue); // Set the outUsdStageData @@ -795,8 +795,8 @@ UsdMayaReferenceAssembly::computeOutStageData(MDataBlock& dataBlock) UsdStageRefPtr usdStage; - UsdMayaStageData* inData = - dynamic_cast(inDataCachedHandle.asPluginData()); + MayaUsdStageData* inData = + dynamic_cast(inDataCachedHandle.asPluginData()); if(inData) { usdStage = inData->stage; @@ -908,11 +908,11 @@ UsdMayaReferenceAssembly::computeOutStageData(MDataBlock& dataBlock) // Create the output outData MFnPluginData pluginDataFn; MObject stageDataObj = - pluginDataFn.create(UsdMayaStageData::mayaTypeId, &retValue); + pluginDataFn.create(MayaUsdStageData::mayaTypeId, &retValue); CHECK_MSTATUS_AND_RETURN_IT(retValue); - UsdMayaStageData* stageData = - reinterpret_cast(pluginDataFn.data(&retValue)); + MayaUsdStageData* stageData = + reinterpret_cast(pluginDataFn.data(&retValue)); CHECK_MSTATUS_AND_RETURN_IT(retValue); // Set the outUsdStageData @@ -1066,7 +1066,7 @@ UsdPrim UsdMayaReferenceAssembly::usdPrim() const MDataHandle outDataHandle = dataBlock.inputValue(outStageDataAttr, &status); CHECK_MSTATUS_AND_RETURN(status, usdPrim); - UsdMayaStageData* outData = dynamic_cast(outDataHandle.asPluginData()); + MayaUsdStageData* outData = dynamic_cast(outDataHandle.asPluginData()); if(!outData) { return usdPrim; // empty UsdPrim } diff --git a/plugin/pxr/maya/lib/usdMaya/referenceAssembly.h b/plugin/pxr/maya/lib/usdMaya/referenceAssembly.h index f5264a397f..ced6e9cb87 100644 --- a/plugin/pxr/maya/lib/usdMaya/referenceAssembly.h +++ b/plugin/pxr/maya/lib/usdMaya/referenceAssembly.h @@ -20,7 +20,7 @@ #include "usdMaya/api.h" #include "usdMaya/proxyShape.h" -#include "usdMaya/usdPrimProvider.h" +#include #include "pxr/pxr.h" diff --git a/plugin/pxr/maya/lib/usdMaya/registryHelper.cpp b/plugin/pxr/maya/lib/usdMaya/registryHelper.cpp index 56e5931fdd..f5d8cf94c1 100644 --- a/plugin/pxr/maya/lib/usdMaya/registryHelper.cpp +++ b/plugin/pxr/maya/lib/usdMaya/registryHelper.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/registryHelper.h" -#include "usdMaya/debugCodes.h" +#include #include "pxr/base/js/converter.h" #include "pxr/base/plug/plugin.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModeDisplayColor.cpp b/plugin/pxr/maya/lib/usdMaya/shadingModeDisplayColor.cpp index 601c777086..9c79682f9a 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModeDisplayColor.cpp +++ b/plugin/pxr/maya/lib/usdMaya/shadingModeDisplayColor.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#include "usdMaya/colorSpace.h" +#include #include "usdMaya/shadingModeExporter.h" #include "usdMaya/shadingModeExporterContext.h" #include "usdMaya/shadingModeRegistry.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.cpp b/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.cpp index 4e74e49bf0..0cb637b07f 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.cpp +++ b/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.cpp @@ -17,7 +17,7 @@ #include "usdMaya/jobArgs.h" #include "usdMaya/shadingModeExporterContext.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/tf/diagnostic.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.h b/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.h index 823fda83d0..3c902d8a29 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.h +++ b/plugin/pxr/maya/lib/usdMaya/shadingModeExporter.h @@ -21,7 +21,7 @@ #include "pxr/pxr.h" #include "usdMaya/api.h" #include "usdMaya/shadingModeExporterContext.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/usd/sdf/path.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.cpp b/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.cpp index 696f165a3c..f94302fccb 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.cpp +++ b/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.cpp @@ -16,7 +16,7 @@ #include "usdMaya/shadingModeExporterContext.h" #include "usdMaya/jobArgs.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/tf/diagnostic.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.h b/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.h index bb59ba8f33..f2e47cdaa9 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.h +++ b/plugin/pxr/maya/lib/usdMaya/shadingModeExporterContext.h @@ -21,7 +21,7 @@ #include "pxr/pxr.h" #include "usdMaya/api.h" #include "usdMaya/jobArgs.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/tf/token.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModePxrRis.cpp b/plugin/pxr/maya/lib/usdMaya/shadingModePxrRis.cpp index 92e6d122d1..a9fd84583c 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModePxrRis.cpp +++ b/plugin/pxr/maya/lib/usdMaya/shadingModePxrRis.cpp @@ -21,7 +21,7 @@ #include "usdMaya/shadingModePxrRis_rfm_map.h" #include "usdMaya/shadingModeRegistry.h" #include "usdMaya/translatorUtil.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeUtil.h" #include "pxr/pxr.h" diff --git a/plugin/pxr/maya/lib/usdMaya/shadingModeUseRegistry.cpp b/plugin/pxr/maya/lib/usdMaya/shadingModeUseRegistry.cpp index 5b6ca45fd3..7dce3c4a0a 100644 --- a/plugin/pxr/maya/lib/usdMaya/shadingModeUseRegistry.cpp +++ b/plugin/pxr/maya/lib/usdMaya/shadingModeUseRegistry.cpp @@ -20,7 +20,7 @@ #include "usdMaya/shadingModeExporterContext.h" #include "usdMaya/shadingModeRegistry.h" #include "usdMaya/shadingUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/token.h" diff --git a/plugin/pxr/maya/lib/usdMaya/skelBindingsProcessor.h b/plugin/pxr/maya/lib/usdMaya/skelBindingsProcessor.h index de787b3cf1..58897426e4 100644 --- a/plugin/pxr/maya/lib/usdMaya/skelBindingsProcessor.h +++ b/plugin/pxr/maya/lib/usdMaya/skelBindingsProcessor.h @@ -19,7 +19,7 @@ /// \file usdMaya/skelBindingsProcessor.h #include "usdMaya/api.h" -#include "usdMaya/util.h" +#include #include "pxr/pxr.h" #include "pxr/usd/sdf/path.h" diff --git a/plugin/pxr/maya/lib/usdMaya/stageData.h b/plugin/pxr/maya/lib/usdMaya/stageData.h deleted file mode 100644 index ac1a388614..0000000000 --- a/plugin/pxr/maya/lib/usdMaya/stageData.h +++ /dev/null @@ -1,108 +0,0 @@ -// -// Copyright 2016 Pixar -// -// 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. -// -#ifndef PXRUSDMAYA_STAGE_DATA_H -#define PXRUSDMAYA_STAGE_DATA_H - -/// \file usdMaya/stageData.h - -#include "usdMaya/api.h" - -#include "pxr/pxr.h" - -#include "pxr/base/tf/staticTokens.h" - -#include "pxr/usd/sdf/path.h" -#include "pxr/usd/usd/stage.h" - -#include -#include -#include -#include -#include - - -PXR_NAMESPACE_OPEN_SCOPE - - -#define PXRUSDMAYA_STAGE_DATA_TOKENS \ - ((MayaTypeName, "pxrUsdStageData")) - -TF_DECLARE_PUBLIC_TOKENS(UsdMayaStageDataTokens, - PXRUSDMAYA_API, - PXRUSDMAYA_STAGE_DATA_TOKENS); - - -class UsdMayaStageData : public MPxGeometryData -{ - public: - /// Unlike other Maya node types, MPxData/MPxGeometryData declare - /// typeId() as a pure virtual method that must be overridden in - /// derived classes, so we have to call this static member "mayaTypeId" - /// instead of just "typeId" as we usually would. - PXRUSDMAYA_API - static const MTypeId mayaTypeId; - PXRUSDMAYA_API - static const MString typeName; - - PXRUSDMAYA_API - static void* creator(); - - /** - * \name MPxGeometryData overrides - */ - //@{ - - PXRUSDMAYA_API - void copy(const MPxData& src) override; - - PXRUSDMAYA_API - MTypeId typeId() const override; - - PXRUSDMAYA_API - MString name() const override; - //@} - - PXRUSDMAYA_API - void registerExitCallback(); - - PXRUSDMAYA_API - void unregisterExitCallback(); - - /** - * \name data - */ - //@{ - - UsdStageRefPtr stage; - SdfPath primPath; - - //@} - - private: - UsdMayaStageData(); - ~UsdMayaStageData() override; - - UsdMayaStageData(const UsdMayaStageData&); - UsdMayaStageData& operator=(const UsdMayaStageData&); - - MCallbackId _exitCallbackId; -}; - - -PXR_NAMESPACE_CLOSE_SCOPE - - -#endif diff --git a/plugin/pxr/maya/lib/usdMaya/stageNode.cpp b/plugin/pxr/maya/lib/usdMaya/stageNode.cpp index 2c81da23e6..9c544eb492 100644 --- a/plugin/pxr/maya/lib/usdMaya/stageNode.cpp +++ b/plugin/pxr/maya/lib/usdMaya/stageNode.cpp @@ -15,8 +15,8 @@ // #include "usdMaya/stageNode.h" -#include "usdMaya/stageCache.h" -#include "usdMaya/stageData.h" +#include +#include #include "pxr/base/tf/staticTokens.h" #include "pxr/base/tf/stringUtils.h" @@ -92,7 +92,7 @@ UsdMayaStageNode::initialize() outUsdStageAttr = typedAttrFn.create("outUsdStage", "os", - UsdMayaStageData::mayaTypeId, + MayaUsdStageData::mayaTypeId, MObject::kNullObj, &status); CHECK_MSTATUS_AND_RETURN_IT(status); @@ -141,11 +141,11 @@ UsdMayaStageNode::compute(const MPlug& plug, MDataBlock& dataBlock) // Create the output stage data object. MFnPluginData pluginDataFn; MObject stageDataObj = - pluginDataFn.create(UsdMayaStageData::mayaTypeId, &status); + pluginDataFn.create(MayaUsdStageData::mayaTypeId, &status); CHECK_MSTATUS_AND_RETURN_IT(status); - UsdMayaStageData* stageData = - reinterpret_cast(pluginDataFn.data(&status)); + MayaUsdStageData* stageData = + reinterpret_cast(pluginDataFn.data(&status)); CHECK_MSTATUS_AND_RETURN_IT(status); stageData->stage = usdStage; diff --git a/plugin/pxr/maya/lib/usdMaya/testenv/testUsdMayaProxyShape.py b/plugin/pxr/maya/lib/usdMaya/testenv/testUsdMayaProxyShape.py index d533800c22..361a95be29 100644 --- a/plugin/pxr/maya/lib/usdMaya/testenv/testUsdMayaProxyShape.py +++ b/plugin/pxr/maya/lib/usdMaya/testenv/testUsdMayaProxyShape.py @@ -15,7 +15,7 @@ # limitations under the License. # -from pxr import Usd +from pxr import Usd, Tf from maya import cmds from maya import standalone @@ -42,21 +42,23 @@ def testProxyShapeBoundingBox(self): bboxSize = cmds.getAttr('Cube_usd.boundingBoxSize')[0] self.assertEqual(bboxSize, (1.0, 1.0, 1.0)) - # The proxy shape is imaged by the pxrHdImagingShape, which should be - # created by the proxy shape's postConstructor() method. Make sure the - # pxrHdImagingShape (and its parent transform) exist. - hdImagingTransformPath = '|HdImaging' - hdImagingShapePath = '%s|HdImagingShape' % hdImagingTransformPath + # The VP2 render delegate doesn't use additional proxy shape + if not Tf.GetEnvSetting('VP2_RENDER_DELEGATE_PROXY'): + # The proxy shape is imaged by the pxrHdImagingShape, which should be + # created by the proxy shape's postConstructor() method. Make sure the + # pxrHdImagingShape (and its parent transform) exist. + hdImagingTransformPath = '|HdImaging' + hdImagingShapePath = '%s|HdImagingShape' % hdImagingTransformPath - self.assertTrue(cmds.objExists(hdImagingTransformPath)) - self.assertEqual(cmds.nodeType(hdImagingTransformPath), 'transform') + self.assertTrue(cmds.objExists(hdImagingTransformPath)) + self.assertEqual(cmds.nodeType(hdImagingTransformPath), 'transform') - self.assertTrue(cmds.objExists(hdImagingShapePath)) - self.assertEqual(cmds.nodeType(hdImagingShapePath), 'pxrHdImagingShape') + self.assertTrue(cmds.objExists(hdImagingShapePath)) + self.assertEqual(cmds.nodeType(hdImagingShapePath), 'pxrHdImagingShape') - self.assertNotEqual( - cmds.ls(hdImagingTransformPath, uuid=True), - cmds.ls(hdImagingShapePath, uuid=True)) + self.assertNotEqual( + cmds.ls(hdImagingTransformPath, uuid=True), + cmds.ls(hdImagingShapePath, uuid=True)) # The pxrHdImagingShape and its parent transform are set so that they # do not write to the Maya scene file and are not exported by diff --git a/plugin/pxr/maya/lib/usdMaya/transformWriter.cpp b/plugin/pxr/maya/lib/usdMaya/transformWriter.cpp index ff404b0223..a772d962e8 100644 --- a/plugin/pxr/maya/lib/usdMaya/transformWriter.cpp +++ b/plugin/pxr/maya/lib/usdMaya/transformWriter.cpp @@ -18,7 +18,7 @@ #include "usdMaya/adaptor.h" #include "usdMaya/primWriterRegistry.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "usdMaya/xformStack.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorCamera.cpp b/plugin/pxr/maya/lib/usdMaya/translatorCamera.cpp index 91d3b9115f..8cb633bd09 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorCamera.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorCamera.cpp @@ -19,7 +19,7 @@ #include "usdMaya/primReaderArgs.h" #include "usdMaya/primReaderContext.h" #include "usdMaya/translatorUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/base/gf/vec2f.h" #include "pxr/base/tf/token.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorGprim.cpp b/plugin/pxr/maya/lib/usdMaya/translatorGprim.cpp index 7cad7e1d7e..f2b0a67741 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorGprim.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorGprim.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/translatorGprim.h" -#include "usdMaya/util.h" +#include #include diff --git a/plugin/pxr/maya/lib/usdMaya/translatorMaterial.cpp b/plugin/pxr/maya/lib/usdMaya/translatorMaterial.cpp index 058be888cb..7a887c5036 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorMaterial.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorMaterial.cpp @@ -19,7 +19,7 @@ #include "usdMaya/shadingModeExporter.h" #include "usdMaya/shadingModeImporter.h" #include "usdMaya/shadingModeRegistry.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/tf/diagnostic.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorMaterial.h b/plugin/pxr/maya/lib/usdMaya/translatorMaterial.h index 381860bc59..b5f6c4bfb1 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorMaterial.h +++ b/plugin/pxr/maya/lib/usdMaya/translatorMaterial.h @@ -21,7 +21,7 @@ #include "pxr/pxr.h" #include "usdMaya/api.h" #include "usdMaya/primReaderContext.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/tf/token.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorMesh.cpp b/plugin/pxr/maya/lib/usdMaya/translatorMesh.cpp index 53aa93cda1..ff48b3c3d0 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorMesh.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorMesh.cpp @@ -25,7 +25,7 @@ #include "usdMaya/translatorGprim.h" #include "usdMaya/translatorMaterial.h" #include "usdMaya/translatorUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/stringUtils.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorMesh_PrimVars.cpp b/plugin/pxr/maya/lib/usdMaya/translatorMesh_PrimVars.cpp index 4d342478f5..9c5e7b0911 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorMesh_PrimVars.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorMesh_PrimVars.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/translatorMesh.h" -#include "usdMaya/colorSpace.h" +#include #include "usdMaya/meshUtil.h" #include "usdMaya/readUtil.h" #include "usdMaya/roundTripUtil.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorMesh_SubDiv.cpp b/plugin/pxr/maya/lib/usdMaya/translatorMesh_SubDiv.cpp index 21399f6651..149a048b9a 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorMesh_SubDiv.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorMesh_SubDiv.cpp @@ -15,7 +15,7 @@ // #include "usdMaya/translatorMesh.h" -#include "usdMaya/util.h" +#include #include "pxr/usd/usdGeom/mesh.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorModelAssembly.cpp b/plugin/pxr/maya/lib/usdMaya/translatorModelAssembly.cpp index c3bb1b40e6..ae1d738a84 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorModelAssembly.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorModelAssembly.cpp @@ -22,10 +22,10 @@ #include "usdMaya/primWriterArgs.h" #include "usdMaya/primWriterContext.h" #include "usdMaya/referenceAssembly.h" -#include "usdMaya/stageCache.h" +#include #include "usdMaya/translatorUtil.h" #include "usdMaya/translatorXformable.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/diagnostic.h" #include "pxr/base/tf/stringUtils.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorPrim.cpp b/plugin/pxr/maya/lib/usdMaya/translatorPrim.cpp index ed8b908822..df1a97b792 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorPrim.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorPrim.cpp @@ -17,7 +17,7 @@ #include "usdMaya/readUtil.h" #include "usdMaya/translatorUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/usd/usdGeom/imageable.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorRfMLight.cpp b/plugin/pxr/maya/lib/usdMaya/translatorRfMLight.cpp index 3adff021f3..7dee04e982 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorRfMLight.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorRfMLight.cpp @@ -23,7 +23,7 @@ #include "usdMaya/primWriterRegistry.h" #include "usdMaya/translatorUtil.h" #include "usdMaya/translatorXformable.h" -#include "usdMaya/util.h" +#include #include "pxr/base/gf/vec3f.h" #include "pxr/base/tf/staticTokens.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorSkel.cpp b/plugin/pxr/maya/lib/usdMaya/translatorSkel.cpp index c8e99f84e2..270fa40cca 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorSkel.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorSkel.cpp @@ -17,7 +17,7 @@ #include "usdMaya/translatorUtil.h" #include "usdMaya/translatorXformable.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/staticData.h" #include "pxr/base/tf/staticTokens.h" diff --git a/plugin/pxr/maya/lib/usdMaya/translatorUtil.cpp b/plugin/pxr/maya/lib/usdMaya/translatorUtil.cpp index 9356a6851c..3c6fbe2cbd 100644 --- a/plugin/pxr/maya/lib/usdMaya/translatorUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/translatorUtil.cpp @@ -20,7 +20,7 @@ #include "usdMaya/primReaderArgs.h" #include "usdMaya/primReaderContext.h" #include "usdMaya/translatorXformable.h" -#include "usdMaya/util.h" +#include #include "usdMaya/xformStack.h" #include "pxr/usd/sdf/schema.h" diff --git a/plugin/pxr/maya/lib/usdMaya/userTaggedAttribute.cpp b/plugin/pxr/maya/lib/usdMaya/userTaggedAttribute.cpp index 72013e5330..49f1bc70fa 100644 --- a/plugin/pxr/maya/lib/usdMaya/userTaggedAttribute.cpp +++ b/plugin/pxr/maya/lib/usdMaya/userTaggedAttribute.cpp @@ -16,7 +16,7 @@ #include "pxr/pxr.h" #include "usdMaya/userTaggedAttribute.h" -#include "usdMaya/util.h" +#include #include "pxr/base/js/json.h" #include "pxr/base/js/value.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapAdaptor.cpp b/plugin/pxr/maya/lib/usdMaya/wrapAdaptor.cpp index 35de1a1157..a7aa6f51ec 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapAdaptor.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapAdaptor.cpp @@ -17,7 +17,7 @@ #include "pxr/pxr.h" #include "usdMaya/adaptor.h" #include "usdMaya/undoHelperCommand.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/pyResultConversions.h" #include "pxr/usd/usdGeom/primvar.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapAssembly.cpp b/plugin/pxr/maya/lib/usdMaya/wrapAssembly.cpp index 040af63096..bcdddb41d1 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapAssembly.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapAssembly.cpp @@ -16,7 +16,7 @@ #include "pxr/pxr.h" #include "usdMaya/referenceAssembly.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/pyContainerConversions.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapColorSpace.cpp b/plugin/pxr/maya/lib/usdMaya/wrapColorSpace.cpp index 39effabfed..5641339c5e 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapColorSpace.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapColorSpace.cpp @@ -14,7 +14,7 @@ // limitations under the License. // #include "pxr/pxr.h" -#include "usdMaya/colorSpace.h" +#include #include "pxr/base/gf/vec3f.h" #include "pxr/base/gf/vec3d.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapEditUtil.cpp b/plugin/pxr/maya/lib/usdMaya/wrapEditUtil.cpp index 2a35fcd294..ece8f5d89f 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapEditUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapEditUtil.cpp @@ -16,7 +16,7 @@ #include "pxr/pxr.h" #include "usdMaya/editUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/pyResultConversions.h" #include "pxr/base/tf/pyEnum.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapMeshUtil.cpp b/plugin/pxr/maya/lib/usdMaya/wrapMeshUtil.cpp index e5c2cacbc4..af6a8f7049 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapMeshUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapMeshUtil.cpp @@ -16,7 +16,7 @@ #include "pxr/pxr.h" #include "usdMaya/meshUtil.h" -#include "usdMaya/util.h" +#include #include "pxr/base/gf/vec3f.h" #include "pxr/base/tf/pyResultConversions.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapQuery.cpp b/plugin/pxr/maya/lib/usdMaya/wrapQuery.cpp index 9d861752e4..3fb69cc4ba 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapQuery.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapQuery.cpp @@ -14,7 +14,7 @@ // limitations under the License. // #include "pxr/pxr.h" -#include "usdMaya/query.h" +#include #include #include diff --git a/plugin/pxr/maya/lib/usdMaya/wrapReadUtil.cpp b/plugin/pxr/maya/lib/usdMaya/wrapReadUtil.cpp index b7442faf41..00575a19aa 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapReadUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapReadUtil.cpp @@ -15,7 +15,7 @@ // #include "pxr/pxr.h" -#include "usdMaya/util.h" +#include #include "usdMaya/readUtil.h" #include "pxr/base/tf/pyResultConversions.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapStageCache.cpp b/plugin/pxr/maya/lib/usdMaya/wrapStageCache.cpp index 3198977432..5ced7aac53 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapStageCache.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapStageCache.cpp @@ -14,7 +14,7 @@ // limitations under the License. // #include "pxr/pxr.h" -#include "usdMaya/stageCache.h" +#include #include #include diff --git a/plugin/pxr/maya/lib/usdMaya/wrapUserTaggedAttribute.cpp b/plugin/pxr/maya/lib/usdMaya/wrapUserTaggedAttribute.cpp index 7e8fd95708..f46f32fef2 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapUserTaggedAttribute.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapUserTaggedAttribute.cpp @@ -16,7 +16,7 @@ #include "pxr/pxr.h" #include "usdMaya/userTaggedAttribute.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/pyContainerConversions.h" #include "pxr/base/tf/pyResultConversions.h" diff --git a/plugin/pxr/maya/lib/usdMaya/wrapWriteUtil.cpp b/plugin/pxr/maya/lib/usdMaya/wrapWriteUtil.cpp index 9d4afe3208..b188719206 100644 --- a/plugin/pxr/maya/lib/usdMaya/wrapWriteUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/wrapWriteUtil.cpp @@ -15,7 +15,7 @@ // #include "pxr/pxr.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeUtil.h" #include "pxr/base/tf/pyResultConversions.h" diff --git a/plugin/pxr/maya/lib/usdMaya/writeJob.cpp b/plugin/pxr/maya/lib/usdMaya/writeJob.cpp index ee5c528543..1181bf9dbb 100644 --- a/plugin/pxr/maya/lib/usdMaya/writeJob.cpp +++ b/plugin/pxr/maya/lib/usdMaya/writeJob.cpp @@ -23,7 +23,7 @@ #include "usdMaya/shadingModeExporterContext.h" #include "usdMaya/transformWriter.h" #include "usdMaya/translatorMaterial.h" -#include "usdMaya/util.h" +#include #include "usdMaya/chaser.h" #include "usdMaya/chaserRegistry.h" diff --git a/plugin/pxr/maya/lib/usdMaya/writeJob.h b/plugin/pxr/maya/lib/usdMaya/writeJob.h index 70bf92bbda..b8399267de 100644 --- a/plugin/pxr/maya/lib/usdMaya/writeJob.h +++ b/plugin/pxr/maya/lib/usdMaya/writeJob.h @@ -19,7 +19,7 @@ /// \file usdMaya/writeJob.h #include "usdMaya/chaser.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/pxr.h" diff --git a/plugin/pxr/maya/lib/usdMaya/writeJobContext.cpp b/plugin/pxr/maya/lib/usdMaya/writeJobContext.cpp index a261258cdf..77364392cd 100644 --- a/plugin/pxr/maya/lib/usdMaya/writeJobContext.cpp +++ b/plugin/pxr/maya/lib/usdMaya/writeJobContext.cpp @@ -21,9 +21,9 @@ #include "usdMaya/primWriter.h" #include "usdMaya/primWriterRegistry.h" #include "usdMaya/skelBindingsProcessor.h" -#include "usdMaya/stageCache.h" +#include #include "usdMaya/transformWriter.h" -#include "usdMaya/util.h" +#include #include "pxr/base/tf/staticTokens.h" #include "pxr/base/tf/stringUtils.h" diff --git a/plugin/pxr/maya/lib/usdMaya/writeUtil.cpp b/plugin/pxr/maya/lib/usdMaya/writeUtil.cpp index d67de34fb2..c6a974c512 100644 --- a/plugin/pxr/maya/lib/usdMaya/writeUtil.cpp +++ b/plugin/pxr/maya/lib/usdMaya/writeUtil.cpp @@ -17,7 +17,7 @@ #include "usdMaya/writeUtil.h" #include "usdMaya/adaptor.h" -#include "usdMaya/colorSpace.h" +#include #include "usdMaya/translatorUtil.h" #include "usdMaya/userTaggedAttribute.h" diff --git a/plugin/pxr/maya/plugin/pxrUsd/CMakeLists.txt b/plugin/pxr/maya/plugin/pxrUsd/CMakeLists.txt index 7194ef686e..04b88e0bab 100644 --- a/plugin/pxr/maya/plugin/pxrUsd/CMakeLists.txt +++ b/plugin/pxr/maya/plugin/pxrUsd/CMakeLists.txt @@ -5,6 +5,7 @@ pxr_plugin(${PXR_PACKAGE} LIBRARIES pxrUsdMayaGL + mayaUsd sdf tf usd @@ -31,6 +32,21 @@ pxr_plugin(${PXR_PACKAGE} DISABLE_PRECOMPILED_HEADERS ) +if(CMAKE_WANT_UFE_BUILD) + find_package(UFE QUIET) + if(UFE_FOUND) + message(STATUS "Building with UFE ${UFE_VERSION} features enabled.") + include_directories(${UFE_INCLUDE_DIR}) + add_definitions(-DWANT_UFE_BUILD) + else() + message(STATUS "UFE not found. UFE features will be disabled.") + endif() +endif() + +if (UFE_FOUND) + target_link_libraries(${PXR_PACKAGE} ${UFE_LIBRARY}) +endif() + pxr_test_scripts( testenv/testPxrUsdAlembicChaser.py ) @@ -39,13 +55,16 @@ pxr_install_test_dir( SRC testenv/AlembicChaser DEST testPxrUsdAlembicChaser ) +set(TEST_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/plugin/pxr") + pxr_register_test(testPxrUsdAlembicChaser CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testPxrUsdAlembicChaser" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testPxrUsdAlembicChaser" TESTENV testPxrUsdAlembicChaser ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) diff --git a/plugin/pxr/maya/plugin/pxrUsd/plugin.cpp b/plugin/pxr/maya/plugin/pxrUsd/plugin.cpp index 03b388fa0f..14233ff218 100644 --- a/plugin/pxr/maya/plugin/pxrUsd/plugin.cpp +++ b/plugin/pxr/maya/plugin/pxrUsd/plugin.cpp @@ -16,6 +16,8 @@ #include "pxr/pxr.h" #include "pxrUsd/api.h" +#include + #include "pxrUsdMayaGL/hdImagingShapeDrawOverride.h" #include "pxrUsdMayaGL/hdImagingShapeUI.h" #include "pxrUsdMayaGL/proxyDrawOverride.h" @@ -28,11 +30,11 @@ #include "usdMaya/importCommand.h" #include "usdMaya/importTranslator.h" #include "usdMaya/listShadingModesCommand.h" -#include "usdMaya/notice.h" +#include #include "usdMaya/pointBasedDeformerNode.h" #include "usdMaya/proxyShape.h" #include "usdMaya/referenceAssembly.h" -#include "usdMaya/stageData.h" +#include #include "usdMaya/stageNode.h" #include "usdMaya/undoHelperCommand.h" @@ -43,6 +45,9 @@ #include #include +#if defined(WANT_UFE_BUILD) +#include +#endif PXR_NAMESPACE_USING_DIRECTIVE @@ -57,10 +62,14 @@ initializePlugin(MObject obj) MStatus status; MFnPlugin plugin(obj, "Pixar", "1.0", "Any"); - status = plugin.registerData( - UsdMayaStageData::typeName, - UsdMayaStageData::mayaTypeId, - UsdMayaStageData::creator); +#if defined(WANT_UFE_BUILD) + status = MayaUsd::ufe::initialize(); + if (!status) { + status.perror("Unable to initialize ufe."); + } +#endif + + status = MayaUsdProxyShapePlugin::initialize(plugin); CHECK_MSTATUS(status); status = plugin.registerNode( @@ -78,14 +87,51 @@ initializePlugin(MObject obj) MPxNode::kDeformerNode); CHECK_MSTATUS(status); - status = plugin.registerShape( - UsdMayaProxyShape::typeName, - UsdMayaProxyShape::typeId, - UsdMayaProxyShape::creator, - UsdMayaProxyShape::initialize, - UsdMayaProxyShapeUI::creator, - &UsdMayaProxyDrawOverride::drawDbClassification); - CHECK_MSTATUS(status); + if (MayaUsdProxyShapePlugin::useVP2_NativeUSD_Rendering()) { + status = plugin.registerShape( + UsdMayaProxyShape::typeName, + UsdMayaProxyShape::typeId, + UsdMayaProxyShape::creator, + UsdMayaProxyShape::initialize, + UsdMayaProxyShapeUI::creator, + MayaUsdProxyShapePlugin::getProxyShapeClassification()); + CHECK_MSTATUS(status); + } + else { + status = plugin.registerShape( + UsdMayaProxyShape::typeName, + UsdMayaProxyShape::typeId, + UsdMayaProxyShape::creator, + UsdMayaProxyShape::initialize, + UsdMayaProxyShapeUI::creator, + &UsdMayaProxyDrawOverride::drawDbClassification); + CHECK_MSTATUS(status); + status = plugin.registerShape( + PxrMayaHdImagingShape::typeName, + PxrMayaHdImagingShape::typeId, + PxrMayaHdImagingShape::creator, + PxrMayaHdImagingShape::initialize, + PxrMayaHdImagingShapeUI::creator, + &PxrMayaHdImagingShapeDrawOverride::drawDbClassification); + CHECK_MSTATUS(status); + status = MHWRender::MDrawRegistry::registerDrawOverrideCreator( + PxrMayaHdImagingShapeDrawOverride::drawDbClassification, + _RegistrantId, + PxrMayaHdImagingShapeDrawOverride::creator); + CHECK_MSTATUS(status); + + status = MHWRender::MDrawRegistry::registerDrawOverrideCreator( + UsdMayaProxyDrawOverride::drawDbClassification, + _RegistrantId, + UsdMayaProxyDrawOverride::Creator); + CHECK_MSTATUS(status); + + status = plugin.registerDisplayFilter( + UsdMayaProxyShape::displayFilterName, + UsdMayaProxyShape::displayFilterLabel, + UsdMayaProxyDrawOverride::drawDbClassification); + CHECK_MSTATUS(status); + } status = plugin.registerNode( UsdMayaReferenceAssembly::typeName, @@ -96,33 +142,6 @@ initializePlugin(MObject obj) &UsdMayaReferenceAssembly::_classification); CHECK_MSTATUS(status); - status = plugin.registerShape( - PxrMayaHdImagingShape::typeName, - PxrMayaHdImagingShape::typeId, - PxrMayaHdImagingShape::creator, - PxrMayaHdImagingShape::initialize, - PxrMayaHdImagingShapeUI::creator, - &PxrMayaHdImagingShapeDrawOverride::drawDbClassification); - CHECK_MSTATUS(status); - - status = MHWRender::MDrawRegistry::registerDrawOverrideCreator( - PxrMayaHdImagingShapeDrawOverride::drawDbClassification, - _RegistrantId, - PxrMayaHdImagingShapeDrawOverride::creator); - CHECK_MSTATUS(status); - - status = MHWRender::MDrawRegistry::registerDrawOverrideCreator( - UsdMayaProxyDrawOverride::drawDbClassification, - _RegistrantId, - UsdMayaProxyDrawOverride::Creator); - CHECK_MSTATUS(status); - - status = plugin.registerDisplayFilter( - UsdMayaProxyShape::displayFilterName, - UsdMayaProxyShape::displayFilterLabel, - UsdMayaProxyDrawOverride::drawDbClassification); - CHECK_MSTATUS(status); - status = MGlobal::sourceFile("usdMaya.mel"); CHECK_MSTATUS(status); @@ -218,6 +237,11 @@ uninitializePlugin(MObject obj) MStatus status; MFnPlugin plugin(obj); +#if defined(WANT_UFE_BUILD) + status = MayaUsd::ufe::finalize(); + CHECK_MSTATUS(status); +#endif + status = plugin.deregisterCommand("usdImport"); if (!status) { status.perror("deregisterCommand usdImport"); @@ -280,7 +304,7 @@ uninitializePlugin(MObject obj) status = plugin.deregisterNode(UsdMayaStageNode::typeId); CHECK_MSTATUS(status); - status = plugin.deregisterData(UsdMayaStageData::mayaTypeId); + status = MayaUsdProxyShapePlugin::finalize(plugin); CHECK_MSTATUS(status); UsdMayaSceneResetNotice::RemoveListener(); diff --git a/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/CMakeLists.txt b/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/CMakeLists.txt index ed763d7562..4d6e4b5222 100644 --- a/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/CMakeLists.txt +++ b/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/CMakeLists.txt @@ -76,13 +76,16 @@ pxr_install_test_dir( SRC testenv/PxrUsdPreviewSurfaceExportTest DEST testPxrUsdPreviewSurfaceExport ) +set(TEST_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/plugin/pxr") + pxr_register_test(testPxrUsdPreviewSurfaceExport CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testPxrUsdPreviewSurfaceExport" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testPxrUsdPreviewSurfaceExport" TESTENV testPxrUsdPreviewSurfaceExport ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources:${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources:${TEST_INSTALL_PREFIX}/maya/plugin/pxrUsdPreviewSurface/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) diff --git a/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/usdPreviewSurfaceWriter.cpp b/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/usdPreviewSurfaceWriter.cpp index 19d45d713e..d8f38358d5 100644 --- a/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/usdPreviewSurfaceWriter.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdPreviewSurface/usdPreviewSurfaceWriter.cpp @@ -19,7 +19,7 @@ #include "pxrUsdPreviewSurface/usdPreviewSurface.h" #include "usdMaya/primWriterRegistry.h" #include "usdMaya/shaderWriter.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "usdMaya/writeUtil.h" diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/CMakeLists.txt b/plugin/pxr/maya/plugin/pxrUsdTranslators/CMakeLists.txt index 422925789e..ebb8e8af78 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/CMakeLists.txt +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/CMakeLists.txt @@ -69,13 +69,16 @@ pxr_test_scripts( testenv/testPxrUsdTranslatorsStroke.py ) +set(TEST_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/plugin/pxr") + pxr_register_test(testPxrUsdTranslators CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testPxrUsdTranslators" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testPxrUsdTranslators" ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -85,12 +88,13 @@ pxr_install_test_dir( ) pxr_register_test(testPxrUsdTranslatorsScope CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testPxrUsdTranslatorsScope" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testPxrUsdTranslatorsScope" TESTENV testPxrUsdTranslatorsScope ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) @@ -100,11 +104,12 @@ pxr_install_test_dir( ) pxr_register_test(testPxrUsdTranslatorsStroke CUSTOM_PYTHON ${MAYA_PY_EXECUTABLE} - COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testPxrUsdTranslatorsStroke" + COMMAND "${TEST_INSTALL_PREFIX}/tests/testPxrUsdTranslatorsStroke" TESTENV testPxrUsdTranslatorsStroke ENV - MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/plugin - MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/plugin/pxr/maya/lib/usd/usdMaya/resources + MAYA_PLUG_IN_PATH=${TEST_INSTALL_PREFIX}/maya/plugin + MAYA_SCRIPT_PATH=${TEST_INSTALL_PREFIX}/maya/lib/usd/usdMaya/resources MAYA_DISABLE_CIP=1 + MAYA_NO_STANDALONE_ATEXIT=1 MAYA_APP_DIR=/maya_profile ) diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/cameraWriter.cpp b/plugin/pxr/maya/plugin/pxrUsdTranslators/cameraWriter.cpp index c12f337f5f..f2946ab779 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/cameraWriter.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/cameraWriter.cpp @@ -19,7 +19,7 @@ #include "usdMaya/adaptor.h" #include "usdMaya/primWriter.h" #include "usdMaya/primWriterRegistry.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/gf/vec2f.h" diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/fileTextureWriter.cpp b/plugin/pxr/maya/plugin/pxrUsdTranslators/fileTextureWriter.cpp index b3d52d91b7..9e96929455 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/fileTextureWriter.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/fileTextureWriter.cpp @@ -18,7 +18,7 @@ #include "usdMaya/primWriterRegistry.h" #include "usdMaya/shaderWriter.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/gf/vec3f.h" diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/instancerWriter.cpp b/plugin/pxr/maya/plugin/pxrUsdTranslators/instancerWriter.cpp index 44f1c78d80..5aa643e878 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/instancerWriter.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/instancerWriter.cpp @@ -17,7 +17,7 @@ #include "usdMaya/adaptor.h" #include "usdMaya/primWriterRegistry.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "usdMaya/writeUtil.h" diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/jointWriter.cpp b/plugin/pxr/maya/plugin/pxrUsdTranslators/jointWriter.cpp index 803c1b244c..2b255041b2 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/jointWriter.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/jointWriter.cpp @@ -21,7 +21,7 @@ #include "usdMaya/primWriterRegistry.h" #include "usdMaya/translatorSkel.h" #include "usdMaya/translatorUtil.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeJobContext.h" #include "pxr/base/tf/staticTokens.h" diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter.cpp b/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter.cpp index d7eca808bb..fc770902c8 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter.cpp @@ -20,7 +20,7 @@ #include "usdMaya/meshUtil.h" #include "usdMaya/primWriter.h" #include "usdMaya/primWriterRegistry.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeUtil.h" #include "usdMaya/writeJobContext.h" diff --git a/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter_Primvars.cpp b/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter_Primvars.cpp index aeb5ea7c33..dbdee6f9d9 100644 --- a/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter_Primvars.cpp +++ b/plugin/pxr/maya/plugin/pxrUsdTranslators/meshWriter_Primvars.cpp @@ -15,9 +15,9 @@ // #include "pxrUsdTranslators/meshWriter.h" -#include "usdMaya/colorSpace.h" +#include #include "usdMaya/roundTripUtil.h" -#include "usdMaya/util.h" +#include #include "usdMaya/writeUtil.h" #include "pxr/base/gf/gamma.h" diff --git a/test/lib/ufe/CMakeLists.txt b/test/lib/ufe/CMakeLists.txt new file mode 100644 index 0000000000..dfab9e3880 --- /dev/null +++ b/test/lib/ufe/CMakeLists.txt @@ -0,0 +1,115 @@ +# +# Copyright 2019 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. +# + +set(TARGET_NAME UFE_TEST) + +# unit test scripts. Note that testTRSBase.py is not a test case, but rather +# a module providing a base class for other tests. +set(test_script_files + testDeleteCmd.py + testMatrices.py + testMayaPickwalk.py + testRotatePivot.py +) + +set(test_support_files + testTRSBase.py +) + +if(CMAKE_UFE_V2_FEATURES_AVAILABLE) + list(APPEND test_script_files + testGroupCmd.py + testAttribute.py + testAttributes.py + # The following files test UFE_V1 interfaces, and therefore should not + # depend on UFE_V2. However, the test code relies on capability to + # retrieve a USD prim from a UFE scene item, which in turn depends on + # functionality that is only available in UFE_V2. Therefore, run the + # tests only if UFE_V2 is available. PPT, 11-Oct-2019. + # + # MAYA-101385: until Maya switches back to UFE_V2, fail, so commented + # out. PPT, 11-Oct-2019. + # + # testDuplicateCmd.py + # testMoveCmd.py + # testRotateCmd.py + # testScaleCmd.py + # testTransform3dTranslate.py + ) +endif() + +# copy ufe tests to ${CMAKE_CURRENT_BINARY_DIR} and run them from there +add_custom_target(${TARGET_NAME} ALL) + +mayaUsd_copyDirectory(${TARGET_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + DIRECTORY test-samples) +mayaUsd_copyDirectory(${TARGET_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + DIRECTORY ufeScripts) +mayaUsd_copyDirectory(${TARGET_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + DIRECTORY ufeTestUtils) +mayaUsd_copyDirectory(${TARGET_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + DIRECTORY ufeTestPlugins) +mayaUsd_copyFiles(${TARGET_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + FILES ${test_script_files}) +mayaUsd_copyFiles(${TARGET_NAME} DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + FILES ${test_support_files}) + +# unit tests +set(pythonPath + "${CMAKE_INSTALL_PREFIX}/lib/python" + "$ENV{PYTHONPATH}" +) + +set(mayaPluginPath + "${CMAKE_INSTALL_PREFIX}/plugin/adsk/plugin" + "${CMAKE_CURRENT_BINARY_DIR}/ufeTestPlugins" +) + +set(path + "${CMAKE_INSTALL_PREFIX}/lib" + "${MAYA_LOCATION}/bin" + "$ENV{PATH}" +) + +if(IS_WINDOWS) + string(REPLACE ";" "\;" pythonPath "${pythonPath}") + string(REPLACE ";" "\;" path "${path}") + string(REPLACE ";" "\;" mayaPluginPath "${mayaPluginPath}") +else() + separate_arguments(pythonPath NATIVE_COMMAND "${pythonPath}") + separate_arguments(path NATIVE_COMMAND "${path}") + separate_arguments(mayaPluginPath NATIVE_COMMAND "${mayaPluginPath}") + + string(REPLACE "\;" ":" pythonPath "${pythonPath}") + string(REPLACE "\;" ":" path "${path}") + string(REPLACE "\;" ":" mayaPluginPath "${mayaPluginPath}") +endif() + +foreach(script ${test_script_files}) + mayaUsd_get_unittest_target(target ${script}) + add_test( + NAME ${target} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${MAYA_PY_EXECUTABLE} -c "from unittest import main;import maya.standalone;maya.standalone.initialize(name='python');import ${target};main(module=${target});maya.standalone.uninitialize()" + ) + set_property(TEST ${target} APPEND PROPERTY ENVIRONMENT + "PYTHONPATH=${pythonPath}" + "PATH=${path}" + "MAYA_PLUG_IN_PATH=${mayaPluginPath}" + "PXR_PLUGINPATH_NAME=${CMAKE_INSTALL_PREFIX}/lib/usd" + "MAYA_NO_STANDALONE_ATEXIT=1" + ) +endforeach() diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/Assembly_room_set.usda b/test/lib/ufe/test-samples/ballset/StandaloneScene/Assembly_room_set.usda new file mode 100644 index 0000000000..a59cc55178 --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/Assembly_room_set.usda @@ -0,0 +1,409 @@ +#usda 1.0 +( + defaultPrim = "Room_set" + subLayers = [ + @edits.usda@ + ] + upAxis = "Y" +) + +def Xform "Room_set" ( + assetInfo = { + asset identifier = @Room_set.usd@ + string name = "Room_set" + } + kind = "assembly" +) +{ + def Xform "Props" ( + kind = "group" + ) + { + def "Ball_1" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_2" + } + ) + { + double3 xformOp:translate = (-5, 2.8575, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_2" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_3" + } + ) + { + double3 xformOp:translate = (-0.0506648173719331, 2.8575, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_3" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_4" + } + ) + { + double3 xformOp:translate = (-0.0506648173719331, 2.8575, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_4" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_5" + } + ) + { + double3 xformOp:translate = (4.89867036525613, 2.8575, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_5" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_6" + } + ) + { + double3 xformOp:translate = (4.89867036525613, 2.8575, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_6" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_7" + } + ) + { + double3 xformOp:translate = (4.89867036525613, 2.8575, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_7" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_8" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, -8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_8" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_9" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_9" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_10" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_10" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_11" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, 8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_11" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_12" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, -11.43) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_12" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_13" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_13" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_14" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_14" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_1" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_15" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_2" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, 11.43) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_16" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_3" + } + ) + { + double3 xformOp:translate = (-2.1425, 7.14375, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_17" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_4" + } + ) + { + double3 xformOp:translate = (2.80683518262807, 7.14375, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_18" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_5" + } + ) + { + double3 xformOp:translate = (2.80683518262807, 7.14375, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_19" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_6" + } + ) + { + double3 xformOp:translate = (7.75617036525613, 7.14375, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_20" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_7" + } + ) + { + double3 xformOp:translate = (7.75617036525613, 7.14375, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_21" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_8" + } + ) + { + double3 xformOp:translate = (7.75617036525613, 7.14375, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_22" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_9" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, -8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_23" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_10" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_24" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_11" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_25" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_12" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, 8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_26" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_13" + } + ) + { + double3 xformOp:translate = (0.715, 11.43, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_27" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_14" + } + ) + { + double3 xformOp:translate = (5.66433518262807, 11.43, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_28" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_1" + } + ) + { + double3 xformOp:translate = (5.66433518262807, 11.43, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_29" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_2" + } + ) + { + double3 xformOp:translate = (10.6136703652561, 11.43, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_30" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_3" + } + ) + { + double3 xformOp:translate = (10.6136703652561, 11.43, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_31" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_4" + } + ) + { + double3 xformOp:translate = (10.6136703652561, 11.43, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_32" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_5" + } + ) + { + double3 xformOp:translate = (3.5725, 15.71625, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_33" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_6" + } + ) + { + double3 xformOp:translate = (8.52183518262807, 15.71625, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_34" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_7" + } + ) + { + double3 xformOp:translate = (8.52183518262807, 15.71625, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_35" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_8" + } + ) + { + double3 xformOp:translate = (6.43, 20.0025, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } +} + + diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.maya.usd b/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.maya.usd new file mode 100644 index 0000000000..09497ee1ff Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.maya.usd differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.shadingVariants.usda b/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.shadingVariants.usda new file mode 100644 index 0000000000..d9ba3ed9a1 --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.shadingVariants.usda @@ -0,0 +1,317 @@ +#usda 1.0 +( + defaultPrim = "Ball" +) + +over "Ball" ( + variants = { + string shadingVariant = "Cue" + } + add variantSets = "shadingVariant" +) +{ + over "mesh" + { + } + + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + } + } + } + variantSet "shadingVariant" = { + "Ball_1" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball1.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(1, 0.850422, 0.0241323)] + } + + } + "Ball_10" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball10.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.0170208, 0.0444973, 0.363132)] + } + + } + "Ball_11" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball11.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.947959, 0.0329563, 0.0134364)] + } + + } + "Ball_12" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball12.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.0473661, 0.0167832, 0.133209)] + } + + } + "Ball_13" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball13.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.956527, 0.215727, 0.0241323)] + } + + } + "Ball_14" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball14.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.0013732, 0.0494753, 0.0429018)] + } + + } + "Ball_15" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball15.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.333438, 0.0019764, 0.00550657)] + } + + } + "Ball_2" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball2.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.0170208, 0.0444973, 0.363132)] + } + + } + "Ball_3" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball3.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.947959, 0.0329563, 0.0134364)] + } + + } + "Ball_4" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball4.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.0473661, 0.0167832, 0.133209)] + } + + } + "Ball_5" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball5.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.956527, 0.215727, 0.0241323)] + } + + } + "Ball_6" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball6.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.0013732, 0.0494753, 0.0429018)] + } + + } + "Ball_7" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball7.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.333438, 0.0019764, 0.00550657)] + } + + } + "Ball_8" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball8.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.00977218, 0.00908114, 0.00778151)] + } + + } + "Ball_9" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ball9.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(1, 0.850422, 0.0241323)] + } + + } + "Cue" { + over "Looks" + { + over "BallLook" + { + over "BallTexture" + { + string filename = "./tex/ballCue.tex" + } + } + } + + over "mesh" + { + color3f[] primvars:displayColor = [(0.991221, 0.982484, 0.743576)] + } + + } + } +} + diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.usd b/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.usd new file mode 100644 index 0000000000..b52b0f26c0 --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/Ball.usd @@ -0,0 +1,21 @@ +#usda 1.0 +( + defaultPrim = "Ball" + upAxis = "Y" +) + +def Xform "Ball" ( + assetInfo = { + asset identifier = @Ball/Ball.usd@ + string name = "Ball" + } + kind = "component" + add references = [ + @./Ball.shadingVariants.usda@, + @./Ball.maya.usd@ + ] +) +{ +} + + diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/Room_set.usd b/test/lib/ufe/test-samples/ballset/StandaloneScene/Room_set.usd new file mode 100644 index 0000000000..3942423402 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/Room_set.usd differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/edits.usda b/test/lib/ufe/test-samples/ballset/StandaloneScene/edits.usda new file mode 100644 index 0000000000..f8bc9ff130 --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/edits.usda @@ -0,0 +1,405 @@ +#usda 1.0 +( + defaultPrim = "Room_set" + upAxis = "Y" +) + +def Xform "Room_set" ( + assetInfo = { + asset identifier = @Room_set.usd@ + string name = "Room_set" + } + kind = "assembly" +) +{ + def Xform "Props" ( + kind = "group" + ) + { + def "Ball_1" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_2" + } + ) + { + double3 xformOp:translate = (-5, 2.8575, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_2" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_3" + } + ) + { + double3 xformOp:translate = (-0.0506648173719331, 2.8575, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_3" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_4" + } + ) + { + double3 xformOp:translate = (-0.0506648173719331, 2.8575, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_4" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_5" + } + ) + { + double3 xformOp:translate = (4.89867036525613, 2.8575, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_5" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_6" + } + ) + { + double3 xformOp:translate = (4.89867036525613, 2.8575, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_6" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_7" + } + ) + { + double3 xformOp:translate = (4.89867036525613, 2.8575, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_7" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_8" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, -8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_8" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_9" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_9" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_10" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_10" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_11" + } + ) + { + double3 xformOp:translate = (9.8480055478842, 2.8575, 8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_11" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_12" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, -11.43) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_12" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_13" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_13" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_14" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_14" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_1" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_15" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_2" + } + ) + { + double3 xformOp:translate = (14.7973407305123, 2.8575, 11.43) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_16" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_3" + } + ) + { + double3 xformOp:translate = (-2.1425, 7.14375, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_17" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_4" + } + ) + { + double3 xformOp:translate = (2.80683518262807, 7.14375, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_18" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_5" + } + ) + { + double3 xformOp:translate = (2.80683518262807, 7.14375, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_19" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_6" + } + ) + { + double3 xformOp:translate = (7.75617036525613, 7.14375, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_20" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_7" + } + ) + { + double3 xformOp:translate = (7.75617036525613, 7.14375, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_21" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_8" + } + ) + { + double3 xformOp:translate = (7.75617036525613, 7.14375, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_22" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_9" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, -8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_23" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_10" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_24" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_11" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_25" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_12" + } + ) + { + double3 xformOp:translate = (12.7055055478842, 7.14375, 8.5725) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_26" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_13" + } + ) + { + double3 xformOp:translate = (0.715, 11.43, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_27" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_14" + } + ) + { + double3 xformOp:translate = (27.155909710631434, 28.129659947096272, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_28" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_1" + } + ) + { + double3 xformOp:translate = (5.66433518262807, 11.43, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_29" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_2" + } + ) + { + double3 xformOp:translate = (10.6136703652561, 11.43, -5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_30" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_3" + } + ) + { + double3 xformOp:translate = (10.6136703652561, 11.43, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_31" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_4" + } + ) + { + double3 xformOp:translate = (10.6136703652561, 11.43, 5.715) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_32" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_5" + } + ) + { + double3 xformOp:translate = (3.5725, 15.71625, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_33" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_6" + } + ) + { + double3 xformOp:translate = (8.52183518262807, 15.71625, -2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_34" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_7" + } + ) + { + double3 xformOp:translate = (8.52183518262807, 15.71625, 2.8575) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + + def "Ball_35" ( + add references = @./Ball.usd@ + variants = { + string shadingVariant = "Ball_8" + } + ) + { + double3 xformOp:translate = (6.43, 20.0025, 0) + uniform token[] xformOpOrder = ["xformOp:translate"] + } + } +} + diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball1.jpg b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball1.jpg new file mode 100644 index 0000000000..f9579793a9 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball1.jpg differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball1.tex b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball1.tex new file mode 100644 index 0000000000..309c7fa328 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball1.tex differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball4.jpg b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball4.jpg new file mode 100644 index 0000000000..8fc7c6eddc Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball4.jpg differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball4.tex b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball4.tex new file mode 100644 index 0000000000..cb16fbed57 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball4.tex differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball8.jpg b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball8.jpg new file mode 100644 index 0000000000..7f73408554 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball8.jpg differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball8.tex b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball8.tex new file mode 100644 index 0000000000..bf65e2eabb Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball8.tex differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball9.jpg b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball9.jpg new file mode 100644 index 0000000000..b7d1850cdd Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball9.jpg differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball9.tex b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball9.tex new file mode 100644 index 0000000000..fd0b374f2b Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ball9.tex differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ballCue.jpg b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ballCue.jpg new file mode 100644 index 0000000000..a0d2ff7831 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ballCue.jpg differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ballCue.tex b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ballCue.tex new file mode 100644 index 0000000000..e1928909a7 Binary files /dev/null and b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/ballCue.tex differ diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/makeTex b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/makeTex new file mode 100644 index 0000000000..0efde57aa7 --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/tex/makeTex @@ -0,0 +1,7 @@ +#!/bin/bash -e +txmake=/opt/pixar/RenderManProServer-20.3/bin/txmake +$txmake ballCue.jpg ballCue.tex +$txmake ball1.jpg ball1.tex +$txmake ball9.jpg ball9.tex +$txmake ball8.jpg ball8.tex +$txmake ball4.jpg ball4.tex diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/top_layer.ma b/test/lib/ufe/test-samples/ballset/StandaloneScene/top_layer.ma new file mode 100644 index 0000000000..2b042039dd --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/top_layer.ma @@ -0,0 +1,185 @@ +//Maya ASCII 2019ff01 scene +//Name: top_layer.ma +//Last modified: Wed, Jan 24, 2018 02:42:12 PM +//Codeset: 1252 +requires maya "2019ff01"; +requires -nodeType "mayaUsdProxyShape" "mayaUsdPlugin" "1.0"; +currentUnit -l centimeter -a degree -t film; +fileInfo "application" "maya"; +fileInfo "product" "Maya 2019"; +fileInfo "version" "Preview Release 84"; +fileInfo "cutIdentifier" "201710181345-000000"; +fileInfo "osv" "Microsoft Windows 7 Enterprise Edition, 64-bit Windows 7 Service Pack 1 (Build 7601)\n"; +createNode transform -s -n "persp"; + rename -uid "09DA59AF-4643-E872-A30C-9B9483DA5348"; + setAttr ".v" no; + setAttr ".t" -type "double3" 65.728843243209113 49.296632432406881 65.728843243209141 ; + setAttr ".r" -type "double3" -27.938352729602379 44.999999999999972 -5.172681101354183e-14 ; +createNode camera -s -n "perspShape" -p "persp"; + rename -uid "36E553F0-4F33-86B2-8575-7E8C259AF19C"; + setAttr -k off ".v" no; + setAttr ".fl" 34.999999999999993; + setAttr ".coi" 105.21748731725418; + setAttr ".imn" -type "string" "persp"; + setAttr ".den" -type "string" "persp_depth"; + setAttr ".man" -type "string" "persp_mask"; + setAttr ".hc" -type "string" "viewSet -p %camera"; +createNode transform -s -n "top"; + rename -uid "5664DF6D-4E66-44C0-BC52-4C83C4F34259"; + setAttr ".v" no; + setAttr ".t" -type "double3" 0 1000.1 0 ; + setAttr ".r" -type "double3" -90 0 0 ; +createNode camera -s -n "topShape" -p "top"; + rename -uid "19A13A48-4ECF-6DDE-D783-14BCA9353A5A"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "top"; + setAttr ".den" -type "string" "top_depth"; + setAttr ".man" -type "string" "top_mask"; + setAttr ".hc" -type "string" "viewSet -t %camera"; + setAttr ".o" yes; +createNode transform -s -n "front"; + rename -uid "B17CCEE7-4D5F-2486-48AC-3494D6063E7C"; + setAttr ".v" no; + setAttr ".t" -type "double3" 0 0 1000.1 ; +createNode camera -s -n "frontShape" -p "front"; + rename -uid "C986F93F-487E-9FEA-02BA-DFBE4E68A730"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "front"; + setAttr ".den" -type "string" "front_depth"; + setAttr ".man" -type "string" "front_mask"; + setAttr ".hc" -type "string" "viewSet -f %camera"; + setAttr ".o" yes; +createNode transform -s -n "side"; + rename -uid "28344726-44BA-275F-3D6E-E1AF18FB1898"; + setAttr ".v" no; + setAttr ".t" -type "double3" 1000.1 0 0 ; + setAttr ".r" -type "double3" 0 90 0 ; +createNode camera -s -n "sideShape" -p "side"; + rename -uid "418D0A52-427D-4B94-26DD-78BD9603DD20"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "side"; + setAttr ".den" -type "string" "side_depth"; + setAttr ".man" -type "string" "side_mask"; + setAttr ".hc" -type "string" "viewSet -s %camera"; + setAttr ".o" yes; +createNode transform -n "transform1"; + rename -uid "E4BD3C45-4F58-7770-55BD-568AEDF1B8ED"; + setAttr ".t" -type "double3" 1 2 3 ; +createNode mayaUsdProxyShape -n "proxyShape1" -p "transform1"; + rename -uid "582C1C04-4F85-0F3B-6862-668E4A0DB2EC"; + setAttr -k off ".v"; + setAttr ".covm[0]" 0 1 1; + setAttr ".cdvm[0]" 0 1 1; + setAttr ".fp" -type "string" "top_layer.usda"; +createNode lightLinker -s -n "lightLinker1"; + rename -uid "25E17A0E-4245-BC20-CC1A-2A994FDD628D"; + setAttr -s 2 ".lnk"; + setAttr -s 2 ".slnk"; +createNode shapeEditorManager -n "shapeEditorManager"; + rename -uid "F26113AA-48CF-F47D-C927-D3B600BA9182"; +createNode poseInterpolatorManager -n "poseInterpolatorManager"; + rename -uid "033958C3-4E04-D817-32DD-DCA5C68287B1"; +createNode displayLayerManager -n "layerManager"; + rename -uid "2A3C8DB0-4E7E-1B43-F8E9-249C7603F01C"; +createNode displayLayer -n "defaultLayer"; + rename -uid "A7CB3FCA-4FFF-91CA-40DB-81A6DFF21DF9"; +createNode renderLayerManager -n "renderLayerManager"; + rename -uid "E78CF143-4578-BA32-9FF1-08BA8FC254ED"; +createNode renderLayer -n "defaultRenderLayer"; + rename -uid "ECEAFB10-4385-6714-6E83-53BB097394A4"; + setAttr ".g" yes; +createNode script -n "uiConfigurationScriptNode"; + rename -uid "2DC71E56-41B8-16B1-29B5-73818F8D6E7A"; + setAttr ".b" -type "string" ( + "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n" + + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n" + + " -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n" + + " -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n" + + " -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n" + + " -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n" + + " -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1125\n -height 825\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n" + + " -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 0\n -isSetMember 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n" + + " -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n" + + " -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 1\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n" + + " -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n" + + " -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 1\n -displayInfinities 0\n -displayValues 0\n -autoFit 1\n -snapTime \"integer\" \n -snapValue \"none\" \n -showResults \"off\" \n -showBufferCurves \"off\" \n -smoothness \"fine\" \n -resultSamples 1\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -showCurveNames 0\n -showActiveCurveNames 0\n -stackedCurves 0\n" + + " -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -displayNormalized 0\n -preSelectionHighlight 0\n -constrainDrag 0\n -classicMode 1\n -valueLinesToggle 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n" + + " -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 1\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n" + + " -displayValues 0\n -autoFit 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -displayValues 0\n -autoFit 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n" + + " -displayActiveKeyTangents 0\n -displayInfinities 0\n -displayValues 0\n -autoFit 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n -showShapes 0\n -showDeformers 0\n" + + " -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n\tif (\"\" != $panelName) {\n" + + "\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n" + + " -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 1\n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n" + + "\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 1\n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n" + + " -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n" + + "\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n" + + "\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1125\\n -height 825\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 1125\\n -height 825\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); + setAttr ".st" 3; +createNode script -n "sceneConfigurationScriptNode"; + rename -uid "AD3C78B6-45CC-9090-B5BF-DD95D99E722C"; + setAttr ".b" -type "string" "playbackOptions -min 1 -max 120 -ast 1 -aet 200 "; + setAttr ".st" 6; +select -ne :time1; + setAttr ".o" 1; + setAttr ".unw" 1; +select -ne :hardwareRenderingGlobals; + setAttr ".otfna" -type "stringArray" 22 "NURBS Curves" "NURBS Surfaces" "Polygons" "Subdiv Surface" "Particles" "Particle Instance" "Fluids" "Strokes" "Image Planes" "UI" "Lights" "Cameras" "Locators" "Joints" "IK Handles" "Deformers" "Motion Trails" "Components" "Hair Systems" "Follicles" "Misc. UI" "Ornaments" ; + setAttr ".otfva" -type "Int32Array" 22 0 1 1 1 1 1 + 1 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 ; + setAttr ".fprt" yes; +select -ne :renderPartition; + setAttr -s 2 ".st"; +select -ne :renderGlobalsList1; +select -ne :defaultShaderList1; + setAttr -s 4 ".s"; +select -ne :postProcessList1; + setAttr -s 2 ".p"; +select -ne :defaultRenderingList1; +select -ne :initialShadingGroup; + setAttr ".ro" yes; +select -ne :initialParticleSE; + setAttr ".ro" yes; +select -ne :defaultResolution; + setAttr ".pa" 1; +select -ne :hardwareRenderGlobals; + setAttr ".ctrs" 256; + setAttr ".btrs" 512; +connectAttr ":time1.o" "proxyShape1.tm"; +relationship "link" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; +relationship "link" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; +relationship "shadowLink" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; +relationship "shadowLink" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; +connectAttr "layerManager.dli[0]" "defaultLayer.id"; +connectAttr "renderLayerManager.rlmi[0]" "defaultRenderLayer.rlid"; +connectAttr "session_layer_usda.cl[0]" "top_layer_usda.pl"; +connectAttr "top_layer_usda.sl[0]" "Assembly_room_set_usda.pl"; +connectAttr "Assembly_room_set_usda.sl[0]" "edits_usda.pl"; +connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; +// End of top_layer.ma diff --git a/test/lib/ufe/test-samples/ballset/StandaloneScene/top_layer.usda b/test/lib/ufe/test-samples/ballset/StandaloneScene/top_layer.usda new file mode 100644 index 0000000000..c021f6407c --- /dev/null +++ b/test/lib/ufe/test-samples/ballset/StandaloneScene/top_layer.usda @@ -0,0 +1,9 @@ +#usda 1.0 +( + defaultPrim = "Room_set" + subLayers = [ + @Assembly_room_set.usda@, + @edits.usda@ + ] + upAxis = "Y" +) diff --git a/test/lib/ufe/test-samples/cylinder/cylinder.usda b/test/lib/ufe/test-samples/cylinder/cylinder.usda new file mode 100644 index 0000000000..0196189414 --- /dev/null +++ b/test/lib/ufe/test-samples/cylinder/cylinder.usda @@ -0,0 +1,25 @@ +#usda 1.0 +( + defaultPrim = "pCylinder1" + endTimeCode = 1 + startTimeCode = 1 + upAxis = "Y" +) + +def Mesh "pCylinder1" ( + kind = "component" +) +{ + uniform bool doubleSided = 1 + float3[] extent = [(-1.0000002, -1, -1.0000005), (1, 1, 1.0000001)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] + int[] faceVertexIndices = [0, 1, 21, 20, 1, 2, 22, 21, 2, 3, 23, 22, 3, 4, 24, 23, 4, 5, 25, 24, 5, 6, 26, 25, 6, 7, 27, 26, 7, 8, 28, 27, 8, 9, 29, 28, 9, 10, 30, 29, 10, 11, 31, 30, 11, 12, 32, 31, 12, 13, 33, 32, 13, 14, 34, 33, 14, 15, 35, 34, 15, 16, 36, 35, 16, 17, 37, 36, 17, 18, 38, 37, 18, 19, 39, 38, 19, 0, 20, 39, 1, 0, 40, 2, 1, 40, 3, 2, 40, 4, 3, 40, 5, 4, 40, 6, 5, 40, 7, 6, 40, 8, 7, 40, 9, 8, 40, 10, 9, 40, 11, 10, 40, 12, 11, 40, 13, 12, 40, 14, 13, 40, 15, 14, 40, 16, 15, 40, 17, 16, 40, 18, 17, 40, 19, 18, 40, 0, 19, 40, 20, 21, 41, 21, 22, 41, 22, 23, 41, 23, 24, 41, 24, 25, 41, 25, 26, 41, 26, 27, 41, 27, 28, 41, 28, 29, 41, 29, 30, 41, 30, 31, 41, 31, 32, 41, 32, 33, 41, 33, 34, 41, 34, 35, 41, 35, 36, 41, 36, 37, 41, 37, 38, 41, 38, 39, 41, 39, 20, 41] + point3f[] points = [(0.95105714, -1, -0.30901718), (0.80901754, -1, -0.5877856), (0.5877856, -1, -0.8090175), (0.30901715, -1, -0.951057), (0, -1, -1.0000005), (-0.30901715, -1, -0.95105696), (-0.5877855, -1, -0.8090173), (-0.80901724, -1, -0.5877854), (-0.9510568, -1, -0.30901706), (-1.0000002, -1, 0), (-0.9510568, -1, 0.30901706), (-0.8090172, -1, 0.58778536), (-0.58778536, -1, 0.8090171), (-0.30901706, -1, 0.95105666), (-2.9802322e-8, -1, 1.0000001), (0.30901697, -1, 0.9510566), (0.58778524, -1, 0.80901706), (0.809017, -1, 0.5877853), (0.95105654, -1, 0.309017), (1, -1, 0), (0.95105714, 1, -0.30901718), (0.80901754, 1, -0.5877856), (0.5877856, 1, -0.8090175), (0.30901715, 1, -0.951057), (0, 1, -1.0000005), (-0.30901715, 1, -0.95105696), (-0.5877855, 1, -0.8090173), (-0.80901724, 1, -0.5877854), (-0.9510568, 1, -0.30901706), (-1.0000002, 1, 0), (-0.9510568, 1, 0.30901706), (-0.8090172, 1, 0.58778536), (-0.58778536, 1, 0.8090171), (-0.30901706, 1, 0.95105666), (-2.9802322e-8, 1, 1.0000001), (0.30901697, 1, 0.9510566), (0.58778524, 1, 0.80901706), (0.809017, 1, 0.5877853), (0.95105654, 1, 0.309017), (1, 1, 0), (0, -1, 0), (0, 1, 0)] + color3f[] primvars:displayColor = [(0.21763764, 0.21763764, 0.21763764)] + float2[] primvars:st = [(0.375, 0.3125), (0.3875, 0.3125), (0.3875, 0.68843985), (0.375, 0.68843985), (0.39999998, 0.3125), (0.39999998, 0.68843985), (0.41249996, 0.3125), (0.41249996, 0.68843985), (0.42499995, 0.3125), (0.42499995, 0.68843985), (0.43749994, 0.3125), (0.43749994, 0.68843985), (0.44999993, 0.3125), (0.44999993, 0.68843985), (0.46249992, 0.3125), (0.46249992, 0.68843985), (0.4749999, 0.3125), (0.4749999, 0.68843985), (0.4874999, 0.3125), (0.4874999, 0.68843985), (0.49999988, 0.3125), (0.49999988, 0.68843985), (0.51249987, 0.3125), (0.51249987, 0.68843985), (0.52499986, 0.3125), (0.52499986, 0.68843985), (0.53749985, 0.3125), (0.53749985, 0.68843985), (0.54999983, 0.3125), (0.54999983, 0.68843985), (0.5624998, 0.3125), (0.5624998, 0.68843985), (0.5749998, 0.3125), (0.5749998, 0.68843985), (0.5874998, 0.3125), (0.5874998, 0.68843985), (0.5999998, 0.3125), (0.5999998, 0.68843985), (0.6124998, 0.3125), (0.6124998, 0.68843985), (0.62499976, 0.3125), (0.62499976, 0.68843985), (0.626409, 0.064408496), (0.64860266, 0.107966065), (0.5, 0.15), (0.5918415, 0.02984102), (0.54828393, 0.0076473355), (0.5, -7.4505806e-8), (0.45171607, 0.0076473504), (0.4081585, 0.02984105), (0.37359107, 0.064408526), (0.3513974, 0.10796608), (0.34374997, 0.15625), (0.3513974, 0.20453392), (0.37359107, 0.24809146), (0.40815854, 0.28265893), (0.4517161, 0.3048526), (0.5, 0.3125), (0.5482839, 0.3048526), (0.59184146, 0.28265893), (0.62640893, 0.24809146), (0.6486026, 0.2045339), (0.65625, 0.15625), (0.6486026, 0.89203393), (0.62640893, 0.93559146), (0.5, 0.8375), (0.59184146, 0.97015893), (0.5482839, 0.9923526), (0.5, 1), (0.4517161, 0.9923526), (0.40815854, 0.97015893), (0.37359107, 0.93559146), (0.3513974, 0.89203393), (0.34374997, 0.84375), (0.3513974, 0.79546607), (0.37359107, 0.75190854), (0.4081585, 0.71734107), (0.45171607, 0.69514734), (0.5, 0.68749994), (0.54828393, 0.69514734), (0.5918415, 0.717341), (0.626409, 0.7519085), (0.64860266, 0.79546607), (0.65625, 0.84375)] ( + interpolation = "faceVarying" + ) + int[] primvars:st:indices = [0, 1, 2, 3, 1, 4, 5, 2, 4, 6, 7, 5, 6, 8, 9, 7, 8, 10, 11, 9, 10, 12, 13, 11, 12, 14, 15, 13, 14, 16, 17, 15, 16, 18, 19, 17, 18, 20, 21, 19, 20, 22, 23, 21, 22, 24, 25, 23, 24, 26, 27, 25, 26, 28, 29, 27, 28, 30, 31, 29, 30, 32, 33, 31, 32, 34, 35, 33, 34, 36, 37, 35, 36, 38, 39, 37, 38, 40, 41, 39, 42, 43, 44, 45, 42, 44, 46, 45, 44, 47, 46, 44, 48, 47, 44, 49, 48, 44, 50, 49, 44, 51, 50, 44, 52, 51, 44, 53, 52, 44, 54, 53, 44, 55, 54, 44, 56, 55, 44, 57, 56, 44, 58, 57, 44, 59, 58, 44, 60, 59, 44, 61, 60, 44, 62, 61, 44, 43, 62, 44, 63, 64, 65, 64, 66, 65, 66, 67, 65, 67, 68, 65, 68, 69, 65, 69, 70, 65, 70, 71, 65, 71, 72, 65, 72, 73, 65, 73, 74, 65, 74, 75, 65, 75, 76, 65, 76, 77, 65, 77, 78, 65, 78, 79, 65, 79, 80, 65, 80, 81, 65, 81, 82, 65, 82, 83, 65, 83, 63, 65] +} + + diff --git a/test/lib/ufe/test-samples/cylinder/usdCylinder.ma b/test/lib/ufe/test-samples/cylinder/usdCylinder.ma new file mode 100644 index 0000000000..9db889e6d2 --- /dev/null +++ b/test/lib/ufe/test-samples/cylinder/usdCylinder.ma @@ -0,0 +1,180 @@ +//Maya ASCII 2019ff01 scene +//Name: usdCylinder.ma +//Last modified: Tue, Oct 09, 2018 02:08:44 PM +//Codeset: UTF-8 +requires maya "2019ff01"; +requires -nodeType "mayaUsdProxyShape" "mayaUsdPlugin" "1.0"; +currentUnit -l centimeter -a degree -t film; +fileInfo "application" "maya"; +fileInfo "product" "Maya 2019"; +fileInfo "version" "Preview Release 96"; +fileInfo "cutIdentifier" "201808292000-000000"; +fileInfo "osv" "Linux 3.10.0-327.36.3.el7.x86_64 #1 SMP Mon Oct 24 16:09:20 UTC 2016 x86_64"; +createNode transform -s -n "persp"; + rename -uid "AF670940-0001-842E-5BBD-17C900000278"; + setAttr ".v" no; + setAttr ".t" -type "double3" 28 21 28 ; + setAttr ".r" -type "double3" -27.938352729602379 44.999999999999972 -5.172681101354183e-14 ; +createNode camera -s -n "perspShape" -p "persp"; + rename -uid "AF670940-0001-842E-5BBD-17C900000279"; + setAttr -k off ".v" no; + setAttr ".fl" 34.999999999999993; + setAttr ".coi" 44.82186966202994; + setAttr ".imn" -type "string" "persp"; + setAttr ".den" -type "string" "persp_depth"; + setAttr ".man" -type "string" "persp_mask"; + setAttr ".hc" -type "string" "viewSet -p %camera"; +createNode transform -s -n "top"; + rename -uid "AF670940-0001-842E-5BBD-17C90000027A"; + setAttr ".v" no; + setAttr ".t" -type "double3" 0 1000.1 0 ; + setAttr ".r" -type "double3" -89.999999999999986 0 0 ; +createNode camera -s -n "topShape" -p "top"; + rename -uid "AF670940-0001-842E-5BBD-17C90000027B"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "top"; + setAttr ".den" -type "string" "top_depth"; + setAttr ".man" -type "string" "top_mask"; + setAttr ".hc" -type "string" "viewSet -t %camera"; + setAttr ".o" yes; +createNode transform -s -n "front"; + rename -uid "AF670940-0001-842E-5BBD-17C90000027C"; + setAttr ".v" no; + setAttr ".t" -type "double3" 0 0 1000.1 ; +createNode camera -s -n "frontShape" -p "front"; + rename -uid "AF670940-0001-842E-5BBD-17C90000027D"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "front"; + setAttr ".den" -type "string" "front_depth"; + setAttr ".man" -type "string" "front_mask"; + setAttr ".hc" -type "string" "viewSet -f %camera"; + setAttr ".o" yes; +createNode transform -s -n "side"; + rename -uid "AF670940-0001-842E-5BBD-17C90000027E"; + setAttr ".v" no; + setAttr ".t" -type "double3" 1000.1 0 0 ; + setAttr ".r" -type "double3" 0 89.999999999999986 0 ; +createNode camera -s -n "sideShape" -p "side"; + rename -uid "AF670940-0001-842E-5BBD-17C90000027F"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "side"; + setAttr ".den" -type "string" "side_depth"; + setAttr ".man" -type "string" "side_mask"; + setAttr ".hc" -type "string" "viewSet -s %camera"; + setAttr ".o" yes; +createNode transform -n "mayaUsdTransform"; + rename -uid "AF670940-0001-842E-5BBD-18C200000287"; +createNode mayaUsdProxyShape -n "shape" -p "mayaUsdTransform"; + rename -uid "AF670940-0001-842E-5BBD-18C200000288"; + setAttr -k off ".v"; + setAttr ".covm[0]" 0 1 1; + setAttr ".cdvm[0]" 0 1 1; + setAttr ".fp" -type "string" "./cylinder.usda"; +createNode lightLinker -s -n "lightLinker1"; + rename -uid "AF670940-0001-842E-5BBD-17C900000280"; + setAttr -s 2 ".lnk"; + setAttr -s 2 ".slnk"; +createNode shapeEditorManager -n "shapeEditorManager"; + rename -uid "AF670940-0001-842E-5BBD-17C900000281"; +createNode poseInterpolatorManager -n "poseInterpolatorManager"; + rename -uid "AF670940-0001-842E-5BBD-17C900000282"; +createNode displayLayerManager -n "layerManager"; + rename -uid "AF670940-0001-842E-5BBD-17C900000283"; +createNode displayLayer -n "defaultLayer"; + rename -uid "AF670940-0001-842E-5BBD-17C900000284"; +createNode renderLayerManager -n "renderLayerManager"; + rename -uid "AF670940-0001-842E-5BBD-17C900000285"; +createNode renderLayer -n "defaultRenderLayer"; + rename -uid "AF670940-0001-842E-5BBD-17C900000286"; + setAttr ".g" yes; +createNode script -n "uiConfigurationScriptNode"; + rename -uid "AF670940-0001-842E-5BBD-18DC0000028A"; + setAttr ".b" -type "string" ( + "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n" + + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n" + + " -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n" + + " -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n" + + " -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n" + + " -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n" + + " -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 725\n -height 787\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n" + + " -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 1\n -isSetMember 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n" + + " -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n" + + " -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 1\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n" + + " -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n" + + " -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 1\n -displayInfinities 0\n -displayValues 0\n -autoFit 1\n -autoFitTime 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showResults \"off\" \n -showBufferCurves \"off\" \n -smoothness \"fine\" \n -resultSamples 1\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -showCurveNames 0\n -showActiveCurveNames 0\n" + + " -stackedCurves 0\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -displayNormalized 0\n -preSelectionHighlight 0\n -constrainDrag 0\n -classicMode 1\n -valueLinesToggle 1\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n" + + " -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 1\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n" + + " -displayValues 0\n -autoFit 0\n -autoFitTime 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -displayValues 0\n -autoFit 0\n -autoFitTime 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n" + + " -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -displayValues 0\n -autoFit 0\n -autoFitTime 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n" + + " -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n" + + " -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n" + + " -hasWatchpoint 0\n $editorName;\n\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -connectionStyle \"bezier\" \n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n" + + " -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n" + + "\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n" + + "\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 725\\n -height 787\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 725\\n -height 787\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); + setAttr ".st" 3; +createNode script -n "sceneConfigurationScriptNode"; + rename -uid "AF670940-0001-842E-5BBD-18DC0000028B"; + setAttr ".b" -type "string" "playbackOptions -min 1 -max 120 -ast 1 -aet 200 "; + setAttr ".st" 6; +select -ne :time1; + setAttr ".o" 1; + setAttr ".unw" 1; +select -ne :hardwareRenderingGlobals; + setAttr ".otfna" -type "stringArray" 22 "NURBS Curves" "NURBS Surfaces" "Polygons" "Subdiv Surface" "Particles" "Particle Instance" "Fluids" "Strokes" "Image Planes" "UI" "Lights" "Cameras" "Locators" "Joints" "IK Handles" "Deformers" "Motion Trails" "Components" "Hair Systems" "Follicles" "Misc. UI" "Ornaments" ; + setAttr ".otfva" -type "Int32Array" 22 0 1 1 1 1 1 + 1 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 ; + setAttr ".fprt" yes; +select -ne :renderPartition; + setAttr -s 2 ".st"; +select -ne :renderGlobalsList1; +select -ne :defaultShaderList1; + setAttr -s 4 ".s"; +select -ne :postProcessList1; + setAttr -s 2 ".p"; +select -ne :defaultRenderingList1; +select -ne :initialShadingGroup; + setAttr ".ro" yes; +select -ne :initialParticleSE; + setAttr ".ro" yes; +select -ne :defaultResolution; + setAttr ".pa" 1; +select -ne :hardwareRenderGlobals; + setAttr ".ctrs" 256; + setAttr ".btrs" 512; +relationship "link" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; +relationship "link" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; +relationship "shadowLink" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; +relationship "shadowLink" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; +connectAttr "layerManager.dli[0]" "defaultLayer.id"; +connectAttr "renderLayerManager.rlmi[0]" "defaultRenderLayer.rlid"; +connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; +// End of usdCylinder.ma diff --git a/test/lib/ufe/test-samples/twoSpheres/sphere.usda b/test/lib/ufe/test-samples/twoSpheres/sphere.usda new file mode 100644 index 0000000000..317fa71a9c --- /dev/null +++ b/test/lib/ufe/test-samples/twoSpheres/sphere.usda @@ -0,0 +1,20 @@ +#usda 1.0 +( + defaultPrim = "sphereXform" + endTimeCode = 1 + startTimeCode = 1 + upAxis = "Y" +) + +def Xform "sphereXform" +{ + double3 xformOp:translate = (10.0, 0.0, 0.0) + uniform token[] xformOpOrder = ["xformOp:translate"] + + def Sphere "sphere" + { + double radius = 2 + float3[] extent = [(-2, -2, -2), (2, 2, 2)] + color3f[] primvars:displayColor = [(0, 1, 0)] + } +} diff --git a/test/lib/ufe/test-samples/twoSpheres/twoSpheres.ma b/test/lib/ufe/test-samples/twoSpheres/twoSpheres.ma new file mode 100644 index 0000000000..d93fd97e05 --- /dev/null +++ b/test/lib/ufe/test-samples/twoSpheres/twoSpheres.ma @@ -0,0 +1,198 @@ +//Maya ASCII 2019ff01 scene +//Name: sphere.ma +//Last modified: Thu, Jun 28, 2018 11:33:30 AM +//Codeset: UTF-8 +requires maya "2019ff01"; +requires -nodeType "mayaUsdProxyShape" "mayaUsdPlugin" "1.0"; +currentUnit -l centimeter -a degree -t film; +fileInfo "application" "maya"; +fileInfo "product" "Maya 2019"; +fileInfo "version" "Preview Release 94"; +fileInfo "cutIdentifier" "201805091219-000000"; +fileInfo "osv" "Linux 3.10.0-327.36.3.el7.x86_64 #1 SMP Mon Oct 24 16:09:20 UTC 2016 x86_64"; +createNode transform -s -n "persp"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000233"; + setAttr ".v" no; + setAttr ".t" -type "double3" 27.999999999998366 20.999999999998771 27.999999999998366 ; + setAttr ".r" -type "double3" -27.938352729602379 44.999999999999972 -5.172681101354183e-14 ; +createNode camera -s -n "perspShape" -p "persp"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000234"; + setAttr -k off ".v" no; + setAttr ".fl" 34.999999999999993; + setAttr ".coi" 44.821869662027325; + setAttr ".imn" -type "string" "persp"; + setAttr ".den" -type "string" "persp_depth"; + setAttr ".man" -type "string" "persp_mask"; + setAttr ".hc" -type "string" "viewSet -p %camera"; +createNode transform -s -n "top"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000235"; + setAttr ".v" no; + setAttr ".t" -type "double3" 0 1000.1 0 ; + setAttr ".r" -type "double3" -89.999999999999986 0 0 ; +createNode camera -s -n "topShape" -p "top"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000236"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "top"; + setAttr ".den" -type "string" "top_depth"; + setAttr ".man" -type "string" "top_mask"; + setAttr ".hc" -type "string" "viewSet -t %camera"; + setAttr ".o" yes; +createNode transform -s -n "front"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000237"; + setAttr ".v" no; + setAttr ".t" -type "double3" 0 0 1000.1 ; +createNode camera -s -n "frontShape" -p "front"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000238"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "front"; + setAttr ".den" -type "string" "front_depth"; + setAttr ".man" -type "string" "front_mask"; + setAttr ".hc" -type "string" "viewSet -f %camera"; + setAttr ".o" yes; +createNode transform -s -n "side"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D700000239"; + setAttr ".v" no; + setAttr ".t" -type "double3" 1000.1 0 0 ; + setAttr ".r" -type "double3" 0 89.999999999999986 0 ; +createNode camera -s -n "sideShape" -p "side"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D70000023A"; + setAttr -k off ".v" no; + setAttr ".rnd" no; + setAttr ".coi" 1000.1; + setAttr ".ow" 30; + setAttr ".imn" -type "string" "side"; + setAttr ".den" -type "string" "side_depth"; + setAttr ".man" -type "string" "side_mask"; + setAttr ".hc" -type "string" "viewSet -s %camera"; + setAttr ".o" yes; +createNode transform -n "usdSphereParent"; + rename -uid "F6E7E9C0-0001-E018-5B35-235600000256"; +createNode mayaUsdProxyShape -n "usdSphereParentShape" -p "usdSphereParent"; + rename -uid "F6E7E9C0-0001-E018-5B35-237400000257"; + setAttr -k off ".v"; + setAttr ".covm[0]" 0 1 1; + setAttr ".cdvm[0]" 0 1 1; + setAttr ".fp" -type "string" "./sphere.usda"; +createNode transform -n "mayaSphere"; + rename -uid "818719C0-0000-0CDD-5B35-295D0000026C"; + setAttr ".t" -type "double3" 10 0 10 ; +createNode mesh -n "mayaSphereShape" -p "mayaSphere"; + rename -uid "818719C0-0000-0CDD-5B35-295D0000026B"; + setAttr -k off ".v"; + setAttr ".vir" yes; + setAttr ".vif" yes; + setAttr ".uvst[0].uvsn" -type "string" "map1"; + setAttr ".cuvs" -type "string" "map1"; + setAttr ".dcc" -type "string" "Ambient+Diffuse"; + setAttr ".covm[0]" 0 1 1; + setAttr ".cdvm[0]" 0 1 1; +createNode lightLinker -s -n "lightLinker1"; + rename -uid "818719C0-0000-0CDD-5B35-29D9000002AE"; + setAttr -s 2 ".lnk"; + setAttr -s 2 ".slnk"; +createNode shapeEditorManager -n "shapeEditorManager"; + rename -uid "818719C0-0000-0CDD-5B35-29D9000002AF"; +createNode poseInterpolatorManager -n "poseInterpolatorManager"; + rename -uid "818719C0-0000-0CDD-5B35-29D9000002B0"; +createNode displayLayerManager -n "layerManager"; + rename -uid "818719C0-0000-0CDD-5B35-29D9000002B1"; +createNode displayLayer -n "defaultLayer"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D800000253"; +createNode renderLayerManager -n "renderLayerManager"; + rename -uid "818719C0-0000-0CDD-5B35-29D9000002B3"; +createNode renderLayer -n "defaultRenderLayer"; + rename -uid "F6E7E9C0-0001-E018-5B35-22D800000255"; + setAttr ".g" yes; +createNode script -n "uiConfigurationScriptNode"; + rename -uid "F6E7E9C0-0001-E018-5B35-263900000259"; + setAttr ".b" -type "string" ( + "// Maya Mel UI Configuration File.\n//\n// This script is machine generated. Edit at your own risk.\n//\n//\n\nglobal string $gMainPane;\nif (`paneLayout -exists $gMainPane`) {\n\n\tglobal int $gUseScenePanelConfig;\n\tint $useSceneConfig = $gUseScenePanelConfig;\n\tint $nodeEditorPanelVisible = stringArrayContains(\"nodeEditorPanel1\", `getPanel -vis`);\n\tint $nodeEditorWorkspaceControlOpen = (`workspaceControl -exists nodeEditorPanel1Window` && `workspaceControl -q -visible nodeEditorPanel1Window`);\n\tint $menusOkayInPanels = `optionVar -q allowMenusInPanels`;\n\tint $nVisPanes = `paneLayout -q -nvp $gMainPane`;\n\tint $nPanes = 0;\n\tstring $editorName;\n\tstring $panelName;\n\tstring $itemFilterName;\n\tstring $panelConfig;\n\n\t//\n\t// get current state of the UI\n\t//\n\tsceneUIReplacement -update $gMainPane;\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Top View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Top View\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"top\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n" + + " -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n" + + " -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Side View\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Side View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"side\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n" + + " -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n" + + " -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n" + + "\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Front View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Front View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"front\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n" + + " -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n" + + " -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n" + + " -width 1\n -height 1\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"modelPanel\" (localizedPanelLabel(\"Persp View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tmodelPanel -edit -l (localizedPanelLabel(\"Persp View\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n modelEditor -e \n -camera \"persp\" \n -useInteractiveMode 0\n -displayLights \"default\" \n -displayAppearance \"smoothShaded\" \n -activeOnly 0\n -ignorePanZoom 0\n -wireframeOnShaded 0\n -headsUpDisplay 1\n -holdOuts 1\n -selectionHiliteDisplay 1\n -useDefaultMaterial 0\n -bufferMode \"double\" \n -twoSidedLighting 0\n -backfaceCulling 0\n -xray 0\n -jointXray 0\n" + + " -activeComponentsXray 0\n -displayTextures 0\n -smoothWireframe 0\n -lineWidth 1\n -textureAnisotropic 0\n -textureHilight 1\n -textureSampling 2\n -textureDisplay \"modulate\" \n -textureMaxSize 16384\n -fogging 0\n -fogSource \"fragment\" \n -fogMode \"linear\" \n -fogStart 0\n -fogEnd 100\n -fogDensity 0.1\n -fogColor 0.5 0.5 0.5 1 \n -depthOfFieldPreview 1\n -maxConstantTransparency 1\n -rendererName \"vp2Renderer\" \n -objectFilterShowInHUD 1\n -isFiltered 0\n -colorResolution 256 256 \n -bumpResolution 512 512 \n -textureCompression 0\n -transparencyAlgorithm \"frontAndBackCull\" \n -transpInShadows 0\n -cullingOverride \"none\" \n -lowQualityLighting 0\n -maximumNumHardwareLights 1\n -occlusionCulling 0\n -shadingModel 0\n" + + " -useBaseRenderer 0\n -useReducedRenderer 0\n -smallObjectCulling 0\n -smallObjectThreshold -1 \n -interactiveDisableShadows 0\n -interactiveBackFaceCull 0\n -sortTransparent 1\n -controllers 1\n -nurbsCurves 1\n -nurbsSurfaces 1\n -polymeshes 1\n -subdivSurfaces 1\n -planes 1\n -lights 1\n -cameras 1\n -controlVertices 1\n -hulls 1\n -grid 1\n -imagePlane 1\n -joints 1\n -ikHandles 1\n -deformers 1\n -dynamics 1\n -particleInstancers 1\n -fluids 1\n -hairSystems 1\n -follicles 1\n -nCloths 1\n -nParticles 1\n -nRigids 1\n -dynamicConstraints 1\n -locators 1\n -manipulators 1\n -pluginShapes 1\n -dimensions 1\n -handles 1\n -pivots 1\n -textures 1\n" + + " -strokes 1\n -motionTrails 1\n -clipGhosts 1\n -greasePencils 1\n -shadows 0\n -captureSequenceNumber -1\n -width 456\n -height 670\n -sceneRenderFilter 0\n $editorName;\n modelEditor -e -viewSelected 0 $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"ToggledOutliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"ToggledOutliner\")) -mbv $menusOkayInPanels $panelName;\n\t\t$editorName = $panelName;\n outlinerEditor -e \n -docTag \"isolOutln_fromSeln\" \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n" + + " -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -isSet 0\n -isSetMember 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n" + + " -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n -renderFilterIndex 0\n -selectionOrder \"chronological\" \n -expandAttribute 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"outlinerPanel\" (localizedPanelLabel(\"Outliner\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\toutlinerPanel -edit -l (localizedPanelLabel(\"Outliner\")) -mbv $menusOkayInPanels $panelName;\n" + + "\t\t$editorName = $panelName;\n outlinerEditor -e \n -showShapes 0\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 0\n -showConnected 0\n -showAnimCurvesOnly 0\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 1\n -showAssets 1\n -showContainedOnly 1\n -showPublishedAsConnected 0\n -showParentContainers 0\n -showContainerContents 1\n -ignoreDagHierarchy 0\n -expandConnections 0\n -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 0\n -highlightActive 1\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 0\n -dropIsParent 1\n" + + " -transmitFilters 0\n -setFilter \"defaultSetFilter\" \n -showSetMembers 1\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 0\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"graphEditor\" (localizedPanelLabel(\"Graph Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Graph Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 1\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 1\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n" + + " -showUpstreamCurves 1\n -showUnitlessCurves 1\n -showCompounds 0\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 1\n -doNotSelectNewObjects 0\n -dropIsParent 1\n -transmitFilters 1\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n" + + " -niceNames 1\n -showNamespace 1\n -showPinIcons 1\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"GraphEd\");\n animCurveEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 1\n -displayInfinities 0\n -displayValues 0\n -autoFit 1\n -autoFitTime 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -showResults \"off\" \n -showBufferCurves \"off\" \n -smoothness \"fine\" \n -resultSamples 1\n -resultScreenSamples 0\n -resultUpdate \"delayed\" \n -showUpstreamCurves 1\n -showCurveNames 0\n -showActiveCurveNames 0\n" + + " -stackedCurves 0\n -stackedCurvesMin -1\n -stackedCurvesMax 1\n -stackedCurvesSpace 0.2\n -displayNormalized 0\n -preSelectionHighlight 0\n -constrainDrag 0\n -classicMode 1\n -valueLinesToggle 1\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dopeSheetPanel\" (localizedPanelLabel(\"Dope Sheet\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dope Sheet\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"OutlineEd\");\n outlinerEditor -e \n -showShapes 1\n -showAssignedMaterials 0\n -showTimeEditor 1\n -showReferenceNodes 0\n -showReferenceMembers 0\n -showAttributes 1\n -showConnected 1\n -showAnimCurvesOnly 1\n" + + " -showMuteInfo 0\n -organizeByLayer 1\n -organizeByClip 1\n -showAnimLayerWeight 1\n -autoExpandLayers 1\n -autoExpand 0\n -showDagOnly 0\n -showAssets 1\n -showContainedOnly 0\n -showPublishedAsConnected 0\n -showParentContainers 1\n -showContainerContents 0\n -ignoreDagHierarchy 0\n -expandConnections 1\n -showUpstreamCurves 1\n -showUnitlessCurves 0\n -showCompounds 1\n -showLeafs 1\n -showNumericAttrsOnly 1\n -highlightActive 0\n -autoSelectNewObjects 0\n -doNotSelectNewObjects 1\n -dropIsParent 1\n -transmitFilters 0\n -setFilter \"0\" \n -showSetMembers 0\n -allowMultiSelection 1\n -alwaysToggleSelect 0\n -directSelect 0\n" + + " -displayMode \"DAG\" \n -expandObjects 0\n -setsIgnoreFilters 1\n -containersIgnoreFilters 0\n -editAttrName 0\n -showAttrValues 0\n -highlightSecondary 0\n -showUVAttrsOnly 0\n -showTextureNodesOnly 0\n -attrAlphaOrder \"default\" \n -animLayerFilterOptions \"allAffecting\" \n -sortOrder \"none\" \n -longNames 0\n -niceNames 1\n -showNamespace 1\n -showPinIcons 0\n -mapMotionTrails 1\n -ignoreHiddenAttribute 0\n -ignoreOutlinerColor 0\n -renderFilterVisible 0\n $editorName;\n\n\t\t\t$editorName = ($panelName+\"DopeSheetEd\");\n dopeSheetEditor -e \n -displayKeys 1\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n" + + " -displayValues 0\n -autoFit 0\n -autoFitTime 0\n -snapTime \"integer\" \n -snapValue \"none\" \n -outliner \"dopeSheetPanel1OutlineEd\" \n -showSummary 1\n -showScene 0\n -hierarchyBelow 0\n -showTicks 1\n -selectionWindow 0 0 0 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"timeEditorPanel\" (localizedPanelLabel(\"Time Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Time Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"clipEditorPanel\" (localizedPanelLabel(\"Trax Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Trax Editor\")) -mbv $menusOkayInPanels $panelName;\n" + + "\n\t\t\t$editorName = clipEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -displayValues 0\n -autoFit 0\n -autoFitTime 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 0 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"sequenceEditorPanel\" (localizedPanelLabel(\"Camera Sequencer\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Camera Sequencer\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = sequenceEditorNameFromPanel($panelName);\n clipEditor -e \n -displayKeys 0\n -displayTangents 0\n" + + " -displayActiveKeys 0\n -displayActiveKeyTangents 0\n -displayInfinities 0\n -displayValues 0\n -autoFit 0\n -autoFitTime 0\n -snapTime \"none\" \n -snapValue \"none\" \n -initialized 0\n -manageSequencer 1 \n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperGraphPanel\" (localizedPanelLabel(\"Hypergraph Hierarchy\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypergraph Hierarchy\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"HyperGraphEd\");\n hyperGraph -e \n -graphLayoutStyle \"hierarchicalLayout\" \n -orientation \"horiz\" \n -mergeConnections 0\n -zoom 1\n -animateTransition 0\n -showRelationships 1\n" + + " -showShapes 0\n -showDeformers 0\n -showExpressions 0\n -showConstraints 0\n -showConnectionFromSelected 0\n -showConnectionToSelected 0\n -showConstraintLabels 0\n -showUnderworld 0\n -showInvisible 0\n -transitionFrames 1\n -opaqueContainers 0\n -freeform 0\n -imagePosition 0 0 \n -imageScale 1\n -imageEnabled 0\n -graphType \"DAG\" \n -heatMapDisplay 0\n -updateSelection 1\n -updateNodeAdded 1\n -useDrawOverrideColor 0\n -limitGraphTraversal -1\n -range 0 0 \n -iconSize \"smallIcons\" \n -showCachedConnections 0\n $editorName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"hyperShadePanel\" (localizedPanelLabel(\"Hypershade\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Hypershade\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"visorPanel\" (localizedPanelLabel(\"Visor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Visor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"nodeEditorPanel\" (localizedPanelLabel(\"Node Editor\")) `;\n\tif ($nodeEditorPanelVisible || $nodeEditorWorkspaceControlOpen) {\n\t\tif (\"\" == $panelName) {\n\t\t\tif ($useSceneConfig) {\n\t\t\t\t$panelName = `scriptedPanel -unParent -type \"nodeEditorPanel\" -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels `;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n" + + " -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n" + + "\t\t\t}\n\t\t} else {\n\t\t\t$label = `panel -q -label $panelName`;\n\t\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Node Editor\")) -mbv $menusOkayInPanels $panelName;\n\n\t\t\t$editorName = ($panelName+\"NodeEditorEd\");\n nodeEditor -e \n -allAttributes 0\n -allNodes 0\n -autoSizeNodes 1\n -consistentNameSize 1\n -createNodeCommand \"nodeEdCreateNodeCommand\" \n -connectNodeOnCreation 0\n -connectOnDrop 0\n -copyConnectionsOnPaste 0\n -defaultPinnedState 0\n -additiveGraphingMode 0\n -settingsChangedCallback \"nodeEdSyncControls\" \n -traversalDepthLimit -1\n -keyPressCommand \"nodeEdKeyPressCommand\" \n -nodeTitleMode \"name\" \n -gridSnap 0\n -gridVisibility 1\n -crosshairOnEdgeDragging 0\n -popupMenuScript \"nodeEdBuildPanelMenus\" \n -showNamespace 1\n -showShapes 1\n" + + " -showSGShapes 0\n -showTransforms 1\n -useAssets 1\n -syncedSelection 1\n -extendToShapes 1\n -editorMode \"default\" \n -hasWatchpoint 0\n $editorName;\n\t\t\tif (!$useSceneConfig) {\n\t\t\t\tpanel -e -l $label $panelName;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"createNodePanel\" (localizedPanelLabel(\"Create Node\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Create Node\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"polyTexturePlacementPanel\" (localizedPanelLabel(\"UV Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"UV Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n" + + "\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"renderWindowPanel\" (localizedPanelLabel(\"Render View\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Render View\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"shapePanel\" (localizedPanelLabel(\"Shape Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tshapePanel -edit -l (localizedPanelLabel(\"Shape Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextPanel \"posePanel\" (localizedPanelLabel(\"Pose Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tposePanel -edit -l (localizedPanelLabel(\"Pose Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynRelEdPanel\" (localizedPanelLabel(\"Dynamic Relationships\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Dynamic Relationships\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"relationshipPanel\" (localizedPanelLabel(\"Relationship Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Relationship Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"referenceEditorPanel\" (localizedPanelLabel(\"Reference Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Reference Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"componentEditorPanel\" (localizedPanelLabel(\"Component Editor\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Component Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"dynPaintScriptedPanelType\" (localizedPanelLabel(\"Paint Effects\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Paint Effects\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"scriptEditorPanel\" (localizedPanelLabel(\"Script Editor\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Script Editor\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"profilerPanel\" (localizedPanelLabel(\"Profiler Tool\")) `;\n" + + "\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Profiler Tool\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\t$panelName = `sceneUIReplacement -getNextScriptedPanel \"contentBrowserPanel\" (localizedPanelLabel(\"Content Browser\")) `;\n\tif (\"\" != $panelName) {\n\t\t$label = `panel -q -label $panelName`;\n\t\tscriptedPanel -edit -l (localizedPanelLabel(\"Content Browser\")) -mbv $menusOkayInPanels $panelName;\n\t\tif (!$useSceneConfig) {\n\t\t\tpanel -e -l $label $panelName;\n\t\t}\n\t}\n\n\n\tif ($useSceneConfig) {\n string $configName = `getPanel -cwl (localizedPanelLabel(\"Current Layout\"))`;\n if (\"\" != $configName) {\n\t\t\tpanelConfiguration -edit -label (localizedPanelLabel(\"Current Layout\")) \n\t\t\t\t-userCreated false\n\t\t\t\t-defaultImage \"vacantCell.xP:/\"\n\t\t\t\t-image \"\"\n\t\t\t\t-sc false\n\t\t\t\t-configString \"global string $gMainPane; paneLayout -e -cn \\\"single\\\" -ps 1 100 100 $gMainPane;\"\n\t\t\t\t-removeAllPanels\n\t\t\t\t-ap false\n" + + "\t\t\t\t\t(localizedPanelLabel(\"Persp View\")) \n\t\t\t\t\t\"modelPanel\"\n" + + "\t\t\t\t\t\"$panelName = `modelPanel -unParent -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels `;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 456\\n -height 670\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t\t\"modelPanel -edit -l (localizedPanelLabel(\\\"Persp View\\\")) -mbv $menusOkayInPanels $panelName;\\n$editorName = $panelName;\\nmodelEditor -e \\n -cam `findStartUpCamera persp` \\n -useInteractiveMode 0\\n -displayLights \\\"default\\\" \\n -displayAppearance \\\"smoothShaded\\\" \\n -activeOnly 0\\n -ignorePanZoom 0\\n -wireframeOnShaded 0\\n -headsUpDisplay 1\\n -holdOuts 1\\n -selectionHiliteDisplay 1\\n -useDefaultMaterial 0\\n -bufferMode \\\"double\\\" \\n -twoSidedLighting 0\\n -backfaceCulling 0\\n -xray 0\\n -jointXray 0\\n -activeComponentsXray 0\\n -displayTextures 0\\n -smoothWireframe 0\\n -lineWidth 1\\n -textureAnisotropic 0\\n -textureHilight 1\\n -textureSampling 2\\n -textureDisplay \\\"modulate\\\" \\n -textureMaxSize 16384\\n -fogging 0\\n -fogSource \\\"fragment\\\" \\n -fogMode \\\"linear\\\" \\n -fogStart 0\\n -fogEnd 100\\n -fogDensity 0.1\\n -fogColor 0.5 0.5 0.5 1 \\n -depthOfFieldPreview 1\\n -maxConstantTransparency 1\\n -rendererName \\\"vp2Renderer\\\" \\n -objectFilterShowInHUD 1\\n -isFiltered 0\\n -colorResolution 256 256 \\n -bumpResolution 512 512 \\n -textureCompression 0\\n -transparencyAlgorithm \\\"frontAndBackCull\\\" \\n -transpInShadows 0\\n -cullingOverride \\\"none\\\" \\n -lowQualityLighting 0\\n -maximumNumHardwareLights 1\\n -occlusionCulling 0\\n -shadingModel 0\\n -useBaseRenderer 0\\n -useReducedRenderer 0\\n -smallObjectCulling 0\\n -smallObjectThreshold -1 \\n -interactiveDisableShadows 0\\n -interactiveBackFaceCull 0\\n -sortTransparent 1\\n -controllers 1\\n -nurbsCurves 1\\n -nurbsSurfaces 1\\n -polymeshes 1\\n -subdivSurfaces 1\\n -planes 1\\n -lights 1\\n -cameras 1\\n -controlVertices 1\\n -hulls 1\\n -grid 1\\n -imagePlane 1\\n -joints 1\\n -ikHandles 1\\n -deformers 1\\n -dynamics 1\\n -particleInstancers 1\\n -fluids 1\\n -hairSystems 1\\n -follicles 1\\n -nCloths 1\\n -nParticles 1\\n -nRigids 1\\n -dynamicConstraints 1\\n -locators 1\\n -manipulators 1\\n -pluginShapes 1\\n -dimensions 1\\n -handles 1\\n -pivots 1\\n -textures 1\\n -strokes 1\\n -motionTrails 1\\n -clipGhosts 1\\n -greasePencils 1\\n -shadows 0\\n -captureSequenceNumber -1\\n -width 456\\n -height 670\\n -sceneRenderFilter 0\\n $editorName;\\nmodelEditor -e -viewSelected 0 $editorName\"\n" + + "\t\t\t\t$configName;\n\n setNamedPanelLayout (localizedPanelLabel(\"Current Layout\"));\n }\n\n panelHistory -e -clear mainPanelHistory;\n sceneUIReplacement -clear;\n\t}\n\n\ngrid -spacing 5 -size 12 -divisions 5 -displayAxes yes -displayGridLines yes -displayDivisionLines yes -displayPerspectiveLabels no -displayOrthographicLabels no -displayAxesBold yes -perspectiveLabelPosition axis -orthographicLabelPosition edge;\nviewManip -drawCompass 0 -compassAngle 0 -frontParameters \"\" -homeParameters \"\" -selectionLockParameters \"\";\n}\n"); + setAttr ".st" 3; +createNode script -n "sceneConfigurationScriptNode"; + rename -uid "F6E7E9C0-0001-E018-5B35-26390000025A"; + setAttr ".b" -type "string" "playbackOptions -min 1 -max 120 -ast 1 -aet 200 "; + setAttr ".st" 6; +createNode polySphere -n "polySphere1"; + rename -uid "818719C0-0000-0CDD-5B35-295D0000026A"; + setAttr ".r" 2; +select -ne :time1; + setAttr ".o" 1; + setAttr ".unw" 1; +select -ne :hardwareRenderingGlobals; + setAttr ".otfna" -type "stringArray" 22 "NURBS Curves" "NURBS Surfaces" "Polygons" "Subdiv Surface" "Particles" "Particle Instance" "Fluids" "Strokes" "Image Planes" "UI" "Lights" "Cameras" "Locators" "Joints" "IK Handles" "Deformers" "Motion Trails" "Components" "Hair Systems" "Follicles" "Misc. UI" "Ornaments" ; + setAttr ".otfva" -type "Int32Array" 22 0 1 1 1 1 1 + 1 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 ; + setAttr ".fprt" yes; +select -ne :renderPartition; + setAttr -s 2 ".st"; +select -ne :renderGlobalsList1; +select -ne :defaultShaderList1; + setAttr -s 4 ".s"; +select -ne :postProcessList1; + setAttr -s 2 ".p"; +select -ne :defaultRenderingList1; +select -ne :initialShadingGroup; + setAttr ".ro" yes; +select -ne :initialParticleSE; + setAttr ".ro" yes; +select -ne :defaultResolution; + setAttr ".pa" 1; +select -ne :hardwareRenderGlobals; + setAttr ".ctrs" 256; + setAttr ".btrs" 512; +connectAttr "polySphere1.out" "mayaSphereShape.i"; +relationship "link" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; +relationship "link" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; +relationship "shadowLink" ":lightLinker1" ":initialShadingGroup.message" ":defaultLightSet.message"; +relationship "shadowLink" ":lightLinker1" ":initialParticleSE.message" ":defaultLightSet.message"; +connectAttr "layerManager.dli[0]" "defaultLayer.id"; +connectAttr "renderLayerManager.rlmi[0]" "defaultRenderLayer.rlid"; +connectAttr "defaultRenderLayer.msg" ":defaultRenderingList1.r" -na; +connectAttr "mayaSphereShape.iog" ":initialShadingGroup.dsm" -na; +// End of sphere.ma diff --git a/test/lib/ufe/testAttribute.py b/test/lib/ufe/testAttribute.py new file mode 100644 index 0000000000..8d3b5381cc --- /dev/null +++ b/test/lib/ufe/testAttribute.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +from ufeTestUtils import usdUtils, mayaUtils +import ufe +from pxr import UsdGeom +import random + +import unittest + +class AttributeTestCase(unittest.TestCase): + '''Verify the Attribute UFE interface, for multiple runtimes. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + random.seed() + + def setUp(self): + '''Called initially to set up the maya test environment''' + self.assertTrue(self.pluginsLoaded) + + def assertVectorAlmostEqual(self, ufeVector, usdVector): + for va, vb in zip(ufeVector.vector, usdVector): + self.assertAlmostEqual(va, vb, places=6) + + def assertColorAlmostEqual(self, ufeColor, usdColor): + for va, vb in zip(ufeColor.color, usdColor): + self.assertAlmostEqual(va, vb, places=6) + + def runTestAttribute(self, path, attrName, ufeAttrClass, ufeAttrType): + '''Engine method to run attribute test.''' + + # Create the UFE/USD attribute for this test from the input path. + + # Get a UFE scene item the input path in the scene. + itemPath = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment(path)]) + ufeItem = ufe.Hierarchy.createItem(itemPath) + + # Get the USD prim for this item. + usdPrim = usdUtils.getPrimFromSceneItem(ufeItem) + + # Create the attributes interface for the item. + ufeAttrs = ufe.Attributes.attributes(ufeItem) + self.assertIsNotNone(ufeAttrs) + + # Get the USDAttribute for the input attribute name so we can use it to + # compare to UFE. + usdAttr = usdPrim.GetAttribute(attrName) + self.assertIsNotNone(usdAttr) + + # Get the attribute that matches the input name and make sure it matches + # the class type of UFE attribute class passed in. + self.assertTrue(ufeAttrs.hasAttribute(attrName)) + ufeAttr = ufeAttrs.attribute(attrName) + self.assertIsInstance(ufeAttr, ufeAttrClass) + + # Verify that the attribute type matches the input UFE type. + self.assertEqual(ufeAttr.type, ufeAttrType) + + # Verify that the scene item the attribute was created with matches + # what is stored in the UFE attribute. + self.assertEqual(ufeAttr.sceneItem(), ufeItem) + + # Verify that this attribute has a value. Note: all the attributes that + # are tested by this method are assumed to have a value. + self.assertTrue(ufeAttr.hasValue()) + + # Verify that the name matched what we created the attribute from. + self.assertEqual(ufeAttr.name, attrName) + + # Test that the string representation of the value is not empty. + self.assertTrue(str(ufeAttr)) + + return ufeAttr, usdAttr + + def testAttributeGeneric(self): + '''Test the Generic attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the xformOpOrder attribute which is + # an unsupported USD type, so it will be a UFE Generic attribute. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35', + attrName=UsdGeom.Tokens.xformOpOrder, + ufeAttrClass=ufe.AttributeGeneric, + ufeAttrType=ufe.Attribute.kGeneric) + + # Now we test the Generic specific methods. + self.assertEqual(ufeAttr.nativeType(), usdAttr.GetTypeName().type.typeName) + + def testAttributeEnumString(self): + '''Test the EnumString attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an EnumString type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35', + attrName=UsdGeom.Tokens.visibility, + ufeAttrClass=ufe.AttributeEnumString, + ufeAttrType=ufe.Attribute.kEnumString) + + # Now we test the EnumString specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + # Make sure 'inherited' is in the list of allowed tokens. + visEnumValues = ufeAttr.getEnumValues() + self.assertIn(UsdGeom.Tokens.inherited, visEnumValues) + + # Change to 'invisible' and verify the return in UFE. + ufeAttr.set(UsdGeom.Tokens.invisible) + self.assertEqual(ufeAttr.get(), UsdGeom.Tokens.invisible) + + # Verify that the new UFE value matches what is directly in USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + def testAttributeBool(self): + '''Test the Bool attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an bool type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/mesh', + attrName='doubleSided', + ufeAttrClass=ufe.AttributeBool, + ufeAttrType=ufe.Attribute.kBool) + + # Now we test the Bool specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with the opposite boolean value. + ufeAttr.set(not ufeAttr.get()) + + # Then make sure that new UFE value matches what it in USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + def testAttributeInt(self): + '''Test the Int attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an integer type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/Looks/BallLook/Base', + attrName='inputAOV', + ufeAttrClass=ufe.AttributeInt, + ufeAttrType=ufe.Attribute.kInt) + + # Now we test the Int specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with a different int value. + ufeAttr.set(ufeAttr.get() + random.randint(1,5)) + + # Then make sure that new UFE value matches what it in USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + def testAttributeFloat(self): + '''Test the Float attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an float type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/Looks/BallLook/Base', + attrName='anisotropic', + ufeAttrClass=ufe.AttributeFloat, + ufeAttrType=ufe.Attribute.kFloat) + + # Now we test the Float specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with a different float value. + ufeAttr.set(random.random()) + + # Then make sure that new UFE value matches what it in USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + def _testAttributeDouble(self): + '''Test the Double attribute type.''' + + # I could not find an double attribute to test with + pass + + def testAttributeStringString(self): + '''Test the String (String) attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an string type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/Looks/BallLook/BallTexture', + attrName='filename', + ufeAttrClass=ufe.AttributeString, + ufeAttrType=ufe.Attribute.kString) + + # Now we test the String specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with a different string value. + # Note: this ball uses the ball8.tex + ufeAttr.set('./tex/ball7.tex') + + # Then make sure that new UFE value matches what it in USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + def testAttributeStringToken(self): + '''Test the String (Token) attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an string type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/Looks/BallLook/BallTexture', + attrName='filter', + ufeAttrClass=ufe.AttributeString, + ufeAttrType=ufe.Attribute.kString) + + # Now we test the String specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with a different string value. + # Note: this attribute is initially set to token 'Box' + ufeAttr.set('Sphere') + + # Then make sure that new UFE value matches what it in USD. + self.assertEqual(ufeAttr.get(), usdAttr.Get()) + + def testAttributeColorFloat3(self): + '''Test the ColorFloat3 attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an ColorFloat3 type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/Looks/BallLook/Base', + attrName='emitColor', + ufeAttrClass=ufe.AttributeColorFloat3, + ufeAttrType=ufe.Attribute.kColorFloat3) + + # Now we test the ColorFloat3 specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertColorAlmostEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with some random color values. + vec = ufe.Color3f(random.random(), random.random(), random.random()) + ufeAttr.set(vec) + + # Then make sure that new UFE value matches what it in USD. + self.assertColorAlmostEqual(ufeAttr.get(), usdAttr.Get()) + + def _testAttributeInt3(self): + '''Test the Int3 attribute type.''' + + # I could not find an int3 attribute to test with. + pass + + def testAttributeFloat3(self): + '''Test the Float3 attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an Float3 type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35/Looks/BallLook/Base', + attrName='bumpNormal', + ufeAttrClass=ufe.AttributeFloat3, + ufeAttrType=ufe.Attribute.kFloat3) + + # Now we test the Float3 specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertVectorAlmostEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with some random color values. + vec = ufe.Vector3f(random.random(), random.random(), random.random()) + ufeAttr.set(vec) + + # Then make sure that new UFE value matches what it in USD. + self.assertVectorAlmostEqual(ufeAttr.get(), usdAttr.Get()) + + def testAttributeDouble3(self): + '''Test the Double3 attribute type.''' + + # Use our engine method to run the bulk of the test (all the stuff from + # the Attribute base class). We use the visibility attribute which is + # an Double3 type. + ufeAttr, usdAttr = attrDict = self.runTestAttribute( + path='/Room_set/Props/Ball_35', + attrName='xformOp:translate', + ufeAttrClass=ufe.AttributeDouble3, + ufeAttrType=ufe.Attribute.kDouble3) + + # Now we test the Double3 specific methods. + + # Compare the initial UFE value to that directly from USD. + self.assertVectorAlmostEqual(ufeAttr.get(), usdAttr.Get()) + + # Set the attribute in UFE with some random values. + vec = ufe.Vector3d(random.uniform(-100, 100), random.uniform(-100, 100), random.uniform(-100, 100)) + ufeAttr.set(vec) + + # Then make sure that new UFE value matches what it in USD. + self.assertVectorAlmostEqual(ufeAttr.get(), usdAttr.Get()) diff --git a/test/lib/ufe/testAttributes.py b/test/lib/ufe/testAttributes.py new file mode 100644 index 0000000000..a9b4c3be07 --- /dev/null +++ b/test/lib/ufe/testAttributes.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +from ufeTestUtils import usdUtils, mayaUtils +import ufe +from pxr import UsdGeom + +import unittest + +class AttributesTestCase(unittest.TestCase): + '''Verify the Attributes UFE interface, for multiple runtimes. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + self.assertTrue(self.pluginsLoaded) + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + def testAttributes(self): + '''Engine method to run attributes test.''' + + # Get a UFE scene item for one of the balls in the scene. + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + + # Then create the attributes interface for that item. + ball35Attrs = ufe.Attributes.attributes(ball35Item) + self.assertIsNotNone(ball35Attrs) + + # Test that we get the same scene item back. + self.assertEqual(ball35Item, ball35Attrs.sceneItem()) + + # Verify that ball35 contains the visibility attribute. + self.assertTrue(ball35Attrs.hasAttribute(UsdGeom.Tokens.visibility)) + + # Verify the attribute type of 'visibility' which we know is a enum token. + self.assertEqual(ball35Attrs.attributeType(UsdGeom.Tokens.visibility), ufe.Attribute.kEnumString) + + # Get all the attribute names for this item. + ball35AttrNames = ball35Attrs.attributeNames + + # Visibility should be in this list. + self.assertIn(UsdGeom.Tokens.visibility, ball35AttrNames) diff --git a/test/lib/ufe/testDeleteCmd.py b/test/lib/ufe/testDeleteCmd.py new file mode 100644 index 0000000000..aed6789169 --- /dev/null +++ b/test/lib/ufe/testDeleteCmd.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.cmds as cmds + +from ufeTestUtils import usdUtils, mayaUtils +import ufe + +import unittest + +class DeleteCmdTestCase(unittest.TestCase): + '''Verify the Maya delete command, for multiple runtimes. + + UFE Feature : SceneItemOps + Maya Feature : delete + Action : Remove object from scene. + Applied On Selection : + - Multiple Selection [Mixed, Non-Maya]. Maya-only selection tested by + Maya. + Undo/Redo Test : Yes + Expect Results To Test : + - Delete removes object from scene. + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the Maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + + # Clear selection to start off + cmds.select(clear=True) + + def testDelete(self): + '''Delete Maya and USD objects.''' + + # Select two objects, one Maya, one USD. + spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) + sphereItem = ufe.Hierarchy.createItem(spherePath) + sphereShapePath = ufe.Path( + mayaUtils.createUfePathSegment("|pSphere1|pSphereShape1")) + sphereShapeItem = ufe.Hierarchy.createItem(sphereShapePath) + + mayaSegment = mayaUtils.createUfePathSegment( + "|world|transform1|proxyShape1") + ball35Path = ufe.Path( + [mayaSegment, + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + propsPath = ufe.Path( + [mayaSegment, usdUtils.createUfePathSegment("/Room_set/Props")]) + propsItem = ufe.Hierarchy.createItem(propsPath) + + sphereShapeName = str(sphereShapeItem.path().back()) + ball35Name = str(ball35Item.path().back()) + + ufe.GlobalSelection.get().append(sphereShapeItem) + ufe.GlobalSelection.get().append(ball35Item) + + # Before delete, each item is a child of its parent. + sphereHierarchy = ufe.Hierarchy.hierarchy(sphereItem) + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + + def childrenNames(children): + return [str(child.path().back()) for child in children] + + sphereChildren = sphereHierarchy.children() + propsChildren = propsHierarchy.children() + + sphereChildrenNames = childrenNames(sphereChildren) + propsChildrenNames = childrenNames(propsChildren) + + self.assertIn(sphereShapeItem, sphereChildren) + self.assertIn(ball35Item, propsChildren) + self.assertIn(sphereShapeName, sphereChildrenNames) + self.assertIn(ball35Name, propsChildrenNames) + + cmds.delete() + + sphereChildren = sphereHierarchy.children() + propsChildren = propsHierarchy.children() + + sphereChildrenNames = childrenNames(sphereChildren) + propsChildrenNames = childrenNames(propsChildren) + + self.assertNotIn(sphereShapeName, sphereChildrenNames) + self.assertNotIn(ball35Name, propsChildrenNames) + + cmds.undo() + + sphereChildren = sphereHierarchy.children() + propsChildren = propsHierarchy.children() + + sphereChildrenNames = childrenNames(sphereChildren) + propsChildrenNames = childrenNames(propsChildren) + + self.assertIn(sphereShapeItem, sphereChildren) + self.assertIn(ball35Item, propsChildren) + self.assertIn(sphereShapeName, sphereChildrenNames) + self.assertIn(ball35Name, propsChildrenNames) + + cmds.redo() + + sphereChildren = sphereHierarchy.children() + propsChildren = propsHierarchy.children() + + sphereChildrenNames = childrenNames(sphereChildren) + propsChildrenNames = childrenNames(propsChildren) + + self.assertNotIn(sphereShapeName, sphereChildrenNames) + self.assertNotIn(ball35Name, propsChildrenNames) diff --git a/test/lib/ufe/testDuplicateCmd.py b/test/lib/ufe/testDuplicateCmd.py new file mode 100644 index 0000000000..bd832b373b --- /dev/null +++ b/test/lib/ufe/testDuplicateCmd.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.cmds as cmds + +from pxr import Sdf + +from ufeTestUtils import usdUtils, mayaUtils +import ufe + +import unittest + +class DuplicateCmdTestCase(unittest.TestCase): + '''Verify the Maya delete command, for multiple runtimes. + + UFE Feature : SceneItemOps + Maya Feature : duplicate + Action : Duplicate objects in the scene. + Applied On Selection : + - Multiple Selection [Mixed, Non-Maya]. Maya-only selection tested by + Maya. + Undo/Redo Test : Yes + Expect Results To Test : + - Duplicate objects in the scene. + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the Maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + + # Clear selection to start off + cmds.select(clear=True) + + def testDuplicate(self): + '''Duplicate Maya and USD objects.''' + + # Select two objects, one Maya, one USD. + spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) + sphereItem = ufe.Hierarchy.createItem(spherePath) + sphereHierarchy = ufe.Hierarchy.hierarchy(sphereItem) + worldItem = sphereHierarchy.parent() + + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment( + "|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + ball35Hierarchy = ufe.Hierarchy.hierarchy(ball35Item) + propsItem = ball35Hierarchy.parent() + + worldHierarchy = ufe.Hierarchy.hierarchy(worldItem) + worldChildrenPre = worldHierarchy.children() + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildrenPre = propsHierarchy.children() + + ufe.GlobalSelection.get().append(sphereItem) + ufe.GlobalSelection.get().append(ball35Item) + + # Set the edit target to the layer in which Ball_35 is defined (has a + # primSpec, in USD terminology). Otherwise, duplication will not find + # a source primSpec to copy. Layers are the (anonymous) session layer, + # the root layer, then the Assembly_room_set sublayer. Trying to find + # the layer by name is not practical, as it requires the full path + # name, which potentially differs per run-time environment. + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + stage = ball35Prim.GetStage() + + layer = stage.GetLayerStack()[2] + stage.SetEditTarget(layer) + + cmds.duplicate() + + # The duplicate command doesn't return duplicated non-Maya UFE objects. + # They are in the selection, in the same order as the sources. + snIter = iter(ufe.GlobalSelection.get()) + sphereDupItem = next(snIter) + sphereDupName = str(sphereDupItem.path().back()) + ball35DupItem = next(snIter) + ball35DupName = str(ball35DupItem.path().back()) + + # MAYA-92350: should not need to re-bind hierarchy interface objects + # with their item. + worldHierarchy = ufe.Hierarchy.hierarchy(worldItem) + worldChildren = worldHierarchy.children() + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildren = propsHierarchy.children() + + self.assertEqual(len(worldChildren)-len(worldChildrenPre), 1) + self.assertEqual(len(propsChildren)-len(propsChildrenPre), 1) + + self.assertIn(sphereDupItem, worldChildren) + self.assertIn(ball35DupItem, propsChildren) + + cmds.undo() + + # The duplicated items should no longer appear in the child list of + # their parents. + + def childrenNames(children): + return [str(child.path().back()) for child in children] + + worldHierarchy = ufe.Hierarchy.hierarchy(worldItem) + worldChildren = worldHierarchy.children() + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildren = propsHierarchy.children() + + worldChildrenNames = childrenNames(worldChildren) + propsChildrenNames = childrenNames(propsChildren) + + self.assertNotIn(sphereDupName, worldChildrenNames) + self.assertNotIn(ball35DupName, propsChildrenNames) + + # MAYA-92264: because of USD bug, redo doesn't work. + return + cmds.redo() + + snIter = iter(ufe.GlobalSelection.get()) + sphereDupItem = next(snIter) + ball35DupItem = next(snIter) + + # MAYA-92350: should not need to re-bind hierarchy interface objects + # with their item. + worldHierarchy = ufe.Hierarchy.hierarchy(worldItem) + worldChildren = worldHierarchy.children() + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildren = propsHierarchy.children() + + self.assertEqual(len(worldChildren)-len(worldChildrenPre), 1) + self.assertEqual(len(propsChildren)-len(propsChildrenPre), 1) + + self.assertIn(sphereDupItem, worldChildren) + self.assertIn(ball35DupItem, propsChildren) diff --git a/test/lib/ufe/testGroupCmd.py b/test/lib/ufe/testGroupCmd.py new file mode 100644 index 0000000000..75d14c554e --- /dev/null +++ b/test/lib/ufe/testGroupCmd.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.cmds as cmds + +from pxr import Sdf + +from ufeTestUtils import usdUtils, mayaUtils +import ufe + +import unittest + +class GroupCmdTestCase(unittest.TestCase): + '''Verify the Maya group command, for multiple runtimes. + + As of 19-Nov-2018, the UFE group command is not integrated into Maya, so + directly test the UFE undoable command. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the Maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Clear selection to start off + cmds.select(clear=True) + + def testUsdGroup(self): + '''Creation of USD group objects.''' + + # Get parent of new group. + propsPath = ufe.Path([ + mayaUtils.createUfePathSegment( + "|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props")]) + propsItem = ufe.Hierarchy.createItem(propsPath) + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildrenPre = propsHierarchy.children() + + groupPath = propsPath + "newGroup" + + # Create new group. + group = propsHierarchy.createGroupCmd("newGroup") + + self.assertIsNotNone(group.item) + # MAYA-92350: must re-create hierarchy interface object. Fix ASAP. + # PPT, 19-Nov-2018. + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildrenPost = propsHierarchy.children() + self.assertEqual(len(propsChildrenPre)+1, len(propsChildrenPost)) + childrenPaths = set([child.path() for child in propsChildrenPost]) + self.assertTrue(groupPath in childrenPaths) + + # Undo + group.undoableCommand.undo() + + # MAYA-92350: must re-create hierarchy interface object. Fix ASAP. + # PPT, 19-Nov-2018. + propsHierarchy = ufe.Hierarchy.hierarchy(propsItem) + propsChildrenPostUndo = propsHierarchy.children() + self.assertEqual(len(propsChildrenPre), len(propsChildrenPostUndo)) + childrenPaths = set([child.path() for child in propsChildrenPostUndo]) + self.assertFalse(groupPath in childrenPaths) + + # MAYA-92264: redo doesn't work. + # group.undoableCommand.redo() diff --git a/test/lib/ufe/testMatrices.py b/test/lib/ufe/testMatrices.py new file mode 100644 index 0000000000..e7a8ac648e --- /dev/null +++ b/test/lib/ufe/testMatrices.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +from ufeTestUtils import usdUtils, mayaUtils + +import ufe + +import maya.api.OpenMaya as om +import maya.cmds as cmds + +from math import radians, sin, cos +import os + +import unittest + +# AX = | 1 0 0 0 | +# | 0 cx sx 0 | +# | 0 -sx cx 0 | +# | 0 0 0 1 | +# sx = sin(rax), cx = cos(rax) +def rotXMatrix(rax): + sx = sin(rax) + cx = cos(rax) + return [[1, 0, 0, 0], [0, cx, sx, 0], [0, -sx, cx, 0], [0, 0, 0, 1]] + +# T = | 1 0 0 0 | +# | 0 1 0 0 | +# | 0 0 1 0 | +# | tx ty tz 1 | +def xlateMatrix(t): + return [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [t[0], t[1], t[2], 1]] + +identityMatrix = xlateMatrix([0, 0, 0]) + +class Transform3dMatricesTestCase(unittest.TestCase): + '''Verify the Transform3d matrix interfaces.''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Read in a simple USD scene: a mesh cylinder at the origin. + filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test-samples", "cylinder", "usdCylinder.ma" ) + cmds.file(filePath, force=True, open=True) + + def assertMatrixAlmostEqual(self, ma, mb): + for ra, rb in zip(ma, mb): + for a, b in zip(ra, rb): + self.assertAlmostEqual(a, b) + + def testMatrices(self): + '''Test inclusive and exclusive matrices.''' + + # Scene hierarchy: + # + # mayaUsdTransform + # |_ shape + # |_ pCylinder1 (USD mesh) + # + # transform has a translation of 10 units along the Y axis, + # and a rotation of 30 degrees around X. pCylinder1 has a further + # 30 degree rotation around X (60 degrees total). + + # Create a non-identity transform for the Maya segment of the UFE path: + # translate the transform of the proxy shape up (Y axis) by 10 + # units, rotate around X 30 degrees. + cmds.setAttr('mayaUsdTransform.translateY', 10) + cmds.setAttr('mayaUsdTransform.rotateX', 30) + + # Next, rotate the USD object by another 30 degrees around X. To + # do so, select it first. + mayaPathSegment = mayaUtils.createUfePathSegment('|world|mayaUsdTransform|shape') + usdPathSegment = usdUtils.createUfePathSegment('/pCylinder1') + cylinderPath = ufe.Path([mayaPathSegment, usdPathSegment]) + cylinderItem = ufe.Hierarchy.createItem(cylinderPath) + + ufe.GlobalSelection.get().append(cylinderItem) + + cmds.rotate(30, r=True, os=True, rotateX=True) + + # Get a Transform3d interface to the cylinder. + t3d = ufe.Transform3d.transform3d(cylinderItem) + + # Get the inclusive and exclusive matrices for the cylinder, and + # for its (last) segment. + cylSegExclMat = t3d.segmentExclusiveMatrix() + cylSegInclMat = t3d.segmentInclusiveMatrix() + cylExclMat = t3d.exclusiveMatrix() + cylInclMat = t3d.inclusiveMatrix() + + # Since the cylinder has no USD parent, its segment exclusive + # matrix is the identity, and its segment inclusive matrix is just + # its 30 degree rotation around X. + self.assertMatrixAlmostEqual(cylSegExclMat.matrix, identityMatrix) + self.assertMatrixAlmostEqual(cylSegInclMat.matrix, rotXMatrix(radians(30))) + + # Get a Transform3d interface for the proxy shape's transform, and + # get its transforms. + xformPath = ufe.Path(mayaUtils.createUfePathSegment('|world|mayaUsdTransform')) + xformItem = ufe.Hierarchy.createItem(xformPath) + t3d = ufe.Transform3d.transform3d(xformItem) + + xformSegExclMat = t3d.segmentExclusiveMatrix() + xformSegInclMat = t3d.segmentInclusiveMatrix() + xformExclMat = t3d.exclusiveMatrix() + xformInclMat = t3d.inclusiveMatrix() + + # Since the transform has no Maya parent, its segment exclusive + # matrix is the identity, and its segment inclusive matrix is + # its 30 degree rotation around X, and its 10 unit Y translation. + sx30 = sin(radians(30)) + cx30 = cos(radians(30)) + self.assertMatrixAlmostEqual(xformSegExclMat.matrix, identityMatrix) + self.assertMatrixAlmostEqual( + xformSegInclMat.matrix, [[1, 0, 0, 0], [0, cx30, sx30, 0], + [0, -sx30, cx30, 0], [0, 10, 0, 1]]) + + # Since the transform is the cylinder's parent, the cylinder's + # exclusive matrix must be (by definition) the transform's + # inclusive matrix. + self.assertMatrixAlmostEqual(xformInclMat.matrix, cylExclMat.matrix) + + # The cylinder's inclusive matrix is the full 60 degree rotation + # around X, and 10 unit Y translation. + sx60 = sin(radians(60)) + cx60 = cos(radians(60)) + self.assertMatrixAlmostEqual( + cylInclMat.matrix, [[1, 0, 0, 0], [0, cx60, sx60, 0], + [0, -sx60, cx60, 0], [0, 10, 0, 1]]) diff --git a/test/lib/ufe/testMayaPickwalk.py b/test/lib/ufe/testMayaPickwalk.py new file mode 100644 index 0000000000..327555c83e --- /dev/null +++ b/test/lib/ufe/testMayaPickwalk.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 unittest + +import maya.cmds as cmds +import sys, os + +from ufeTestUtils import usdUtils, mayaUtils, ufeUtils +import ufe + +class MayaUFEPickWalkTesting(unittest.TestCase): + ''' + These tests are to verify the hierarchy interface provided by UFE into multiple + runtimes. It will be testing out Pickwalk on Maya. + + UFE Feature : Hierarchy + Maya Feature : Pickwalk + Action : Pickwalk [Up, Down, Left Right] + Applied On Selection : + - No selection - Given node as param + - Single Selection [Maya, Non-Maya] + - Multiple Selection [Mixed, Non-Mixed] + Undo/Redo Test : Yes + Expect Results To Test : + - Maya Selection + - UFE Selection + Edge Cases : + - Down on last item (Down again) + - Up on top item (Up again) + - Maya item walk to Non-Maya Item + - Non-Maya item walk to Maya Item + - Walk on non-supported UFE items + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + @classmethod + def tearDownClass(cls): + # Clearing the undo stack with file new avoids mayapy crashing on + # exit while cleaning out the undo stack, because the Python commands + # we use in this test are destroyed after the Python interpreter exits. + cmds.file(new=True, force=True) + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Set up memento - [[mayaSelection, ufeSelection], ...] + self.memento = [] + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + cmds.polyCube() + + # Clear selection to start off + cmds.select(clear=True) + + def snapShotAndTest(self, expectedResults = None): + ''' + Take a snapshot of the current selection in Maya and UFE. + Test these selection on the expected results. If None are given, + UFE and maya selections are equal. + Args: + expectedResults ([mayaSelection, ufeSelection]): + Expected results to test on. + ''' + mayaSelection = mayaUtils.getMayaSelectionList() + ufeSelection = ufeUtils.getUfeGlobalSelectionList() + self.memento.append((mayaSelection, ufeSelection)) + if expectedResults: + self.assertEqual(self.memento[-1][0], expectedResults[0]) + self.assertEqual(self.memento[-1][1], expectedResults[1]) + else : + self.assertEqual(self.memento[-1][0], self.memento[-1][1]) + + def rewindMemento(self): + ''' + Undo through all items in memento. Make sure that the current + selection match their respective registered selection in memento. + ''' + for m in reversed(self.memento[:-1]): + cmds.undo() + self.assertEqual(m[0], mayaUtils.getMayaSelectionList()) + self.assertEqual(m[1], ufeUtils.getUfeGlobalSelectionList()) + + def fforwardMemento(self): + ''' + Redo through all items in memento. Make sure that the current + selection match their respective registered selection in memento. + ''' + # Test initial + self.assertEqual(self.memento[0][0], mayaUtils.getMayaSelectionList()) + self.assertEqual(self.memento[0][1], ufeUtils.getUfeGlobalSelectionList()) + # Skip first + for m in self.memento[1:]: + cmds.redo() + self.assertEqual(m[0], mayaUtils.getMayaSelectionList()) + self.assertEqual(m[1], ufeUtils.getUfeGlobalSelectionList()) + + def test_pickWalk(self): + ''' + This test will be verify the use of Maya's pickWalk into Maya objects and Usd objects. + ''' + # Initial state check up + self.snapShotAndTest() + + # No Selection + cmds.pickWalk("pSphere1", d="down") + self.snapShotAndTest() + + # Single Selection - Maya Item + cmds.select("pCube1") + self.snapShotAndTest() + + cmds.pickWalk(d="down") + self.snapShotAndTest() + + # Edge Case: Maya item to UFE Item + cmds.select("proxyShape1") + self.snapShotAndTest() + cmds.pickWalk(d="down") # /Room_set + self.snapShotAndTest(([], ['Room_set'])) + + # Edge Case: UFE Item to Maya + cmds.pickWalk(d="up") # /proxyShape1 + self.snapShotAndTest() + + # Pickwalk all the way down in USD - Pickwalk down again + for usdItem in ['Room_set', 'Props', 'Ball_1', 'mesh']: + cmds.pickWalk(d="down") # Room_set / Props / Ball_1 / mesh + self.snapShotAndTest(([], [usdItem])) + + # Edge Case : Down on last item (Down again) + cmds.pickWalk(d="down") + self.snapShotAndTest(([], ['mesh'])) + + # Edge Case : Up on top item (Up again) + cmds.select("transform1") + self.snapShotAndTest() + cmds.pickWalk(d="up") # transform1 + self.snapShotAndTest() # World is not selectable in maya + + + # Pickwalk on unsupported UFE items + cmds.select("pCube1.e[6]") + self.snapShotAndTest((["pCube1.e[6]"], ["pCubeShape1"])) + self.assertTrue(next(iter(ufe.GlobalSelection.get())).isProperty()) + + # TODO: HS 2019 : test fails. MAYA-101373 +# cmds.pickWalk(type="edgeloop", d="right") +# import pdb; pdb.set_trace() +# self.snapShotAndTest((["pCube1.e[10]"], ["pCubeShape1"])) +# self.assertTrue(next(iter(ufe.GlobalSelection.get())).isProperty()) # pCubeShape1 in ufe selection is a property + + + # Pickwalk on Non-Mixed Maya items is already tested in Maya regression tests + # Pickwalk on Non-Mixed USD items + ufeUtils.selectPath(ufe.Path([ \ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), \ + usdUtils.createUfePathSegment("/Room_set/Props/Ball_1") \ + ]), True) + self.snapShotAndTest(([], ['Ball_1'])) + + + ufeUtils.selectPath(ufe.Path([ \ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), \ + usdUtils.createUfePathSegment("/Room_set/Props/Ball_2") \ + ])) + self.snapShotAndTest(([], ['Ball_1', 'Ball_2'])) + + cmds.pickWalk(d="down") + self.snapShotAndTest(([], ['mesh', 'mesh'])) + + # Pickwalk on mixed items + ufeUtils.selectPath(ufe.Path([ \ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), \ + usdUtils.createUfePathSegment("/Room_set/Props/Ball_1") \ + ]), True) + self.snapShotAndTest(([], ['Ball_1'])) + + ufeUtils.selectPath(ufe.Path( mayaUtils.createUfePathSegment("|pCube1"))) + self.snapShotAndTest((['pCube1'], ['Ball_1', 'pCube1'])) + + # Selection on Maya items from UFE does not work + cmds.pickWalk(d="down") + self.snapShotAndTest((['pCubeShape1'], ['mesh', 'pCubeShape1'])) + + # Test Complete - Undo and redo everything + ''' MAYA-92081 : Undoing cmds.select does not restore the UFE selection. + the undo(rewindMemento) would fail. Disabling this until defect is fixed + self.rewindMemento() + self.fforwardMemento() + ''' diff --git a/test/lib/ufe/testMoveCmd.py b/test/lib/ufe/testMoveCmd.py new file mode 100644 index 0000000000..a55bd06f00 --- /dev/null +++ b/test/lib/ufe/testMoveCmd.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.api.OpenMaya as om +import maya.cmds as cmds + +from ufeTestUtils import usdUtils, mayaUtils, ufeUtils +import testTRSBase +import ufe + +import unittest + +from functools import partial + +def matrix4dTranslation(matrix4d): + translation = matrix4d.matrix[-1] + return translation[:-1] + +def transform3dTranslation(transform3d): + return matrix4dTranslation(transform3d.inclusiveMatrix()) + +def addVec(mayaVec, usdVec): + return mayaVec + om.MVector(*usdVec) + +def multiSelectAddTranslations(translationList, translation2): + return [translation+translation2 for translation in translationList] + +class MoveCmdTestCase(testTRSBase.TRSTestCaseBase): + '''Verify the Transform3d UFE interface, for multiple runtimes. + + The Maya move command is used to test setting object translation. As of + 27-Mar-2018, only world space relative moves are supported by Maya code. + Object translation is read using the Transform3d interface and the native + run-time interface. + + UFE Feature : Transform3d + Maya Feature : move + Action : Relative move in world space. + Applied On Selection : + - No selection - Given node as param + - Single Selection [Maya, Non-Maya] + - Multiple Selection [Mixed, Non-Maya]. Maya-only selection tested by + Maya. + Undo/Redo Test : Yes + Expect Results To Test : + - Maya Dag object world space position. + - USD object world space position. + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Set up memento, a list of snapshots. + self.memento = [] + + # Callables to get current object translation using the run-time and + # UFE. + self.runTimeTranslation = None + self.ufeTranslation = None + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + cmds.polyCube() + + # Clear selection to start off + cmds.select(clear=True) + + def snapshotRunTimeUFE(self): + '''Return a pair with translation read from the run-time and from UFE. + + Tests that the translation read from the run-time interface matches the + UFE translation. + ''' + runTimeVec = self.runTimeTranslation() + ufeVec = self.ufeTranslation() + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + return (runTimeVec, ufeVec) + + def multiSelectSnapshotRunTimeUFE(self, items): + '''Return a list of pairs with translation read from the run-time and from UFE. + + Tests that the translation read from the run-time interface matches the + UFE translation. + ''' + snapshot = [] + for item in items: + runTimeVec = self.runTimeTranslation(item) + ufeVec = self.ufeTranslation(item) + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + snapshot.append((runTimeVec, ufeVec)) + return snapshot + + def assertVectorAlmostEqual(self, a, b): + for va, vb in zip(a, b): + self.assertAlmostEqual(va, vb) + + def runTestMove(self, expected): + '''Engine method to run move test.''' + + # Save the initial position to the memento list. + self.snapShotAndTest(expected) + + # Do some move commands, and compare with expected. + for relativeMove in [om.MVector(4, 5, 6), om.MVector(-3, -2, -1)]: + cmds.move(*relativeMove, relative=True) + expected += relativeMove + self.snapShotAndTest(expected) + + # Test undo, redo. + self.rewindMemento() + self.fforwardMemento() + + def runMultiSelectTestMove(self, items, expected): + '''Engine method to run multiple selection move test.''' + + # Save the initial positions to the memento list. + self.multiSelectSnapShotAndTest(items, expected) + + # Do some move commands, and compare with expected. + for relativeMove in [om.MVector(4, 5, 6), om.MVector(-3, -2, -1)]: + cmds.move(*relativeMove, relative=True) + expected = multiSelectAddTranslations(expected, relativeMove) + self.multiSelectSnapShotAndTest(items, expected) + + # Test undo, redo. + self.multiSelectRewindMemento(items) + self.multiSelectFforwardMemento(items) + + def testMoveMaya(self): + '''Move Maya object, read through the Transform3d interface.''' + + # Give the sphere an initial position, and select it. + expected = om.MVector(1, 2, 3) + sphereObj = om.MSelectionList().add('pSphere1').getDagPath(0).node() + sphereFn = om.MFnTransform(sphereObj) + sphereFn.setTranslation(expected, om.MSpace.kTransform) + spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) + sphereItem = ufe.Hierarchy.createItem(spherePath) + + ufe.GlobalSelection.get().append(sphereItem) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(sphereItem) + + # Set up the callables that will retrieve the translation. + self.runTimeTranslation = partial( + sphereFn.translation, om.MSpace.kTransform) + self.ufeTranslation = partial(transform3dTranslation, transform3d) + + self.runTestMove(expected) + + def testMoveUSD(self): + '''Move USD object, read through the Transform3d interface.''' + + # Select Ball_35 to move it. + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + + ufe.GlobalSelection.get().append(ball35Item) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(ball35Item) + + # We compare the UFE translation with the USD run-time translation. To + # obtain the full translation of Ball_35, we need to add the USD + # translation to the Maya proxy shape translation. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def ball35Translation(): + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + return addVec( + proxyShapeXformFn.translation(om.MSpace.kTransform), + ball35Prim.GetAttribute('xformOp:translate').Get()) + + # Set up the callables that will retrieve the translation. + self.runTimeTranslation = ball35Translation + self.ufeTranslation = partial(transform3dTranslation, transform3d) + + # Save the initial position to the memento list. + expected = ball35Translation() + + self.runTestMove(expected) + + # Not running because of expired prim problems. PPT, 21-Dec-2018. + def _testMultiSelectMoveUSD(self): + '''Move multiple USD objects, read through Transform3d interface.''' + + # Select multiple balls to move them. + proxyShapePathSegment = mayaUtils.createUfePathSegment( + "|world|transform1|proxyShape1") + + balls = ['Ball_33', 'Ball_34'] + ballPaths = [ + ufe.Path([proxyShapePathSegment, + usdUtils.createUfePathSegment('/Room_set/Props/'+ball)]) + for ball in balls] + ballItems = [ufe.Hierarchy.createItem(ballPath) + for ballPath in ballPaths] + + for ballItem in ballItems: + ufe.GlobalSelection.get().append(ballItem) + + # We compare the UFE translation with the USD run-time translation. To + # obtain the full translation of USD scene items, we need to add the USD + # translation to the Maya proxy shape translation. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def usdSceneItemTranslation(item): + prim = usdUtils.getPrimFromSceneItem(item) + if not prim.HasAttribute('xformOp:translate'): + return proxyShapeXformFn.translation(om.MSpace.kTransform) + else: + return addVec( + proxyShapeXformFn.translation(om.MSpace.kTransform), + prim.GetAttribute('xformOp:translate').Get()) + + def ufeSceneItemTranslation(item): + return transform3dTranslation(ufe.Transform3d.transform3d(item)) + + # Set up the callables that will retrieve the translation. + self.runTimeTranslation = usdSceneItemTranslation + self.ufeTranslation = ufeSceneItemTranslation + + # Give the tail item in the selection an initial translation that + # is different, to catch bugs where the relative translation + # incorrectly squashes any existing translation. + backItem = ballItems[-1] + backT3d = ufe.Transform3d.transform3d(backItem) + initialTranslation = [-10, -20, -30] + backT3d.translate(*initialTranslation) + self.assertVectorAlmostEqual(ufeSceneItemTranslation(backItem), + usdSceneItemTranslation(backItem)) + + # Save the initial positions to the memento list. + expected = [usdSceneItemTranslation(ballItem) for ballItem in ballItems] + + #Temporarily disabling undo redo until we fix it for PR 94 + self.runMultiSelectTestMove(ballItems, expected) diff --git a/test/lib/ufe/testRotateCmd.py b/test/lib/ufe/testRotateCmd.py new file mode 100644 index 0000000000..8dc0f1d8b1 --- /dev/null +++ b/test/lib/ufe/testRotateCmd.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.api.OpenMaya as om +import maya.cmds as cmds +from math import radians + +from ufeTestUtils import usdUtils, mayaUtils, ufeUtils +import testTRSBase +import ufe + +import unittest + +from functools import partial + +def transform3dRotation(transform3d): + matrix = om.MMatrix(transform3d.inclusiveMatrix().matrix) + return om.MTransformationMatrix(matrix).rotation() + +def addRotations(eulerRotation1, eulerRotation2): + src = om.MTransformationMatrix(eulerRotation1.asMatrix()) + return src.rotateBy(eulerRotation2, om.MSpace.kObject).rotation() + +def multiSelectAddRotations(eulerRotationList, eulerRotation2): + return [addRotations(eulerRotation, eulerRotation2) + for eulerRotation in eulerRotationList] + +class RotateCmdTestCase(testTRSBase.TRSTestCaseBase): + '''Verify the Transform3d UFE interface, for multiple runtimes. + + The Maya rotate command is used to test setting object rotation. As of + 23-May-2018, only world space relative rotates are supported by Maya code. + Object rotation is read using the Transform3d interface and the native + run-time interface. + + UFE Feature : Transform3d + Maya Feature : rotate + Action : Relative rotate in world space. + Applied On Selection : + - No selection - Given node as param + - Single Selection [Maya, Non-Maya] + - Multiple Selection [Mixed, Non-Maya]. Maya-only selection tested by + Maya. + Undo/Redo Test : Yes + Expect Results To Test : + - Maya Dag object world space position. + - USD object world space position. + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Set up memento, a list of snapshots. + self.memento = [] + + # Callables to get current object rotation using the run-time and + # UFE. + self.runTimeRotation = None + self.ufeRotation = None + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + cmds.polyCube() + + # Clear selection to start off + cmds.select(clear=True) + + def snapshotRunTimeUFE(self): + '''Return a pair with rotation read from the run-time and from UFE. + + Tests that the rotation read from the run-time interface matches the + UFE rotation. + ''' + runTimeVec = self.runTimeRotation() + ufeVec = self.ufeRotation() + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + return (runTimeVec, ufeVec) + + def multiSelectSnapshotRunTimeUFE(self, items): + '''Return a list of pairs with rotation read from the run-time and from UFE. + + Tests that the rotation read from the run-time interface matches the + UFE rotation. + ''' + snapshot = [] + for item in items: + runTimeVec = self.runTimeRotation(item) + ufeVec = self.ufeRotation(item) + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + snapshot.append((runTimeVec, ufeVec)) + return snapshot + + def assertVectorAlmostEqual(self, a, b): + for va, vb in zip(a, b): + self.assertAlmostEqual(va, vb) + + def runTestRotate(self, expected): + '''Engine method to run rotate test.''' + + # Save the initial position to the memento list. + self.snapShotAndTest(expected) + + # Do some rotate commands, and compare with expected. + for x, y, z in [[10, 20, 30], [-30, -20, -10]]: + cmds.rotate(x, y, z, relative=True, objectSpace=True, forceOrderXYZ=True) # Just as in default rotations by manipulator + expected = addRotations(expected, om.MEulerRotation(radians(x), radians(y), radians(z))) + self.snapShotAndTest(expected) + + # Test undo, redo. + self.rewindMemento() + self.fforwardMemento() + + def runMultiSelectTestRotate(self, items, expected): + '''Engine method to run multiple selection rotate test.''' + + # Save the initial positions to the memento list. + self.multiSelectSnapShotAndTest(items, expected) + + # Do some rotate commands, and compare with expected. + for x, y, z in [[10, 20, 30], [-30, -20, -10]]: + cmds.rotate(x, y, z, relative=True, objectSpace=True, forceOrderXYZ=True) # Just as in default rotations by manipulator + expected = multiSelectAddRotations(expected, om.MEulerRotation(radians(x), radians(y), radians(z))) + self.multiSelectSnapShotAndTest(items, expected) + + # Test undo, redo. + self.multiSelectRewindMemento(items) + self.multiSelectFforwardMemento(items) + + def testRotateMaya(self): + '''Rotate Maya object, read through the Transform3d interface.''' + + # Give the sphere an initial position, and select it. + rotation = om.MEulerRotation(radians(30), radians(60), radians(90)) + sphereObj = om.MSelectionList().add('pSphere1').getDagPath(0).node() + sphereFn = om.MFnTransform(sphereObj) + sphereFn.setRotation(rotation, om.MSpace.kTransform) + + # Select pSphere1 + spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) + sphereItem = ufe.Hierarchy.createItem(spherePath) + ufe.GlobalSelection.get().append(sphereItem) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(sphereItem) + + # Set up the callables that will retrieve the rotation. + self.runTimeRotation = partial( + sphereFn.rotation, om.MSpace.kTransform) + self.ufeRotation = partial(transform3dRotation, transform3d) + + self.runTestRotate(rotation) + + def testRotateUSD(self): + '''Rotate USD object, read through the Transform3d interface.''' + + # Select Ball_35 to rotate it. + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + + ufe.GlobalSelection.get().append(ball35Item) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(ball35Item) + + # We compare the UFE rotation with the USD run-time rotation. To + # obtain the full rotation of Ball_35, we need to add the USD + # rotation to the Maya proxy shape rotation. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def ball35Rotation(): + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + if not ball35Prim.HasAttribute('xformOp:rotateXYZ'): + return proxyShapeXformFn.rotation(om.MSpace.kTransform) + else: + x,y,z = ball35Prim.GetAttribute('xformOp:rotateXYZ').Get() + return proxyShapeXformFn.rotation(om.MSpace.kTransform) + om.MEulerRotation(radians(x), radians(y), radians(z)) + + # Set up the callables that will retrieve the rotation. + self.runTimeRotation = ball35Rotation + self.ufeRotation = partial(transform3dRotation, transform3d) + + # Save the initial position to the memento list. + expected = ball35Rotation() + + # MAYA-96058: unfortunately, rotate command currently requires a rotate + # manipulator to be created to update the UFE object. + manipCtx = cmds.manipRotateContext() + cmds.setToolTo(manipCtx) + + #Temporarily disabling undo redo until we fix it for PR 94 + self.runTestRotate(expected) + + def _testMultiSelectRotateUSD(self): + '''Rotate multiple USD objects, read through Transform3d interface.''' + + # Select multiple balls to rotate them. + proxyShapePathSegment = mayaUtils.createUfePathSegment( + "|world|transform1|proxyShape1") + + balls = ['Ball_33', 'Ball_34'] + ballPaths = [ + ufe.Path([proxyShapePathSegment, + usdUtils.createUfePathSegment('/Room_set/Props/'+ball)]) + for ball in balls] + ballItems = [ufe.Hierarchy.createItem(ballPath) + for ballPath in ballPaths] + + for ballItem in ballItems: + ufe.GlobalSelection.get().append(ballItem) + + # We compare the UFE rotation with the USD run-time rotation. To + # obtain the full rotation of USD scene items, we need to add the USD + # rotation to the Maya proxy shape rotation. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def usdSceneItemRotation(item): + prim = usdUtils.getPrimFromSceneItem(item) + if not prim.HasAttribute('xformOp:rotateXYZ'): + return proxyShapeXformFn.rotation(om.MSpace.kTransform) + else: + x,y,z = prim.GetAttribute('xformOp:rotateXYZ').Get() + return proxyShapeXformFn.rotation(om.MSpace.kTransform) + om.MEulerRotation(radians(x), radians(y), radians(z)) + + def ufeSceneItemRotation(item): + return transform3dRotation(ufe.Transform3d.transform3d(item)) + + # Set up the callables that will retrieve the rotation. + self.runTimeRotation = usdSceneItemRotation + self.ufeRotation = ufeSceneItemRotation + + # Give the tail item in the selection an initial rotation that + # is different, to catch bugs where the relative rotation + # incorrectly squashes any existing rotation. + backItem = ballItems[-1] + backT3d = ufe.Transform3d.transform3d(backItem) + initialRot = [-10, -20, -30] + backT3d.rotate(*initialRot) + self.assertVectorAlmostEqual([radians(a) for a in initialRot], + usdSceneItemRotation(backItem)) + + # Save the initial positions to the memento list. + expected = [usdSceneItemRotation(ballItem) for ballItem in ballItems] + + # MAYA-96058: unfortunately, rotate command currently requires a rotate + # manipulator to be created to update the UFE object. + manipCtx = cmds.manipRotateContext() + cmds.setToolTo(manipCtx) + + #Temporarily disabling undo redo until we fix it for PR 94 + self.runMultiSelectTestRotate(ballItems, expected) + diff --git a/test/lib/ufe/testRotatePivot.py b/test/lib/ufe/testRotatePivot.py new file mode 100644 index 0000000000..585e87d454 --- /dev/null +++ b/test/lib/ufe/testRotatePivot.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +from ufeTestUtils import usdUtils, mayaUtils + +import ufe + +import maya.api.OpenMaya as om +import maya.cmds as cmds + +from math import radians, degrees, sin +import os + +import unittest + +def v3dToMPoint(v): + return om.MPoint(v.x(), v.y(), v.z()) + +class RotatePivotTestCase(unittest.TestCase): + '''Verify the Transform3d UFE rotate pivot interface. + + UFE Feature : Transform3d + Maya Feature : rotate pivot + Action : Set the rotate pivot. + Applied On Selection : + - No selection - Given node as param + - Single Selection : Not tested. + - Multiple Selection [Mixed, Non-Maya] : Not tested. + + Undo/Redo Test : UFE undoable command only. + Expect Results To Test : + - Maya Dag object world space position. + - USD object world space position. + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Create a simple USD scene. Ideally this would be done + # programmatically, but as of 28-Jun-2018 attempts to do so have + # resulted in a file that crashes Maya on pickWalk of the scene. + # Use a saved scene read from file instead. + filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test-samples", "twoSpheres", "twoSpheres.ma" ) + cmds.file(filePath, force=True, open=True) + + def testRotatePivot(self): + # mayaSphere is at (10, 0, 10) in local space, and since it has no + # parent, in world space as well. + spherePath = om.MSelectionList().add('mayaSphere').getDagPath(0) + sphereFn = om.MFnTransform(spherePath) + rotZ = radians(45) + rot = om.MEulerRotation(0, 0, rotZ) + # Pivot around x=0. + pivot = om.MPoint(-10, 0, 0) + sphereFn.setRotatePivot(pivot, om.MSpace.kTransform, False) + sphereFn.setRotation(rot, om.MSpace.kTransform) + # MFnTransform and MTransformationMatrix always return the individual + # components of the matrix, including translation, which is unaffected + # by pivot changes, as expected. The fully-multiplied result is in the + # computed MMatrix. + xyWorldValue = sin(rotZ) * 10 + sphereMatrix = sphereFn.transformation().asMatrix() + # MMatrix is indexed linearly as a 16-element vector, starting at row 0. + def ndx(i, j): + return i*4+j + def checkPos(m, p): + self.assertAlmostEqual(m[ndx(3,0)], p[0]) + self.assertAlmostEqual(m[ndx(3,1)], p[1]) + self.assertAlmostEqual(m[ndx(3,2)], p[2]) + + checkPos(sphereMatrix, [xyWorldValue, xyWorldValue, 10]) + + # Do the same with the USD object, through UFE. + # USD sphere is at (10, 0, 0) in local space, and since its parents + # have an identity transform, in world space as well. + usdSpherePath = ufe.Path([ + mayaUtils.createUfePathSegment( + '|world|usdSphereParent|usdSphereParentShape'), + usdUtils.createUfePathSegment('/sphereXform/sphere')]) + usdSphereItem = ufe.Hierarchy.createItem(usdSpherePath) + t3d = ufe.Transform3d.transform3d(usdSphereItem) + + t3d.rotatePivotTranslate(pivot[0], pivot[1], pivot[2]) + usdPivot = t3d.rotatePivot() + self.assertEqual(v3dToMPoint(usdPivot), pivot) + + t3d.rotate(degrees(rot[0]), degrees(rot[1]), degrees(rot[2])) + sphereMatrix = om.MMatrix(t3d.inclusiveMatrix().matrix) + checkPos(sphereMatrix, [xyWorldValue, xyWorldValue, 0]) + + # Use a UFE undoable command to set the pivot. + t3d.rotatePivotTranslate(0, 0, 0) + usdPivot = t3d.rotatePivot() + self.assertEqual(v3dToMPoint(usdPivot), om.MPoint(0, 0, 0)) + + sphereMatrix = om.MMatrix(t3d.inclusiveMatrix().matrix) + checkPos(sphereMatrix, [10, 0, 0]) + + rotatePivotCmd = t3d.rotatePivotTranslateCmd() + rotatePivotCmd.translate(pivot[0], pivot[1], pivot[2]) + + usdPivot = t3d.rotatePivot() + self.assertEqual(v3dToMPoint(usdPivot), pivot) + + sphereMatrix = om.MMatrix(t3d.inclusiveMatrix().matrix) + + checkPos(sphereMatrix, [xyWorldValue, xyWorldValue, 0]) + + rotatePivotCmd.undo() + + usdPivot = t3d.rotatePivot() + self.assertEqual(v3dToMPoint(usdPivot), om.MPoint(0, 0, 0)) + + sphereMatrix = om.MMatrix(t3d.inclusiveMatrix().matrix) + checkPos(sphereMatrix, [10, 0, 0]) + + # redo() cannot be tested, as it is not implemented. diff --git a/test/lib/ufe/testScaleCmd.py b/test/lib/ufe/testScaleCmd.py new file mode 100644 index 0000000000..8b24372b5d --- /dev/null +++ b/test/lib/ufe/testScaleCmd.py @@ -0,0 +1,279 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.api.OpenMaya as om +import maya.cmds as cmds + +from ufeTestUtils import usdUtils, mayaUtils, ufeUtils +import testTRSBase +import ufe + +import unittest + +from functools import partial + +def transform3dScale(transform3d): + matrix = om.MMatrix(transform3d.inclusiveMatrix().matrix) + return om.MTransformationMatrix(matrix).scale(om.MSpace.kObject) + +def combineScales(scale1, scale2): + return [scale1[0]*scale2[0], scale1[1]*scale2[1], scale1[2]*scale2[2] ] + +def multiSelectCombineScales(scaleList, scale2): + return [combineScales(scale, scale2) for scale in scaleList] + +class ScaleCmdTestCase(testTRSBase.TRSTestCaseBase): + '''Verify the Transform3d UFE interface, for multiple runtimes. + + The Maya scale command is used to test setting object scale. As of + 27-Mar-2018, only world space relative scales are supported by Maya code. + Object scale is read using the Transform3d interface and the native + run-time interface. + + UFE Feature : Transform3d + Maya Feature : scale + Action : Relative scale in world space. + Applied On Selection : + - No selection - Given node as param + - Single Selection [Maya, Non-Maya] + - Multiple Selection [Mixed, Non-Maya]. Maya-only selection tested by + Maya. + Undo/Redo Test : Yes + Expect Results To Test : + - Maya Dag object world space position. + - USD object world space position. + Edge Cases : + - None. + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Set up memento, a list of snapshots. + self.memento = [] + + # Callables to get current object scale using the run-time and + # UFE. + self.runTimeScale = None + self.ufeScale = None + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + cmds.polyCube() + + # Clear selection to start off + cmds.select(clear=True) + + def snapshotRunTimeUFE(self): + '''Return a pair with scale read from the run-time and from UFE. + + Tests that the scale read from the run-time interface matches the + UFE scale. + ''' + runTimeVec = self.runTimeScale() + ufeVec = self.ufeScale() + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + return (runTimeVec, ufeVec) + + def multiSelectSnapshotRunTimeUFE(self, items): + '''Return a list of pairs with scale read from the run-time and from UFE. + + Tests that the scale read from the run-time interface matches the + UFE scale. + ''' + snapshot = [] + for item in items: + runTimeVec = self.runTimeScale(item) + ufeVec = self.ufeScale(item) + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + snapshot.append((runTimeVec, ufeVec)) + return snapshot + + def assertVectorAlmostEqual(self, a, b): + for va, vb in zip(a, b): + # In this test (perhaps in general, not investigated), scale + # extraction from matrix provides 6 decimal places, not default 7, + # close enough. PPT, 21-Dec-2018. + self.assertAlmostEqual(va, vb, places=6) + + def runTestScale(self, expected): + '''Engine method to run scale test.''' + + # Save the initial position to the memento list. + self.snapShotAndTest(expected) + + # Do some scale commands, and compare with expected. + for relativeScale in [[4, 5, 6], [0.5, 0.2, 0.1]]: + cmds.scale(*relativeScale, relative=True) + expected = combineScales(expected, relativeScale) + self.snapShotAndTest(expected) + + # Test undo, redo. + self.rewindMemento() + self.fforwardMemento() + + def runMultiSelectTestScale(self, items, expected): + '''Engine method to run multiple selection scale test.''' + + # Save the initial positions to the memento list. + self.multiSelectSnapShotAndTest(items, expected) + + # Do some scale commands, and compare with expected. + for relativeScale in [[4, 5, 6], [0.5, 0.2, 0.1]]: + cmds.scale(*relativeScale, relative=True) + expected = multiSelectCombineScales(expected, relativeScale) + self.multiSelectSnapShotAndTest(items, expected) + + # Test undo, redo. + self.multiSelectRewindMemento(items) + self.multiSelectFforwardMemento(items) + + def testScaleMaya(self): + '''Scale Maya object, read through the Transform3d interface.''' + + # Give the sphere an initial position, and select it. + expected = [1, 2, 3] + sphereObj = om.MSelectionList().add('pSphere1').getDagPath(0).node() + sphereFn = om.MFnTransform(sphereObj) + sphereFn.setScale(expected) + spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) + sphereItem = ufe.Hierarchy.createItem(spherePath) + + ufe.GlobalSelection.get().append(sphereItem) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(sphereItem) + + # Set up the callables that will retrieve the scale. + self.runTimeScale = partial( + sphereFn.scale) + self.ufeScale = partial(transform3dScale, transform3d) + + self.runTestScale(expected) + + def testScaleUSD(self): + '''Scale USD object, read through the Transform3d interface.''' + + # Select Ball_35 to scale it. + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + + ufe.GlobalSelection.get().append(ball35Item) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(ball35Item) + + # We compare the UFE scale with the USD run-time scale. To + # obtain the full scale of Ball_35, we need to add the USD + # scale to the Maya proxy shape scale. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def ball35Scale(): + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + if not ball35Prim.HasAttribute('xformOp:scale'): + return proxyShapeXformFn.scale() + else: + return combineScales(proxyShapeXformFn.scale(), ball35Prim.GetAttribute('xformOp:scale').Get()) + + # Set up the callables that will retrieve the scale. + self.runTimeScale = ball35Scale + self.ufeScale = partial(transform3dScale, transform3d) + + # Save the initial position to the memento list. + expected = ball35Scale() + + # MAYA-96058: unfortunately, scale command currently requires a scale + # manipulator to be created to update the UFE object. + manipCtx = cmds.manipScaleContext() + cmds.setToolTo(manipCtx) + + self.runTestScale(expected) + + def _testMultiSelectScaleUSD(self): + '''Scale multiple USD objects, read through Transform3d interface.''' + + # Select multiple balls to scale them. + proxyShapePathSegment = mayaUtils.createUfePathSegment( + "|world|transform1|proxyShape1") + + # Test passes for a single item. + # balls = ['Ball_33'] + balls = ['Ball_33', 'Ball_34'] + ballPaths = [ + ufe.Path([proxyShapePathSegment, + usdUtils.createUfePathSegment('/Room_set/Props/'+ball)]) + for ball in balls] + ballItems = [ufe.Hierarchy.createItem(ballPath) + for ballPath in ballPaths] + + for ballItem in ballItems: + ufe.GlobalSelection.get().append(ballItem) + + # We compare the UFE scale with the USD run-time scale. To + # obtain the full scale of USD scene items, we need to add the USD + # scale to the Maya proxy shape scale. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def usdSceneItemScale(item): + prim = usdUtils.getPrimFromSceneItem(ball35Item) + if not prim.HasAttribute('xformOp:scale'): + return proxyShapeXformFn.scale() + else: + return combineScales(proxyShapeXformFn.scale(), prim.GetAttribute('xformOp:scale').Get()) + + def ufeSceneItemScale(item): + return transform3dScale(ufe.Transform3d.transform3d(item)) + + # Set up the callables that will retrieve the scale. + self.runTimeScale = usdSceneItemScale + self.ufeScale = ufeSceneItemScale + + # Give the tail item in the selection an initial scale that + # is different, to catch bugs where the relative scale + # incorrectly squashes any existing scale. + backItem = ballItems[-1] + backT3d = ufe.Transform3d.transform3d(backItem) + initialScale = [1.1, 2.2, 3.3] + backT3d.scale(*initialScale) + self.assertVectorAlmostEqual(initialScale, usdSceneItemScale(backItem)) + + # Save the initial positions to the memento list. + expected = [usdSceneItemScale(ballItem) for ballItem in ballItems] + + # MAYA-96058: unfortunately, scale command currently requires a scale + # manipulator to be created to update the UFE object. + manipCtx = cmds.manipScaleContext() + cmds.setToolTo(manipCtx) + + #Temporarily disabling undo redo until we fix it for PR 94 + self.runMultiSelectTestScale(ballItems, expected) diff --git a/test/lib/ufe/testTRSBase.py b/test/lib/ufe/testTRSBase.py new file mode 100644 index 0000000000..4a4a93f69f --- /dev/null +++ b/test/lib/ufe/testTRSBase.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 unittest + +import maya.cmds as cmds + +class TRSTestCaseBase(unittest.TestCase): + '''Base class for translate (move), rotate, scale command tests.''' + + def snapShotAndTest(self, expected): + '''Take a snapshot of the state and append it to the memento list. + + The snapshot is compared to the expected results. + ''' + snapshot = self.snapshotRunTimeUFE() + self.memento.append(snapshot) + # Since snapshotRunTimeUFE checks run-time to UFE equality, we can use + # the UFE or the run-time value to check against expected. + self.assertVectorAlmostEqual(snapshot[1], expected) + + def multiSelectSnapShotAndTest(self, items, expected): + '''Take a snapshot of the state and append it to the memento list. + + The snapshot is compared to the expected results. + ''' + snapshot = self.multiSelectSnapshotRunTimeUFE(items) + self.memento.append(snapshot) + for (itemSnapshot, itemExpected) in zip(snapshot, expected): + # Since multiSelectSnapshotRunTimeUFE checks run-time to UFE + # equality, we can use the UFE or the run-time value to + # check against expected. + self.assertVectorAlmostEqual(itemSnapshot[1], itemExpected) + + def rewindMemento(self): + '''Undo through all items in memento. + + Starting at the top of the undo stack, perform undo to bring us to the + bottom of the undo stack. During iteration, we ensure that the current + state matches the state stored in the memento. + ''' + # Ignore the top of the memento stack, as it corresponds to the current + # state. + for m in reversed(self.memento[:-1]): + cmds.undo() + self.assertEqual(m, self.snapshotRunTimeUFE()) + + def fforwardMemento(self): + '''Redo through all items in memento. + + Starting at the bottom of the undo stack, perform redo to bring us to + the top of the undo stack. During iteration, we ensure that the current + state matches the state stored in the memento. + ''' + # For a memento list of length n, n-1 redo operations sets us current. + self.assertEqual(self.memento[0], self.snapshotRunTimeUFE()) + # Skip first + for m in self.memento[1:]: + cmds.redo() + self.assertEqual(m, self.snapshotRunTimeUFE()) + + def multiSelectRewindMemento(self, items): + '''Undo through all items in memento. + + Starting at the top of the undo stack, perform undo to bring us to the + bottom of the undo stack. During iteration, we ensure that the current + state matches the state stored in the memento. + ''' + # Ignore the top of the memento stack, as it corresponds to the current + # state. + for m in reversed(self.memento[:-1]): + cmds.undo() + self.assertEqual(m, self.multiSelectSnapshotRunTimeUFE(items)) + + def multiSelectFforwardMemento(self, items): + '''Redo through all items in memento. + + Starting at the bottom of the undo stack, perform redo to bring us to + the top of the undo stack. During iteration, we ensure that the current + state matches the state stored in the memento. + ''' + # For a memento list of length n, n-1 redo operations sets us current. + self.assertEqual(self.memento[0], self.multiSelectSnapshotRunTimeUFE(items)) + # Skip first + for m in self.memento[1:]: + cmds.redo() + self.assertEqual(m, self.multiSelectSnapshotRunTimeUFE(items)) diff --git a/test/lib/ufe/testTransform3dTranslate.py b/test/lib/ufe/testTransform3dTranslate.py new file mode 100644 index 0000000000..647464443c --- /dev/null +++ b/test/lib/ufe/testTransform3dTranslate.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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 maya.api.OpenMaya as om +import maya.cmds as cmds + +from ufeTestUtils import usdUtils, mayaUtils, ufeUtils +import ufe + +import unittest + +from functools import partial + +from pxr import Gf + +def matrix4dTranslation(matrix4d): + translation = matrix4d.matrix[-1] + return translation[:-1] + +def transform3dTranslation(transform3d): + return matrix4dTranslation(transform3d.inclusiveMatrix()) + +def addVec(mayaVec, usdVec): + return mayaVec + om.MVector(*usdVec) + +class TestObserver(ufe.Observer): + def __init__(self): + super(TestObserver, self).__init__() + self.changed = 0 + + def __call__(self, notification): + if isinstance(notification, ufe.Transform3dChanged): + self.changed += 1 + + def notifications(self): + return self.changed + +class Transform3dTranslateTestCase(unittest.TestCase): + '''Verify the Transform3d UFE translate interface, for multiple runtimes. + + The run-time native interface is used to test setting object translation. + As of 27-Mar-2018, only world space relative moves are supported by Maya + code. Object translation is read using the Transform3d interface and the + native run-time interface. + + UFE Feature : Transform3d + Maya Feature : move + Action : Relative move in world space. + Applied On Selection : + - No selection - Given node as param + - Single Selection [Maya, Non-Maya] + - Multiple Selection [Mixed, Non-Maya]. Maya-only selection tested by + Maya. + Undo/Redo Test : Yes + Expect Results To Test : + - Maya Dag object world space position. + - USD object world space position. + Edge Cases : + - None. + + ''' + + pluginsLoaded = False + + @classmethod + def setUpClass(cls): + if not cls.pluginsLoaded: + cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + + def setUp(self): + ''' Called initially to set up the maya test environment ''' + # Load plugins + self.assertTrue(self.pluginsLoaded) + + # Callables to get current object translation using the run-time and + # UFE interfaces. + self.getRunTimeTranslation = None + self.getUfeTranslation = None + + # Callable to set current object translation using the run-time + # interface. + self.setRunTimeTranslation = None + + # Open top_layer.ma scene in test-samples + mayaUtils.openTopLayerScene() + + # Create some extra Maya nodes + cmds.polySphere() + cmds.polyCube() + + # Clear selection to start off + cmds.select(clear=True) + + def assertRunTimeUFEAlmostEqual(self): + '''Tests that the translation read from the run-time interface matches the UFE translation. + + Returns a pair with translation read from the run-time and from UFE. + ''' + runTimeVec = self.getRunTimeTranslation() + ufeVec = self.getUfeTranslation() + self.assertVectorAlmostEqual(runTimeVec, ufeVec) + + def assertVectorAlmostEqual(self, a, b): + for va, vb in zip(a, b): + self.assertAlmostEqual(va, vb) + + def runTestMove(self): + '''Engine method to run move test.''' + + # Compare the initial positions. + self.assertRunTimeUFEAlmostEqual() + + # Do some move commands, and compare. + for xlation in [om.MVector(4, 5, 6), om.MVector(-3, -2, -1)]: + self.setRunTimeTranslation(xlation) + self.assertRunTimeUFEAlmostEqual() + + def _testMoveMaya(self): + '''Move Maya object, read through the Transform3d interface.''' + + # Give the sphere an initial position, and select it. + expected = om.MVector(1, 2, 3) + sphereObj = om.MSelectionList().add('pSphere1').getDagPath(0).node() + sphereFn = om.MFnTransform(sphereObj) + def setMayaTranslation(xlation): + sphereFn.setTranslation(xlation, om.MSpace.kTransform) + setMayaTranslation(expected) + spherePath = ufe.Path(mayaUtils.createUfePathSegment("|pSphere1")) + sphereItem = ufe.Hierarchy.createItem(spherePath) + + ufe.GlobalSelection.get().append(sphereItem) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(sphereItem) + + # Set up the callables that will set and get the translation. + self.setRunTimeTranslation = setMayaTranslation + self.getRunTimeTranslation = partial( + sphereFn.translation, om.MSpace.kTransform) + self.getUfeTranslation = partial(transform3dTranslation, transform3d) + + self.runTestMove() + + def _testMoveUSD(self): + '''Move USD object, read through the Transform3d interface.''' + + # Select Ball_35 to move it. + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + + ufe.GlobalSelection.get().append(ball35Item) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(ball35Item) + + # We compare the UFE translation with the USD run-time translation. To + # obtain the full translation of Ball_35, we need to add the USD + # translation to the Maya proxy shape translation. + proxyShapeXformObj = om.MSelectionList().add('transform1').getDagPath(0).node() + proxyShapeXformFn = om.MFnTransform(proxyShapeXformObj) + + def ball35Translation(): + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + return addVec( + proxyShapeXformFn.translation(om.MSpace.kTransform), + ball35Prim.GetAttribute('xformOp:translate').Get()) + + def ball35SetTranslation(xlation): + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + ball35Prim.GetAttribute('xformOp:translate').Set( + Gf.Vec3d(*xlation)) + + # Set up the callables that will set and get the translation. + self.setRunTimeTranslation = ball35SetTranslation + self.getRunTimeTranslation = ball35Translation + self.getUfeTranslation = partial(transform3dTranslation, transform3d) + + self.runTestMove() + + def testObservation(self): + '''Test Transform3d observation interface. + + As of 11-Apr-2018 only implemented for USD objects. + ''' + + # Select Ball_35 to move it. + ball35Path = ufe.Path([ + mayaUtils.createUfePathSegment("|world|transform1|proxyShape1"), + usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) + ball35Item = ufe.Hierarchy.createItem(ball35Path) + + # Create a Transform3d interface for it. + transform3d = ufe.Transform3d.transform3d(ball35Item) + + t3dObs = TestObserver() + + # We start off with no observers for Ball_35. + self.assertFalse(ufe.Transform3d.hasObservers(ball35Path)) + self.assertFalse(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) + self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 0) + + # Set the observer to observe Ball_35. + ufe.Transform3d.addObserver(ball35Item, t3dObs) + + self.assertTrue(ufe.Transform3d.hasObservers(ball35Path)) + self.assertTrue(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) + self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 1) + + # No notifications yet. + self.assertEqual(t3dObs.notifications(), 0) + + # We only select the ball AFTER doing our initial tests because + # the MayaUSD plugin creates a transform3d observer on selection + # change to update the bounding box. + ufe.GlobalSelection.get().append(ball35Item) + + # Move the prim. + ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) + ball35Prim.GetAttribute('xformOp:translate').Set( + Gf.Vec3d(10, 20, 30)) + + # Notified. + self.assertEqual(t3dObs.notifications(), 1) diff --git a/test/lib/ufe/ufeScripts/__init__.py b/test/lib/ufe/ufeScripts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/lib/ufe/ufeScripts/ufeSelectCmd.py b/test/lib/ufe/ufeScripts/ufeSelectCmd.py new file mode 100644 index 0000000000..cc697f5104 --- /dev/null +++ b/test/lib/ufe/ufeScripts/ufeSelectCmd.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +#- +# =========================================================================== +# WARNING: PROTOTYPE CODE +# +# The code in this file is intended as an engineering prototype, to demonstrate +# UFE integration in Maya. Its performance and stability may make it +# unsuitable for production use. +# +# Autodesk believes production quality would be better achieved with a C++ +# version of this code. +# +# =========================================================================== +#+ + +"""Maya UFE selection command. + +Operations in Maya are performed on the selection. This imposes the +requirement that selection in Maya must be an undoable operation, so that +operations after an undo have the proper selection as input. + +Maya selections done through non-UFE UIs already go through the undoable select +command. Selections done through UFE UIs must use the undoable command in this +module. +""" + +# Code in this module was initially in the mayaUfe module, which defines +# the initialization and finalization functions for the mayaUfe plugin. +# This confusingly caused two instances of each command class to exist (as +# demonstrated by different values of id() on the class), one used by the +# command creator, and the other by the rest of the Python code. +# Separating out the command code into this module fixed the issue. PPT, +# 26-Jan-2018. + +import maya.api.OpenMaya as OpenMaya + +import maya.cmds as cmds + +import ufe.PyUfe as PyUfe + +# Messages should be localized. +kUfeSelectCmdPrivate = 'Private UFE select command %s arguments not set up.' + +def append(item): + return SelectAppendCmd.execute(item) + +def remove(item): + return SelectRemoveCmd.execute(item) + +def clear(): + SelectClearCmd.execute() + +def replaceWith(selection): + SelectReplaceWithCmd.execute(selection) + +#============================================================================== +# CLASS SelectCmdBase +#============================================================================== + +class SelectCmdBase(OpenMaya.MPxCommand): + """Base class for UFE selection commands. + + This command is intended as a base class for concrete UFE select commands. + """ + + def __init__(self): + super(SelectCmdBase, self).__init__() + self.globalSelection = PyUfe.GlobalSelection.get() + + def isUndoable(self): + return True + + def validateArgs(self): + return True + + def doIt(self, args): + # Completely ignore the MArgList argument, as it's unnecessary: + # arguments to the commands are passed in Python object form + # directly to the command's constructor. + + if self.validateArgs() is False: + self.displayWarning(kUfeSelectCmdPrivate % self.kCmdName) + else: + self.redoIt() + +#============================================================================== +# CLASS SelectAppendCmd +#============================================================================== + +class SelectAppendCmd(SelectCmdBase): + """Append an item to the UFE selection. + + This command is a private implementation detail of this module and should + not be called otherwise.""" + + kCmdName = 'ufeSelectAppend' + + # Command data. Must be set before creating an instance of the command + # and executing it. + item = None + + # Command return data. Set by doIt(). + result = None + + @staticmethod + def execute(item): + """Append the item to the UFE selection, and add an entry to the + undo queue.""" + + # Would be nice to have a guard context to restore the class data + # to its previous value (which is None). Not obvious how to write + # a Python context manager for this, as Python simply binds names + # to objects in a scope. + SelectAppendCmd.item = item + cmds.ufeSelectAppend() + result = SelectAppendCmd.result + SelectAppendCmd.item = None + SelectAppendCmd.result = None + return result + + @staticmethod + def creator(): + return SelectAppendCmd(SelectAppendCmd.item) + + def __init__(self, item): + super(SelectAppendCmd, self).__init__() + self.item = item + self.result = None + + def validateArgs(self): + return self.item is not None + + def doIt(self, args): + super(SelectAppendCmd, self).doIt(args) + # Save the result out as a class member. + SelectAppendCmd.result = self.result + + def redoIt(self): + self.result = self.globalSelection.append(self.item) + + def undoIt(self): + if self.result: + self.globalSelection.remove(self.item) + +#============================================================================== +# CLASS SelectRemoveCmd +#============================================================================== + +class SelectRemoveCmd(SelectCmdBase): + """Append an item to the UFE selection. + + This command is a private implementation detail of this module and should + not be called otherwise.""" + + kCmdName = 'ufeSelectRemove' + + # Command data. Must be set before creating an instance of the command + # and executing it. + item = None + + # Command return data. Set by doIt(). + result = None + + @staticmethod + def execute(item): + """Remove the item from the UFE selection, and add an entry to the + undo queue.""" + + # See SelectAppendCmd.execute comments. + SelectRemoveCmd.item = item + cmds.ufeSelectRemove() + result = SelectRemoveCmd.result + SelectRemoveCmd.item = None + SelectRemoveCmd.result = None + return result + + @staticmethod + def creator(): + return SelectRemoveCmd(SelectRemoveCmd.item) + + def __init__(self, item): + super(SelectRemoveCmd, self).__init__() + self.item = item + self.result = None + + def validateArgs(self): + return self.item is not None + + def doIt(self, args): + super(SelectRemoveCmd, self).doIt(args) + # Save the result out as a class member. + SelectRemoveCmd.result = self.result + + def redoIt(self): + self.result = self.globalSelection.remove(self.item) + + def undoIt(self): + # This is not a true undo! Selection.remove removes an item regardless + # of its position in the list, but append places the item in the last + # position. Saving and restoring the complete list is O(n) for n + # elements in the list; we want an O(1) solution. Selection.remove + # should return the list position of the removed element, for undo O(1) + # re-insertion using a future Selection.insert(). In C++, this list + # position would be an iterator; a matching Python binding would most + # likely require custom pybind code. PPT, 26-Jan-2018. + if self.result: + self.globalSelection.append(self.item) + +#============================================================================== +# CLASS SelectClearCmd +#============================================================================== + +class SelectClearCmd(SelectCmdBase): + """Clear the UFE selection. + + This command is a private implementation detail of this module and should + not be called otherwise.""" + + kCmdName = 'ufeSelectClear' + + @staticmethod + def execute(): + """Clear the UFE selection, and add an entry to the undo queue.""" + cmds.ufeSelectClear() + + @staticmethod + def creator(): + return SelectClearCmd() + + def __init__(self): + super(SelectClearCmd, self).__init__() + self.savedSelection = None + + def redoIt(self): + self.savedSelection = self.globalSelection + self.globalSelection.clear() + + def undoIt(self): + self.globalSelection.replaceWith(self.savedSelection) + +#============================================================================== +# CLASS SelectReplaceWithCmd +#============================================================================== + +class SelectReplaceWithCmd(SelectCmdBase): + """Replace the UFE selection with a new selection. + + This command is a private implementation detail of this module and should + not be called otherwise.""" + + kCmdName = 'ufeSelectReplaceWith' + + # Command data. Must be set before creating an instance of the command + # and executing it. + selection = None + + @staticmethod + def execute(selection): + """Replace the UFE selection with a new selection, and add an entry to + the undo queue.""" + + # See SelectAppendCmd.execute comments. + SelectReplaceWithCmd.selection = selection + cmds.ufeSelectReplaceWith() + SelectReplaceWithCmd.selection = None + + @staticmethod + def creator(): + return SelectReplaceWithCmd(SelectReplaceWithCmd.selection) + + def __init__(self, selection): + super(SelectReplaceWithCmd, self).__init__() + self.selection = selection + self.savedSelection = None + + def redoIt(self): + # No easy way to copy a Selection, so create a new one and call + # replaceWith(). selection[:], copy.copy(selection), and + # copy.deepcopy(selection) all raise Python exceptions. + self.savedSelection = PyUfe.Selection() + self.savedSelection.replaceWith(self.globalSelection) + self.globalSelection.replaceWith(self.selection) + + def undoIt(self): + self.globalSelection.replaceWith(self.savedSelection) diff --git a/test/lib/ufe/ufeTestPlugins/ufeTestCmdsPlugin.py b/test/lib/ufe/ufeTestPlugins/ufeTestCmdsPlugin.py new file mode 100644 index 0000000000..8eb495c262 --- /dev/null +++ b/test/lib/ufe/ufeTestPlugins/ufeTestCmdsPlugin.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +""" +Plugin to register commands for UFE tests. +""" + +import maya.api.OpenMaya as OpenMaya + +from ufeScripts import ufeSelectCmd + +ufeTestCmdsVersion = '0.1' + +# Using the Maya Python API 2.0. +def maya_useNewAPI(): + pass + +commands = [ufeSelectCmd.SelectAppendCmd, ufeSelectCmd.SelectRemoveCmd, + ufeSelectCmd.SelectClearCmd, ufeSelectCmd.SelectReplaceWithCmd] + +def initializePlugin(mobject): + mplugin = OpenMaya.MFnPlugin(mobject, "Autodesk", ufeTestCmdsVersion, "Any") + + for cmd in commands: + try: + mplugin.registerCommand(cmd.kCmdName, cmd.creator) + except: + OpenMaya.MGlobal.displayError('Register failed for %s' % cmd.kCmdName) + +def uninitializePlugin(mobject): + """ Uninitialize all the nodes """ + mplugin = OpenMaya.MFnPlugin(mobject, "Autodesk", ufeTestCmdsVersion, "Any") + + for cmd in commands: + try: + mplugin.deregisterCommand(cmd.kCmdName) + except: + OpenMaya.MGlobal.displayError('Unregister failed for %s' % cmd.kCmdName) diff --git a/test/lib/ufe/ufeTestUtils/__init__.py b/test/lib/ufe/ufeTestUtils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/lib/ufe/ufeTestUtils/mayaUtils.py b/test/lib/ufe/ufeTestUtils/mayaUtils.py new file mode 100644 index 0000000000..04de70c4a0 --- /dev/null +++ b/test/lib/ufe/ufeTestUtils/mayaUtils.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +""" + Helper functions regarding Maya that will be used throughout the test. +""" + + +import maya.cmds as cmds +import sys, os + +import ufe + +ALL_PLUGINS = ["mayaUsdPlugin", "ufeTestCmdsPlugin"] + +mayaRuntimeID = 1 +mayaSeparator = "|" + +def loadPlugin(pluginName): + """ + Load all given plugins created or needed by maya-ufe-plugin + Args: + pluginName (str): The plugin name to load + Returns: + True if all plugins are loaded. False if a plugin failed to load + """ + try: + if not isPluginLoaded(pluginName): + cmds.loadPlugin( pluginName, quiet = True ) + return True + except: + print sys.exc_info()[1] + print "Unable to load %s" % pluginName + return False + +def isPluginLoaded(pluginName): + """ + Verifies that the given plugin is loaded + Args: + pluginName (str): The plugin name to verify + Returns: + True if the plugin is loaded. False if a plugin failed to load + """ + return cmds.pluginInfo( pluginName, loaded=True, query=True) + +def isMayaUsdPluginLoaded(): + """ + Load plugins needed by UFE tests. + Returns: + True if plugins loaded successfully. False if a plugin failed to load + """ + successLoad = True + for plugin in ALL_PLUGINS: + successLoad = successLoad and loadPlugin(plugin) + return successLoad + +def createUfePathSegment(mayaPath): + """ + Create an UFE path from a given maya path. + Make sure that it starts with |world. We are currently + supporting Maya nodes being at the top of UFE Paths (03/26/2018) + Args: + mayaPath (str): The maya path to use + Returns : + PathSegment of the given mayaPath + """ + if not mayaPath.startswith("|world"): + mayaPath = "|world" + mayaPath + return ufe.PathSegment(mayaPath, mayaRuntimeID, mayaSeparator) + + +def getMayaSelectionList(): + """ + Returns the current Maya selection in a list + Returns: + A list(str) containing all selected Maya items + """ + # Remove the unicode of cmds.ls + return [x.encode('UTF8') for x in cmds.ls(sl=True)] + +def openTopLayerScene(): + ''' + The test scene hierarchy is represented as : + |world + |pSphere1 + |pSphereShape1 + |transform1 + |proxyShape1 + /Room_set + /Props + /Ball_1 + /Ball_2 + ... + /Ball_35 + ''' + # Open top_layer file which contains the USD scene + filePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "test-samples", "ballset", "StandaloneScene", "top_layer.ma" ) + cmds.file(filePath, force=True, open=True) + diff --git a/test/lib/ufe/ufeTestUtils/ufeUtils.py b/test/lib/ufe/ufeTestUtils/ufeUtils.py new file mode 100644 index 0000000000..383d3648cc --- /dev/null +++ b/test/lib/ufe/ufeTestUtils/ufeUtils.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +""" + Helper functions regarding UFE that will be used throughout the test. +""" + +import ufe +from maya import cmds +from ufeScripts import ufeSelectCmd + +def getUfeGlobalSelectionList(): + """ + Returns the current UFE selection in a list + Returns: + A list(str) containing all selected UFE items + """ + selection = [] + for item in ufe.GlobalSelection.get(): + selection.append(str(item.path().back())) + return selection + + +def selectPath(path, replace=False): + """ + Select a path in the UFE Global selection + Args: + path (ufe.Path): The UFE path to select + replace (bool=False): Replace the selection with + given UFE path + """ + sceneItem = ufe.Hierarchy.createItem(path) + if replace: + selection = ufe.Selection() + selection.append(sceneItem) + ufeSelectCmd.replaceWith(selection) + else: + ufeSelectCmd.append(sceneItem) \ No newline at end of file diff --git a/test/lib/ufe/ufeTestUtils/usdUtils.py b/test/lib/ufe/ufeTestUtils/usdUtils.py new file mode 100644 index 0000000000..afbe56eac2 --- /dev/null +++ b/test/lib/ufe/ufeTestUtils/usdUtils.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# +# Copyright 2019 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. +# + +""" + Helper functions regarding USD that will be used throughout the test. +""" + +usdSeparator = '/' +usdRuntimeID = 2 +import ufe +import mayaUsd.ufe + +def createUfePathSegment(usdPath): + """ + Create an UFE path from a given usd path. + Args: + usdPath (str): The usd path to use + Returns : + PathSegment of the given usdPath + """ + return ufe.PathSegment(usdPath, usdRuntimeID, usdSeparator) + +def getPrimFromSceneItem(item): + rawItem = item.getRawAddress() + prim = mayaUsd.ufe.getPrimFromRawItem(rawItem) + return prim